Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Update Templates | 15016809 | 918 days ago | IN | 0 ETH | 0.00214018 |
Latest 10 internal transactions
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
15016829 | 918 days ago | Contract Creation | 0 ETH | |||
15016829 | 918 days ago | Contract Creation | 0 ETH | |||
15016829 | 918 days ago | Contract Creation | 0 ETH | |||
15016829 | 918 days ago | Contract Creation | 0 ETH | |||
15016829 | 918 days ago | Contract Creation | 0 ETH | |||
15016808 | 918 days ago | Contract Creation | 0 ETH | |||
15016808 | 918 days ago | Contract Creation | 0 ETH | |||
15016808 | 918 days ago | Contract Creation | 0 ETH | |||
15016808 | 918 days ago | Contract Creation | 0 ETH | |||
15016808 | 918 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
BridgeCreator
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "../bridge/Bridge.sol"; import "../bridge/SequencerInbox.sol"; import "../bridge/ISequencerInbox.sol"; import "../bridge/Inbox.sol"; import "../bridge/Outbox.sol"; import "./RollupEventInbox.sol"; import "../bridge/IBridge.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; contract BridgeCreator is Ownable { Bridge public bridgeTemplate; SequencerInbox public sequencerInboxTemplate; Inbox public inboxTemplate; RollupEventInbox public rollupEventInboxTemplate; Outbox public outboxTemplate; event TemplatesUpdated(); constructor() Ownable() { bridgeTemplate = new Bridge(); sequencerInboxTemplate = new SequencerInbox(); inboxTemplate = new Inbox(); rollupEventInboxTemplate = new RollupEventInbox(); outboxTemplate = new Outbox(); } function updateTemplates( address _bridgeTemplate, address _sequencerInboxTemplate, address _inboxTemplate, address _rollupEventInboxTemplate, address _outboxTemplate ) external onlyOwner { bridgeTemplate = Bridge(_bridgeTemplate); sequencerInboxTemplate = SequencerInbox(_sequencerInboxTemplate); inboxTemplate = Inbox(_inboxTemplate); rollupEventInboxTemplate = RollupEventInbox(_rollupEventInboxTemplate); outboxTemplate = Outbox(_outboxTemplate); emit TemplatesUpdated(); } struct CreateBridgeFrame { ProxyAdmin admin; Bridge bridge; SequencerInbox sequencerInbox; Inbox inbox; RollupEventInbox rollupEventInbox; Outbox outbox; } function createBridge( address adminProxy, address rollup, ISequencerInbox.MaxTimeVariation memory maxTimeVariation ) external returns ( Bridge, SequencerInbox, Inbox, RollupEventInbox, Outbox ) { CreateBridgeFrame memory frame; { frame.bridge = Bridge( address(new TransparentUpgradeableProxy(address(bridgeTemplate), adminProxy, "")) ); frame.sequencerInbox = SequencerInbox( address( new TransparentUpgradeableProxy(address(sequencerInboxTemplate), adminProxy, "") ) ); frame.inbox = Inbox( address(new TransparentUpgradeableProxy(address(inboxTemplate), adminProxy, "")) ); frame.rollupEventInbox = RollupEventInbox( address( new TransparentUpgradeableProxy( address(rollupEventInboxTemplate), adminProxy, "" ) ) ); frame.outbox = Outbox( address(new TransparentUpgradeableProxy(address(outboxTemplate), adminProxy, "")) ); } frame.bridge.initialize(IOwnable(rollup)); frame.sequencerInbox.initialize(IBridge(frame.bridge), maxTimeVariation); frame.inbox.initialize(IBridge(frame.bridge), ISequencerInbox(frame.sequencerInbox)); frame.rollupEventInbox.initialize(IBridge(frame.bridge)); frame.outbox.initialize(IBridge(frame.bridge)); return ( frame.bridge, frame.sequencerInbox, frame.inbox, frame.rollupEventInbox, frame.outbox ); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.4; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "./IBridge.sol"; import "./Messages.sol"; import "../libraries/DelegateCallAware.sol"; import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol"; /** * @title Staging ground for incoming and outgoing messages * @notice Holds the inbox accumulator for sequenced and delayed messages. * It is also the ETH escrow for value sent with these messages. * Since the escrow is held here, this contract also contains a list of allowed * outboxes that can make calls from here and withdraw this escrow. */ contract Bridge is Initializable, DelegateCallAware, IBridge { using AddressUpgradeable for address; struct InOutInfo { uint256 index; bool allowed; } mapping(address => InOutInfo) private allowedDelayedInboxesMap; mapping(address => InOutInfo) private allowedOutboxesMap; address[] public allowedDelayedInboxList; address[] public allowedOutboxList; address private _activeOutbox; /// @dev Accumulator for delayed inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message. bytes32[] public override delayedInboxAccs; /// @dev Accumulator for sequencer inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message. bytes32[] public override sequencerInboxAccs; IOwnable public override rollup; address public sequencerInbox; address private constant EMPTY_ACTIVEOUTBOX = address(type(uint160).max); function initialize(IOwnable rollup_) external initializer onlyDelegated { _activeOutbox = EMPTY_ACTIVEOUTBOX; rollup = rollup_; } modifier onlyRollupOrOwner() { if (msg.sender != address(rollup)) { address rollupOwner = rollup.owner(); if (msg.sender != rollupOwner) { revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner); } } _; } /// @dev returns the address of current active Outbox, or zero if no outbox is active function activeOutbox() public view returns (address) { address outbox = _activeOutbox; // address zero is returned if no outbox is set, but the value used in storage // is non-zero to save users some gas (as storage refunds are usually maxed out) // EIP-1153 would help here. // we don't return `EMPTY_ACTIVEOUTBOX` to avoid a breaking change on the current api if (outbox == EMPTY_ACTIVEOUTBOX) return address(0); return outbox; } function allowedDelayedInboxes(address inbox) external view override returns (bool) { return allowedDelayedInboxesMap[inbox].allowed; } function allowedOutboxes(address outbox) external view override returns (bool) { return allowedOutboxesMap[outbox].allowed; } modifier onlySequencerInbox() { if (msg.sender != sequencerInbox) revert NotSequencerInbox(msg.sender); _; } function enqueueSequencerMessage(bytes32 dataHash, uint256 afterDelayedMessagesRead) external override onlySequencerInbox returns ( uint256 seqMessageIndex, bytes32 beforeAcc, bytes32 delayedAcc, bytes32 acc ) { seqMessageIndex = sequencerInboxAccs.length; if (sequencerInboxAccs.length > 0) { beforeAcc = sequencerInboxAccs[sequencerInboxAccs.length - 1]; } if (afterDelayedMessagesRead > 0) { delayedAcc = delayedInboxAccs[afterDelayedMessagesRead - 1]; } acc = keccak256(abi.encodePacked(beforeAcc, dataHash, delayedAcc)); sequencerInboxAccs.push(acc); } /** * @dev allows the sequencer inbox to submit a delayed message of the batchPostingReport type * This is done through a separate function entrypoint instead of allowing the sequencer inbox * to call `enqueueDelayedMessage` to avoid the gas overhead of an extra SLOAD in either * every delayed inbox or every sequencer inbox call. */ function submitBatchSpendingReport(address sender, bytes32 messageDataHash) external override onlySequencerInbox returns (uint256) { return addMessageToDelayedAccumulator( L1MessageType_batchPostingReport, sender, uint64(block.number), uint64(block.timestamp), // solhint-disable-line not-rely-on-time, block.basefee, messageDataHash ); } /** * @dev Enqueue a message in the delayed inbox accumulator. * These messages are later sequenced in the SequencerInbox, either by the sequencer as * part of a normal batch, or by force inclusion. */ function enqueueDelayedMessage( uint8 kind, address sender, bytes32 messageDataHash ) external payable override returns (uint256) { if (!allowedDelayedInboxesMap[msg.sender].allowed) revert NotDelayedInbox(msg.sender); return addMessageToDelayedAccumulator( kind, sender, uint64(block.number), uint64(block.timestamp), // solhint-disable-line not-rely-on-time block.basefee, messageDataHash ); } function addMessageToDelayedAccumulator( uint8 kind, address sender, uint64 blockNumber, uint64 blockTimestamp, uint256 baseFeeL1, bytes32 messageDataHash ) internal returns (uint256) { uint256 count = delayedInboxAccs.length; bytes32 messageHash = Messages.messageHash( kind, sender, blockNumber, blockTimestamp, count, baseFeeL1, messageDataHash ); bytes32 prevAcc = 0; if (count > 0) { prevAcc = delayedInboxAccs[count - 1]; } delayedInboxAccs.push(Messages.accumulateInboxMessage(prevAcc, messageHash)); emit MessageDelivered( count, prevAcc, msg.sender, kind, sender, messageDataHash, baseFeeL1, blockTimestamp ); return count; } function executeCall( address to, uint256 value, bytes calldata data ) external override returns (bool success, bytes memory returnData) { if (!allowedOutboxesMap[msg.sender].allowed) revert NotOutbox(msg.sender); if (data.length > 0 && !to.isContract()) revert NotContract(to); address prevOutbox = _activeOutbox; _activeOutbox = msg.sender; // We set and reset active outbox around external call so activeOutbox remains valid during call // We use a low level call here since we want to bubble up whether it succeeded or failed to the caller // rather than reverting on failure as well as allow contract and non-contract calls // solhint-disable-next-line avoid-low-level-calls (success, returnData) = to.call{value: value}(data); _activeOutbox = prevOutbox; emit BridgeCallTriggered(msg.sender, to, value, data); } function setSequencerInbox(address _sequencerInbox) external override onlyRollupOrOwner { sequencerInbox = _sequencerInbox; emit SequencerInboxUpdated(_sequencerInbox); } function setDelayedInbox(address inbox, bool enabled) external override onlyRollupOrOwner { InOutInfo storage info = allowedDelayedInboxesMap[inbox]; bool alreadyEnabled = info.allowed; emit InboxToggle(inbox, enabled); if ((alreadyEnabled && enabled) || (!alreadyEnabled && !enabled)) { return; } if (enabled) { allowedDelayedInboxesMap[inbox] = InOutInfo(allowedDelayedInboxList.length, true); allowedDelayedInboxList.push(inbox); } else { allowedDelayedInboxList[info.index] = allowedDelayedInboxList[ allowedDelayedInboxList.length - 1 ]; allowedDelayedInboxesMap[allowedDelayedInboxList[info.index]].index = info.index; allowedDelayedInboxList.pop(); delete allowedDelayedInboxesMap[inbox]; } } function setOutbox(address outbox, bool enabled) external override onlyRollupOrOwner { if (outbox == EMPTY_ACTIVEOUTBOX) revert InvalidOutboxSet(outbox); 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 delayedMessageCount() external view override returns (uint256) { return delayedInboxAccs.length; } function sequencerMessageCount() external view override returns (uint256) { return sequencerInboxAccs.length; } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./IBridge.sol"; import "./IInbox.sol"; import "./ISequencerInbox.sol"; import "../rollup/IRollupLogic.sol"; import "./Messages.sol"; import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol"; import {GasRefundEnabled, IGasRefunder} from "../libraries/IGasRefunder.sol"; import "../libraries/DelegateCallAware.sol"; import {MAX_DATA_SIZE} from "../libraries/Constants.sol"; /** * @title Accepts batches from the sequencer and adds them to the rollup inbox. * @notice Contains the inbox accumulator which is the ordering of all data and transactions to be processed by the rollup. * As part of submitting a batch the sequencer is also expected to include items enqueued * in the delayed inbox (Bridge.sol). If items in the delayed inbox are not included by a * sequencer within a time limit they can be force included into the rollup inbox by anyone. */ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox { uint256 public totalDelayedMessagesRead; IBridge public bridge; /// @dev The size of the batch header uint256 public constant HEADER_LENGTH = 40; /// @dev If the first batch data byte after the header has this bit set, /// the sequencer inbox has authenticated the data. Currently not used. bytes1 public constant DATA_AUTHENTICATED_FLAG = 0x40; IOwnable public rollup; mapping(address => bool) public isBatchPoster; ISequencerInbox.MaxTimeVariation public maxTimeVariation; struct DasKeySetInfo { bool isValidKeyset; uint64 creationBlock; } mapping(bytes32 => DasKeySetInfo) public dasKeySetInfo; modifier onlyRollupOwner() { if (msg.sender != rollup.owner()) revert NotOwner(msg.sender, address(rollup)); _; } function initialize( IBridge bridge_, ISequencerInbox.MaxTimeVariation calldata maxTimeVariation_ ) external onlyDelegated { if (bridge != IBridge(address(0))) revert AlreadyInit(); if (bridge_ == IBridge(address(0))) revert HadZeroInit(); bridge = bridge_; rollup = bridge_.rollup(); maxTimeVariation = maxTimeVariation_; } function getTimeBounds() internal view virtual returns (TimeBounds memory) { TimeBounds memory bounds; if (block.timestamp > maxTimeVariation.delaySeconds) { bounds.minTimestamp = uint64(block.timestamp - maxTimeVariation.delaySeconds); } bounds.maxTimestamp = uint64(block.timestamp + maxTimeVariation.futureSeconds); if (block.number > maxTimeVariation.delayBlocks) { bounds.minBlockNumber = uint64(block.number - maxTimeVariation.delayBlocks); } bounds.maxBlockNumber = uint64(block.number + maxTimeVariation.futureBlocks); return bounds; } /// @notice Force messages from the delayed inbox to be included in the chain /// Callable by any address, but message can only be force-included after maxTimeVariation.delayBlocks and maxTimeVariation.delaySeconds /// has elapsed. As part of normal behaviour the sequencer will include these messages /// so it's only necessary to call this if the sequencer is down, or not including /// any delayed messages. /// @param _totalDelayedMessagesRead The total number of messages to read up to /// @param kind The kind of the last message to be included /// @param l1BlockAndTime The l1 block and the l1 timestamp of the last message to be included /// @param baseFeeL1 The l1 gas price of the last message to be included /// @param sender The sender of the last message to be included /// @param messageDataHash The messageDataHash of the last message to be included function forceInclusion( uint256 _totalDelayedMessagesRead, uint8 kind, uint64[2] calldata l1BlockAndTime, uint256 baseFeeL1, address sender, bytes32 messageDataHash ) external { if (_totalDelayedMessagesRead <= totalDelayedMessagesRead) revert DelayedBackwards(); bytes32 messageHash = Messages.messageHash( kind, sender, l1BlockAndTime[0], l1BlockAndTime[1], _totalDelayedMessagesRead - 1, baseFeeL1, messageDataHash ); // Can only force-include after the Sequencer-only window has expired. if (l1BlockAndTime[0] + maxTimeVariation.delayBlocks >= block.number) revert ForceIncludeBlockTooSoon(); if (l1BlockAndTime[1] + maxTimeVariation.delaySeconds >= block.timestamp) revert ForceIncludeTimeTooSoon(); // Verify that message hash represents the last message sequence of delayed message to be included bytes32 prevDelayedAcc = 0; if (_totalDelayedMessagesRead > 1) { prevDelayedAcc = bridge.delayedInboxAccs(_totalDelayedMessagesRead - 2); } if ( bridge.delayedInboxAccs(_totalDelayedMessagesRead - 1) != Messages.accumulateInboxMessage(prevDelayedAcc, messageHash) ) revert IncorrectMessagePreimage(); (bytes32 dataHash, TimeBounds memory timeBounds) = formEmptyDataHash( _totalDelayedMessagesRead ); ( uint256 seqMessageIndex, bytes32 beforeAcc, bytes32 delayedAcc, bytes32 afterAcc ) = addSequencerL2BatchImpl(dataHash, _totalDelayedMessagesRead, 0); emit SequencerBatchDelivered( seqMessageIndex, beforeAcc, afterAcc, delayedAcc, totalDelayedMessagesRead, timeBounds, BatchDataLocation.NoData ); } function addSequencerL2BatchFromOrigin( uint256 sequenceNumber, bytes calldata data, uint256 afterDelayedMessagesRead, IGasRefunder gasRefunder ) external refundsGas(gasRefunder) { // solhint-disable-next-line avoid-tx-origin if (msg.sender != tx.origin) revert NotOrigin(); if (!isBatchPoster[msg.sender]) revert NotBatchPoster(); (bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash( data, afterDelayedMessagesRead ); ( uint256 seqMessageIndex, bytes32 beforeAcc, bytes32 delayedAcc, bytes32 afterAcc ) = addSequencerL2BatchImpl(dataHash, afterDelayedMessagesRead, data.length); if (seqMessageIndex != sequenceNumber) revert BadSequencerNumber(seqMessageIndex, sequenceNumber); emit SequencerBatchDelivered( sequenceNumber, beforeAcc, afterAcc, delayedAcc, totalDelayedMessagesRead, timeBounds, BatchDataLocation.TxInput ); } function addSequencerL2Batch( uint256 sequenceNumber, bytes calldata data, uint256 afterDelayedMessagesRead, IGasRefunder gasRefunder ) external override refundsGas(gasRefunder) { if (!isBatchPoster[msg.sender] && msg.sender != address(rollup)) revert NotBatchPoster(); (bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash( data, afterDelayedMessagesRead ); // we set the calldata length posted to 0 here since the caller isn't the origin // of the tx, so they might have not paid tx input cost for the calldata ( uint256 seqMessageIndex, bytes32 beforeAcc, bytes32 delayedAcc, bytes32 afterAcc ) = addSequencerL2BatchImpl(dataHash, afterDelayedMessagesRead, 0); if (seqMessageIndex != sequenceNumber) revert BadSequencerNumber(seqMessageIndex, sequenceNumber); emit SequencerBatchDelivered( sequenceNumber, beforeAcc, afterAcc, delayedAcc, afterDelayedMessagesRead, timeBounds, BatchDataLocation.SeparateBatchEvent ); emit SequencerBatchData(sequenceNumber, data); } modifier validateBatchData(bytes calldata data) { uint256 fullDataLen = HEADER_LENGTH + data.length; if (fullDataLen > MAX_DATA_SIZE) revert DataTooLarge(fullDataLen, MAX_DATA_SIZE); if (data.length > 0 && (data[0] & DATA_AUTHENTICATED_FLAG) == DATA_AUTHENTICATED_FLAG) { revert DataNotAuthenticated(); } // the first byte is used to identify the type of batch data // das batches expect to have the type byte set, followed by the keyset (so they should have at least 33 bytes) if (data.length >= 33 && data[0] & 0x80 != 0) { // we skip the first byte, then read the next 32 bytes for the keyset bytes32 dasKeysetHash = bytes32(data[1:33]); if (!dasKeySetInfo[dasKeysetHash].isValidKeyset) revert NoSuchKeyset(dasKeysetHash); } _; } function packHeader(uint256 afterDelayedMessagesRead) internal view returns (bytes memory, TimeBounds memory) { TimeBounds memory timeBounds = getTimeBounds(); bytes memory header = abi.encodePacked( timeBounds.minTimestamp, timeBounds.maxTimestamp, timeBounds.minBlockNumber, timeBounds.maxBlockNumber, uint64(afterDelayedMessagesRead) ); // This must always be true from the packed encoding assert(header.length == HEADER_LENGTH); return (header, timeBounds); } function formDataHash(bytes calldata data, uint256 afterDelayedMessagesRead) internal view validateBatchData(data) returns (bytes32, TimeBounds memory) { (bytes memory header, TimeBounds memory timeBounds) = packHeader(afterDelayedMessagesRead); bytes32 dataHash = keccak256(bytes.concat(header, data)); return (dataHash, timeBounds); } function formEmptyDataHash(uint256 afterDelayedMessagesRead) internal view returns (bytes32, TimeBounds memory) { (bytes memory header, TimeBounds memory timeBounds) = packHeader(afterDelayedMessagesRead); return (keccak256(header), timeBounds); } function addSequencerL2BatchImpl( bytes32 dataHash, uint256 afterDelayedMessagesRead, uint256 calldataLengthPosted ) internal returns ( uint256 seqMessageIndex, bytes32 beforeAcc, bytes32 delayedAcc, bytes32 acc ) { if (afterDelayedMessagesRead < totalDelayedMessagesRead) revert DelayedBackwards(); if (afterDelayedMessagesRead > bridge.delayedMessageCount()) revert DelayedTooFar(); (seqMessageIndex, beforeAcc, delayedAcc, acc) = bridge.enqueueSequencerMessage( dataHash, afterDelayedMessagesRead ); totalDelayedMessagesRead = afterDelayedMessagesRead; if (calldataLengthPosted > 0) { // this msg isn't included in the current sequencer batch, but instead added to // the delayed messages queue that is yet to be included address batchPoster = msg.sender; bytes memory spendingReportMsg = abi.encodePacked( block.timestamp, batchPoster, dataHash, seqMessageIndex, block.basefee ); uint256 msgNum = bridge.submitBatchSpendingReport( batchPoster, keccak256(spendingReportMsg) ); // this is the same event used by Inbox.sol after including a message to the delayed message accumulator emit InboxMessageDelivered(msgNum, spendingReportMsg); } } function inboxAccs(uint256 index) external view override returns (bytes32) { return bridge.sequencerInboxAccs(index); } function batchCount() external view override returns (uint256) { return bridge.sequencerMessageCount(); } /** * @notice Set max delay for sequencer inbox * @param maxTimeVariation_ the maximum time variation parameters */ function setMaxTimeVariation(ISequencerInbox.MaxTimeVariation memory maxTimeVariation_) external override onlyRollupOwner { maxTimeVariation = maxTimeVariation_; emit OwnerFunctionCalled(0); } /** * @notice Updates whether an address is authorized to be a batch poster at the sequencer inbox * @param addr the address * @param isBatchPoster_ if the specified address should be authorized as a batch poster */ function setIsBatchPoster(address addr, bool isBatchPoster_) external override onlyRollupOwner { isBatchPoster[addr] = isBatchPoster_; emit OwnerFunctionCalled(1); } /** * @notice Makes Data Availability Service keyset valid * @param keysetBytes bytes of the serialized keyset */ function setValidKeyset(bytes calldata keysetBytes) external override onlyRollupOwner { bytes32 ksHash = keccak256(keysetBytes); if (dasKeySetInfo[ksHash].isValidKeyset) revert AlreadyValidDASKeyset(ksHash); dasKeySetInfo[ksHash] = DasKeySetInfo({ isValidKeyset: true, creationBlock: uint64(block.number) }); emit SetValidKeyset(ksHash, keysetBytes); emit OwnerFunctionCalled(2); } /** * @notice Invalidates a Data Availability Service keyset * @param ksHash hash of the keyset */ function invalidateKeysetHash(bytes32 ksHash) external override onlyRollupOwner { if (!dasKeySetInfo[ksHash].isValidKeyset) revert NoSuchKeyset(ksHash); // we don't delete the block creation value since its used to fetch the SetValidKeyset // event efficiently. The event provides the hash preimage of the key. // this is still needed when syncing the chain after a keyset is invalidated. dasKeySetInfo[ksHash].isValidKeyset = false; emit InvalidateKeyset(ksHash); emit OwnerFunctionCalled(3); } function isValidKeysetHash(bytes32 ksHash) external view returns (bool) { return dasKeySetInfo[ksHash].isValidKeyset; } /// @notice the creation block is intended to still be available after a keyset is deleted function getKeysetCreationBlock(bytes32 ksHash) external view returns (uint256) { DasKeySetInfo memory ksInfo = dasKeySetInfo[ksHash]; if (ksInfo.creationBlock == 0) revert NoSuchKeyset(ksHash); return uint256(ksInfo.creationBlock); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "../libraries/IGasRefunder.sol"; import {AlreadyInit, HadZeroInit, NotOrigin, DataTooLarge, NotRollup} from "../libraries/Error.sol"; import "./IDelayedMessageProvider.sol"; interface ISequencerInbox is IDelayedMessageProvider { struct MaxTimeVariation { uint256 delayBlocks; uint256 futureBlocks; uint256 delaySeconds; uint256 futureSeconds; } struct TimeBounds { uint64 minTimestamp; uint64 maxTimestamp; uint64 minBlockNumber; uint64 maxBlockNumber; } enum BatchDataLocation { TxInput, SeparateBatchEvent, NoData } event SequencerBatchDelivered( uint256 indexed batchSequenceNumber, bytes32 indexed beforeAcc, bytes32 indexed afterAcc, bytes32 delayedAcc, uint256 afterDelayedMessagesRead, TimeBounds timeBounds, BatchDataLocation dataLocation ); event OwnerFunctionCalled(uint256 indexed id); /// @dev a separate event that emits batch data when this isn't easily accessible in the tx.input event SequencerBatchData(uint256 indexed batchSequenceNumber, bytes data); /// @dev a valid keyset was added event SetValidKeyset(bytes32 indexed keysetHash, bytes keysetBytes); /// @dev a keyset was invalidated event InvalidateKeyset(bytes32 indexed keysetHash); /// @dev Thrown when someone attempts to read fewer messages than have already been read error DelayedBackwards(); /// @dev Thrown when someone attempts to read more messages than exist error DelayedTooFar(); /// @dev Force include can only read messages more blocks old than the delay period error ForceIncludeBlockTooSoon(); /// @dev Force include can only read messages more seconds old than the delay period error ForceIncludeTimeTooSoon(); /// @dev The message provided did not match the hash in the delayed inbox error IncorrectMessagePreimage(); /// @dev This can only be called by the batch poster error NotBatchPoster(); /// @dev The sequence number provided to this message was inconsistent with the number of batches already included error BadSequencerNumber(uint256 stored, uint256 received); /// @dev The batch data has the inbox authenticated bit set, but the batch data was not authenticated by the inbox error DataNotAuthenticated(); /// @dev Tried to create an already valid Data Availability Service keyset error AlreadyValidDASKeyset(bytes32); /// @dev Tried to use or invalidate an already invalid Data Availability Service keyset error NoSuchKeyset(bytes32); function inboxAccs(uint256 index) external view returns (bytes32); function batchCount() external view returns (uint256); function addSequencerL2Batch( uint256 sequenceNumber, bytes calldata data, uint256 afterDelayedMessagesRead, IGasRefunder gasRefunder ) external; // Methods only callable by rollup owner /** * @notice Set max time variation from actual time for sequencer inbox * @param timeVariation the maximum time variation parameters */ function setMaxTimeVariation(MaxTimeVariation memory timeVariation) external; /** * @notice Updates whether an address is authorized to be a batch poster at the sequencer inbox * @param addr the address * @param isBatchPoster if the specified address should be authorized as a batch poster */ function setIsBatchPoster(address addr, bool isBatchPoster) external; function setValidKeyset(bytes calldata keysetBytes) external; function invalidateKeysetHash(bytes32 ksHash) external; }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.4; import "./IInbox.sol"; import "./ISequencerInbox.sol"; import "./IBridge.sol"; import "./Messages.sol"; import "../libraries/AddressAliasHelper.sol"; import "../libraries/DelegateCallAware.sol"; import { L2_MSG, L1MessageType_L2FundedByL1, L1MessageType_submitRetryableTx, L1MessageType_ethDeposit, L2MessageType_unsignedEOATx, L2MessageType_unsignedContractTx } from "../libraries/MessageTypes.sol"; import {MAX_DATA_SIZE} from "../libraries/Constants.sol"; import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; /** * @title Inbox for user and contract originated messages * @notice Messages created via this inbox are enqueued in the delayed accumulator * to await inclusion in the SequencerInbox */ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox { IBridge public override bridge; ISequencerInbox public sequencerInbox; /// ------------------------------------ allow list start ------------------------------------ /// bool public allowListEnabled; mapping(address => bool) public isAllowed; event AllowListAddressSet(address indexed user, bool val); event AllowListEnabledUpdated(bool isEnabled); function setAllowList(address[] memory user, bool[] memory val) external onlyRollupOrOwner { require(user.length == val.length, "INVALID_INPUT"); for (uint256 i = 0; i < user.length; i++) { isAllowed[user[i]] = val[i]; emit AllowListAddressSet(user[i], val[i]); } } function setAllowListEnabled(bool _allowListEnabled) external onlyRollupOrOwner { require(_allowListEnabled != allowListEnabled, "ALREADY_SET"); allowListEnabled = _allowListEnabled; emit AllowListEnabledUpdated(_allowListEnabled); } /// @dev this modifier checks the tx.origin instead of msg.sender for convenience (ie it allows /// allowed users to interact with the token bridge without needing the token bridge to be allowList aware). /// this modifier is not intended to use to be used for security (since this opens the allowList to /// a smart contract phishing risk). modifier onlyAllowed() { if (allowListEnabled && !isAllowed[tx.origin]) revert NotAllowedOrigin(tx.origin); _; } /// ------------------------------------ allow list end ------------------------------------ /// modifier onlyRollupOrOwner() { IOwnable rollup = bridge.rollup(); if (msg.sender != address(rollup)) { address rollupOwner = rollup.owner(); if (msg.sender != rollupOwner) { revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner); } } _; } /// @notice pauses all inbox functionality function pause() external onlyRollupOrOwner { _pause(); } /// @notice unpauses all inbox functionality function unpause() external onlyRollupOrOwner { _unpause(); } function initialize(IBridge _bridge, ISequencerInbox _sequencerInbox) external initializer onlyDelegated { if (address(bridge) != address(0)) revert AlreadyInit(); bridge = _bridge; sequencerInbox = _sequencerInbox; allowListEnabled = false; __Pausable_init(); } /// @dev function to be called one time during the inbox upgrade process /// this is used to fix the storage slots function postUpgradeInit(IBridge _bridge) external onlyDelegated onlyProxyOwner { uint8 slotsToWipe = 3; for (uint8 i = 0; i < slotsToWipe; i++) { assembly { sstore(i, 0) } } allowListEnabled = false; bridge = _bridge; } /** * @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 whenNotPaused onlyAllowed returns (uint256) { // solhint-disable-next-line avoid-tx-origin if (msg.sender != tx.origin) revert NotOrigin(); if (messageData.length > MAX_DATA_SIZE) revert DataTooLarge(messageData.length, MAX_DATA_SIZE); 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 whenNotPaused onlyAllowed returns (uint256) { return _deliverMessage(L2_MSG, msg.sender, messageData); } function sendL1FundedUnsignedTransaction( uint256 gasLimit, uint256 maxFeePerGas, uint256 nonce, address to, bytes calldata data ) external payable virtual override whenNotPaused onlyAllowed returns (uint256) { return _deliverMessage( L1MessageType_L2FundedByL1, msg.sender, abi.encodePacked( L2MessageType_unsignedEOATx, gasLimit, maxFeePerGas, nonce, uint256(uint160(to)), msg.value, data ) ); } function sendL1FundedContractTransaction( uint256 gasLimit, uint256 maxFeePerGas, address to, bytes calldata data ) external payable virtual override whenNotPaused onlyAllowed returns (uint256) { return _deliverMessage( L1MessageType_L2FundedByL1, msg.sender, abi.encodePacked( L2MessageType_unsignedContractTx, gasLimit, maxFeePerGas, uint256(uint160(to)), msg.value, data ) ); } function sendUnsignedTransaction( uint256 gasLimit, uint256 maxFeePerGas, uint256 nonce, address to, uint256 value, bytes calldata data ) external virtual override whenNotPaused onlyAllowed returns (uint256) { return _deliverMessage( L2_MSG, msg.sender, abi.encodePacked( L2MessageType_unsignedEOATx, gasLimit, maxFeePerGas, nonce, uint256(uint160(to)), value, data ) ); } function sendContractTransaction( uint256 gasLimit, uint256 maxFeePerGas, address to, uint256 value, bytes calldata data ) external virtual override whenNotPaused onlyAllowed returns (uint256) { return _deliverMessage( L2_MSG, msg.sender, abi.encodePacked( L2MessageType_unsignedContractTx, gasLimit, maxFeePerGas, uint256(uint160(to)), value, data ) ); } /** * @notice Get the L1 fee for submitting a retryable * @dev This fee can be paid by funds already in the L2 aliased address or by the current message value * @dev This formula may change in the future, to future proof your code query this method instead of inlining!! * @param dataLength The length of the retryable's calldata, in bytes * @param baseFee The block basefee when the retryable is included in the chain */ function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee) public pure returns (uint256) { return (1400 + 6 * dataLength) * baseFee; } /// @notice deposit eth from L1 to L2 /// @dev this does not trigger the fallback function when receiving in the L2 side. /// Look into retryable tickets if you are interested in this functionality. /// @dev this function should not be called inside contract constructors function depositEth() public payable override whenNotPaused onlyAllowed returns (uint256) { address dest = msg.sender; // solhint-disable-next-line avoid-tx-origin if (AddressUpgradeable.isContract(msg.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. dest = AddressAliasHelper.applyL1ToL2Alias(msg.sender); } return _deliverMessage( L1MessageType_ethDeposit, msg.sender, abi.encodePacked(dest, msg.value) ); } /// @notice deprecated in favour of depositEth with no parameters function depositEth(uint256) external payable virtual override whenNotPaused onlyAllowed returns (uint256) { return depositEth(); } /** * @notice deprecated in favour of unsafeCreateRetryableTicket * @dev deprecated in favour of unsafeCreateRetryableTicket * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error * @param to 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 gasLimit x maxFeePerGas - 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 gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) * @param data ABI encoded data of L2 message * @return unique id for retryable transaction (keccak256(requestID, uint(0) ) */ function createRetryableTicketNoRefundAliasRewrite( address to, uint256 l2CallValue, uint256 maxSubmissionCost, address excessFeeRefundAddress, address callValueRefundAddress, uint256 gasLimit, uint256 maxFeePerGas, bytes calldata data ) external payable virtual whenNotPaused onlyAllowed returns (uint256) { return unsafeCreateRetryableTicket( to, l2CallValue, maxSubmissionCost, excessFeeRefundAddress, callValueRefundAddress, gasLimit, maxFeePerGas, data ); } /** * @notice Put a 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 * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error * @param to 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 gasLimit x maxFeePerGas - 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 gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) * @param data ABI encoded data of L2 message * @return unique id for retryable transaction (keccak256(requestID, uint(0) ) */ function createRetryableTicket( address to, uint256 l2CallValue, uint256 maxSubmissionCost, address excessFeeRefundAddress, address callValueRefundAddress, uint256 gasLimit, uint256 maxFeePerGas, bytes calldata data ) external payable virtual override whenNotPaused onlyAllowed returns (uint256) { // ensure the user's deposit alone will make submission succeed if (msg.value < (maxSubmissionCost + l2CallValue + gasLimit * maxFeePerGas)) { revert InsufficientValue( maxSubmissionCost + l2CallValue + gasLimit * maxFeePerGas, msg.value ); } // if a refund address is a contract, we apply the alias to it // so that it can access its funds on the L2 // since the beneficiary and other refund addresses don't get rewritten by arb-os if (AddressUpgradeable.isContract(excessFeeRefundAddress)) { excessFeeRefundAddress = AddressAliasHelper.applyL1ToL2Alias(excessFeeRefundAddress); } if (AddressUpgradeable.isContract(callValueRefundAddress)) { // this is the beneficiary. be careful since this is the address that can cancel the retryable in the L2 callValueRefundAddress = AddressAliasHelper.applyL1ToL2Alias(callValueRefundAddress); } return unsafeCreateRetryableTicketInternal( to, l2CallValue, maxSubmissionCost, excessFeeRefundAddress, callValueRefundAddress, gasLimit, maxFeePerGas, data ); } /** * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts * @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed funds * come from the deposit alone, rather than falling back on the user's L2 balance * @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress). * createRetryableTicket method is the recommended standard. * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error * @param to 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 gasLimit x maxFeePerGas - 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 gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) * @param data ABI encoded data of L2 message * @return unique id for retryable transaction (keccak256(requestID, uint(0) ) */ function unsafeCreateRetryableTicketInternal( address to, uint256 l2CallValue, uint256 maxSubmissionCost, address excessFeeRefundAddress, address callValueRefundAddress, uint256 gasLimit, uint256 maxFeePerGas, bytes calldata data ) internal virtual whenNotPaused onlyAllowed returns (uint256) { // gas price and limit of 1 should never be a valid input, so instead they are used as // magic values to trigger a revert in eth calls that surface data without requiring a tx trace if (gasLimit == 1 || maxFeePerGas == 1) revert RetryableData( msg.sender, to, l2CallValue, msg.value, maxSubmissionCost, excessFeeRefundAddress, callValueRefundAddress, gasLimit, maxFeePerGas, data ); uint256 submissionFee = calculateRetryableSubmissionFee(data.length, block.basefee); if (maxSubmissionCost < submissionFee) revert InsufficientSubmissionCost(submissionFee, maxSubmissionCost); return _deliverMessage( L1MessageType_submitRetryableTx, msg.sender, abi.encodePacked( uint256(uint160(to)), l2CallValue, msg.value, maxSubmissionCost, uint256(uint160(excessFeeRefundAddress)), uint256(uint160(callValueRefundAddress)), gasLimit, maxFeePerGas, data.length, data ) ); } function unsafeCreateRetryableTicket( address, uint256, uint256, address, address, uint256, uint256, bytes calldata ) public payable override returns (uint256) { revert("UNSAFE_RETRYABLES_TEMPORARILY_DISABLED"); } function _deliverMessage( uint8 _kind, address _sender, bytes memory _messageData ) internal returns (uint256) { if (_messageData.length > MAX_DATA_SIZE) revert DataTooLarge(_messageData.length, MAX_DATA_SIZE); uint256 msgNum = deliverToBridge( _kind, AddressAliasHelper.applyL1ToL2Alias(_sender), keccak256(_messageData) ); emit InboxMessageDelivered(msgNum, _messageData); return msgNum; } function deliverToBridge( uint8 kind, address sender, bytes32 messageDataHash ) internal returns (uint256) { return bridge.enqueueDelayedMessage{value: msg.value}(kind, sender, messageDataHash); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.4; import "./IBridge.sol"; import "./IOutbox.sol"; import "../libraries/MerkleLib.sol"; import "../libraries/DelegateCallAware.sol"; /// @dev this error is thrown since certain functions are only expected to be used in simulations, not in actual txs error SimulationOnlyEntrypoint(); contract Outbox is DelegateCallAware, IOutbox { address public rollup; // the rollup contract IBridge public bridge; // the bridge contract mapping(uint256 => bytes32) public spent; // packed spent bitmap mapping(bytes32 => bytes32) public roots; // maps root hashes => L2 block hash struct L2ToL1Context { uint128 l2Block; uint128 l1Block; uint128 timestamp; 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; // default context values to be used in storage instead of zero, to save on storage refunds // it is assumed that arb-os never assigns these values to a valid leaf to be redeemed uint128 private constant L2BLOCK_DEFAULT_CONTEXT = type(uint128).max; uint128 private constant L1BLOCK_DEFAULT_CONTEXT = type(uint128).max; uint128 private constant TIMESTAMP_DEFAULT_CONTEXT = type(uint128).max; bytes32 private constant OUTPUTID_DEFAULT_CONTEXT = bytes32(type(uint256).max); address private constant SENDER_DEFAULT_CONTEXT = address(type(uint160).max); uint128 public constant OUTBOX_VERSION = 2; function initialize(IBridge _bridge) external onlyDelegated { if (address(bridge) != address(0)) revert AlreadyInit(); // address zero is returned if no context is set, but the values used in storage // are non-zero to save users some gas (as storage refunds are usually maxed out) // EIP-1153 would help here context = L2ToL1Context({ l2Block: L2BLOCK_DEFAULT_CONTEXT, l1Block: L1BLOCK_DEFAULT_CONTEXT, timestamp: TIMESTAMP_DEFAULT_CONTEXT, outputId: OUTPUTID_DEFAULT_CONTEXT, sender: SENDER_DEFAULT_CONTEXT }); bridge = _bridge; rollup = address(_bridge.rollup()); } function updateSendRoot(bytes32 root, bytes32 l2BlockHash) external override { if (msg.sender != rollup) revert NotRollup(msg.sender, rollup); roots[root] = l2BlockHash; emit SendRootUpdated(root, l2BlockHash); } /// @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) { address sender = context.sender; // we don't return the default context value to avoid a breaking change in the API if (sender == SENDER_DEFAULT_CONTEXT) return address(0); return sender; } /// @return l2Block return L2 block when the L2 tx was initiated or zero /// if no L2 to L1 transaction is active function l2ToL1Block() external view override returns (uint256) { uint128 l2Block = context.l2Block; // we don't return the default context value to avoid a breaking change in the API if (l2Block == L1BLOCK_DEFAULT_CONTEXT) return uint256(0); return uint256(l2Block); } /// @return l1Block return L1 block when the L2 tx was initiated or zero /// if no L2 to L1 transaction is active function l2ToL1EthBlock() external view override returns (uint256) { uint128 l1Block = context.l1Block; // we don't return the default context value to avoid a breaking change in the API if (l1Block == L1BLOCK_DEFAULT_CONTEXT) return uint256(0); return uint256(l1Block); } /// @return timestamp return L2 timestamp when the L2 tx was initiated or zero /// if no L2 to L1 transaction is active function l2ToL1Timestamp() external view override returns (uint256) { uint128 timestamp = context.timestamp; // we don't return the default context value to avoid a breaking change in the API if (timestamp == TIMESTAMP_DEFAULT_CONTEXT) return uint256(0); return uint256(timestamp); } /// @notice batch number is deprecated and now always returns 0 function l2ToL1BatchNum() external pure override returns (uint256) { return 0; } /// @return outputId returns the unique output identifier of the L2 to L1 tx or /// zero if no L2 to L1 transaction is active function l2ToL1OutputId() external view override returns (bytes32) { bytes32 outputId = context.outputId; // we don't return the default context value to avoid a breaking change in the API if (outputId == OUTPUTID_DEFAULT_CONTEXT) return bytes32(0); return outputId; } /** * @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 proof Merkle proof of message inclusion in send root * @param index Merkle path to message * @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1) * @param to 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 value wei in L1 message * @param data abi-encoded L1 message data */ function executeTransaction( bytes32[] calldata proof, uint256 index, address l2Sender, address to, uint256 l2Block, uint256 l1Block, uint256 l2Timestamp, uint256 value, bytes calldata data ) external { bytes32 userTx = calculateItemHash( l2Sender, to, l2Block, l1Block, l2Timestamp, value, data ); recordOutputAsSpent(proof, index, userTx); executeTransactionImpl(index, l2Sender, to, l2Block, l1Block, l2Timestamp, value, data); } /// @dev function used to simulate the result of a particular function call from the outbox /// it is useful for things such as gas estimates. This function includes all costs except for /// proof validation (which can be considered offchain as a somewhat of a fixed cost - it's /// not really a fixed cost, but can be treated as so with a fixed overhead for gas estimation). /// We can't include the cost of proof validation since this is intended to be used to simulate txs /// that are included in yet-to-be confirmed merkle roots. The simulation entrypoint could instead pretend /// to confirm a pending merkle root, but that would be less pratical for integrating with tooling. /// It is only possible to trigger it when the msg sender is address zero, which should be impossible /// unless under simulation in an eth_call or eth_estimateGas function executeTransactionSimulation( uint256 index, address l2Sender, address to, uint256 l2Block, uint256 l1Block, uint256 l2Timestamp, uint256 value, bytes calldata data ) external { if (msg.sender != address(0)) revert SimulationOnlyEntrypoint(); executeTransactionImpl(index, l2Sender, to, l2Block, l1Block, l2Timestamp, value, data); } function executeTransactionImpl( uint256 outputId, address l2Sender, address to, uint256 l2Block, uint256 l1Block, uint256 l2Timestamp, uint256 value, bytes calldata data ) internal { emit OutBoxTransactionExecuted(to, l2Sender, 0, outputId); // 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), outputId: bytes32(outputId) }); // set and reset vars around execution so they remain valid during call executeBridgeCall(to, value, data); context = prevContext; } function recordOutputAsSpent( bytes32[] memory proof, uint256 index, bytes32 item ) internal { if (proof.length >= 256) revert ProofTooLong(proof.length); if (index >= 2**proof.length) revert PathNotMinimal(index, 2**proof.length); // Hash the leaf an extra time to prove it's a leaf bytes32 calcRoot = calculateMerkleRoot(proof, index, item); if (roots[calcRoot] == bytes32(0)) revert UnknownRoot(calcRoot); uint256 spentIndex = index / 255; // Note: Reserves the MSB. uint256 bitOffset = index % 255; bytes32 replay = spent[spentIndex]; if (((replay >> bitOffset) & bytes32(uint256(1))) != bytes32(0)) revert AlreadySpent(index); spent[spentIndex] = (replay | bytes32(1 << bitOffset)); } function executeBridgeCall( address to, uint256 value, bytes memory data ) internal { (bool success, bytes memory returndata) = bridge.executeCall(to, value, 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 BridgeCallFailed(); } } } function calculateItemHash( address l2Sender, address to, uint256 l2Block, uint256 l1Block, uint256 l2Timestamp, uint256 value, bytes calldata data ) public pure returns (bytes32) { return keccak256(abi.encodePacked(l2Sender, to, l2Block, l1Block, l2Timestamp, value, data)); } function calculateMerkleRoot( bytes32[] memory proof, uint256 path, bytes32 item ) public pure returns (bytes32) { return MerkleLib.calculateRoot(proof, path, keccak256(abi.encodePacked(item))); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./IRollupEventInbox.sol"; import "../bridge/IBridge.sol"; import "../bridge/IDelayedMessageProvider.sol"; import "../libraries/DelegateCallAware.sol"; import {INITIALIZATION_MSG_TYPE} from "../libraries/MessageTypes.sol"; /** * @title The inbox for rollup protocol events */ contract RollupEventInbox is IRollupEventInbox, IDelayedMessageProvider, DelegateCallAware { 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 public override bridge; address public override rollup; modifier onlyRollup() { require(msg.sender == rollup, "ONLY_ROLLUP"); _; } function initialize(IBridge _bridge) external override onlyDelegated { require(address(bridge) == address(0), "ALREADY_INIT"); bridge = _bridge; rollup = address(_bridge.rollup()); } function rollupInitialized(uint256 chainId) external override onlyRollup { bytes memory initMsg = abi.encodePacked(chainId); uint256 num = bridge.enqueueDelayedMessage( INITIALIZATION_MSG_TYPE, address(0), keccak256(initMsg) ); emit InboxMessageDelivered(num, initMsg); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.4; import {NotContract, NotRollupOrOwner} from "../libraries/Error.sol"; import "./IOwnable.sol"; /// @dev Thrown when an un-authorized address tries to access an only-inbox function /// @param sender The un-authorized sender error NotDelayedInbox(address sender); /// @dev Thrown when an un-authorized address tries to access an only-sequencer-inbox function /// @param sender The un-authorized sender error NotSequencerInbox(address sender); /// @dev Thrown when an un-authorized address tries to access an only-outbox function /// @param sender The un-authorized sender error NotOutbox(address sender); /// @dev the provided outbox address isn't valid /// @param outbox address of outbox being set error InvalidOutboxSet(address outbox); interface IBridge { event MessageDelivered( uint256 indexed messageIndex, bytes32 indexed beforeInboxAcc, address inbox, uint8 kind, address sender, bytes32 messageDataHash, uint256 baseFeeL1, uint64 timestamp ); event BridgeCallTriggered( address indexed outbox, address indexed to, uint256 value, bytes data ); event InboxToggle(address indexed inbox, bool enabled); event OutboxToggle(address indexed outbox, bool enabled); event SequencerInboxUpdated(address newSequencerInbox); function enqueueDelayedMessage( uint8 kind, address sender, bytes32 messageDataHash ) external payable returns (uint256); function enqueueSequencerMessage(bytes32 dataHash, uint256 afterDelayedMessagesRead) external returns ( uint256 seqMessageIndex, bytes32 beforeAcc, bytes32 delayedAcc, bytes32 acc ); function submitBatchSpendingReport(address batchPoster, bytes32 dataHash) external returns (uint256 msgNum); function executeCall( address to, uint256 value, bytes calldata data ) external returns (bool success, bytes memory returnData); // These are only callable by the admin function setDelayedInbox(address inbox, bool enabled) external; function setOutbox(address inbox, bool enabled) external; function setSequencerInbox(address _sequencerInbox) external; // View functions function sequencerInbox() external view returns (address); function activeOutbox() external view returns (address); function allowedDelayedInboxes(address inbox) external view returns (bool); function allowedOutboxes(address outbox) external view returns (bool); function delayedInboxAccs(uint256 index) external view returns (bytes32); function sequencerInboxAccs(uint256 index) external view returns (bytes32); function delayedMessageCount() external view returns (uint256); function sequencerMessageCount() external view returns (uint256); function rollup() external view returns (IOwnable); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^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() { _transferOwnership(_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 { _transferOwnership(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"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/transparent/ProxyAdmin.sol) pragma solidity ^0.8.0; import "./TransparentUpgradeableProxy.sol"; import "../../access/Ownable.sol"; /** * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}. */ contract ProxyAdmin is Ownable { /** * @dev Returns the current implementation of `proxy`. * * Requirements: * * - This contract must be the admin of `proxy`. */ function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("implementation()")) == 0x5c60da1b (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b"); require(success); return abi.decode(returndata, (address)); } /** * @dev Returns the current admin of `proxy`. * * Requirements: * * - This contract must be the admin of `proxy`. */ function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) { // We need to manually run the static call since the getter cannot be flagged as view // bytes4(keccak256("admin()")) == 0xf851a440 (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440"); require(success); return abi.decode(returndata, (address)); } /** * @dev Changes the admin of `proxy` to `newAdmin`. * * Requirements: * * - This contract must be the current admin of `proxy`. */ function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner { proxy.changeAdmin(newAdmin); } /** * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}. * * Requirements: * * - This contract must be the admin of `proxy`. */ function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner { proxy.upgradeTo(implementation); } /** * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See * {TransparentUpgradeableProxy-upgradeToAndCall}. * * Requirements: * * - This contract must be the admin of `proxy`. */ function upgradeAndCall( TransparentUpgradeableProxy proxy, address implementation, bytes memory data ) public payable virtual onlyOwner { proxy.upgradeToAndCall{value: msg.value}(implementation, data); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol) pragma solidity ^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 proxied contracts do not make use of 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 {ERC1967Proxy-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. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() initializer {} * ``` * ==== */ 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() { // If the contract is initializing we ignore whether _initialized is set in order to support multiple // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the // contract may have been reentered. require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} modifier, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @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 * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 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"); (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"); (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"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal 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 assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; library Messages { function messageHash( uint8 kind, address sender, uint64 blockNumber, uint64 timestamp, uint256 inboxSeqNum, uint256 baseFeeL1, bytes32 messageDataHash ) internal pure returns (bytes32) { return keccak256( abi.encodePacked( kind, sender, blockNumber, timestamp, inboxSeqNum, baseFeeL1, messageDataHash ) ); } function accumulateInboxMessage(bytes32 prevAcc, bytes32 message) internal pure returns (bytes32) { return keccak256(abi.encodePacked(prevAcc, message)); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import {NotOwner} from "./Error.sol"; /// @dev A stateless contract that allows you to infer if the current call has been delegated or not /// Pattern used here is from UUPS implementation by the OpenZeppelin team abstract contract DelegateCallAware { address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegate call. This allows a function to be * callable on the proxy contract but not on the logic contract. */ modifier onlyDelegated() { require(address(this) != __self, "Function must be called through delegatecall"); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { require(address(this) == __self, "Function must not be called through delegatecall"); _; } /// @dev Check that msg.sender is the current EIP 1967 proxy admin modifier onlyProxyOwner() { // Storage slot with the admin of the proxy contract // This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1 bytes32 slot = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; address admin; assembly { admin := sload(slot) } if (msg.sender != admin) revert NotOwner(msg.sender, admin); _; } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.4; uint8 constant L2_MSG = 3; uint8 constant L1MessageType_L2FundedByL1 = 7; uint8 constant L1MessageType_submitRetryableTx = 9; uint8 constant L1MessageType_ethDeposit = 12; uint8 constant L1MessageType_batchPostingReport = 13; uint8 constant L2MessageType_unsignedEOATx = 0; uint8 constant L2MessageType_unsignedContractTx = 1; uint8 constant ROLLUP_PROTOCOL_EVENT_TYPE = 8; uint8 constant INITIALIZATION_MSG_TYPE = 11;
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.4; /// @dev Init was already called error AlreadyInit(); /// Init was called with param set to zero that must be nonzero error HadZeroInit(); /// @dev Thrown when non owner tries to access an only-owner function /// @param sender The msg.sender who is not the owner /// @param owner The owner address error NotOwner(address sender, address owner); /// @dev Thrown when an address that is not the rollup tries to call an only-rollup function /// @param sender The sender who is not the rollup /// @param rollup The rollup address authorized to call this function error NotRollup(address sender, address rollup); /// @dev Thrown when the contract was not called directly from the origin ie msg.sender != tx.origin error NotOrigin(); /// @dev Provided data was too large /// @param dataLength The length of the data that is too large /// @param maxDataLength The max length the data can be error DataTooLarge(uint256 dataLength, uint256 maxDataLength); /// @dev The provided is not a contract and was expected to be /// @param addr The adddress in question error NotContract(address addr); /// @dev The merkle proof provided was too long /// @param actualLength The length of the merkle proof provided /// @param maxProofLength The max length a merkle proof can have error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength); /// @dev Thrown when an un-authorized address tries to access an admin function /// @param sender The un-authorized sender /// @param rollup The rollup, which would be authorized /// @param owner The rollup's owner, which would be authorized error NotRollupOrOwner(address sender, address rollup, address owner);
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.4; interface IOwnable { function owner() external view returns (address); }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.4; import "./IBridge.sol"; import "./IDelayedMessageProvider.sol"; import {AlreadyInit, NotOrigin, DataTooLarge} from "../libraries/Error.sol"; /// @dev The contract is paused, so cannot be paused error AlreadyPaused(); /// @dev The contract is unpaused, so cannot be unpaused error AlreadyUnpaused(); /// @dev The contract is paused error Paused(); /// @dev msg.value sent to the inbox isn't high enough error InsufficientValue(uint256 expected, uint256 actual); /// @dev submission cost provided isn't enough to create retryable ticket error InsufficientSubmissionCost(uint256 expected, uint256 actual); /// @dev address not allowed to interact with the given contract error NotAllowedOrigin(address origin); /// @dev used to convey retryable tx data in eth calls without requiring a tx trace /// this follows a pattern similar to EIP-3668 where reverts surface call information error RetryableData( address from, address to, uint256 l2CallValue, uint256 deposit, uint256 maxSubmissionCost, address excessFeeRefundAddress, address callValueRefundAddress, uint256 gasLimit, uint256 maxFeePerGas, bytes data ); interface IInbox is IDelayedMessageProvider { function sendL2Message(bytes calldata messageData) external returns (uint256); function sendUnsignedTransaction( uint256 gasLimit, uint256 maxFeePerGas, uint256 nonce, address to, uint256 value, bytes calldata data ) external returns (uint256); function sendContractTransaction( uint256 gasLimit, uint256 maxFeePerGas, address to, uint256 value, bytes calldata data ) external returns (uint256); function sendL1FundedUnsignedTransaction( uint256 gasLimit, uint256 maxFeePerGas, uint256 nonce, address to, bytes calldata data ) external payable returns (uint256); function sendL1FundedContractTransaction( uint256 gasLimit, uint256 maxFeePerGas, address to, bytes calldata data ) external payable returns (uint256); /// @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error function createRetryableTicket( address to, uint256 arbTxCallValue, uint256 maxSubmissionCost, address submissionRefundAddress, address valueRefundAddress, uint256 gasLimit, uint256 maxFeePerGas, bytes calldata data ) external payable returns (uint256); /// @notice TEMPORARILY DISABLED as exact mechanics are being worked out /// @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error function unsafeCreateRetryableTicket( address to, uint256 arbTxCallValue, uint256 maxSubmissionCost, address submissionRefundAddress, address valueRefundAddress, uint256 gasLimit, uint256 maxFeePerGas, bytes calldata data ) external payable returns (uint256); function depositEth() external payable returns (uint256); /// @notice deprecated in favour of depositEth with no parameters function depositEth(uint256 maxSubmissionCost) external payable returns (uint256); function bridge() external view returns (IBridge); }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./RollupLib.sol"; import "./IRollupCore.sol"; import "../bridge/ISequencerInbox.sol"; import "../bridge/IOutbox.sol"; import "../bridge/IOwnable.sol"; interface IRollupUserAbs is IRollupCore, IOwnable { /// @dev the user logic just validated configuration and shouldn't write to state during init /// this allows the admin logic to ensure consistency on parameters. function initialize(address stakeToken) external view; function isERC20Enabled() external view returns (bool); function rejectNextNode(address stakerAddress) external; function confirmNextNode(bytes32 blockHash, bytes32 sendRoot) external; function stakeOnExistingNode(uint64 nodeNum, bytes32 nodeHash) external; function stakeOnNewNode( RollupLib.Assertion memory assertion, bytes32 expectedNodeHash, uint256 prevNodeInboxMaxCount ) external; function returnOldDeposit(address stakerAddress) external; function reduceDeposit(uint256 target) external; function removeZombie(uint256 zombieNum, uint256 maxNodes) external; function removeOldZombies(uint256 startIndex) external; function requiredStake( uint256 blockNumber, uint64 firstUnresolvedNodeNum, uint64 latestCreatedNode ) external view returns (uint256); function currentRequiredStake() external view returns (uint256); function countStakedZombies(uint64 nodeNum) external view returns (uint256); function countZombiesStakedOnChildren(uint64 nodeNum) external view returns (uint256); function requireUnresolvedExists() external view; function requireUnresolved(uint256 nodeNum) external view; function withdrawStakerFunds() external returns (uint256); function createChallenge( address[2] calldata stakers, uint64[2] calldata nodeNums, MachineStatus[2] calldata machineStatuses, GlobalState[2] calldata globalStates, uint64 numBlocks, bytes32 secondExecutionHash, uint256[2] calldata proposedTimes, bytes32[2] calldata wasmModuleRoots ) external; } interface IRollupUser is IRollupUserAbs { function newStakeOnExistingNode(uint64 nodeNum, bytes32 nodeHash) external payable; function newStakeOnNewNode( RollupLib.Assertion calldata assertion, bytes32 expectedNodeHash, uint256 prevNodeInboxMaxCount ) external payable; function addToDeposit(address stakerAddress) external payable; } interface IRollupUserERC20 is IRollupUserAbs { function newStakeOnExistingNode( uint256 tokenAmount, uint64 nodeNum, bytes32 nodeHash ) external; function newStakeOnNewNode( uint256 tokenAmount, RollupLib.Assertion calldata assertion, bytes32 expectedNodeHash, uint256 prevNodeInboxMaxCount ) external; function addToDeposit(address stakerAddress, uint256 tokenAmount) external; } interface IRollupAdmin { event OwnerFunctionCalled(uint256 indexed id); function initialize(Config calldata config, ContractDependencies calldata connectedContracts) external; /** * @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 setDelayedInbox(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 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 proxy * @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(uint64 newConfirmPeriod) external; /** * @notice Set number of extra blocks after a challenge * @param newExtraTimeBlocks new number of blocks */ function setExtraChallengeTimeBlocks(uint64 newExtraTimeBlocks) 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 logic! * @param newStakeToken address of token used for staking */ function setStakeToken(address newStakeToken) 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( uint64 prevNode, uint256 prevNodeInboxMaxCount, RollupLib.Assertion memory assertion, bytes32 expectedNodeHash ) external; function forceConfirmNode( uint64 nodeNum, bytes32 blockHash, bytes32 sendRoot ) external; function setLoserStakeEscrow(address newLoserStakerEscrow) external; /** * @notice Set the proving WASM module root * @param newWasmModuleRoot new module root */ function setWasmModuleRoot(bytes32 newWasmModuleRoot) external; /** * @notice set a new sequencer inbox contract * @param _sequencerInbox new address of sequencer inbox */ function setSequencerInbox(address _sequencerInbox) external; }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.6.11 <0.9.0; interface IGasRefunder { function onGasSpent( address payable spender, uint256 gasUsed, uint256 calldataSize ) external returns (bool success); } abstract contract GasRefundEnabled { /// @dev this refunds the sender for execution costs of the tx /// calldata costs are only refunded if `msg.sender == tx.origin` to guarantee the value refunded relates to charging /// for the `tx.input`. this avoids a possible attack where you generate large calldata from a contract and get over-refunded modifier refundsGas(IGasRefunder gasRefunder) { uint256 startGasLeft = gasleft(); _; if (address(gasRefunder) != address(0)) { uint256 calldataSize = 0; // if triggered in a contract call, the spender may be overrefunded by appending dummy data to the call // so we check if it is a top level call, which would mean the sender paid calldata as part of tx.input if (msg.sender == tx.origin) { assembly { calldataSize := calldatasize() } } gasRefunder.onGasSpent(payable(msg.sender), startGasLeft - gasleft(), calldataSize); } } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.4; // 90% of Geth's 128KB tx size limit, leaving ~13KB for proving uint256 constant MAX_DATA_SIZE = 117964; uint64 constant NO_CHAL_INDEX = 0;
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; interface IDelayedMessageProvider { /// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator event InboxMessageDelivered(uint256 indexed messageNum, bytes data); /// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator /// same as InboxMessageDelivered but the batch data is available in tx.input event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum); }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "../challenge/IChallengeManager.sol"; import "../challenge/ChallengeLib.sol"; import "../state/GlobalState.sol"; import "../bridge/ISequencerInbox.sol"; import "../bridge/IBridge.sol"; import "../bridge/IOutbox.sol"; import "../bridge/IInbox.sol"; import "./IRollupEventInbox.sol"; import "./IRollupLogic.sol"; struct Config { uint64 confirmPeriodBlocks; uint64 extraChallengeTimeBlocks; address stakeToken; uint256 baseStake; bytes32 wasmModuleRoot; address owner; address loserStakeEscrow; uint256 chainId; ISequencerInbox.MaxTimeVariation sequencerInboxMaxTimeVariation; } struct ContractDependencies { IBridge bridge; ISequencerInbox sequencerInbox; IInbox inbox; IOutbox outbox; IRollupEventInbox rollupEventInbox; IChallengeManager challengeManager; IRollupAdmin rollupAdminLogic; IRollupUser rollupUserLogic; // misc contracts that are useful when interacting with the rollup address validatorUtils; address validatorWalletCreator; } library RollupLib { using GlobalStateLib for GlobalState; struct ExecutionState { GlobalState globalState; MachineStatus machineStatus; } function stateHash(ExecutionState calldata execState, uint256 inboxMaxCount) internal pure returns (bytes32) { return keccak256( abi.encodePacked( execState.globalState.hash(), inboxMaxCount, execState.machineStatus ) ); } /// @dev same as stateHash but expects execState in memory instead of calldata function stateHashMem(ExecutionState memory execState, uint256 inboxMaxCount) internal pure returns (bytes32) { return keccak256( abi.encodePacked( execState.globalState.hash(), inboxMaxCount, execState.machineStatus ) ); } struct Assertion { ExecutionState beforeState; ExecutionState afterState; uint64 numBlocks; } function executionHash(Assertion memory assertion) internal pure returns (bytes32) { MachineStatus[2] memory statuses; statuses[0] = assertion.beforeState.machineStatus; statuses[1] = assertion.afterState.machineStatus; GlobalState[2] memory globalStates; globalStates[0] = assertion.beforeState.globalState; globalStates[1] = assertion.afterState.globalState; // TODO: benchmark how much this abstraction adds of gas overhead return executionHash(statuses, globalStates, assertion.numBlocks); } function executionHash( MachineStatus[2] memory statuses, GlobalState[2] memory globalStates, uint64 numBlocks ) internal pure returns (bytes32) { bytes32[] memory segments = new bytes32[](2); segments[0] = ChallengeLib.blockStateHash(statuses[0], globalStates[0].hash()); segments[1] = ChallengeLib.blockStateHash(statuses[1], globalStates[1].hash()); return ChallengeLib.hashChallengeState(0, numBlocks, segments); } function challengeRootHash( bytes32 execution, uint256 proposedTime, bytes32 wasmModuleRoot ) internal pure returns (bytes32) { return keccak256(abi.encodePacked(execution, proposedTime, wasmModuleRoot)); } function confirmHash(Assertion memory assertion) internal pure returns (bytes32) { return confirmHash( assertion.afterState.globalState.getBlockHash(), assertion.afterState.globalState.getSendRoot() ); } function confirmHash(bytes32 blockHash, bytes32 sendRoot) internal pure returns (bytes32) { return keccak256(abi.encodePacked(blockHash, sendRoot)); } function nodeHash( bool hasSibling, bytes32 lastHash, bytes32 assertionExecHash, bytes32 inboxAcc, bytes32 wasmModuleRoot ) internal pure returns (bytes32) { uint8 hasSiblingInt = hasSibling ? 1 : 0; return keccak256( abi.encodePacked( hasSiblingInt, lastHash, assertionExecHash, inboxAcc, wasmModuleRoot ) ); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./Node.sol"; import "./RollupLib.sol"; interface IRollupCore { struct Staker { uint256 amountStaked; uint64 index; uint64 latestStakedNode; // currentChallenge is 0 if staker is not in a challenge uint64 currentChallenge; bool isStaked; } event RollupInitialized(bytes32 machineHash, uint256 chainId); event NodeCreated( uint64 indexed nodeNum, bytes32 indexed parentNodeHash, bytes32 indexed nodeHash, bytes32 executionHash, RollupLib.Assertion assertion, bytes32 afterInboxBatchAcc, bytes32 wasmModuleRoot, uint256 inboxMaxCount ); event NodeConfirmed(uint64 indexed nodeNum, bytes32 blockHash, bytes32 sendRoot); event NodeRejected(uint64 indexed nodeNum); event RollupChallengeStarted( uint64 indexed challengeIndex, address asserter, address challenger, uint64 challengedNode ); event UserStakeUpdated(address indexed user, uint256 initialBalance, uint256 finalBalance); event UserWithdrawableFundsUpdated( address indexed user, uint256 initialBalance, uint256 finalBalance ); function confirmPeriodBlocks() external view returns (uint64); function extraChallengeTimeBlocks() external view returns (uint64); function chainId() external view returns (uint256); function baseStake() external view returns (uint256); function wasmModuleRoot() external view returns (bytes32); function bridge() external view returns (IBridge); function sequencerInbox() external view returns (ISequencerInbox); function outbox() external view returns (IOutbox); function rollupEventInbox() external view returns (IRollupEventInbox); function challengeManager() external view returns (IChallengeManager); function loserStakeEscrow() external view returns (address); function stakeToken() external view returns (address); function minimumAssertionPeriod() external view returns (uint256); function isValidator(address) external view returns (bool); /** * @notice Get the Node for the given index. */ function getNode(uint64 nodeNum) external view returns (Node memory); /** * @notice Check if the specified node has been staked on by the provided staker. * Only accurate at the latest confirmed node and afterwards. */ function nodeHasStaker(uint64 nodeNum, address staker) external view returns (bool); /** * @notice Get the address of the staker at the given index * @param stakerNum Index of the staker * @return Address of the staker */ function getStakerAddress(uint64 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 (uint64); /** * @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 (uint64); /** * @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 Retrieves stored information about a requested staker * @param staker Staker address to retrieve * @return A structure with information about the requested staker */ function getStaker(address staker) external view returns (Staker memory); /** * @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 (uint64); /// @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 (uint64); /// @return Index of the latest confirmed node function latestConfirmed() external view returns (uint64); /// @return Index of the latest rollup node created function latestNodeCreated() external view returns (uint64); /// @return Ethereum block that the most recent stake was created function lastStakeBlock() external view returns (uint64); /// @return Number of active stakers currently staked function stakerCount() external view returns (uint64); }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.4; import {AlreadyInit, NotRollup} from "../libraries/Error.sol"; /// @dev The provided proof was too long /// @param proofLength The length of the too-long proof error ProofTooLong(uint256 proofLength); /// @dev The output index was greater than the maximum /// @param index The output index /// @param maxIndex The max the index could be error PathNotMinimal(uint256 index, uint256 maxIndex); /// @dev The calculated root does not exist /// @param root The calculated root error UnknownRoot(bytes32 root); /// @dev The record has already been spent /// @param index The index of the spent record error AlreadySpent(uint256 index); /// @dev A call to the bridge failed with no return data error BridgeCallFailed(); interface IOutbox { event SendRootUpdated(bytes32 indexed blockHash, bytes32 indexed outputRoot); event OutBoxTransactionExecuted( address indexed to, address indexed l2Sender, uint256 indexed zero, 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); // @deprecated batch number is now always 0 function l2ToL1BatchNum() external view returns (uint256); function l2ToL1OutputId() external view returns (bytes32); function updateSendRoot(bytes32 sendRoot, bytes32 l2BlockHash) external; }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "../state/Machine.sol"; import "../bridge/IBridge.sol"; import "../bridge/ISequencerInbox.sol"; import "../osp/IOneStepProofEntry.sol"; import "./IChallengeResultReceiver.sol"; import "./ChallengeLib.sol"; interface IChallengeManager { enum ChallengeTerminationType { TIMEOUT, BLOCK_PROOF, EXECUTION_PROOF, CLEARED } event InitiatedChallenge( uint64 indexed challengeIndex, GlobalState startState, GlobalState endState ); event Bisected( uint64 indexed challengeIndex, bytes32 indexed challengeRoot, uint256 challengedSegmentStart, uint256 challengedSegmentLength, bytes32[] chainHashes ); event ExecutionChallengeBegun(uint64 indexed challengeIndex, uint256 blockSteps); event OneStepProofCompleted(uint64 indexed challengeIndex); event ChallengeEnded(uint64 indexed challengeIndex, ChallengeTerminationType kind); function initialize( IChallengeResultReceiver resultReceiver_, ISequencerInbox sequencerInbox_, IBridge bridge_, IOneStepProofEntry osp_ ) external; function createChallenge( bytes32 wasmModuleRoot_, MachineStatus[2] calldata startAndEndMachineStatuses_, GlobalState[2] calldata startAndEndGlobalStates_, uint64 numBlocks, address asserter_, address challenger_, uint256 asserterTimeLeft_, uint256 challengerTimeLeft_ ) external returns (uint64); function challengeInfo(uint64 challengeIndex_) external view returns (ChallengeLib.Challenge memory); function currentResponder(uint64 challengeIndex) external view returns (address); function isTimedOut(uint64 challengeIndex) external view returns (bool); function currentResponderTimeLeft(uint64 challengeIndex_) external view returns (uint256); function clearChallenge(uint64 challengeIndex_) external; function timeout(uint64 challengeIndex_) external; }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "../state/Machine.sol"; import "../state/GlobalState.sol"; library ChallengeLib { using MachineLib for Machine; using ChallengeLib for Challenge; /// @dev It's assumed that that uninitialzed challenges have mode NONE enum ChallengeMode { NONE, BLOCK, EXECUTION } struct Participant { address addr; uint256 timeLeft; } struct Challenge { Participant current; Participant next; uint256 lastMoveTimestamp; bytes32 wasmModuleRoot; bytes32 challengeStateHash; uint64 maxInboxMessages; ChallengeMode mode; } struct SegmentSelection { uint256 oldSegmentsStart; uint256 oldSegmentsLength; bytes32[] oldSegments; uint256 challengePosition; } function timeUsedSinceLastMove(Challenge storage challenge) internal view returns (uint256) { return block.timestamp - challenge.lastMoveTimestamp; } function isTimedOut(Challenge storage challenge) internal view returns (bool) { return challenge.timeUsedSinceLastMove() > challenge.current.timeLeft; } function getStartMachineHash(bytes32 globalStateHash, bytes32 wasmModuleRoot) internal pure returns (bytes32) { // Start the value stack with the function call ABI for the entrypoint Value[] memory startingValues = new Value[](3); startingValues[0] = ValueLib.newRefNull(); startingValues[1] = ValueLib.newI32(0); startingValues[2] = ValueLib.newI32(0); ValueArray memory valuesArray = ValueArray({inner: startingValues}); ValueStack memory values = ValueStack({proved: valuesArray, remainingHash: 0}); ValueStack memory internalStack; StackFrameWindow memory frameStack; Machine memory mach = Machine({ status: MachineStatus.RUNNING, valueStack: values, internalStack: internalStack, frameStack: frameStack, globalStateHash: globalStateHash, moduleIdx: 0, functionIdx: 0, functionPc: 0, modulesRoot: wasmModuleRoot }); return mach.hash(); } function getEndMachineHash(MachineStatus status, bytes32 globalStateHash) internal pure returns (bytes32) { if (status == MachineStatus.FINISHED) { return keccak256(abi.encodePacked("Machine finished:", globalStateHash)); } else if (status == MachineStatus.ERRORED) { return keccak256(abi.encodePacked("Machine errored:")); } else if (status == MachineStatus.TOO_FAR) { return keccak256(abi.encodePacked("Machine too far:")); } else { revert("BAD_BLOCK_STATUS"); } } function extractChallengeSegment(SegmentSelection calldata selection) internal pure returns (uint256 segmentStart, uint256 segmentLength) { uint256 oldChallengeDegree = selection.oldSegments.length - 1; segmentLength = selection.oldSegmentsLength / oldChallengeDegree; // Intentionally done before challengeLength is potentially added to for the final segment segmentStart = selection.oldSegmentsStart + segmentLength * selection.challengePosition; if (selection.challengePosition == selection.oldSegments.length - 2) { segmentLength += selection.oldSegmentsLength % oldChallengeDegree; } } function hashChallengeState( uint256 segmentsStart, uint256 segmentsLength, bytes32[] memory segments ) internal pure returns (bytes32) { return keccak256(abi.encodePacked(segmentsStart, segmentsLength, segments)); } function blockStateHash(MachineStatus status, bytes32 globalStateHash) internal pure returns (bytes32) { if (status == MachineStatus.FINISHED) { return keccak256(abi.encodePacked("Block state:", globalStateHash)); } else if (status == MachineStatus.ERRORED) { return keccak256(abi.encodePacked("Block state, errored:", globalStateHash)); } else if (status == MachineStatus.TOO_FAR) { return keccak256(abi.encodePacked("Block state, too far:")); } else { revert("BAD_BLOCK_STATUS"); } } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; struct GlobalState { bytes32[2] bytes32Vals; uint64[2] u64Vals; } library GlobalStateLib { uint16 internal constant BYTES32_VALS_NUM = 2; uint16 internal constant U64_VALS_NUM = 2; function hash(GlobalState memory state) internal pure returns (bytes32) { return keccak256( abi.encodePacked( "Global state:", state.bytes32Vals[0], state.bytes32Vals[1], state.u64Vals[0], state.u64Vals[1] ) ); } function getBlockHash(GlobalState memory state) internal pure returns (bytes32) { return state.bytes32Vals[0]; } function getSendRoot(GlobalState memory state) internal pure returns (bytes32) { return state.bytes32Vals[1]; } function getInboxPosition(GlobalState memory state) internal pure returns (uint64) { return state.u64Vals[0]; } function getPositionInMessage(GlobalState memory state) internal pure returns (uint64) { return state.u64Vals[1]; } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "../bridge/IBridge.sol"; interface IRollupEventInbox { function bridge() external view returns (IBridge); function initialize(IBridge _bridge) external; function rollup() external view returns (address); function rollupInitialized(uint256 chainId) external; }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./ValueStack.sol"; import "./Instructions.sol"; import "./StackFrame.sol"; enum MachineStatus { RUNNING, FINISHED, ERRORED, TOO_FAR } struct Machine { MachineStatus status; ValueStack valueStack; ValueStack internalStack; StackFrameWindow frameStack; bytes32 globalStateHash; uint32 moduleIdx; uint32 functionIdx; uint32 functionPc; bytes32 modulesRoot; } library MachineLib { using StackFrameLib for StackFrameWindow; using ValueStackLib for ValueStack; function hash(Machine memory mach) internal pure returns (bytes32) { // Warning: the non-running hashes are replicated in Challenge if (mach.status == MachineStatus.RUNNING) { return keccak256( abi.encodePacked( "Machine running:", mach.valueStack.hash(), mach.internalStack.hash(), mach.frameStack.hash(), mach.globalStateHash, mach.moduleIdx, mach.functionIdx, mach.functionPc, mach.modulesRoot ) ); } else if (mach.status == MachineStatus.FINISHED) { return keccak256(abi.encodePacked("Machine finished:", mach.globalStateHash)); } else if (mach.status == MachineStatus.ERRORED) { return keccak256(abi.encodePacked("Machine errored:")); } else if (mach.status == MachineStatus.TOO_FAR) { return keccak256(abi.encodePacked("Machine too far:")); } else { revert("BAD_MACH_STATUS"); } } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./IOneStepProver.sol"; library OneStepProofEntryLib { uint256 internal constant MAX_STEPS = 1 << 43; } interface IOneStepProofEntry { function proveOneStep( ExecutionContext calldata execCtx, uint256 machineStep, bytes32 beforeHash, bytes calldata proof ) external view returns (bytes32 afterHash); }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; interface IChallengeResultReceiver { function completeChallenge( uint256 challengeIndex, address winner, address loser ) external; }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./Value.sol"; import "./ValueArray.sol"; struct ValueStack { ValueArray proved; bytes32 remainingHash; } library ValueStackLib { using ValueLib for Value; using ValueArrayLib for ValueArray; function hash(ValueStack memory stack) internal pure returns (bytes32 h) { h = stack.remainingHash; uint256 len = stack.proved.length(); for (uint256 i = 0; i < len; i++) { h = keccak256(abi.encodePacked("Value stack:", stack.proved.get(i).hash(), h)); } } function peek(ValueStack memory stack) internal pure returns (Value memory) { uint256 len = stack.proved.length(); return stack.proved.get(len - 1); } function pop(ValueStack memory stack) internal pure returns (Value memory) { return stack.proved.pop(); } function push(ValueStack memory stack, Value memory val) internal pure { return stack.proved.push(val); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; struct Instruction { uint16 opcode; uint256 argumentData; } library Instructions { uint16 internal constant UNREACHABLE = 0x00; uint16 internal constant NOP = 0x01; uint16 internal constant RETURN = 0x0F; uint16 internal constant CALL = 0x10; uint16 internal constant CALL_INDIRECT = 0x11; uint16 internal constant LOCAL_GET = 0x20; uint16 internal constant LOCAL_SET = 0x21; uint16 internal constant GLOBAL_GET = 0x23; uint16 internal constant GLOBAL_SET = 0x24; uint16 internal constant I32_LOAD = 0x28; uint16 internal constant I64_LOAD = 0x29; uint16 internal constant F32_LOAD = 0x2A; uint16 internal constant F64_LOAD = 0x2B; uint16 internal constant I32_LOAD8_S = 0x2C; uint16 internal constant I32_LOAD8_U = 0x2D; uint16 internal constant I32_LOAD16_S = 0x2E; uint16 internal constant I32_LOAD16_U = 0x2F; uint16 internal constant I64_LOAD8_S = 0x30; uint16 internal constant I64_LOAD8_U = 0x31; uint16 internal constant I64_LOAD16_S = 0x32; uint16 internal constant I64_LOAD16_U = 0x33; uint16 internal constant I64_LOAD32_S = 0x34; uint16 internal constant I64_LOAD32_U = 0x35; uint16 internal constant I32_STORE = 0x36; uint16 internal constant I64_STORE = 0x37; uint16 internal constant F32_STORE = 0x38; uint16 internal constant F64_STORE = 0x39; uint16 internal constant I32_STORE8 = 0x3A; uint16 internal constant I32_STORE16 = 0x3B; uint16 internal constant I64_STORE8 = 0x3C; uint16 internal constant I64_STORE16 = 0x3D; uint16 internal constant I64_STORE32 = 0x3E; uint16 internal constant MEMORY_SIZE = 0x3F; uint16 internal constant MEMORY_GROW = 0x40; uint16 internal constant DROP = 0x1A; uint16 internal constant SELECT = 0x1B; uint16 internal constant I32_CONST = 0x41; uint16 internal constant I64_CONST = 0x42; uint16 internal constant F32_CONST = 0x43; uint16 internal constant F64_CONST = 0x44; uint16 internal constant I32_EQZ = 0x45; uint16 internal constant I32_RELOP_BASE = 0x46; uint16 internal constant IRELOP_EQ = 0; uint16 internal constant IRELOP_NE = 1; uint16 internal constant IRELOP_LT_S = 2; uint16 internal constant IRELOP_LT_U = 3; uint16 internal constant IRELOP_GT_S = 4; uint16 internal constant IRELOP_GT_U = 5; uint16 internal constant IRELOP_LE_S = 6; uint16 internal constant IRELOP_LE_U = 7; uint16 internal constant IRELOP_GE_S = 8; uint16 internal constant IRELOP_GE_U = 9; uint16 internal constant IRELOP_LAST = IRELOP_GE_U; uint16 internal constant I64_EQZ = 0x50; uint16 internal constant I64_RELOP_BASE = 0x51; uint16 internal constant I32_UNOP_BASE = 0x67; uint16 internal constant IUNOP_CLZ = 0; uint16 internal constant IUNOP_CTZ = 1; uint16 internal constant IUNOP_POPCNT = 2; uint16 internal constant IUNOP_LAST = IUNOP_POPCNT; uint16 internal constant I32_ADD = 0x6A; uint16 internal constant I32_SUB = 0x6B; uint16 internal constant I32_MUL = 0x6C; uint16 internal constant I32_DIV_S = 0x6D; uint16 internal constant I32_DIV_U = 0x6E; uint16 internal constant I32_REM_S = 0x6F; uint16 internal constant I32_REM_U = 0x70; uint16 internal constant I32_AND = 0x71; uint16 internal constant I32_OR = 0x72; uint16 internal constant I32_XOR = 0x73; uint16 internal constant I32_SHL = 0x74; uint16 internal constant I32_SHR_S = 0x75; uint16 internal constant I32_SHR_U = 0x76; uint16 internal constant I32_ROTL = 0x77; uint16 internal constant I32_ROTR = 0x78; uint16 internal constant I64_UNOP_BASE = 0x79; uint16 internal constant I64_ADD = 0x7C; uint16 internal constant I64_SUB = 0x7D; uint16 internal constant I64_MUL = 0x7E; uint16 internal constant I64_DIV_S = 0x7F; uint16 internal constant I64_DIV_U = 0x80; uint16 internal constant I64_REM_S = 0x81; uint16 internal constant I64_REM_U = 0x82; uint16 internal constant I64_AND = 0x83; uint16 internal constant I64_OR = 0x84; uint16 internal constant I64_XOR = 0x85; uint16 internal constant I64_SHL = 0x86; uint16 internal constant I64_SHR_S = 0x87; uint16 internal constant I64_SHR_U = 0x88; uint16 internal constant I64_ROTL = 0x89; uint16 internal constant I64_ROTR = 0x8A; uint16 internal constant I32_WRAP_I64 = 0xA7; uint16 internal constant I64_EXTEND_I32_S = 0xAC; uint16 internal constant I64_EXTEND_I32_U = 0xAD; uint16 internal constant I32_REINTERPRET_F32 = 0xBC; uint16 internal constant I64_REINTERPRET_F64 = 0xBD; uint16 internal constant F32_REINTERPRET_I32 = 0xBE; uint16 internal constant F64_REINTERPRET_I64 = 0xBF; uint16 internal constant I32_EXTEND_8S = 0xC0; uint16 internal constant I32_EXTEND_16S = 0xC1; uint16 internal constant I64_EXTEND_8S = 0xC2; uint16 internal constant I64_EXTEND_16S = 0xC3; uint16 internal constant I64_EXTEND_32S = 0xC4; uint16 internal constant INIT_FRAME = 0x8002; uint16 internal constant ARBITRARY_JUMP = 0x8003; uint16 internal constant ARBITRARY_JUMP_IF = 0x8004; uint16 internal constant MOVE_FROM_STACK_TO_INTERNAL = 0x8005; uint16 internal constant MOVE_FROM_INTERNAL_TO_STACK = 0x8006; uint16 internal constant DUP = 0x8008; uint16 internal constant CROSS_MODULE_CALL = 0x8009; uint16 internal constant CALLER_MODULE_INTERNAL_CALL = 0x800A; uint16 internal constant GET_GLOBAL_STATE_BYTES32 = 0x8010; uint16 internal constant SET_GLOBAL_STATE_BYTES32 = 0x8011; uint16 internal constant GET_GLOBAL_STATE_U64 = 0x8012; uint16 internal constant SET_GLOBAL_STATE_U64 = 0x8013; uint16 internal constant READ_PRE_IMAGE = 0x8020; uint16 internal constant READ_INBOX_MESSAGE = 0x8021; uint16 internal constant HALT_AND_SET_FINISHED = 0x8022; uint256 internal constant INBOX_INDEX_SEQUENCER = 0; uint256 internal constant INBOX_INDEX_DELAYED = 1; function hash(Instruction memory inst) internal pure returns (bytes32) { return keccak256(abi.encodePacked("Instruction:", inst.opcode, inst.argumentData)); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./Value.sol"; struct StackFrame { Value returnPc; bytes32 localsMerkleRoot; uint32 callerModule; uint32 callerModuleInternals; } struct StackFrameWindow { StackFrame[] proved; bytes32 remainingHash; } library StackFrameLib { using ValueLib for Value; function hash(StackFrame memory frame) internal pure returns (bytes32) { return keccak256( abi.encodePacked( "Stack frame:", frame.returnPc.hash(), frame.localsMerkleRoot, frame.callerModule, frame.callerModuleInternals ) ); } function hash(StackFrameWindow memory window) internal pure returns (bytes32 h) { h = window.remainingHash; for (uint256 i = 0; i < window.proved.length; i++) { h = keccak256(abi.encodePacked("Stack frame stack:", hash(window.proved[i]), h)); } } function peek(StackFrameWindow memory window) internal pure returns (StackFrame memory) { require(window.proved.length == 1, "BAD_WINDOW_LENGTH"); return window.proved[0]; } function pop(StackFrameWindow memory window) internal pure returns (StackFrame memory frame) { require(window.proved.length == 1, "BAD_WINDOW_LENGTH"); frame = window.proved[0]; window.proved = new StackFrame[](0); } function push(StackFrameWindow memory window, StackFrame memory frame) internal pure { StackFrame[] memory newProved = new StackFrame[](window.proved.length + 1); for (uint256 i = 0; i < window.proved.length; i++) { newProved[i] = window.proved[i]; } newProved[window.proved.length] = frame; window.proved = newProved; } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; enum ValueType { I32, I64, F32, F64, REF_NULL, FUNC_REF, INTERNAL_REF } struct Value { ValueType valueType; uint256 contents; } library ValueLib { function hash(Value memory val) internal pure returns (bytes32) { return keccak256(abi.encodePacked("Value:", val.valueType, val.contents)); } function maxValueType() internal pure returns (ValueType) { return ValueType.INTERNAL_REF; } function assumeI32(Value memory val) internal pure returns (uint32) { uint256 uintval = uint256(val.contents); require(val.valueType == ValueType.I32, "NOT_I32"); require(uintval < (1 << 32), "BAD_I32"); return uint32(uintval); } function assumeI64(Value memory val) internal pure returns (uint64) { uint256 uintval = uint256(val.contents); require(val.valueType == ValueType.I64, "NOT_I64"); require(uintval < (1 << 64), "BAD_I64"); return uint64(uintval); } function newRefNull() internal pure returns (Value memory) { return Value({valueType: ValueType.REF_NULL, contents: 0}); } function newI32(uint32 x) internal pure returns (Value memory) { return Value({valueType: ValueType.I32, contents: uint256(x)}); } function newI64(uint64 x) internal pure returns (Value memory) { return Value({valueType: ValueType.I64, contents: uint256(x)}); } function newBoolean(bool x) internal pure returns (Value memory) { if (x) { return newI32(uint32(1)); } else { return newI32(uint32(0)); } } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./Value.sol"; struct ValueArray { Value[] inner; } library ValueArrayLib { function get(ValueArray memory arr, uint256 index) internal pure returns (Value memory) { return arr.inner[index]; } function set( ValueArray memory arr, uint256 index, Value memory val ) internal pure { arr.inner[index] = val; } function length(ValueArray memory arr) internal pure returns (uint256) { return arr.inner.length; } function push(ValueArray memory arr, Value memory val) internal pure { Value[] memory newInner = new Value[](arr.inner.length + 1); for (uint256 i = 0; i < arr.inner.length; i++) { newInner[i] = arr.inner[i]; } newInner[arr.inner.length] = val; arr.inner = newInner; } function pop(ValueArray memory arr) internal pure returns (Value memory popped) { popped = arr.inner[arr.inner.length - 1]; Value[] memory newInner = new Value[](arr.inner.length - 1); for (uint256 i = 0; i < newInner.length; i++) { newInner[i] = arr.inner[i]; } arr.inner = newInner; } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "../state/Machine.sol"; import "../state/Module.sol"; import "../state/Instructions.sol"; import "../bridge/ISequencerInbox.sol"; import "../bridge/IBridge.sol"; struct ExecutionContext { uint256 maxInboxMessagesRead; IBridge bridge; } abstract contract IOneStepProver { function executeOneStep( ExecutionContext memory execCtx, Machine calldata mach, Module calldata mod, Instruction calldata instruction, bytes calldata proof ) external view virtual returns (Machine memory result, Module memory resultMod); }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./ModuleMemory.sol"; struct Module { bytes32 globalsMerkleRoot; ModuleMemory moduleMemory; bytes32 tablesMerkleRoot; bytes32 functionsMerkleRoot; uint32 internalsOffset; } library ModuleLib { using ModuleMemoryLib for ModuleMemory; function hash(Module memory mod) internal pure returns (bytes32) { return keccak256( abi.encodePacked( "Module:", mod.globalsMerkleRoot, mod.moduleMemory.hash(), mod.tablesMerkleRoot, mod.functionsMerkleRoot, mod.internalsOffset ) ); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./MerkleProof.sol"; import "./Deserialize.sol"; struct ModuleMemory { uint64 size; uint64 maxSize; bytes32 merkleRoot; } library ModuleMemoryLib { using MerkleProofLib for MerkleProof; function hash(ModuleMemory memory mem) internal pure returns (bytes32) { return keccak256(abi.encodePacked("Memory:", mem.size, mem.maxSize, mem.merkleRoot)); } function proveLeaf( ModuleMemory memory mem, uint256 leafIdx, bytes calldata proof, uint256 startOffset ) internal pure returns ( bytes32 contents, uint256 offset, MerkleProof memory merkle ) { offset = startOffset; (contents, offset) = Deserialize.b32(proof, offset); (merkle, offset) = Deserialize.merkleProof(proof, offset); bytes32 recomputedRoot = merkle.computeRootFromMemory(leafIdx, contents); require(recomputedRoot == mem.merkleRoot, "WRONG_MEM_ROOT"); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./Value.sol"; import "./Instructions.sol"; import "./Module.sol"; struct MerkleProof { bytes32[] counterparts; } library MerkleProofLib { using ModuleLib for Module; using ValueLib for Value; function computeRootFromValue( MerkleProof memory proof, uint256 index, Value memory leaf ) internal pure returns (bytes32) { return computeRootUnsafe(proof, index, leaf.hash(), "Value merkle tree:"); } function computeRootFromInstruction( MerkleProof memory proof, uint256 index, Instruction memory inst ) internal pure returns (bytes32) { return computeRootUnsafe(proof, index, Instructions.hash(inst), "Instruction merkle tree:"); } function computeRootFromFunction( MerkleProof memory proof, uint256 index, bytes32 codeRoot ) internal pure returns (bytes32) { bytes32 h = keccak256(abi.encodePacked("Function:", codeRoot)); return computeRootUnsafe(proof, index, h, "Function merkle tree:"); } function computeRootFromMemory( MerkleProof memory proof, uint256 index, bytes32 contents ) internal pure returns (bytes32) { bytes32 h = keccak256(abi.encodePacked("Memory leaf:", contents)); return computeRootUnsafe(proof, index, h, "Memory merkle tree:"); } function computeRootFromElement( MerkleProof memory proof, uint256 index, bytes32 funcTypeHash, Value memory val ) internal pure returns (bytes32) { bytes32 h = keccak256(abi.encodePacked("Table element:", funcTypeHash, val.hash())); return computeRootUnsafe(proof, index, h, "Table element merkle tree:"); } function computeRootFromTable( MerkleProof memory proof, uint256 index, uint8 tableType, uint64 tableSize, bytes32 elementsRoot ) internal pure returns (bytes32) { bytes32 h = keccak256(abi.encodePacked("Table:", tableType, tableSize, elementsRoot)); return computeRootUnsafe(proof, index, h, "Table merkle tree:"); } function computeRootFromModule( MerkleProof memory proof, uint256 index, Module memory mod ) internal pure returns (bytes32) { return computeRootUnsafe(proof, index, mod.hash(), "Module merkle tree:"); } // WARNING: leafHash must be computed in such a way that it cannot be a non-leaf hash. function computeRootUnsafe( MerkleProof memory proof, uint256 index, bytes32 leafHash, string memory prefix ) internal pure returns (bytes32 h) { h = leafHash; for (uint256 layer = 0; layer < proof.counterparts.length; layer++) { if (index & 1 == 0) { h = keccak256(abi.encodePacked(prefix, h, proof.counterparts[layer])); } else { h = keccak256(abi.encodePacked(prefix, proof.counterparts[layer], h)); } index >>= 1; } } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./Value.sol"; import "./ValueStack.sol"; import "./Machine.sol"; import "./Instructions.sol"; import "./StackFrame.sol"; import "./MerkleProof.sol"; import "./ModuleMemory.sol"; import "./Module.sol"; import "./GlobalState.sol"; library Deserialize { function u8(bytes calldata proof, uint256 startOffset) internal pure returns (uint8 ret, uint256 offset) { offset = startOffset; ret = uint8(proof[offset]); offset++; } function u16(bytes calldata proof, uint256 startOffset) internal pure returns (uint16 ret, uint256 offset) { offset = startOffset; for (uint256 i = 0; i < 16 / 8; i++) { ret <<= 8; ret |= uint8(proof[offset]); offset++; } } function u32(bytes calldata proof, uint256 startOffset) internal pure returns (uint32 ret, uint256 offset) { offset = startOffset; for (uint256 i = 0; i < 32 / 8; i++) { ret <<= 8; ret |= uint8(proof[offset]); offset++; } } function u64(bytes calldata proof, uint256 startOffset) internal pure returns (uint64 ret, uint256 offset) { offset = startOffset; for (uint256 i = 0; i < 64 / 8; i++) { ret <<= 8; ret |= uint8(proof[offset]); offset++; } } function u256(bytes calldata proof, uint256 startOffset) internal pure returns (uint256 ret, uint256 offset) { offset = startOffset; for (uint256 i = 0; i < 256 / 8; i++) { ret <<= 8; ret |= uint8(proof[offset]); offset++; } } function b32(bytes calldata proof, uint256 startOffset) internal pure returns (bytes32 ret, uint256 offset) { offset = startOffset; uint256 retInt; (retInt, offset) = u256(proof, offset); ret = bytes32(retInt); } function value(bytes calldata proof, uint256 startOffset) internal pure returns (Value memory val, uint256 offset) { offset = startOffset; uint8 typeInt = uint8(proof[offset]); offset++; require(typeInt <= uint8(ValueLib.maxValueType()), "BAD_VALUE_TYPE"); uint256 contents; (contents, offset) = u256(proof, offset); val = Value({valueType: ValueType(typeInt), contents: contents}); } function valueStack(bytes calldata proof, uint256 startOffset) internal pure returns (ValueStack memory stack, uint256 offset) { offset = startOffset; bytes32 remainingHash; (remainingHash, offset) = b32(proof, offset); uint256 provedLength; (provedLength, offset) = u256(proof, offset); Value[] memory proved = new Value[](provedLength); for (uint256 i = 0; i < proved.length; i++) { (proved[i], offset) = value(proof, offset); } stack = ValueStack({proved: ValueArray(proved), remainingHash: remainingHash}); } function instruction(bytes calldata proof, uint256 startOffset) internal pure returns (Instruction memory inst, uint256 offset) { offset = startOffset; uint16 opcode; uint256 data; (opcode, offset) = u16(proof, offset); (data, offset) = u256(proof, offset); inst = Instruction({opcode: opcode, argumentData: data}); } function stackFrame(bytes calldata proof, uint256 startOffset) internal pure returns (StackFrame memory window, uint256 offset) { offset = startOffset; Value memory returnPc; bytes32 localsMerkleRoot; uint32 callerModule; uint32 callerModuleInternals; (returnPc, offset) = value(proof, offset); (localsMerkleRoot, offset) = b32(proof, offset); (callerModule, offset) = u32(proof, offset); (callerModuleInternals, offset) = u32(proof, offset); window = StackFrame({ returnPc: returnPc, localsMerkleRoot: localsMerkleRoot, callerModule: callerModule, callerModuleInternals: callerModuleInternals }); } function stackFrameWindow(bytes calldata proof, uint256 startOffset) internal pure returns (StackFrameWindow memory window, uint256 offset) { offset = startOffset; bytes32 remainingHash; (remainingHash, offset) = b32(proof, offset); StackFrame[] memory proved; if (proof[offset] != 0) { offset++; proved = new StackFrame[](1); (proved[0], offset) = stackFrame(proof, offset); } else { offset++; proved = new StackFrame[](0); } window = StackFrameWindow({proved: proved, remainingHash: remainingHash}); } function moduleMemory(bytes calldata proof, uint256 startOffset) internal pure returns (ModuleMemory memory mem, uint256 offset) { offset = startOffset; uint64 size; uint64 maxSize; bytes32 root; (size, offset) = u64(proof, offset); (maxSize, offset) = u64(proof, offset); (root, offset) = b32(proof, offset); mem = ModuleMemory({size: size, maxSize: maxSize, merkleRoot: root}); } function module(bytes calldata proof, uint256 startOffset) internal pure returns (Module memory mod, uint256 offset) { offset = startOffset; bytes32 globalsMerkleRoot; ModuleMemory memory mem; bytes32 tablesMerkleRoot; bytes32 functionsMerkleRoot; uint32 internalsOffset; (globalsMerkleRoot, offset) = b32(proof, offset); (mem, offset) = moduleMemory(proof, offset); (tablesMerkleRoot, offset) = b32(proof, offset); (functionsMerkleRoot, offset) = b32(proof, offset); (internalsOffset, offset) = u32(proof, offset); mod = Module({ globalsMerkleRoot: globalsMerkleRoot, moduleMemory: mem, tablesMerkleRoot: tablesMerkleRoot, functionsMerkleRoot: functionsMerkleRoot, internalsOffset: internalsOffset }); } function globalState(bytes calldata proof, uint256 startOffset) internal pure returns (GlobalState memory state, uint256 offset) { offset = startOffset; // using constant ints for array size requires newer solidity bytes32[2] memory bytes32Vals; uint64[2] memory u64Vals; for (uint8 i = 0; i < GlobalStateLib.BYTES32_VALS_NUM; i++) { (bytes32Vals[i], offset) = b32(proof, offset); } for (uint8 i = 0; i < GlobalStateLib.U64_VALS_NUM; i++) { (u64Vals[i], offset) = u64(proof, offset); } state = GlobalState({bytes32Vals: bytes32Vals, u64Vals: u64Vals}); } function machine(bytes calldata proof, uint256 startOffset) internal pure returns (Machine memory mach, uint256 offset) { offset = startOffset; MachineStatus status; { uint8 statusU8; (statusU8, offset) = u8(proof, offset); if (statusU8 == 0) { status = MachineStatus.RUNNING; } else if (statusU8 == 1) { status = MachineStatus.FINISHED; } else if (statusU8 == 2) { status = MachineStatus.ERRORED; } else if (statusU8 == 3) { status = MachineStatus.TOO_FAR; } else { revert("UNKNOWN_MACH_STATUS"); } } ValueStack memory values; ValueStack memory internalStack; bytes32 globalStateHash; uint32 moduleIdx; uint32 functionIdx; uint32 functionPc; StackFrameWindow memory frameStack; bytes32 modulesRoot; (values, offset) = valueStack(proof, offset); (internalStack, offset) = valueStack(proof, offset); (frameStack, offset) = stackFrameWindow(proof, offset); (globalStateHash, offset) = b32(proof, offset); (moduleIdx, offset) = u32(proof, offset); (functionIdx, offset) = u32(proof, offset); (functionPc, offset) = u32(proof, offset); (modulesRoot, offset) = b32(proof, offset); mach = Machine({ status: status, valueStack: values, internalStack: internalStack, frameStack: frameStack, globalStateHash: globalStateHash, moduleIdx: moduleIdx, functionIdx: functionIdx, functionPc: functionPc, modulesRoot: modulesRoot }); } function merkleProof(bytes calldata proof, uint256 startOffset) internal pure returns (MerkleProof memory merkle, uint256 offset) { offset = startOffset; uint8 length; (length, offset) = u8(proof, offset); bytes32[] memory counterparts = new bytes32[](length); for (uint8 i = 0; i < length; i++) { (counterparts[i], offset) = b32(proof, offset); } merkle = MerkleProof(counterparts); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; struct Node { // Hash of the state of the chain as of this node bytes32 stateHash; // Hash of the data that can be challenged bytes32 challengeHash; // Hash of the data that will be committed if this node is confirmed bytes32 confirmData; // Index of the node previous to this one uint64 prevNum; // Deadline at which this node can be confirmed uint64 deadlineBlock; // Deadline at which a child of this node can be confirmed uint64 noChildConfirmedBeforeBlock; // Number of stakers staked on this node. This includes real stakers and zombies uint64 stakerCount; // Number of stakers staked on a child node. This includes real stakers and zombies uint64 childStakerCount; // This value starts at zero and is set to a value when the first child is created. After that it is constant until the node is destroyed or the owner destroys pending nodes uint64 firstChildBlock; // The number of the latest child of this node to be created uint64 latestChildNumber; // The block number when this node was created uint64 createdAtBlock; // A hash of all the data needed to determine this node's validity, to protect against reorgs bytes32 nodeHash; } /** * @notice Utility functions for Node */ library NodeLib { /** * @notice Initialize a Node * @param _stateHash Initial value of stateHash * @param _challengeHash Initial value of challengeHash * @param _confirmData Initial value of confirmData * @param _prevNum Initial value of prevNum * @param _deadlineBlock Initial value of deadlineBlock * @param _nodeHash Initial value of nodeHash */ function createNode( bytes32 _stateHash, bytes32 _challengeHash, bytes32 _confirmData, uint64 _prevNum, uint64 _deadlineBlock, bytes32 _nodeHash ) internal view returns (Node memory) { Node memory node; node.stateHash = _stateHash; node.challengeHash = _challengeHash; node.confirmData = _confirmData; node.prevNum = _prevNum; node.deadlineBlock = _deadlineBlock; node.noChildConfirmedBeforeBlock = _deadlineBlock; node.createdAtBlock = uint64(block.number); node.nodeHash = _nodeHash; return node; } /** * @notice Update child properties * @param number The child number to set */ function childCreated(Node storage self, uint64 number) internal { if (self.firstChildBlock == 0) { self.firstChildBlock = uint64(block.number); } self.latestChildNumber = number; } /** * @notice Update the child confirmed deadline * @param deadline The new deadline to set */ function newChildConfirmDeadline(Node storage self, uint64 deadline) internal { self.noChildConfirmedBeforeBlock = deadline; } /** * @notice Check whether the current block number has met or passed the node's deadline */ function requirePastDeadline(Node memory self) internal view { require(block.number >= self.deadlineBlock, "BEFORE_DEADLINE"); } /** * @notice Check whether the current block number has met or passed deadline for children of this node to be confirmed */ function requirePastChildConfirmDeadline(Node memory self) internal view { require(block.number >= self.noChildConfirmedBeforeBlock, "CHILD_TOO_RECENT"); } }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; library AddressAliasHelper { uint160 internal constant OFFSET = uint160(0x1111000000000000000000000000000000001111); /// @notice Utility function that converts the address in the L1 that submitted a tx to /// the inbox to the msg.sender viewed in the L2 /// @param l1Address the address in the L1 that triggered the tx to L2 /// @return l2Address L2 address as viewed in msg.sender function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) { unchecked { l2Address = address(uint160(l1Address) + OFFSET); } } /// @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) { unchecked { l1Address = address(uint160(l2Address) - OFFSET); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.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 PausableUpgradeable is Initializable, ContextUpgradeable { /** * @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. */ function __Pausable_init() internal onlyInitializing { __Pausable_init_unchained(); } function __Pausable_init_unchained() internal onlyInitializing { _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()); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/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 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 onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.4; import {MerkleProofTooLong} from "./Error.sol"; 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; if (proofItems > 256) revert MerkleProofTooLong(proofItems, 256); bytes32 h = item; for (uint256 i = 0; i < proofItems; i++) { bytes32 node = nodes[i]; if (route % 2 == 0) { assembly { mstore(0x00, h) mstore(0x20, node) h := keccak256(0x00, 0x40) } } else { assembly { mstore(0x00, node) mstore(0x20, h) h := keccak256(0x00, 0x40) } } route /= 2; } return h; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^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 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) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol) pragma solidity ^0.8.0; import "../ERC1967/ERC1967Proxy.sol"; /** * @dev This contract implements a proxy that is upgradeable by an admin. * * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector * clashing], which can potentially be used in an attack, this contract uses the * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two * things that go hand in hand: * * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if * that call matches one of the admin functions exposed by the proxy itself. * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the * implementation. If the admin tries to call a function on the implementation it will fail with an error that says * "admin cannot fallback to proxy target". * * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due * to sudden errors when trying to call a function from the proxy implementation. * * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy. */ contract TransparentUpgradeableProxy is ERC1967Proxy { /** * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}. */ constructor( address _logic, address admin_, bytes memory _data ) payable ERC1967Proxy(_logic, _data) { assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1)); _changeAdmin(admin_); } /** * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin. */ modifier ifAdmin() { if (msg.sender == _getAdmin()) { _; } else { _fallback(); } } /** * @dev Returns the current admin. * * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function admin() external ifAdmin returns (address admin_) { admin_ = _getAdmin(); } /** * @dev Returns the current implementation. * * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` */ function implementation() external ifAdmin returns (address implementation_) { implementation_ = _implementation(); } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. * * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}. */ function changeAdmin(address newAdmin) external virtual ifAdmin { _changeAdmin(newAdmin); } /** * @dev Upgrade the implementation of the proxy. * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}. */ function upgradeTo(address newImplementation) external ifAdmin { _upgradeToAndCall(newImplementation, bytes(""), false); } /** * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the * proxied contract. * * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}. */ function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin { _upgradeToAndCall(newImplementation, data, true); } /** * @dev Returns the current admin. */ function _admin() internal view virtual returns (address) { return _getAdmin(); } /** * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}. */ function _beforeFallback() internal virtual override { require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target"); super._beforeFallback(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol) pragma solidity ^0.8.0; import "../Proxy.sol"; import "./ERC1967Upgrade.sol"; /** * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an * implementation address that can be changed. This address is stored in storage in the location specified by * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the * implementation behind the proxy. */ contract ERC1967Proxy is Proxy, ERC1967Upgrade { /** * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`. * * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded * function call, and allows initializating the storage of the proxy like a Solidity constructor. */ constructor(address _logic, bytes memory _data) payable { assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1)); _upgradeToAndCall(_logic, _data, false); } /** * @dev Returns the current implementation address. */ function _implementation() internal view virtual override returns (address impl) { return ERC1967Upgrade._getImplementation(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/Proxy.sol) pragma solidity ^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 internal call site, it will return directly to the external caller. */ function _delegate(address implementation) internal virtual { 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 // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../interfaces/draft-IERC1822.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967Upgrade { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @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 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^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 // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @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 * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 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"); (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"); (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"); (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"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal 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 assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly { r.slot := slot } } }
{ "optimizer": { "enabled": true, "runs": 100 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"TemplatesUpdated","type":"event"},{"inputs":[],"name":"bridgeTemplate","outputs":[{"internalType":"contract Bridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"adminProxy","type":"address"},{"internalType":"address","name":"rollup","type":"address"},{"components":[{"internalType":"uint256","name":"delayBlocks","type":"uint256"},{"internalType":"uint256","name":"futureBlocks","type":"uint256"},{"internalType":"uint256","name":"delaySeconds","type":"uint256"},{"internalType":"uint256","name":"futureSeconds","type":"uint256"}],"internalType":"struct ISequencerInbox.MaxTimeVariation","name":"maxTimeVariation","type":"tuple"}],"name":"createBridge","outputs":[{"internalType":"contract Bridge","name":"","type":"address"},{"internalType":"contract SequencerInbox","name":"","type":"address"},{"internalType":"contract Inbox","name":"","type":"address"},{"internalType":"contract RollupEventInbox","name":"","type":"address"},{"internalType":"contract Outbox","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"inboxTemplate","outputs":[{"internalType":"contract Inbox","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"outboxTemplate","outputs":[{"internalType":"contract Outbox","name":"","type":"address"}],"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":[],"name":"rollupEventInboxTemplate","outputs":[{"internalType":"contract RollupEventInbox","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sequencerInboxTemplate","outputs":[{"internalType":"contract SequencerInbox","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bridgeTemplate","type":"address"},{"internalType":"address","name":"_sequencerInboxTemplate","type":"address"},{"internalType":"address","name":"_inboxTemplate","type":"address"},{"internalType":"address","name":"_rollupEventInboxTemplate","type":"address"},{"internalType":"address","name":"_outboxTemplate","type":"address"}],"name":"updateTemplates","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5061001a3361018c565b604051610026906101dc565b604051809103906000f080158015610042573d6000803e3d6000fd5b50600180546001600160a01b0319166001600160a01b039290921691909117905560405161006f906101ea565b604051809103906000f08015801561008b573d6000803e3d6000fd5b50600280546001600160a01b0319166001600160a01b03929092169190911790556040516100b8906101f8565b604051809103906000f0801580156100d4573d6000803e3d6000fd5b50600380546001600160a01b0319166001600160a01b039290921691909117905560405161010190610206565b604051809103906000f08015801561011d573d6000803e3d6000fd5b50600480546001600160a01b0319166001600160a01b039290921691909117905560405161014a90610214565b604051809103906000f080158015610166573d6000803e3d6000fd5b50600580546001600160a01b0319166001600160a01b0392909216919091179055610222565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6115178062001b9283390190565b611d7c80620030a983390190565b6122688062004e2583390190565b6104ca806200708d83390190565b611357806200755783390190565b61196080620002326000396000f3fe60806040523480156200001157600080fd5b5060043610620000ab5760003560e01c806395fd089f116200006e57806395fd089f146200015e578063ae583c031462000172578063e6027a871462000186578063f2fde38b146200019a578063fc6a2ed014620001b157600080fd5b80632147e58e14620000b05780636c6e47c014620000c9578063715018a6146200011f5780637ba0e85714620001295780638da5cb5b146200014c575b600080fd5b620000c7620000c136600462000812565b620001c5565b005b620000e0620000da36600462000882565b62000281565b604080516001600160a01b03968716815294861660208601529285169284019290925283166060830152909116608082015260a0015b60405180910390f35b620000c7620006ba565b6003546200013d906001600160a01b031681565b60405162000116919062000931565b6000546001600160a01b03166200013d565b6001546200013d906001600160a01b031681565b6004546200013d906001600160a01b031681565b6002546200013d906001600160a01b031681565b620000c7620001ab36600462000945565b620006f5565b6005546200013d906001600160a01b031681565b6000546001600160a01b03163314620001fb5760405162461bcd60e51b8152600401620001f2906200096a565b60405180910390fd5b600180546001600160a01b03199081166001600160a01b0388811691909117909255600280548216878416179055600380548216868416179055600480548216858416179055600580549091169183169190911790556040517fc9d3947d22fa124aaec4c7e8c919f79016e2d7b48eee10568375d98b86460d1b90600090a15050505050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905281908190819081906001546040516001600160a01b03909116908a90620002d990620007e7565b620002e69291906200099f565b604051809103906000f08015801562000303573d6000803e3d6000fd5b506001600160a01b0390811660208301526002546040519116908a906200032a90620007e7565b620003379291906200099f565b604051809103906000f08015801562000354573d6000803e3d6000fd5b506001600160a01b0390811660408084019190915260035490519116908a906200037e90620007e7565b6200038b9291906200099f565b604051809103906000f080158015620003a8573d6000803e3d6000fd5b506001600160a01b0390811660608301526004546040519116908a90620003cf90620007e7565b620003dc9291906200099f565b604051809103906000f080158015620003f9573d6000803e3d6000fd5b506001600160a01b0390811660808301526005546040519116908a906200042090620007e7565b6200042d9291906200099f565b604051809103906000f0801580156200044a573d6000803e3d6000fd5b506001600160a01b0390811660a0830152602082015160405163189acdbd60e31b815291169063c4d66de89062000486908b9060040162000931565b600060405180830381600087803b158015620004a157600080fd5b505af1158015620004b6573d6000803e3d6000fd5b5050506040808301516020808501518351630fbd495960e11b81526001600160a01b0391821660048201528c516024820152918c01516044830152928b0151606482015260608b0151608482015291169150631f7a92b29060a401600060405180830381600087803b1580156200052c57600080fd5b505af115801562000541573d6000803e3d6000fd5b50505060608201516020830151604080850151905163485cc95560e01b81526001600160a01b03928316600482015290821660248201529116915063485cc95590604401600060405180830381600087803b158015620005a057600080fd5b505af1158015620005b5573d6000803e3d6000fd5b5050505080608001516001600160a01b031663c4d66de882602001516040518263ffffffff1660e01b8152600401620005ef919062000931565b600060405180830381600087803b1580156200060a57600080fd5b505af11580156200061f573d6000803e3d6000fd5b505050508060a001516001600160a01b031663c4d66de882602001516040518263ffffffff1660e01b815260040162000659919062000931565b600060405180830381600087803b1580156200067457600080fd5b505af115801562000689573d6000803e3d6000fd5b50505050602081015160408201516060830151608084015160a090940151929c919b50995091975095509350505050565b6000546001600160a01b03163314620006e75760405162461bcd60e51b8152600401620001f2906200096a565b620006f3600062000797565b565b6000546001600160a01b03163314620007225760405162461bcd60e51b8152600401620001f2906200096a565b6001600160a01b038116620007895760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401620001f2565b620007948162000797565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610f6280620009c983390190565b80356001600160a01b03811681146200080d57600080fd5b919050565b600080600080600060a086880312156200082b57600080fd5b6200083686620007f5565b94506200084660208701620007f5565b93506200085660408701620007f5565b92506200086660608701620007f5565b91506200087660808701620007f5565b90509295509295909350565b600080600083850360c08112156200089957600080fd5b620008a485620007f5565b9350620008b460208601620007f5565b92506080603f1982011215620008c957600080fd5b506040516080810181811067ffffffffffffffff82111715620008fc57634e487b7160e01b600052604160045260246000fd5b806040525060408501358152606085013560208201526080850135604082015260a08501356060820152809150509250925092565b6001600160a01b0391909116815260200190565b6000602082840312156200095857600080fd5b6200096382620007f5565b9392505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6001600160a01b039283168152911660208201526060604082018190526000908201526080019056fe608060405260405162000f6238038062000f62833981016040819052620000269162000519565b82816200005560017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005f9565b60008051602062000f1b833981519152146200007557620000756200061f565b6200008382826000620000e7565b50620000b3905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005f9565b60008051602062000efb83398151915214620000d357620000d36200061f565b620000de8262000124565b50505062000688565b620000f2836200017f565b600082511180620001005750805b156200011f576200011d8383620001c160201b620002601760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6200014f620001f0565b604080516001600160a01b03928316815291841660208301520160405180910390a16200017c8162000229565b50565b6200018a81620002de565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001e9838360405180606001604052806027815260200162000f3b6027913962000381565b9392505050565b60006200021a60008051602062000efb83398151915260001b6200046760201b620002081760201c565b546001600160a01b0316919050565b6001600160a01b038116620002945760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002bd60008051602062000efb83398151915260001b6200046760201b620002081760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002f4816200046a60201b6200028c1760201c565b620003585760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200028b565b80620002bd60008051602062000f1b83398151915260001b6200046760201b620002081760201c565b60606001600160a01b0384163b620003eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016200028b565b600080856001600160a01b03168560405162000408919062000635565b600060405180830381855af49150503d806000811462000445576040519150601f19603f3d011682016040523d82523d6000602084013e6200044a565b606091505b5090925090506200045d82828662000479565b9695505050505050565b90565b6001600160a01b03163b151590565b606083156200048a575081620001e9565b8251156200049b5782518084602001fd5b8160405162461bcd60e51b81526004016200028b919062000653565b80516001600160a01b0381168114620004cf57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000507578181015183820152602001620004ed565b838111156200011d5750506000910152565b6000806000606084860312156200052f57600080fd5b6200053a84620004b7565b92506200054a60208501620004b7565b60408501519092506001600160401b03808211156200056857600080fd5b818601915086601f8301126200057d57600080fd5b815181811115620005925762000592620004d4565b604051601f8201601f19908116603f01168101908382118183101715620005bd57620005bd620004d4565b81604052828152896020848701011115620005d757600080fd5b620005ea836020830160208801620004ea565b80955050505050509250925092565b6000828210156200061a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b6000825162000649818460208701620004ea565b9190910192915050565b602081526000825180602084015262000674816040850160208701620004ea565b601f01601f19169190910160400192915050565b61086380620006986000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106ed565b610118565b61005b610093366004610708565b61015f565b3480156100a457600080fd5b506100ad6101d0565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106ed565b61020b565b3480156100f557600080fd5b506100ad610235565b61010661029b565b61011661011161033a565b610344565b565b610120610368565b6001600160a01b0316336001600160a01b03161415610157576101548160405180602001604052806000815250600061039b565b50565b6101546100fe565b610167610368565b6001600160a01b0316336001600160a01b031614156101c8576101c38383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061039b915050565b505050565b6101c36100fe565b60006101da610368565b6001600160a01b0316336001600160a01b03161415610200576101fb61033a565b905090565b6102086100fe565b90565b610213610368565b6001600160a01b0316336001600160a01b0316141561015757610154816103c6565b600061023f610368565b6001600160a01b0316336001600160a01b03161415610200576101fb610368565b606061028583836040518060600160405280602781526020016108076027913961041a565b9392505050565b6001600160a01b03163b151590565b6102a3610368565b6001600160a01b0316336001600160a01b031614156101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101fb6104f5565b3660008037600080366000845af43d6000803e808015610363573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103a48361051d565b6000825111806103b15750805b156101c3576103c08383610260565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103ef610368565b604080516001600160a01b03928316815291841660208301520160405180910390a16101548161055d565b60606104258461028c565b6104805760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610331565b600080856001600160a01b03168560405161049b91906107b7565b600060405180830381855af49150503d80600081146104d6576040519150601f19603f3d011682016040523d82523d6000602084013e6104db565b606091505b50915091506104eb828286610606565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61038c565b6105268161063f565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105c25760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b6064820152608401610331565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60608315610615575081610285565b8251156106255782518084602001fd5b8160405162461bcd60e51b815260040161033191906107d3565b6106488161028c565b6106aa5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610331565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105e5565b80356001600160a01b03811681146106e857600080fd5b919050565b6000602082840312156106ff57600080fd5b610285826106d1565b60008060006040848603121561071d57600080fd5b610726846106d1565b9250602084013567ffffffffffffffff8082111561074357600080fd5b818601915086601f83011261075757600080fd5b81358181111561076657600080fd5b87602082850101111561077857600080fd5b6020830194508093505050509250925092565b60005b838110156107a657818101518382015260200161078e565b838111156103c05750506000910152565b600082516107c981846020870161078b565b9190910192915050565b60208152600082518060208401526107f281604085016020870161078b565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220fb0d75414bd881ce16381528bf0b9b2c1bea4c3e27069fcb6981b67d1535643064736f6c63430008090033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220b9239b356d47b5d41770e5c501cfed8f7323172098c560518542c8012309af5e64736f6c6343000809003360a06040523060805234801561001457600080fd5b506080516114e76100306000396000610c1b01526114e76000f3fe6080604052600436106101035760003560e01c80639e5d4c49116100a0578063cee3d72811610064578063cee3d7281461033a578063d5719dc21461035a578063e76f5c8d1461037a578063eca067ad1461039a578063ee35f327146103af57600080fd5b80639e5d4c491461027a578063ab5d8943146102a8578063ae60bd13146102bd578063c4d66de8146102fa578063cb23bcb51461031a57600080fd5b806284120c1461010857806316bf55791461012c578063413b35bd1461014c57806347fb24c5146101985780634f61f850146101ba5780637a88b107146101da578063845bde82146101fa5780638db5993b1461023a578063945e11471461024d575b600080fd5b34801561011457600080fd5b506007545b6040519081526020015b60405180910390f35b34801561013857600080fd5b506101196101473660046111bd565b6103cf565b34801561015857600080fd5b506101886101673660046111ee565b6001600160a01b031660009081526002602052604090206001015460ff1690565b6040519015158152602001610123565b3480156101a457600080fd5b506101b86101b336600461120b565b6103f0565b005b3480156101c657600080fd5b506101b86101d53660046111ee565b6106fb565b3480156101e657600080fd5b506101196101f5366004611249565b610820565b34801561020657600080fd5b5061021a610215366004611275565b610866565b604080519485526020850193909352918301526060820152608001610123565b610119610248366004611297565b610979565b34801561025957600080fd5b5061026d6102683660046111bd565b6109c4565b60405161012391906112de565b34801561028657600080fd5b5061029a6102953660046112f2565b6109ee565b60405161012392919061137b565b3480156102b457600080fd5b5061026d610b46565b3480156102c957600080fd5b506101886102d83660046111ee565b6001600160a01b03166000908152600160208190526040909120015460ff1690565b34801561030657600080fd5b506101b86103153660046111ee565b610b6c565b34801561032657600080fd5b5060085461026d906001600160a01b031681565b34801561034657600080fd5b506101b861035536600461120b565b610ce0565b34801561036657600080fd5b506101196103753660046111bd565b61100e565b34801561038657600080fd5b5061026d6103953660046111bd565b61101e565b3480156103a657600080fd5b50600654610119565b3480156103bb57600080fd5b5060095461026d906001600160a01b031681565b600781815481106103df57600080fd5b600091825260209091200154905081565b6008546001600160a01b031633146104c85760085460408051638da5cb5b60e01b815290516000926001600160a01b031691638da5cb5b916004808301926020929190829003018186803b15801561044757600080fd5b505afa15801561045b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061047f91906113da565b9050336001600160a01b038216146104c657600854604051630739600760e01b81526104bd9133916001600160a01b039091169084906004016113f7565b60405180910390fd5b505b6001600160a01b0382166000818152600160208181526040928390209182015492518515158152919360ff90931692917f6675ce8882cb71637de5903a193d218cc0544be9c0650cb83e0955f6aa2bf521910160405180910390a280801561052d5750825b8061053f57508015801561053f575082155b1561054a5750505050565b82156105d857604080518082018252600380548252600160208084018281526001600160a01b038a166000818152928490529582209451855551938201805460ff1916941515949094179093558154908101825591527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180546001600160a01b03191690911790556106f4565b600380546105e89060019061141a565b815481106105f8576105f861143f565b6000918252602090912001548254600380546001600160a01b039093169290919081106106275761062761143f565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555081600001546001600060038560000154815481106106755761067561143f565b60009182526020808320909101546001600160a01b0316835282019290925260400190205560038054806106ab576106ab611455565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861682526001908190526040822091825501805460ff191690555b50505b5050565b6008546001600160a01b031633146107ca5760085460408051638da5cb5b60e01b815290516000926001600160a01b031691638da5cb5b916004808301926020929190829003018186803b15801561075257600080fd5b505afa158015610766573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078a91906113da565b9050336001600160a01b038216146107c857600854604051630739600760e01b81526104bd9133916001600160a01b039091169084906004016113f7565b505b600980546001600160a01b0319166001600160a01b0383161790556040517f8c1e6003ed33ca6748d4ad3dd4ecc949065c89dceb31fdf546a5289202763c6a906108159083906112de565b60405180910390a150565b6009546000906001600160a01b03163314610850573360405163223e13c160e21b81526004016104bd91906112de565b61085f600d844342488761102e565b9392505050565b6009546000908190819081906001600160a01b0316331461089c573360405163223e13c160e21b81526004016104bd91906112de565b600754935083156108d557600780546108b79060019061141a565b815481106108c7576108c761143f565b906000526020600020015492505b84156109065760066108e860018761141a565b815481106108f8576108f861143f565b906000526020600020015491505b60408051602081018590529081018790526060810183905260800160408051601f198184030181529190528051602090910120600780546001810182556000919091527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68801819055939692955090935050565b3360009081526001602081905260408220015460ff166109ae573360405163b6c60ea360e01b81526004016104bd91906112de565b6109bc84844342488761102e565b949350505050565b600481815481106109d457600080fd5b6000918252602090912001546001600160a01b0316905081565b3360009081526002602052604081206001015460609060ff16610a2657336040516332ea82ab60e01b81526004016104bd91906112de565b8215801590610a3d57506001600160a01b0386163b155b15610a5d578560405163b5cf5b8f60e01b81526004016104bd91906112de565b600580546001600160a01b0319811633179091556040516001600160a01b03918216918816908790610a92908890889061146b565b60006040518083038185875af1925050503d8060008114610acf576040519150601f19603f3d011682016040523d82523d6000602084013e610ad4565b606091505b50600580546001600160a01b0319166001600160a01b038581169190911790915560405192955090935088169033907f2d9d115ef3e4a606d698913b1eae831a3cdfe20d9a83d48007b0526749c3d46690610b34908a908a908a9061147b565b60405180910390a35094509492505050565b6005546000906001600160a01b0390811690811415610b6757600091505090565b919050565b600054610100900460ff16610b875760005460ff1615610b8b565b303b155b610bee5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104bd565b600054610100900460ff16158015610c10576000805461ffff19166101011790555b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161415610c9e5760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b60648201526084016104bd565b600580546001600160a01b036001600160a01b031991821681179092556008805490911691841691909117905580156106f7576000805461ff00191690555050565b6008546001600160a01b03163314610daf5760085460408051638da5cb5b60e01b815290516000926001600160a01b031691638da5cb5b916004808301926020929190829003018186803b158015610d3757600080fd5b505afa158015610d4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6f91906113da565b9050336001600160a01b03821614610dad57600854604051630739600760e01b81526104bd9133916001600160a01b039091169084906004016113f7565b505b6001600160a01b038281161415610ddb578160405163077abed160e41b81526004016104bd91906112de565b6001600160a01b038216600081815260026020908152604091829020600181015492518515158152909360ff90931692917f49477e7356dbcb654ab85d7534b50126772d938130d1350e23e2540370c8dffa910160405180910390a2808015610e415750825b80610e53575080158015610e53575082155b15610e5e5750505050565b8215610eed57604080518082018252600480548252600160208084018281526001600160a01b038a16600081815260029093529582209451855551938201805460ff1916941515949094179093558154908101825591527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b0180546001600160a01b03191690911790556106f4565b60048054610efd9060019061141a565b81548110610f0d57610f0d61143f565b6000918252602090912001548254600480546001600160a01b03909316929091908110610f3c57610f3c61143f565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508160000154600260006004856000015481548110610f8a57610f8a61143f565b60009182526020808320909101546001600160a01b031683528201929092526040019020556004805480610fc057610fc0611455565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03861682526002905260408120908155600101805460ff1916905550505050565b600681815481106103df57600080fd5b600381815481106109d457600080fd5b600654604080516001600160f81b031960f88a901b166020808301919091526bffffffffffffffffffffffff1960608a901b1660218301526001600160c01b031960c089811b8216603585015288901b16603d830152604582018490526065820186905260858083018690528351808403909101815260a5909201909252805191012060009190600082156110e85760066110ca60018561141a565b815481106110da576110da61143f565b906000526020600020015490505b6040805160208082018490528183018590528251808303840181526060830180855281519190920120600680546001810182556000919091527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f015533905260ff8c1660808201526001600160a01b038b1660a082015260c0810187905260e0810188905267ffffffffffffffff89166101008201529051829185917f5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1918190036101200190a3509098975050505050505050565b6000602082840312156111cf57600080fd5b5035919050565b6001600160a01b03811681146111eb57600080fd5b50565b60006020828403121561120057600080fd5b813561085f816111d6565b6000806040838503121561121e57600080fd5b8235611229816111d6565b91506020830135801515811461123e57600080fd5b809150509250929050565b6000806040838503121561125c57600080fd5b8235611267816111d6565b946020939093013593505050565b6000806040838503121561128857600080fd5b50508035926020909101359150565b6000806000606084860312156112ac57600080fd5b833560ff811681146112bd57600080fd5b925060208401356112cd816111d6565b929592945050506040919091013590565b6001600160a01b0391909116815260200190565b6000806000806060858703121561130857600080fd5b8435611313816111d6565b935060208501359250604085013567ffffffffffffffff8082111561133757600080fd5b818701915087601f83011261134b57600080fd5b81358181111561135a57600080fd5b88602082850101111561136c57600080fd5b95989497505060200194505050565b821515815260006020604081840152835180604085015260005b818110156113b157858101830151858201606001528201611395565b818111156113c3576000606083870101525b50601f01601f191692909201606001949350505050565b6000602082840312156113ec57600080fd5b815161085f816111d6565b6001600160a01b0393841681529183166020830152909116604082015260600190565b60008282101561143a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b8183823760009101908152919050565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f191601019291505056fea26469706673582212201b943ce98f4e56fba380e6ca7fa68d8b0eedf80e4f11c1a57535ce01a8047edc64736f6c6343000809003360a06040523060805234801561001457600080fd5b50608051611d4c61003060003960006103e80152611d4c6000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c80637fa3a40e116100ad578063d9dd67ab11610071578063d9dd67ab146102ca578063e5a358c8146102dd578063e78cea9214610301578063ebea461d14610314578063f19815781461034a57600080fd5b80637fa3a40e1461025d5780638442086014610266578063b31761f814610279578063cb23bcb51461028c578063d1ce8da8146102b757600080fd5b806361a93f8f116100f457806361a93f8f146101af5780636e7df3e7146101c25780636f12b0c9146101d5578063715ea34b146101e857806371c3e6fe1461023a57600080fd5b806306f13056146101315780631637be481461014c5780631f7a92b21461017f578063258f04951461019457806327957a49146101a7575b600080fd5b61013961035d565b6040519081526020015b60405180910390f35b61016f61015a366004611764565b60009081526008602052604090205460ff1690565b6040519015158152602001610143565b61019261018d366004611795565b6103dd565b005b6101396101a2366004611764565b610595565b610139602881565b6101926101bd36600461181e565b6105fe565b6101926101d0366004611896565b6107dd565b6101926101e336600461181e565b6108e3565b61021b6101f6366004611764565b60086020526000908152604090205460ff81169061010090046001600160401b031682565b6040805192151583526001600160401b03909116602083015201610143565b61016f6102483660046118cf565b60036020526000908152604090205460ff1681565b61013960005481565b610192610274366004611764565b6109fd565b6101926102873660046118f3565b610b50565b60025461029f906001600160a01b031681565b6040516001600160a01b039091168152602001610143565b6101926102c5366004611966565b610c50565b6101396102d8366004611764565b610e21565b6102e8600160fe1b81565b6040516001600160f81b03199091168152602001610143565b60015461029f906001600160a01b031681565b60045460055460065460075461032a9392919084565b604080519485526020850193909352918301526060820152608001610143565b6101926103583660046119a7565b610ea4565b600154604080516221048360e21b815290516000926001600160a01b0316916284120c916004808301926020929190829003018186803b1580156103a057600080fd5b505afa1580156103b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103d89190611a17565b905090565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614156104705760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b60648201526084015b60405180910390fd5b6001546001600160a01b03161561049a57604051633bcd329760e21b815260040160405180910390fd5b6001600160a01b0382166104c157604051631ad0f74360e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0384169081179091556040805163cb23bcb560e01b8152905163cb23bcb591600480820192602092909190829003018186803b15801561051557600080fd5b505afa158015610529573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061054d9190611a30565b600280546001600160a01b0319166001600160a01b03929092169190911790558035600490815560208201356005556040820135600655606082013560075581905b50505050565b600081815260086020908152604080832081518083019092525460ff81161515825261010090046001600160401b0316918101829052906105eb5760405162f20c5d60e01b815260048101849052602401610467565b602001516001600160401b031692915050565b8060005a3360009081526003602052604090205490915060ff1615801561063057506002546001600160a01b03163314155b1561064e57604051632dd9fc9760e01b815260040160405180910390fd5b60008061065c8888886111d7565b91509150600080600080610672868b600061134a565b93509350935093508c84146106a45760405163ac7411c960e01b815260048101859052602481018e9052604401610467565b80838e600080516020611cd7833981519152858e8a60016040516106cb9493929190611a4d565b60405180910390a48c7ffe325ca1efe4c5c1062c981c3ee74b781debe4ea9440306a96d2a55759c66c208d8d604051610705929190611ac1565b60405180910390a2505050506001600160a01b0384161591506107d49050576000333214156107315750365b826001600160a01b031663e3db8a49335a61074c9086611b06565b6040516001600160e01b031960e085901b1681526001600160a01b039092166004830152602482015260448101849052606401602060405180830381600087803b15801561079957600080fd5b505af11580156107ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d19190611b1d565b50505b50505050505050565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561082b57600080fd5b505afa15801561083f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108639190611a30565b6001600160a01b0316336001600160a01b0316146108a557600254604051631194af8760e11b81526104679133916001600160a01b0390911690600401611b3a565b6001600160a01b038216600090815260036020526040808220805460ff191684151517905551600191600080516020611cf783398151915291a25050565b8060005a90503332146109095760405163feb3d07160e01b815260040160405180910390fd5b3360009081526003602052604090205460ff1661093957604051632dd9fc9760e01b815260040160405180910390fd5b6000806109478888886111d7565b9092509050600080808061095c868b8d61134a565b93509350935093508c841461098e5760405163ac7411c960e01b815260048101859052602481018e9052604401610467565b80838e600080516020611cd7833981519152856000548a60006040516109b79493929190611a4d565b60405180910390a4505050506001600160a01b0384161591506107d4905057600033321415610731575036826001600160a01b031663e3db8a49335a61074c9086611b06565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610a4b57600080fd5b505afa158015610a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a839190611a30565b6001600160a01b0316336001600160a01b031614610ac557600254604051631194af8760e11b81526104679133916001600160a01b0390911690600401611b3a565b60008181526008602052604090205460ff16610af65760405162f20c5d60e01b815260048101829052602401610467565b600081815260086020526040808220805460ff191690555182917f5cb4218b272fd214168ac43e90fb4d05d6c36f0b17ffb4c2dd07c234d744eb2a91a2604051600390600080516020611cf783398151915290600090a250565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b9e57600080fd5b505afa158015610bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd69190611a30565b6001600160a01b0316336001600160a01b031614610c1857600254604051631194af8760e11b81526104679133916001600160a01b0390911690600401611b3a565b80516004556020810151600555604080820151600655606082015160075551600090600080516020611cf7833981519152908290a250565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c9e57600080fd5b505afa158015610cb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd69190611a30565b6001600160a01b0316336001600160a01b031614610d1857600254604051631194af8760e11b81526104679133916001600160a01b0390911690600401611b3a565b60008282604051610d2a929190611b54565b604080519182900390912060008181526008602052919091205490915060ff1615610d6b57604051637d17eeed60e11b815260048101829052602401610467565b60408051808201825260018152436001600160401b0390811660208084019182526000868152600890915284902092518354915168ffffffffffffffffff1990921690151568ffffffffffffffff0019161761010091909216021790555181907fabca9b7986bc22ad0160eb0cb88ae75411eacfba4052af0b457a9335ef65572290610dfa9086908690611ac1565b60405180910390a2604051600290600080516020611cf783398151915290600090a2505050565b6001546040516316bf557960e01b8152600481018390526000916001600160a01b0316906316bf55799060240160206040518083038186803b158015610e6657600080fd5b505afa158015610e7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9e9190611a17565b92915050565b6000548611610ec657604051633eb9f37d60e11b815260040160405180910390fd5b6000610f768684610eda6020890189611b7a565b610eea60408a0160208b01611b7a565b610ef560018d611b06565b6040805160f89690961b6001600160f81b03191660208088019190915260609590951b6001600160601b031916602187015260c093841b6001600160c01b031990811660358801529290931b909116603d85015260458401526065830188905260858084018790528151808503909101815260a59093019052815191012090565b6004549091504390610f8b6020880188611b7a565b6001600160401b0316610f9e9190611ba3565b10610fbc5760405163ad3515d960e01b815260040160405180910390fd5b6006544290610fd16040880160208901611b7a565b6001600160401b0316610fe49190611ba3565b106110025760405163c76d17e560e01b815260040160405180910390fd5b6000600188111561109a576001546001600160a01b031663d5719dc261102960028b611b06565b6040518263ffffffff1660e01b815260040161104791815260200190565b60206040518083038186803b15801561105f57600080fd5b505afa158015611073573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110979190611a17565b90505b60408051602080820184905281830185905282518083038401815260609092019092528051910120600180546001600160a01b03169063d5719dc2906110e0908c611b06565b6040518263ffffffff1660e01b81526004016110fe91815260200190565b60206040518083038186803b15801561111657600080fd5b505afa15801561112a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114e9190611a17565b1461116c576040516313947fd760e01b815260040160405180910390fd5b6000806111788a6115d6565b9150915060008060008061118e868f600061134a565b9350935093509350808385600080516020611cd7833981519152856000548a60026040516111bf9493929190611a4d565b60405180910390a45050505050505050505050505050565b60006111e161173d565b848460006111f0826028611ba3565b90506201cccc81111561122257604051634634691b60e01b8152600481018290526201cccc6024820152604401610467565b811580159061125a5750600160fe1b80848460008161124357611243611b64565b9050013560f81c60f81b166001600160f81b031916145b1561127857604051631f97007f60e01b815260040160405180910390fd5b602182108015906112a657508282600081811061129757611297611b64565b90910135600160ff1b16151590505b156112fa5760006112bb602160018587611bbb565b6112c491611be5565b60008181526008602052604090205490915060ff166112f85760405162f20c5d60e01b815260048101829052602401610467565b505b60008061130688611602565b915091506000828b8b60405160200161132193929190611c2f565b60408051808303601f1901815291905280516020909101209b919a509098505050505050505050565b60008060008060005486101561137357604051633eb9f37d60e11b815260040160405180910390fd5b600160009054906101000a90046001600160a01b03166001600160a01b031663eca067ad6040518163ffffffff1660e01b815260040160206040518083038186803b1580156113c157600080fd5b505afa1580156113d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f99190611a17565b8611156114195760405163925f8bd360e01b815260040160405180910390fd5b60015460405163422def4160e11b815260048101899052602481018890526001600160a01b039091169063845bde8290604401608060405180830381600087803b15801561146657600080fd5b505af115801561147a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149e9190611c57565b60008a90559296509094509250905084156115cd576040805142602082015233606081901b6001600160601b03191692820192909252605481018990526074810186905248609482015260009060b40160408051808303601f190181529082905260015481516020830120637a88b10760e01b84526001600160a01b0386811660048601526024850191909152919350600092911690637a88b10790604401602060405180830381600087803b15801561155757600080fd5b505af115801561156b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158f9190611a17565b9050807fff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b836040516115c19190611c8d565b60405180910390a25050505b93509350935093565b60006115e061173d565b6000806115ec85611602565b8151602090920191909120969095509350505050565b606061160c61173d565b60006116166116a9565b9050600081600001518260200151836040015184606001518860405160200161167e95949392919060c095861b6001600160c01b0319908116825294861b8516600882015292851b8416601084015290841b8316601883015290921b16602082015260280190565b604051602081830303815290604052905060288151146116a0576116a0611cc0565b94909350915050565b6116b161173d565b6116b961173d565b6006544211156116dc576006546116d09042611b06565b6001600160401b031681525b6007546116e99042611ba3565b6001600160401b0316602082015260045443111561171d5760045461170e9043611b06565b6001600160401b031660408201525b60055461172a9043611ba3565b6001600160401b03166060820152919050565b60408051608081018252600080825260208201819052918101829052606081019190915290565b60006020828403121561177657600080fd5b5035919050565b6001600160a01b038116811461179257600080fd5b50565b60008082840360a08112156117a957600080fd5b83356117b48161177d565b92506080601f19820112156117c857600080fd5b506020830190509250929050565b60008083601f8401126117e857600080fd5b5081356001600160401b038111156117ff57600080fd5b60208301915083602082850101111561181757600080fd5b9250929050565b60008060008060006080868803121561183657600080fd5b8535945060208601356001600160401b0381111561185357600080fd5b61185f888289016117d6565b90955093505060408601359150606086013561187a8161177d565b809150509295509295909350565b801515811461179257600080fd5b600080604083850312156118a957600080fd5b82356118b48161177d565b915060208301356118c481611888565b809150509250929050565b6000602082840312156118e157600080fd5b81356118ec8161177d565b9392505050565b60006080828403121561190557600080fd5b604051608081018181106001600160401b038211171561193557634e487b7160e01b600052604160045260246000fd5b8060405250823581526020830135602082015260408301356040820152606083013560608201528091505092915050565b6000806020838503121561197957600080fd5b82356001600160401b0381111561198f57600080fd5b61199b858286016117d6565b90969095509350505050565b60008060008060008060e087890312156119c057600080fd5b86359550602087013560ff811681146119d857600080fd5b945060808701888111156119eb57600080fd5b60408801945035925060a0870135611a028161177d565b8092505060c087013590509295509295509295565b600060208284031215611a2957600080fd5b5051919050565b600060208284031215611a4257600080fd5b81516118ec8161177d565b600060e0820190508582528460208301526001600160401b038085511660408401528060208601511660608401528060408601511660808401528060608601511660a08401525060038310611ab257634e487b7160e01b600052602160045260246000fd5b8260c083015295945050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b634e487b7160e01b600052601160045260246000fd5b600082821015611b1857611b18611af0565b500390565b600060208284031215611b2f57600080fd5b81516118ec81611888565b6001600160a01b0392831681529116602082015260400190565b8183823760009101908152919050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611b8c57600080fd5b81356001600160401b03811681146118ec57600080fd5b60008219821115611bb657611bb6611af0565b500190565b60008085851115611bcb57600080fd5b83861115611bd857600080fd5b5050820193919092039150565b80356020831015610e9e57600019602084900360031b1b1692915050565b60005b83811015611c1e578181015183820152602001611c06565b8381111561058f5750506000910152565b60008451611c41818460208901611c03565b8201838582376000930192835250909392505050565b60008060008060808587031215611c6d57600080fd5b505082516020840151604085015160609095015191969095509092509050565b6020815260008251806020840152611cac816040850160208701611c03565b601f01601f19169190910160400192915050565b634e487b7160e01b600052600160045260246000fdfe7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7ea8787f128d10b2cc0317b0c3960f9ad447f7f6c1ed189db1083ccffd20f456ea264697066735822122008f8afab8272a8f52f2960ad5a31bed4bbefd2c3371f20706dbf57181ad623a364736f6c6343000809003360a06040523060805234801561001457600080fd5b50608051612231610037600039600081816108f1015261100601526122316000f3fe6080604052600436106101405760003560e01c806367ef3ab8116100b6578063babcc5391161006f578063babcc53914610307578063c474d2c514610337578063e3de72a514610357578063e78cea9214610377578063ee35f327146103a4578063efeadb6d146103c457600080fd5b806367ef3ab81461026c5780636e6e8a6a1461027f5780638456cb59146102925780638a631aa6146102a7578063a66b327d146102c7578063b75436bb146102e757600080fd5b8063439370b111610108578063439370b1146101e6578063485cc955146101ee5780635075788b1461020e5780635c975abb1461022e5780635e91675814610246578063679b6ded1461025957600080fd5b80630f4d14e9146101455780631b871c8d1461016b5780631fe927cf1461017e57806322bd5c1c1461019e5780633f4ba83a146101cf575b600080fd5b61015861015336600461191d565b6103e4565b6040519081526020015b60405180910390f35b610158610179366004611993565b610471565b34801561018a57600080fd5b50610158610199366004611a37565b610504565b3480156101aa57600080fd5b506066546101bf90600160a01b900460ff1681565b6040519015158152602001610162565b3480156101db57600080fd5b506101e4610622565b005b610158610762565b3480156101fa57600080fd5b506101e4610209366004611a78565b610842565b34801561021a57600080fd5b50610158610229366004611ab1565b6109b1565b34801561023a57600080fd5b5060335460ff166101bf565b610158610254366004611b2d565b610a60565b610158610267366004611993565b610b0b565b61015861027a366004611b96565b610c34565b61015861028d366004611993565b610ce2565b34801561029e57600080fd5b506101e4610d3c565b3480156102b357600080fd5b506101586102c2366004611c08565b610e79565b3480156102d357600080fd5b506101586102e2366004611c5c565b610f1a565b3480156102f357600080fd5b50610158610302366004611a37565b610f45565b34801561031357600080fd5b506101bf610322366004611c7e565b60676020526000908152604090205460ff1681565b34801561034357600080fd5b506101e4610352366004611c7e565b610ffb565b34801561036357600080fd5b506101e4610372366004611d86565b6110fd565b34801561038357600080fd5b50606554610397906001600160a01b031681565b6040516101629190611e47565b3480156103b057600080fd5b50606654610397906001600160a01b031681565b3480156103d057600080fd5b506101e46103df366004611e5b565b61137d565b60006103f260335460ff1690565b156104185760405162461bcd60e51b815260040161040f90611e76565b60405180910390fd5b606654600160a01b900460ff16801561044157503260009081526067602052604090205460ff16155b156104615732604051630f51ed7160e41b815260040161040f9190611e47565b610469610762565b90505b919050565b600061047f60335460ff1690565b1561049c5760405162461bcd60e51b815260040161040f90611e76565b606654600160a01b900460ff1680156104c557503260009081526067602052604090205460ff16155b156104e55732604051630f51ed7160e41b815260040161040f9190611e47565b6104f68a8a8a8a8a8a8a8a8a610ce2565b9a9950505050505050505050565b600061051260335460ff1690565b1561052f5760405162461bcd60e51b815260040161040f90611e76565b606654600160a01b900460ff16801561055857503260009081526067602052604090205460ff16155b156105785732604051630f51ed7160e41b815260040161040f9190611e47565b3332146105985760405163feb3d07160e01b815260040160405180910390fd5b6201cccc8211156105c857604051634634691b60e01b8152600481018390526201cccc602482015260440161040f565b60006105ed60033386866040516105e0929190611ea0565b604051809103902061155c565b60405190915081907fab532385be8f1005a4b6ba8fa20a2245facb346134ac739fe9a5198dc1580b9c90600090a29392505050565b6065546040805163cb23bcb560e01b815290516000926001600160a01b03169163cb23bcb5916004808301926020929190829003018186803b15801561066757600080fd5b505afa15801561067b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061069f9190611eb0565b9050336001600160a01b03821614610757576000816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156106ec57600080fd5b505afa158015610700573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107249190611eb0565b9050336001600160a01b0382161461075557338282604051630739600760e01b815260040161040f93929190611ecd565b505b61075f6115f6565b50565b600061077060335460ff1690565b1561078d5760405162461bcd60e51b815260040161040f90611e76565b606654600160a01b900460ff1680156107b657503260009081526067602052604090205460ff16155b156107d65732604051630f51ed7160e41b815260040161040f9190611e47565b33803b1515806107e65750323314155b156107f957503361111161111160901b01015b6040516bffffffffffffffffffffffff19606083901b16602082015234603482015261083c90600c9033906054015b604051602081830303815290604052611683565b91505090565b600054610100900460ff1661085d5760005460ff1615610861565b303b155b6108c45760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161040f565b600054610100900460ff161580156108e6576000805461ffff19166101011790555b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016141561092f5760405162461bcd60e51b815260040161040f90611ef0565b6065546001600160a01b03161561095957604051633bcd329760e21b815260040160405180910390fd5b606580546001600160a01b038086166001600160a01b031990921691909117909155606680546001600160a81b03191691841691909117905561099a611719565b80156109ac576000805461ff00191690555b505050565b60006109bf60335460ff1690565b156109dc5760405162461bcd60e51b815260040161040f90611e76565b606654600160a01b900460ff168015610a0557503260009081526067602052604090205460ff16155b15610a255732604051630f51ed7160e41b815260040161040f9190611e47565b610a5460033360008b8b8b8b6001600160a01b03168b8b8b604051602001610828989796959493929190611f3c565b98975050505050505050565b6000610a6e60335460ff1690565b15610a8b5760405162461bcd60e51b815260040161040f90611e76565b606654600160a01b900460ff168015610ab457503260009081526067602052604090205460ff16155b15610ad45732604051630f51ed7160e41b815260040161040f9190611e47565b610b0160073360018989896001600160a01b0316348a8a6040516020016108289796959493929190611f82565b9695505050505050565b6000610b1960335460ff1690565b15610b365760405162461bcd60e51b815260040161040f90611e76565b606654600160a01b900460ff168015610b5f57503260009081526067602052604090205460ff16155b15610b7f5732604051630f51ed7160e41b815260040161040f9190611e47565b610b898486611fd7565b610b938a8a611ff6565b610b9d9190611ff6565b341015610be557610bae8486611fd7565b610bb88a8a611ff6565b610bc29190611ff6565b604051631c102d6360e21b8152600481019190915234602482015260440161040f565b6001600160a01b0387163b15610c045761111161111160901b01870196505b6001600160a01b0386163b15610c235761111161111160901b01860195505b6104f68a8a8a8a8a8a8a8a8a61174a565b6000610c4260335460ff1690565b15610c5f5760405162461bcd60e51b815260040161040f90611e76565b606654600160a01b900460ff168015610c8857503260009081526067602052604090205460ff16155b15610ca85732604051630f51ed7160e41b815260040161040f9190611e47565b610cd760073360008a8a8a8a6001600160a01b0316348b8b604051602001610828989796959493929190611f3c565b979650505050505050565b60405162461bcd60e51b815260206004820152602660248201527f554e534146455f524554525941424c45535f54454d504f524152494c595f444960448201526514d05093115160d21b606482015260009060840161040f565b6065546040805163cb23bcb560e01b815290516000926001600160a01b03169163cb23bcb5916004808301926020929190829003018186803b158015610d8157600080fd5b505afa158015610d95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610db99190611eb0565b9050336001600160a01b03821614610e71576000816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e0657600080fd5b505afa158015610e1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3e9190611eb0565b9050336001600160a01b03821614610e6f57338282604051630739600760e01b815260040161040f93929190611ecd565b505b61075f611892565b6000610e8760335460ff1690565b15610ea45760405162461bcd60e51b815260040161040f90611e76565b606654600160a01b900460ff168015610ecd57503260009081526067602052604090205460ff16155b15610eed5732604051630f51ed7160e41b815260040161040f9190611e47565b610cd760033360018a8a8a6001600160a01b03168a8a8a6040516020016108289796959493929190611f82565b600081610f28846006611fd7565b610f3490610578611ff6565b610f3e9190611fd7565b9392505050565b6000610f5360335460ff1690565b15610f705760405162461bcd60e51b815260040161040f90611e76565b606654600160a01b900460ff168015610f9957503260009081526067602052604090205460ff16155b15610fb95732604051630f51ed7160e41b815260040161040f9190611e47565b610f3e60033385858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061168392505050565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614156110445760405162461bcd60e51b815260040161040f90611ef0565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61038054336001600160a01b038216146110a157604051631194af8760e11b81523360048201526001600160a01b038216602482015260440161040f565b600360005b8160ff168160ff1610156110ca5760008155806110c28161200e565b9150506110a6565b50506066805460ff60a01b191690555050606580546001600160a01b0319166001600160a01b0392909216919091179055565b6065546040805163cb23bcb560e01b815290516000926001600160a01b03169163cb23bcb5916004808301926020929190829003018186803b15801561114257600080fd5b505afa158015611156573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117a9190611eb0565b9050336001600160a01b03821614611232576000816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156111c757600080fd5b505afa1580156111db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ff9190611eb0565b9050336001600160a01b0382161461123057338282604051630739600760e01b815260040161040f93929190611ecd565b505b81518351146112735760405162461bcd60e51b815260206004820152600d60248201526c1253959053125117d253941555609a1b604482015260640161040f565b60005b8351811015611377578281815181106112915761129161202e565b6020026020010151606760008684815181106112af576112af61202e565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055508381815181106113005761130061202e565b60200260200101516001600160a01b03167fd9739f45a01ce092c5cdb3d68f63d63d21676b1c6c0b4f9cbc6be4cf5449595a8483815181106113445761134461202e565b602002602001015160405161135d911515815260200190565b60405180910390a28061136f81612044565b915050611276565b50505050565b6065546040805163cb23bcb560e01b815290516000926001600160a01b03169163cb23bcb5916004808301926020929190829003018186803b1580156113c257600080fd5b505afa1580156113d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113fa9190611eb0565b9050336001600160a01b038216146114b2576000816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561144757600080fd5b505afa15801561145b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147f9190611eb0565b9050336001600160a01b038216146114b057338282604051630739600760e01b815260040161040f93929190611ecd565b505b606660149054906101000a900460ff16151582151514156115035760405162461bcd60e51b815260206004820152600b60248201526a1053149150511657d4d15560aa1b604482015260640161040f565b60668054831515600160a01b0260ff60a01b199091161790556040517f16435b45f7482047f839a6a19d291442627200f52cad2803c595150d0d440eb39061155090841515815260200190565b60405180910390a15050565b606554604051638db5993b60e01b815260ff851660048201526001600160a01b038481166024830152604482018490526000921690638db5993b9034906064016020604051808303818588803b1580156115b557600080fd5b505af11580156115c9573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906115ee919061205f565b949350505050565b60335460ff1661163f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161040f565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516116799190611e47565b60405180910390a1565b60006201cccc825111156116b9578151604051634634691b60e01b815260048101919091526201cccc602482015260440161040f565b60006116d78561111161111160901b0186018551602087012061155c565b9050807fff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b846040516117099190612078565b60405180910390a2949350505050565b600054610100900460ff166117405760405162461bcd60e51b815260040161040f906120cd565b6117486118ea565b565b600061175860335460ff1690565b156117755760405162461bcd60e51b815260040161040f90611e76565b606654600160a01b900460ff16801561179e57503260009081526067602052604090205460ff16155b156117be5732604051630f51ed7160e41b815260040161040f9190611e47565b84600114806117cd5750836001145b1561180157338a8a348b8b8b8b8b8b8b6040516307c266e360e01b815260040161040f9b9a99989796959493929190612118565b600061180d8348610f1a565b90508089101561183a57604051637d6f91c560e11b815260048101829052602481018a905260440161040f565b6118836009338d6001600160a01b03168d348e8e6001600160a01b03168e6001600160a01b03168e8e8e8e90508f8f6040516020016108289b9a999897969594939291906121a1565b9b9a5050505050505050505050565b60335460ff16156118b55760405162461bcd60e51b815260040161040f90611e76565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861166c3390565b600054610100900460ff166119115760405162461bcd60e51b815260040161040f906120cd565b6033805460ff19169055565b60006020828403121561192f57600080fd5b5035919050565b6001600160a01b038116811461075f57600080fd5b60008083601f84011261195d57600080fd5b5081356001600160401b0381111561197457600080fd5b60208301915083602082850101111561198c57600080fd5b9250929050565b60008060008060008060008060006101008a8c0312156119b257600080fd5b89356119bd81611936565b985060208a0135975060408a0135965060608a01356119db81611936565b955060808a01356119eb81611936565b945060a08a0135935060c08a0135925060e08a01356001600160401b03811115611a1457600080fd5b611a208c828d0161194b565b915080935050809150509295985092959850929598565b60008060208385031215611a4a57600080fd5b82356001600160401b03811115611a6057600080fd5b611a6c8582860161194b565b90969095509350505050565b60008060408385031215611a8b57600080fd5b8235611a9681611936565b91506020830135611aa681611936565b809150509250929050565b600080600080600080600060c0888a031215611acc57600080fd5b8735965060208801359550604088013594506060880135611aec81611936565b93506080880135925060a08801356001600160401b03811115611b0e57600080fd5b611b1a8a828b0161194b565b989b979a50959850939692959293505050565b600080600080600060808688031215611b4557600080fd5b85359450602086013593506040860135611b5e81611936565b925060608601356001600160401b03811115611b7957600080fd5b611b858882890161194b565b969995985093965092949392505050565b60008060008060008060a08789031215611baf57600080fd5b8635955060208701359450604087013593506060870135611bcf81611936565b925060808701356001600160401b03811115611bea57600080fd5b611bf689828a0161194b565b979a9699509497509295939492505050565b60008060008060008060a08789031215611c2157600080fd5b86359550602087013594506040870135611c3a81611936565b93506060870135925060808701356001600160401b03811115611bea57600080fd5b60008060408385031215611c6f57600080fd5b50508035926020909101359150565b600060208284031215611c9057600080fd5b8135610f3e81611936565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715611cd957611cd9611c9b565b604052919050565b60006001600160401b03821115611cfa57611cfa611c9b565b5060051b60200190565b8035801515811461046c57600080fd5b600082601f830112611d2557600080fd5b81356020611d3a611d3583611ce1565b611cb1565b82815260059290921b84018101918181019086841115611d5957600080fd5b8286015b84811015611d7b57611d6e81611d04565b8352918301918301611d5d565b509695505050505050565b60008060408385031215611d9957600080fd5b82356001600160401b0380821115611db057600080fd5b818501915085601f830112611dc457600080fd5b81356020611dd4611d3583611ce1565b82815260059290921b84018101918181019089841115611df357600080fd5b948201945b83861015611e1a578535611e0b81611936565b82529482019490820190611df8565b96505086013592505080821115611e3057600080fd5b50611e3d85828601611d14565b9150509250929050565b6001600160a01b0391909116815260200190565b600060208284031215611e6d57600080fd5b610f3e82611d04565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b8183823760009101908152919050565b600060208284031215611ec257600080fd5b8151610f3e81611936565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b60ff60f81b8960f81b168152876001820152866021820152856041820152846061820152836081820152818360a18301376000910160a101908152979650505050505050565b60ff60f81b8860f81b16815286600182015285602182015284604182015283606182015281836081830137600091016081019081529695505050505050565b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615611ff157611ff1611fc1565b500290565b6000821982111561200957612009611fc1565b500190565b600060ff821660ff81141561202557612025611fc1565b60010192915050565b634e487b7160e01b600052603260045260246000fd5b600060001982141561205857612058611fc1565b5060010190565b60006020828403121561207157600080fd5b5051919050565b600060208083528351808285015260005b818110156120a557858101830151858201604001528201612089565b818111156120b7576000604083870101525b50601f01601f1916929092016040019392505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160a01b038c811682528b81166020830152604082018b9052606082018a90526080820189905287811660a0830152861660c082015260e0810185905261010081018490526101406101208201819052810182905260006101608385828501376000838501820152601f909301601f19169091019091019b9a5050505050505050505050565b8b81528a60208201528960408201528860608201528760808201528660a08201528560c08201528460e08201528361010082015260006101208385828501376000929093019092019081529b9a505050505050505050505056fea26469706673582212207d7a52cb36bc48391b7efd0988a2ecdbf4c9bafea74c73e0b9089e5e8888ce1464736f6c6343000809003360a06040523060805234801561001457600080fd5b5060805161049b61002f600039600060c6015261049b6000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063c4d66de814610051578063cb23bcb514610066578063e199be3514610095578063e78cea92146100a8575b600080fd5b61006461005f36600461039d565b6100bb565b005b600154610079906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b6100646100a33660046103c1565b610245565b600054610079906001600160a01b031681565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016141561014e5760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b60648201526084015b60405180910390fd5b6000546001600160a01b0316156101965760405162461bcd60e51b815260206004820152600c60248201526b1053149150511657d253925560a21b6044820152606401610145565b600080546001600160a01b0319166001600160a01b0383169081179091556040805163cb23bcb560e01b8152905163cb23bcb591600480820192602092909190829003018186803b1580156101ea57600080fd5b505afa1580156101fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061022291906103da565b600180546001600160a01b0319166001600160a01b039290921691909117905550565b6001546001600160a01b0316331461028d5760405162461bcd60e51b815260206004820152600b60248201526a04f4e4c595f524f4c4c55560ac1b6044820152606401610145565b6000816040516020016102a291815260200190565b60408051808303601f19018152908290526000805482516020840120638db5993b60e01b8552600b6004860152602485018390526044850152919350916001600160a01b0390911690638db5993b90606401602060405180830381600087803b15801561030e57600080fd5b505af1158015610322573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061034691906103f7565b9050807fff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b836040516103789190610410565b60405180910390a2505050565b6001600160a01b038116811461039a57600080fd5b50565b6000602082840312156103af57600080fd5b81356103ba81610385565b9392505050565b6000602082840312156103d357600080fd5b5035919050565b6000602082840312156103ec57600080fd5b81516103ba81610385565b60006020828403121561040957600080fd5b5051919050565b600060208083528351808285015260005b8181101561043d57858101830151858201604001528201610421565b8181111561044f576000604083870101525b50601f01601f191692909201604001939250505056fea26469706673582212208370f04f753af7aff14c5e3ecd4d0cc9de11333c1b1defd4a5d3fd84170af92c64736f6c6343000809003360a06040523060805234801561001457600080fd5b5060805161132761003060003960006104b801526113276000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80639f0c04bf116100925780639f0c04bf1461017c578063a04cee601461018f578063ae6dead7146101a2578063b0f30537146101c2578063c4d66de8146101ca578063c75184df146101dd578063cb23bcb5146101fd578063d5b5cc2314610210578063e78cea921461023057600080fd5b80627436d3146100ef57806308635a9514610115578063119852711461012a578063288e5b1014610131578063465477901461014457806372f2a8c71461014c57806380648b02146101545780638515bc6a14610174575b600080fd5b6101026100fd366004610c41565b610243565b6040519081526020015b60405180910390f35b610128610123366004610d61565b610280565b005b6000610102565b61012861013f366004610e55565b6102f3565b61010261032e565b61010261035d565b61015c61037a565b6040516001600160a01b03909116815260200161010c565b61010261039b565b61010261018a366004610ef0565b6103c3565b61012861019d366004610f7e565b610408565b6101026101b0366004610fa0565b60036020526000908152604090205481565b61010261048c565b6101286101d8366004610fb9565b6104ad565b6101e5600281565b6040516001600160801b03909116815260200161010c565b60005461015c906001600160a01b031681565b61010261021e366004610fa0565b60026020526000908152604090205481565b60015461015c906001600160a01b031681565b600061027884848460405160200161025d91815260200190565b6040516020818303038152906040528051906020012061066d565b949350505050565b600061029289898989898989896103c3565b90506102d48c8c808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508e925085915061072a9050565b6102e58a8a8a8a8a8a8a8a8a610849565b505050505050505050505050565b331561031257604051630e13b69d60e01b815260040160405180910390fd5b610323898989898989898989610849565b505050505050505050565b6004546000906001600160801b039081169081141561034f57600091505090565b6001600160801b0316919050565b60065460009060001981141561037557506000919050565b919050565b6007546000906001600160a01b039081169081141561037557600091505090565b6004546000906001600160801b03600160801b90910481169081141561034f57600091505090565b600088888888888888886040516020016103e4989796959493929190610fdd565b60405160208183030381529060405280519060200120905098975050505050505050565b6000546001600160a01b0316331461044d57600054604051630e4cf1bf60e21b81523360048201526001600160a01b0390911660248201526044015b60405180910390fd5b60008281526003602052604080822083905551829184917fb4df3847300f076a369cd76d2314b470a1194d9e8a6bb97f1860aee88a5f67489190a35050565b6005546000906001600160801b039081169081141561034f57600091505090565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016141561053b5760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b6064820152608401610444565b6001546001600160a01b03161561056557604051633bcd329760e21b815260040160405180910390fd5b6040805160a0810182526001600160801b038082526020808301829052828401829052600019606084018190526001600160a01b0360809094018490526004818155600580546001600160801b031916909417909355600655600780546001600160a01b03199081168517909155600180549487169490911684179055835163cb23bcb560e01b81529351929363cb23bcb593818401939091829003018186803b15801561061257600080fd5b505afa158015610626573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064a9190611036565b600080546001600160a01b0319166001600160a01b039290921691909117905550565b82516000906101008111156106a057604051637ed6198f60e11b8152600481018290526101006024820152604401610444565b8260005b828110156107205760008782815181106106c0576106c0611053565b602002602001015190506002876106d7919061107f565b6106ef578260005280602052604060002092506106ff565b8060005282602052604060002092505b61070a6002886110a9565b9650508080610718906110bd565b9150506106a4565b5095945050505050565b61010083511061075257825160405163ab6a068360e01b815260040161044491815260200190565b825161075f9060026111be565b821061079657818351600261077491906111be565b604051630b8a724b60e01b815260048101929092526024820152604401610444565b60006107a3848484610243565b6000818152600360205260409020549091506107d5576040516310e61af960e31b815260048101829052602401610444565b60006107e260ff856110a9565b905060006107f160ff8661107f565b60008381526002602052604090205490915080821c6001161561082a57604051639715b8d360e01b815260048101879052602401610444565b600092835260026020526040909220600190911b909117905550505050565b6000886001600160a01b0316886001600160a01b03167f20af7f3bbfe38132b8900ae295cd9c8d1914be7052d061a511f3f728dab189648c60405161089091815260200190565b60405180910390a4600060046040518060a00160405290816000820160009054906101000a90046001600160801b03166001600160801b03166001600160801b031681526020016000820160109054906101000a90046001600160801b03166001600160801b03166001600160801b031681526020016001820160009054906101000a90046001600160801b03166001600160801b03166001600160801b03168152602001600282015481526020016003820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152505090506040518060a00160405280886001600160801b03168152602001876001600160801b03168152602001866001600160801b031681526020018b60001b81526020018a6001600160a01b0316815250600460008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a8154816001600160801b0302191690836001600160801b0316021790555060408201518160010160006101000a8154816001600160801b0302191690836001600160801b031602179055506060820151816002015560808201518160030160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550905050610ac1888585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610b3392505050565b805160208201516001600160801b03918216600160801b91831691909102176004556040820151600580546001600160801b03191691909216179055606081015160065560800151600780546001600160a01b0319166001600160a01b03909216919091179055505050505050505050565b600154604051639e5d4c4960e01b815260009182916001600160a01b0390911690639e5d4c4990610b6c908890889088906004016111fa565b600060405180830381600087803b158015610b8657600080fd5b505af1158015610b9a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bc29190810190611243565b9150915081610bf457805115610bdb5780518082602001fd5b604051631bb7daad60e11b815260040160405180910390fd5b5050505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715610c3957610c39610bfb565b604052919050565b600080600060608486031215610c5657600080fd5b83356001600160401b0380821115610c6d57600080fd5b818601915086601f830112610c8157600080fd5b8135602082821115610c9557610c95610bfb565b8160051b9250610ca6818401610c11565b828152928401810192818101908a851115610cc057600080fd5b948201945b84861015610cde57853582529482019490820190610cc5565b9a918901359950506040909701359695505050505050565b6001600160a01b0381168114610d0b57600080fd5b50565b803561037581610cf6565b60008083601f840112610d2b57600080fd5b5081356001600160401b03811115610d4257600080fd5b602083019150836020828501011115610d5a57600080fd5b9250929050565b60008060008060008060008060008060006101208c8e031215610d8357600080fd5b8b356001600160401b0380821115610d9a57600080fd5b818e0191508e601f830112610dae57600080fd5b813581811115610dbd57600080fd5b8f60208260051b8501011115610dd257600080fd5b60208381019e50909c508e01359a50610ded60408f01610d0e565b9950610dfb60608f01610d0e565b985060808e0135975060a08e0135965060c08e0135955060e08e013594506101008e0135915080821115610e2e57600080fd5b50610e3b8e828f01610d19565b915080935050809150509295989b509295989b9093969950565b60008060008060008060008060006101008a8c031215610e7457600080fd5b8935985060208a0135610e8681610cf6565b975060408a0135610e9681610cf6565b965060608a0135955060808a0135945060a08a0135935060c08a0135925060e08a01356001600160401b03811115610ecd57600080fd5b610ed98c828d01610d19565b915080935050809150509295985092959850929598565b60008060008060008060008060e0898b031215610f0c57600080fd5b8835610f1781610cf6565b97506020890135610f2781610cf6565b965060408901359550606089013594506080890135935060a0890135925060c08901356001600160401b03811115610f5e57600080fd5b610f6a8b828c01610d19565b999c989b5096995094979396929594505050565b60008060408385031215610f9157600080fd5b50508035926020909101359150565b600060208284031215610fb257600080fd5b5035919050565b600060208284031215610fcb57600080fd5b8135610fd681610cf6565b9392505050565b60006bffffffffffffffffffffffff19808b60601b168352808a60601b16601484015250876028830152866048830152856068830152846088830152828460a8840137506000910160a801908152979650505050505050565b60006020828403121561104857600080fd5b8151610fd681610cf6565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601260045260246000fd5b60008261108e5761108e611069565b500690565b634e487b7160e01b600052601160045260246000fd5b6000826110b8576110b8611069565b500490565b60006000198214156110d1576110d1611093565b5060010190565b600181815b808511156111135781600019048211156110f9576110f9611093565b8085161561110657918102915b93841c93908002906110dd565b509250929050565b60008261112a575060016111b8565b81611137575060006111b8565b816001811461114d576002811461115757611173565b60019150506111b8565b60ff84111561116857611168611093565b50506001821b6111b8565b5060208310610133831016604e8410600b8410161715611196575081810a6111b8565b6111a083836110d8565b80600019048211156111b4576111b4611093565b0290505b92915050565b6000610fd6838361111b565b60005b838110156111e55781810151838201526020016111cd565b838111156111f4576000848401525b50505050565b60018060a01b0384168152826020820152606060408201526000825180606084015261122d8160808501602087016111ca565b601f01601f191691909101608001949350505050565b6000806040838503121561125657600080fd5b8251801515811461126657600080fd5b60208401519092506001600160401b038082111561128357600080fd5b818501915085601f83011261129757600080fd5b8151818111156112a9576112a9610bfb565b6112bc601f8201601f1916602001610c11565b91508082528660208285010111156112d357600080fd5b6112e48160208401602086016111ca565b508092505050925092905056fea2646970667358221220fe96d12538caf4a4c82df9e3848da5c01165a067ade28ad28e200c44397c3fb664736f6c63430008090033
Deployed Bytecode
0x60806040523480156200001157600080fd5b5060043610620000ab5760003560e01c806395fd089f116200006e57806395fd089f146200015e578063ae583c031462000172578063e6027a871462000186578063f2fde38b146200019a578063fc6a2ed014620001b157600080fd5b80632147e58e14620000b05780636c6e47c014620000c9578063715018a6146200011f5780637ba0e85714620001295780638da5cb5b146200014c575b600080fd5b620000c7620000c136600462000812565b620001c5565b005b620000e0620000da36600462000882565b62000281565b604080516001600160a01b03968716815294861660208601529285169284019290925283166060830152909116608082015260a0015b60405180910390f35b620000c7620006ba565b6003546200013d906001600160a01b031681565b60405162000116919062000931565b6000546001600160a01b03166200013d565b6001546200013d906001600160a01b031681565b6004546200013d906001600160a01b031681565b6002546200013d906001600160a01b031681565b620000c7620001ab36600462000945565b620006f5565b6005546200013d906001600160a01b031681565b6000546001600160a01b03163314620001fb5760405162461bcd60e51b8152600401620001f2906200096a565b60405180910390fd5b600180546001600160a01b03199081166001600160a01b0388811691909117909255600280548216878416179055600380548216868416179055600480548216858416179055600580549091169183169190911790556040517fc9d3947d22fa124aaec4c7e8c919f79016e2d7b48eee10568375d98b86460d1b90600090a15050505050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905281908190819081906001546040516001600160a01b03909116908a90620002d990620007e7565b620002e69291906200099f565b604051809103906000f08015801562000303573d6000803e3d6000fd5b506001600160a01b0390811660208301526002546040519116908a906200032a90620007e7565b620003379291906200099f565b604051809103906000f08015801562000354573d6000803e3d6000fd5b506001600160a01b0390811660408084019190915260035490519116908a906200037e90620007e7565b6200038b9291906200099f565b604051809103906000f080158015620003a8573d6000803e3d6000fd5b506001600160a01b0390811660608301526004546040519116908a90620003cf90620007e7565b620003dc9291906200099f565b604051809103906000f080158015620003f9573d6000803e3d6000fd5b506001600160a01b0390811660808301526005546040519116908a906200042090620007e7565b6200042d9291906200099f565b604051809103906000f0801580156200044a573d6000803e3d6000fd5b506001600160a01b0390811660a0830152602082015160405163189acdbd60e31b815291169063c4d66de89062000486908b9060040162000931565b600060405180830381600087803b158015620004a157600080fd5b505af1158015620004b6573d6000803e3d6000fd5b5050506040808301516020808501518351630fbd495960e11b81526001600160a01b0391821660048201528c516024820152918c01516044830152928b0151606482015260608b0151608482015291169150631f7a92b29060a401600060405180830381600087803b1580156200052c57600080fd5b505af115801562000541573d6000803e3d6000fd5b50505060608201516020830151604080850151905163485cc95560e01b81526001600160a01b03928316600482015290821660248201529116915063485cc95590604401600060405180830381600087803b158015620005a057600080fd5b505af1158015620005b5573d6000803e3d6000fd5b5050505080608001516001600160a01b031663c4d66de882602001516040518263ffffffff1660e01b8152600401620005ef919062000931565b600060405180830381600087803b1580156200060a57600080fd5b505af11580156200061f573d6000803e3d6000fd5b505050508060a001516001600160a01b031663c4d66de882602001516040518263ffffffff1660e01b815260040162000659919062000931565b600060405180830381600087803b1580156200067457600080fd5b505af115801562000689573d6000803e3d6000fd5b50505050602081015160408201516060830151608084015160a090940151929c919b50995091975095509350505050565b6000546001600160a01b03163314620006e75760405162461bcd60e51b8152600401620001f2906200096a565b620006f3600062000797565b565b6000546001600160a01b03163314620007225760405162461bcd60e51b8152600401620001f2906200096a565b6001600160a01b038116620007895760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401620001f2565b620007948162000797565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610f6280620009c983390190565b80356001600160a01b03811681146200080d57600080fd5b919050565b600080600080600060a086880312156200082b57600080fd5b6200083686620007f5565b94506200084660208701620007f5565b93506200085660408701620007f5565b92506200086660608701620007f5565b91506200087660808701620007f5565b90509295509295909350565b600080600083850360c08112156200089957600080fd5b620008a485620007f5565b9350620008b460208601620007f5565b92506080603f1982011215620008c957600080fd5b506040516080810181811067ffffffffffffffff82111715620008fc57634e487b7160e01b600052604160045260246000fd5b806040525060408501358152606085013560208201526080850135604082015260a08501356060820152809150509250925092565b6001600160a01b0391909116815260200190565b6000602082840312156200095857600080fd5b6200096382620007f5565b9392505050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6001600160a01b039283168152911660208201526060604082018190526000908201526080019056fe608060405260405162000f6238038062000f62833981016040819052620000269162000519565b82816200005560017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005f9565b60008051602062000f1b833981519152146200007557620000756200061f565b6200008382826000620000e7565b50620000b3905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005f9565b60008051602062000efb83398151915214620000d357620000d36200061f565b620000de8262000124565b50505062000688565b620000f2836200017f565b600082511180620001005750805b156200011f576200011d8383620001c160201b620002601760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6200014f620001f0565b604080516001600160a01b03928316815291841660208301520160405180910390a16200017c8162000229565b50565b6200018a81620002de565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001e9838360405180606001604052806027815260200162000f3b6027913962000381565b9392505050565b60006200021a60008051602062000efb83398151915260001b6200046760201b620002081760201c565b546001600160a01b0316919050565b6001600160a01b038116620002945760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002bd60008051602062000efb83398151915260001b6200046760201b620002081760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002f4816200046a60201b6200028c1760201c565b620003585760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200028b565b80620002bd60008051602062000f1b83398151915260001b6200046760201b620002081760201c565b60606001600160a01b0384163b620003eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016200028b565b600080856001600160a01b03168560405162000408919062000635565b600060405180830381855af49150503d806000811462000445576040519150601f19603f3d011682016040523d82523d6000602084013e6200044a565b606091505b5090925090506200045d82828662000479565b9695505050505050565b90565b6001600160a01b03163b151590565b606083156200048a575081620001e9565b8251156200049b5782518084602001fd5b8160405162461bcd60e51b81526004016200028b919062000653565b80516001600160a01b0381168114620004cf57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000507578181015183820152602001620004ed565b838111156200011d5750506000910152565b6000806000606084860312156200052f57600080fd5b6200053a84620004b7565b92506200054a60208501620004b7565b60408501519092506001600160401b03808211156200056857600080fd5b818601915086601f8301126200057d57600080fd5b815181811115620005925762000592620004d4565b604051601f8201601f19908116603f01168101908382118183101715620005bd57620005bd620004d4565b81604052828152896020848701011115620005d757600080fd5b620005ea836020830160208801620004ea565b80955050505050509250925092565b6000828210156200061a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b6000825162000649818460208701620004ea565b9190910192915050565b602081526000825180602084015262000674816040850160208701620004ea565b601f01601f19169190910160400192915050565b61086380620006986000396000f3fe60806040526004361061004e5760003560e01c80633659cfe6146100655780634f1ef286146100855780635c60da1b146100985780638f283970146100c9578063f851a440146100e95761005d565b3661005d5761005b6100fe565b005b61005b6100fe565b34801561007157600080fd5b5061005b6100803660046106ed565b610118565b61005b610093366004610708565b61015f565b3480156100a457600080fd5b506100ad6101d0565b6040516001600160a01b03909116815260200160405180910390f35b3480156100d557600080fd5b5061005b6100e43660046106ed565b61020b565b3480156100f557600080fd5b506100ad610235565b61010661029b565b61011661011161033a565b610344565b565b610120610368565b6001600160a01b0316336001600160a01b03161415610157576101548160405180602001604052806000815250600061039b565b50565b6101546100fe565b610167610368565b6001600160a01b0316336001600160a01b031614156101c8576101c38383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506001925061039b915050565b505050565b6101c36100fe565b60006101da610368565b6001600160a01b0316336001600160a01b03161415610200576101fb61033a565b905090565b6102086100fe565b90565b610213610368565b6001600160a01b0316336001600160a01b0316141561015757610154816103c6565b600061023f610368565b6001600160a01b0316336001600160a01b03161415610200576101fb610368565b606061028583836040518060600160405280602781526020016108076027913961041a565b9392505050565b6001600160a01b03163b151590565b6102a3610368565b6001600160a01b0316336001600160a01b031614156101165760405162461bcd60e51b815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f78792074617267606482015261195d60f21b608482015260a4015b60405180910390fd5b60006101fb6104f5565b3660008037600080366000845af43d6000803e808015610363573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b546001600160a01b0316919050565b6103a48361051d565b6000825111806103b15750805b156101c3576103c08383610260565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6103ef610368565b604080516001600160a01b03928316815291841660208301520160405180910390a16101548161055d565b60606104258461028c565b6104805760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610331565b600080856001600160a01b03168560405161049b91906107b7565b600060405180830381855af49150503d80600081146104d6576040519150601f19603f3d011682016040523d82523d6000602084013e6104db565b606091505b50915091506104eb828286610606565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc61038c565b6105268161063f565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6001600160a01b0381166105c25760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b6064820152608401610331565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80546001600160a01b0319166001600160a01b039290921691909117905550565b60608315610615575081610285565b8251156106255782518084602001fd5b8160405162461bcd60e51b815260040161033191906107d3565b6106488161028c565b6106aa5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610331565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6105e5565b80356001600160a01b03811681146106e857600080fd5b919050565b6000602082840312156106ff57600080fd5b610285826106d1565b60008060006040848603121561071d57600080fd5b610726846106d1565b9250602084013567ffffffffffffffff8082111561074357600080fd5b818601915086601f83011261075757600080fd5b81358181111561076657600080fd5b87602082850101111561077857600080fd5b6020830194508093505050509250925092565b60005b838110156107a657818101518382015260200161078e565b838111156103c05750506000910152565b600082516107c981846020870161078b565b9190910192915050565b60208152600082518060208401526107f281604085016020870161078b565b601f01601f1916919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220fb0d75414bd881ce16381528bf0b9b2c1bea4c3e27069fcb6981b67d1535643064736f6c63430008090033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220b9239b356d47b5d41770e5c501cfed8f7323172098c560518542c8012309af5e64736f6c63430008090033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ 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.