Contract 0xE681857DEfE8b454244e701BA63EfAa078d7eA85

Contract Overview

Balance:
2,916.653451685584150103 Ether

Token:
Txn Hash
Block
From
To
Value
0xc0e3b0d88450d367033d747111c0da6ce226965530080ecc22ed7da6fed5aea3(pending)2021-03-06 16:26:488 secs ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether(Pending)(Pending)
0x3341d20fdaf5ff63ada17e3e35106bc636ea15dadc88ea326a38b593561038d8(pending)2021-02-05 11:06:1929 days 5 hrs ago0x0598d2c365a5661032a91da03ed74e298ceea67b IN 0xe681857defe8b454244e701ba63efaa078d7ea850.12 Ether(Pending)(Pending)
0x1148262b00585cfead0d432c53173846ec3904351cc4f4f30d4a4e0d01f80b95(pending)2021-02-05 11:06:1929 days 5 hrs ago0x379f025b37e04d9d5ec4e3198b36717fa54c513c IN 0xe681857defe8b454244e701ba63efaa078d7ea852 Ether(Pending)(Pending)
0x2c0768d9012f56be3dfcc9ec912055127ded1f85458a97223fbf5b96da27f159(pending)2021-02-05 11:06:1929 days 5 hrs ago0x379f025b37e04d9d5ec4e3198b36717fa54c513c IN 0xe681857defe8b454244e701ba63efaa078d7ea850.006 Ether(Pending)(Pending)
0x418a6a4166090ad996859930088430457bd0f43b58f7c0c492b0a9ac2a3934fe(pending)2021-02-05 11:06:1929 days 5 hrs ago0x0b835351e98682aab42407edce5a92eeb0031b36 IN 0xe681857defe8b454244e701ba63efaa078d7ea850.1 Ether(Pending)(Pending)
0xd054ca5d152ec8da54b68142c18a5eb4701ae4c3462919601e82bf4554e6471c(pending)2021-02-05 10:36:1629 days 5 hrs ago0x0598d2c365a5661032a91da03ed74e298ceea67b IN 0xe681857defe8b454244e701ba63efaa078d7ea850.1199 Ether(Pending)(Pending)
0xce795b69b2bfcc56df6de36068b7284d1f180cad43c7ea8056ffa078674d5d0b(pending)2021-02-05 10:36:1529 days 5 hrs ago0x379f025b37e04d9d5ec4e3198b36717fa54c513c IN 0xe681857defe8b454244e701ba63efaa078d7ea850.007 Ether(Pending)(Pending)
0xc559984175c027fa0558c5e8b73eee03e339d86cbbb02bd0ddca6965598d8e6a(pending)2021-02-05 10:36:1529 days 5 hrs ago0x379f025b37e04d9d5ec4e3198b36717fa54c513c IN 0xe681857defe8b454244e701ba63efaa078d7ea850.006 Ether(Pending)(Pending)
0x79221180726af27ad7ace4363641528277fcef7ddf43a30a40d06449510d806f(pending)2021-02-05 10:36:1529 days 5 hrs ago0x379f025b37e04d9d5ec4e3198b36717fa54c513c IN 0xe681857defe8b454244e701ba63efaa078d7ea850.005 Ether(Pending)(Pending)
0xe9c50a66c9220ddddc9cda5048408598605703e89137b19d25d77bee9a4d699d237897262021-03-06 16:26:0848 secs ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0015405630
0x8fcb38108f855e532bb40cd6e52914d235676d6f14f6ea12f21a2cc516af4142237897232021-03-06 16:25:521 min ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0014088630
0xaa4be3ee34f1062b4a9df708bc898e1d4c7ae24898a52100ff47f15dbbba6a7b237897222021-03-06 16:25:481 min ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0013696230
0x5fafb0baef7b96abb264517e39c61a6c4550012a046a17521713be37541964df237897192021-03-06 16:25:321 min ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0012963930
0xf9464b4ebb88715cdbdf7e44d4785c469715ef8f7e97f47e3f47d30c4157c9b2237897172021-03-06 16:25:201 min ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0016130730
0x819f26c33456f8208449be7fda27211f7d4867351f78ffdf946866a8085c6b48237897142021-03-06 16:25:041 min ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.001661730
0xf90313ef1f89ffbfe6642e8de6e9a0edeb5c65b16167a0ed171313d205403332237897112021-03-06 16:24:482 mins ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0014498130
0x7b3e5644962a760884ca74e0d9bdffadae9fabe35bf073d61e9dc172c4fe0d13237897082021-03-06 16:24:322 mins ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0020975130
0x9a5bfb6eac8830abe2241f7c8f3b2db090ff8f04faa80fea2f3af3fba123af20237897052021-03-06 16:24:162 mins ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0014950530
0x219c8852b502afcd1529b81e7ca81f1ae9ff3ffa7413e5797486c771ac461643237897022021-03-06 16:24:002 mins ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.001545630
0x1a75983f1d6ac086be8c6799df8313d3bb5bebde030f9ea13fd88e2dd7cf5339237897012021-03-06 16:23:563 mins ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0013481430
0x30948440b70c82c78bb7fe75dee9851e86f75e8c3202f2d2d1f1b75c31abf9ee237896982021-03-06 16:23:403 mins ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0014687730
0xff2698756f4940344da061fc581e7fd7ae35c7bb8451b28e68277c2b15fd3eb8237896952021-03-06 16:23:243 mins ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0014680530
0x6955a2cd72810ae441619c4b55f3c9b8b1947886da6dc494e99b6bfd41a61ec9237896952021-03-06 16:23:243 mins ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0016069530
0x4bcc94ed1a402c1cc6a578adcdfb7495ddca8d2bdb0c1549fdaf75e0a84071ad237896902021-03-06 16:22:564 mins ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0014957730
0x40871a9af73da0f756a9936cf08c32d8c1cd3bbc8828369c880d8a3b7e897db8237896892021-03-06 16:22:524 mins ago0xa310ad70887dab6b2b47d72825bbd9db6f1279fa IN  0xe681857defe8b454244e701ba63efaa078d7ea850 Ether0.0020295930
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xe173995ffa1fbbfd1ba93e60091e21e935bdce6fc2ff1711004845c53e0f1615237843852021-03-06 8:28:127 hrs 58 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x415f42cf223e721711d174d846958e2e7bd46c2298df9864ec0e28e7741d84b2237843732021-03-06 8:27:087 hrs 59 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x089e388a0479fc938c19dfd564e722a9b34548c3922b60eaef7ea7eacbd72edc237838362021-03-06 7:39:088 hrs 47 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0xe9b8a17033a13e996a93536a8678572a8af828c55740a1eabd8f0ace43778fe7237837972021-03-06 7:35:408 hrs 51 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x2509b9739cfc1247c2e1edffd3e9b203d771c4d33aa1c88589332da49b04bfa4237821832021-03-06 5:10:5211 hrs 16 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x08198fc020d82b8d38391f7523443cf39345c914a9926e6e259258adea074898237817962021-03-06 4:36:2811 hrs 50 mins ago 0xe681857defe8b454244e701ba63efaa078d7ea85 0x7d669a64deb8a4a51eea755bb0e19fd39ce25ae90 Ether
0x1c68f493c958cc28346f054ab410ab45a30888216f21090527c216d477f4a2e6237817732021-03-06 4:34:2411 hrs 52 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x01b310f56397ca9a80db6ecb39e42544259f7d0bf13ac9bb713f6d3edf530460237814542021-03-06 4:05:4812 hrs 21 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x420226c92b70c32e95be7928b3c44136292164940e8c4803024f060585b4c481237814362021-03-06 4:04:1212 hrs 22 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0xc88f31dae2ae439fa4c985e0fa2fcec26f6bf57873eb7fc6c17dc660585760a5237811992021-03-06 3:42:5212 hrs 44 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0xecdf573076f1bdce941db6d9af4f64089ab6a9d48e027bfd09142add4b6240dc237811272021-03-06 3:36:2812 hrs 50 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x9553853f6f07e7d4edda5dfe313db52f7a9555f9b2710c4145db683992afe1cd237811182021-03-06 3:35:4012 hrs 51 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x3088a9eda25febeab84ee00f0f71a6f5c7f597ab7abd77b66c7b9524ec6526e0237801662021-03-06 2:10:3614 hrs 16 mins ago 0xe681857defe8b454244e701ba63efaa078d7ea85 0x7d669a64deb8a4a51eea755bb0e19fd39ce25ae90 Ether
0xc76bd347e1195bba5172c2144cda6fdf42acb51399fda0a3235df5506b663e6f237763482021-03-05 20:28:2819 hrs 58 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x15286c9a10ae7b3edafcd97c276e8f8436497ac7a2646acbe6599b393e272831237763422021-03-05 20:27:5619 hrs 59 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x000d896cd4f66d59dae8ae0c925f9e4fdcc4be262e3473ab2ef2f077b2864a21237763372021-03-05 20:27:2419 hrs 59 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x6d7b493027ed79b2b418cc298af517512391921345f1aeaa0db36b8a91c4c88b237755982021-03-05 19:21:3221 hrs 5 mins ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x334bbe997ed67f6118732c6395e17df8632315470a74ccb36eae93950f2af091237699802021-03-05 10:55:241 day 5 hrs ago 0xe681857defe8b454244e701ba63efaa078d7ea85 0xfe45d1134ca3acd42e0a25905bd1cf5c295d8b090 Ether
0x64212d6307d4277646fad861e168c2630c4867c4cc4abd2bc0586bec30514e7f237683272021-03-05 8:27:241 day 7 hrs ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0xd52c764308a02063f477aa69c17ee12e0175358a8910b449872bb8341453b38d237682732021-03-05 8:22:241 day 8 hrs ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x278cd40af89b1a03d925f1437b4eaaa9be8824ce0270e66dc552ca8cefc5b372237682512021-03-05 8:20:281 day 8 hrs ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0xe6e68dd39839dc9b337bbe98ef339323b03444e6e80d230626d02b95e0bc7bda237676412021-03-05 7:26:041 day 9 hrs ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x104e708bf2088dd81d784c8682e2687414ef600a2465c5ed9e418e6e3915c34c237627372021-03-04 23:59:241 day 16 hrs ago 0x239136240e2f41d72ca7ed3ea356767c83fc9a80 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x9039595911fb965e9c35f979c692b01630dd89343f872017cbaf89c555a27845237626212021-03-04 23:49:001 day 16 hrs ago 0x36501dcd0007aa4db373667d730c5ae91a7b3cc8 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
0x6201ffd3204bf0612a594b1a65fea8451ee33b72009000f793b63d21f62afc08237625512021-03-04 23:42:361 day 16 hrs ago 0x239136240e2f41d72ca7ed3ea356767c83fc9a80 0xe681857defe8b454244e701ba63efaa078d7ea850 Ether
[ Download CSV Export 
Loading

Contract Source Code Verified (Similar Match)
Note: This contract matches the deployed ByteCode of the Source Code for Contract 0xb8A500d736c7728E61138cE5e0Bc215ba950370E

Contract Name:
GlobalInbox

Compiler Version
v0.5.17+commit.d19bba13

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 58 : Hashing.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./Value.sol";

library Hashing {
    using Hashing for Value.Data;
    using Value for Value.CodePoint;

    function hashInt(uint256 val) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(val));
    }

    function hashCodePoint(Value.CodePoint memory cp) internal pure returns (bytes32) {
        assert(cp.immediate.length < 2);
        if (cp.immediate.length == 0) {
            return
                keccak256(abi.encodePacked(Value.codePointTypeCode(), cp.opcode, cp.nextCodePoint));
        }
        return
            keccak256(
                abi.encodePacked(
                    Value.codePointTypeCode(),
                    cp.opcode,
                    cp.immediate[0].hash(),
                    cp.nextCodePoint
                )
            );
    }

    function hashTuplePreImage(bytes32 innerHash, uint256 valueSize)
        internal
        pure
        returns (bytes32)
    {
        return keccak256(abi.encodePacked(uint8(Value.tupleTypeCode()), innerHash, valueSize));
    }

    function hash(Value.Data memory val) internal pure returns (bytes32) {
        if (val.typeCode == Value.intTypeCode()) {
            return hashInt(val.intVal);
        } else if (val.typeCode == Value.codePointTypeCode()) {
            return hashCodePoint(val.cpVal);
        } else if (val.typeCode == Value.tuplePreImageTypeCode()) {
            return hashTuplePreImage(bytes32(val.intVal), val.size);
        } else if (val.typeCode == Value.tupleTypeCode()) {
            Value.Data memory preImage = getTuplePreImage(val.tupleVal);
            return preImage.hash();
        } else if (val.typeCode == Value.hashOnlyTypeCode()) {
            return bytes32(val.intVal);
        } else {
            require(false, "Invalid type code");
        }
    }

    function getTuplePreImage(Value.Data[] memory vals) internal pure returns (Value.Data memory) {
        require(vals.length <= 8, "Invalid tuple length");
        bytes32[] memory hashes = new bytes32[](vals.length);
        uint256 hashCount = hashes.length;
        uint256 size = 1;
        for (uint256 i = 0; i < hashCount; i++) {
            hashes[i] = vals[i].hash();
            size += vals[i].size;
        }
        bytes32 firstHash = keccak256(abi.encodePacked(uint8(hashes.length), hashes));
        return Value.newTuplePreImage(firstHash, size);
    }
}

File 2 of 58 : Value.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

library Value {
    uint8 internal constant INT_TYPECODE = 0;
    uint8 internal constant CODE_POINT_TYPECODE = 1;
    uint8 internal constant HASH_PRE_IMAGE_TYPECODE = 2;
    uint8 internal constant TUPLE_TYPECODE = 3;
    // All values received from clients will have type codes less than the VALUE_TYPE_COUNT
    uint8 internal constant VALUE_TYPE_COUNT = TUPLE_TYPECODE + 9;

    // The following types do not show up in the marshalled format and is
    // only used for internal tracking purposes
    uint8 internal constant HASH_ONLY = 100;

    struct CodePoint {
        uint8 opcode;
        bytes32 nextCodePoint;
        Data[] immediate;
    }

    struct Data {
        uint256 intVal;
        CodePoint cpVal;
        Data[] tupleVal;
        uint8 typeCode;
        uint256 size;
    }

    function tupleTypeCode() internal pure returns (uint8) {
        return TUPLE_TYPECODE;
    }

    function tuplePreImageTypeCode() internal pure returns (uint8) {
        return HASH_PRE_IMAGE_TYPECODE;
    }

    function intTypeCode() internal pure returns (uint8) {
        return INT_TYPECODE;
    }

    function codePointTypeCode() internal pure returns (uint8) {
        return CODE_POINT_TYPECODE;
    }

    function valueTypeCode() internal pure returns (uint8) {
        return VALUE_TYPE_COUNT;
    }

    function hashOnlyTypeCode() internal pure returns (uint8) {
        return HASH_ONLY;
    }

    function isValidTupleSize(uint256 size) internal pure returns (bool) {
        return size <= 8;
    }

    function typeCodeVal(Data memory val) internal pure returns (Data memory) {
        require(val.typeCode != 2, "invalid type code");
        return newInt(val.typeCode);
    }

    function valLength(Data memory val) internal pure returns (uint8) {
        if (val.typeCode == TUPLE_TYPECODE) {
            return uint8(val.tupleVal.length);
        } else {
            return 1;
        }
    }

    function isInt(Data memory val) internal pure returns (bool) {
        return val.typeCode == INT_TYPECODE;
    }

    function isCodePoint(Data memory val) internal pure returns (bool) {
        return val.typeCode == CODE_POINT_TYPECODE;
    }

    function isTuple(Data memory val) internal pure returns (bool) {
        return val.typeCode == TUPLE_TYPECODE;
    }

    function isValidTypeForSend(Data memory val) internal pure returns (bool) {
        if (val.typeCode == INT_TYPECODE) {
            return true;
        } else if (val.typeCode == CODE_POINT_TYPECODE) {
            return false;
        } else if (val.typeCode == HASH_PRE_IMAGE_TYPECODE) {
            require(false, "must have full value");
        } else if (val.typeCode == TUPLE_TYPECODE) {
            uint256 valueCount = val.tupleVal.length;
            for (uint256 i = 0; i < valueCount; i++) {
                if (!isValidTypeForSend(val.tupleVal[i])) {
                    return false;
                }
            }
            return true;
        } else if (val.typeCode == HASH_ONLY) {
            return false;
        } else {
            require(false, "Invalid type code");
        }
    }

    function newEmptyTuple() internal pure returns (Data memory) {
        return newTuple(new Data[](0));
    }

    function newBoolean(bool val) internal pure returns (Data memory) {
        if (val) {
            return newInt(1);
        } else {
            return newInt(0);
        }
    }

    function newInt(uint256 _val) internal pure returns (Data memory) {
        return Data(_val, CodePoint(0, 0, new Data[](0)), new Data[](0), INT_TYPECODE, uint256(1));
    }

    function newHashedValue(bytes32 valueHash, uint256 valueSize)
        internal
        pure
        returns (Data memory)
    {
        return
            Data(
                uint256(valueHash),
                CodePoint(0, 0, new Data[](0)),
                new Data[](0),
                HASH_ONLY,
                valueSize
            );
    }

    function newTuple(Data[] memory _val) internal pure returns (Data memory) {
        require(isValidTupleSize(_val.length), "Tuple must have valid size");
        uint256 size = 1;

        for (uint256 i = 0; i < _val.length; i++) {
            size += _val[i].size;
        }

        return Data(0, CodePoint(0, 0, new Data[](0)), _val, TUPLE_TYPECODE, size);
    }

    function newTuplePreImage(bytes32 preImageHash, uint256 size)
        internal
        pure
        returns (Data memory)
    {
        return
            Data(
                uint256(preImageHash),
                CodePoint(0, 0, new Data[](0)),
                new Data[](0),
                HASH_PRE_IMAGE_TYPECODE,
                size
            );
    }

    function newCodePoint(uint8 opCode, bytes32 nextHash) internal pure returns (Data memory) {
        return newCodePoint(CodePoint(opCode, nextHash, new Data[](0)));
    }

    function newCodePoint(
        uint8 opCode,
        bytes32 nextHash,
        Data memory immediate
    ) internal pure returns (Data memory) {
        Data[] memory imm = new Data[](1);
        imm[0] = immediate;
        return newCodePoint(CodePoint(opCode, nextHash, imm));
    }

    function newCodePoint(CodePoint memory _val) private pure returns (Data memory) {
        return Data(0, _val, new Data[](0), CODE_POINT_TYPECODE, uint256(1));
    }
}

File 3 of 58 : IOneStepProof.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

interface IOneStepProof {
    function executeStep(
        bytes32 inboxAcc,
        bytes32 messagesAcc,
        bytes32 logsAcc,
        bytes calldata proof
    ) external pure returns (uint64 gas, bytes32[5] memory fields);

    function executeStepWithMessage(
        bytes32 inboxAcc,
        bytes32 messagesAcc,
        bytes32 logsAcc,
        bytes calldata proof,
        uint8 _kind,
        uint256 _blockNumber,
        uint256 _timestamp,
        address _sender,
        uint256 _inboxSeqNum,
        bytes calldata _msgData
    ) external pure returns (uint64 gas, bytes32[5] memory fields);
}

File 4 of 58 : Machine.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./Marshaling.sol";

import "../libraries/DebugPrint.sol";

library Machine {
    using Hashing for Value.Data;

    uint256 internal constant MACHINE_EXTENSIVE = 0;
    uint256 internal constant MACHINE_ERRORSTOP = 1;
    uint256 internal constant MACHINE_HALT = 2;

    function addStackVal(Value.Data memory stackValHash, Value.Data memory valHash)
        internal
        pure
        returns (Value.Data memory)
    {
        Value.Data[] memory vals = new Value.Data[](2);
        vals[0] = valHash;
        vals[1] = stackValHash;

        return Hashing.getTuplePreImage(vals);
    }

    struct Data {
        bytes32 instructionStackHash;
        Value.Data dataStack;
        Value.Data auxStack;
        Value.Data registerVal;
        Value.Data staticVal;
        uint256 arbGasRemaining;
        bytes32 errHandlerHash;
        Value.Data pendingMessage;
        uint256 status;
    }

    function toString(Data memory machine) internal pure returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "Machine(",
                    DebugPrint.bytes32string(machine.instructionStackHash),
                    ", \n",
                    DebugPrint.bytes32string(machine.dataStack.hash()),
                    ", \n",
                    DebugPrint.bytes32string(machine.auxStack.hash()),
                    ", \n",
                    DebugPrint.bytes32string(machine.registerVal.hash()),
                    ", \n",
                    DebugPrint.bytes32string(machine.staticVal.hash()),
                    ", \n",
                    DebugPrint.uint2str(machine.arbGasRemaining),
                    ", \n",
                    DebugPrint.bytes32string(machine.errHandlerHash),
                    ", \n",
                    DebugPrint.bytes32string(machine.pendingMessage.hash()),
                    ")\n"
                )
            );
    }

    function setExtensive(Data memory machine) internal pure {
        machine.status = MACHINE_EXTENSIVE;
    }

    function setErrorStop(Data memory machine) internal pure {
        machine.status = MACHINE_ERRORSTOP;
    }

    function setHalt(Data memory machine) internal pure {
        machine.status = MACHINE_HALT;
    }

    function addDataStackValue(Data memory machine, Value.Data memory val) internal pure {
        machine.dataStack = addStackVal(machine.dataStack, val);
    }

    function addAuxStackValue(Data memory machine, Value.Data memory val) internal pure {
        machine.auxStack = addStackVal(machine.auxStack, val);
    }

    function addDataStackInt(Data memory machine, uint256 val) internal pure {
        machine.dataStack = addStackVal(machine.dataStack, Value.newInt(val));
    }

    function machineHash(
        bytes32 instructionStackHash,
        Value.Data memory dataStack,
        Value.Data memory auxStack,
        Value.Data memory registerVal,
        Value.Data memory staticVal,
        uint256 arbGasRemaining,
        bytes32 errHandlerHash,
        Value.Data memory pendingMessage
    ) internal pure returns (bytes32) {
        return
            hash(
                Data(
                    instructionStackHash,
                    dataStack,
                    auxStack,
                    registerVal,
                    staticVal,
                    arbGasRemaining,
                    errHandlerHash,
                    pendingMessage,
                    MACHINE_EXTENSIVE
                )
            );
    }

    function hash(Data memory machine) internal pure returns (bytes32) {
        if (machine.status == MACHINE_HALT) {
            return bytes32(uint256(0));
        } else if (machine.status == MACHINE_ERRORSTOP) {
            return bytes32(uint256(1));
        } else {
            return
                keccak256(
                    abi.encodePacked(
                        machine.instructionStackHash,
                        machine.dataStack.hash(),
                        machine.auxStack.hash(),
                        machine.registerVal.hash(),
                        machine.staticVal.hash(),
                        machine.arbGasRemaining,
                        machine.errHandlerHash,
                        machine.pendingMessage.hash()
                    )
                );
        }
    }

    function clone(Data memory machine) internal pure returns (Data memory) {
        return
            Data(
                machine.instructionStackHash,
                machine.dataStack,
                machine.auxStack,
                machine.registerVal,
                machine.staticVal,
                machine.arbGasRemaining,
                machine.errHandlerHash,
                machine.pendingMessage,
                machine.status
            );
    }

    function deserializeMachine(bytes memory data, uint256 offset)
        internal
        pure
        returns (
            uint256, // offset
            Data memory // machine
        )
    {
        Data memory m;
        m.status = MACHINE_EXTENSIVE;
        uint256 instructionStack;
        uint256 errHandler;
        (offset, instructionStack) = Marshaling.deserializeInt(data, offset);

        (offset, m.dataStack) = Marshaling.deserializeHashPreImage(data, offset);
        (offset, m.auxStack) = Marshaling.deserializeHashPreImage(data, offset);
        (offset, m.registerVal) = Marshaling.deserialize(data, offset);
        (offset, m.staticVal) = Marshaling.deserialize(data, offset);
        (offset, m.arbGasRemaining) = Marshaling.deserializeInt(data, offset);
        (offset, errHandler) = Marshaling.deserializeInt(data, offset);
        (offset, m.pendingMessage) = Marshaling.deserialize(data, offset);

        m.instructionStackHash = bytes32(instructionStack);
        m.errHandlerHash = bytes32(errHandler);
        return (offset, m);
    }
}

File 5 of 58 : Marshaling.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./Value.sol";
import "./Hashing.sol";

import "../libraries/BytesLib.sol";

library Marshaling {
    using BytesLib for bytes;
    using Value for Value.Data;

    function deserializeHashPreImage(bytes memory data, uint256 startOffset)
        internal
        pure
        returns (uint256 offset, Value.Data memory value)
    {
        require(data.length >= startOffset && data.length - startOffset >= 64, "to short");
        bytes32 hashData;
        uint256 size;
        (offset, hashData) = extractBytes32(data, startOffset);
        (offset, size) = deserializeInt(data, offset);
        return (offset, Value.newTuplePreImage(hashData, size));
    }

    function deserializeInt(bytes memory data, uint256 startOffset)
        internal
        pure
        returns (
            uint256, // offset
            uint256 // val
        )
    {
        require(data.length >= startOffset && data.length - startOffset >= 32, "too short");
        return (startOffset + 32, data.toUint(startOffset));
    }

    function deserializeCheckedInt(bytes memory data, uint256 startOffset)
        internal
        pure
        returns (
            bool, // valid
            uint256, // offset
            uint256 // val
        )
    {
        uint256 totalLength = data.length;
        if (
            totalLength < startOffset ||
            totalLength - startOffset < 33 ||
            uint8(data[startOffset]) != Value.intTypeCode()
        ) {
            return (false, startOffset, 0);
        }
        return (true, startOffset + 33, data.toUint(startOffset + 1));
    }

    function deserializeCodePoint(bytes memory data, uint256 startOffset)
        internal
        pure
        returns (
            uint256, // offset
            Value.Data memory // val
        )
    {
        uint256 offset = startOffset;
        uint8 immediateType;
        uint8 opCode;
        Value.Data memory immediate;
        bytes32 nextHash;

        (offset, immediateType) = extractUint8(data, offset);
        (offset, opCode) = extractUint8(data, offset);
        if (immediateType == 1) {
            (offset, immediate) = deserialize(data, offset);
        }
        (offset, nextHash) = extractBytes32(data, offset);
        if (immediateType == 1) {
            return (offset, Value.newCodePoint(opCode, nextHash, immediate));
        }
        return (offset, Value.newCodePoint(opCode, nextHash));
    }

    function deserializeTuple(
        uint8 memberCount,
        bytes memory data,
        uint256 startOffset
    )
        internal
        pure
        returns (
            uint256, // offset
            Value.Data[] memory // val
        )
    {
        uint256 offset = startOffset;
        Value.Data[] memory members = new Value.Data[](memberCount);
        for (uint8 i = 0; i < memberCount; i++) {
            (offset, members[i]) = deserialize(data, offset);
        }
        return (offset, members);
    }

    function deserialize(bytes memory data, uint256 startOffset)
        internal
        pure
        returns (
            uint256, // offset
            Value.Data memory // val
        )
    {
        require(startOffset < data.length, "invalid offset");
        (uint256 offset, uint8 valType) = extractUint8(data, startOffset);
        if (valType == Value.intTypeCode()) {
            uint256 intVal;
            (offset, intVal) = deserializeInt(data, offset);
            return (offset, Value.newInt(intVal));
        } else if (valType == Value.codePointTypeCode()) {
            return deserializeCodePoint(data, offset);
        } else if (valType == Value.tuplePreImageTypeCode()) {
            return deserializeHashPreImage(data, offset);
        } else if (valType >= Value.tupleTypeCode() && valType < Value.valueTypeCode()) {
            uint8 tupLength = uint8(valType - Value.tupleTypeCode());
            Value.Data[] memory tupleVal;
            (offset, tupleVal) = deserializeTuple(tupLength, data, offset);
            return (offset, Value.newTuple(tupleVal));
        }
        require(false, "invalid typecode");
    }

    /**
     * @notice Convert data[startOffset:startOffset + dataLength] into an Arbitrum bytestack value
     * @dev The bytestack object is a series of nested 2 tuples terminating in an empty tuple, ex. (size, (data1, (data2, (data3, ()))))
     * @param data Data object containing a superset of the data we want to serialize
     * @param startOffset Offset in data where the data we want to convert beings
     * @param dataLength Number of bytes that we want to include in the bytestack result
     */
    function bytesToBytestack(
        bytes memory data,
        uint256 startOffset,
        uint256 dataLength
    ) internal pure returns (Value.Data memory) {
        uint256 wholeChunkCount = dataLength / 32;

        // tuple code + size + (for each chunk tuple code + chunk val) + empty tuple code
        Value.Data memory stack = Value.newEmptyTuple();
        Value.Data[] memory vals = new Value.Data[](2);

        // Break each full chunk of the data into 32 byte ints an interatively construct nested tuples including the data
        for (uint256 i = 0; i < wholeChunkCount; i++) {
            vals[0] = Value.newInt(data.toUint(startOffset + i * 32));
            vals[1] = stack;
            stack = Hashing.getTuplePreImage(vals);
        }

        // If the data didn't evenly divide into chunks. We take the remaining data and add it to the bytestack
        if (dataLength % 32 != 0) {
            // Grab the last 32 byte of the data and then shift it over to get only the relevent value. This way we avoid reading beyond the end of the data
            uint256 lastVal = data.toUint(startOffset + dataLength - 32);
            lastVal <<= (32 - (dataLength % 32)) * 8;
            vals[0] = Value.newInt(lastVal);
            vals[1] = stack;
            stack = Hashing.getTuplePreImage(vals);
        }

        // Include the length of the included data at the top level of the tuple stack
        vals[0] = Value.newInt(dataLength);
        vals[1] = stack;

        return Hashing.getTuplePreImage(vals);
    }

    /**
     * @notice If the data passed to this function is a valid bytestack object, return the convertion of it to raw bytes form. Otherwise return that it was invalid.
     * @dev The bytestack format is described in the documentation of bytesToBytestack
     * @param data Data object containing the potential serialized bytestack value
     * @param startOffset Offset in data where the bytestack is claimed to begin
     */
    function bytestackToBytes(bytes memory data, uint256 startOffset)
        internal
        pure
        returns (
            bool valid,
            uint256 offset,
            bytes memory byteData
        )
    {
        // Bytestack should start with the size in bytes of the contained data
        uint256 byteCount;
        (valid, offset, byteCount) = parseBytestackChunk(data, startOffset);
        if (!valid) {
            return (false, offset, byteData);
        }

        // If byteCount % 32 != 0, the last chunk will have byteCount % 32 bytes of data in it and the rest should be ignored
        uint256 fullChunkCount = byteCount / 32;
        uint256 partialChunkSize = byteCount % 32;
        uint256 totalChunkCount = fullChunkCount + (partialChunkSize > 0 ? 1 : 0);

        bytes32[] memory fullChunks = new bytes32[](fullChunkCount);
        bytes memory partialChunk = new bytes(partialChunkSize);

        uint256 fullChunkIndex = 0;

        for (uint256 i = 0; i < totalChunkCount; i++) {
            uint256 nextChunk;
            (valid, offset, nextChunk) = parseBytestackChunk(data, offset);
            if (!valid) {
                return (false, offset, byteData);
            }

            // The chunks appear backwards in the serialization so we reverse their order there
            // Therefore the first chunk is the one which may be partial
            if (i == 0 && partialChunkSize > 0) {
                // Copy only partialChunkSize bytes over into partialChunk
                bytes32 chunkBytes = bytes32(nextChunk);
                for (uint256 j = 0; j < partialChunkSize; j++) {
                    partialChunk[j] = chunkBytes[j];
                }
            } else {
                // Put the chunks into fullChunks in reverse order
                // We use a separate index fullChunkIndex since we may or may not have included a partial chunk
                fullChunks[fullChunkCount - 1 - fullChunkIndex] = bytes32(nextChunk);
                fullChunkIndex++;
            }
        }
        // The bytestack should end with an empty tuple
        uint8 valType;
        (offset, valType) = extractUint8(data, offset);
        if (valType != Value.tupleTypeCode()) {
            return (false, offset, byteData);
        }
        return (true, offset, abi.encodePacked(fullChunks, partialChunk));
    }

    function parseBytestackChunk(bytes memory data, uint256 startOffset)
        private
        pure
        returns (
            bool valid,
            uint256 offset,
            uint256 nextChunk
        )
    {
        uint8 valType;
        (offset, valType) = extractUint8(data, startOffset);
        if (valType != Value.tupleTypeCode() + 2) {
            return (false, offset, nextChunk);
        }
        (valid, offset, nextChunk) = deserializeCheckedInt(data, offset);
        if (!valid) {
            return (false, offset, nextChunk);
        }
        return (true, offset, nextChunk);
    }

    function extractUint8(bytes memory data, uint256 startOffset)
        private
        pure
        returns (
            uint256, // offset
            uint8 // val
        )
    {
        return (startOffset + 1, uint8(data[startOffset]));
    }

    function extractBytes32(bytes memory data, uint256 startOffset)
        private
        pure
        returns (
            uint256, // offset
            bytes32 // val
        )
    {
        return (startOffset + 32, data.toBytes32(startOffset));
    }
}

File 6 of 58 : BytesLib.sol
// SPDX-License-Identifier: MIT

/*
 * @title Solidity Bytes Arrays Utils
 * @author Gonçalo Sá <[email protected]>
 *
 * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
 *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
 */

pragma solidity ^0.5.11;

/* solhint-disable no-inline-assembly */
library BytesLib {
    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
        require(_bytes.length >= (_start + 20), "Read out of bounds");
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
        require(_bytes.length >= (_start + 1), "Read out of bounds");
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
        require(_bytes.length >= (_start + 32), "Read out of bounds");
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
        require(_bytes.length >= (_start + 32), "Read out of bounds");
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }
}
/* solhint-enable no-inline-assembly */

File 7 of 58 : DebugPrint.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

library DebugPrint {
    function char(bytes1 b) private pure returns (bytes1 c) {
        if (uint8(b) < 10) {
            return bytes1(uint8(b) + 0x30);
        } else {
            return bytes1(uint8(b) + 0x57);
        }
    }

    function bytes32string(bytes32 b32) internal pure returns (string memory out) {
        bytes memory s = new bytes(64);

        for (uint256 i = 0; i < 32; i++) {
            bytes1 b = bytes1(b32[i]);
            bytes1 hi = bytes1(uint8(b) / 16);
            bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));
            s[i * 2] = char(hi);
            s[i * 2 + 1] = char(lo);
        }

        out = string(s);
    }

    // Taken from https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol
    function uint2str(uint256 _iParam) internal pure returns (string memory _uintAsString) {
        uint256 _i = _iParam;
        if (_i == 0) {
            return "0";
        }
        uint256 j = _i;
        uint256 len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint256 k = len - 1;
        while (_i != 0) {
            bstr[k--] = bytes1(uint8(48 + (_i % 10)));
            _i /= 10;
        }
        return string(bstr);
    }
}

File 8 of 58 : OneStepProof.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./IOneStepProof.sol";
import "./Value.sol";
import "./Machine.sol";
import "../inbox/Messages.sol";
import "../libraries/Keccak.sol";

// Originally forked from https://github.com/leapdao/solEVM-enforcer/tree/master

contract OneStepProof is IOneStepProof {
    using Machine for Machine.Data;
    using Hashing for Value.Data;
    using Value for Value.Data;

    uint256 private constant SEND_SIZE_LIMIT = 10000;

    uint256 private constant MAX_UINT256 = ((1 << 128) + 1) * ((1 << 128) - 1);

    string private constant BAD_IMM_TYP = "BAD_IMM_TYP";
    string private constant NO_IMM = "NO_IMM";
    string private constant STACK_MISSING = "STACK_MISSING";
    string private constant AUX_MISSING = "AUX_MISSING";
    string private constant STACK_MANY = "STACK_MANY";
    string private constant AUX_MANY = "AUX_MANY";
    string private constant INBOX_VAL = "INBOX_VAL";

    function executeStep(
        bytes32 inboxAcc,
        bytes32 messagesAcc,
        bytes32 logsAcc,
        bytes calldata proof
    ) external pure returns (uint64 gas, bytes32[5] memory fields) {
        AssertionContext memory context = initializeExecutionContext(
            inboxAcc,
            messagesAcc,
            logsAcc,
            proof
        );

        executeOp(context);

        return returnContext(context);
    }

    function executeStepWithMessage(
        bytes32 inboxAcc,
        bytes32 messagesAcc,
        bytes32 logsAcc,
        bytes calldata proof,
        uint8 _kind,
        uint256 _blockNumber,
        uint256 _timestamp,
        address _sender,
        uint256 _inboxSeqNum,
        bytes calldata _msgData
    ) external pure returns (uint64 gas, bytes32[5] memory fields) {
        AssertionContext memory context = initializeExecutionContext(
            inboxAcc,
            messagesAcc,
            logsAcc,
            proof
        );

        context.inboxMessageHash = Messages.messageHash(
            _kind,
            _sender,
            _blockNumber,
            _timestamp,
            _inboxSeqNum,
            keccak256(_msgData)
        );

        context.inboxMessage = Messages.messageValue(
            _kind,
            _blockNumber,
            _timestamp,
            _sender,
            _inboxSeqNum,
            _msgData
        );
        executeOp(context);
        return returnContext(context);
    }

    // fields
    // startMachineHash,
    // endMachineHash,
    // afterInboxHash,
    // afterMessagesHash,
    // afterLogsHash

    function returnContext(AssertionContext memory context)
        private
        pure
        returns (uint64 gas, bytes32[5] memory fields)
    {
        return (
            context.gas,
            [
                Machine.hash(context.startMachine),
                Machine.hash(context.afterMachine),
                context.inboxAcc,
                context.messageAcc,
                context.logAcc
            ]
        );
    }

    struct ValueStack {
        uint256 length;
        Value.Data[] values;
    }

    function popVal(ValueStack memory stack) private pure returns (Value.Data memory) {
        Value.Data memory val = stack.values[stack.length - 1];
        stack.length--;
        return val;
    }

    function pushVal(ValueStack memory stack, Value.Data memory val) private pure {
        stack.values[stack.length] = val;
        stack.length++;
    }

    struct AssertionContext {
        Machine.Data startMachine;
        Machine.Data afterMachine;
        bytes32 inboxAcc;
        bytes32 messageAcc;
        bytes32 logAcc;
        uint64 gas;
        Value.Data inboxMessage;
        bytes32 inboxMessageHash;
        ValueStack stack;
        ValueStack auxstack;
        bool hadImmediate;
        uint8 opcode;
        bytes proof;
        uint256 offset;
    }

    function handleError(AssertionContext memory context) private pure {
        if (context.afterMachine.errHandlerHash == CODE_POINT_ERROR) {
            context.afterMachine.setErrorStop();
        } else {
            context.afterMachine.instructionStackHash = context.afterMachine.errHandlerHash;
        }
    }

    function handleOpcodeError(AssertionContext memory context) private pure {
        handleError(context);
        // Also clear the stack and auxstack
        context.stack.length = 0;
        context.auxstack.length = 0;
    }

    function initializeExecutionContext(
        bytes32 inboxAcc,
        bytes32 messagesAcc,
        bytes32 logsAcc,
        bytes memory proof
    ) internal pure returns (AssertionContext memory) {
        uint8 stackCount = uint8(proof[0]);
        uint8 auxstackCount = uint8(proof[1]);
        uint256 offset = 2;

        // Leave some extra space for values pushed on the stack in the proofs
        Value.Data[] memory stackVals = new Value.Data[](stackCount + 4);
        Value.Data[] memory auxstackVals = new Value.Data[](auxstackCount + 4);
        for (uint256 i = 0; i < stackCount; i++) {
            (offset, stackVals[i]) = Marshaling.deserialize(proof, offset);
        }
        for (uint256 i = 0; i < auxstackCount; i++) {
            (offset, auxstackVals[i]) = Marshaling.deserialize(proof, offset);
        }
        Machine.Data memory mach;
        (offset, mach) = Machine.deserializeMachine(proof, offset);

        uint8 immediate = uint8(proof[offset]);
        uint8 opCode = uint8(proof[offset + 1]);
        offset += 2;
        AssertionContext memory context = AssertionContext(
            mach,
            mach.clone(),
            inboxAcc,
            messagesAcc,
            logsAcc,
            0,
            Value.newEmptyTuple(),
            0,
            ValueStack(stackCount, stackVals),
            ValueStack(auxstackCount, auxstackVals),
            immediate == 1,
            opCode,
            proof,
            offset
        );

        require(immediate == 0 || immediate == 1, BAD_IMM_TYP);
        Value.Data memory cp;
        if (immediate == 0) {
            cp = Value.newCodePoint(uint8(opCode), context.startMachine.instructionStackHash);
        } else {
            // If we have an immediate, there must be at least one stack value
            require(stackVals.length > 0, NO_IMM);
            cp = Value.newCodePoint(
                uint8(opCode),
                context.startMachine.instructionStackHash,
                stackVals[stackCount - 1]
            );
        }
        context.startMachine.instructionStackHash = cp.hash();

        // Add the stack and auxstack values to the start machine
        uint256 i = 0;
        for (i = 0; i < stackCount - immediate; i++) {
            context.startMachine.addDataStackValue(stackVals[i]);
        }
        for (i = 0; i < auxstackCount; i++) {
            context.startMachine.addAuxStackValue(auxstackVals[i]);
        }

        return context;
    }

    function executeOp(AssertionContext memory context) internal pure {
        (
            uint256 dataPopCount,
            uint256 auxPopCount,
            uint64 gasCost,
            function(AssertionContext memory) internal pure impl
        ) = opInfo(context.opcode);
        context.gas = gasCost;

        // Update end machine gas remaining before running opcode
        // No need to overflow check since the check for whether we
        // have sufficient gas fixes the overflow case
        context.afterMachine.arbGasRemaining = context.afterMachine.arbGasRemaining - gasCost;

        if (context.startMachine.arbGasRemaining < gasCost) {
            context.afterMachine.arbGasRemaining = MAX_UINT256;
            handleError(context);
            return;
        }

        if (context.stack.length < dataPopCount) {
            // If we have insufficient values, reject the proof unless the stack has been fully exhausted
            require(
                context.afterMachine.dataStack.hash() == Value.newEmptyTuple().hash(),
                STACK_MISSING
            );
            // If the stack is empty, the instruction underflowed so we have hit an error
            handleError(context);
            return;
        }

        if (context.auxstack.length < auxPopCount) {
            // If we have insufficient values, reject the proof unless the auxstack has been fully exhausted
            require(
                context.afterMachine.auxStack.hash() == Value.newEmptyTuple().hash(),
                AUX_MISSING
            );
            // If the auxstack is empty, the instruction underflowed so we have hit an error
            handleError(context);
            return;
        }

        // Require the prover to submit the minimal number of stack items
        require(
            ((dataPopCount > 0 || !context.hadImmediate) && context.stack.length == dataPopCount) ||
                (context.hadImmediate && dataPopCount == 0 && context.stack.length == 1),
            STACK_MANY
        );
        require(context.auxstack.length == auxPopCount, AUX_MANY);

        impl(context);

        // Add the stack and auxstack values to the start machine
        uint256 i = 0;

        for (i = 0; i < context.stack.length; i++) {
            context.afterMachine.addDataStackValue(context.stack.values[i]);
        }

        for (i = 0; i < context.auxstack.length; i++) {
            context.afterMachine.addAuxStackValue(context.auxstack.values[i]);
        }
    }

    /* solhint-disable no-inline-assembly */

    // Arithmetic

    function binaryMathOp(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        if (!val1.isInt() || !val2.isInt()) {
            handleOpcodeError(context);
            return;
        }
        uint256 a = val1.intVal;
        uint256 b = val2.intVal;

        uint256 c;
        if (context.opcode == OP_ADD) {
            assembly {
                c := add(a, b)
            }
        } else if (context.opcode == OP_MUL) {
            assembly {
                c := mul(a, b)
            }
        } else if (context.opcode == OP_SUB) {
            assembly {
                c := sub(a, b)
            }
        } else if (context.opcode == OP_EXP) {
            assembly {
                c := exp(a, b)
            }
        } else if (context.opcode == OP_SIGNEXTEND) {
            assembly {
                c := signextend(a, b)
            }
        } else if (context.opcode == OP_LT) {
            assembly {
                c := lt(a, b)
            }
        } else if (context.opcode == OP_GT) {
            assembly {
                c := gt(a, b)
            }
        } else if (context.opcode == OP_SLT) {
            assembly {
                c := slt(a, b)
            }
        } else if (context.opcode == OP_SGT) {
            assembly {
                c := sgt(a, b)
            }
        } else if (context.opcode == OP_AND) {
            assembly {
                c := and(a, b)
            }
        } else if (context.opcode == OP_OR) {
            assembly {
                c := or(a, b)
            }
        } else if (context.opcode == OP_XOR) {
            assembly {
                c := xor(a, b)
            }
        } else if (context.opcode == OP_BYTE) {
            assembly {
                c := byte(a, b)
            }
        } else if (context.opcode == OP_SHL) {
            assembly {
                c := shl(a, b)
            }
        } else if (context.opcode == OP_SHR) {
            assembly {
                c := shr(a, b)
            }
        } else if (context.opcode == OP_SAR) {
            assembly {
                c := sar(a, b)
            }
        } else if (context.opcode == OP_ETHHASH2) {
            c = uint256(keccak256(abi.encodePacked(a, b)));
        } else {
            assert(false);
        }

        pushVal(context.stack, Value.newInt(c));
    }

    function binaryMathOpZero(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        if (!val1.isInt() || !val2.isInt() || val2.intVal == 0) {
            handleOpcodeError(context);
            return;
        }
        uint256 a = val1.intVal;
        uint256 b = val2.intVal;

        uint256 c;
        if (context.opcode == OP_DIV) {
            assembly {
                c := div(a, b)
            }
        } else if (context.opcode == OP_SDIV) {
            assembly {
                c := sdiv(a, b)
            }
        } else if (context.opcode == OP_MOD) {
            assembly {
                c := mod(a, b)
            }
        } else if (context.opcode == OP_SMOD) {
            assembly {
                c := smod(a, b)
            }
        } else {
            assert(false);
        }

        pushVal(context.stack, Value.newInt(c));
    }

    function executeMathModInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        Value.Data memory val3 = popVal(context.stack);
        if (!val1.isInt() || !val2.isInt() || !val3.isInt() || val3.intVal == 0) {
            handleOpcodeError(context);
            return;
        }
        uint256 a = val1.intVal;
        uint256 b = val2.intVal;
        uint256 m = val3.intVal;

        uint256 c;

        if (context.opcode == OP_ADDMOD) {
            assembly {
                c := addmod(a, b, m)
            }
        } else if (context.opcode == OP_MULMOD) {
            assembly {
                c := mulmod(a, b, m)
            }
        } else {
            assert(false);
        }

        pushVal(context.stack, Value.newInt(c));
    }

    function executeEqInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        pushVal(context.stack, Value.newBoolean(val1.hash() == val2.hash()));
    }

    function executeIszeroInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        if (!val1.isInt()) {
            pushVal(context.stack, Value.newInt(0));
        } else {
            uint256 a = val1.intVal;
            uint256 c;
            assembly {
                c := iszero(a)
            }
            pushVal(context.stack, Value.newInt(c));
        }
    }

    function executeNotInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        if (!val1.isInt()) {
            handleOpcodeError(context);
            return;
        }
        uint256 a = val1.intVal;
        uint256 c;
        assembly {
            c := not(a)
        }
        pushVal(context.stack, Value.newInt(c));
    }

    /* solhint-enable no-inline-assembly */

    // Hash

    function executeHashInsn(AssertionContext memory context) internal pure {
        Value.Data memory val = popVal(context.stack);
        pushVal(context.stack, Value.newInt(uint256(val.hash())));
    }

    function executeTypeInsn(AssertionContext memory context) internal pure {
        Value.Data memory val = popVal(context.stack);
        pushVal(context.stack, val.typeCodeVal());
    }

    function executeKeccakFInsn(AssertionContext memory context) internal pure {
        Value.Data memory val = popVal(context.stack);
        if (!val.isTuple() || val.tupleVal.length != 7) {
            handleOpcodeError(context);
            return;
        }

        Value.Data[] memory values = val.tupleVal;
        for (uint256 i = 0; i < 7; i++) {
            if (!values[i].isInt()) {
                handleOpcodeError(context);
                return;
            }
        }
        uint256[25] memory data;
        for (uint256 i = 0; i < 25; i++) {
            data[5 * (i % 5) + i / 5] = uint256(uint64(values[i / 4].intVal >> ((i % 4) * 64)));
        }

        data = Keccak.keccakF(data);

        Value.Data[] memory outValues = new Value.Data[](7);
        for (uint256 i = 0; i < 7; i++) {
            outValues[i] = Value.newInt(0);
        }

        for (uint256 i = 0; i < 25; i++) {
            outValues[i / 4].intVal |= data[5 * (i % 5) + i / 5] << ((i % 4) * 64);
        }

        pushVal(context.stack, Value.newTuple(outValues));
    }

    // Stack ops

    function executePopInsn(AssertionContext memory context) internal pure {
        popVal(context.stack);
    }

    function executeSpushInsn(AssertionContext memory context) internal pure {
        pushVal(context.stack, context.afterMachine.staticVal);
    }

    function executeRpushInsn(AssertionContext memory context) internal pure {
        pushVal(context.stack, context.afterMachine.registerVal);
    }

    function executeRsetInsn(AssertionContext memory context) internal pure {
        context.afterMachine.registerVal = popVal(context.stack);
    }

    function executeJumpInsn(AssertionContext memory context) internal pure {
        Value.Data memory val = popVal(context.stack);
        if (!val.isCodePoint()) {
            handleOpcodeError(context);
            return;
        }
        context.afterMachine.instructionStackHash = val.hash();
    }

    function executeCjumpInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        if (!val1.isCodePoint() || !val2.isInt()) {
            handleOpcodeError(context);
            return;
        }
        if (val2.intVal != 0) {
            context.afterMachine.instructionStackHash = val1.hash();
        }
    }

    function executeStackemptyInsn(AssertionContext memory context) internal pure {
        bool empty = context.stack.length == 0 &&
            context.afterMachine.dataStack.hash() == Value.newEmptyTuple().hash();
        pushVal(context.stack, Value.newBoolean(empty));
    }

    function executePcpushInsn(AssertionContext memory context) internal pure {
        pushVal(context.stack, Value.newHashedValue(context.startMachine.instructionStackHash, 1));
    }

    function executeAuxpushInsn(AssertionContext memory context) internal pure {
        pushVal(context.auxstack, popVal(context.stack));
    }

    function executeAuxpopInsn(AssertionContext memory context) internal pure {
        pushVal(context.stack, popVal(context.auxstack));
    }

    function executeAuxstackemptyInsn(AssertionContext memory context) internal pure {
        bool empty = context.auxstack.length == 0 &&
            context.afterMachine.auxStack.hash() == Value.newEmptyTuple().hash();
        pushVal(context.stack, Value.newBoolean(empty));
    }

    function executeNopInsn(AssertionContext memory) internal pure {}

    function executeErrpushInsn(AssertionContext memory context) internal pure {
        pushVal(context.stack, Value.newHashedValue(context.afterMachine.errHandlerHash, 1));
    }

    function executeErrsetInsn(AssertionContext memory context) internal pure {
        Value.Data memory val = popVal(context.stack);
        if (!val.isCodePoint()) {
            handleOpcodeError(context);
            return;
        }
        context.afterMachine.errHandlerHash = val.hash();
    }

    // Dup ops

    function executeDup0Insn(AssertionContext memory context) internal pure {
        Value.Data memory val = popVal(context.stack);
        pushVal(context.stack, val);
        pushVal(context.stack, val);
    }

    function executeDup1Insn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        pushVal(context.stack, val2);
        pushVal(context.stack, val1);
        pushVal(context.stack, val2);
    }

    function executeDup2Insn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        Value.Data memory val3 = popVal(context.stack);
        pushVal(context.stack, val3);
        pushVal(context.stack, val2);
        pushVal(context.stack, val1);
        pushVal(context.stack, val3);
    }

    // Swap ops

    function executeSwap1Insn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        pushVal(context.stack, val1);
        pushVal(context.stack, val2);
    }

    function executeSwap2Insn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        Value.Data memory val3 = popVal(context.stack);
        pushVal(context.stack, val1);
        pushVal(context.stack, val2);
        pushVal(context.stack, val3);
    }

    // Tuple ops

    function executeTgetInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        if (!val1.isInt() || !val2.isTuple() || val1.intVal >= val2.valLength()) {
            handleOpcodeError(context);
            return;
        }
        pushVal(context.stack, val2.tupleVal[val1.intVal]);
    }

    function executeTsetInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        Value.Data memory val3 = popVal(context.stack);
        if (!val1.isInt() || !val2.isTuple() || val1.intVal >= val2.valLength()) {
            handleOpcodeError(context);
            return;
        }
        Value.Data[] memory tupleVals = val2.tupleVal;
        tupleVals[val1.intVal] = val3;
        pushVal(context.stack, Value.newTuple(tupleVals));
    }

    function executeTlenInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        if (!val1.isTuple()) {
            handleOpcodeError(context);
            return;
        }
        pushVal(context.stack, Value.newInt(val1.valLength()));
    }

    function executeXgetInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory auxVal = popVal(context.auxstack);
        if (!val1.isInt() || !auxVal.isTuple() || val1.intVal >= auxVal.valLength()) {
            handleOpcodeError(context);
            return;
        }
        pushVal(context.auxstack, auxVal);
        pushVal(context.stack, auxVal.tupleVal[val1.intVal]);
    }

    function executeXsetInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        Value.Data memory auxVal = popVal(context.auxstack);
        if (!auxVal.isTuple() || !val1.isInt() || val1.intVal >= auxVal.valLength()) {
            handleOpcodeError(context);
            return;
        }
        Value.Data[] memory tupleVals = auxVal.tupleVal;
        tupleVals[val1.intVal] = val2;
        pushVal(context.auxstack, Value.newTuple(tupleVals));
    }

    // Logging

    function executeLogInsn(AssertionContext memory context) internal pure {
        context.logAcc = keccak256(abi.encodePacked(context.logAcc, popVal(context.stack).hash()));
    }

    // System operations

    function executeSendInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        if (val1.size > SEND_SIZE_LIMIT || !val1.isValidTypeForSend()) {
            handleOpcodeError(context);
            return;
        }
        context.messageAcc = keccak256(abi.encodePacked(context.messageAcc, val1.hash()));
    }

    function incrementInbox(AssertionContext memory context)
        private
        pure
        returns (Value.Data memory)
    {
        require(context.inboxMessageHash != 0, INBOX_VAL);
        context.inboxAcc = Messages.addMessageToInbox(context.inboxAcc, context.inboxMessageHash);
        return context.inboxMessage;
    }

    function executeInboxPeekInsn(AssertionContext memory context) internal pure {
        Value.Data memory val = popVal(context.stack);
        if (context.afterMachine.pendingMessage.hash() != Value.newEmptyTuple().hash()) {
            context.afterMachine.pendingMessage = incrementInbox(context);
        }
        // The pending message must be a tuple of size at least 2
        pushVal(
            context.stack,
            Value.newBoolean(context.afterMachine.pendingMessage.tupleVal[1].hash() == val.hash())
        );
    }

    function executeInboxInsn(AssertionContext memory context) internal pure {
        if (context.afterMachine.pendingMessage.hash() != Value.newEmptyTuple().hash()) {
            // The pending message field is already full
            pushVal(context.stack, context.afterMachine.pendingMessage);
            context.afterMachine.pendingMessage = Value.newEmptyTuple();
        } else {
            pushVal(context.stack, incrementInbox(context));
        }
    }

    function executeSetGasInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        if (!val1.isInt()) {
            handleOpcodeError(context);
            return;
        }
        context.afterMachine.arbGasRemaining = val1.intVal;
    }

    function executePushGasInsn(AssertionContext memory context) internal pure {
        pushVal(context.stack, Value.newInt(context.afterMachine.arbGasRemaining));
    }

    function executeErrCodePointInsn(AssertionContext memory context) internal pure {
        pushVal(context.stack, Value.newHashedValue(CODE_POINT_ERROR, 1));
    }

    function executePushInsnInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        if (!val1.isInt() || !val2.isCodePoint()) {
            handleOpcodeError(context);
            return;
        }
        pushVal(context.stack, Value.newCodePoint(uint8(val1.intVal), val2.hash()));
    }

    function executePushInsnImmInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        Value.Data memory val3 = popVal(context.stack);
        if (!val1.isInt() || !val3.isCodePoint()) {
            handleOpcodeError(context);
            return;
        }
        pushVal(context.stack, Value.newCodePoint(uint8(val1.intVal), val3.hash(), val2));
    }

    function executeSideloadInsn(AssertionContext memory context) internal pure {
        Value.Data[] memory values = new Value.Data[](0);
        pushVal(context.stack, Value.newTuple(values));
    }

    function executeECRecoverInsn(AssertionContext memory context) internal pure {
        Value.Data memory val1 = popVal(context.stack);
        Value.Data memory val2 = popVal(context.stack);
        Value.Data memory val3 = popVal(context.stack);
        Value.Data memory val4 = popVal(context.stack);
        if (!val1.isInt() || !val2.isInt() || !val3.isInt() || !val4.isInt()) {
            handleOpcodeError(context);
            return;
        }
        bytes32 r = bytes32(val1.intVal);
        bytes32 s = bytes32(val2.intVal);
        if (val3.intVal != 0 && val3.intVal != 1) {
            pushVal(context.stack, Value.newInt(0));
            return;
        }
        uint8 v = uint8(val3.intVal) + 27;
        bytes32 message = bytes32(val4.intVal);
        address ret = ecrecover(message, v, r, s);
        pushVal(context.stack, Value.newInt(uint256(ret)));
    }

    function executeErrorInsn(AssertionContext memory context) internal pure {
        handleOpcodeError(context);
    }

    function executeStopInsn(AssertionContext memory context) internal pure {
        context.afterMachine.setHalt();
    }

    // Stop and arithmetic ops
    uint8 private constant OP_ADD = 0x01;
    uint8 private constant OP_MUL = 0x02;
    uint8 private constant OP_SUB = 0x03;
    uint8 private constant OP_DIV = 0x04;
    uint8 private constant OP_SDIV = 0x05;
    uint8 private constant OP_MOD = 0x06;
    uint8 private constant OP_SMOD = 0x07;
    uint8 private constant OP_ADDMOD = 0x08;
    uint8 private constant OP_MULMOD = 0x09;
    uint8 private constant OP_EXP = 0x0a;
    uint8 private constant OP_SIGNEXTEND = 0x0b;

    // Comparison & bitwise logic
    uint8 private constant OP_LT = 0x10;
    uint8 private constant OP_GT = 0x11;
    uint8 private constant OP_SLT = 0x12;
    uint8 private constant OP_SGT = 0x13;
    uint8 private constant OP_EQ = 0x14;
    uint8 private constant OP_ISZERO = 0x15;
    uint8 private constant OP_AND = 0x16;
    uint8 private constant OP_OR = 0x17;
    uint8 private constant OP_XOR = 0x18;
    uint8 private constant OP_NOT = 0x19;
    uint8 private constant OP_BYTE = 0x1a;
    uint8 private constant OP_SHL = 0x1b;
    uint8 private constant OP_SHR = 0x1c;
    uint8 private constant OP_SAR = 0x1d;

    // SHA3
    uint8 private constant OP_HASH = 0x20;
    uint8 private constant OP_TYPE = 0x21;
    uint8 private constant OP_ETHHASH2 = 0x22;
    uint8 private constant OP_KECCAK_F = 0x23;

    // Stack, Memory, Storage and Flow Operations
    uint8 private constant OP_POP = 0x30;
    uint8 private constant OP_SPUSH = 0x31;
    uint8 private constant OP_RPUSH = 0x32;
    uint8 private constant OP_RSET = 0x33;
    uint8 private constant OP_JUMP = 0x34;
    uint8 private constant OP_CJUMP = 0x35;
    uint8 private constant OP_STACKEMPTY = 0x36;
    uint8 private constant OP_PCPUSH = 0x37;
    uint8 private constant OP_AUXPUSH = 0x38;
    uint8 private constant OP_AUXPOP = 0x39;
    uint8 private constant OP_AUXSTACKEMPTY = 0x3a;
    uint8 private constant OP_NOP = 0x3b;
    uint8 private constant OP_ERRPUSH = 0x3c;
    uint8 private constant OP_ERRSET = 0x3d;

    // Duplication and Exchange operations
    uint8 private constant OP_DUP0 = 0x40;
    uint8 private constant OP_DUP1 = 0x41;
    uint8 private constant OP_DUP2 = 0x42;
    uint8 private constant OP_SWAP1 = 0x43;
    uint8 private constant OP_SWAP2 = 0x44;

    // Tuple opertations
    uint8 private constant OP_TGET = 0x50;
    uint8 private constant OP_TSET = 0x51;
    uint8 private constant OP_TLEN = 0x52;
    uint8 private constant OP_XGET = 0x53;
    uint8 private constant OP_XSET = 0x54;

    // Logging opertations
    uint8 private constant OP_BREAKPOINT = 0x60;
    uint8 private constant OP_LOG = 0x61;

    // System operations
    uint8 private constant OP_SEND = 0x70;
    uint8 private constant OP_INBOX_PEEK = 0x71;
    uint8 private constant OP_INBOX = 0x72;
    uint8 private constant OP_ERROR = 0x73;
    uint8 private constant OP_STOP = 0x74;
    uint8 private constant OP_SETGAS = 0x75;
    uint8 private constant OP_PUSHGAS = 0x76;
    uint8 private constant OP_ERR_CODE_POINT = 0x77;
    uint8 private constant OP_PUSH_INSN = 0x78;
    uint8 private constant OP_PUSH_INSN_IMM = 0x79;
    // uint8 private constant OP_OPEN_INSN = 0x7a;
    uint8 private constant OP_SIDELOAD = 0x7b;

    uint8 private constant OP_ECRECOVER = 0x80;

    uint8 private constant CODE_POINT_TYPECODE = 1;
    bytes32 private constant CODE_POINT_ERROR = keccak256(
        abi.encodePacked(CODE_POINT_TYPECODE, uint8(0), bytes32(0))
    );

    function opInfo(uint256 opCode)
        private
        pure
        returns (
            uint256, // stack pops
            uint256, // auxstack pops
            uint64, // gas used
            function(AssertionContext memory) internal pure // impl
        )
    {
        if (opCode == OP_ADD || opCode == OP_MUL || opCode == OP_SUB) {
            return (2, 0, 3, binaryMathOp);
        } else if (opCode == OP_DIV || opCode == OP_MOD) {
            return (2, 0, 4, binaryMathOpZero);
        } else if (opCode == OP_SDIV || opCode == OP_SMOD) {
            return (2, 0, 7, binaryMathOpZero);
        } else if (opCode == OP_ADDMOD || opCode == OP_MULMOD) {
            return (3, 0, 4, executeMathModInsn);
        } else if (opCode == OP_EXP) {
            return (2, 0, 25, binaryMathOp);
        } else if (opCode == OP_SIGNEXTEND) {
            return (2, 0, 7, binaryMathOp);
        } else if (
            opCode == OP_LT ||
            opCode == OP_GT ||
            opCode == OP_SLT ||
            opCode == OP_SGT ||
            opCode == OP_AND ||
            opCode == OP_OR ||
            opCode == OP_XOR
        ) {
            return (2, 0, 2, binaryMathOp);
        } else if (opCode == OP_EQ) {
            return (2, 0, 2, executeEqInsn);
        } else if (opCode == OP_ISZERO) {
            return (1, 0, 1, executeIszeroInsn);
        } else if (opCode == OP_NOT) {
            return (1, 0, 1, executeNotInsn);
        } else if (opCode == OP_BYTE || opCode == OP_SHL || opCode == OP_SHR || opCode == OP_SAR) {
            return (2, 0, 4, binaryMathOp);
        } else if (opCode == OP_HASH) {
            return (1, 0, 7, executeHashInsn);
        } else if (opCode == OP_TYPE) {
            return (1, 0, 3, executeTypeInsn);
        } else if (opCode == OP_ETHHASH2) {
            return (2, 0, 8, binaryMathOp);
        } else if (opCode == OP_KECCAK_F) {
            return (1, 0, 600, executeKeccakFInsn);
        } else if (opCode == OP_POP) {
            return (1, 0, 1, executePopInsn);
        } else if (opCode == OP_SPUSH) {
            return (0, 0, 1, executeSpushInsn);
        } else if (opCode == OP_RPUSH) {
            return (0, 0, 1, executeRpushInsn);
        } else if (opCode == OP_RSET) {
            return (1, 0, 2, executeRsetInsn);
        } else if (opCode == OP_JUMP) {
            return (1, 0, 4, executeJumpInsn);
        } else if (opCode == OP_CJUMP) {
            return (2, 0, 4, executeCjumpInsn);
        } else if (opCode == OP_STACKEMPTY) {
            return (0, 0, 2, executeStackemptyInsn);
        } else if (opCode == OP_PCPUSH) {
            return (0, 0, 1, executePcpushInsn);
        } else if (opCode == OP_AUXPUSH) {
            return (1, 0, 1, executeAuxpushInsn);
        } else if (opCode == OP_AUXPOP) {
            return (0, 1, 1, executeAuxpopInsn);
        } else if (opCode == OP_AUXSTACKEMPTY) {
            return (0, 0, 2, executeAuxstackemptyInsn);
        } else if (opCode == OP_NOP) {
            return (0, 0, 1, executeNopInsn);
        } else if (opCode == OP_ERRPUSH) {
            return (0, 0, 1, executeErrpushInsn);
        } else if (opCode == OP_ERRSET) {
            return (1, 0, 1, executeErrsetInsn);
        } else if (opCode == OP_DUP0) {
            return (1, 0, 1, executeDup0Insn);
        } else if (opCode == OP_DUP1) {
            return (2, 0, 1, executeDup1Insn);
        } else if (opCode == OP_DUP2) {
            return (3, 0, 1, executeDup2Insn);
        } else if (opCode == OP_SWAP1) {
            return (2, 0, 1, executeSwap1Insn);
        } else if (opCode == OP_SWAP2) {
            return (3, 0, 1, executeSwap2Insn);
        } else if (opCode == OP_TGET) {
            return (2, 0, 2, executeTgetInsn);
        } else if (opCode == OP_TSET) {
            return (3, 0, 40, executeTsetInsn);
        } else if (opCode == OP_TLEN) {
            return (1, 0, 2, executeTlenInsn);
        } else if (opCode == OP_XGET) {
            return (1, 1, 3, executeXgetInsn);
        } else if (opCode == OP_XSET) {
            return (2, 1, 41, executeXsetInsn);
        } else if (opCode == OP_BREAKPOINT) {
            return (0, 0, 100, executeNopInsn);
        } else if (opCode == OP_LOG) {
            return (1, 0, 100, executeLogInsn);
        } else if (opCode == OP_SEND) {
            return (1, 0, 100, executeSendInsn);
        } else if (opCode == OP_INBOX_PEEK) {
            return (1, 0, 40, executeInboxPeekInsn);
        } else if (opCode == OP_INBOX) {
            return (0, 0, 40, executeInboxInsn);
        } else if (opCode == OP_ERROR) {
            return (0, 0, 5, executeErrorInsn);
        } else if (opCode == OP_STOP) {
            return (0, 0, 10, executeStopInsn);
        } else if (opCode == OP_SETGAS) {
            return (1, 0, 0, executeSetGasInsn);
        } else if (opCode == OP_PUSHGAS) {
            return (0, 0, 1, executePushGasInsn);
        } else if (opCode == OP_ERR_CODE_POINT) {
            return (0, 0, 25, executeErrCodePointInsn);
        } else if (opCode == OP_PUSH_INSN) {
            return (2, 0, 25, executePushInsnInsn);
        } else if (opCode == OP_PUSH_INSN_IMM) {
            return (3, 0, 25, executePushInsnImmInsn);
        } else if (opCode == OP_SIDELOAD) {
            return (0, 0, 10, executeSideloadInsn);
        } else if (opCode == OP_ECRECOVER) {
            return (4, 0, 20000, executeECRecoverInsn);
        } else {
            return (0, 0, 0, executeErrorInsn);
        }
    }
}

File 9 of 58 : Messages.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "../arch/Value.sol";
import "../arch/Marshaling.sol";
import "../libraries/BytesLib.sol";

library Messages {
    using BytesLib for bytes;

    function messageHash(
        uint8 kind,
        address sender,
        uint256 blockNumber,
        uint256 timestamp,
        uint256 inboxSeqNum,
        bytes32 messageDataHash
    ) internal pure returns (bytes32) {
        return
            keccak256(
                abi.encodePacked(kind, sender, blockNumber, timestamp, inboxSeqNum, messageDataHash)
            );
    }

    function messageValue(
        uint8 kind,
        uint256 blockNumber,
        uint256 timestamp,
        address sender,
        uint256 inboxSeqNum,
        bytes memory messageData
    ) internal pure returns (Value.Data memory) {
        Value.Data[] memory tupData = new Value.Data[](6);
        tupData[0] = Value.newInt(uint256(kind));
        tupData[1] = Value.newInt(blockNumber);
        tupData[2] = Value.newInt(timestamp);
        tupData[3] = Value.newInt(uint256(sender));
        tupData[4] = Value.newInt(inboxSeqNum);
        tupData[5] = Marshaling.bytesToBytestack(messageData, 0, messageData.length);
        return Value.newTuple(tupData);
    }

    function addMessageToInbox(bytes32 inbox, bytes32 message) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(inbox, message));
    }

    struct OutgoingMessage {
        uint8 kind;
        address sender;
        bytes data;
    }

    struct EthMessage {
        address dest;
        uint256 value;
    }

    struct ERC20Message {
        address token;
        address dest;
        uint256 value;
    }

    struct ERC721Message {
        address token;
        address dest;
        uint256 id;
    }

    uint256 private constant ETH_MESSAGE_LENGTH = 20 + 32;
    uint256 private constant ERC20_MESSAGE_LENGTH = 20 + 20 + 32;
    uint256 private constant ERC721_MESSAGE_LENGTH = 20 + 20 + 32;

    function unmarshalOutgoingMessage(bytes memory data, uint256 startOffset)
        internal
        pure
        returns (
            bool valid,
            uint256 offset,
            OutgoingMessage memory message
        )
    {
        offset = startOffset;
        uint8 valType = uint8(data[offset]);
        offset++;

        if (valType != Value.tupleTypeCode() + 3) {
            return (false, startOffset, message);
        }

        uint256 rawKind;
        (valid, offset, rawKind) = Marshaling.deserializeCheckedInt(data, offset);
        if (!valid) {
            return (false, startOffset, message);
        }
        message.kind = uint8(rawKind);

        uint256 senderRaw;
        (valid, offset, senderRaw) = Marshaling.deserializeCheckedInt(data, offset);
        if (!valid) {
            return (false, startOffset, message);
        }

        message.sender = address(uint160((senderRaw)));
        (valid, offset, message.data) = Marshaling.bytestackToBytes(data, offset);
        if (!valid) {
            return (false, startOffset, message);
        }

        return (true, offset, message);
    }

    function parseEthMessage(bytes memory data)
        internal
        pure
        returns (bool valid, Messages.EthMessage memory message)
    {
        if (data.length < ETH_MESSAGE_LENGTH) {
            return (false, message);
        }
        uint256 offset = 0;
        offset += 12;
        message.dest = data.toAddress(offset);
        offset += 20;
        message.value = data.toUint(offset);
        return (true, message);
    }

    function parseERC20Message(bytes memory data)
        internal
        pure
        returns (bool valid, Messages.ERC20Message memory message)
    {
        if (data.length < ERC20_MESSAGE_LENGTH) {
            return (false, message);
        }
        uint256 offset = 0;
        offset += 12;
        message.token = data.toAddress(offset);
        offset += 20;
        offset += 12;
        message.dest = data.toAddress(offset);
        offset += 20;
        message.value = data.toUint(offset);
        return (true, message);
    }

    function parseERC721Message(bytes memory data)
        internal
        pure
        returns (bool valid, Messages.ERC721Message memory message)
    {
        if (data.length < ERC721_MESSAGE_LENGTH) {
            return (false, message);
        }
        uint256 offset = 0;
        offset += 12;
        message.token = data.toAddress(offset);
        offset += 20;
        offset += 12;
        message.dest = data.toAddress(offset);
        offset += 20;
        message.id = data.toUint(offset);
        return (true, message);
    }
}

File 10 of 58 : Keccak.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

///      This algorithm has been extracted from the implementation of smart pool (https://github.com/smartpool)
library Keccak {
    function keccakF(uint256[25] memory a) internal pure returns (uint256[25] memory) {
        uint256[5] memory c;
        uint256[5] memory d;
        //uint D_0; uint D_1; uint D_2; uint D_3; uint D_4;
        uint256[25] memory b;

        uint256[24] memory rc = [
            uint256(0x0000000000000001),
            0x0000000000008082,
            0x800000000000808A,
            0x8000000080008000,
            0x000000000000808B,
            0x0000000080000001,
            0x8000000080008081,
            0x8000000000008009,
            0x000000000000008A,
            0x0000000000000088,
            0x0000000080008009,
            0x000000008000000A,
            0x000000008000808B,
            0x800000000000008B,
            0x8000000000008089,
            0x8000000000008003,
            0x8000000000008002,
            0x8000000000000080,
            0x000000000000800A,
            0x800000008000000A,
            0x8000000080008081,
            0x8000000000008080,
            0x0000000080000001,
            0x8000000080008008
        ];

        for (uint256 i = 0; i < 24; i++) {
            /*
            for( x = 0 ; x < 5 ; x++ ) {
                C[x] = A[5*x]^A[5*x+1]^A[5*x+2]^A[5*x+3]^A[5*x+4];
            }*/

            c[0] = a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4];
            c[1] = a[5] ^ a[6] ^ a[7] ^ a[8] ^ a[9];
            c[2] = a[10] ^ a[11] ^ a[12] ^ a[13] ^ a[14];
            c[3] = a[15] ^ a[16] ^ a[17] ^ a[18] ^ a[19];
            c[4] = a[20] ^ a[21] ^ a[22] ^ a[23] ^ a[24];

            /*
            for( x = 0 ; x < 5 ; x++ ) {
                D[x] = C[(x+4)%5]^((C[(x+1)%5] * 2)&0xffffffffffffffff | (C[(x+1)%5]/(2**63)));
            }*/

            d[0] = c[4] ^ (((c[1] * 2) & 0xffffffffffffffff) | (c[1] / (2**63)));
            d[1] = c[0] ^ (((c[2] * 2) & 0xffffffffffffffff) | (c[2] / (2**63)));
            d[2] = c[1] ^ (((c[3] * 2) & 0xffffffffffffffff) | (c[3] / (2**63)));
            d[3] = c[2] ^ (((c[4] * 2) & 0xffffffffffffffff) | (c[4] / (2**63)));
            d[4] = c[3] ^ (((c[0] * 2) & 0xffffffffffffffff) | (c[0] / (2**63)));

            /*
            for( x = 0 ; x < 5 ; x++ ) {
                for( y = 0 ; y < 5 ; y++ ) {
                    A[5*x+y] = A[5*x+y] ^ D[x];
                }
            }*/

            a[0] = a[0] ^ d[0];
            a[1] = a[1] ^ d[0];
            a[2] = a[2] ^ d[0];
            a[3] = a[3] ^ d[0];
            a[4] = a[4] ^ d[0];
            a[5] = a[5] ^ d[1];
            a[6] = a[6] ^ d[1];
            a[7] = a[7] ^ d[1];
            a[8] = a[8] ^ d[1];
            a[9] = a[9] ^ d[1];
            a[10] = a[10] ^ d[2];
            a[11] = a[11] ^ d[2];
            a[12] = a[12] ^ d[2];
            a[13] = a[13] ^ d[2];
            a[14] = a[14] ^ d[2];
            a[15] = a[15] ^ d[3];
            a[16] = a[16] ^ d[3];
            a[17] = a[17] ^ d[3];
            a[18] = a[18] ^ d[3];
            a[19] = a[19] ^ d[3];
            a[20] = a[20] ^ d[4];
            a[21] = a[21] ^ d[4];
            a[22] = a[22] ^ d[4];
            a[23] = a[23] ^ d[4];
            a[24] = a[24] ^ d[4];

            /*Rho and pi steps*/
            b[0] = a[0];
            b[8] = (((a[1] * (2**36)) & 0xffffffffffffffff) | (a[1] / (2**28)));
            b[11] = (((a[2] * (2**3)) & 0xffffffffffffffff) | (a[2] / (2**61)));
            b[19] = (((a[3] * (2**41)) & 0xffffffffffffffff) | (a[3] / (2**23)));
            b[22] = (((a[4] * (2**18)) & 0xffffffffffffffff) | (a[4] / (2**46)));
            b[2] = (((a[5] * (2**1)) & 0xffffffffffffffff) | (a[5] / (2**63)));
            b[5] = (((a[6] * (2**44)) & 0xffffffffffffffff) | (a[6] / (2**20)));
            b[13] = (((a[7] * (2**10)) & 0xffffffffffffffff) | (a[7] / (2**54)));
            b[16] = (((a[8] * (2**45)) & 0xffffffffffffffff) | (a[8] / (2**19)));
            b[24] = (((a[9] * (2**2)) & 0xffffffffffffffff) | (a[9] / (2**62)));
            b[4] = (((a[10] * (2**62)) & 0xffffffffffffffff) | (a[10] / (2**2)));
            b[7] = (((a[11] * (2**6)) & 0xffffffffffffffff) | (a[11] / (2**58)));
            b[10] = (((a[12] * (2**43)) & 0xffffffffffffffff) | (a[12] / (2**21)));
            b[18] = (((a[13] * (2**15)) & 0xffffffffffffffff) | (a[13] / (2**49)));
            b[21] = (((a[14] * (2**61)) & 0xffffffffffffffff) | (a[14] / (2**3)));
            b[1] = (((a[15] * (2**28)) & 0xffffffffffffffff) | (a[15] / (2**36)));
            b[9] = (((a[16] * (2**55)) & 0xffffffffffffffff) | (a[16] / (2**9)));
            b[12] = (((a[17] * (2**25)) & 0xffffffffffffffff) | (a[17] / (2**39)));
            b[15] = (((a[18] * (2**21)) & 0xffffffffffffffff) | (a[18] / (2**43)));
            b[23] = (((a[19] * (2**56)) & 0xffffffffffffffff) | (a[19] / (2**8)));
            b[3] = (((a[20] * (2**27)) & 0xffffffffffffffff) | (a[20] / (2**37)));
            b[6] = (((a[21] * (2**20)) & 0xffffffffffffffff) | (a[21] / (2**44)));
            b[14] = (((a[22] * (2**39)) & 0xffffffffffffffff) | (a[22] / (2**25)));
            b[17] = (((a[23] * (2**8)) & 0xffffffffffffffff) | (a[23] / (2**56)));
            b[20] = (((a[24] * (2**14)) & 0xffffffffffffffff) | (a[24] / (2**50)));

            /*Xi state*/
            /*
            for( x = 0 ; x < 5 ; x++ ) {
                for( y = 0 ; y < 5 ; y++ ) {
                    A[5*x+y] = B[5*x+y]^((~B[5*((x+1)%5)+y]) & B[5*((x+2)%5)+y]);
                }
            }*/

            a[0] = b[0] ^ ((~b[5]) & b[10]);
            a[1] = b[1] ^ ((~b[6]) & b[11]);
            a[2] = b[2] ^ ((~b[7]) & b[12]);
            a[3] = b[3] ^ ((~b[8]) & b[13]);
            a[4] = b[4] ^ ((~b[9]) & b[14]);
            a[5] = b[5] ^ ((~b[10]) & b[15]);
            a[6] = b[6] ^ ((~b[11]) & b[16]);
            a[7] = b[7] ^ ((~b[12]) & b[17]);
            a[8] = b[8] ^ ((~b[13]) & b[18]);
            a[9] = b[9] ^ ((~b[14]) & b[19]);
            a[10] = b[10] ^ ((~b[15]) & b[20]);
            a[11] = b[11] ^ ((~b[16]) & b[21]);
            a[12] = b[12] ^ ((~b[17]) & b[22]);
            a[13] = b[13] ^ ((~b[18]) & b[23]);
            a[14] = b[14] ^ ((~b[19]) & b[24]);
            a[15] = b[15] ^ ((~b[20]) & b[0]);
            a[16] = b[16] ^ ((~b[21]) & b[1]);
            a[17] = b[17] ^ ((~b[22]) & b[2]);
            a[18] = b[18] ^ ((~b[23]) & b[3]);
            a[19] = b[19] ^ ((~b[24]) & b[4]);
            a[20] = b[20] ^ ((~b[0]) & b[5]);
            a[21] = b[21] ^ ((~b[1]) & b[6]);
            a[22] = b[22] ^ ((~b[2]) & b[7]);
            a[23] = b[23] ^ ((~b[3]) & b[8]);
            a[24] = b[24] ^ ((~b[4]) & b[9]);

            /*Last step*/
            a[0] = a[0] ^ rc[i];
        }

        return a;
    }
}

File 11 of 58 : BisectionChallenge.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./Challenge.sol";
import "./IBisectionChallenge.sol";

import "../libraries/MerkleLib.sol";

contract BisectionChallenge is IBisectionChallenge, Challenge {
    event Continued(uint256 segmentIndex, uint256 deadlineTicks);

    // Incorrect previous state
    string private constant BIS_PREV = "BIS_PREV";

    // Incorrect previous state
    string private constant CON_PREV = "CON_PREV";
    // Invalid assertion selected
    string private constant CON_PROOF = "CON_PROOF";
    // Incorrect previous state

    // After bisection this is an array of all sub-assertions
    // After a challenge, the first assertion is the main assertion
    bytes32 private challengeState;

    function initializeBisection(
        address _rollupAddress,
        address payable _asserter,
        address payable _challenger,
        uint256 _challengePeriodTicks,
        bytes32 _challengeState
    ) external {
        Challenge.initializeChallenge(
            _rollupAddress,
            _asserter,
            _challenger,
            _challengePeriodTicks
        );
        challengeState = _challengeState;
    }

    function chooseSegment(
        uint256 _segmentToChallenge,
        bytes memory _proof,
        bytes32 _bisectionRoot,
        bytes32 _bisectionHash
    ) public challengerAction {
        require(_bisectionRoot == challengeState, CON_PREV);
        require(
            MerkleLib.verifyProof(_proof, _bisectionRoot, _bisectionHash, _segmentToChallenge + 1),
            CON_PROOF
        );

        challengeState = _bisectionHash;

        challengerResponded();
        emit Continued(_segmentToChallenge, deadlineTicks);
    }

    function commitToSegment(bytes32[] memory hashes) internal {
        challengeState = MerkleLib.generateRoot(hashes);
    }

    function requireMatchesPrevState(bytes32 _challengeState) internal view {
        require(_challengeState == challengeState, BIS_PREV);
    }

    function firstSegmentSize(uint256 totalCount, uint256 bisectionCount)
        internal
        pure
        returns (uint256)
    {
        return totalCount / bisectionCount + (totalCount % bisectionCount);
    }

    function otherSegmentSize(uint256 totalCount, uint256 bisectionCount)
        internal
        pure
        returns (uint256)
    {
        return totalCount / bisectionCount;
    }
}

File 12 of 58 : Challenge.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "../rollup/IStaking.sol";
import "../libraries/RollupTime.sol";
import "../libraries/Cloneable.sol";

contract Challenge is Cloneable {
    enum State { NoChallenge, AsserterTurn, ChallengerTurn }

    event InitiatedChallenge(uint256 deadlineTicks);

    event AsserterTimedOut();
    event ChallengerTimedOut();

    // Can online initialize once
    string private constant CHAL_INIT_STATE = "CHAL_INIT_STATE";
    // Can only continue challenge in response to bisection

    string private constant CON_STATE = "CON_STATE";
    // deadline expired
    string private constant CON_DEADLINE = "CON_DEADLINE";
    // Only original challenger can continue challenge
    string private constant CON_SENDER = "CON_SENDER";

    // Can only bisect assertion in response to a challenge
    string private constant BIS_STATE = "BIS_STATE";
    // deadline expired
    string private constant BIS_DEADLINE = "BIS_DEADLINE";
    // Only original asserter can continue bisect
    string private constant BIS_SENDER = "BIS_SENDER";

    address internal rollupAddress;
    address payable internal asserter;
    address payable internal challenger;

    uint256 internal deadlineTicks;

    // The current deadline at which the challenge timeouts and a winner is
    // declared. This deadline resets at each step in the challenge
    uint256 private challengePeriodTicks;

    State private state;

    modifier asserterAction {
        require(State.AsserterTurn == state, BIS_STATE);
        require(RollupTime.blocksToTicks(block.number) <= deadlineTicks, BIS_DEADLINE);
        require(msg.sender == asserter, BIS_SENDER);
        _;
    }

    modifier challengerAction {
        require(State.ChallengerTurn == state, CON_STATE);
        require(RollupTime.blocksToTicks(block.number) <= deadlineTicks, CON_DEADLINE);
        require(msg.sender == challenger, CON_SENDER);
        _;
    }

    function timeoutChallenge() public {
        require(RollupTime.blocksToTicks(block.number) > deadlineTicks, "Deadline hasn't expired");

        if (state == State.AsserterTurn) {
            emit AsserterTimedOut();
            _challengerWin();
        } else {
            emit ChallengerTimedOut();
            _asserterWin();
        }
    }

    function initializeChallenge(
        address _rollupAddress,
        address payable _asserter,
        address payable _challenger,
        uint256 _challengePeriodTicks
    ) internal {
        require(state == State.NoChallenge, CHAL_INIT_STATE);

        rollupAddress = _rollupAddress;
        asserter = _asserter;
        challenger = _challenger;
        challengePeriodTicks = _challengePeriodTicks;
        state = State.AsserterTurn;
        updateDeadline();

        emit InitiatedChallenge(deadlineTicks);
    }

    function updateDeadline() internal {
        deadlineTicks = RollupTime.blocksToTicks(block.number) + challengePeriodTicks;
    }

    function asserterResponded() internal {
        state = State.ChallengerTurn;
        updateDeadline();
    }

    function challengerResponded() internal {
        state = State.AsserterTurn;
        updateDeadline();
    }

    function _asserterWin() internal {
        IStaking(rollupAddress).resolveChallenge(asserter, challenger);
        safeSelfDestruct(msg.sender);
    }

    function _challengerWin() internal {
        IStaking(rollupAddress).resolveChallenge(challenger, asserter);
        safeSelfDestruct(msg.sender);
    }
}

File 13 of 58 : IStaking.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

interface IStaking {
    function resolveChallenge(address payable winner, address loser) external;
}

File 14 of 58 : RollupTime.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

library RollupTime {
    uint256 private constant TICKS_PER_BLOCK = 1000; // 1 tick == 1 milliblock

    function ticksToBlocks(uint256 ticks) internal pure returns (uint128) {
        return uint128(ticks / TICKS_PER_BLOCK);
    }

    function blocksToTicks(uint256 blockNum) internal pure returns (uint256) {
        return uint256(blockNum) * TICKS_PER_BLOCK;
    }
}

File 15 of 58 : Cloneable.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./ICloneable.sol";

contract Cloneable is ICloneable {
    string private constant NOT_CLONE = "NOT_CLONE";

    bool private isMasterCopy;

    constructor() public {
        isMasterCopy = true;
    }

    function isMaster() external view returns (bool) {
        return isMasterCopy;
    }

    function safeSelfDestruct(address payable dest) internal {
        require(!isMasterCopy, NOT_CLONE);
        selfdestruct(dest);
    }
}

File 16 of 58 : ICloneable.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

interface ICloneable {
    function isMaster() external view returns (bool);
}

File 17 of 58 : IBisectionChallenge.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

interface IBisectionChallenge {
    function initializeBisection(
        address _rollupAddress,
        address payable _asserter,
        address payable _challenger,
        uint256 _challengePeriodTicks,
        bytes32 _challengeState
    ) external;
}

File 18 of 58 : MerkleLib.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

library MerkleLib {
    function generateAddressRoot(address[] memory _addresses) internal pure returns (bytes32) {
        bytes32[] memory _hashes = new bytes32[](_addresses.length);
        for (uint256 i = 0; i < _addresses.length; i++) {
            _hashes[i] = bytes32(bytes20(_addresses[i]));
        }
        return generateRoot(_hashes);
    }

    function generateRoot(bytes32[] memory _hashes) internal pure returns (bytes32) {
        bytes32[] memory prevLayer = _hashes;
        while (prevLayer.length > 1) {
            bytes32[] memory nextLayer = new bytes32[]((prevLayer.length + 1) / 2);
            for (uint256 i = 0; i < nextLayer.length; i++) {
                if (2 * i + 1 < prevLayer.length) {
                    nextLayer[i] = keccak256(
                        abi.encodePacked(prevLayer[2 * i], prevLayer[2 * i + 1])
                    );
                } else {
                    nextLayer[i] = prevLayer[2 * i];
                }
            }
            prevLayer = nextLayer;
        }
        return prevLayer[0];
    }

    function verifyProof(
        bytes memory proof,
        bytes32 root,
        bytes32 hash,
        uint256 index
    ) internal pure returns (bool) {
        // use the index to determine the node ordering
        // index ranges 1 to n

        bytes32 el;
        bytes32 h = hash;
        uint256 remaining;

        for (uint256 j = 32; j <= proof.length; j += 32) {
            // solhint-disable-next-line no-inline-assembly
            assembly {
                el := mload(add(proof, j))
            }

            // calculate remaining elements in proof
            remaining = (proof.length - j + 32) / 32;

            // we don't assume that the tree is padded to a power of 2
            // if the index is odd then the proof will start with a hash at a higher
            // layer, so we have to adjust the index to be the index at that layer
            while (remaining > 0 && index % 2 == 1 && index > 2**remaining) {
                index = uint256(index) / 2 + 1;
            }

            if (index % 2 == 0) {
                h = keccak256(abi.encodePacked(el, h));
                index = index / 2;
            } else {
                h = keccak256(abi.encodePacked(h, el));
                index = uint256(index) / 2 + 1;
            }
        }

        return h == root;
    }
}

File 19 of 58 : ChallengeFactory.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "../libraries/CloneFactory.sol";

import "./IChallengeFactory.sol";
import "./IBisectionChallenge.sol";
import "./IExecutionChallenge.sol";
import "./ChallengeUtils.sol";

contract ChallengeFactory is CloneFactory, IChallengeFactory {
    // Invalid challenge type
    string public constant INVALID_TYPE_STR = "INVALID_TYPE";

    ICloneable public inboxTopChallengeTemplate;
    ICloneable public executionChallengeTemplate;
    address public oneStepProofAddress;

    constructor(
        address _inboxTopChallengeTemplate,
        address _executionChallengeTemplate,
        address _oneStepProofAddress
    ) public {
        inboxTopChallengeTemplate = ICloneable(_inboxTopChallengeTemplate);
        executionChallengeTemplate = ICloneable(_executionChallengeTemplate);
        oneStepProofAddress = _oneStepProofAddress;
    }

    function generateCloneAddress(
        address asserter,
        address challenger,
        uint256 challengeType
    ) public view returns (address) {
        return
            address(
                uint160(
                    uint256(
                        keccak256(
                            abi.encodePacked(
                                bytes1(0xff),
                                address(this),
                                generateNonce(asserter, challenger),
                                cloneCodeHash(getChallengeTemplate(challengeType))
                            )
                        )
                    )
                )
            );
    }

    function createChallenge(
        address payable _asserter,
        address payable _challenger,
        uint256 _challengePeriodTicks,
        bytes32 _challengeHash,
        uint256 challengeType
    ) external returns (address) {
        ICloneable challengeTemplate = getChallengeTemplate(challengeType);
        address clone = createClone(challengeTemplate);
        IBisectionChallenge(clone).initializeBisection(
            msg.sender,
            _asserter,
            _challenger,
            _challengePeriodTicks,
            _challengeHash
        );

        if (challengeType == ChallengeUtils.getInvalidExType()) {
            IExecutionChallenge(clone).connectOneStepProof(oneStepProofAddress);
        }
        return address(clone);
    }

    function generateNonce(address asserter, address challenger) private view returns (uint256) {
        return uint256(keccak256(abi.encodePacked(asserter, challenger, msg.sender)));
    }

    function getChallengeTemplate(uint256 challengeType) private view returns (ICloneable) {
        if (challengeType == ChallengeUtils.getInvalidInboxType()) {
            return inboxTopChallengeTemplate;
        } else if (challengeType == ChallengeUtils.getInvalidExType()) {
            return executionChallengeTemplate;
        } else {
            require(false, INVALID_TYPE_STR);
        }
    }
}

File 20 of 58 : CloneFactory.sol
// SPDX-License-Identifier: MIT

// Taken from https://github.com/optionality/clone-factory/blob/master/contracts/CloneFactory.sol

pragma solidity ^0.5.11;

/*
The MIT License (MIT)
Copyright (c) 2018 Murray Software, LLC.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
//solhint-disable max-line-length
//solhint-disable no-inline-assembly

import "./ICloneable.sol";

contract CloneFactory {
    string private constant CLONE_MASTER = "CLONE_MASTER";

    function createClone(ICloneable target) internal returns (address result) {
        require(target.isMaster(), CLONE_MASTER);
        bytes20 targetBytes = bytes20(address(target));
        assembly {
            let clone := mload(0x40)
            mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(clone, 0x14), targetBytes)
            mstore(
                add(clone, 0x28),
                0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
            )
            result := create(0, clone, 0x37)
        }
    }

    function create2Clone(ICloneable target, bytes32 salt) internal returns (address result) {
        require(target.isMaster(), CLONE_MASTER);
        bytes20 targetBytes = bytes20(address(target));
        assembly {
            let clone := mload(0x40)
            mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(clone, 0x14), targetBytes)
            mstore(
                add(clone, 0x28),
                0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
            )
            result := create2(0, clone, 0x37, salt)
        }
    }

    function isClone(ICloneable target, address query) internal view returns (bool result) {
        bytes20 targetBytes = bytes20(address(target));
        assembly {
            let clone := mload(0x40)
            mstore(clone, 0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000)
            mstore(add(clone, 0xa), targetBytes)
            mstore(
                add(clone, 0x1e),
                0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
            )

            let other := add(clone, 0x40)
            extcodecopy(query, other, 0, 0x2d)
            result := and(
                eq(mload(clone), mload(other)),
                eq(mload(add(clone, 0xd)), mload(add(other, 0xd)))
            )
        }
    }

    function cloneCodeHash(ICloneable target) internal pure returns (bytes32 result) {
        bytes20 targetBytes = bytes20(address(target));
        assembly {
            let clone := mload(0x40)
            mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(clone, 0x14), targetBytes)
            mstore(
                add(clone, 0x28),
                0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
            )
            result := keccak256(clone, 0x37)
        }
    }
}

File 21 of 58 : IChallengeFactory.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

interface IChallengeFactory {
    function createChallenge(
        address payable _asserter,
        address payable _challenger,
        uint256 _challengePeriodTicks,
        bytes32 _challengeHash,
        uint256 challengeType
    ) external returns (address);

    function generateCloneAddress(
        address asserter,
        address challenger,
        uint256 challengeType
    ) external view returns (address);
}

File 22 of 58 : IExecutionChallenge.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

interface IExecutionChallenge {
    function connectOneStepProof(address oneStepProof) external;
}

File 23 of 58 : ChallengeUtils.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

library ChallengeUtils {
    uint256 public constant INVALID_INBOX_TOP_TYPE = 0;
    uint256 public constant INVALID_EXECUTION_TYPE = 1;
    uint256 public constant VALID_CHILD_TYPE = 2;

    function getInvalidInboxType() internal pure returns (uint256) {
        return INVALID_INBOX_TOP_TYPE;
    }

    function getInvalidExType() internal pure returns (uint256) {
        return INVALID_EXECUTION_TYPE;
    }

    function getValidChildType() internal pure returns (uint256) {
        return VALID_CHILD_TYPE;
    }

    function inboxTopHash(
        bytes32 _lowerHash,
        bytes32 _topHash,
        uint256 _chainLength
    ) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(_lowerHash, _topHash, _chainLength));
    }

    struct ExecutionAssertion {
        uint64 numSteps;
        uint64 numArbGas;
        bytes32 beforeMachineHash;
        bytes32 afterMachineHash;
        bytes32 beforeInboxHash;
        bytes32 afterInboxHash;
        bytes32 firstMessageHash;
        bytes32 lastMessageHash;
        uint64 messageCount;
        bytes32 firstLogHash;
        bytes32 lastLogHash;
        uint64 logCount;
    }

    function hash(ExecutionAssertion memory assertion) internal pure returns (bytes32) {
        return
            keccak256(
                abi.encodePacked(
                    assertion.numSteps,
                    assertion.numArbGas,
                    assertion.beforeMachineHash,
                    assertion.afterMachineHash,
                    assertion.beforeInboxHash,
                    assertion.afterInboxHash,
                    assertion.firstMessageHash,
                    assertion.lastMessageHash,
                    assertion.messageCount,
                    assertion.firstLogHash,
                    assertion.lastLogHash,
                    assertion.logCount
                )
            );
    }
}

File 24 of 58 : ExecutionChallenge.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./IExecutionChallenge.sol";
import "./BisectionChallenge.sol";
import "./ChallengeUtils.sol";

import "../arch/IOneStepProof.sol";

import "../libraries/MerkleLib.sol";

contract ExecutionChallenge is IExecutionChallenge, BisectionChallenge {
    using ChallengeUtils for ChallengeUtils.ExecutionAssertion;

    event BisectedAssertion(bytes32[] assertionHashes, uint256 deadlineTicks);

    event OneStepProofCompleted();

    IOneStepProof private executor;

    // Incorrect previous state
    string private constant BIS_INPLEN = "BIS_INPLEN";
    // Proof was incorrect
    string private constant OSP_PROOF = "OSP_PROOF";

    struct BisectAssertionData {
        bytes32[] machineHashes;
        bytes32[] inboxAccs;
        bytes32[] messageAccs;
        bytes32[] logAccs;
        uint64[] outCounts;
        uint64[] gases;
        uint64 totalSteps;
    }

    function connectOneStepProof(address oneStepProof) external {
        executor = IOneStepProof(oneStepProof);
    }

    function bisectAssertion(
        bytes32[] memory _machineHashes,
        bytes32[] memory _inboxAccs,
        bytes32[] memory _messageAccs,
        bytes32[] memory _logAccs,
        uint64[] memory _outCounts,
        uint64[] memory _gases,
        uint64 _totalSteps
    ) public asserterAction {
        BisectAssertionData memory bisection = BisectAssertionData(
            _machineHashes,
            _inboxAccs,
            _messageAccs,
            _logAccs,
            _outCounts,
            _gases,
            _totalSteps
        );
        _bisectAssertion(bisection);
    }

    function _checkBisectionPrecondition(BisectAssertionData memory _data) private view {
        uint256 bisectionCount = _data.machineHashes.length - 1;
        require(bisectionCount + 1 == _data.inboxAccs.length, BIS_INPLEN);
        require(bisectionCount + 1 == _data.messageAccs.length, BIS_INPLEN);
        require(bisectionCount + 1 == _data.logAccs.length, BIS_INPLEN);
        require(bisectionCount == _data.gases.length, BIS_INPLEN);
        require(bisectionCount * 2 == _data.outCounts.length, BIS_INPLEN);
        uint64 totalGas = 0;
        uint64 totalMessageCount = 0;
        uint64 totalLogCount = 0;
        for (uint256 i = 0; i < bisectionCount; i++) {
            totalGas += _data.gases[i];
            totalMessageCount += _data.outCounts[i];
            totalLogCount += _data.outCounts[bisectionCount + i];
        }

        requireMatchesPrevState(
            _generateAssertionHash(
                _data,
                _data.totalSteps,
                0,
                bisectionCount,
                totalGas,
                totalMessageCount,
                totalLogCount
            )
        );
    }

    function _generateBisectionHash(
        BisectAssertionData memory data,
        uint64 stepCount,
        uint256 bisectionCount,
        uint256 i
    ) private pure returns (bytes32) {
        return
            _generateAssertionHash(
                data,
                stepCount,
                i,
                i + 1,
                data.gases[i],
                data.outCounts[i],
                data.outCounts[bisectionCount + i]
            );
    }

    function _generateAssertionHash(
        BisectAssertionData memory data,
        uint64 stepCount,
        uint256 start,
        uint256 end,
        uint64 gas,
        uint64 messageCount,
        uint64 logCount
    ) private pure returns (bytes32) {
        return
            ChallengeUtils
                .ExecutionAssertion(
                stepCount,
                gas,
                data.machineHashes[start],
                data.machineHashes[end],
                data.inboxAccs[start],
                data.inboxAccs[end],
                data.messageAccs[start],
                data.messageAccs[end],
                messageCount,
                data.logAccs[start],
                data.logAccs[end],
                logCount
            )
                .hash();
    }

    function _bisectAssertion(BisectAssertionData memory _data) private {
        uint256 bisectionCount = _data.machineHashes.length - 1;
        _checkBisectionPrecondition(_data);
        bytes32[] memory hashes = new bytes32[](bisectionCount);
        hashes[0] = _generateBisectionHash(
            _data,
            uint64(firstSegmentSize(uint256(_data.totalSteps), bisectionCount)),
            bisectionCount,
            0
        );
        for (uint256 i = 1; i < bisectionCount; i++) {
            hashes[i] = _generateBisectionHash(
                _data,
                uint64(otherSegmentSize(uint256(_data.totalSteps), bisectionCount)),
                bisectionCount,
                i
            );
        }

        commitToSegment(hashes);
        asserterResponded();

        emit BisectedAssertion(hashes, deadlineTicks);
    }

    function oneStepProofWithMessage(
        bytes32 _firstInbox,
        bytes32 _firstMessage,
        bytes32 _firstLog,
        bytes memory _proof,
        uint8 _kind,
        uint256 _blockNumber,
        uint256 _timestamp,
        address _sender,
        uint256 _inboxSeqNum,
        bytes memory _msgData
    ) public asserterAction {
        (uint64 gas, bytes32[5] memory fields) = executor.executeStepWithMessage(
            _firstInbox,
            _firstMessage,
            _firstLog,
            _proof,
            _kind,
            _blockNumber,
            _timestamp,
            _sender,
            _inboxSeqNum,
            _msgData
        );

        checkProof(gas, _firstInbox, _firstMessage, _firstLog, fields);
    }

    function oneStepProof(
        bytes32 _firstInbox,
        bytes32 _firstMessage,
        bytes32 _firstLog,
        bytes memory _proof
    ) public asserterAction {
        (uint64 gas, bytes32[5] memory fields) = executor.executeStep(
            _firstInbox,
            _firstMessage,
            _firstLog,
            _proof
        );

        checkProof(gas, _firstInbox, _firstMessage, _firstLog, fields);
    }

    function checkProof(
        uint64 gas,
        bytes32 firstInbox,
        bytes32 firstMessage,
        bytes32 firstLog,
        bytes32[5] memory fields
    ) private {
        bytes32 startMachineHash = fields[0];
        bytes32 endMachineHash = fields[1];
        bytes32 afterInboxHash = fields[2];
        bytes32 afterMessagesHash = fields[3];
        bytes32 afterLogsHash = fields[4];
        // The one step proof already guarantees us that firstMessage and lastMessage
        // are either one or 0 messages apart and the same is true for logs. Therefore
        // we can infer the message count and log count based on whether the fields
        // are equal or not
        ChallengeUtils.ExecutionAssertion memory assertion = ChallengeUtils.ExecutionAssertion(
            1,
            gas,
            startMachineHash,
            endMachineHash,
            firstInbox,
            afterInboxHash,
            firstMessage,
            afterMessagesHash,
            firstMessage == afterMessagesHash ? 0 : 1,
            firstLog,
            afterLogsHash,
            firstLog == afterLogsHash ? 0 : 1
        );
        requireMatchesPrevState(assertion.hash());

        emit OneStepProofCompleted();
        _asserterWin();
    }
}

File 25 of 58 : InboxTopChallenge.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./BisectionChallenge.sol";
import "./ChallengeUtils.sol";

import "../inbox/Messages.sol";

contract InboxTopChallenge is BisectionChallenge {
    event Bisected(bytes32[] chainHashes, uint256 totalLength, uint256 deadlineTicks);

    event OneStepProofCompleted();

    // Proof was incorrect
    string private constant HC_OSP_PROOF = "HC_OSP_PROOF";

    function bisect(bytes32[] calldata _chainHashes, uint256 _chainLength) external asserterAction {
        uint256 bisectionCount = _chainHashes.length - 1;

        requireMatchesPrevState(
            ChallengeUtils.inboxTopHash(_chainHashes[0], _chainHashes[bisectionCount], _chainLength)
        );

        require(_chainLength > 1, "bisection too short");
        bytes32[] memory hashes = new bytes32[](bisectionCount);
        hashes[0] = ChallengeUtils.inboxTopHash(
            _chainHashes[0],
            _chainHashes[1],
            firstSegmentSize(_chainLength, bisectionCount)
        );
        for (uint256 i = 1; i < bisectionCount; i++) {
            hashes[i] = ChallengeUtils.inboxTopHash(
                _chainHashes[i],
                _chainHashes[i + 1],
                otherSegmentSize(_chainLength, bisectionCount)
            );
        }

        commitToSegment(hashes);
        asserterResponded();
        emit Bisected(_chainHashes, _chainLength, deadlineTicks);
    }

    function oneStepProof(bytes32 _lowerHash, bytes32 _value) external asserterAction {
        requireMatchesPrevState(
            ChallengeUtils.inboxTopHash(
                _lowerHash,
                Messages.addMessageToInbox(_lowerHash, _value),
                1
            )
        );

        emit OneStepProofCompleted();
        _asserterWin();
    }
}

File 26 of 58 : GlobalEthWallet.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

contract GlobalEthWallet {
    mapping(address => uint256) private ethWallets;

    function withdrawEth() external {
        uint256 value = getEthBalance(msg.sender);
        delete ethWallets[msg.sender];
        msg.sender.transfer(value);
    }

    function getEthBalance(address _owner) public view returns (uint256) {
        return ethWallets[_owner];
    }

    function depositEth(address _destination) internal {
        ethWallets[_destination] += msg.value;
    }

    function transferEth(
        address _from,
        address _to,
        uint256 _value
    ) internal returns (bool) {
        if (_value > ethWallets[_from]) {
            return false;
        }
        ethWallets[_from] -= _value;
        ethWallets[_to] += _value;
        return true;
    }
}

File 27 of 58 : GlobalFTWallet.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "../interfaces/IERC20.sol";
import "../interfaces/IPairedErc20.sol";

contract GlobalFTWallet {
    string public constant FAILED_TRANSFER = "FAILED_TRANSFER";

    struct FTWallet {
        address contractAddress;
        uint256 balance;
    }

    struct UserFTWallet {
        mapping(address => uint256) ftIndex;
        FTWallet[] ftList;
    }

    mapping(address => UserFTWallet) private ftWallets;

    // Uninitialized paired contracts default to Unpaired
    enum PairingStatus { Unpaired, Requested, Paired }

    struct PairedContract {
        bool paired;
        mapping(address => PairingStatus) connectedRollups;
    }

    mapping(address => PairedContract) private pairedContracts;

    function ownedERC20s(address _owner) external view returns (address[] memory) {
        UserFTWallet storage wallet = ftWallets[_owner];
        address[] memory addresses = new address[](wallet.ftList.length);
        uint256 addressCount = addresses.length;
        for (uint256 i = 0; i < addressCount; i++) {
            addresses[i] = wallet.ftList[i].contractAddress;
        }
        return addresses;
    }

    function withdrawERC20(address _tokenContract) external {
        uint256 value = getERC20Balance(_tokenContract, msg.sender);
        require(removeToken(msg.sender, _tokenContract, value), "insufficient balance");
        if (pairedContracts[_tokenContract].paired) {
            IPairedErc20(_tokenContract).mint(msg.sender, value);
        } else {
            require(IERC20(_tokenContract).transfer(msg.sender, value), FAILED_TRANSFER);
        }
    }

    function getERC20Balance(address _tokenContract, address _owner) public view returns (uint256) {
        UserFTWallet storage wallet = ftWallets[_owner];
        uint256 index = wallet.ftIndex[_tokenContract];
        if (index == 0) {
            return 0;
        }
        return wallet.ftList[index - 1].balance;
    }

    function isPairedContract(address _tokenContract, address _chain)
        external
        view
        returns (PairingStatus)
    {
        return pairedContracts[_tokenContract].connectedRollups[_chain];
    }

    function requestPairing(address _tokenContract, address _chain) internal {
        PairedContract storage pairedContract = pairedContracts[_tokenContract];
        require(
            pairedContract.connectedRollups[_chain] == PairingStatus.Unpaired,
            "must be unpaired"
        );
        if (!pairedContract.paired) {
            // This is the first time pairing with a chain
            pairedContract.paired = true;

            // Burn existing balance since we will switch over to minting on withdrawal
            IPairedErc20 tokenContract = IPairedErc20(_tokenContract);
            tokenContract.burn(address(this), tokenContract.balanceOf(address(this)));
        }
        pairedContract.connectedRollups[_chain] = PairingStatus.Requested;
    }

    function updatePairing(
        address _tokenContract,
        address _chain,
        bool success
    ) internal {
        PairedContract storage pairedContract = pairedContracts[_tokenContract];
        if (pairedContract.connectedRollups[_chain] != PairingStatus.Requested) {
            // If the pairing hasn't been requested, ignore this
            return;
        }
        if (success) {
            pairedContract.connectedRollups[_chain] = PairingStatus.Paired;
        } else {
            pairedContract.connectedRollups[_chain] = PairingStatus.Unpaired;
        }
    }

    function depositERC20(
        address _tokenContract,
        address _destination,
        uint256 _value
    ) internal {
        PairedContract storage pairedContract = pairedContracts[_tokenContract];
        bool isPaired = pairedContract.paired;

        bool recipientMintNewTokens = isPaired &&
            pairedContract.connectedRollups[_destination] == PairingStatus.Paired;
        if (!recipientMintNewTokens) {
            addToken(_destination, _tokenContract, _value);
        }

        if (isPaired) {
            IPairedErc20(_tokenContract).burn(msg.sender, _value);
        } else {
            require(
                IERC20(_tokenContract).transferFrom(msg.sender, address(this), _value),
                FAILED_TRANSFER
            );
        }
    }

    function transferERC20(
        address _from,
        address _to,
        address _tokenContract,
        uint256 _value
    ) internal returns (bool) {
        // Skip removing or adding tokens for a pair contract with one of its connected rollups
        PairedContract storage pairedContract = pairedContracts[_tokenContract];
        bool isPaired = pairedContract.paired;
        bool senderMintNewTokens = isPaired &&
            pairedContract.connectedRollups[_from] == PairingStatus.Paired;
        if (!senderMintNewTokens && !removeToken(_from, _tokenContract, _value)) {
            return false;
        }

        bool recipientMintNewTokens = isPaired &&
            pairedContract.connectedRollups[_to] == PairingStatus.Paired;
        if (!recipientMintNewTokens) {
            addToken(_to, _tokenContract, _value);
        }
        return true;
    }

    function addToken(
        address _user,
        address _tokenContract,
        uint256 _value
    ) private {
        if (_value == 0) {
            return;
        }
        UserFTWallet storage wallet = ftWallets[_user];
        uint256 index = wallet.ftIndex[_tokenContract];
        if (index == 0) {
            index = wallet.ftList.push(FTWallet(_tokenContract, 0));
            wallet.ftIndex[_tokenContract] = index;
        }
        wallet.ftList[index - 1].balance += _value;
    }

    function removeToken(
        address _user,
        address _tokenContract,
        uint256 _value
    ) private returns (bool) {
        if (_value == 0) {
            return true;
        }
        UserFTWallet storage wallet = ftWallets[_user];
        uint256 walletIndex = wallet.ftIndex[_tokenContract];
        if (walletIndex == 0) {
            // Wallet has no coins from given ERC20 contract
            return false;
        }
        FTWallet storage tokenWallet = wallet.ftList[walletIndex - 1];
        if (_value > tokenWallet.balance) {
            // Wallet does not own enough ERC20 tokens
            return false;
        }
        tokenWallet.balance -= _value;
        if (tokenWallet.balance == 0) {
            wallet.ftIndex[wallet.ftList[wallet.ftList.length - 1].contractAddress] = walletIndex;
            wallet.ftList[walletIndex - 1] = wallet.ftList[wallet.ftList.length - 1];
            delete wallet.ftIndex[_tokenContract];
            wallet.ftList.pop();
        }
        return true;
    }
}

File 28 of 58 : IERC20.sol
// SPDX-License-Identifier: MIT

// Taken from @openzeppelin with MIT License

pragma solidity ^0.5.11;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see {ERC20Detailed}.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 29 of 58 : IPairedErc20.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

interface IPairedErc20 {
    function mint(address account, uint256 amount) external;

    function burn(address account, uint256 amount) external;

    function balanceOf(address account) external view returns (uint256);
}

File 30 of 58 : GlobalInbox.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./GlobalEthWallet.sol";
import "./GlobalFTWallet.sol";
import "./GlobalNFTWallet.sol";
import "./IGlobalInbox.sol";
import "./Messages.sol";
import "./PaymentRecords.sol";

contract GlobalInbox is
    IGlobalInbox,
    GlobalEthWallet,
    GlobalFTWallet,
    GlobalNFTWallet,
    PaymentRecords // solhint-disable-next-line bracket-align
{
    uint8 internal constant ETH_TRANSFER = 0;
    uint8 internal constant ERC20_TRANSFER = 1;
    uint8 internal constant ERC721_TRANSFER = 2;
    uint8 internal constant L2_MSG = 3;
    uint8 internal constant INITIALIZATION_MSG = 4;
    uint8 internal constant L2_CONTRACT_PAIR = 5;

    struct Inbox {
        bytes32 value;
        uint256 count;
    }

    mapping(address => Inbox) private inboxes;

    function getInbox(address account) external view returns (bytes32, uint256) {
        Inbox storage inbox = inboxes[account];
        return (inbox.value, inbox.count);
    }

    /**
     * @notice Process a set of marshalled messages confirmed by a rollup chain
     * @dev messageCounts and nodeHashes are used to uniquely identify messages in conjunction with PaymentRecords
     * @param messages Contiguously marshaled messages from a set of assertions
     * @param initialMaxSendCount Previous total message count sent by this sender
     * @param finalMaxSendCount Total message count sent by this sender after these messages
     */
    function sendMessages(
        bytes calldata messages,
        uint256 initialMaxSendCount,
        uint256 finalMaxSendCount
    ) external {
        bool valid;
        uint256 offset = 0;
        Messages.OutgoingMessage memory message;

        for (uint256 i = initialMaxSendCount; i < finalMaxSendCount; i++) {
            (valid, offset, message) = Messages.unmarshalOutgoingMessage(messages, offset);
            if (!valid) {
                return;
            }
            sendDeserializedMsg(i, message);
        }
    }

    /**
     * @notice Send a generic L2 message to a given Arbitrum Rollup chain
     * @dev This method is an optimization to avoid having to emit the entirety of the messageData in a log. Instead validators are expected to be able to parse the data from the transaction's input
     * @param chain Address of the rollup chain that the ETH is deposited into
     * @param messageData Data of the message being sent
     */
    function sendL2MessageFromOrigin(address chain, bytes calldata messageData) external {
        // solhint-disable-next-line avoid-tx-origin
        require(msg.sender == tx.origin, "origin only");
        uint256 inboxSeqNum = _deliverMessageImpl(
            chain,
            L2_MSG,
            msg.sender,
            keccak256(messageData)
        );
        emit MessageDeliveredFromOrigin(chain, L2_MSG, msg.sender, inboxSeqNum);
    }

    /**
     * @notice Send a generic L2 message to a given Arbitrum Rollup chain
     * @dev This method can be used to send any type of message that doesn't require L1 validation
     * @param chain Address of the rollup chain that the ETH is deposited into
     * @param messageData Data of the message being sent
     */
    function sendL2Message(address chain, bytes calldata messageData) external {
        _deliverMessage(chain, L2_MSG, msg.sender, messageData);
    }

    function deployL2ContractPair(
        address chain,
        uint256 maxGas,
        uint256 gasPriceBid,
        uint256 payment,
        bytes calldata contractData
    ) external {
        require(isContract(msg.sender), "must be called by contract");
        requestPairing(msg.sender, chain);
        _deliverMessage(
            chain,
            L2_CONTRACT_PAIR,
            msg.sender,
            abi.encodePacked(maxGas, gasPriceBid, payment, contractData)
        );
        emit BuddyContractPair(msg.sender, chain);
    }

    /**
     * @notice Send a generic L2 message to a given Arbitrum Rollup chain
     * @dev This method can be used to send any type of message that doesn't require L1 validation
     * @param messageData Data of the message being sent
     */
    function sendInitializationMessage(bytes calldata messageData) external {
        _deliverMessage(msg.sender, INITIALIZATION_MSG, msg.sender, messageData);
    }

    /**
     * @notice Deposits ETH into a given Arbitrum Rollup chain
     * @dev This method is payable and will deposit all value it is called with
     * @param chain Address of the rollup chain that the ETH is deposited into
     * @param to Address on the rollup chain that will receive the ETH
     */
    function depositEthMessage(address chain, address to) external payable {
        depositEth(chain);
        _deliverMessage(
            chain,
            ETH_TRANSFER,
            msg.sender,
            abi.encodePacked(uint256(uint160(bytes20(to))), msg.value)
        );
    }

    /**
     * @notice Deposits an ERC20 token into a given Arbitrum Rollup chain
     * @dev This method requires approving this contract for transfers
     * @param chain Address of the rollup chain that the token is deposited into
     * @param erc20 L1 address of the token being deposited
     * @param to Address on the rollup chain that will receive the tokens
     * @param value Quantity of tokens being deposited
     */
    function depositERC20Message(
        address chain,
        address erc20,
        address to,
        uint256 value
    ) external {
        depositERC20(erc20, chain, value);
        _deliverMessage(
            chain,
            ERC20_TRANSFER,
            msg.sender,
            abi.encodePacked(uint256(uint160(bytes20(erc20))), uint256(uint160(bytes20(to))), value)
        );
    }

    /**
     * @notice Deposits an ERC721 token into a given Arbitrum Rollup chain
     * @dev This method requires approving this contract for transfers
     * @param chain Address of the rollup chain that the token is deposited into
     * @param erc721 L1 address of the token being deposited
     * @param to Address on the rollup chain that will receive the token
     * @param id ID of the token being deposited
     */
    function depositERC721Message(
        address chain,
        address erc721,
        address to,
        uint256 id
    ) external {
        depositERC721(erc721, chain, id);
        _deliverMessage(
            chain,
            ERC721_TRANSFER,
            msg.sender,
            abi.encodePacked(uint256(uint160(bytes20(erc721))), uint256(uint160(bytes20(to))), id)
        );
    }

    function _deliverMessage(
        address _chain,
        uint8 _kind,
        address _sender,
        bytes memory _messageData
    ) private {
        uint256 inboxSeqNum = _deliverMessageImpl(_chain, _kind, _sender, keccak256(_messageData));
        emit MessageDelivered(_chain, _kind, _sender, inboxSeqNum, _messageData);
    }

    function _deliverMessageImpl(
        address _chain,
        uint8 _kind,
        address _sender,
        bytes32 _messageDataHash
    ) private returns (uint256) {
        Inbox storage inbox = inboxes[_chain];
        uint256 updatedCount = inbox.count + 1;
        bytes32 messageHash = Messages.messageHash(
            _kind,
            _sender,
            block.number,
            block.timestamp, // solhint-disable-line not-rely-on-time
            updatedCount,
            _messageDataHash
        );
        inbox.value = Messages.addMessageToInbox(inbox.value, messageHash);
        inbox.count = updatedCount;
        return updatedCount;
    }

    function sendDeserializedMsg(uint256 messageIndex, Messages.OutgoingMessage memory message)
        private
    {
        if (message.kind == ETH_TRANSFER) {
            (bool valid, Messages.EthMessage memory eth) = Messages.parseEthMessage(message.data);
            if (!valid) {
                return;
            }

            address paymentOwner = getPaymentOwner(eth.dest, messageIndex);
            deletePayment(eth.dest, messageIndex);
            transferEth(msg.sender, paymentOwner, eth.value);
        } else if (message.kind == ERC20_TRANSFER) {
            (bool valid, Messages.ERC20Message memory erc20) = Messages.parseERC20Message(
                message.data
            );
            if (!valid) {
                return;
            }

            address paymentOwner = getPaymentOwner(erc20.dest, messageIndex);
            transferERC20(msg.sender, paymentOwner, erc20.token, erc20.value);
            deletePayment(erc20.dest, messageIndex);
        } else if (message.kind == ERC721_TRANSFER) {
            (bool valid, Messages.ERC721Message memory erc721) = Messages.parseERC721Message(
                message.data
            );
            if (!valid) {
                return;
            }

            address paymentOwner = getPaymentOwner(erc721.dest, messageIndex);
            transferNFT(msg.sender, paymentOwner, erc721.token, erc721.id);
            deletePayment(erc721.dest, messageIndex);
        } else if (message.kind == L2_CONTRACT_PAIR) {
            updatePairing(message.sender, msg.sender, message.data[0] != 0);
            emit BuddyContractDeployed(message.sender, message.data);
        }
    }

    // Implementation taken from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.1.0/contracts/utils/Address.sol)
    function isContract(address account) private view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;

        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            codehash := extcodehash(account)
        }
        return (codehash != accountHash && codehash != 0x0);
    }
}

File 31 of 58 : GlobalNFTWallet.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "../interfaces/IERC721.sol";

contract GlobalNFTWallet {
    struct NFTWallet {
        address contractAddress;
        mapping(uint256 => uint256) tokenIndex;
        uint256[] tokenList;
    }

    struct UserNFTWallet {
        mapping(address => uint256) nftWalletIndex;
        NFTWallet[] nftWalletList;
    }

    mapping(address => UserNFTWallet) private nftWallets;

    function ownedERC721s(address _owner) external view returns (address[] memory) {
        UserNFTWallet storage wallet = nftWallets[_owner];
        address[] memory addresses = new address[](wallet.nftWalletList.length);
        uint256 addressCount = addresses.length;
        for (uint256 i = 0; i < addressCount; i++) {
            addresses[i] = wallet.nftWalletList[i].contractAddress;
        }
        return addresses;
    }

    function getERC721Tokens(address _erc721, address _owner)
        external
        view
        returns (uint256[] memory)
    {
        UserNFTWallet storage wallet = nftWallets[_owner];
        uint256 index = wallet.nftWalletIndex[_erc721];
        if (index == 0) {
            return new uint256[](0);
        }
        return wallet.nftWalletList[index - 1].tokenList;
    }

    function hasERC721(
        address _erc721,
        address _owner,
        uint256 _tokenId
    ) external view returns (bool) {
        UserNFTWallet storage wallet = nftWallets[_owner];
        uint256 index = wallet.nftWalletIndex[_erc721];
        if (index == 0) {
            return false;
        }
        return wallet.nftWalletList[index - 1].tokenIndex[_tokenId] != 0;
    }

    function withdrawERC721(address _erc721, uint256 _tokenId) external {
        require(removeNFTToken(msg.sender, _erc721, _tokenId), "Wallet doesn't own token");
        IERC721(_erc721).safeTransferFrom(address(this), msg.sender, _tokenId);
    }

    function depositERC721(
        address _erc721,
        address _destination,
        uint256 _tokenId
    ) internal {
        IERC721(_erc721).transferFrom(msg.sender, address(this), _tokenId);
        addNFTToken(_destination, _erc721, _tokenId);
    }

    function transferNFT(
        address _from,
        address _to,
        address _erc721,
        uint256 _tokenId
    ) internal returns (bool) {
        if (!removeNFTToken(_from, _erc721, _tokenId)) {
            return false;
        }
        addNFTToken(_to, _erc721, _tokenId);
        return true;
    }

    function addNFTToken(
        address _user,
        address _erc721,
        uint256 _tokenId
    ) private {
        UserNFTWallet storage wallet = nftWallets[_user];
        uint256 index = wallet.nftWalletIndex[_erc721];
        if (index == 0) {
            index = wallet.nftWalletList.push(NFTWallet(_erc721, new uint256[](0)));
            wallet.nftWalletIndex[_erc721] = index;
        }
        NFTWallet storage nftWallet = wallet.nftWalletList[index - 1];
        require(nftWallet.tokenIndex[_tokenId] == 0, "can't add already owned token");
        nftWallet.tokenList.push(_tokenId);
        nftWallet.tokenIndex[_tokenId] = nftWallet.tokenList.length;
    }

    function removeNFTToken(
        address _user,
        address _erc721,
        uint256 _tokenId
    ) private returns (bool) {
        UserNFTWallet storage wallet = nftWallets[_user];
        uint256 walletIndex = wallet.nftWalletIndex[_erc721];
        if (walletIndex == 0) {
            // Wallet has no coins from given NFT contract
            return false;
        }
        NFTWallet storage nftWallet = wallet.nftWalletList[walletIndex - 1];
        uint256 tokenIndex = nftWallet.tokenIndex[_tokenId];
        if (tokenIndex == 0) {
            // Wallet does not own specific NFT
            return false;
        }
        nftWallet.tokenIndex[nftWallet.tokenList[nftWallet.tokenList.length - 1]] = tokenIndex;
        nftWallet.tokenList[tokenIndex - 1] = nftWallet.tokenList[nftWallet.tokenList.length - 1];
        delete nftWallet.tokenIndex[_tokenId];
        nftWallet.tokenList.pop();
        if (nftWallet.tokenList.length == 0) {
            wallet.nftWalletIndex[wallet.nftWalletList[wallet.nftWalletList.length - 1]
                .contractAddress] = walletIndex;
            wallet.nftWalletList[walletIndex - 1] = wallet.nftWalletList[wallet
                .nftWalletList
                .length - 1];
            delete wallet.nftWalletIndex[_erc721];
            wallet.nftWalletList.pop();
        }
        return true;
    }
}

File 32 of 58 : IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.5.11;

/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  Note: the ERC-165 identifier for this interface is 0x80ac58cd.
/* is ERC165 */
interface IERC721 {
    /// @dev This emits when ownership of any NFT changes by any mechanism.
    ///  This event emits when NFTs are created (`from` == 0) and destroyed
    ///  (`to` == 0). Exception: during contract creation, any number of NFTs
    ///  may be created and assigned without emitting Transfer. At the time of
    ///  any transfer, the approved address for that NFT (if any) is reset to none.
    event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

    /// @dev This emits when the approved address for an NFT is changed or
    ///  reaffirmed. The zero address indicates there is no approved address.
    ///  When a Transfer event emits, this also indicates that the approved
    ///  address for that NFT (if any) is reset to none.
    event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);

    /// @dev This emits when an operator is enabled or disabled for an owner.
    ///  The operator can manage all NFTs of the owner.
    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

    /// @notice Count all NFTs assigned to an owner
    /// @dev NFTs assigned to the zero address are considered invalid, and this
    ///  function throws for queries about the zero address.
    /// @param _owner An address for whom to query the balance
    /// @return The number of NFTs owned by `_owner`, possibly zero
    function balanceOf(address _owner) external view returns (uint256);

    /// @notice Find the owner of an NFT
    /// @dev NFTs assigned to zero address are considered invalid, and queries
    ///  about them do throw.
    /// @param _tokenId The identifier for an NFT
    /// @return The address of the owner of the NFT
    function ownerOf(uint256 _tokenId) external view returns (address);

    /// @notice Transfers the ownership of an NFT from one address to another address
    /// @dev Throws unless `msg.sender` is the current owner, an authorized
    ///  operator, or the approved address for this NFT. Throws if `_from` is
    ///  not the current owner. Throws if `_to` is the zero address. Throws if
    ///  `_tokenId` is not a valid NFT. When transfer is complete, this function
    ///  checks if `_to` is a smart contract (code size > 0). If so, it calls
    ///  `onERC721Received` on `_to` and throws if the return value is not
    ///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    /// @param data Additional data with no specified format, sent in call to `_to`
    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _tokenId,
        bytes calldata data
    ) external payable;

    /// @notice Transfers the ownership of an NFT from one address to another address
    /// @dev This works identically to the other function with an extra data parameter,
    ///  except this function just sets data to "".
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    function safeTransferFrom(
        address _from,
        address _to,
        uint256 _tokenId
    ) external payable;

    /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
    ///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
    ///  THEY MAY BE PERMANENTLY LOST
    /// @dev Throws unless `msg.sender` is the current owner, an authorized
    ///  operator, or the approved address for this NFT. Throws if `_from` is
    ///  not the current owner. Throws if `_to` is the zero address. Throws if
    ///  `_tokenId` is not a valid NFT.
    /// @param _from The current owner of the NFT
    /// @param _to The new owner
    /// @param _tokenId The NFT to transfer
    function transferFrom(
        address _from,
        address _to,
        uint256 _tokenId
    ) external payable;

    /// @notice Change or reaffirm the approved address for an NFT
    /// @dev The zero address indicates there is no approved address.
    ///  Throws unless `msg.sender` is the current NFT owner, or an authorized
    ///  operator of the current owner.
    /// @param _approved The new approved NFT controller
    /// @param _tokenId The NFT to approve
    function approve(address _approved, uint256 _tokenId) external payable;

    /// @notice Enable or disable approval for a third party ("operator") to manage
    ///  all of `msg.sender`'s assets
    /// @dev Emits the ApprovalForAll event. The contract MUST allow
    ///  multiple operators per owner.
    /// @param _operator Address to add to the set of authorized operators
    /// @param _approved True if the operator is approved, false to revoke approval
    function setApprovalForAll(address _operator, bool _approved) external;

    /// @notice Get the approved address for a single NFT
    /// @dev Throws if `_tokenId` is not a valid NFT.
    /// @param _tokenId The NFT to find the approved address for
    /// @return The approved address for this NFT, or the zero address if there is none
    function getApproved(uint256 _tokenId) external view returns (address);

    /// @notice Query if an address is an authorized operator for another address
    /// @param _owner The address that owns the NFTs
    /// @param _operator The address that acts on behalf of the owner
    /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}

interface IERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceID The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    ///  uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceID` and
    ///  `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

File 33 of 58 : IGlobalInbox.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

interface IGlobalInbox {
    event MessageDelivered(
        address indexed chain,
        uint8 indexed kind,
        address indexed sender,
        uint256 inboxSeqNum,
        bytes data
    );

    event MessageDeliveredFromOrigin(
        address indexed chain,
        uint8 indexed kind,
        address indexed sender,
        uint256 inboxSeqNum
    );

    event BuddyContractDeployed(address indexed sender, bytes data);
    event BuddyContractPair(address indexed sender, address data);

    function getInbox(address account) external view returns (bytes32, uint256);

    function sendMessages(
        bytes calldata _messages,
        uint256 initialMaxSendCount,
        uint256 finalMaxSendCount
    ) external;

    function sendInitializationMessage(bytes calldata messageData) external;

    function sendL2Message(address chain, bytes calldata messageData) external;

    function deployL2ContractPair(
        address chain,
        uint256 maxGas,
        uint256 gasPriceBid,
        uint256 payment,
        bytes calldata contractData
    ) external;
}

File 34 of 58 : PaymentRecords.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

contract PaymentRecords {
    mapping(bytes32 => address) private payments;

    event PaymentTransfer(
        uint256 messageIndex,
        address originalOwner,
        address prevOwner,
        address newOwner
    );

    function transferPayment(
        address originalOwner,
        address newOwner,
        uint256 messageIndex
    ) external {
        address currentOwner = getPaymentOwner(originalOwner, messageIndex);
        require(msg.sender == currentOwner, "Must be payment owner.");

        payments[keccak256(abi.encodePacked(messageIndex, originalOwner))] = newOwner;

        emit PaymentTransfer(messageIndex, originalOwner, currentOwner, newOwner);
    }

    function getPaymentOwner(address originalOwner, uint256 messageIndex)
        public
        view
        returns (address)
    {
        address currentOwner = payments[keccak256(abi.encodePacked(messageIndex, originalOwner))];

        if (currentOwner == address(0)) {
            return originalOwner;
        } else {
            return currentOwner;
        }
    }

    function deletePayment(address originalOwner, uint256 messageIndex) internal {
        delete payments[keccak256(abi.encodePacked(messageIndex, originalOwner))];
    }
}

File 35 of 58 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.5.11;

// SafeMath comes from @openzeppelin under the MIT License

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 36 of 58 : ArbFactory.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "../libraries/CloneFactory.sol";

import "./IArbRollup.sol";

contract ArbFactory is CloneFactory {
    event RollupCreated(address rollupAddress);

    ICloneable public rollupTemplate;
    address public globalInboxAddress;
    address public challengeFactoryAddress;

    constructor(
        ICloneable _rollupTemplate,
        address _globalInboxAddress,
        address _challengeFactoryAddress
    ) public {
        rollupTemplate = _rollupTemplate;
        globalInboxAddress = _globalInboxAddress;
        challengeFactoryAddress = _challengeFactoryAddress;
    }

    function createRollup(
        bytes32 _vmState,
        uint128 _gracePeriodTicks,
        uint128 _arbGasSpeedLimitPerTick,
        uint64 _maxExecutionSteps,
        uint128 _stakeRequirement,
        address _stakeToken,
        address payable _owner,
        bytes calldata _extraConfig
    ) external {
        address clone = createClone(rollupTemplate);
        IArbRollup(clone).init(
            _vmState,
            _gracePeriodTicks,
            _arbGasSpeedLimitPerTick,
            _maxExecutionSteps,
            _stakeRequirement,
            _stakeToken,
            _owner,
            challengeFactoryAddress,
            globalInboxAddress,
            _extraConfig
        );
        emit RollupCreated(clone);
    }
}

File 37 of 58 : IArbRollup.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

interface IArbRollup {
    function init(
        bytes32 _vmState,
        uint128 _gracePeriodTicks,
        uint128 _arbGasSpeedLimitPerTick,
        uint64 _maxExecutionSteps,
        uint128 _stakeRequirement,
        address _stakeToken,
        address payable _owner,
        address _challengeFactoryAddress,
        address _globalInboxAddress,
        bytes calldata _extraConfig
    ) external;
}

File 38 of 58 : ArbRollup.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./IArbRollup.sol";
import "./NodeGraph.sol";
import "./Staking.sol";
import "../inbox/IGlobalInbox.sol";
import "../libraries/Cloneable.sol";

contract ArbRollup is IArbRollup, Cloneable, NodeGraph, Staking {
    // invalid path proof
    string private constant PLACE_LEAF = "PLACE_LEAF";

    // invalid leaf
    string private constant MOVE_LEAF = "MOVE_LEAF";

    // invalid path proof
    string private constant RECOV_PATH_PROOF = "RECOV_PATH_PROOF";
    // Invalid conflict proof
    string private constant RECOV_CONFLICT_PROOF = "RECOV_CONFLICT_PROOF";
    // Proof must be of nonzero length
    string private constant RECVOLD_LENGTH = "RECVOLD_LENGTH";
    // invalid leaf
    string private constant RECOV_DEADLINE_LEAF = "RECOV_DEADLINE_LEAF";
    // Node is not passed deadline
    string private constant RECOV_DEADLINE_TIME = "RECOV_DEADLINE_TIME";

    // invalid staker location proof
    string private constant MAKE_STAKER_PROOF = "MAKE_STAKER_PROOF";

    // Type is not invalid
    string private constant CONF_INV_TYPE = "CONF_INV_TYPE";
    // Node is not passed deadline
    string private constant CONF_TIME = "CONF_TIME";
    // There must be at least one staker
    string private constant CONF_HAS_STAKER = "CONF_HAS_STAKER";

    // Only callable by owner
    string private constant ONLY_OWNER = "ONLY_OWNER";

    string public constant VERSION = "0.7.0";

    address payable public owner;

    IGlobalInbox public globalInbox;

    event RollupCreated(
        bytes32 initVMHash,
        uint128 gracePeriodTicks,
        uint128 arbGasSpeedLimitPerTick,
        uint64 maxExecutionSteps,
        uint128 stakeRequirement,
        address owner,
        bytes extraConfig
    );

    event ConfirmedAssertion(bytes32[] logsAccHash);

    event ConfirmedValidAssertion(bytes32 indexed nodeHash);

    function init(
        bytes32 _vmState,
        uint128 _gracePeriodTicks,
        uint128 _arbGasSpeedLimitPerTick,
        uint64 _maxExecutionSteps,
        uint128 _stakeRequirement,
        address _stakeToken,
        address payable _owner,
        address _challengeFactoryAddress,
        address _globalInboxAddress,
        bytes calldata _extraConfig
    ) external {
        emit RollupCreated(
            _vmState,
            _gracePeriodTicks,
            _arbGasSpeedLimitPerTick,
            _maxExecutionSteps,
            _stakeRequirement,
            _owner,
            _extraConfig
        );

        NodeGraph.init(_vmState, _gracePeriodTicks, _arbGasSpeedLimitPerTick, _maxExecutionSteps);
        Staking.init(_stakeRequirement, _stakeToken, _challengeFactoryAddress);
        globalInbox = IGlobalInbox(_globalInboxAddress);
        owner = _owner;

        globalInbox.sendInitializationMessage(
            abi.encodePacked(
                uint256(_gracePeriodTicks),
                uint256(_arbGasSpeedLimitPerTick),
                uint256(_maxExecutionSteps),
                uint256(_stakeRequirement),
                bytes32(bytes20(_stakeToken)),
                bytes32(bytes20(_owner)),
                _extraConfig
            )
        );
    }

    /**
     * @notice Place a stake on an existing node at or after the latest confirmed node
     * @param proof1 Node graph proof that the stake location is a decendent of latest confirmed
     * @param proof2 Node graph proof that the stake location is an ancestor of a current leaf
     */
    function placeStake(bytes32[] calldata proof1, bytes32[] calldata proof2) external payable {
        bytes32 location = RollupUtils.calculateLeafFromPath(latestConfirmed(), proof1);
        bytes32 leaf = RollupUtils.calculateLeafFromPath(location, proof2);
        require(isValidLeaf(leaf), PLACE_LEAF);
        createStake(location);
    }

    /**
     * @notice Move an existing stake to an existing leaf that is a decendent of the node the stake exists on
     * @param proof1 Node graph proof that the destination location is a decendent of the current location
     * @param proof2 Node graph proof that the stake location is an ancestor of a current leaf
     */
    function moveStake(bytes32[] calldata proof1, bytes32[] calldata proof2) external {
        bytes32 stakerLocation = getStakerLocation(msg.sender);
        bytes32 newLocation = RollupUtils.calculateLeafFromPath(stakerLocation, proof1);
        bytes32 leaf = RollupUtils.calculateLeafFromPath(newLocation, proof2);
        require(isValidLeaf(leaf), MOVE_LEAF);
        updateStakerLocation(msg.sender, newLocation);
    }

    /**
     * @notice Redeem your stake if it is on or before the current latest confirmed node
     * @param proof Node graph proof your stake is on or before the latest confirmed node
     */
    function recoverStakeConfirmed(bytes32[] calldata proof) external {
        _recoverStakeConfirmed(msg.sender, proof);
    }

    /**
     * @notice Force a stake to be redeemed if it is before the current latest confirmed node
     * @param stakerAddress Address of the staker whose stake will be removed
     * @param proof Node graph proof your stake is before the latest confirmed node
     */
    function recoverStakeOld(address payable stakerAddress, bytes32[] calldata proof) external {
        require(proof.length > 0, RECVOLD_LENGTH);
        _recoverStakeConfirmed(stakerAddress, proof);
    }

    /**
     * @notice Force a stake to be redeemed if it is place on a node which can never be confirmed
     * @dev This method works by showing that the staker's position conflicts with the latest confirmed node
     * @param stakerAddress Address of the staker whose stake will be removed
     * @param node Identifier of a node which is a common ancestor of the latest confirmed node and the staker's location
     * @param latestConfirmedProof Node graph proof that the latest confirmed node is a decendent of the supplied node
     * @param stakerProof Node graph proof that the staker's node is a decendent of the supplied node
     */
    function recoverStakeMooted(
        address payable stakerAddress,
        bytes32 node,
        bytes32[] calldata latestConfirmedProof,
        bytes32[] calldata stakerProof
    ) external {
        bytes32 stakerLocation = getStakerLocation(msg.sender);
        require(
            latestConfirmedProof[0] != stakerProof[0] &&
                RollupUtils.calculateLeafFromPath(node, latestConfirmedProof) ==
                latestConfirmed() &&
                RollupUtils.calculateLeafFromPath(node, stakerProof) == stakerLocation,
            RECOV_CONFLICT_PROOF
        );
        refundStaker(stakerAddress);
    }

    // Kick off if successor node whose deadline has passed
    // TODO: Add full documentation
    function recoverStakePassedDeadline(
        address payable stakerAddress,
        uint256 deadlineTicks,
        bytes32 disputableNodeHashVal,
        uint256 childType,
        bytes32 vmProtoStateHash,
        bytes32[] calldata proof
    ) external {
        bytes32 stakerLocation = getStakerLocation(msg.sender);
        bytes32 nextNode = RollupUtils.childNodeHash(
            stakerLocation,
            deadlineTicks,
            disputableNodeHashVal,
            childType,
            vmProtoStateHash
        );
        bytes32 leaf = RollupUtils.calculateLeafFromPath(nextNode, proof);
        require(isValidLeaf(leaf), RECOV_DEADLINE_LEAF);
        require(block.number >= RollupTime.blocksToTicks(deadlineTicks), RECOV_DEADLINE_TIME);

        refundStaker(stakerAddress);
    }

    /**
     * @notice Submit a new assertion to be built on top of the specified leaf if it is validly constructed
     * @dev This method selects an existing leaf to build an assertion on top of. If it succeeds that leaf is eliminated and four new leaves are created. The asserter is automatically moved to stake on the new valid leaf.
     * @param fields Packed data for the following fields
     *   beforeMachineHash The hash of the machine at the end of the previous assertion
     *   afterMachineHash Claimed machine hash after this assertion is completed
     *   beforeInboxTop The hash of the global inbox that the previous assertion had read up to
     *   afterInboxTop Claimed hash of the global inbox at height beforeInboxCount + importedMessageCount
     *   messagesAccHash Claimed commitment to a set of messages output in the assertion
     *   logsAccHash Claimed commitment to a set of logs output in the assertion
     *   prevPrevLeafHash The hash of the leaf that was the ancestor of the leaf we're building on
     *   prevDataHash Type specific data of the node we're on

     * @param fields2 Packed data for the following fields
     *   beforeInboxCount The total number of messages read after the previous assertion executed
     *   prevDeadlineTicks The challenge deadline of the node this assertion builds on
     *   importedMessageCount Argument specifying the number of messages read
     *   beforeMessageCount The total number of messages that have been output by the chain before this assertion
     *   beforeLogCount The total number of messages that have been output by the chain before this assertion
     * @param validBlockHashPrecondition Hash of a known block to invalidate the assertion if too deep a reorg occurs
     * @param validBlockHeightPrecondition Height of the block with hash validBlockHash
     * @param messageCount Claimed number of messages emitted in the assertion
     * @param logCount Claimed number of logs emitted in the assertion
     * @param prevChildType The type of node that this assertion builds on top of
     * @param numSteps Argument specifying the number of steps execuited
     * @param numArbGas Claimed amount of ArbGas used in the assertion
     * @param stakerProof Node graph proof that the asserter is on or can move to the leaf this assertion builds on
     */
    function makeAssertion(
        bytes32[8] calldata fields,
        uint256[5] calldata fields2,
        bytes32 validBlockHashPrecondition,
        uint256 validBlockHeightPrecondition,
        uint64 messageCount,
        uint64 logCount,
        uint32 prevChildType,
        uint64 numSteps,
        uint64 numArbGas,
        bytes32[] calldata stakerProof
    ) external {
        require(
            blockhash(validBlockHeightPrecondition) == validBlockHashPrecondition,
            "invalid known block"
        );
        NodeGraphUtils.AssertionData memory assertData = NodeGraphUtils.makeAssertion(
            fields,
            fields2,
            prevChildType,
            numSteps,
            numArbGas,
            messageCount,
            logCount
        );

        (bytes32 inboxValue, uint256 inboxCount) = globalInbox.getInbox(address(this));

        (bytes32 prevLeaf, bytes32 newValid) = makeAssertion(assertData, inboxValue, inboxCount);

        bytes32 stakerLocation = getStakerLocation(msg.sender);
        require(
            RollupUtils.calculateLeafFromPath(stakerLocation, stakerProof) == prevLeaf,
            MAKE_STAKER_PROOF
        );
        updateStakerLocation(msg.sender, newValid);
    }

    modifier onlyOwner() {
        require(msg.sender == owner, ONLY_OWNER);
        _;
    }

    function ownerShutdown() external onlyOwner {
        safeSelfDestruct(msg.sender);
    }

    function _recoverStakeConfirmed(address payable stakerAddress, bytes32[] memory proof) private {
        bytes32 stakerLocation = getStakerLocation(msg.sender);
        require(
            RollupUtils.calculateLeafFromPath(stakerLocation, proof) == latestConfirmed(),
            RECOV_PATH_PROOF
        );
        refundStaker(stakerAddress);
    }

    /**
     * @notice Confirm an arbitrary number of pending assertions
     * @dev Confirming multiple assertions at once has the advantage that we can skip most checks for all nodes but the final one
     * @dev TODO: An adversary could potentially make this method too expensive to call by creating a large number of validators. This issue could be avoided by providing an interactive confirmation challenge along with this synchronous one.\
     * @param initalProtoStateHash Hash of the protocol state of the predecessor to the first node confirmed
     * @param branches For each node being confirmed, this is the type of node it was
     * @param deadlineTicks For each node being confirmed, this is the deadline for validators challenging it
     * @param challengeNodeData For the invalid nodes being confirmed, this is the hash of the challenge specific data in that node
     * @param logsAcc For the valid nodes being confirmed, this is the claim about what logs were emitted
     * @param vmProtoStateHashes For the valid nodes being confirmed, this is the state after that node is confirmed
     * @param messageCounts The number of messages in each valid assertion confirmed
     * @param messages All the messages output by the confirmed assertions marshaled in order from oldest to newest
     * @param stakerAddresses The list of all currently staked validators
     * @param stakerProofs A concatenated list of proofs for each validator showing that they agree with the given node
     * @param stakerProofOffsets A list of indexes into stakerProofs to break it into pieces for each validator
     */
    function confirm(
        bytes32 initalProtoStateHash,
        uint256 beforeSendCount,
        uint256[] memory branches,
        uint256[] memory deadlineTicks,
        bytes32[] memory challengeNodeData,
        bytes32[] memory logsAcc,
        bytes32[] memory vmProtoStateHashes,
        uint256[] memory messageCounts,
        bytes memory messages,
        address[] memory stakerAddresses,
        bytes32[] memory stakerProofs,
        uint256[] memory stakerProofOffsets
    ) public {
        return
            _confirm(
                RollupUtils.ConfirmData(
                    initalProtoStateHash,
                    beforeSendCount,
                    branches,
                    deadlineTicks,
                    challengeNodeData,
                    logsAcc,
                    vmProtoStateHashes,
                    messageCounts,
                    messages
                ),
                stakerAddresses,
                stakerProofs,
                stakerProofOffsets
            );
    }

    function _confirm(
        RollupUtils.ConfirmData memory data,
        address[] memory stakerAddresses,
        bytes32[] memory stakerProofs,
        uint256[] memory stakerProofOffsets
    ) private {
        uint256 totalNodeCount = data.branches.length;
        // If last node is after deadline, then all nodes are
        require(
            RollupTime.blocksToTicks(block.number) >= data.deadlineTicks[totalNodeCount - 1],
            CONF_TIME
        );

        (bytes32[] memory validNodeHashes, RollupUtils.NodeData memory finalNodeData) = RollupUtils
            .confirm(data, latestConfirmed());

        uint256 validNodeCount = validNodeHashes.length;
        for (uint256 i = 0; i < validNodeCount; i++) {
            emit ConfirmedValidAssertion(validNodeHashes[i]);
        }
        uint256 activeCount = checkAlignedStakers(
            finalNodeData.nodeHash,
            data.deadlineTicks[totalNodeCount - 1],
            stakerAddresses,
            stakerProofs,
            stakerProofOffsets
        );
        require(activeCount > 0, CONF_HAS_STAKER);

        confirmNode(finalNodeData.nodeHash);

        // Send all messages is a single batch
        globalInbox.sendMessages(
            data.messages,
            data.initialSendCount,
            finalNodeData.beforeSendCount
        );

        if (validNodeCount > 0) {
            emit ConfirmedAssertion(data.logsAcc);
        }
    }
}

File 39 of 58 : NodeGraph.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./RollupUtils.sol";
import "./NodeGraphUtils.sol";
import "./VM.sol";

import "../arch/Value.sol";

import "../libraries/RollupTime.sol";

contract NodeGraph {
    using SafeMath for uint256;
    using Hashing for Value.Data;

    // invalid leaf
    string private constant MAKE_LEAF = "MAKE_LEAF";
    // Can only disputable assert if machine is not errored or halted
    string private constant MAKE_RUN = "MAKE_RUN";
    // Tried to execute too many steps
    string private constant MAKE_STEP = "MAKE_STEP";
    // Tried to import more messages than exist in ethe inbox
    string private constant MAKE_MESSAGE_CNT = "MAKE_MESSAGE_CNT";

    string private constant PRUNE_LEAF = "PRUNE_LEAF";
    string private constant PRUNE_PROOFLEN = "PRUNE_PROOFLEN";
    string private constant PRUNE_CONFLICT = "PRUNE_CONFLICT";

    // Fields
    //  prevLeaf
    //  inboxValue
    //  afterMachineHash
    //  afterInboxHash
    //  messagesAccHash
    //  logsAccHash
    //  validNodeHash

    event RollupAsserted(
        bytes32[7] fields,
        uint256 inboxCount,
        uint256 importedMessageCount,
        uint64 numArbGas,
        uint64 numSteps,
        uint256 beforeMessageCount,
        uint64 messageCount,
        uint256 beforeLogCount,
        uint64 logCount
    );

    event RollupConfirmed(bytes32 nodeHash);

    event RollupPruned(bytes32 leaf);

    VM.Params public vmParams;
    mapping(bytes32 => bool) private leaves;
    bytes32 private latestConfirmedPriv;

    /**
     * @notice Prune an arbitrary number of leaves from the node graph
     * @dev Pruning leaves frees up blockchain storage, but is otherwise unnecessary
     * @notice See _pruneLeaf for parameter documentation
     */
    function pruneLeaves(
        bytes32[] calldata fromNodes,
        bytes32[] calldata leafProofs,
        uint256[] calldata leafProofLengths,
        bytes32[] calldata latestConfProofs,
        uint256[] calldata latestConfirmedProofLengths
    ) external {
        uint256 pruneCount = fromNodes.length;

        require(
            leafProofLengths.length == pruneCount &&
                latestConfirmedProofLengths.length == pruneCount,
            "input length mistmatch"
        );
        uint256 prevLeafOffset = 0;
        uint256 prevConfOffset = 0;

        for (uint256 i = 0; i < pruneCount; i++) {
            (prevLeafOffset, prevConfOffset) = _pruneLeaf(
                fromNodes[i],
                latestConfirmedProofLengths[i],
                leafProofLengths[i],
                leafProofs,
                latestConfProofs,
                prevLeafOffset,
                prevConfOffset
            );
        }
    }

    function latestConfirmed() public view returns (bytes32) {
        return latestConfirmedPriv;
    }

    function isValidLeaf(bytes32 leaf) public view returns (bool) {
        return leaves[leaf];
    }

    function init(
        bytes32 _vmState,
        uint128 _gracePeriodTicks,
        uint128 _arbGasSpeedLimitPerTick,
        uint64 _maxExecutionSteps
    ) internal {
        // VM protocol state
        bytes32 vmProtoStateHash = RollupUtils.protoStateHash(_vmState, 0, 0, 0, 0);
        bytes32 initialNode = RollupUtils.childNodeHash(0, 0, 0, 0, vmProtoStateHash);
        latestConfirmedPriv = initialNode;
        leaves[initialNode] = true;

        // VM parameters
        vmParams.gracePeriodTicks = _gracePeriodTicks;
        vmParams.arbGasSpeedLimitPerTick = _arbGasSpeedLimitPerTick;
        vmParams.maxExecutionSteps = _maxExecutionSteps;
    }

    function makeAssertion(
        NodeGraphUtils.AssertionData memory data,
        bytes32 inboxValue,
        uint256 inboxCount
    ) internal returns (bytes32, bytes32) {
        (bytes32 prevLeaf, bytes32 vmProtoHashBefore) = NodeGraphUtils.computePrevLeaf(data);
        require(isValidLeaf(prevLeaf), MAKE_LEAF);
        _verifyAssertionData(data);

        require(
            data.importedMessageCount <= inboxCount.sub(data.beforeInboxCount),
            MAKE_MESSAGE_CNT
        );

        bytes32 validLeaf = _initializeAssertionLeaves(
            data,
            prevLeaf,
            vmProtoHashBefore,
            inboxValue,
            inboxCount
        );

        delete leaves[prevLeaf];

        emitAssertedEvent(data, prevLeaf, validLeaf, inboxValue, inboxCount);
        return (prevLeaf, validLeaf);
    }

    function confirmNode(bytes32 to) internal {
        latestConfirmedPriv = to;
        emit RollupConfirmed(to);
    }

    function emitAssertedEvent(
        NodeGraphUtils.AssertionData memory data,
        bytes32 prevLeaf,
        bytes32 validLeaf,
        bytes32 inboxValue,
        uint256 inboxCount
    ) private {
        emit RollupAsserted(
            [
                prevLeaf,
                inboxValue,
                data.assertion.afterMachineHash,
                data.assertion.afterInboxHash,
                data.assertion.lastMessageHash,
                data.assertion.lastLogHash,
                validLeaf
            ],
            inboxCount,
            data.importedMessageCount,
            data.assertion.numArbGas,
            data.assertion.numSteps,
            data.beforeMessageCount,
            data.assertion.messageCount,
            data.beforeLogCount,
            data.assertion.logCount
        );
    }

    /**
     * @notice Prune a leaf from the node graph if it conflicts with the latest confirmed node
     * @dev Pruning leaves frees up blockchain storage, but is otherwise unnecessary
     * @param from The node where the leaf we want to prune diverged from the correct path
     * @param latestConfirmedProofLength Length of the proof showing the from is an ancestor of latest confirmed
     * @param leafProofLength Length of the proof showing the the pruned leaf conflicts with the from node
     * @param leafProofs Array containing the leaf conflict proof
     * @param latestConfProofs Array containing the leaf confirmed proof
     * @param prevLeafOffset Index into the leaf proof
     * @param prevConfOffset Index into the confirm proof
     */
    function _pruneLeaf(
        bytes32 from,
        uint256 latestConfirmedProofLength,
        uint256 leafProofLength,
        bytes32[] memory leafProofs,
        bytes32[] memory latestConfProofs,
        uint256 prevLeafOffset,
        uint256 prevConfOffset
    ) private returns (uint256, uint256) {
        require(leafProofLength > 0 && latestConfirmedProofLength > 0, PRUNE_PROOFLEN);
        uint256 nextLeafOffset = prevLeafOffset + leafProofLength;
        uint256 nextConfOffset = prevConfOffset + latestConfirmedProofLength;

        // If the function call was produced valid at any point, either all these checks will pass or all will fail
        bool isValidNode = RollupUtils.calculateLeafFromPath(
            from,
            latestConfProofs,
            prevConfOffset,
            nextConfOffset
        ) == latestConfirmed();

        require(
            isValidNode && leafProofs[prevLeafOffset] != latestConfProofs[prevConfOffset],
            PRUNE_CONFLICT
        );

        bytes32 leaf = RollupUtils.calculateLeafFromPath(
            from,
            leafProofs,
            prevLeafOffset,
            nextLeafOffset
        );
        if (isValidLeaf(leaf)) {
            delete leaves[leaf];
            emit RollupPruned(leaf);
        }

        return (nextLeafOffset, nextConfOffset);
    }

    function _verifyAssertionData(NodeGraphUtils.AssertionData memory data) private view {
        require(
            !VM.isErrored(data.assertion.beforeMachineHash) &&
                !VM.isHalted(data.assertion.beforeMachineHash),
            MAKE_RUN
        );
        require(data.assertion.numSteps <= vmParams.maxExecutionSteps, MAKE_STEP);
    }

    function _initializeAssertionLeaves(
        NodeGraphUtils.AssertionData memory data,
        bytes32 prevLeaf,
        bytes32 vmProtoHashBefore,
        bytes32 inboxValue,
        uint256 inboxCount
    ) private returns (bytes32) {
        (uint256 checkTimeTicks, uint256 deadlineTicks) = NodeGraphUtils.getTimeData(
            vmParams,
            data,
            block.number
        );

        bytes32 invalidInboxLeaf = NodeGraphUtils.generateInvalidInboxTopLeaf(
            data,
            prevLeaf,
            deadlineTicks,
            inboxValue,
            inboxCount,
            vmProtoHashBefore,
            vmParams.gracePeriodTicks
        );
        bytes32 invalidExecLeaf = NodeGraphUtils.generateInvalidExecutionLeaf(
            data,
            prevLeaf,
            deadlineTicks,
            vmProtoHashBefore,
            vmParams.gracePeriodTicks,
            checkTimeTicks
        );
        bytes32 validLeaf = NodeGraphUtils.generateValidLeaf(data, prevLeaf, deadlineTicks);

        leaves[invalidInboxLeaf] = true;
        leaves[invalidExecLeaf] = true;
        leaves[validLeaf] = true;

        return validLeaf;
    }
}

File 40 of 58 : RollupUtils.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "../arch/Marshaling.sol";
import "../libraries/RollupTime.sol";

import "../challenge/ChallengeUtils.sol";

library RollupUtils {
    using Hashing for Value.Data;

    string private constant CONF_INP = "CONF_INP";

    struct ConfirmData {
        bytes32 initalProtoStateHash;
        uint256 initialSendCount;
        uint256[] branches;
        uint256[] deadlineTicks;
        bytes32[] challengeNodeData;
        bytes32[] logsAcc;
        bytes32[] vmProtoStateHashes;
        uint256[] messageCounts;
        bytes messages;
    }

    struct NodeData {
        uint256 validNum;
        uint256 invalidNum;
        uint256 messagesOffset;
        bytes32 vmProtoStateHash;
        uint256 beforeSendCount;
        bytes32 nodeHash;
    }

    function getInitialNodeData(
        bytes32 vmProtoStateHash,
        uint256 beforeSendCount,
        bytes32 confNode
    ) private pure returns (NodeData memory) {
        return NodeData(0, 0, 0, vmProtoStateHash, beforeSendCount, confNode);
    }

    function confirm(ConfirmData memory data, bytes32 confNode)
        internal
        pure
        returns (bytes32[] memory validNodeHashes, NodeData memory)
    {
        verifyDataLength(data);

        uint256 nodeCount = data.branches.length;
        uint256 validNodeCount = data.messageCounts.length;
        validNodeHashes = new bytes32[](validNodeCount);
        NodeData memory currentNodeData = getInitialNodeData(
            data.initalProtoStateHash,
            data.initialSendCount,
            confNode
        );

        for (uint256 nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) {
            bool isValidChildType = processNode(data, currentNodeData, nodeIndex);

            if (isValidChildType) {
                validNodeHashes[currentNodeData.validNum - 1] = currentNodeData.nodeHash;
            }
        }
        return (validNodeHashes, currentNodeData);
    }

    function processNode(
        ConfirmData memory data,
        NodeData memory nodeData,
        uint256 nodeIndex
    ) private pure returns (bool) {
        uint256 branchType = data.branches[nodeIndex];
        bool isValidChildType = (branchType == ChallengeUtils.getValidChildType());
        bytes32 nodeDataHash;

        if (isValidChildType) {
            (
                nodeData.beforeSendCount,
                nodeData.messagesOffset,
                nodeDataHash,
                nodeData.vmProtoStateHash
            ) = processValidNode(
                data,
                nodeData.validNum,
                nodeData.beforeSendCount,
                nodeData.messagesOffset
            );
            nodeData.validNum++;
        } else {
            nodeDataHash = data.challengeNodeData[nodeData.invalidNum];
            nodeData.invalidNum++;
        }

        nodeData.nodeHash = childNodeHash(
            nodeData.nodeHash,
            data.deadlineTicks[nodeIndex],
            nodeDataHash,
            branchType,
            nodeData.vmProtoStateHash
        );

        return isValidChildType;
    }

    function processValidNode(
        ConfirmData memory data,
        uint256 validNum,
        uint256 beforeSendCount,
        uint256 startOffset
    )
        internal
        pure
        returns (
            uint256,
            uint256,
            bytes32,
            bytes32
        )
    {
        uint256 sendCount = data.messageCounts[validNum];
        (bytes32 lastMsgHash, uint256 messagesOffset) = generateLastMessageHash(
            data.messages,
            startOffset,
            sendCount
        );
        bytes32 nodeDataHash = validDataHash(beforeSendCount, lastMsgHash, data.logsAcc[validNum]);
        bytes32 vmProtoStateHash = data.vmProtoStateHashes[validNum];
        return (beforeSendCount + sendCount, messagesOffset, nodeDataHash, vmProtoStateHash);
    }

    function generateLastMessageHash(
        bytes memory messages,
        uint256 startOffset,
        uint256 count
    ) internal pure returns (bytes32, uint256) {
        bytes32 hashVal = 0x00;
        Value.Data memory messageVal;
        uint256 offset = startOffset;
        for (uint256 i = 0; i < count; i++) {
            (offset, messageVal) = Marshaling.deserialize(messages, offset);
            hashVal = keccak256(abi.encodePacked(hashVal, messageVal.hash()));
        }
        return (hashVal, offset);
    }

    function verifyDataLength(RollupUtils.ConfirmData memory data) private pure {
        uint256 nodeCount = data.branches.length;
        uint256 validNodeCount = data.messageCounts.length;
        require(data.vmProtoStateHashes.length == validNodeCount, CONF_INP);
        require(data.logsAcc.length == validNodeCount, CONF_INP);
        require(data.deadlineTicks.length == nodeCount, CONF_INP);
        require(data.challengeNodeData.length == nodeCount - validNodeCount, CONF_INP);
    }

    function protoStateHash(
        bytes32 machineHash,
        bytes32 inboxTop,
        uint256 inboxCount,
        uint256 messageCount,
        uint256 logCount
    ) internal pure returns (bytes32) {
        return
            keccak256(abi.encodePacked(machineHash, inboxTop, inboxCount, messageCount, logCount));
    }

    function validDataHash(
        uint256 beforeSendCount,
        bytes32 messagesAcc,
        bytes32 logsAcc
    ) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(beforeSendCount, messagesAcc, logsAcc));
    }

    function challengeDataHash(bytes32 challenge, uint256 challengePeriod)
        internal
        pure
        returns (bytes32)
    {
        return keccak256(abi.encodePacked(challenge, challengePeriod));
    }

    function childNodeHash(
        bytes32 prevNodeHash,
        uint256 deadlineTicks,
        bytes32 nodeDataHash,
        uint256 childType,
        bytes32 vmProtoStateHash
    ) internal pure returns (bytes32) {
        return
            keccak256(
                abi.encodePacked(
                    prevNodeHash,
                    keccak256(
                        abi.encodePacked(vmProtoStateHash, deadlineTicks, nodeDataHash, childType)
                    )
                )
            );
    }

    function calculateLeafFromPath(bytes32 from, bytes32[] memory proof)
        internal
        pure
        returns (bytes32)
    {
        return calculateLeafFromPath(from, proof, 0, proof.length);
    }

    function calculateLeafFromPath(
        bytes32 from,
        bytes32[] memory proof,
        uint256 start,
        uint256 end
    ) internal pure returns (bytes32) {
        bytes32 node = from;
        for (uint256 i = start; i < end; i++) {
            node = keccak256(abi.encodePacked(node, proof[i]));
        }
        return node;
    }
}

File 41 of 58 : NodeGraphUtils.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./RollupUtils.sol";
import "../libraries/RollupTime.sol";
import "../challenge/ChallengeUtils.sol";
import "./VM.sol";

library NodeGraphUtils {
    using Hashing for Value.Data;

    struct AssertionData {
        uint256 beforeInboxCount;
        bytes32 prevPrevLeafHash;
        uint256 prevDeadlineTicks;
        bytes32 prevDataHash;
        uint32 prevChildType;
        uint256 importedMessageCount;
        uint256 beforeMessageCount;
        uint256 beforeLogCount;
        ChallengeUtils.ExecutionAssertion assertion;
    }

    function makeAssertion(
        bytes32[8] memory fields,
        uint256[5] memory fields2,
        uint32 prevChildType,
        uint64 numSteps,
        uint64 numArbGas,
        uint64 messageCount,
        uint64 logCount
    ) internal pure returns (AssertionData memory) {
        ChallengeUtils.ExecutionAssertion memory assertion = ChallengeUtils.ExecutionAssertion(
            numSteps,
            numArbGas,
            fields[0],
            fields[1],
            fields[2],
            fields[3],
            0,
            fields[4],
            messageCount,
            0,
            fields[5],
            logCount
        );
        return
            AssertionData(
                fields2[0],
                fields[6],
                fields2[1],
                fields[7],
                prevChildType,
                fields2[2],
                fields2[3],
                fields2[4],
                assertion
            );
    }

    function computePrevLeaf(AssertionData memory data)
        internal
        pure
        returns (bytes32 prevLeaf, bytes32 vmProtoHashBefore)
    {
        vmProtoHashBefore = RollupUtils.protoStateHash(
            data.assertion.beforeMachineHash,
            data.assertion.beforeInboxHash,
            data.beforeInboxCount,
            data.beforeMessageCount,
            data.beforeLogCount
        );
        prevLeaf = RollupUtils.childNodeHash(
            data.prevPrevLeafHash,
            data.prevDeadlineTicks,
            data.prevDataHash,
            data.prevChildType,
            vmProtoHashBefore
        );
    }

    function getTimeData(
        VM.Params memory vmParams,
        AssertionData memory data,
        uint256 blockNum
    ) internal pure returns (uint256, uint256) {
        uint256 checkTimeTicks = data.assertion.numArbGas / vmParams.arbGasSpeedLimitPerTick;
        uint256 deadlineTicks = RollupTime.blocksToTicks(blockNum) + vmParams.gracePeriodTicks;
        if (deadlineTicks < data.prevDeadlineTicks) {
            deadlineTicks = data.prevDeadlineTicks;
        }
        deadlineTicks += checkTimeTicks;

        return (checkTimeTicks, deadlineTicks);
    }

    function generateInvalidInboxTopLeaf(
        AssertionData memory data,
        bytes32 prevLeaf,
        uint256 deadlineTicks,
        bytes32 inboxValue,
        uint256 inboxCount,
        bytes32 vmProtoHashBefore,
        uint256 gracePeriodTicks
    ) internal pure returns (bytes32) {
        bytes32 challengeHash = ChallengeUtils.inboxTopHash(
            data.assertion.afterInboxHash,
            inboxValue,
            inboxCount - (data.beforeInboxCount + data.importedMessageCount)
        );
        return
            RollupUtils.childNodeHash(
                prevLeaf,
                deadlineTicks,
                RollupUtils.challengeDataHash(
                    challengeHash,
                    gracePeriodTicks + RollupTime.blocksToTicks(1)
                ),
                ChallengeUtils.getInvalidInboxType(),
                vmProtoHashBefore
            );
    }

    function generateInvalidExecutionLeaf(
        AssertionData memory data,
        bytes32 prevLeaf,
        uint256 deadlineTicks,
        bytes32 vmProtoHashBefore,
        uint256 gracePeriodTicks,
        uint256 checkTimeTicks
    ) internal pure returns (bytes32 leaf) {
        return
            RollupUtils.childNodeHash(
                prevLeaf,
                deadlineTicks,
                RollupUtils.challengeDataHash(
                    ChallengeUtils.hash(data.assertion),
                    gracePeriodTicks + checkTimeTicks
                ),
                ChallengeUtils.getInvalidExType(),
                vmProtoHashBefore
            );
    }

    function generateValidLeaf(
        AssertionData memory data,
        bytes32 prevLeaf,
        uint256 deadlineTicks
    ) internal pure returns (bytes32) {
        return
            RollupUtils.childNodeHash(
                prevLeaf,
                deadlineTicks,
                RollupUtils.validDataHash(
                    data.beforeMessageCount,
                    data.assertion.lastMessageHash,
                    data.assertion.lastLogHash
                ),
                ChallengeUtils.getValidChildType(),
                RollupUtils.protoStateHash(
                    data.assertion.afterMachineHash,
                    data.assertion.afterInboxHash,
                    data.beforeInboxCount + data.importedMessageCount,
                    data.beforeMessageCount + data.assertion.messageCount,
                    data.beforeLogCount + data.assertion.logCount
                )
            );
    }
}

File 42 of 58 : VM.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "../arch/Value.sol";
import "../libraries/SafeMath.sol";

library VM {
    using SafeMath for uint256;

    bytes32 private constant MACHINE_HALT_HASH = bytes32(0);
    bytes32 private constant MACHINE_ERROR_HASH = bytes32(uint256(1));

    struct Params {
        // these are defined just once for each vM
        uint256 gracePeriodTicks;
        uint256 arbGasSpeedLimitPerTick;
        uint64 maxExecutionSteps;
    }

    function isErrored(bytes32 vmStateHash) internal pure returns (bool) {
        return vmStateHash == MACHINE_ERROR_HASH;
    }

    function isHalted(bytes32 vmStateHash) internal pure returns (bool) {
        return vmStateHash == MACHINE_HALT_HASH;
    }
}

File 43 of 58 : Staking.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "./RollupUtils.sol";
import "../libraries/RollupTime.sol";

import "../challenge/ChallengeUtils.sol";
import "../challenge/IChallengeFactory.sol";

import "../interfaces/IERC20.sol";

contract Staking {
    // VM already initialized"
    string private constant INIT_TWICE = "INIT_TWICE";
    // Challenge factory must be nonzero
    string private constant INIT_NONZERO = "INIT_NONZERO";

    // Invalid staker
    string private constant INV_STAKER = "INV_STAKER";

    // must supply stake value
    string private constant STK_AMT = "STK_AMT";
    // Staker already exists
    string private constant TRANSFER_FAILED = "TRANSFER_FAILED";
    string private constant ALRDY_STAKED = "ALRDY_STAKED";

    // Challenge can only be resolved by spawned contract
    string private constant RES_CHAL_SENDER = "RES_CHAL_SENDER";

    // staker1 staked after deadline
    string private constant STK1_DEADLINE = "STK1_DEADLINE";
    // staker2 staked after deadline
    string private constant STK2_DEADLINE = "STK2_DEADLINE";
    // staker1 already in a challenge
    string private constant STK1_IN_CHAL = "STK1_IN_CHAL";
    // staker2 already in a challenge
    string private constant STK2_IN_CHAL = "STK2_IN_CHAL";
    // Child types must be ordered
    string private constant TYPE_ORDER = "TYPE_ORDER";
    // Invalid child type
    string private constant INVLD_CHLD_TYPE = "INVLD_CHLD_TYPE";
    // Challenge asserter proof
    string private constant ASSERT_PROOF = "ASSERT_PROOF";
    // Challenge challenger proof
    string private constant CHAL_PROOF = "CHAL_PROOF";

    // must include proof for all stakers
    string private constant CHCK_COUNT = "CHCK_COUNT";
    // Stakers must be ordered
    string private constant CHCK_ORDER = "CHCK_ORDER";
    // at least one active staker disagrees
    string private constant CHCK_STAKER_PROOF = "CHCK_STAKER_PROOF";
    string private constant CHCK_OFFSETS = "CHCK_OFFSETS";

    uint256 private constant MAX_CHILD_TYPE = 3;

    IChallengeFactory public challengeFactory;

    struct Staker {
        bytes32 location;
        uint128 creationTimeBlocks;
        bool inChallenge;
    }

    uint128 private stakeRequirement;
    address private stakeToken;
    mapping(address => Staker) private stakers;
    uint256 private stakerCount;
    mapping(address => bool) private challenges;
    mapping(address => uint256) withdrawnStakes;

    event RollupStakeCreated(address staker, bytes32 nodeHash);

    event RollupStakeRefunded(address staker);

    event RollupStakeMoved(address staker, bytes32 toNodeHash);

    event RollupChallengeStarted(
        address asserter,
        address challenger,
        uint256 challengeType,
        address challengeContract
    );

    event RollupChallengeCompleted(address challengeContract, address winner, address loser);

    function getStakeRequired() external view returns (uint128) {
        return stakeRequirement;
    }

    function getStakeToken() external view returns (address) {
        return stakeToken;
    }

    function isStaked(address _stakerAddress) external view returns (bool) {
        return stakers[_stakerAddress].location != 0x00;
    }

    function getWithdrawnStake(address payable _staker) external {
        uint256 amount = withdrawnStakes[_staker];
        if (amount == 0) {
            return;
        }
        if (stakeToken == address(0)) {
            _staker.transfer(amount);
        } else {
            require(IERC20(stakeToken).transfer(_staker, amount), TRANSFER_FAILED);
        }
    }

    /**
     * @notice Update stakers with the result of a challenge that has ended. The winner received half of the losers deposit and the rest is burned
     * @dev Currently the rollup contract keeps the burned funds. These are frozen since the rollup contract has no way to withdraw them
     * @dev This function can only be called by a challenge contract launched by this contract. Because of this we don't require any other input validator
     * @dev Consider using CREATE2 to eliminate the need to remember what challenges we've launched
     * @param winner The address of the staker who won the challenge
     * @param loser The address of the staker who lost the challenge
     */
    function resolveChallenge(address payable winner, address loser) external {
        require(challenges[msg.sender], RES_CHAL_SENDER);
        delete challenges[msg.sender];

        Staker storage winningStaker = getValidStaker(address(winner));
        withdrawnStakes[winner] += stakeRequirement / 2;
        winningStaker.inChallenge = false;
        deleteStaker(loser);

        emit RollupChallengeCompleted(msg.sender, address(winner), loser);
    }

    /**
     * @notice Initiate a challenge between two validators staked on this rollup chain.
     * @dev Anyone can force two conflicted validators to engage in a challenge
     * @dev The challenge will occur on the oldest node that the two validators disagree about
     * @param asserterAddress The staker who claimed a given node was valid
     * @param challengerAddress The address who claimed that the same node was invalid
     * @param prevNode The node which is the parent of the two conflicting nodes the asserter and challenger are on
     * @param deadlineTicks The deadline to challenge the asserter's node
     * @param stakerNodeTypes The type of nodes that the asserter and challenger are staked on
     * @param vmProtoHashes The protocol states claimed by each validator
     * @param asserterProof A proof that the asserter actually staked that the claimed node was correct
     * @param challengerProof A proof that the challenger actually staked that hte claimed node was invalid
     * @param asserterNodeHash Type specific data in the asserter's node
     * @param challengerDataHash Information from the challenger's node about the claim the asserter is disputing
     * @param challengerPeriodTicks Amount of time dedicated to rounds of the challenge created
     */
    function startChallenge(
        address payable asserterAddress,
        address payable challengerAddress,
        bytes32 prevNode,
        uint256 deadlineTicks,
        uint256[2] memory stakerNodeTypes, // [asserterNodeType, challengerNodeType]
        bytes32[2] memory vmProtoHashes, // [asserterVMProtoHash, challengerVMProtoHash]
        bytes32[] memory asserterProof,
        bytes32[] memory challengerProof,
        bytes32 asserterNodeHash,
        bytes32 challengerDataHash,
        uint128 challengerPeriodTicks
    ) public {
        Staker storage asserter = getValidStaker(asserterAddress);
        Staker storage challenger = getValidStaker(challengerAddress);

        require(
            RollupTime.blocksToTicks(asserter.creationTimeBlocks) < deadlineTicks,
            STK1_DEADLINE
        );
        require(
            RollupTime.blocksToTicks(challenger.creationTimeBlocks) < deadlineTicks,
            STK2_DEADLINE
        );
        require(!asserter.inChallenge, STK1_IN_CHAL);
        require(!challenger.inChallenge, STK2_IN_CHAL);
        require(stakerNodeTypes[0] > stakerNodeTypes[1], TYPE_ORDER);
        require(
            RollupUtils.calculateLeafFromPath(
                RollupUtils.childNodeHash(
                    prevNode,
                    deadlineTicks,
                    asserterNodeHash,
                    stakerNodeTypes[0],
                    vmProtoHashes[0]
                ),
                asserterProof
            ) == asserter.location,
            ASSERT_PROOF
        );
        require(
            RollupUtils.calculateLeafFromPath(
                RollupUtils.childNodeHash(
                    prevNode,
                    deadlineTicks,
                    RollupUtils.challengeDataHash(challengerDataHash, challengerPeriodTicks),
                    stakerNodeTypes[1],
                    vmProtoHashes[1]
                ),
                challengerProof
            ) == challenger.location,
            CHAL_PROOF
        );

        asserter.inChallenge = true;
        challenger.inChallenge = true;

        createChallenge(
            asserterAddress,
            challengerAddress,
            challengerPeriodTicks,
            challengerDataHash,
            stakerNodeTypes[1]
        );
    }

    function createChallenge(
        address payable asserterAddress,
        address payable challengerAddress,
        uint128 challengerPeriodTicks,
        bytes32 challengerDataHash,
        uint256 stakerNodeType
    ) internal {
        address newChallengeAddr = challengeFactory.createChallenge(
            asserterAddress,
            challengerAddress,
            challengerPeriodTicks,
            challengerDataHash,
            stakerNodeType
        );

        challenges[newChallengeAddr] = true;

        emit RollupChallengeStarted(
            asserterAddress,
            challengerAddress,
            stakerNodeType,
            newChallengeAddr
        );
    }

    function init(
        uint128 _stakeRequirement,
        address _stakeToken,
        address _challengeFactoryAddress
    ) internal {
        require(address(challengeFactory) == address(0), INIT_TWICE);
        require(_challengeFactoryAddress != address(0), INIT_NONZERO);

        challengeFactory = IChallengeFactory(_challengeFactoryAddress);

        // VM parameters
        stakeRequirement = _stakeRequirement;
        stakeToken = _stakeToken;
    }

    function getStakerLocation(address _stakerAddress) internal view returns (bytes32) {
        bytes32 location = stakers[_stakerAddress].location;
        require(location != 0x00, INV_STAKER);
        return location;
    }

    function createStake(bytes32 location) internal {
        if (stakeToken == address(0)) {
            require(msg.value == stakeRequirement, STK_AMT);
        } else {
            require(msg.value == 0, STK_AMT);
            require(
                IERC20(stakeToken).transferFrom(msg.sender, address(this), stakeRequirement),
                TRANSFER_FAILED
            );
        }

        require(stakers[msg.sender].location == 0x00, ALRDY_STAKED);
        stakers[msg.sender] = Staker(location, uint128(block.number), false);
        stakerCount++;

        emit RollupStakeCreated(msg.sender, location);
    }

    function updateStakerLocation(address _stakerAddress, bytes32 _location) internal {
        stakers[_stakerAddress].location = _location;
        emit RollupStakeMoved(_stakerAddress, _location);
    }

    function refundStaker(address payable _stakerAddress) internal {
        deleteStaker(_stakerAddress);
        withdrawnStakes[_stakerAddress] += stakeRequirement;

        emit RollupStakeRefunded(address(_stakerAddress));
    }

    function getValidStaker(address _stakerAddress) private view returns (Staker storage) {
        Staker storage staker = stakers[_stakerAddress];
        require(staker.location != 0x00, INV_STAKER);
        return staker;
    }

    function deleteStaker(address _stakerAddress) private {
        delete stakers[_stakerAddress];
        stakerCount--;
    }

    function checkAlignedStakers(
        bytes32 node,
        uint256 deadlineTicks,
        address[] memory stakerAddresses,
        bytes32[] memory stakerProofs,
        uint256[] memory stakerProofOffsets
    ) internal view returns (uint256) {
        uint256 _stakerCount = stakerAddresses.length;
        require(_stakerCount == stakerCount, CHCK_COUNT);
        require(_stakerCount + 1 == stakerProofOffsets.length, CHCK_OFFSETS);

        bytes20 prevStaker = 0x00;
        uint256 activeCount = 0;
        bool isActive = false;

        for (uint256 index = 0; index < _stakerCount; index++) {
            address currentStaker = stakerAddresses[index];

            isActive = _verifyAlignedStaker(
                node,
                stakerProofs,
                deadlineTicks,
                currentStaker,
                prevStaker,
                stakerProofOffsets[index],
                stakerProofOffsets[index + 1]
            );

            if (isActive) {
                activeCount++;
            }

            prevStaker = bytes20(currentStaker);
        }
        return activeCount;
    }

    function _verifyAlignedStaker(
        bytes32 node,
        bytes32[] memory stakerProofs,
        uint256 deadlineTicks,
        address stakerAddress,
        bytes20 prevStaker,
        uint256 proofStart,
        uint256 proofEnd
    ) private view returns (bool) {
        require(bytes20(stakerAddress) > prevStaker, CHCK_ORDER);
        Staker storage staker = getValidStaker(stakerAddress);
        bool isActive = RollupTime.blocksToTicks(staker.creationTimeBlocks) < deadlineTicks;

        if (isActive) {
            require(
                RollupUtils.calculateLeafFromPath(node, stakerProofs, proofStart, proofEnd) ==
                    staker.location,
                CHCK_STAKER_PROOF
            );
        }

        return isActive;
    }
}

File 44 of 58 : BuddyERC20.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "arbos-contracts/contracts/ArbERC20.sol";
import "../inbox/IGlobalInbox.sol";
import "../interfaces/IPairedErc20.sol";
import "@openzeppelin/contracts/ownership/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";

contract BaseDetails is ERC20Detailed {
    constructor() public ERC20Detailed("Token Buddy", "TB", 18) {}
}

contract ArbBuddyERC20 is ArbERC20, BaseDetails {}

contract EthBuddyERC20 is IPairedErc20, Ownable, ERC20, BaseDetails {
    address public inbox;

    constructor(address _globalInbox) public {
        inbox = _globalInbox;
        _mint(msg.sender, 1000000000000);
    }

    function connectToChain(address _chain) public onlyOwner {
        IGlobalInbox inboxCon = IGlobalInbox(inbox);
        inboxCon.deployL2ContractPair(_chain, 10000000000, 0, 0, type(ArbERC20).creationCode);
    }

    function mint(address account, uint256 amount) public {
        require(inbox == msg.sender, "only callable by global inbox");
        _mint(account, amount);
    }

    function burn(address account, uint256 amount) public {
        require(inbox == msg.sender, "only callable by global inbox");
        _burn(account, amount);
    }
}

File 45 of 58 : ArbERC20.sol
/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.0;

import "./ArbSys.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract ArbERC20 is ERC20 {
    function adminMint(address account, uint256 amount) public {
        // This function is only callable through admin logic since address 1 cannot make calls
        require(msg.sender == address(1));
        _mint(account, amount);
    }

    function withdraw(address account, uint256 amount) public {
        _burn(msg.sender, amount);
        ArbSys(100).withdrawERC20(account, amount);
    }
}

File 46 of 58 : ArbSys.sol
/*
 * Copyright 2019-2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity >=0.4.21 <0.6.0;

interface ArbSys {
    // Send given amount of ERC-20 tokens to dest with token contract sender.
    // This is safe to freely call since the sender is authenticated and thus
    // you can only send fake tokens, not steal real ones
    function withdrawERC20(address dest, uint256 amount) external;

    // Send given ERC-721 token to dest with token contract sender.
    // This is safe by the above arguement
    function withdrawERC721(address dest, uint256 id) external;

    // Send given amount of Eth to dest with from sender.
    function withdrawEth(address dest) external payable;

    // Return the number of transactions issued by the given external account
    // or the account sequence number of the given contract
    function getTransactionCount(address account) external view returns (uint256);

    function getStorageAt(address account, uint256 index) external view returns (uint256);
}

File 47 of 58 : ERC20.sol
pragma solidity ^0.5.0;

import "../../GSN/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20Mintable}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20};
     *
     * Requirements:
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for `sender`'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal {
        require(account != address(0), "ERC20: mint to the zero address");

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal {
        require(account != address(0), "ERC20: burn from the zero address");

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
     *
     * This is internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`.`amount` is then deducted
     * from the caller's allowance.
     *
     * See {_burn} and {_approve}.
     */
    function _burnFrom(address account, uint256 amount) internal {
        _burn(account, amount);
        _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
    }
}

File 48 of 58 : Context.sol
pragma solidity ^0.5.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, which should be used via inheritance.
    constructor () internal { }
    // solhint-disable-previous-line no-empty-blocks

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 49 of 58 : IERC20.sol
pragma solidity ^0.5.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see {ERC20Detailed}.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 50 of 58 : SafeMath.sol
pragma solidity ^0.5.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 51 of 58 : Ownable.sol
pragma solidity ^0.5.0;

import "../GSN/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(isOwner(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Returns true if the caller is the current owner.
     */
    function isOwner() public view returns (bool) {
        return _msgSender() == _owner;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

File 52 of 58 : ERC20Detailed.sol
pragma solidity ^0.5.0;

import "./IERC20.sol";

/**
 * @dev Optional functions from the ERC20 standard.
 */
contract ERC20Detailed is IERC20 {
    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
     * these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name, string memory symbol, uint8 decimals) public {
        _name = name;
        _symbol = symbol;
        _decimals = decimals;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }
}

File 53 of 58 : ChallengeTester.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "../challenge/IChallengeFactory.sol";
import "../rollup/IStaking.sol";

contract ChallengeTester is IStaking {
    IChallengeFactory private challengeFactory;

    constructor(address challengeFactory_) public {
        challengeFactory = IChallengeFactory(challengeFactory_);
    }

    function resolveChallenge(address payable, address) external {
        return;
    }

    function startChallenge(
        address payable asserterAddress,
        address payable challengerAddress,
        uint128 challengerPeriodTicks,
        bytes32 challengerDataHash,
        uint256 challengeType
    ) public {
        challengeFactory.createChallenge(
            asserterAddress,
            challengerAddress,
            challengerPeriodTicks,
            challengerDataHash,
            challengeType
        );
    }
}

File 54 of 58 : KeccakTester.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "../libraries/Keccak.sol";

library KeccakTester {
    function keccakF(uint256[25] memory input) public pure returns (uint256[25] memory) {
        return Keccak.keccakF(input);
    }
}

File 55 of 58 : MachineTester.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2012, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "../arch/Machine.sol";
import "../arch/Marshaling.sol";
import "../arch/Value.sol";

contract MachineTester {
    using Hashing for Value.Data;
    using Machine for Machine.Data;

    function deserializeMachine(bytes memory data) public pure returns (uint256, bytes32) {
        uint256 offset;
        Machine.Data memory machine;
        (offset, machine) = Machine.deserializeMachine(data, 0);
        return (offset, machine.hash());
    }

    function addStackVal(bytes memory data1, bytes memory data2) public pure returns (bytes32) {
        uint256 offset;
        Value.Data memory val1;
        Value.Data memory val2;

        (offset, val1) = Marshaling.deserialize(data1, 0);

        (offset, val2) = Marshaling.deserialize(data2, 0);

        return Machine.addStackVal(val1, val2).hash();
    }
}

File 56 of 58 : MessageTester.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;
pragma experimental ABIEncoderV2;

import "../inbox/Messages.sol";

contract MessageTester {
    using Hashing for Value.Data;

    function messageHash(
        uint8 messageType,
        address sender,
        uint256 blockNumber,
        uint256 timestamp,
        uint256 inboxSeqNum,
        bytes32 messageDataHash
    ) public pure returns (bytes32) {
        return
            Messages.messageHash(
                messageType,
                sender,
                blockNumber,
                timestamp,
                inboxSeqNum,
                messageDataHash
            );
    }

    function messageValueHash(
        uint8 messageType,
        uint256 blockNumber,
        uint256 timestamp,
        address sender,
        uint256 inboxSeqNum,
        bytes memory messageData
    ) public pure returns (bytes32) {
        return
            Messages
                .messageValue(messageType, blockNumber, timestamp, sender, inboxSeqNum, messageData)
                .hash();
    }

    function addMessageToInbox(bytes32 inbox, bytes32 message) public pure returns (bytes32) {
        return Messages.addMessageToInbox(inbox, message);
    }

    function unmarshalOutgoingMessage(bytes memory data, uint256 startOffset)
        public
        pure
        returns (
            bool, // valid
            uint256, // offset
            uint8, // kind
            address, // sender
            bytes memory // data
        )
    {
        (bool valid, uint256 offset, Messages.OutgoingMessage memory message) = Messages
            .unmarshalOutgoingMessage(data, startOffset);
        return (valid, offset, message.kind, message.sender, message.data);
    }

    function parseEthMessage(bytes memory data)
        public
        pure
        returns (bool valid, Messages.EthMessage memory message)
    {
        return Messages.parseEthMessage(data);
    }

    function parseERC20Message(bytes memory data)
        public
        pure
        returns (bool valid, Messages.ERC20Message memory message)
    {
        return Messages.parseERC20Message(data);
    }

    function parseERC721Message(bytes memory data)
        public
        pure
        returns (bool valid, Messages.ERC721Message memory message)
    {
        return Messages.parseERC721Message(data);
    }
}

File 57 of 58 : RollupTester.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
pragma solidity ^0.5.11;

import "../rollup/RollupUtils.sol";
import "../rollup/NodeGraphUtils.sol";

contract RollupTester {
    function confirm(
        bytes32 confNode,
        bytes32 initalProtoStateHash,
        uint256 beforeSendCount,
        uint256[] memory branches,
        uint256[] memory deadlineTicks,
        bytes32[] memory challengeNodeData,
        bytes32[] memory logsAcc,
        bytes32[] memory vmProtoStateHashes,
        uint256[] memory messageCounts,
        bytes memory messages
    )
        public
        pure
        returns (
            bytes32[] memory validNodeHashes,
            bytes32 vmProtoStateHash,
            bytes32 lastNodeHash
        )
    {
        RollupUtils.NodeData memory finalNodeData;
        (validNodeHashes, finalNodeData) = RollupUtils.confirm(
            RollupUtils.ConfirmData(
                initalProtoStateHash,
                beforeSendCount,
                branches,
                deadlineTicks,
                challengeNodeData,
                logsAcc,
                vmProtoStateHashes,
                messageCounts,
                messages
            ),
            confNode
        );
        return (validNodeHashes, finalNodeData.vmProtoStateHash, finalNodeData.nodeHash);
    }

    function generateLastMessageHash(
        bytes memory messages,
        uint256 startOffset,
        uint256 length
    ) public pure returns (bytes32, uint256) {
        return RollupUtils.generateLastMessageHash(messages, startOffset, length);
    }

    function processValidNode(
        bytes32[] memory logsAcc,
        bytes32[] memory vmProtoStateHashes,
        uint256[] memory messageCounts,
        bytes memory messages,
        uint256 validNum,
        uint256 beforeSendCount,
        uint256 startOffset
    )
        public
        pure
        returns (
            uint256 afterSendCount,
            uint256 afterOffset,
            bytes32 nodeDataHash,
            bytes32 vmProtoStateHash
        )
    {
        return
            RollupUtils.processValidNode(
                RollupUtils.ConfirmData(
                    0,
                    0,
                    new uint256[](0),
                    new uint256[](0),
                    new bytes32[](0),
                    logsAcc,
                    vmProtoStateHashes,
                    messageCounts,
                    messages
                ),
                validNum,
                beforeSendCount,
                startOffset
            );
    }

    function calculateLeafFromPath(bytes32 from, bytes32[] memory proof)
        public
        pure
        returns (bytes32)
    {
        return RollupUtils.calculateLeafFromPath(from, proof);
    }

    function childNodeHash(
        bytes32 prevNodeHash,
        uint256 deadlineTicks,
        bytes32 nodeDataHash,
        uint256 childType,
        bytes32 vmProtoStateHash
    ) public pure returns (bytes32) {
        return
            RollupUtils.childNodeHash(
                prevNodeHash,
                deadlineTicks,
                nodeDataHash,
                childType,
                vmProtoStateHash
            );
    }

    function computeProtoHashBefore(
        bytes32 machineHash,
        bytes32 inboxTop,
        uint256 inboxCount,
        uint256 messageCount,
        uint256 logCount
    ) public pure returns (bytes32) {
        return
            RollupUtils.protoStateHash(machineHash, inboxTop, inboxCount, messageCount, logCount);
    }

    function computePrevLeaf(
        bytes32[8] memory fields,
        uint256[5] memory fields2,
        uint32 prevChildType,
        uint64 numSteps,
        uint64 numArbGas,
        uint64 messageCount,
        uint64 logCount
    ) public pure returns (bytes32 prevLeaf, bytes32 vmProtoHashBefore) {
        NodeGraphUtils.AssertionData memory assertData = NodeGraphUtils.makeAssertion(
            fields,
            fields2,
            prevChildType,
            numSteps,
            numArbGas,
            messageCount,
            logCount
        );

        return NodeGraphUtils.computePrevLeaf(assertData);
    }

    function generateInvalidInboxTopLeaf(
        uint256[4] memory invalidInboxData,
        bytes32[8] memory fields,
        uint256[5] memory fields2,
        uint32 prevChildType,
        uint64 numSteps,
        uint64 numArbGas,
        uint64 messageCount,
        uint64 logCount
    ) public pure returns (bytes32) {
        NodeGraphUtils.AssertionData memory assertData = NodeGraphUtils.makeAssertion(
            fields,
            fields2,
            prevChildType,
            numSteps,
            numArbGas,
            messageCount,
            logCount
        );

        return _generateInvalidInboxTopLeaf(assertData, invalidInboxData);
    }

    function _generateInvalidInboxTopLeaf(
        NodeGraphUtils.AssertionData memory assertData,
        uint256[4] memory invalidInboxData
    ) private pure returns (bytes32) {
        (bytes32 prevLeaf, bytes32 vmProtoHashBefore) = NodeGraphUtils.computePrevLeaf(assertData);

        return
            NodeGraphUtils.generateInvalidInboxTopLeaf(
                assertData,
                prevLeaf,
                invalidInboxData[3],
                bytes32(invalidInboxData[0]),
                invalidInboxData[1],
                vmProtoHashBefore,
                invalidInboxData[2]
            );
    }

    function generateInvalidExecutionLeaf(
        uint256 gracePeriodTicks,
        uint256 checkTimeTicks,
        uint256 deadlineTicks,
        bytes32[8] memory fields,
        uint256[5] memory fields2,
        uint32 prevChildType,
        uint64 numSteps,
        uint64 numArbGas,
        uint64 messageCount,
        uint64 logCount
    ) public pure returns (bytes32) {
        NodeGraphUtils.AssertionData memory assertData = NodeGraphUtils.makeAssertion(
            fields,
            fields2,
            prevChildType,
            numSteps,
            numArbGas,
            messageCount,
            logCount
        );

        return
            _generateInvalidExecutionLeaf(
                assertData,
                gracePeriodTicks,
                checkTimeTicks,
                deadlineTicks
            );
    }

    function _generateInvalidExecutionLeaf(
        NodeGraphUtils.AssertionData memory assertData,
        uint256 gracePeriodTicks,
        uint256 checkTimeTicks,
        uint256 deadlineTicks
    ) private pure returns (bytes32) {
        (bytes32 prevLeaf, bytes32 vmProtoHashBefore) = NodeGraphUtils.computePrevLeaf(assertData);

        return
            NodeGraphUtils.generateInvalidExecutionLeaf(
                assertData,
                prevLeaf,
                deadlineTicks,
                vmProtoHashBefore,
                gracePeriodTicks,
                checkTimeTicks
            );
    }

    function generateValidLeaf(
        uint256 deadlineTicks,
        bytes32[8] memory fields,
        uint256[5] memory fields2,
        uint32 prevChildType,
        uint64 numSteps,
        uint64 numArbGas,
        uint64 messageCount,
        uint64 logCount
    ) public pure returns (bytes32) {
        NodeGraphUtils.AssertionData memory assertData = NodeGraphUtils.makeAssertion(
            fields,
            fields2,
            prevChildType,
            numSteps,
            numArbGas,
            messageCount,
            logCount
        );

        return _generateValidLeaf(assertData, deadlineTicks);
    }

    function _generateValidLeaf(
        NodeGraphUtils.AssertionData memory assertData,
        uint256 deadlineTicks
    ) private pure returns (bytes32) {
        (bytes32 prevLeaf, ) = NodeGraphUtils.computePrevLeaf(assertData);

        return NodeGraphUtils.generateValidLeaf(assertData, prevLeaf, deadlineTicks);
    }
}

File 58 of 58 : ValueTester.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

pragma solidity ^0.5.11;

import "../arch/Value.sol";
import "../arch/Marshaling.sol";

contract ValueTester {
    using Hashing for Value.Data;

    function deserializeHash(bytes memory data, uint256 startOffset)
        public
        pure
        returns (
            uint256, // offset
            bytes32 // valHash
        )
    {
        (uint256 offset, Value.Data memory value) = Marshaling.deserialize(data, startOffset);
        return (offset, value.hash());
    }

    function bytesToBytestackHash(
        bytes memory data,
        uint256 startOffset,
        uint256 dataLength
    ) public pure returns (bytes32) {
        return Marshaling.bytesToBytestack(data, startOffset, dataLength).hash();
    }

    function bytestackToBytes(bytes memory data, uint256 offset)
        public
        pure
        returns (
            bool,
            uint256,
            bytes memory
        )
    {
        return Marshaling.bytestackToBytes(data, offset);
    }

    function hashTuplePreImage(bytes32 innerHash, uint256 valueSize) public pure returns (bytes32) {
        return Hashing.hashTuplePreImage(innerHash, valueSize);
    }

    function hashTestTuple() public pure returns (bytes32) {
        Value.Data[] memory tupVals = new Value.Data[](2);
        tupVals[0] = Value.newInt(uint256(111));
        tupVals[1] = Value.newTuple(new Value.Data[](0));
        return Value.newTuple(tupVals).hash();
    }
}

Settings
{
  "metadata": {
    "useLiteralContent": false
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"BuddyContractDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"data","type":"address"}],"name":"BuddyContractPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"chain","type":"address"},{"indexed":true,"internalType":"uint8","name":"kind","type":"uint8"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"inboxSeqNum","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"MessageDelivered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"chain","type":"address"},{"indexed":true,"internalType":"uint8","name":"kind","type":"uint8"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"inboxSeqNum","type":"uint256"}],"name":"MessageDeliveredFromOrigin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"messageIndex","type":"uint256"},{"indexed":false,"internalType":"address","name":"originalOwner","type":"address"},{"indexed":false,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"PaymentTransfer","type":"event"},{"constant":true,"inputs":[],"name":"FAILED_TRANSFER","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"chain","type":"address"},{"internalType":"uint256","name":"maxGas","type":"uint256"},{"internalType":"uint256","name":"gasPriceBid","type":"uint256"},{"internalType":"uint256","name":"payment","type":"uint256"},{"internalType":"bytes","name":"contractData","type":"bytes"}],"name":"deployL2ContractPair","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"chain","type":"address"},{"internalType":"address","name":"erc20","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"depositERC20Message","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"chain","type":"address"},{"internalType":"address","name":"erc721","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"depositERC721Message","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"chain","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"depositEthMessage","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_tokenContract","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"getERC20Balance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_erc721","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"getERC721Tokens","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getEthBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getInbox","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"originalOwner","type":"address"},{"internalType":"uint256","name":"messageIndex","type":"uint256"}],"name":"getPaymentOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_erc721","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"hasERC721","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_tokenContract","type":"address"},{"internalType":"address","name":"_chain","type":"address"}],"name":"isPairedContract","outputs":[{"internalType":"enum GlobalFTWallet.PairingStatus","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"ownedERC20s","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"ownedERC721s","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"messageData","type":"bytes"}],"name":"sendInitializationMessage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"chain","type":"address"},{"internalType":"bytes","name":"messageData","type":"bytes"}],"name":"sendL2Message","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"chain","type":"address"},{"internalType":"bytes","name":"messageData","type":"bytes"}],"name":"sendL2MessageFromOrigin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"messages","type":"bytes"},{"internalType":"uint256","name":"initialMaxSendCount","type":"uint256"},{"internalType":"uint256","name":"finalMaxSendCount","type":"uint256"}],"name":"sendMessages","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"originalOwner","type":"address"},{"internalType":"address","name":"newOwner","type":"address"},{"internalType":"uint256","name":"messageIndex","type":"uint256"}],"name":"transferPayment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_tokenContract","type":"address"}],"name":"withdrawERC20","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_erc721","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"withdrawERC721","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"withdrawEth","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50612cee806100206000396000f3fe6080604052600436106101355760003560e01c80636e2b89c5116100ab578063c3a8962c1161006f578063c3a8962c146106ca578063caba3af014610705578063e628c91c14610786578063f3e414f8146107c9578063f4f3b20014610802578063fbef861b1461083557610135565b80636e2b89c51461056557806374c6eccc146105985780638b7010aa14610623578063a0ef91df1461066c578063bca22b761461068157610135565b806345a53f09116100fd57806345a53f09146103375780634d2301cc1461038e57806356434fe9146103d35780635bd212901461045d5780635cc96efa1461048b578063659e42cd1461050657610135565b8063022016811461013a5780630547e1b4146101865780630758fb0a146101db57806333f2ac421461026657806341acf61414610299575b600080fd5b34801561014657600080fd5b5061016d6004803603602081101561015d57600080fd5b50356001600160a01b03166108c0565b6040805192835260208301919091528051918290030190f35b34801561019257600080fd5b506101bf600480360360408110156101a957600080fd5b506001600160a01b0381351690602001356108e6565b604080516001600160a01b039092168252519081900360200190f35b3480156101e757600080fd5b50610216600480360360408110156101fe57600080fd5b506001600160a01b038135811691602001351661094d565b60408051602080825283518183015283519192839290830191858101910280838360005b8381101561025257818101518382015260200161023a565b505050509050019250505060405180910390f35b34801561027257600080fd5b506102166004803603602081101561028957600080fd5b50356001600160a01b0316610a12565b3480156102a557600080fd5b50610335600480360360a08110156102bc57600080fd5b6001600160a01b038235169160208101359160408201359160608101359181019060a081016080820135600160201b8111156102f757600080fd5b82018360208201111561030957600080fd5b803590602001918460018302840111600160201b8311171561032a57600080fd5b509092509050610ad5565b005b34801561034357600080fd5b5061037a6004803603606081101561035a57600080fd5b506001600160a01b03813581169160208101359091169060400135610bcd565b604080519115158252519081900360200190f35b34801561039a57600080fd5b506103c1600480360360208110156103b157600080fd5b50356001600160a01b0316610c4d565b60408051918252519081900360200190f35b3480156103df57600080fd5b506103e8610c68565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561042257818101518382015260200161040a565b50505050905090810190601f16801561044f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103356004803603604081101561047357600080fd5b506001600160a01b0381358116916020013516610c93565b34801561049757600080fd5b50610335600480360360208110156104ae57600080fd5b810190602081018135600160201b8111156104c857600080fd5b8201836020820111156104da57600080fd5b803590602001918460018302840111600160201b831117156104fb57600080fd5b509092509050610cd9565b34801561051257600080fd5b506105416004803603604081101561052957600080fd5b506001600160a01b0381358116916020013516610d1c565b6040518082600281111561055157fe5b60ff16815260200191505060405180910390f35b34801561057157600080fd5b506102166004803603602081101561058857600080fd5b50356001600160a01b0316610d4e565b3480156105a457600080fd5b50610335600480360360408110156105bb57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156105e557600080fd5b8201836020820111156105f757600080fd5b803590602001918460018302840111600160201b8311171561061857600080fd5b509092509050610e05565b34801561062f57600080fd5b506103356004803603608081101561064657600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135610e4d565b34801561067857600080fd5b50610335610ea2565b34801561068d57600080fd5b50610335600480360360808110156106a457600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135610eed565b3480156106d657600080fd5b506103c1600480360360408110156106ed57600080fd5b506001600160a01b0381358116916020013516610f3c565b34801561071157600080fd5b506103356004803603606081101561072857600080fd5b810190602081018135600160201b81111561074257600080fd5b82018360208201111561075457600080fd5b803590602001918460018302840111600160201b8311171561077557600080fd5b919350915080359060200135610fa5565b34801561079257600080fd5b50610335600480360360608110156107a957600080fd5b506001600160a01b0381358116916020810135909116906040013561102c565b3480156107d557600080fd5b50610335600480360360408110156107ec57600080fd5b506001600160a01b03813516906020013561113f565b34801561080e57600080fd5b506103356004803603602081101561082557600080fd5b50356001600160a01b031661120b565b34801561084157600080fd5b506103356004803603604081101561085857600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561088257600080fd5b82018360208201111561089457600080fd5b803590602001918460018302840111600160201b831117156108b557600080fd5b509092509050611422565b6001600160a01b038116600090815260056020526040902080546001909101545b915091565b6040805160208082018490526001600160601b0319606086901b1682840152825160348184030181526054909201835281519181019190912060009081526004909152908120546001600160a01b0316806109445783915050610947565b90505b92915050565b6001600160a01b03808216600090815260036020908152604080832093861683529083905290205460609190806109965750506040805160008152602081019091529050610947565b8160010160018203815481106109a857fe5b9060005260206000209060030201600201805480602002602001604051908101604052809291908181526020018280548015610a0357602002820191906000526020600020905b8154815260200190600101908083116109ef575b50505050509250505092915050565b6001600160a01b038116600090815260036020908152604091829020600181015483518181528184028101909301909352606092909183918015610a60578160200160208202803883390190505b50805190915060005b81811015610acb57836001018181548110610a8057fe5b600091825260209091206003909102015483516001600160a01b0390911690849083908110610aab57fe5b6001600160a01b0390921660209283029190910190910152600101610a69565b5090949350505050565b610ade336114db565b610b2f576040805162461bcd60e51b815260206004820152601a60248201527f6d7573742062652063616c6c656420627920636f6e7472616374000000000000604482015290519081900360640190fd5b610b393387611517565b610b868660053388888888886040516020018086815260200185815260200184815260200183838082843780830192505050955050505050506040516020818303038152906040526116c3565b604080516001600160a01b0388168152905133917feaa7eb17fe081a8c502cff47a2a944377a71c63065a02cd44b16a06d1a0d4dc7919081900360200190a2505050505050565b6001600160a01b03808316600090815260036020908152604080832093871683529083905281205490919080610c0857600092505050610c46565b816001016001820381548110610c1a57fe5b906000526020600020906003020160010160008581526020019081526020016000205460001415925050505b9392505050565b6001600160a01b031660009081526020819052604090205490565b6040518060400160405280600f81526020016e2320a4a622a22faa2920a729a322a960891b81525081565b610c9c8261179a565b604080516001600160a01b038316602082015234818301528151808203830181526060909101909152610cd590839060009033906116c3565b5050565b610cd53360043385858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506116c392505050565b6001600160a01b0391821660009081526002602090815260408083209390941682526001909201909152205460ff1690565b6001600160a01b03811660009081526001602081815260409283902091820154835181815281830281019092019093526060928391908015610d9a578160200160208202803883390190505b50805190915060005b81811015610acb57836001018181548110610dba57fe5b600091825260209091206002909102015483516001600160a01b0390911690849083908110610de557fe5b6001600160a01b0390921660209283029190910190910152600101610da3565b610e488360033385858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506116c392505050565b505050565b610e588385836117b9565b604080516001600160a01b0380861660208301528416818301526060818101849052825180830390910181526080909101909152610e9c90859060029033906116c3565b50505050565b6000610ead33610c4d565b3360008181526020819052604080822082905551929350909183156108fc0291849190818181858888f19350505050158015610cd5573d6000803e3d6000fd5b610ef8838583611830565b604080516001600160a01b0380861660208301528416818301526060818101849052825180830390910181526080909101909152610e9c90859060019033906116c3565b6001600160a01b03808216600090815260016020908152604080832093861683529083905281205490919080610f7757600092505050610947565b816001016001820381548110610f8957fe5b9060005260206000209060020201600101549250505092915050565b600080610fb0612b9d565b845b8481101561102257610ffb88888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250879250611a06915050565b91955093509150836110105750505050610e9c565b61101a8183611af2565b600101610fb2565b5050505050505050565b600061103884836108e6565b9050336001600160a01b03821614611090576040805162461bcd60e51b815260206004820152601660248201527526bab9ba103132903830bcb6b2b73a1037bbb732b91760511b604482015290519081900360640190fd5b6040805160208082018590526001600160601b0319606088901b16828401528251603481840301815260548301808552815191830191909120600090815260049092529083902080546001600160a01b038089166001600160a01b031990921682179092559186905280881660748401528416609483015260b482015290517f56e2b14cbe3f09b8a7337ab17e6ce5da744339e435db498d5ba53655695c03e59181900360d40190a150505050565b61114a338383611d08565b61119b576040805162461bcd60e51b815260206004820152601860248201527f57616c6c657420646f65736e2774206f776e20746f6b656e0000000000000000604482015290519081900360640190fd5b60408051632142170760e11b81523060048201523360248201526044810183905290516001600160a01b038416916342842e0e91606480830192600092919082900301818387803b1580156111ef57600080fd5b505af1158015611203573d6000803e3d6000fd5b505050505050565b60006112178233610f3c565b9050611224338383611f70565b61126c576040805162461bcd60e51b8152602060048201526014602482015273696e73756666696369656e742062616c616e636560601b604482015290519081900360640190fd5b6001600160a01b03821660009081526002602052604090205460ff16156112f857604080516340c10f1960e01b81523360048201526024810183905290516001600160a01b038416916340c10f1991604480830192600092919082900301818387803b1580156112db57600080fd5b505af11580156112ef573d6000803e3d6000fd5b50505050610cd5565b6040805163a9059cbb60e01b81523360048201526024810183905290516001600160a01b0384169163a9059cbb9160448083019260209291908290030181600087803b15801561134757600080fd5b505af115801561135b573d6000803e3d6000fd5b505050506040513d602081101561137157600080fd5b505160408051808201909152600f81526e2320a4a622a22faa2920a729a322a960891b602082015290610e485760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156113e75781810151838201526020016113cf565b50505050905090810190601f1680156114145780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b333214611464576040805162461bcd60e51b815260206004820152600b60248201526a6f726967696e206f6e6c7960a81b604482015290519081900360640190fd5b600061148f846003338686604051808383808284376040519201829003909120935061210392505050565b60408051828152905191925033916003916001600160a01b038816917fe923069519faf69b0726ed766a213f61b6f07f2ecf11d55582cc440d8806b0bc9181900360200190a450505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061150f57508115155b949350505050565b6001600160a01b0382166000908152600260205260408120906001600160a01b038316600090815260018301602052604090205460ff16600281111561155957fe5b1461159e576040805162461bcd60e51b815260206004820152601060248201526f1b5d5cdd081899481d5b9c185a5c995960821b604482015290519081900360640190fd5b805460ff1661169857805460ff19166001178155604080516370a0823160e01b81523060048201819052915185926001600160a01b03841692639dc29fac9284916370a08231916024808301926020929190829003018186803b15801561160457600080fd5b505afa158015611618573d6000803e3d6000fd5b505050506040513d602081101561162e57600080fd5b5051604080516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915251604480830192600092919082900301818387803b15801561167e57600080fd5b505af1158015611692573d6000803e3d6000fd5b50505050505b6001600160a01b03919091166000908152600191820160205260409020805460ff1916909117905550565b60006116d88585858580519060200120612103565b9050826001600160a01b03168460ff16866001600160a01b03167f35e48d636f39df5c5ca2278452d6d89bf9f07c2ff15f46d08aa402c46638b88284866040518083815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611758578181015183820152602001611740565b50505050905090810190601f1680156117855780820380516001836020036101000a031916815260200191505b50935050505060405180910390a45050505050565b6001600160a01b03166000908152602081905260409020805434019055565b604080516323b872dd60e01b81523360048201523060248201526044810183905290516001600160a01b038516916323b872dd91606480830192600092919082900301818387803b15801561180d57600080fd5b505af1158015611821573d6000803e3d6000fd5b50505050610e48828483612155565b6001600160a01b03831660009081526002602052604081208054909160ff90911690818015611887575060026001600160a01b038616600090815260018501602052604090205460ff16600281111561188557fe5b145b905080611899576118998587866122d9565b811561190a5760408051632770a7eb60e21b81523360048201526024810186905290516001600160a01b03881691639dc29fac91604480830192600092919082900301818387803b1580156118ed57600080fd5b505af1158015611901573d6000803e3d6000fd5b50505050611203565b604080516323b872dd60e01b81523360048201523060248201526044810186905290516001600160a01b038816916323b872dd9160648083019260209291908290030181600087803b15801561195f57600080fd5b505af1158015611973573d6000803e3d6000fd5b505050506040513d602081101561198957600080fd5b505160408051808201909152600f81526e2320a4a622a22faa2920a729a322a960891b6020820152906119fd5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156113e75781810151838201526020016113cf565b50505050505050565b600080611a11612b9d565b8391506000858381518110611a2257fe5b016020015160019093019260f81c9050611a3a6123b0565b60030160ff168160ff1614611a56575060009250839150611aeb565b6000611a6287856123b6565b9196509450905084611a7d575060009350849250611aeb9050565b60ff811683526000611a8f88866123b6565b9197509550905085611aab575060009450859350611aeb915050565b6001600160a01b0381166020850152611ac48886612433565b6040870152909650945085611ae3575060009450859350611aeb915050565b506001945050505b9250925092565b805160ff16611b51576000611b05612bbc565b611b12836040015161268a565b9150915081611b22575050610cd5565b6000611b328260000151866108e6565b9050611b428260000151866126e6565b6112ef3382846020015161273c565b805160ff1660011415611bc2576000611b68612bd3565b611b75836040015161279a565b9150915081611b85575050610cd5565b6000611b958260200151866108e6565b9050611bab338284600001518560400151612817565b50611bba8260200151866126e6565b505050610cd5565b805160ff1660021415611c1c576000611bd9612bd3565b611be6836040015161279a565b9150915081611bf6575050610cd5565b6000611c068260200151866108e6565b9050611bab3382846000015185604001516128eb565b805160ff1660051415610cd557611c598160200151338360400151600081518110611c4357fe5b01602001516001600160f81b031916151561291a565b80602001516001600160a01b03167fa98915d9854858ea787b0abcd4e8e3a96802bc19a25474a8b7017a303628e44482604001516040518080602001828103825283818151815260200191508051906020019080838360005b83811015611cca578181015183820152602001611cb2565b50505050905090810190601f168015611cf75780820380516001836020036101000a031916815260200191505b509250505060405180910390a25050565b6001600160a01b03808416600090815260036020908152604080832093861683529083905281205490919080611d4357600092505050610c46565b6000826001016001830381548110611d5757fe5b600091825260208083208884526001600390930201918201905260409091205490915080611d8c576000945050505050610c46565b60028201805482916001850191600091906000198101908110611dab57fe5b600091825260208083209091015483528201929092526040019020556002820180546000198101908110611ddb57fe5b9060005260206000200154826002016001830381548110611df857fe5b600091825260208083209091019290925587815260018401909152604081205560028201805480611e2557fe5b6000828152602081208201600019908101919091550190556002820154611f625760018401805484918691600091906000198101908110611e6257fe5b600091825260208083206003909202909101546001600160a01b031683528201929092526040019020556001840180546000198101908110611ea057fe5b9060005260206000209060030201846001016001850381548110611ec057fe5b60009182526020909120825460039092020180546001600160a01b0319166001600160a01b0390921691909117815560028083018054611f039284019190612bf3565b5050506001600160a01b03871660009081526020859052604081205560018401805480611f2c57fe5b60008281526020812060036000199093019283020180546001600160a01b031916815590611f5d6002830182612c43565b505090555b506001979650505050505050565b600081611f7f57506001610c46565b6001600160a01b03808516600090815260016020908152604080832093871683529083905290205480611fb757600092505050610c46565b6000826001016001830381548110611fcb57fe5b906000526020600020906002020190508060010154851115611ff35760009350505050610c46565b600181018054869003908190556120f6576001830180548391859160009190600019810190811061202057fe5b600091825260208083206002909202909101546001600160a01b03168352820192909252604001902055600183018054600019810190811061205e57fe5b906000526020600020906002020183600101600184038154811061207e57fe5b60009182526020808320845460029093020180546001600160a01b0319166001600160a01b03938416178155600194850154908501559089168252859052604081205583018054806120cc57fe5b60008281526020812060026000199093019283020180546001600160a01b03191681556001015590555b5060019695505050505050565b6001600160a01b0384166000908152600560205260408120600180820154018261213187874342868a6129c1565b9050612141836000015482612a2a565b835550600190910181905595945050505050565b6001600160a01b03808416600090815260036020908152604080832093861683529083905290205480612215576040805180820182526001600160a01b0386811682528251600080825260208083019095528484019182526001878101805491820180825590835291869020855160039092020180546001600160a01b031916919094161783559051805191946121f492600285019290910190612c64565b5050506001600160a01b038516600090815260208490526040902081905590505b600082600101600183038154811061222957fe5b90600052602060002090600302019050806001016000858152602001908152602001600020546000146122a3576040805162461bcd60e51b815260206004820152601d60248201527f63616e27742061646420616c7265616479206f776e656420746f6b656e000000604482015290519081900360640190fd5b60028101805460018181018355600083815260208082209093018890559254968352909201909152604090209290925550505050565b806122e357610e48565b6001600160a01b0380841660009081526001602090815260408083209386168352908390529020548061237c57506040805180820182526001600160a01b0385811680835260006020808501828152600188810180548083018083559186528486209851600290910290980180546001600160a01b03191698909716979097178655905194019390935590815290849052919091208190555b8282600101600183038154811061238f57fe5b60009182526020909120600160029092020101805490910190555050505050565b60035b90565b60008060008085519050848110806123d057506021858203105b806123f857506123de612a56565b60ff168686815181106123ed57fe5b016020015160f81c14155b1561240d575060009250839150829050611aeb565b6001602186016124258888840163ffffffff612a5b16565b935093509350509250925092565b600080606060006124448686612ab4565b919550935090508361245a575060009250611aeb565b60208104601f8216600081612470576000612473565b60015b60ff16830190506060836040519080825280602002602001820160405280156124a6578160200160208202803883390190505b5090506060836040519080825280601f01601f1916602001820160405280156124d6576020820181803883390190505b5090506000805b848110156125a15760006124f18e8c612ab4565b919d509b5090508b612510575060009a50611aeb975050505050505050565b8115801561251e5750600087115b15612571578060005b8881101561256a5781816020811061253b57fe5b1a60f81b86828151811061254b57fe5b60200101906001600160f81b031916908160001a905350600101612527565b5050612598565b8060001b858460018b03038151811061258657fe5b60209081029190910101526001909201915b506001016124dd565b5060006125ae8d8b612b16565b909a5090506125bb6123b0565b60ff168160ff16146125d9575060009950611aeb9650505050505050565b60018a858560405160200180838051906020019060200280838360005b8381101561260e5781810151838201526020016125f6565b5050505090500182805190602001908083835b602083106126405780518252601f199092019160209182019101612621565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040529a509a509a5050505050505050509250925092565b6000612694612bbc565b6034835110156126a757600091506108e1565b600c6126b9848263ffffffff612b3d16565b6001600160a01b031682526014016126d7848263ffffffff612a5b16565b60208301525060019150915091565b6040805160208082019390935260609390931b6001600160601b031916838201528051808403603401815260549093018152825192820192909220600090815260049091522080546001600160a01b0319169055565b6001600160a01b03831660009081526020819052604081205482111561276457506000610c46565b506001600160a01b0392831660009081526020819052604080822080548490039055929093168352912080549091019055600190565b60006127a4612bd3565b6048835110156127b757600091506108e1565b600c6127c9848263ffffffff612b3d16565b6001600160a01b031682526020016127e7848263ffffffff612b3d16565b6001600160a01b03166020830152601401612808848263ffffffff612a5b16565b60408301525060019150915091565b6001600160a01b0382166000908152600260205260408120805460ff168281801561286a575060026001600160a01b038916600090815260018501602052604090205460ff16600281111561286857fe5b145b9050801580156128825750612880888787611f70565b155b15612893576000935050505061150f565b60008280156128ca575060026001600160a01b038916600090815260018601602052604090205460ff1660028111156128c857fe5b145b9050806128dc576128dc8888886122d9565b50600198975050505050505050565b60006128f8858484611d08565b6129045750600061150f565b61290f848484612155565b506001949350505050565b6001600160a01b038316600090815260026020526040902060016001600160a01b038416600090815260018301602052604090205460ff16600281111561295d57fe5b146129685750610e48565b8115612998576001600160a01b03831660009081526001820160205260409020805460ff19166002179055610e9c565b6001600160a01b0392909216600090815260019092016020525060409020805460ff1916905550565b6040805160f89790971b6001600160f81b03191660208089019190915260609690961b6001600160601b03191660218801526035870194909452605586019290925260758501526095808501919091528151808503909101815260b59093019052815191012090565b604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b600090565b60008160200183511015612aab576040805162461bcd60e51b815260206004820152601260248201527152656164206f7574206f6620626f756e647360701b604482015290519081900360640190fd5b50016020015190565b600080600080612ac48686612b16565b9093509050612ad16123b0565b60020160ff168160ff1614612aea575060009250611aeb565b612af486846123b6565b9195509350915083612b0a575060009250611aeb565b50600192509250925092565b60008082600101848481518110612b2957fe5b016020015190925060f81c90509250929050565b60008160140183511015612b8d576040805162461bcd60e51b815260206004820152601260248201527152656164206f7574206f6620626f756e647360701b604482015290519081900360640190fd5b500160200151600160601b900490565b6040805160608082018352600080835260208301529181019190915290565b604080518082019091526000808252602082015290565b604080516060810182526000808252602082018190529181019190915290565b828054828255906000526020600020908101928215612c335760005260206000209182015b82811115612c33578254825591600101919060010190612c18565b50612c3f929150612c9f565b5090565b5080546000825590600052602060002090810190612c619190612c9f565b50565b828054828255906000526020600020908101928215612c33579160200282015b82811115612c33578251825591602001919060010190612c84565b6123b391905b80821115612c3f5760008155600101612ca556fea265627a7a723158208d0258f52a713845868ae3c79a3b104df6dc2009829aeccfb5c765e9cf4d812f64736f6c63430005110032

Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading