Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SequencerInbox
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 {
AlreadyInit,
HadZeroInit,
NotOrigin,
DataTooLarge,
NotRollup,
DelayedBackwards,
DelayedTooFar,
ForceIncludeBlockTooSoon,
ForceIncludeTimeTooSoon,
IncorrectMessagePreimage,
NotBatchPoster,
BadSequencerNumber,
DataNotAuthenticated,
AlreadyValidDASKeyset,
NoSuchKeyset,
NotForked
} from "../libraries/Error.sol";
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;
/// @inheritdoc ISequencerInbox
uint256 public constant HEADER_LENGTH = 40;
/// @inheritdoc ISequencerInbox
bytes1 public constant DATA_AUTHENTICATED_FLAG = 0x40;
IOwnable public rollup;
mapping(address => bool) public isBatchPoster;
ISequencerInbox.MaxTimeVariation public maxTimeVariation;
mapping(bytes32 => DasKeySetInfo) public dasKeySetInfo;
modifier onlyRollupOwner() {
if (msg.sender != rollup.owner()) revert NotOwner(msg.sender, address(rollup));
_;
}
uint256 internal immutable deployTimeChainId = block.chainid;
function _chainIdChanged() internal view returns (bool) {
return deployTimeChainId != block.chainid;
}
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;
}
/// @inheritdoc ISequencerInbox
function removeDelayAfterFork() external {
if (!_chainIdChanged()) revert NotForked();
maxTimeVariation = ISequencerInbox.MaxTimeVariation({
delayBlocks: 1,
futureBlocks: 1,
delaySeconds: 1,
futureSeconds: 1
});
}
/// @inheritdoc ISequencerInbox
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 __totalDelayedMessagesRead = _totalDelayedMessagesRead;
uint256 prevSeqMsgCount = bridge.sequencerReportedSubMessageCount();
uint256 newSeqMsgCount = prevSeqMsgCount +
_totalDelayedMessagesRead -
totalDelayedMessagesRead;
(
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 afterAcc
) = addSequencerL2BatchImpl(
dataHash,
__totalDelayedMessagesRead,
0,
prevSeqMsgCount,
newSeqMsgCount
);
emit SequencerBatchDelivered(
seqMessageIndex,
beforeAcc,
afterAcc,
delayedAcc,
totalDelayedMessagesRead,
timeBounds,
BatchDataLocation.NoData
);
}
/// @dev Deprecated in favor of the variant specifying message counts for consistency
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, 0, 0);
if (seqMessageIndex != sequenceNumber)
revert BadSequencerNumber(seqMessageIndex, sequenceNumber);
emit SequencerBatchDelivered(
sequenceNumber,
beforeAcc,
afterAcc,
delayedAcc,
totalDelayedMessagesRead,
timeBounds,
BatchDataLocation.TxInput
);
}
function addSequencerL2BatchFromOrigin(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder,
uint256 prevMessageCount,
uint256 newMessageCount
) 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
);
// Reformat the stack to prevent "Stack too deep"
uint256 sequenceNumber_ = sequenceNumber;
TimeBounds memory timeBounds_ = timeBounds;
bytes32 dataHash_ = dataHash;
uint256 dataLength = data.length;
uint256 afterDelayedMessagesRead_ = afterDelayedMessagesRead;
uint256 prevMessageCount_ = prevMessageCount;
uint256 newMessageCount_ = newMessageCount;
(
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 afterAcc
) = addSequencerL2BatchImpl(
dataHash_,
afterDelayedMessagesRead_,
dataLength,
prevMessageCount_,
newMessageCount_
);
if (seqMessageIndex != sequenceNumber_ && sequenceNumber_ != ~uint256(0))
revert BadSequencerNumber(seqMessageIndex, sequenceNumber_);
emit SequencerBatchDelivered(
seqMessageIndex,
beforeAcc,
afterAcc,
delayedAcc,
totalDelayedMessagesRead,
timeBounds_,
BatchDataLocation.TxInput
);
}
function addSequencerL2Batch(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder,
uint256 prevMessageCount,
uint256 newMessageCount
) external override refundsGas(gasRefunder) {
if (!isBatchPoster[msg.sender] && msg.sender != address(rollup)) revert NotBatchPoster();
(bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash(
data,
afterDelayedMessagesRead
);
uint256 seqMessageIndex;
{
// Reformat the stack to prevent "Stack too deep"
uint256 sequenceNumber_ = sequenceNumber;
TimeBounds memory timeBounds_ = timeBounds;
bytes32 dataHash_ = dataHash;
uint256 afterDelayedMessagesRead_ = afterDelayedMessagesRead;
uint256 prevMessageCount_ = prevMessageCount;
uint256 newMessageCount_ = newMessageCount;
// 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
bytes32 beforeAcc;
bytes32 delayedAcc;
bytes32 afterAcc;
(seqMessageIndex, beforeAcc, delayedAcc, afterAcc) = addSequencerL2BatchImpl(
dataHash_,
afterDelayedMessagesRead_,
0,
prevMessageCount_,
newMessageCount_
);
if (seqMessageIndex != sequenceNumber_ && sequenceNumber_ != ~uint256(0))
revert BadSequencerNumber(seqMessageIndex, sequenceNumber_);
emit SequencerBatchDelivered(
seqMessageIndex,
beforeAcc,
afterAcc,
delayedAcc,
totalDelayedMessagesRead,
timeBounds_,
BatchDataLocation.SeparateBatchEvent
);
}
emit SequencerBatchData(seqMessageIndex, 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,
uint256 prevMessageCount,
uint256 newMessageCount
)
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,
prevMessageCount,
newMessageCount
);
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 returns (bytes32) {
return bridge.sequencerInboxAccs(index);
}
function batchCount() external view returns (uint256) {
return bridge.sequencerMessageCount();
}
/// @inheritdoc ISequencerInbox
function setMaxTimeVariation(ISequencerInbox.MaxTimeVariation memory maxTimeVariation_)
external
onlyRollupOwner
{
maxTimeVariation = maxTimeVariation_;
emit OwnerFunctionCalled(0);
}
/// @inheritdoc ISequencerInbox
function setIsBatchPoster(address addr, bool isBatchPoster_) external onlyRollupOwner {
isBatchPoster[addr] = isBatchPoster_;
emit OwnerFunctionCalled(1);
}
/// @inheritdoc ISequencerInbox
function setValidKeyset(bytes calldata keysetBytes) external onlyRollupOwner {
uint256 ksWord = uint256(keccak256(bytes.concat(hex"fe", keccak256(keysetBytes))));
bytes32 ksHash = bytes32(ksWord ^ (1 << 255));
require(keysetBytes.length < 64 * 1024, "keyset is too large");
if (dasKeySetInfo[ksHash].isValidKeyset) revert AlreadyValidDASKeyset(ksHash);
dasKeySetInfo[ksHash] = DasKeySetInfo({
isValidKeyset: true,
creationBlock: uint64(block.number)
});
emit SetValidKeyset(ksHash, keysetBytes);
emit OwnerFunctionCalled(2);
}
/// @inheritdoc ISequencerInbox
function invalidateKeysetHash(bytes32 ksHash) external 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;
}
/// @inheritdoc ISequencerInbox
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.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);
// Bridge Errors
/// @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);
// Inbox Errors
/// @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
);
/// @dev Thrown when a L1 chainId fork is detected
error L1Forked();
/// @dev Thrown when a L1 chainId fork is not detected
error NotForked();
// Outbox Errors
/// @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();
// Sequencer Inbox Errors
/// @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 sequence message number provided to this message was inconsistent with the previous one
error BadSequencerMessageNumber(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);// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
import "./IOwnable.sol";
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 allowedDelayedInboxList(uint256) external returns (address);
function allowedOutboxList(uint256) external returns (address);
/// @dev Accumulator for delayed inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
function delayedInboxAccs(uint256) external view returns (bytes32);
/// @dev Accumulator for sequencer inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
function sequencerInboxAccs(uint256) external view returns (bytes32);
function rollup() external view returns (IOwnable);
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 sequencerReportedSubMessageCount() external view returns (uint256);
/**
* @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 returns (uint256);
function executeCall(
address to,
uint256 value,
bytes calldata data
) external returns (bool success, bytes memory returnData);
function delayedMessageCount() external view returns (uint256);
function sequencerMessageCount() external view returns (uint256);
// ---------- onlySequencerInbox functions ----------
function enqueueSequencerMessage(
bytes32 dataHash,
uint256 afterDelayedMessagesRead,
uint256 prevMessageCount,
uint256 newMessageCount
)
external
returns (
uint256 seqMessageIndex,
bytes32 beforeAcc,
bytes32 delayedAcc,
bytes32 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 batchPoster, bytes32 dataHash)
external
returns (uint256 msgNum);
// ---------- onlyRollupOrOwner functions ----------
function setSequencerInbox(address _sequencerInbox) external;
function setDelayedInbox(address inbox, bool enabled) external;
function setOutbox(address inbox, bool enabled) external;
// ---------- initializer ----------
function initialize(IOwnable rollup_) external;
}// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
import "./IBridge.sol";
import "./IDelayedMessageProvider.sol";
import "./ISequencerInbox.sol";
interface IInbox is IDelayedMessageProvider {
function bridge() external view returns (IBridge);
function sequencerInbox() external view returns (ISequencerInbox);
/**
* @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
* This method will be disabled upon L1 fork to prevent replay attacks on L2
* @param messageData Data of the message being sent
*/
function sendL2MessageFromOrigin(bytes calldata messageData) external returns (uint256);
/**
* @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
* This method will be disabled upon L1 fork to prevent replay attacks on L2
* @param messageData Data of the message being sent
*/
function sendL2Message(bytes calldata messageData) 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);
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);
/**
* @dev This method can only be called upon L1 fork and will not alias the caller
* This method will revert if not called from origin
*/
function sendL1FundedUnsignedTransactionToFork(
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 nonce,
address to,
bytes calldata data
) external payable returns (uint256);
/**
* @dev This method can only be called upon L1 fork and will not alias the caller
* This method will revert if not called from origin
*/
function sendUnsignedTransactionToFork(
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 nonce,
address to,
uint256 value,
bytes calldata data
) external returns (uint256);
/**
* @notice Send a message to initiate L2 withdrawal
* @dev This method can only be called upon L1 fork and will not alias the caller
* This method will revert if not called from origin
*/
function sendWithdrawEthToFork(
uint256 gasLimit,
uint256 maxFeePerGas,
uint256 nonce,
uint256 value,
address withdrawTo
) external returns (uint256);
/**
* @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, if 0 current block.basefee will be used
*/
function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee)
external
view
returns (uint256);
/**
* @notice Deposit eth from L1 to L2 to address of the sender if sender is an EOA, and to its aliased address if the sender is a contract
* @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() external payable returns (uint256);
/**
* @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 message number of the retryable transaction
*/
function createRetryableTicket(
address to,
uint256 l2CallValue,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
bytes calldata data
) external payable returns (uint256);
/**
* @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 message number of the retryable transaction
*/
function unsafeCreateRetryableTicket(
address to,
uint256 l2CallValue,
uint256 maxSubmissionCost,
address excessFeeRefundAddress,
address callValueRefundAddress,
uint256 gasLimit,
uint256 maxFeePerGas,
bytes calldata data
) external payable returns (uint256);
// ---------- onlyRollupOrOwner functions ----------
/// @notice pauses all inbox functionality
function pause() external;
/// @notice unpauses all inbox functionality
function unpause() external;
// ---------- initializer ----------
/**
* @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;
function initialize(IBridge _bridge, ISequencerInbox _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
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
pragma experimental ABIEncoderV2;
import "../libraries/IGasRefunder.sol";
import "./IDelayedMessageProvider.sol";
import "./IBridge.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);
function totalDelayedMessagesRead() external view returns (uint256);
function bridge() external view returns (IBridge);
/// @dev The size of the batch header
// solhint-disable-next-line func-name-mixedcase
function HEADER_LENGTH() external view returns (uint256);
/// @dev If the first batch data byte after the header has this bit set,
/// the sequencer inbox has authenticated the data. Currently not used.
// solhint-disable-next-line func-name-mixedcase
function DATA_AUTHENTICATED_FLAG() external view returns (bytes1);
function rollup() external view returns (IOwnable);
function isBatchPoster(address) external view returns (bool);
struct DasKeySetInfo {
bool isValidKeyset;
uint64 creationBlock;
}
// https://github.com/ethereum/solidity/issues/11826
// function maxTimeVariation() external view returns (MaxTimeVariation calldata);
// function dasKeySetInfo(bytes32) external view returns (DasKeySetInfo calldata);
/// @notice Remove force inclusion delay after a L1 chainId fork
function removeDelayAfterFork() external;
/// @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;
function inboxAccs(uint256 index) external view returns (bytes32);
function batchCount() external view returns (uint256);
function isValidKeysetHash(bytes32 ksHash) external view returns (bool);
/// @notice the creation block is intended to still be available after a keyset is deleted
function getKeysetCreationBlock(bytes32 ksHash) external view returns (uint256);
// ---------- BatchPoster functions ----------
function addSequencerL2BatchFromOrigin(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder
) external;
function addSequencerL2Batch(
uint256 sequenceNumber,
bytes calldata data,
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder,
uint256 prevMessageCount,
uint256 newMessageCount
) external;
// ---------- onlyRollupOrOwner functions ----------
/**
* @notice Set max delay for sequencer inbox
* @param maxTimeVariation_ the maximum time variation parameters
*/
function setMaxTimeVariation(MaxTimeVariation memory maxTimeVariation_) 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;
/**
* @notice Makes Data Availability Service keyset valid
* @param keysetBytes bytes of the serialized keyset
*/
function setValidKeyset(bytes calldata keysetBytes) external;
/**
* @notice Invalidates a Data Availability Service keyset
* @param ksHash hash of the keyset
*/
function invalidateKeysetHash(bytes32 ksHash) external;
// ---------- initializer ----------
function initialize(IBridge bridge_, MaxTimeVariation calldata maxTimeVariation_) 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 "./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 removeWhitelistAfterFork() external;
function removeWhitelistAfterValidatorAfk() external;
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;
/**
* @notice set the validatorWhitelistDisabled flag
* @param _validatorWhitelistDisabled new value of validatorWhitelistDisabled, i.e. true = disabled
*/
function setValidatorWhitelistDisabled(bool _validatorWhitelistDisabled) 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;
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.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
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <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;
assembly {
calldataSize := calldatasize()
}
uint256 calldataWords = (calldataSize + 31) / 32;
// account for the CALLDATACOPY cost of the proxy contract, including the memory expansion cost
startGasLeft += calldataWords * 6 + (calldataWords**2) / 512;
// 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
// solhint-disable-next-line avoid-tx-origin
if (msg.sender != tx.origin) {
// We can't be sure if this calldata came from the top level tx,
// so to be safe we tell the gas refunder there was no calldata.
calldataSize = 0;
}
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.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; // 90% of Geth's 128KB tx size limit, leaving ~13KB for proving uint256 constant MAX_DATA_SIZE = 117964; uint64 constant NO_CHAL_INDEX = 0; // Expected seconds per block in Ethereum PoS uint256 constant ETH_POS_BLOCK_TIME = 12;
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1
// solhint-disable-next-line compiler-version
pragma solidity >=0.4.21 <0.9.0;
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
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.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;
uint64 genesisBlockNum;
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);
function validatorWhitelistDisabled() 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
// solhint-disable-next-line compiler-version
pragma solidity >=0.6.9 <0.9.0;
import "./IBridge.sol";
interface IOutbox {
event SendRootUpdated(bytes32 indexed outputRoot, bytes32 indexed l2BlockHash);
event OutBoxTransactionExecuted(
address indexed to,
address indexed l2Sender,
uint256 indexed zero,
uint256 transactionIndex
);
function rollup() external view returns (address); // the rollup contract
function bridge() external view returns (IBridge); // the bridge contract
function spent(uint256) external view returns (bytes32); // packed spent bitmap
function roots(bytes32) external view returns (bytes32); // maps root hashes => L2 block hash
// solhint-disable-next-line func-name-mixedcase
function OUTBOX_VERSION() external view returns (uint128); // the outbox version
function updateSendRoot(bytes32 sendRoot, bytes32 l2BlockHash) external;
/// @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 returns (address);
/// @return l2Block return L2 block when the L2 tx was initiated or 0 if no L2 to L1 transaction is active
function l2ToL1Block() external view returns (uint256);
/// @return l1Block return L1 block when the L2 tx was initiated or 0 if no L2 to L1 transaction is active
function l2ToL1EthBlock() external view returns (uint256);
/// @return timestamp return L2 timestamp when the L2 tx was initiated or 0 if no L2 to L1 transaction is active
function l2ToL1Timestamp() external view returns (uint256);
/// @return outputId returns the unique output identifier of the L2 to L1 tx or 0 if no L2 to L1 transaction is active
function l2ToL1OutputId() external view returns (bytes32);
/**
* @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.
* @dev it is not possible to execute any L2-to-L1 transaction which contains data
* to a contract address without any code (as enforced by the Bridge contract).
* @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;
/**
* @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 practical 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;
/**
* @param index Merkle path to message
* @return true if the message has been spent
*/
function isSpent(uint256 index) external view returns (bool);
function calculateItemHash(
address l2Sender,
address to,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 value,
bytes calldata data
) external pure returns (bytes32);
function calculateMerkleRoot(
bytes32[] memory proof,
uint256 path,
bytes32 item
) external pure returns (bytes32);
}// 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 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];
}
function isEmpty(GlobalState calldata state) internal pure returns (bool) {
return (state.bytes32Vals[0] == bytes32(0) &&
state.bytes32Vals[1] == bytes32(0) &&
state.u64Vals[0] == 0 &&
state.u64Vals[1] == 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 "../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");
}
}{
"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
Contract ABI
API[{"inputs":[],"name":"AlreadyInit","type":"error"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"AlreadyValidDASKeyset","type":"error"},{"inputs":[{"internalType":"uint256","name":"stored","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"}],"name":"BadSequencerNumber","type":"error"},{"inputs":[],"name":"DataNotAuthenticated","type":"error"},{"inputs":[{"internalType":"uint256","name":"dataLength","type":"uint256"},{"internalType":"uint256","name":"maxDataLength","type":"uint256"}],"name":"DataTooLarge","type":"error"},{"inputs":[],"name":"DelayedBackwards","type":"error"},{"inputs":[],"name":"DelayedTooFar","type":"error"},{"inputs":[],"name":"ForceIncludeBlockTooSoon","type":"error"},{"inputs":[],"name":"ForceIncludeTimeTooSoon","type":"error"},{"inputs":[],"name":"HadZeroInit","type":"error"},{"inputs":[],"name":"IncorrectMessagePreimage","type":"error"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"NoSuchKeyset","type":"error"},{"inputs":[],"name":"NotBatchPoster","type":"error"},{"inputs":[],"name":"NotForked","type":"error"},{"inputs":[],"name":"NotOrigin","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"NotOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"messageNum","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"InboxMessageDelivered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"messageNum","type":"uint256"}],"name":"InboxMessageDeliveredFromOrigin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"keysetHash","type":"bytes32"}],"name":"InvalidateKeyset","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"OwnerFunctionCalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"batchSequenceNumber","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"SequencerBatchData","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"batchSequenceNumber","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"beforeAcc","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"afterAcc","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"delayedAcc","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"afterDelayedMessagesRead","type":"uint256"},{"components":[{"internalType":"uint64","name":"minTimestamp","type":"uint64"},{"internalType":"uint64","name":"maxTimestamp","type":"uint64"},{"internalType":"uint64","name":"minBlockNumber","type":"uint64"},{"internalType":"uint64","name":"maxBlockNumber","type":"uint64"}],"indexed":false,"internalType":"struct ISequencerInbox.TimeBounds","name":"timeBounds","type":"tuple"},{"indexed":false,"internalType":"enum ISequencerInbox.BatchDataLocation","name":"dataLocation","type":"uint8"}],"name":"SequencerBatchDelivered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"keysetHash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"keysetBytes","type":"bytes"}],"name":"SetValidKeyset","type":"event"},{"inputs":[],"name":"DATA_AUTHENTICATED_FLAG","outputs":[{"internalType":"bytes1","name":"","type":"bytes1"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HEADER_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sequenceNumber","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"afterDelayedMessagesRead","type":"uint256"},{"internalType":"contract IGasRefunder","name":"gasRefunder","type":"address"},{"internalType":"uint256","name":"prevMessageCount","type":"uint256"},{"internalType":"uint256","name":"newMessageCount","type":"uint256"}],"name":"addSequencerL2Batch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sequenceNumber","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"afterDelayedMessagesRead","type":"uint256"},{"internalType":"contract IGasRefunder","name":"gasRefunder","type":"address"}],"name":"addSequencerL2BatchFromOrigin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sequenceNumber","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"afterDelayedMessagesRead","type":"uint256"},{"internalType":"contract IGasRefunder","name":"gasRefunder","type":"address"},{"internalType":"uint256","name":"prevMessageCount","type":"uint256"},{"internalType":"uint256","name":"newMessageCount","type":"uint256"}],"name":"addSequencerL2BatchFromOrigin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"batchCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bridge","outputs":[{"internalType":"contract IBridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"dasKeySetInfo","outputs":[{"internalType":"bool","name":"isValidKeyset","type":"bool"},{"internalType":"uint64","name":"creationBlock","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalDelayedMessagesRead","type":"uint256"},{"internalType":"uint8","name":"kind","type":"uint8"},{"internalType":"uint64[2]","name":"l1BlockAndTime","type":"uint64[2]"},{"internalType":"uint256","name":"baseFeeL1","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes32","name":"messageDataHash","type":"bytes32"}],"name":"forceInclusion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"ksHash","type":"bytes32"}],"name":"getKeysetCreationBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"inboxAccs","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IBridge","name":"bridge_","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":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"ksHash","type":"bytes32"}],"name":"invalidateKeysetHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isBatchPoster","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"ksHash","type":"bytes32"}],"name":"isValidKeysetHash","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTimeVariation","outputs":[{"internalType":"uint256","name":"delayBlocks","type":"uint256"},{"internalType":"uint256","name":"futureBlocks","type":"uint256"},{"internalType":"uint256","name":"delaySeconds","type":"uint256"},{"internalType":"uint256","name":"futureSeconds","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"removeDelayAfterFork","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rollup","outputs":[{"internalType":"contract IOwnable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"isBatchPoster_","type":"bool"}],"name":"setIsBatchPoster","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"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":"setMaxTimeVariation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"keysetBytes","type":"bytes"}],"name":"setValidKeyset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalDelayedMessagesRead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60c0604052306080524660a05234801561001857600080fd5b5060805160a05161235761003e6000396000610c890152600061041901526123576000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c80638f111f3c116100b8578063d9dd67ab1161007c578063d9dd67ab146102e8578063e0bc9729146102fb578063e5a358c81461030e578063e78cea9214610332578063ebea461d14610345578063f19815781461037b57600080fd5b80638f111f3c1461027c57806396cc5c781461028f578063b31761f814610297578063cb23bcb5146102aa578063d1ce8da8146102d557600080fd5b80636e7df3e71161010a5780636e7df3e7146101c55780636f12b0c9146101d8578063715ea34b146101eb57806371c3e6fe1461023d5780637fa3a40e14610260578063844208601461026957600080fd5b806306f13056146101475780631637be48146101625780631f7a92b214610195578063258f0495146101aa57806327957a49146101bd575b600080fd5b61014f61038e565b6040519081526020015b60405180910390f35b610185610170366004611b9e565b60009081526008602052604090205460ff1690565b6040519015158152602001610159565b6101a86101a3366004611bcf565b61040e565b005b61014f6101b8366004611b9e565b6105c6565b61014f602881565b6101a86101d3366004611c1e565b61062f565b6101a86101e6366004611c9f565b610735565b61021e6101f9366004611b9e565b60086020526000908152604090205460ff81169061010090046001600160401b031682565b6040805192151583526001600160401b03909116602083015201610159565b61018561024b366004611d09565b60036020526000908152604090205460ff1681565b61014f60005481565b6101a8610277366004611b9e565b610924565b6101a861028a366004611d2d565b610a77565b6101a8610c86565b6101a86102a5366004611da9565b610cfd565b6002546102bd906001600160a01b031681565b6040516001600160a01b039091168152602001610159565b6101a86102e3366004611e1c565b610dfd565b61014f6102f6366004611b9e565b611045565b6101a8610309366004611d2d565b6110c8565b610319600160fe1b81565b6040516001600160f81b03199091168152602001610159565b6001546102bd906001600160a01b031681565b60045460055460065460075461035b9392919084565b604080519485526020850193909352918301526060820152608001610159565b6101a8610389366004611e5d565b61121d565b600154604080516221048360e21b815290516000926001600160a01b0316916284120c916004808301926020929190829003018186803b1580156103d157600080fd5b505afa1580156103e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104099190611ecd565b905090565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614156104a15760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b60648201526084015b60405180910390fd5b6001546001600160a01b0316156104cb57604051633bcd329760e21b815260040160405180910390fd5b6001600160a01b0382166104f257604051631ad0f74360e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0384169081179091556040805163cb23bcb560e01b8152905163cb23bcb591600480820192602092909190829003018186803b15801561054657600080fd5b505afa15801561055a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057e9190611ee6565b600280546001600160a01b0319166001600160a01b03929092169190911790558035600490815560208201356005556040820135600655606082013560075581905b50505050565b600081815260086020908152604080832081518083019092525460ff81161515825261010090046001600160401b03169181018290529061061c5760405162f20c5d60e01b815260048101849052602401610498565b602001516001600160401b031692915050565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561067d57600080fd5b505afa158015610691573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b59190611ee6565b6001600160a01b0316336001600160a01b0316146106f757600254604051631194af8760e11b81526104989133916001600160a01b0390911690600401611f03565b6001600160a01b038216600090815260036020526040808220805460ff19168415151790555160019160008051602061230283398151915291a25050565b8060005a905033321461075b5760405163feb3d07160e01b815260040160405180910390fd5b3360009081526003602052604090205460ff1661078b57604051632dd9fc9760e01b815260040160405180910390fd5b600080610799888888611600565b909250905060008080806107b0868b8d8480611773565b93509350935093508c84146107e25760405163ac7411c960e01b815260048101859052602481018e9052604401610498565b80838e6000805160206122e2833981519152856000548a600060405161080b9493929190611f1d565b60405180910390a4505050506001600160a01b03841615915061091b905057366000602061083a83601f611fa7565b6108449190611fbf565b90506102006108546002836120c5565b61085e9190611fbf565b6108698260066120d4565b6108739190611fa7565b61087d9084611fa7565b925033321461088b57600091505b836001600160a01b031663e3db8a49335a6108a690876120f3565b856040518463ffffffff1660e01b81526004016108c59392919061210a565b602060405180830381600087803b1580156108df57600080fd5b505af11580156108f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610917919061212b565b5050505b50505050505050565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561097257600080fd5b505afa158015610986573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109aa9190611ee6565b6001600160a01b0316336001600160a01b0316146109ec57600254604051631194af8760e11b81526104989133916001600160a01b0390911690600401611f03565b60008181526008602052604090205460ff16610a1d5760405162f20c5d60e01b815260048101829052602401610498565b600081815260086020526040808220805460ff191690555182917f5cb4218b272fd214168ac43e90fb4d05d6c36f0b17ffb4c2dd07c234d744eb2a91a260405160039060008051602061230283398151915290600090a250565b8260005a9050333214610a9d5760405163feb3d07160e01b815260040160405180910390fd5b3360009081526003602052604090205460ff16610acd57604051632dd9fc9760e01b815260040160405180910390fd5b600080610adb8a8a8a611600565b90925090508a81838b8b8a8a6000808080610af989888a8989611773565b93509350935093508a8414158015610b1357506000198b14155b15610b3b5760405163ac7411c960e01b815260048101859052602481018c9052604401610498565b8083856000805160206122e2833981519152856000548f6000604051610b649493929190611f1d565b60405180910390a4505050506001600160a01b038b16159850610c7b975050505050505050573660006020610b9a83601f611fa7565b610ba49190611fbf565b9050610200610bb46002836120c5565b610bbe9190611fbf565b610bc98260066120d4565b610bd39190611fa7565b610bdd9084611fa7565b9250333214610beb57600091505b836001600160a01b031663e3db8a49335a610c0690876120f3565b856040518463ffffffff1660e01b8152600401610c259392919061210a565b602060405180830381600087803b158015610c3f57600080fd5b505af1158015610c53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c77919061212b565b5050505b505050505050505050565b467f00000000000000000000000000000000000000000000000000000000000000001415610cc757604051635180dd8360e11b815260040160405180910390fd5b60408051608081018252600180825260208201819052918101829052606001819052600481905560058190556006819055600755565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d4b57600080fd5b505afa158015610d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d839190611ee6565b6001600160a01b0316336001600160a01b031614610dc557600254604051631194af8760e11b81526104989133916001600160a01b0390911690600401611f03565b80516004556020810151600555604080820151600655606082015160075551600090600080516020612302833981519152908290a250565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e4b57600080fd5b505afa158015610e5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e839190611ee6565b6001600160a01b0316336001600160a01b031614610ec557600254604051631194af8760e11b81526104989133916001600160a01b0390911690600401611f03565b60008282604051610ed7929190612148565b604051908190038120607f60f91b6020830152602182015260410160408051601f1981840301815291905280516020909101209050600160ff1b8118620100008310610f5b5760405162461bcd60e51b81526020600482015260136024820152726b657973657420697320746f6f206c6172676560681b6044820152606401610498565b60008181526008602052604090205460ff1615610f8e57604051637d17eeed60e11b815260048101829052602401610498565b60408051808201825260018152436001600160401b0390811660208084019182526000868152600890915284902092518354915168ffffffffffffffffff1990921690151568ffffffffffffffff0019161761010091909216021790555181907fabca9b7986bc22ad0160eb0cb88ae75411eacfba4052af0b457a9335ef6557229061101d9087908790612158565b60405180910390a260405160029060008051602061230283398151915290600090a250505050565b6001546040516316bf557960e01b8152600481018390526000916001600160a01b0316906316bf55799060240160206040518083038186803b15801561108a57600080fd5b505afa15801561109e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c29190611ecd565b92915050565b8260005a3360009081526003602052604090205490915060ff161580156110fa57506002546001600160a01b03163314155b1561111857604051632dd9fc9760e01b815260040160405180910390fd5b6000806111268a8a8a611600565b909250905060008b82848b8a8a8680806111438787838888611773565b929c5090945092509050888a1480159061115f57506000198914155b156111875760405163ac7411c960e01b8152600481018b9052602481018a9052604401610498565b80838b6000805160206122e2833981519152856000548d60016040516111b09493929190611f1d565b60405180910390a4505050505050505050807ffe325ca1efe4c5c1062c981c3ee74b781debe4ea9440306a96d2a55759c66c208c8c6040516111f3929190612158565b60405180910390a25050506001600160a01b03821615610c7b573660006020610b9a83601f611fa7565b600054861161123f57604051633eb9f37d60e11b815260040160405180910390fd5b60006112ef8684611253602089018961219d565b61126360408a0160208b0161219d565b61126e60018d6120f3565b6040805160f89690961b6001600160f81b03191660208088019190915260609590951b6001600160601b031916602187015260c093841b6001600160c01b031990811660358801529290931b909116603d85015260458401526065830188905260858084018790528151808503909101815260a59093019052815191012090565b6004549091504390611304602088018861219d565b6001600160401b03166113179190611fa7565b106113355760405163ad3515d960e01b815260040160405180910390fd5b600654429061134a604088016020890161219d565b6001600160401b031661135d9190611fa7565b1061137b5760405163c76d17e560e01b815260040160405180910390fd5b60006001881115611413576001546001600160a01b031663d5719dc26113a260028b6120f3565b6040518263ffffffff1660e01b81526004016113c091815260200190565b60206040518083038186803b1580156113d857600080fd5b505afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114109190611ecd565b90505b60408051602080820184905281830185905282518083038401815260609092019092528051910120600180546001600160a01b03169063d5719dc290611459908c6120f3565b6040518263ffffffff1660e01b815260040161147791815260200190565b60206040518083038186803b15801561148f57600080fd5b505afa1580156114a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c79190611ecd565b146114e5576040516313947fd760e01b815260040160405180910390fd5b6000806114f18a611a10565b9150915060008a90506000600160009054906101000a90046001600160a01b03166001600160a01b0316635fca4a166040518163ffffffff1660e01b815260040160206040518083038186803b15801561154a57600080fd5b505afa15801561155e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115829190611ecd565b9050600080548d836115949190611fa7565b61159e91906120f3565b90506000806000806115b4898860008989611773565b93509350935093508083856000805160206122e2833981519152856000548d60026040516115e59493929190611f1d565b60405180910390a45050505050505050505050505050505050565b600061160a611b77565b84846000611619826028611fa7565b90506201cccc81111561164b57604051634634691b60e01b8152600481018290526201cccc6024820152604401610498565b81158015906116835750600160fe1b80848460008161166c5761166c612187565b9050013560f81c60f81b166001600160f81b031916145b156116a157604051631f97007f60e01b815260040160405180910390fd5b602182108015906116cf5750828260008181106116c0576116c0612187565b90910135600160ff1b16151590505b156117235760006116e46021600185876121c6565b6116ed916121f0565b60008181526008602052604090205490915060ff166117215760405162f20c5d60e01b815260048101829052602401610498565b505b60008061172f88611a3c565b915091506000828b8b60405160200161174a9392919061223a565b60408051808303601f1901815291905280516020909101209b919a509098505050505050505050565b60008060008060005488101561179c57604051633eb9f37d60e11b815260040160405180910390fd5b600160009054906101000a90046001600160a01b03166001600160a01b031663eca067ad6040518163ffffffff1660e01b815260040160206040518083038186803b1580156117ea57600080fd5b505afa1580156117fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118229190611ecd565b8811156118425760405163925f8bd360e01b815260040160405180910390fd5b60015460405163432cc52b60e11b8152600481018b9052602481018a905260448101889052606481018790526001600160a01b03909116906386598a5690608401608060405180830381600087803b15801561189d57600080fd5b505af11580156118b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d59190612262565b60008c9055929650909450925090508615611a04576040805142602082015233606081901b6001600160601b03191692820192909252605481018b90526074810186905248609482015260009060b40160408051808303601f190181529082905260015481516020830120637a88b10760e01b84526001600160a01b0386811660048601526024850191909152919350600092911690637a88b10790604401602060405180830381600087803b15801561198e57600080fd5b505af11580156119a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c69190611ecd565b9050807fff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b836040516119f89190612298565b60405180910390a25050505b95509550955095915050565b6000611a1a611b77565b600080611a2685611a3c565b8151602090920191909120969095509350505050565b6060611a46611b77565b6000611a50611ae3565b90506000816000015182602001518360400151846060015188604051602001611ab895949392919060c095861b6001600160c01b0319908116825294861b8516600882015292851b8416601084015290841b8316601883015290921b16602082015260280190565b60405160208183030381529060405290506028815114611ada57611ada6122cb565b94909350915050565b611aeb611b77565b611af3611b77565b600654421115611b1657600654611b0a90426120f3565b6001600160401b031681525b600754611b239042611fa7565b6001600160401b03166020820152600454431115611b5757600454611b4890436120f3565b6001600160401b031660408201525b600554611b649043611fa7565b6001600160401b03166060820152919050565b60408051608081018252600080825260208201819052918101829052606081019190915290565b600060208284031215611bb057600080fd5b5035919050565b6001600160a01b0381168114611bcc57600080fd5b50565b60008082840360a0811215611be357600080fd5b8335611bee81611bb7565b92506080601f1982011215611c0257600080fd5b506020830190509250929050565b8015158114611bcc57600080fd5b60008060408385031215611c3157600080fd5b8235611c3c81611bb7565b91506020830135611c4c81611c10565b809150509250929050565b60008083601f840112611c6957600080fd5b5081356001600160401b03811115611c8057600080fd5b602083019150836020828501011115611c9857600080fd5b9250929050565b600080600080600060808688031215611cb757600080fd5b8535945060208601356001600160401b03811115611cd457600080fd5b611ce088828901611c57565b909550935050604086013591506060860135611cfb81611bb7565b809150509295509295909350565b600060208284031215611d1b57600080fd5b8135611d2681611bb7565b9392505050565b600080600080600080600060c0888a031215611d4857600080fd5b8735965060208801356001600160401b03811115611d6557600080fd5b611d718a828b01611c57565b909750955050604088013593506060880135611d8c81611bb7565b969995985093969295946080840135945060a09093013592915050565b600060808284031215611dbb57600080fd5b604051608081018181106001600160401b0382111715611deb57634e487b7160e01b600052604160045260246000fd5b8060405250823581526020830135602082015260408301356040820152606083013560608201528091505092915050565b60008060208385031215611e2f57600080fd5b82356001600160401b03811115611e4557600080fd5b611e5185828601611c57565b90969095509350505050565b60008060008060008060e08789031215611e7657600080fd5b86359550602087013560ff81168114611e8e57600080fd5b94506080870188811115611ea157600080fd5b60408801945035925060a0870135611eb881611bb7565b8092505060c087013590509295509295509295565b600060208284031215611edf57600080fd5b5051919050565b600060208284031215611ef857600080fd5b8151611d2681611bb7565b6001600160a01b0392831681529116602082015260400190565b600060e0820190508582528460208301526001600160401b038085511660408401528060208601511660608401528060408601511660808401528060608601511660a08401525060038310611f8257634e487b7160e01b600052602160045260246000fd5b8260c083015295945050505050565b634e487b7160e01b600052601160045260246000fd5b60008219821115611fba57611fba611f91565b500190565b600082611fdc57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561201c57816000190482111561200257612002611f91565b8085161561200f57918102915b93841c9390800290611fe6565b509250929050565b600082612033575060016110c2565b81612040575060006110c2565b816001811461205657600281146120605761207c565b60019150506110c2565b60ff84111561207157612071611f91565b50506001821b6110c2565b5060208310610133831016604e8410600b841016171561209f575081810a6110c2565b6120a98383611fe1565b80600019048211156120bd576120bd611f91565b029392505050565b6000611d2660ff841683612024565b60008160001904831182151516156120ee576120ee611f91565b500290565b60008282101561210557612105611f91565b500390565b6001600160a01b039390931683526020830191909152604082015260600190565b60006020828403121561213d57600080fd5b8151611d2681611c10565b8183823760009101908152919050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156121af57600080fd5b81356001600160401b0381168114611d2657600080fd5b600080858511156121d657600080fd5b838611156121e357600080fd5b5050820193919092039150565b803560208310156110c257600019602084900360031b1b1692915050565b60005b83811015612229578181015183820152602001612211565b838111156105c05750506000910152565b6000845161224c81846020890161220e565b8201838582376000930192835250909392505050565b6000806000806080858703121561227857600080fd5b505082516020840151604085015160609095015191969095509092509050565b60208152600082518060208401526122b781604085016020870161220e565b601f01601f19169190910160400192915050565b634e487b7160e01b600052600160045260246000fdfe7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7ea8787f128d10b2cc0317b0c3960f9ad447f7f6c1ed189db1083ccffd20f456ea264697066735822122037f21842a3c6a5f06afa8ec57c8c24cc8ac1a85878cb0ade9054f4431ddb95fb64736f6c63430008090033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101425760003560e01c80638f111f3c116100b8578063d9dd67ab1161007c578063d9dd67ab146102e8578063e0bc9729146102fb578063e5a358c81461030e578063e78cea9214610332578063ebea461d14610345578063f19815781461037b57600080fd5b80638f111f3c1461027c57806396cc5c781461028f578063b31761f814610297578063cb23bcb5146102aa578063d1ce8da8146102d557600080fd5b80636e7df3e71161010a5780636e7df3e7146101c55780636f12b0c9146101d8578063715ea34b146101eb57806371c3e6fe1461023d5780637fa3a40e14610260578063844208601461026957600080fd5b806306f13056146101475780631637be48146101625780631f7a92b214610195578063258f0495146101aa57806327957a49146101bd575b600080fd5b61014f61038e565b6040519081526020015b60405180910390f35b610185610170366004611b9e565b60009081526008602052604090205460ff1690565b6040519015158152602001610159565b6101a86101a3366004611bcf565b61040e565b005b61014f6101b8366004611b9e565b6105c6565b61014f602881565b6101a86101d3366004611c1e565b61062f565b6101a86101e6366004611c9f565b610735565b61021e6101f9366004611b9e565b60086020526000908152604090205460ff81169061010090046001600160401b031682565b6040805192151583526001600160401b03909116602083015201610159565b61018561024b366004611d09565b60036020526000908152604090205460ff1681565b61014f60005481565b6101a8610277366004611b9e565b610924565b6101a861028a366004611d2d565b610a77565b6101a8610c86565b6101a86102a5366004611da9565b610cfd565b6002546102bd906001600160a01b031681565b6040516001600160a01b039091168152602001610159565b6101a86102e3366004611e1c565b610dfd565b61014f6102f6366004611b9e565b611045565b6101a8610309366004611d2d565b6110c8565b610319600160fe1b81565b6040516001600160f81b03199091168152602001610159565b6001546102bd906001600160a01b031681565b60045460055460065460075461035b9392919084565b604080519485526020850193909352918301526060820152608001610159565b6101a8610389366004611e5d565b61121d565b600154604080516221048360e21b815290516000926001600160a01b0316916284120c916004808301926020929190829003018186803b1580156103d157600080fd5b505afa1580156103e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104099190611ecd565b905090565b306001600160a01b037f000000000000000000000000d03bfe2ce83632f4e618a97299cc91b1335bb2d91614156104a15760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b60648201526084015b60405180910390fd5b6001546001600160a01b0316156104cb57604051633bcd329760e21b815260040160405180910390fd5b6001600160a01b0382166104f257604051631ad0f74360e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0384169081179091556040805163cb23bcb560e01b8152905163cb23bcb591600480820192602092909190829003018186803b15801561054657600080fd5b505afa15801561055a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061057e9190611ee6565b600280546001600160a01b0319166001600160a01b03929092169190911790558035600490815560208201356005556040820135600655606082013560075581905b50505050565b600081815260086020908152604080832081518083019092525460ff81161515825261010090046001600160401b03169181018290529061061c5760405162f20c5d60e01b815260048101849052602401610498565b602001516001600160401b031692915050565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561067d57600080fd5b505afa158015610691573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b59190611ee6565b6001600160a01b0316336001600160a01b0316146106f757600254604051631194af8760e11b81526104989133916001600160a01b0390911690600401611f03565b6001600160a01b038216600090815260036020526040808220805460ff19168415151790555160019160008051602061230283398151915291a25050565b8060005a905033321461075b5760405163feb3d07160e01b815260040160405180910390fd5b3360009081526003602052604090205460ff1661078b57604051632dd9fc9760e01b815260040160405180910390fd5b600080610799888888611600565b909250905060008080806107b0868b8d8480611773565b93509350935093508c84146107e25760405163ac7411c960e01b815260048101859052602481018e9052604401610498565b80838e6000805160206122e2833981519152856000548a600060405161080b9493929190611f1d565b60405180910390a4505050506001600160a01b03841615915061091b905057366000602061083a83601f611fa7565b6108449190611fbf565b90506102006108546002836120c5565b61085e9190611fbf565b6108698260066120d4565b6108739190611fa7565b61087d9084611fa7565b925033321461088b57600091505b836001600160a01b031663e3db8a49335a6108a690876120f3565b856040518463ffffffff1660e01b81526004016108c59392919061210a565b602060405180830381600087803b1580156108df57600080fd5b505af11580156108f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610917919061212b565b5050505b50505050505050565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561097257600080fd5b505afa158015610986573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109aa9190611ee6565b6001600160a01b0316336001600160a01b0316146109ec57600254604051631194af8760e11b81526104989133916001600160a01b0390911690600401611f03565b60008181526008602052604090205460ff16610a1d5760405162f20c5d60e01b815260048101829052602401610498565b600081815260086020526040808220805460ff191690555182917f5cb4218b272fd214168ac43e90fb4d05d6c36f0b17ffb4c2dd07c234d744eb2a91a260405160039060008051602061230283398151915290600090a250565b8260005a9050333214610a9d5760405163feb3d07160e01b815260040160405180910390fd5b3360009081526003602052604090205460ff16610acd57604051632dd9fc9760e01b815260040160405180910390fd5b600080610adb8a8a8a611600565b90925090508a81838b8b8a8a6000808080610af989888a8989611773565b93509350935093508a8414158015610b1357506000198b14155b15610b3b5760405163ac7411c960e01b815260048101859052602481018c9052604401610498565b8083856000805160206122e2833981519152856000548f6000604051610b649493929190611f1d565b60405180910390a4505050506001600160a01b038b16159850610c7b975050505050505050573660006020610b9a83601f611fa7565b610ba49190611fbf565b9050610200610bb46002836120c5565b610bbe9190611fbf565b610bc98260066120d4565b610bd39190611fa7565b610bdd9084611fa7565b9250333214610beb57600091505b836001600160a01b031663e3db8a49335a610c0690876120f3565b856040518463ffffffff1660e01b8152600401610c259392919061210a565b602060405180830381600087803b158015610c3f57600080fd5b505af1158015610c53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c77919061212b565b5050505b505050505050505050565b467f00000000000000000000000000000000000000000000000000000000000000011415610cc757604051635180dd8360e11b815260040160405180910390fd5b60408051608081018252600180825260208201819052918101829052606001819052600481905560058190556006819055600755565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d4b57600080fd5b505afa158015610d5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d839190611ee6565b6001600160a01b0316336001600160a01b031614610dc557600254604051631194af8760e11b81526104989133916001600160a01b0390911690600401611f03565b80516004556020810151600555604080820151600655606082015160075551600090600080516020612302833981519152908290a250565b600260009054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015610e4b57600080fd5b505afa158015610e5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e839190611ee6565b6001600160a01b0316336001600160a01b031614610ec557600254604051631194af8760e11b81526104989133916001600160a01b0390911690600401611f03565b60008282604051610ed7929190612148565b604051908190038120607f60f91b6020830152602182015260410160408051601f1981840301815291905280516020909101209050600160ff1b8118620100008310610f5b5760405162461bcd60e51b81526020600482015260136024820152726b657973657420697320746f6f206c6172676560681b6044820152606401610498565b60008181526008602052604090205460ff1615610f8e57604051637d17eeed60e11b815260048101829052602401610498565b60408051808201825260018152436001600160401b0390811660208084019182526000868152600890915284902092518354915168ffffffffffffffffff1990921690151568ffffffffffffffff0019161761010091909216021790555181907fabca9b7986bc22ad0160eb0cb88ae75411eacfba4052af0b457a9335ef6557229061101d9087908790612158565b60405180910390a260405160029060008051602061230283398151915290600090a250505050565b6001546040516316bf557960e01b8152600481018390526000916001600160a01b0316906316bf55799060240160206040518083038186803b15801561108a57600080fd5b505afa15801561109e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c29190611ecd565b92915050565b8260005a3360009081526003602052604090205490915060ff161580156110fa57506002546001600160a01b03163314155b1561111857604051632dd9fc9760e01b815260040160405180910390fd5b6000806111268a8a8a611600565b909250905060008b82848b8a8a8680806111438787838888611773565b929c5090945092509050888a1480159061115f57506000198914155b156111875760405163ac7411c960e01b8152600481018b9052602481018a9052604401610498565b80838b6000805160206122e2833981519152856000548d60016040516111b09493929190611f1d565b60405180910390a4505050505050505050807ffe325ca1efe4c5c1062c981c3ee74b781debe4ea9440306a96d2a55759c66c208c8c6040516111f3929190612158565b60405180910390a25050506001600160a01b03821615610c7b573660006020610b9a83601f611fa7565b600054861161123f57604051633eb9f37d60e11b815260040160405180910390fd5b60006112ef8684611253602089018961219d565b61126360408a0160208b0161219d565b61126e60018d6120f3565b6040805160f89690961b6001600160f81b03191660208088019190915260609590951b6001600160601b031916602187015260c093841b6001600160c01b031990811660358801529290931b909116603d85015260458401526065830188905260858084018790528151808503909101815260a59093019052815191012090565b6004549091504390611304602088018861219d565b6001600160401b03166113179190611fa7565b106113355760405163ad3515d960e01b815260040160405180910390fd5b600654429061134a604088016020890161219d565b6001600160401b031661135d9190611fa7565b1061137b5760405163c76d17e560e01b815260040160405180910390fd5b60006001881115611413576001546001600160a01b031663d5719dc26113a260028b6120f3565b6040518263ffffffff1660e01b81526004016113c091815260200190565b60206040518083038186803b1580156113d857600080fd5b505afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114109190611ecd565b90505b60408051602080820184905281830185905282518083038401815260609092019092528051910120600180546001600160a01b03169063d5719dc290611459908c6120f3565b6040518263ffffffff1660e01b815260040161147791815260200190565b60206040518083038186803b15801561148f57600080fd5b505afa1580156114a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114c79190611ecd565b146114e5576040516313947fd760e01b815260040160405180910390fd5b6000806114f18a611a10565b9150915060008a90506000600160009054906101000a90046001600160a01b03166001600160a01b0316635fca4a166040518163ffffffff1660e01b815260040160206040518083038186803b15801561154a57600080fd5b505afa15801561155e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115829190611ecd565b9050600080548d836115949190611fa7565b61159e91906120f3565b90506000806000806115b4898860008989611773565b93509350935093508083856000805160206122e2833981519152856000548d60026040516115e59493929190611f1d565b60405180910390a45050505050505050505050505050505050565b600061160a611b77565b84846000611619826028611fa7565b90506201cccc81111561164b57604051634634691b60e01b8152600481018290526201cccc6024820152604401610498565b81158015906116835750600160fe1b80848460008161166c5761166c612187565b9050013560f81c60f81b166001600160f81b031916145b156116a157604051631f97007f60e01b815260040160405180910390fd5b602182108015906116cf5750828260008181106116c0576116c0612187565b90910135600160ff1b16151590505b156117235760006116e46021600185876121c6565b6116ed916121f0565b60008181526008602052604090205490915060ff166117215760405162f20c5d60e01b815260048101829052602401610498565b505b60008061172f88611a3c565b915091506000828b8b60405160200161174a9392919061223a565b60408051808303601f1901815291905280516020909101209b919a509098505050505050505050565b60008060008060005488101561179c57604051633eb9f37d60e11b815260040160405180910390fd5b600160009054906101000a90046001600160a01b03166001600160a01b031663eca067ad6040518163ffffffff1660e01b815260040160206040518083038186803b1580156117ea57600080fd5b505afa1580156117fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118229190611ecd565b8811156118425760405163925f8bd360e01b815260040160405180910390fd5b60015460405163432cc52b60e11b8152600481018b9052602481018a905260448101889052606481018790526001600160a01b03909116906386598a5690608401608060405180830381600087803b15801561189d57600080fd5b505af11580156118b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d59190612262565b60008c9055929650909450925090508615611a04576040805142602082015233606081901b6001600160601b03191692820192909252605481018b90526074810186905248609482015260009060b40160408051808303601f190181529082905260015481516020830120637a88b10760e01b84526001600160a01b0386811660048601526024850191909152919350600092911690637a88b10790604401602060405180830381600087803b15801561198e57600080fd5b505af11580156119a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c69190611ecd565b9050807fff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b836040516119f89190612298565b60405180910390a25050505b95509550955095915050565b6000611a1a611b77565b600080611a2685611a3c565b8151602090920191909120969095509350505050565b6060611a46611b77565b6000611a50611ae3565b90506000816000015182602001518360400151846060015188604051602001611ab895949392919060c095861b6001600160c01b0319908116825294861b8516600882015292851b8416601084015290841b8316601883015290921b16602082015260280190565b60405160208183030381529060405290506028815114611ada57611ada6122cb565b94909350915050565b611aeb611b77565b611af3611b77565b600654421115611b1657600654611b0a90426120f3565b6001600160401b031681525b600754611b239042611fa7565b6001600160401b03166020820152600454431115611b5757600454611b4890436120f3565b6001600160401b031660408201525b600554611b649043611fa7565b6001600160401b03166060820152919050565b60408051608081018252600080825260208201819052918101829052606081019190915290565b600060208284031215611bb057600080fd5b5035919050565b6001600160a01b0381168114611bcc57600080fd5b50565b60008082840360a0811215611be357600080fd5b8335611bee81611bb7565b92506080601f1982011215611c0257600080fd5b506020830190509250929050565b8015158114611bcc57600080fd5b60008060408385031215611c3157600080fd5b8235611c3c81611bb7565b91506020830135611c4c81611c10565b809150509250929050565b60008083601f840112611c6957600080fd5b5081356001600160401b03811115611c8057600080fd5b602083019150836020828501011115611c9857600080fd5b9250929050565b600080600080600060808688031215611cb757600080fd5b8535945060208601356001600160401b03811115611cd457600080fd5b611ce088828901611c57565b909550935050604086013591506060860135611cfb81611bb7565b809150509295509295909350565b600060208284031215611d1b57600080fd5b8135611d2681611bb7565b9392505050565b600080600080600080600060c0888a031215611d4857600080fd5b8735965060208801356001600160401b03811115611d6557600080fd5b611d718a828b01611c57565b909750955050604088013593506060880135611d8c81611bb7565b969995985093969295946080840135945060a09093013592915050565b600060808284031215611dbb57600080fd5b604051608081018181106001600160401b0382111715611deb57634e487b7160e01b600052604160045260246000fd5b8060405250823581526020830135602082015260408301356040820152606083013560608201528091505092915050565b60008060208385031215611e2f57600080fd5b82356001600160401b03811115611e4557600080fd5b611e5185828601611c57565b90969095509350505050565b60008060008060008060e08789031215611e7657600080fd5b86359550602087013560ff81168114611e8e57600080fd5b94506080870188811115611ea157600080fd5b60408801945035925060a0870135611eb881611bb7565b8092505060c087013590509295509295509295565b600060208284031215611edf57600080fd5b5051919050565b600060208284031215611ef857600080fd5b8151611d2681611bb7565b6001600160a01b0392831681529116602082015260400190565b600060e0820190508582528460208301526001600160401b038085511660408401528060208601511660608401528060408601511660808401528060608601511660a08401525060038310611f8257634e487b7160e01b600052602160045260246000fd5b8260c083015295945050505050565b634e487b7160e01b600052601160045260246000fd5b60008219821115611fba57611fba611f91565b500190565b600082611fdc57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561201c57816000190482111561200257612002611f91565b8085161561200f57918102915b93841c9390800290611fe6565b509250929050565b600082612033575060016110c2565b81612040575060006110c2565b816001811461205657600281146120605761207c565b60019150506110c2565b60ff84111561207157612071611f91565b50506001821b6110c2565b5060208310610133831016604e8410600b841016171561209f575081810a6110c2565b6120a98383611fe1565b80600019048211156120bd576120bd611f91565b029392505050565b6000611d2660ff841683612024565b60008160001904831182151516156120ee576120ee611f91565b500290565b60008282101561210557612105611f91565b500390565b6001600160a01b039390931683526020830191909152604082015260600190565b60006020828403121561213d57600080fd5b8151611d2681611c10565b8183823760009101908152919050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156121af57600080fd5b81356001600160401b0381168114611d2657600080fd5b600080858511156121d657600080fd5b838611156121e357600080fd5b5050820193919092039150565b803560208310156110c257600019602084900360031b1b1692915050565b60005b83811015612229578181015183820152602001612211565b838111156105c05750506000910152565b6000845161224c81846020890161220e565b8201838582376000930192835250909392505050565b6000806000806080858703121561227857600080fd5b505082516020840151604085015160609095015191969095509092509050565b60208152600082518060208401526122b781604085016020870161220e565b601f01601f19169190910160400192915050565b634e487b7160e01b600052600160045260246000fdfe7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7ea8787f128d10b2cc0317b0c3960f9ad447f7f6c1ed189db1083ccffd20f456ea264697066735822122037f21842a3c6a5f06afa8ec57c8c24cc8ac1a85878cb0ade9054f4431ddb95fb64736f6c63430008090033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.