ETH Price: $3,335.52 (-0.62%)
Gas: 4.2 Gwei
 
Transaction Hash
Method
Block
From
To
Hub Contract Wit...135444462021-11-03 14:43:431154 days ago1635950623IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.00969937162.96536886
Empty Channel135444242021-11-03 14:39:091154 days ago1635950349IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.01993412152.49832428
Start Exit135380562021-11-02 14:27:551155 days ago1635863275IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.01954527164.74020857
Hub Contract Wit...103399862020-06-26 7:09:351649 days ago1593155375IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0022349240
Hub Authorized U...90622632019-12-06 20:03:591852 days ago1575662639IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0047163610
Hub Authorized U...89961052019-11-25 2:59:321863 days ago1574650772IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0008537113
Hub Authorized U...89960552019-11-25 2:44:221863 days ago1574649862IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0008537113
Hub Authorized U...89959912019-11-25 2:31:021863 days ago1574649062IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0008537113
Hub Authorized U...89959622019-11-25 2:21:291863 days ago1574648489IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0008537113
Hub Authorized U...89934132019-11-24 16:21:151864 days ago1574612475IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0051967610
Hub Authorized U...89825792019-11-22 21:08:341866 days ago1574456914IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0055059210
Hub Authorized U...89458932019-11-16 18:22:251872 days ago1573928545IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0047610210
Hub Authorized U...89412492019-11-15 23:35:431873 days ago1573860943IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0049835210
Hub Authorized U...89394912019-11-15 16:38:581873 days ago1573835938IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0006573410
Hub Authorized U...89347992019-11-14 21:54:431874 days ago1573768483IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.005510510
Hub Authorized U...89000702019-11-09 3:24:071879 days ago1573269847IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0049709410
Hub Authorized U...88788382019-11-05 17:17:411883 days ago1572974261IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.005182910
Hub Authorized U...88710102019-11-04 11:15:231884 days ago1572866123IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0053454810
Hub Authorized U...88647112019-11-03 10:52:361885 days ago1572778356IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0047755210
Hub Authorized U...88613352019-11-02 21:46:221886 days ago1572731182IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0050466410
Hub Authorized U...88570822019-11-02 5:21:391886 days ago1572672099IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0049407810
Hub Authorized U...88548312019-11-01 20:38:361887 days ago1572640716IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0054183810
Hub Authorized U...88450252019-10-31 6:52:401888 days ago1572504760IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0056927512
Hub Authorized U...88432282019-10-30 23:54:331889 days ago1572479673IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0047452410
Hub Authorized U...88389372019-10-30 7:16:561889 days ago1572419816IN
0xbf2aEaB0...fc5Cf662b
0 ETH0.0053288210
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
135444462021-11-03 14:43:431154 days ago1635950623
0xbf2aEaB0...fc5Cf662b
69.04723546 ETH
135444242021-11-03 14:39:091154 days ago1635950349
0xbf2aEaB0...fc5Cf662b
0.08436122 ETH
90622632019-12-06 20:03:591852 days ago1575662639
0xbf2aEaB0...fc5Cf662b
0.53072461 ETH
89934132019-11-24 16:21:151864 days ago1574612475
0xbf2aEaB0...fc5Cf662b
0.2055458 ETH
89825792019-11-22 21:08:341866 days ago1574456914
0xbf2aEaB0...fc5Cf662b
0.10781521 ETH
89458932019-11-16 18:22:251872 days ago1573928545
0xbf2aEaB0...fc5Cf662b
0.00600959 ETH
89412492019-11-15 23:35:431873 days ago1573860943
0xbf2aEaB0...fc5Cf662b
0.02949013 ETH
89347992019-11-14 21:54:431874 days ago1573768483
0xbf2aEaB0...fc5Cf662b
0.00453851 ETH
89000702019-11-09 3:24:071879 days ago1573269847
0xbf2aEaB0...fc5Cf662b
0.08466799 ETH
88788382019-11-05 17:17:411883 days ago1572974261
0xbf2aEaB0...fc5Cf662b
0.55486651 ETH
88710102019-11-04 11:15:231884 days ago1572866123
0xbf2aEaB0...fc5Cf662b
0.02728037 ETH
88647112019-11-03 10:52:361885 days ago1572778356
0xbf2aEaB0...fc5Cf662b
0.00463136 ETH
88613352019-11-02 21:46:221886 days ago1572731182
0xbf2aEaB0...fc5Cf662b
0.14604678 ETH
88570822019-11-02 5:21:391886 days ago1572672099
0xbf2aEaB0...fc5Cf662b
0.00375171 ETH
88548312019-11-01 20:38:361887 days ago1572640716
0xbf2aEaB0...fc5Cf662b
0.02225321 ETH
88450252019-10-31 6:52:401888 days ago1572504760
0xbf2aEaB0...fc5Cf662b
0.00380937 ETH
88432282019-10-30 23:54:331889 days ago1572479673
0xbf2aEaB0...fc5Cf662b
0.04248721 ETH
88389372019-10-30 7:16:561889 days ago1572419816
0xbf2aEaB0...fc5Cf662b
0.00073254 ETH
88378902019-10-30 3:11:141889 days ago1572405074
0xbf2aEaB0...fc5Cf662b
0.83558254 ETH
88355722019-10-29 18:26:581890 days ago1572373618
0xbf2aEaB0...fc5Cf662b
0.26900188 ETH
88347242019-10-29 15:14:541890 days ago1572362094
0xbf2aEaB0...fc5Cf662b
0.05111623 ETH
88315762019-10-29 2:51:531890 days ago1572317513
0xbf2aEaB0...fc5Cf662b
0.0383729 ETH
88315582019-10-29 2:47:111890 days ago1572317231
0xbf2aEaB0...fc5Cf662b
0.02314295 ETH
88314022019-10-29 2:09:501890 days ago1572314990
0xbf2aEaB0...fc5Cf662b
0.14745315 ETH
88308152019-10-29 0:01:071891 days ago1572307267
0xbf2aEaB0...fc5Cf662b
0.00060496 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ChannelManager

Compiler Version
v0.4.25+commit.59dbf8f1

Optimization Enabled:
Yes with 1 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2018-12-22
*/

pragma solidity ^0.4.25;
pragma experimental ABIEncoderV2;
// produced by the Solididy File Flattener (c) David Appleton 2018
// contact : [email protected]
// released under Apache 2.0 licence
contract ERC20Basic {
  function totalSupply() public view returns (uint256);
  function balanceOf(address who) public view returns (uint256);
  function transfer(address to, uint256 value) public returns (bool);
  event Transfer(address indexed from, address indexed to, uint256 value);
}

library ECTools {

    // @dev Recovers the address which has signed a message
    // @thanks https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d
    function recoverSigner(bytes32 _hashedMsg, string _sig) public pure returns (address) {
        require(_hashedMsg != 0x00);

        // need this for test RPC
        bytes memory prefix = "\x19Ethereum Signed Message:\n32";
        bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, _hashedMsg));

        if (bytes(_sig).length != 132) {
            return 0x0;
        }
        bytes32 r;
        bytes32 s;
        uint8 v;
        bytes memory sig = hexstrToBytes(substring(_sig, 2, 132));
        assembly {
            r := mload(add(sig, 32))
            s := mload(add(sig, 64))
            v := byte(0, mload(add(sig, 96)))
        }
        if (v < 27) {
            v += 27;
        }
        if (v < 27 || v > 28) {
            return 0x0;
        }
        return ecrecover(prefixedHash, v, r, s);
    }

    // @dev Verifies if the message is signed by an address
    function isSignedBy(bytes32 _hashedMsg, string _sig, address _addr) public pure returns (bool) {
        require(_addr != 0x0);

        return _addr == recoverSigner(_hashedMsg, _sig);
    }

    // @dev Converts an hexstring to bytes
    function hexstrToBytes(string _hexstr) public pure returns (bytes) {
        uint len = bytes(_hexstr).length;
        require(len % 2 == 0);

        bytes memory bstr = bytes(new string(len / 2));
        uint k = 0;
        string memory s;
        string memory r;
        for (uint i = 0; i < len; i += 2) {
            s = substring(_hexstr, i, i + 1);
            r = substring(_hexstr, i + 1, i + 2);
            uint p = parseInt16Char(s) * 16 + parseInt16Char(r);
            bstr[k++] = uintToBytes32(p)[31];
        }
        return bstr;
    }

    // @dev Parses a hexchar, like 'a', and returns its hex value, in this case 10
    function parseInt16Char(string _char) public pure returns (uint) {
        bytes memory bresult = bytes(_char);
        // bool decimals = false;
        if ((bresult[0] >= 48) && (bresult[0] <= 57)) {
            return uint(bresult[0]) - 48;
        } else if ((bresult[0] >= 65) && (bresult[0] <= 70)) {
            return uint(bresult[0]) - 55;
        } else if ((bresult[0] >= 97) && (bresult[0] <= 102)) {
            return uint(bresult[0]) - 87;
        } else {
            revert();
        }
    }

    // @dev Converts a uint to a bytes32
    // @thanks https://ethereum.stackexchange.com/questions/4170/how-to-convert-a-uint-to-bytes-in-solidity
    function uintToBytes32(uint _uint) public pure returns (bytes b) {
        b = new bytes(32);
        assembly {mstore(add(b, 32), _uint)}
    }

    // @dev Hashes the signed message
    // @ref https://github.com/ethereum/go-ethereum/issues/3731#issuecomment-293866868
    function toEthereumSignedMessage(string _msg) public pure returns (bytes32) {
        uint len = bytes(_msg).length;
        require(len > 0);
        bytes memory prefix = "\x19Ethereum Signed Message:\n";
        return keccak256(abi.encodePacked(prefix, uintToString(len), _msg));
    }

    // @dev Converts a uint in a string
    function uintToString(uint _uint) public pure returns (string str) {
        uint len = 0;
        uint m = _uint + 0;
        while (m != 0) {
            len++;
            m /= 10;
        }
        bytes memory b = new bytes(len);
        uint i = len - 1;
        while (_uint != 0) {
            uint remainder = _uint % 10;
            _uint = _uint / 10;
            b[i--] = byte(48 + remainder);
        }
        str = string(b);
    }


    // @dev extract a substring
    // @thanks https://ethereum.stackexchange.com/questions/31457/substring-in-solidity
    function substring(string _str, uint _startIndex, uint _endIndex) public pure returns (string) {
        bytes memory strBytes = bytes(_str);
        require(_startIndex <= _endIndex);
        require(_startIndex >= 0);
        require(_endIndex <= strBytes.length);

        bytes memory result = new bytes(_endIndex - _startIndex);
        for (uint i = _startIndex; i < _endIndex; i++) {
            result[i - _startIndex] = strBytes[i];
        }
        return string(result);
    }
}
library SafeMath {

    /**
    * @dev Multiplies two numbers, reverts on 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-solidity/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b);

        return c;
    }

    /**
    * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
    */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0); // Solidity only automatically asserts when dividing by 0
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
    * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
    */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;

        return c;
    }

    /**
    * @dev Adds two numbers, reverts on overflow.
    */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);

        return c;
    }

    /**
    * @dev Divides two numbers and returns the remainder (unsigned integer modulo),
    * reverts when dividing by zero.
    */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
    }
}
contract ERC20 is ERC20Basic {
  function allowance(address owner, address spender) public view returns (uint256);
  function transferFrom(address from, address to, uint256 value) public returns (bool);
  function approve(address spender, uint256 value) public returns (bool);
  event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract ChannelManager {
    using SafeMath for uint256;

    string public constant NAME = "Channel Manager";
    string public constant VERSION = "0.0.1";

    address public hub;
    uint256 public challengePeriod;
    ERC20 public approvedToken;

    uint256 public totalChannelWei;
    uint256 public totalChannelToken;

    event DidHubContractWithdraw (
        uint256 weiAmount,
        uint256 tokenAmount
    );

    // Note: the payload of DidUpdateChannel contains the state that caused
    // the update, not the state post-update (ex, if the update contains a
    // deposit, the event's ``pendingDeposit`` field will be present and the
    // event's ``balance`` field will not have been updated to reflect that
    // balance).
    event DidUpdateChannel (
        address indexed user,
        uint256 senderIdx, // 0: hub, 1: user
        uint256[2] weiBalances, // [hub, user]
        uint256[2] tokenBalances, // [hub, user]
        uint256[4] pendingWeiUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[4] pendingTokenUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[2] txCount, // [global, onchain]
        bytes32 threadRoot,
        uint256 threadCount
    );

    // Note: unlike the DidUpdateChannel event, the ``DidStartExitChannel``
    // event will contain the channel state after any state that has been
    // applied as part of startExitWithUpdate.
    event DidStartExitChannel (
        address indexed user,
        uint256 senderIdx, // 0: hub, 1: user
        uint256[2] weiBalances, // [hub, user]
        uint256[2] tokenBalances, // [hub, user]
        uint256[2] txCount, // [global, onchain]
        bytes32 threadRoot,
        uint256 threadCount
    );

    event DidEmptyChannel (
        address indexed user,
        uint256 senderIdx, // 0: hub, 1: user
        uint256[2] weiBalances, // [hub, user]
        uint256[2] tokenBalances, // [hub, user]
        uint256[2] txCount, // [global, onchain]
        bytes32 threadRoot,
        uint256 threadCount
    );

    event DidStartExitThread (
        address user,
        address indexed sender,
        address indexed receiver,
        uint256 threadId,
        address senderAddress, // either hub or user
        uint256[2] weiBalances, // [sender, receiver]
        uint256[2] tokenBalances, // [sender, receiver]
        uint256 txCount
    );

    event DidChallengeThread (
        address indexed sender,
        address indexed receiver,
        uint256 threadId,
        address senderAddress, // can be either hub, sender, or receiver
        uint256[2] weiBalances, // [sender, receiver]
        uint256[2] tokenBalances, // [sender, receiver]
        uint256 txCount
    );

    event DidEmptyThread (
        address user,
        address indexed sender,
        address indexed receiver,
        uint256 threadId,
        address senderAddress, // can be anyone
        uint256[2] channelWeiBalances,
        uint256[2] channelTokenBalances,
        uint256[2] channelTxCount,
        bytes32 channelThreadRoot,
        uint256 channelThreadCount
    );

    event DidNukeThreads(
        address indexed user,
        address senderAddress, // can be anyone
        uint256 weiAmount, // amount of wei sent
        uint256 tokenAmount, // amount of tokens sent
        uint256[2] channelWeiBalances,
        uint256[2] channelTokenBalances,
        uint256[2] channelTxCount,
        bytes32 channelThreadRoot,
        uint256 channelThreadCount
    );

    enum ChannelStatus {
       Open,
       ChannelDispute,
       ThreadDispute
    }

    struct Channel {
        uint256[3] weiBalances; // [hub, user, total]
        uint256[3] tokenBalances; // [hub, user, total]
        uint256[2] txCount; // persisted onchain even when empty [global, pending]
        bytes32 threadRoot;
        uint256 threadCount;
        address exitInitiator;
        uint256 channelClosingTime;
        ChannelStatus status;
    }

    struct Thread {
        uint256[2] weiBalances; // [sender, receiver]
        uint256[2] tokenBalances; // [sender, receiver]
        uint256 txCount; // persisted onchain even when empty
        uint256 threadClosingTime;
        bool[2] emptied; // [sender, receiver]
    }

    mapping(address => Channel) public channels;
    mapping(address => mapping(address => mapping(uint256 => Thread))) threads; // threads[sender][receiver][threadId]

    bool locked;

    modifier onlyHub() {
        require(msg.sender == hub);
        _;
    }

    modifier noReentrancy() {
        require(!locked, "Reentrant call.");
        locked = true;
        _;
        locked = false;
    }

    constructor(address _hub, uint256 _challengePeriod, address _tokenAddress) public {
        hub = _hub;
        challengePeriod = _challengePeriod;
        approvedToken = ERC20(_tokenAddress);
    }

    function hubContractWithdraw(uint256 weiAmount, uint256 tokenAmount) public noReentrancy onlyHub {
        require(
            getHubReserveWei() >= weiAmount,
            "hubContractWithdraw: Contract wei funds not sufficient to withdraw"
        );
        require(
            getHubReserveTokens() >= tokenAmount,
            "hubContractWithdraw: Contract token funds not sufficient to withdraw"
        );

        hub.transfer(weiAmount);
        require(
            approvedToken.transfer(hub, tokenAmount),
            "hubContractWithdraw: Token transfer failure"
        );

        emit DidHubContractWithdraw(weiAmount, tokenAmount);
    }

    function getHubReserveWei() public view returns (uint256) {
        return address(this).balance.sub(totalChannelWei);
    }

    function getHubReserveTokens() public view returns (uint256) {
        return approvedToken.balanceOf(address(this)).sub(totalChannelToken);
    }

    function hubAuthorizedUpdate(
        address user,
        address recipient,
        uint256[2] weiBalances, // [hub, user]
        uint256[2] tokenBalances, // [hub, user]
        uint256[4] pendingWeiUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[4] pendingTokenUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[2] txCount, // [global, onchain] persisted onchain even when empty
        bytes32 threadRoot,
        uint256 threadCount,
        uint256 timeout,
        string sigUser
    ) public noReentrancy onlyHub {
        Channel storage channel = channels[user];

        _verifyAuthorizedUpdate(
            channel,
            txCount,
            weiBalances,
            tokenBalances,
            pendingWeiUpdates,
            pendingTokenUpdates,
            timeout,
            true
        );

        _verifySig(
            [user, recipient],
            weiBalances,
            tokenBalances,
            pendingWeiUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
            pendingTokenUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
            txCount,
            threadRoot,
            threadCount,
            timeout,
            "", // skip hub sig verification
            sigUser,
            [false, true] // [checkHubSig?, checkUser] <- only need to check user
        );

        _updateChannelBalances(channel, weiBalances, tokenBalances, pendingWeiUpdates, pendingTokenUpdates);

        // transfer wei and token to recipient
        recipient.transfer(pendingWeiUpdates[3]);
        require(approvedToken.transfer(recipient, pendingTokenUpdates[3]), "user token withdrawal transfer failed");

        // update state variables
        channel.txCount = txCount;
        channel.threadRoot = threadRoot;
        channel.threadCount = threadCount;

        emit DidUpdateChannel(
            user,
            0, // senderIdx
            weiBalances,
            tokenBalances,
            pendingWeiUpdates,
            pendingTokenUpdates,
            txCount,
            threadRoot,
            threadCount
        );
    }

    function userAuthorizedUpdate(
        address recipient,
        uint256[2] weiBalances, // [hub, user]
        uint256[2] tokenBalances, // [hub, user]
        uint256[4] pendingWeiUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[4] pendingTokenUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[2] txCount, // persisted onchain even when empty
        bytes32 threadRoot,
        uint256 threadCount,
        uint256 timeout,
        string sigHub
    ) public payable noReentrancy {
        require(msg.value == pendingWeiUpdates[2], "msg.value is not equal to pending user deposit");

        Channel storage channel = channels[msg.sender];

        _verifyAuthorizedUpdate(
            channel,
            txCount,
            weiBalances,
            tokenBalances,
            pendingWeiUpdates,
            pendingTokenUpdates,
            timeout,
            false
        );

        _verifySig(
            [msg.sender, recipient],
            weiBalances,
            tokenBalances,
            pendingWeiUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
            pendingTokenUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
            txCount,
            threadRoot,
            threadCount,
            timeout,
            sigHub,
            "", // skip user sig verification
            [true, false] // [checkHubSig?, checkUser] <- only need to check hub
        );

        // transfer user token deposit to this contract
        require(approvedToken.transferFrom(msg.sender, address(this), pendingTokenUpdates[2]), "user token deposit failed");

        _updateChannelBalances(channel, weiBalances, tokenBalances, pendingWeiUpdates, pendingTokenUpdates);

        // transfer wei and token to recipient
        recipient.transfer(pendingWeiUpdates[3]);
        require(approvedToken.transfer(recipient, pendingTokenUpdates[3]), "user token withdrawal transfer failed");

        // update state variables
        channel.txCount = txCount;
        channel.threadRoot = threadRoot;
        channel.threadCount = threadCount;

        emit DidUpdateChannel(
            msg.sender,
            1, // senderIdx
            weiBalances,
            tokenBalances,
            pendingWeiUpdates,
            pendingTokenUpdates,
            channel.txCount,
            channel.threadRoot,
            channel.threadCount
        );
    }

    /**********************
     * Unilateral Functions
     *********************/

    // start exit with onchain state
    function startExit(
        address user
    ) public noReentrancy {
        require(user != hub, "user can not be hub");
        require(user != address(this), "user can not be channel manager");

        Channel storage channel = channels[user];
        require(channel.status == ChannelStatus.Open, "channel must be open");

        require(msg.sender == hub || msg.sender == user, "exit initiator must be user or hub");

        channel.exitInitiator = msg.sender;
        channel.channelClosingTime = now.add(challengePeriod);
        channel.status = ChannelStatus.ChannelDispute;

        emit DidStartExitChannel(
            user,
            msg.sender == hub ? 0 : 1,
            [channel.weiBalances[0], channel.weiBalances[1]],
            [channel.tokenBalances[0], channel.tokenBalances[1]],
            channel.txCount,
            channel.threadRoot,
            channel.threadCount
        );
    }

    // start exit with offchain state
    function startExitWithUpdate(
        address[2] user, // [user, recipient]
        uint256[2] weiBalances, // [hub, user]
        uint256[2] tokenBalances, // [hub, user]
        uint256[4] pendingWeiUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[4] pendingTokenUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[2] txCount, // [global, onchain] persisted onchain even when empty
        bytes32 threadRoot,
        uint256 threadCount,
        uint256 timeout,
        string sigHub,
        string sigUser
    ) public noReentrancy {
        Channel storage channel = channels[user[0]];
        require(channel.status == ChannelStatus.Open, "channel must be open");

        require(msg.sender == hub || msg.sender == user[0], "exit initiator must be user or hub");

        require(timeout == 0, "can't start exit with time-sensitive states");

        _verifySig(
            user,
            weiBalances,
            tokenBalances,
            pendingWeiUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
            pendingTokenUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
            txCount,
            threadRoot,
            threadCount,
            timeout,
            sigHub,
            sigUser,
            [true, true] // [checkHubSig?, checkUser] <- check both sigs
        );

        require(txCount[0] > channel.txCount[0], "global txCount must be higher than the current global txCount");
        require(txCount[1] >= channel.txCount[1], "onchain txCount must be higher or equal to the current onchain txCount");

        // offchain wei/token balances do not exceed onchain total wei/token
        require(weiBalances[0].add(weiBalances[1]) <= channel.weiBalances[2], "wei must be conserved");
        require(tokenBalances[0].add(tokenBalances[1]) <= channel.tokenBalances[2], "tokens must be conserved");

        // pending onchain txs have been executed - force update offchain state to reflect this
        if (txCount[1] == channel.txCount[1]) {
            _applyPendingUpdates(channel.weiBalances, weiBalances, pendingWeiUpdates);
            _applyPendingUpdates(channel.tokenBalances, tokenBalances, pendingTokenUpdates);

        // pending onchain txs have *not* been executed - revert pending deposits and withdrawals back into offchain balances
        } else { //txCount[1] > channel.txCount[1]
            _revertPendingUpdates(channel.weiBalances, weiBalances, pendingWeiUpdates);
            _revertPendingUpdates(channel.tokenBalances, tokenBalances, pendingTokenUpdates);
        }

        // update state variables
        // only update txCount[0] (global)
        // - txCount[1] should only be updated by user/hubAuthorizedUpdate
        channel.txCount[0] = txCount[0];
        channel.threadRoot = threadRoot;
        channel.threadCount = threadCount;

        channel.exitInitiator = msg.sender;
        channel.channelClosingTime = now.add(challengePeriod);
        channel.status = ChannelStatus.ChannelDispute;

        emit DidStartExitChannel(
            user[0],
            msg.sender == hub ? 0 : 1,
            [channel.weiBalances[0], channel.weiBalances[1]],
            [channel.tokenBalances[0], channel.tokenBalances[1]],
            channel.txCount,
            channel.threadRoot,
            channel.threadCount
        );
    }

    // party that didn't start exit can challenge and empty
    function emptyChannelWithChallenge(
        address[2] user,
        uint256[2] weiBalances, // [hub, user]
        uint256[2] tokenBalances, // [hub, user]
        uint256[4] pendingWeiUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[4] pendingTokenUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[2] txCount, // persisted onchain even when empty
        bytes32 threadRoot,
        uint256 threadCount,
        uint256 timeout,
        string sigHub,
        string sigUser
    ) public noReentrancy {
        Channel storage channel = channels[user[0]];
        require(channel.status == ChannelStatus.ChannelDispute, "channel must be in dispute");
        require(now < channel.channelClosingTime, "channel closing time must not have passed");

        require(msg.sender != channel.exitInitiator, "challenger can not be exit initiator");
        require(msg.sender == hub || msg.sender == user[0], "challenger must be either user or hub");

        require(timeout == 0, "can't start exit with time-sensitive states");

        _verifySig(
            user,
            weiBalances,
            tokenBalances,
            pendingWeiUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
            pendingTokenUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
            txCount,
            threadRoot,
            threadCount,
            timeout,
            sigHub,
            sigUser,
            [true, true] // [checkHubSig?, checkUser] <- check both sigs
        );

        require(txCount[0] > channel.txCount[0], "global txCount must be higher than the current global txCount");
        require(txCount[1] >= channel.txCount[1], "onchain txCount must be higher or equal to the current onchain txCount");

        // offchain wei/token balances do not exceed onchain total wei/token
        require(weiBalances[0].add(weiBalances[1]) <= channel.weiBalances[2], "wei must be conserved");
        require(tokenBalances[0].add(tokenBalances[1]) <= channel.tokenBalances[2], "tokens must be conserved");

        // pending onchain txs have been executed - force update offchain state to reflect this
        if (txCount[1] == channel.txCount[1]) {
            _applyPendingUpdates(channel.weiBalances, weiBalances, pendingWeiUpdates);
            _applyPendingUpdates(channel.tokenBalances, tokenBalances, pendingTokenUpdates);

        // pending onchain txs have *not* been executed - revert pending deposits and withdrawals back into offchain balances
        } else { //txCount[1] > channel.txCount[1]
            _revertPendingUpdates(channel.weiBalances, weiBalances, pendingWeiUpdates);
            _revertPendingUpdates(channel.tokenBalances, tokenBalances, pendingTokenUpdates);
        }

        // deduct hub/user wei/tokens from total channel balances
        channel.weiBalances[2] = channel.weiBalances[2].sub(channel.weiBalances[0]).sub(channel.weiBalances[1]);
        channel.tokenBalances[2] = channel.tokenBalances[2].sub(channel.tokenBalances[0]).sub(channel.tokenBalances[1]);

        // transfer hub wei balance from channel to reserves
        totalChannelWei = totalChannelWei.sub(channel.weiBalances[0]).sub(channel.weiBalances[1]);
        // transfer user wei balance to user
        user[0].transfer(channel.weiBalances[1]);
        channel.weiBalances[0] = 0;
        channel.weiBalances[1] = 0;

        // transfer hub token balance from channel to reserves
        totalChannelToken = totalChannelToken.sub(channel.tokenBalances[0]).sub(channel.tokenBalances[1]);
        // transfer user token balance to user
        require(approvedToken.transfer(user[0], channel.tokenBalances[1]), "user token withdrawal transfer failed");
        channel.tokenBalances[0] = 0;
        channel.tokenBalances[1] = 0;

        // update state variables
        // only update txCount[0] (global)
        // - txCount[1] should only be updated by user/hubAuthorizedUpdate
        channel.txCount[0] = txCount[0];
        channel.threadRoot = threadRoot;
        channel.threadCount = threadCount;

        if (channel.threadCount > 0) {
            channel.status = ChannelStatus.ThreadDispute;
        } else {
            channel.channelClosingTime = 0;
            channel.status = ChannelStatus.Open;
        }

        channel.exitInitiator = address(0x0);

        emit DidEmptyChannel(
            user[0],
            msg.sender == hub ? 0 : 1,
            [channel.weiBalances[0], channel.weiBalances[1]],
            [channel.tokenBalances[0], channel.tokenBalances[1]],
            channel.txCount,
            channel.threadRoot,
            channel.threadCount
        );
    }

    // after timer expires - anyone can call; even before timer expires, non-exit-initiating party can call
    function emptyChannel(
        address user
    ) public noReentrancy {
        require(user != hub, "user can not be hub");
        require(user != address(this), "user can not be channel manager");

        Channel storage channel = channels[user];
        require(channel.status == ChannelStatus.ChannelDispute, "channel must be in dispute");

        require(
          channel.channelClosingTime < now ||
          msg.sender != channel.exitInitiator && (msg.sender == hub || msg.sender == user),
          "channel closing time must have passed or msg.sender must be non-exit-initiating party"
        );

        // deduct hub/user wei/tokens from total channel balances
        channel.weiBalances[2] = channel.weiBalances[2].sub(channel.weiBalances[0]).sub(channel.weiBalances[1]);
        channel.tokenBalances[2] = channel.tokenBalances[2].sub(channel.tokenBalances[0]).sub(channel.tokenBalances[1]);

        // transfer hub wei balance from channel to reserves
        totalChannelWei = totalChannelWei.sub(channel.weiBalances[0]).sub(channel.weiBalances[1]);
        // transfer user wei balance to user
        user.transfer(channel.weiBalances[1]);
        channel.weiBalances[0] = 0;
        channel.weiBalances[1] = 0;

        // transfer hub token balance from channel to reserves
        totalChannelToken = totalChannelToken.sub(channel.tokenBalances[0]).sub(channel.tokenBalances[1]);
        // transfer user token balance to user
        require(approvedToken.transfer(user, channel.tokenBalances[1]), "user token withdrawal transfer failed");
        channel.tokenBalances[0] = 0;
        channel.tokenBalances[1] = 0;

        if (channel.threadCount > 0) {
            channel.status = ChannelStatus.ThreadDispute;
        } else {
            channel.channelClosingTime = 0;
            channel.status = ChannelStatus.Open;
        }

        channel.exitInitiator = address(0x0);

        emit DidEmptyChannel(
            user,
            msg.sender == hub ? 0 : 1,
            [channel.weiBalances[0], channel.weiBalances[1]],
            [channel.tokenBalances[0], channel.tokenBalances[1]],
            channel.txCount,
            channel.threadRoot,
            channel.threadCount
        );
    }

    // **********************
    // THREAD DISPUTE METHODS
    // **********************

    // either party starts exit with initial state
    function startExitThread(
        address user,
        address sender,
        address receiver,
        uint256 threadId,
        uint256[2] weiBalances, // [sender, receiver]
        uint256[2] tokenBalances, // [sender, receiver]
        bytes proof,
        string sig
    ) public noReentrancy {
        Channel storage channel = channels[user];
        require(channel.status == ChannelStatus.ThreadDispute, "channel must be in thread dispute phase");
        require(msg.sender == hub || msg.sender == user, "thread exit initiator must be user or hub");
        require(user == sender || user == receiver, "user must be thread sender or receiver");

        require(weiBalances[1] == 0 && tokenBalances[1] == 0, "initial receiver balances must be zero");

        Thread storage thread = threads[sender][receiver][threadId];

        require(thread.threadClosingTime == 0, "thread closing time must be zero");

        _verifyThread(sender, receiver, threadId, weiBalances, tokenBalances, 0, proof, sig, channel.threadRoot);

        thread.weiBalances = weiBalances;
        thread.tokenBalances = tokenBalances;
        thread.threadClosingTime = now.add(challengePeriod);

        emit DidStartExitThread(
            user,
            sender,
            receiver,
            threadId,
            msg.sender,
            thread.weiBalances,
            thread.tokenBalances,
            thread.txCount
        );
    }

    // either party starts exit with offchain state
    function startExitThreadWithUpdate(
        address user,
        address[2] threadMembers, //[sender, receiver]
        uint256 threadId,
        uint256[2] weiBalances, // [sender, receiver]
        uint256[2] tokenBalances, // [sender, receiver]
        bytes proof,
        string sig,
        uint256[2] updatedWeiBalances, // [sender, receiver]
        uint256[2] updatedTokenBalances, // [sender, receiver]
        uint256 updatedTxCount,
        string updateSig
    ) public noReentrancy {
        Channel storage channel = channels[user];
        require(channel.status == ChannelStatus.ThreadDispute, "channel must be in thread dispute phase");
        require(msg.sender == hub || msg.sender == user, "thread exit initiator must be user or hub");
        require(user == threadMembers[0] || user == threadMembers[1], "user must be thread sender or receiver");

        require(weiBalances[1] == 0 && tokenBalances[1] == 0, "initial receiver balances must be zero");

        Thread storage thread = threads[threadMembers[0]][threadMembers[1]][threadId];
        require(thread.threadClosingTime == 0, "thread closing time must be zero");

        _verifyThread(threadMembers[0], threadMembers[1], threadId, weiBalances, tokenBalances, 0, proof, sig, channel.threadRoot);

        // *********************
        // PROCESS THREAD UPDATE
        // *********************

        require(updatedTxCount > 0, "updated thread txCount must be higher than 0");
        require(updatedWeiBalances[0].add(updatedWeiBalances[1]) == weiBalances[0], "sum of updated wei balances must match sender's initial wei balance");
        require(updatedTokenBalances[0].add(updatedTokenBalances[1]) == tokenBalances[0], "sum of updated token balances must match sender's initial token balance");

        // Note: explicitly set threadRoot == 0x0 because then it doesn't get checked by _isContained (updated state is not part of root)
        _verifyThread(threadMembers[0], threadMembers[1], threadId, updatedWeiBalances, updatedTokenBalances, updatedTxCount, "", updateSig, bytes32(0x0));

        thread.weiBalances = updatedWeiBalances;
        thread.tokenBalances = updatedTokenBalances;
        thread.txCount = updatedTxCount;
        thread.threadClosingTime = now.add(challengePeriod);

        emit DidStartExitThread(
            user,
            threadMembers[0],
            threadMembers[1],
            threadId,
            msg.sender == hub ? 0 : 1,
            thread.weiBalances,
            thread.tokenBalances,
            thread.txCount
        );
    }

    // either hub, sender, or receiver can update the thread state in place
    function challengeThread(
        address sender,
        address receiver,
        uint256 threadId,
        uint256[2] weiBalances, // updated weiBalances
        uint256[2] tokenBalances, // updated tokenBalances
        uint256 txCount,
        string sig
    ) public noReentrancy {
        require(msg.sender == hub || msg.sender == sender || msg.sender == receiver, "only hub, sender, or receiver can call this function");

        Thread storage thread = threads[sender][receiver][threadId];
        //verify that thread settlement period has not yet expired
        require(now < thread.threadClosingTime, "thread closing time must not have passed");

        // assumes that the non-sender has a later thread state than what was being proposed when the thread exit started
        require(txCount > thread.txCount, "thread txCount must be higher than the current thread txCount");
        require(weiBalances[0].add(weiBalances[1]) == thread.weiBalances[0].add(thread.weiBalances[1]), "updated wei balances must match sum of thread wei balances");
        require(tokenBalances[0].add(tokenBalances[1]) == thread.tokenBalances[0].add(thread.tokenBalances[1]), "updated token balances must match sum of thread token balances");

        require(weiBalances[1] >= thread.weiBalances[1] && tokenBalances[1] >= thread.tokenBalances[1], "receiver balances may never decrease");

        // Note: explicitly set threadRoot == 0x0 because then it doesn't get checked by _isContained (updated state is not part of root)
        _verifyThread(sender, receiver, threadId, weiBalances, tokenBalances, txCount, "", sig, bytes32(0x0));

        // save the thread balances and txCount
        thread.weiBalances = weiBalances;
        thread.tokenBalances = tokenBalances;
        thread.txCount = txCount;

        emit DidChallengeThread(
            sender,
            receiver,
            threadId,
            msg.sender,
            thread.weiBalances,
            thread.tokenBalances,
            thread.txCount
        );
    }

    //After the thread state has been finalized onchain, emptyThread can be called to withdraw funds for each channel separately.
    function emptyThread(
        address user,
        address sender,
        address receiver,
        uint256 threadId,
        uint256[2] weiBalances, // [sender, receiver] -> initial balances
        uint256[2] tokenBalances, // [sender, receiver] -> initial balances
        bytes proof,
        string sig
    ) public noReentrancy {
        Channel storage channel = channels[user];
        require(channel.status == ChannelStatus.ThreadDispute, "channel must be in thread dispute");
        require(msg.sender == hub || msg.sender == user, "only hub or user can empty thread");
        require(user == sender || user == receiver, "user must be thread sender or receiver");

        require(weiBalances[1] == 0 && tokenBalances[1] == 0, "initial receiver balances must be zero");

        Thread storage thread = threads[sender][receiver][threadId];

        // We check to make sure that the thread state has been finalized
        require(thread.threadClosingTime != 0 && thread.threadClosingTime < now, "Thread closing time must have passed");

        // Make sure user has not emptied before
        require(!thread.emptied[user == sender ? 0 : 1], "user cannot empty twice");

        // verify initial thread state.
        _verifyThread(sender, receiver, threadId, weiBalances, tokenBalances, 0, proof, sig, channel.threadRoot);

        require(thread.weiBalances[0].add(thread.weiBalances[1]) == weiBalances[0], "sum of thread wei balances must match sender's initial wei balance");
        require(thread.tokenBalances[0].add(thread.tokenBalances[1]) == tokenBalances[0], "sum of thread token balances must match sender's initial token balance");

        // deduct sender/receiver wei/tokens about to be emptied from the thread from the total channel balances
        channel.weiBalances[2] = channel.weiBalances[2].sub(thread.weiBalances[0]).sub(thread.weiBalances[1]);
        channel.tokenBalances[2] = channel.tokenBalances[2].sub(thread.tokenBalances[0]).sub(thread.tokenBalances[1]);

        // deduct wei balances from total channel wei and reset thread balances
        totalChannelWei = totalChannelWei.sub(thread.weiBalances[0]).sub(thread.weiBalances[1]);

        // if user is receiver, send them receiver wei balance
        if (user == receiver) {
            user.transfer(thread.weiBalances[1]);
        // if user is sender, send them remaining sender wei balance
        } else if (user == sender) {
            user.transfer(thread.weiBalances[0]);
        }

        // deduct token balances from channel total balances and reset thread balances
        totalChannelToken = totalChannelToken.sub(thread.tokenBalances[0]).sub(thread.tokenBalances[1]);

        // if user is receiver, send them receiver token balance
        if (user == receiver) {
            require(approvedToken.transfer(user, thread.tokenBalances[1]), "user [receiver] token withdrawal transfer failed");
        // if user is sender, send them remaining sender token balance
        } else if (user == sender) {
            require(approvedToken.transfer(user, thread.tokenBalances[0]), "user [sender] token withdrawal transfer failed");
        }

        // Record that user has emptied
        thread.emptied[user == sender ? 0 : 1] = true;

        // decrement the channel threadCount
        channel.threadCount = channel.threadCount.sub(1);

        // if this is the last thread being emptied, re-open the channel
        if (channel.threadCount == 0) {
            channel.threadRoot = bytes32(0x0);
            channel.channelClosingTime = 0;
            channel.status = ChannelStatus.Open;
        }

        emit DidEmptyThread(
            user,
            sender,
            receiver,
            threadId,
            msg.sender,
            [channel.weiBalances[0], channel.weiBalances[1]],
            [channel.tokenBalances[0], channel.tokenBalances[1]],
            channel.txCount,
            channel.threadRoot,
            channel.threadCount
        );
    }


    // anyone can call to re-open an account stuck in threadDispute after 10x challengePeriods from channel state finalization
    function nukeThreads(
        address user
    ) public noReentrancy {
        require(user != hub, "user can not be hub");
        require(user != address(this), "user can not be channel manager");

        Channel storage channel = channels[user];
        require(channel.status == ChannelStatus.ThreadDispute, "channel must be in thread dispute");
        require(channel.channelClosingTime.add(challengePeriod.mul(10)) < now, "channel closing time must have passed by 10 challenge periods");

        // transfer any remaining channel wei to user
        totalChannelWei = totalChannelWei.sub(channel.weiBalances[2]);
        user.transfer(channel.weiBalances[2]);
        uint256 weiAmount = channel.weiBalances[2];
        channel.weiBalances[2] = 0;

        // transfer any remaining channel tokens to user
        totalChannelToken = totalChannelToken.sub(channel.tokenBalances[2]);
        require(approvedToken.transfer(user, channel.tokenBalances[2]), "user token withdrawal transfer failed");
        uint256 tokenAmount = channel.tokenBalances[2];
        channel.tokenBalances[2] = 0;

        // reset channel params
        channel.threadCount = 0;
        channel.threadRoot = bytes32(0x0);
        channel.channelClosingTime = 0;
        channel.status = ChannelStatus.Open;

        emit DidNukeThreads(
            user,
            msg.sender,
            weiAmount,
            tokenAmount,
            [channel.weiBalances[0], channel.weiBalances[1]],
            [channel.tokenBalances[0], channel.tokenBalances[1]],
            channel.txCount,
            channel.threadRoot,
            channel.threadCount
        );
    }

    function() external payable {}

    // ******************
    // INTERNAL FUNCTIONS
    // ******************

    function _verifyAuthorizedUpdate(
        Channel storage channel,
        uint256[2] txCount,
        uint256[2] weiBalances,
        uint256[2] tokenBalances, // [hub, user]
        uint256[4] pendingWeiUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[4] pendingTokenUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256 timeout,
        bool isHub
    ) internal view {
        require(channel.status == ChannelStatus.Open, "channel must be open");

        // Usage:
        // 1. exchange operations to protect user from exchange rate fluctuations
        // 2. protects hub against user delaying forever
        require(timeout == 0 || now < timeout, "the timeout must be zero or not have passed");

        require(txCount[0] > channel.txCount[0], "global txCount must be higher than the current global txCount");
        require(txCount[1] >= channel.txCount[1], "onchain txCount must be higher or equal to the current onchain txCount");

        // offchain wei/token balances do not exceed onchain total wei/token
        require(weiBalances[0].add(weiBalances[1]) <= channel.weiBalances[2], "wei must be conserved");
        require(tokenBalances[0].add(tokenBalances[1]) <= channel.tokenBalances[2], "tokens must be conserved");

        // hub has enough reserves for wei/token deposits for both the user and itself (if isHub, user deposit comes from hub)
        if (isHub) {
            require(pendingWeiUpdates[0].add(pendingWeiUpdates[2]) <= getHubReserveWei(), "insufficient reserve wei for deposits");
            require(pendingTokenUpdates[0].add(pendingTokenUpdates[2]) <= getHubReserveTokens(), "insufficient reserve tokens for deposits");
        // hub has enough reserves for only its own wei/token deposits
        } else {
            require(pendingWeiUpdates[0] <= getHubReserveWei(), "insufficient reserve wei for deposits");
            require(pendingTokenUpdates[0] <= getHubReserveTokens(), "insufficient reserve tokens for deposits");
        }

        // wei is conserved - the current total channel wei + both deposits > final balances + both withdrawals
        require(channel.weiBalances[2].add(pendingWeiUpdates[0]).add(pendingWeiUpdates[2]) >=
                weiBalances[0].add(weiBalances[1]).add(pendingWeiUpdates[1]).add(pendingWeiUpdates[3]), "insufficient wei");

        // token is conserved - the current total channel token + both deposits > final balances + both withdrawals
        require(channel.tokenBalances[2].add(pendingTokenUpdates[0]).add(pendingTokenUpdates[2]) >=
                tokenBalances[0].add(tokenBalances[1]).add(pendingTokenUpdates[1]).add(pendingTokenUpdates[3]), "insufficient token");
    }

    function _applyPendingUpdates(
        uint256[3] storage channelBalances,
        uint256[2] balances,
        uint256[4] pendingUpdates
    ) internal {
        // update hub balance
        // If the deposit is greater than the withdrawal, add the net of deposit minus withdrawal to the balances.
        // Assumes the net has *not yet* been added to the balances.
        if (pendingUpdates[0] > pendingUpdates[1]) {
            channelBalances[0] = balances[0].add(pendingUpdates[0].sub(pendingUpdates[1]));
        // Otherwise, if the deposit is less than or equal to the withdrawal,
        // Assumes the net has *already* been added to the balances.
        } else {
            channelBalances[0] = balances[0];
        }

        // update user balance
        // If the deposit is greater than the withdrawal, add the net of deposit minus withdrawal to the balances.
        // Assumes the net has *not yet* been added to the balances.
        if (pendingUpdates[2] > pendingUpdates[3]) {
            channelBalances[1] = balances[1].add(pendingUpdates[2].sub(pendingUpdates[3]));

        // Otherwise, if the deposit is less than or equal to the withdrawal,
        // Assumes the net has *already* been added to the balances.
        } else {
            channelBalances[1] = balances[1];
        }
    }

    function _revertPendingUpdates(
        uint256[3] storage channelBalances,
        uint256[2] balances,
        uint256[4] pendingUpdates
    ) internal {
        // If the pending update has NOT been executed AND deposits > withdrawals, offchain state was NOT updated with delta, and is thus correct
        if (pendingUpdates[0] > pendingUpdates[1]) {
            channelBalances[0] = balances[0];

        // If the pending update has NOT been executed AND deposits < withdrawals, offchain state should have been updated with delta, and must be reverted
        } else {
            channelBalances[0] = balances[0].add(pendingUpdates[1].sub(pendingUpdates[0])); // <- add withdrawal, sub deposit (opposite order as _applyPendingUpdates)
        }

        // If the pending update has NOT been executed AND deposits > withdrawals, offchain state was NOT updated with delta, and is thus correct
        if (pendingUpdates[2] > pendingUpdates[3]) {
            channelBalances[1] = balances[1];

        // If the pending update has NOT been executed AND deposits > withdrawals, offchain state should have been updated with delta, and must be reverted
        } else {
            channelBalances[1] = balances[1].add(pendingUpdates[3].sub(pendingUpdates[2])); // <- add withdrawal, sub deposit (opposite order as _applyPendingUpdates)
        }
    }

    function _updateChannelBalances(
        Channel storage channel,
        uint256[2] weiBalances,
        uint256[2] tokenBalances,
        uint256[4] pendingWeiUpdates,
        uint256[4] pendingTokenUpdates
    ) internal {
        _applyPendingUpdates(channel.weiBalances, weiBalances, pendingWeiUpdates);
        _applyPendingUpdates(channel.tokenBalances, tokenBalances, pendingTokenUpdates);

        totalChannelWei = totalChannelWei.add(pendingWeiUpdates[0]).add(pendingWeiUpdates[2]).sub(pendingWeiUpdates[1]).sub(pendingWeiUpdates[3]);
        totalChannelToken = totalChannelToken.add(pendingTokenUpdates[0]).add(pendingTokenUpdates[2]).sub(pendingTokenUpdates[1]).sub(pendingTokenUpdates[3]);

        // update channel total balances
        channel.weiBalances[2] = channel.weiBalances[2].add(pendingWeiUpdates[0]).add(pendingWeiUpdates[2]).sub(pendingWeiUpdates[1]).sub(pendingWeiUpdates[3]);
        channel.tokenBalances[2] = channel.tokenBalances[2].add(pendingTokenUpdates[0]).add(pendingTokenUpdates[2]).sub(pendingTokenUpdates[1]).sub(pendingTokenUpdates[3]);
    }

    function _verifySig (
        address[2] user, // [user, recipient]
        uint256[2] weiBalances, // [hub, user]
        uint256[2] tokenBalances, // [hub, user]
        uint256[4] pendingWeiUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[4] pendingTokenUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
        uint256[2] txCount, // [global, onchain] persisted onchain even when empty
        bytes32 threadRoot,
        uint256 threadCount,
        uint256 timeout,
        string sigHub,
        string sigUser,
        bool[2] checks // [checkHubSig?, checkUserSig?]
    ) internal view {
        require(user[0] != hub, "user can not be hub");
        require(user[0] != address(this), "user can not be channel manager");

        // prepare state hash to check hub sig
        bytes32 state = keccak256(
            abi.encodePacked(
                address(this),
                user, // [user, recipient]
                weiBalances, // [hub, user]
                tokenBalances, // [hub, user]
                pendingWeiUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
                pendingTokenUpdates, // [hubDeposit, hubWithdrawal, userDeposit, userWithdrawal]
                txCount, // persisted onchain even when empty
                threadRoot,
                threadCount,
                timeout
            )
        );

        if (checks[0]) {
            require(hub == ECTools.recoverSigner(state, sigHub), "hub signature invalid");
        }

        if (checks[1]) {
            require(user[0] == ECTools.recoverSigner(state, sigUser), "user signature invalid");
        }
    }

    function _verifyThread(
        address sender,
        address receiver,
        uint256 threadId,
        uint256[2] weiBalances,
        uint256[2] tokenBalances,
        uint256 txCount,
        bytes proof,
        string sig,
        bytes32 threadRoot
    ) internal view {
        require(sender != receiver, "sender can not be receiver");
        require(sender != hub && receiver != hub, "hub can not be sender or receiver");
        require(sender != address(this) && receiver != address(this), "channel manager can not be sender or receiver");

        bytes32 state = keccak256(
            abi.encodePacked(
                address(this),
                sender,
                receiver,
                threadId,
                weiBalances, // [sender, receiver]
                tokenBalances, // [sender, receiver]
                txCount // persisted onchain even when empty
            )
        );
        require(ECTools.isSignedBy(state, sig, sender), "signature invalid");

        if (threadRoot != bytes32(0x0)) {
            require(_isContained(state, proof, threadRoot), "initial thread state is not contained in threadRoot");
        }
    }

    function _isContained(bytes32 _hash, bytes _proof, bytes32 _root) internal pure returns (bool) {
        bytes32 cursor = _hash;
        bytes32 proofElem;

        for (uint256 i = 64; i <= _proof.length; i += 32) {
            assembly { proofElem := mload(add(_proof, i)) }

            if (cursor < proofElem) {
                cursor = keccak256(abi.encodePacked(cursor, proofElem));
            } else {
                cursor = keccak256(abi.encodePacked(proofElem, cursor));
            }
        }

        return cursor == _root;
    }

    function getChannelBalances(address user) constant public returns (
        uint256 weiHub,
        uint256 weiUser,
        uint256 weiTotal,
        uint256 tokenHub,
        uint256 tokenUser,
        uint256 tokenTotal
    ) {
        Channel memory channel = channels[user];
        return (
            channel.weiBalances[0],
            channel.weiBalances[1],
            channel.weiBalances[2],
            channel.tokenBalances[0],
            channel.tokenBalances[1],
            channel.tokenBalances[2]
        );
    }

    function getChannelDetails(address user) constant public returns (
        uint256 txCountGlobal,
        uint256 txCountChain,
        bytes32 threadRoot,
        uint256 threadCount,
        address exitInitiator,
        uint256 channelClosingTime,
        ChannelStatus status
    ) {
        Channel memory channel = channels[user];
        return (
            channel.txCount[0],
            channel.txCount[1],
            channel.threadRoot,
            channel.threadCount,
            channel.exitInitiator,
            channel.channelClosingTime,
            channel.status
        );
    }
}

Contract Security Audit

Contract ABI

[{"constant":true,"inputs":[],"name":"totalChannelWei","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"weiAmount","type":"uint256"},{"name":"tokenAmount","type":"uint256"}],"name":"hubContractWithdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address"},{"name":"threadMembers","type":"address[2]"},{"name":"threadId","type":"uint256"},{"name":"weiBalances","type":"uint256[2]"},{"name":"tokenBalances","type":"uint256[2]"},{"name":"proof","type":"bytes"},{"name":"sig","type":"string"},{"name":"updatedWeiBalances","type":"uint256[2]"},{"name":"updatedTokenBalances","type":"uint256[2]"},{"name":"updatedTxCount","type":"uint256"},{"name":"updateSig","type":"string"}],"name":"startExitThreadWithUpdate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"sender","type":"address"},{"name":"receiver","type":"address"},{"name":"threadId","type":"uint256"},{"name":"weiBalances","type":"uint256[2]"},{"name":"tokenBalances","type":"uint256[2]"},{"name":"txCount","type":"uint256"},{"name":"sig","type":"string"}],"name":"challengeThread","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalChannelToken","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"hub","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"user","type":"address"}],"name":"getChannelBalances","outputs":[{"name":"weiHub","type":"uint256"},{"name":"weiUser","type":"uint256"},{"name":"weiTotal","type":"uint256"},{"name":"tokenHub","type":"uint256"},{"name":"tokenUser","type":"uint256"},{"name":"tokenTotal","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address"}],"name":"emptyChannel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address"},{"name":"recipient","type":"address"},{"name":"weiBalances","type":"uint256[2]"},{"name":"tokenBalances","type":"uint256[2]"},{"name":"pendingWeiUpdates","type":"uint256[4]"},{"name":"pendingTokenUpdates","type":"uint256[4]"},{"name":"txCount","type":"uint256[2]"},{"name":"threadRoot","type":"bytes32"},{"name":"threadCount","type":"uint256"},{"name":"timeout","type":"uint256"},{"name":"sigUser","type":"string"}],"name":"hubAuthorizedUpdate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address[2]"},{"name":"weiBalances","type":"uint256[2]"},{"name":"tokenBalances","type":"uint256[2]"},{"name":"pendingWeiUpdates","type":"uint256[4]"},{"name":"pendingTokenUpdates","type":"uint256[4]"},{"name":"txCount","type":"uint256[2]"},{"name":"threadRoot","type":"bytes32"},{"name":"threadCount","type":"uint256"},{"name":"timeout","type":"uint256"},{"name":"sigHub","type":"string"},{"name":"sigUser","type":"string"}],"name":"startExitWithUpdate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address"}],"name":"startExit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"user","type":"address"}],"name":"getChannelDetails","outputs":[{"name":"txCountGlobal","type":"uint256"},{"name":"txCountChain","type":"uint256"},{"name":"threadRoot","type":"bytes32"},{"name":"threadCount","type":"uint256"},{"name":"exitInitiator","type":"address"},{"name":"channelClosingTime","type":"uint256"},{"name":"status","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address"}],"name":"nukeThreads","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"channels","outputs":[{"name":"threadRoot","type":"bytes32"},{"name":"threadCount","type":"uint256"},{"name":"exitInitiator","type":"address"},{"name":"channelClosingTime","type":"uint256"},{"name":"status","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getHubReserveTokens","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address[2]"},{"name":"weiBalances","type":"uint256[2]"},{"name":"tokenBalances","type":"uint256[2]"},{"name":"pendingWeiUpdates","type":"uint256[4]"},{"name":"pendingTokenUpdates","type":"uint256[4]"},{"name":"txCount","type":"uint256[2]"},{"name":"threadRoot","type":"bytes32"},{"name":"threadCount","type":"uint256"},{"name":"timeout","type":"uint256"},{"name":"sigHub","type":"string"},{"name":"sigUser","type":"string"}],"name":"emptyChannelWithChallenge","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"NAME","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getHubReserveWei","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address"},{"name":"sender","type":"address"},{"name":"receiver","type":"address"},{"name":"threadId","type":"uint256"},{"name":"weiBalances","type":"uint256[2]"},{"name":"tokenBalances","type":"uint256[2]"},{"name":"proof","type":"bytes"},{"name":"sig","type":"string"}],"name":"emptyThread","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"approvedToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address"},{"name":"sender","type":"address"},{"name":"receiver","type":"address"},{"name":"threadId","type":"uint256"},{"name":"weiBalances","type":"uint256[2]"},{"name":"tokenBalances","type":"uint256[2]"},{"name":"proof","type":"bytes"},{"name":"sig","type":"string"}],"name":"startExitThread","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"recipient","type":"address"},{"name":"weiBalances","type":"uint256[2]"},{"name":"tokenBalances","type":"uint256[2]"},{"name":"pendingWeiUpdates","type":"uint256[4]"},{"name":"pendingTokenUpdates","type":"uint256[4]"},{"name":"txCount","type":"uint256[2]"},{"name":"threadRoot","type":"bytes32"},{"name":"threadCount","type":"uint256"},{"name":"timeout","type":"uint256"},{"name":"sigHub","type":"string"}],"name":"userAuthorizedUpdate","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"challengePeriod","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"VERSION","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_hub","type":"address"},{"name":"_challengePeriod","type":"uint256"},{"name":"_tokenAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"weiAmount","type":"uint256"},{"indexed":false,"name":"tokenAmount","type":"uint256"}],"name":"DidHubContractWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"senderIdx","type":"uint256"},{"indexed":false,"name":"weiBalances","type":"uint256[2]"},{"indexed":false,"name":"tokenBalances","type":"uint256[2]"},{"indexed":false,"name":"pendingWeiUpdates","type":"uint256[4]"},{"indexed":false,"name":"pendingTokenUpdates","type":"uint256[4]"},{"indexed":false,"name":"txCount","type":"uint256[2]"},{"indexed":false,"name":"threadRoot","type":"bytes32"},{"indexed":false,"name":"threadCount","type":"uint256"}],"name":"DidUpdateChannel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"senderIdx","type":"uint256"},{"indexed":false,"name":"weiBalances","type":"uint256[2]"},{"indexed":false,"name":"tokenBalances","type":"uint256[2]"},{"indexed":false,"name":"txCount","type":"uint256[2]"},{"indexed":false,"name":"threadRoot","type":"bytes32"},{"indexed":false,"name":"threadCount","type":"uint256"}],"name":"DidStartExitChannel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"senderIdx","type":"uint256"},{"indexed":false,"name":"weiBalances","type":"uint256[2]"},{"indexed":false,"name":"tokenBalances","type":"uint256[2]"},{"indexed":false,"name":"txCount","type":"uint256[2]"},{"indexed":false,"name":"threadRoot","type":"bytes32"},{"indexed":false,"name":"threadCount","type":"uint256"}],"name":"DidEmptyChannel","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"user","type":"address"},{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"receiver","type":"address"},{"indexed":false,"name":"threadId","type":"uint256"},{"indexed":false,"name":"senderAddress","type":"address"},{"indexed":false,"name":"weiBalances","type":"uint256[2]"},{"indexed":false,"name":"tokenBalances","type":"uint256[2]"},{"indexed":false,"name":"txCount","type":"uint256"}],"name":"DidStartExitThread","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"receiver","type":"address"},{"indexed":false,"name":"threadId","type":"uint256"},{"indexed":false,"name":"senderAddress","type":"address"},{"indexed":false,"name":"weiBalances","type":"uint256[2]"},{"indexed":false,"name":"tokenBalances","type":"uint256[2]"},{"indexed":false,"name":"txCount","type":"uint256"}],"name":"DidChallengeThread","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"user","type":"address"},{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"receiver","type":"address"},{"indexed":false,"name":"threadId","type":"uint256"},{"indexed":false,"name":"senderAddress","type":"address"},{"indexed":false,"name":"channelWeiBalances","type":"uint256[2]"},{"indexed":false,"name":"channelTokenBalances","type":"uint256[2]"},{"indexed":false,"name":"channelTxCount","type":"uint256[2]"},{"indexed":false,"name":"channelThreadRoot","type":"bytes32"},{"indexed":false,"name":"channelThreadCount","type":"uint256"}],"name":"DidEmptyThread","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"senderAddress","type":"address"},{"indexed":false,"name":"weiAmount","type":"uint256"},{"indexed":false,"name":"tokenAmount","type":"uint256"},{"indexed":false,"name":"channelWeiBalances","type":"uint256[2]"},{"indexed":false,"name":"channelTokenBalances","type":"uint256[2]"},{"indexed":false,"name":"channelTxCount","type":"uint256[2]"},{"indexed":false,"name":"channelThreadRoot","type":"bytes32"},{"indexed":false,"name":"channelThreadCount","type":"uint256"}],"name":"DidNukeThreads","type":"event"}]

60806040523480156200001157600080fd5b5060405160608062005e8683398101806040526200003391908101906200008e565b60008054600160a060020a03948516600160a060020a03199182161790915560019290925560028054919093169116179055620000f1565b6000620000798251620000e2565b9392505050565b6000620000798251620000ee565b600080600060608486031215620000a457600080fd5b6000620000b286866200006b565b9350506020620000c58682870162000080565b9250506040620000d8868287016200006b565b9150509250925092565b600160a060020a031690565b90565b615d8580620001016000396000f3006080604052600436106101235763ffffffff60e060020a6000350416629e8690811461012557806301dd7da9146101505780630955acd41461017057806325c29be01461019057806332b573e1146101b0578063365a86fc146101c557806345a92009146101e75780634e2a5c5a14610219578063686bf4601461023957806369f817761461025957806372cc174c1461027957806374c25c20146102995780637651a86b146102cc5780637dce34f7146102ec5780639bcf63cd1461031d578063a1e1fe9314610332578063a3f4df7e14610352578063ad872d0314610374578063b04993ef14610389578063bab46259146103a9578063c8b2f7d6146103cb578063ea682e37146103eb578063f3f480d9146103fe578063ffa1ad7414610413575b005b34801561013157600080fd5b5061013a610428565b6040516101479190615a0a565b60405180910390f35b34801561015c57600080fd5b5061012361016b366004614383565b61042e565b34801561017c57600080fd5b5061012361018b36600461403b565b610604565b34801561019c57600080fd5b506101236101ab366004613f86565b61099b565b3480156101bc57600080fd5b5061013a610c1e565b3480156101d157600080fd5b506101da610c24565b6040516101479190615393565b3480156101f357600080fd5b50610207610202366004613d5a565b610c33565b60405161014796959493929190615ad0565b34801561022557600080fd5b50610123610234366004613d5a565b610d8f565b34801561024557600080fd5b50610123610254366004613e7e565b611159565b34801561026557600080fd5b50610123610274366004614246565b611396565b34801561028557600080fd5b50610123610294366004613d5a565b61168c565b3480156102a557600080fd5b506102b96102b4366004613d5a565b611818565b6040516101479796959493929190615a68565b3480156102d857600080fd5b506101236102e7366004613d5a565b611982565b3480156102f857600080fd5b5061030c610307366004613d5a565b611c8a565b60405161014795949392919061555f565b34801561032957600080fd5b5061013a611cc9565b34801561033e57600080fd5b5061012361034d366004614246565b611d5c565b34801561035e57600080fd5b50610367612198565b6040516101479190615679565b34801561038057600080fd5b5061013a6121c4565b34801561039557600080fd5b506101236103a4366004613d9e565b6121dc565b3480156103b557600080fd5b506103be612871565b60405161014791906155ab565b3480156103d757600080fd5b506101236103e6366004613d9e565b612880565b6101236103f9366004614152565b612aaf565b34801561040a57600080fd5b5061013a612daf565b34801561041f57600080fd5b50610367612db5565b60035481565b60075460ff161561045d5760405160e560020a62461bcd028152600401610454906157ba565b60405180910390fd5b6007805460ff1916600117905560005433600160a060020a039091161461048357600080fd5b8161048c6121c4565b10156104ad5760405160e560020a62461bcd0281526004016104549061585a565b806104b6611cc9565b10156104d75760405160e560020a62461bcd028152600401610454906157ea565b60008054604051600160a060020a039091169184156108fc02918591818181858888f19350505050158015610510573d6000803e3d6000fd5b5060025460005460405160e060020a63a9059cbb028152600160a060020a039283169263a9059cbb9261054a9291169085906004016153cf565b602060405180830381600087803b15801561056457600080fd5b505af1158015610578573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061059c9190810190614347565b15156105bd5760405160e560020a62461bcd0281526004016104549061581a565b7f60a3ff34ec09137572f54ff0fde3035ae459c9bebfdb1643a897de83211ebdf082826040516105ee929190615a5a565b60405180910390a150506007805460ff19169055565b600754600090819060ff161561062f5760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff19166001179055600160a060020a038d16600090815260056020526040902091506002600c83015460ff16600281111561066b57fe5b1461068b5760405160e560020a62461bcd0281526004016104549061598a565b600054600160a060020a03163314806106ac575033600160a060020a038e16145b15156106cd5760405160e560020a62461bcd028152600401610454906158ea565b8b51600160a060020a038e8116911614806106f7575060208c0151600160a060020a038e81169116145b15156107185760405160e560020a62461bcd028152600401610454906159fa565b60208a015115801561072c57506020890151155b151561074d5760405160e560020a62461bcd0281526004016104549061587a565b8b51600160a060020a03166000908152600660205260408120908d60016020020151600160a060020a0316600160a060020a0316815260200190815260200160002060008c81526020019081526020016000209050806005015460001415156107cb5760405160e560020a62461bcd0281526004016104549061579a565b6107ef8c600060200201518d600160200201518d8d8d60008e8e8a60080154612dd7565b600084116108125760405160e560020a62461bcd0281526004016104549061595a565b89516108358760015b60200201518860005b60200201519063ffffffff6130c016565b146108555760405160e560020a62461bcd0281526004016104549061589a565b885161086b8660015b6020020151876000610824565b1461088b5760405160e560020a62461bcd028152600401610454906157ca565b8b516020808e015160408051928301905260008083526108b693928f918b918b918b91908b90612dd7565b6108c281876002613aac565b506108d36002808301908790613aac565b50600481018490556001546108ef90429063ffffffff6130c016565b60058201558b60016020020151600160a060020a03168c60006020020151600160a060020a0316600080516020615ccc8339815191528f8e6000809054906101000a9004600160a060020a0316600160a060020a031633600160a060020a03161461095b57600161095e565b60005b600487015460405161097a9493929189916002830191906154e7565b60405180910390a350506007805460ff191690555050505050505050505050565b60075460009060ff16156109c45760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff1916600117905560005433600160a060020a0390911614806109f4575033600160a060020a038916145b80610a07575033600160a060020a038816145b1515610a285760405160e560020a62461bcd028152600401610454906159ea565b50600160a060020a038088166000908152600660209081526040808320938a16835292815282822088835290522060058101544210610a7c5760405160e560020a62461bcd0281526004016104549061586a565b60048101548311610aa25760405160e560020a62461bcd028152600401610454906159da565b610abc81600101548260005b01549063ffffffff6130c016565b610ac786600161085e565b14610ae75760405160e560020a62461bcd0281526004016104549061574a565b6003810154610afb90600283016000610aae565b6020850151610b0c90866000610824565b14610b2c5760405160e560020a62461bcd0281526004016104549061583a565b6001810154602086015110801590610b4c57506003810154602085015110155b1515610b6d5760405160e560020a62461bcd0281526004016104549061571a565b610b928888888888886020604051908101604052806000815250896000600102612dd7565b610b9e81866002613aac565b50610baf6002808301908690613aac565b5060048101839055604051600160a060020a0380891691908a16907f738f3bb8a8a2b4d0dc29a4076d3a4e41e510cd1044877421546903039766ad1990610c02908a903390879060028201908b90615a18565b60405180910390a350506007805460ff19169055505050505050565b60045481565b600054600160a060020a031681565b600080600080600080610c44613aea565b600160a060020a03881660009081526005602052604090819020815161016081019092528161010081018260038282826020028201915b815481526020019060010190808311610c7b5750505091835250506040805160608101918290526020909201919060038481019182845b815481526020019060010190808311610cb2575050509183525050604080518082019182905260209092019190600684019060029082845b815481526020019060010190808311610cea5750505091835250506008820154602082015260098201546040820152600a820154600160a060020a03166060820152600b8201546080820152600c82015460a09091019060ff166002811115610d4f57fe5b6002811115610d5a57fe5b9052508051805160208083015160409384015194820151805192810151940151929d909c50939a509850909650945092505050565b60075460009060ff1615610db85760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff19166001179055600054600160a060020a0383811691161415610df65760405160e560020a62461bcd0281526004016104549061592a565b600160a060020a038216301415610e225760405160e560020a62461bcd0281526004016104549061599a565b50600160a060020a03811660009081526005602052604090206001600c82015460ff166002811115610e5057fe5b14610e705760405160e560020a62461bcd0281526004016104549061573a565b4281600b01541080610eb65750600a810154600160a060020a03163314801590610eb65750600054600160a060020a0316331480610eb6575033600160a060020a038316145b1515610ed75760405160e560020a62461bcd028152600401610454906159aa565b610f048160015b01548254610ef8908460025b01549063ffffffff6130dd16565b9063ffffffff6130dd16565b8160020155610f266003820160015b0154600383018054610ef8916002610eea565b6005820155610f4c8160015b0154610ef88360005b01546003549063ffffffff6130dd16565b6003556001810154604051600160a060020a0384169180156108fc02916000818181858888f19350505050158015610f88573d6000803e3d6000fd5b5060008181015560008160010155610fbd6003820160015b0154610ef86003840160005b01546004549063ffffffff6130dd16565b600455600254600160a060020a031663a9059cbb8360038401600101546040518363ffffffff1660e060020a028152600401610ffa9291906153cf565b602060405180830381600087803b15801561101457600080fd5b505af1158015611028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061104c9190810190614347565b151561106d5760405160e560020a62461bcd0281526004016104549061570a565b600060038201819055600482018190556009820154111561109c57600c8101805460ff191660021790556110b0565b6000600b820155600c8101805460ff191690555b600a81018054600160a060020a0319169055600054600160a060020a0383811691600080516020615d2c833981519152911633146110ef5760016110f2565b60005b6040805180820182528554815260018601546020808301919091528251808401845260038801548152600488015491810191909152600887015460098801549351611143959460068a019291615b1f565b60405180910390a250506007805460ff19169055565b60075460009060ff16156111825760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff1916600117905560005433600160a060020a03909116146111a857600080fd5b50600160a060020a038b1660009081526005602052604090206111d281878c8c8c8c8960016130f4565b604080518082018252600160a060020a03808f1682528d166020808301919091528251808201845260008082528451808601909552845260019184019190915261122d928d918d918d918d918d918d918d918d918d906133b8565b61123a818b8b8b8b613781565b6060880151604051600160a060020a038d169180156108fc02916000818181858888f19350505050158015611273573d6000803e3d6000fd5b50600254606088015160405160e060020a63a9059cbb028152600160a060020a039092169163a9059cbb916112ad918f91906004016153cf565b602060405180830381600087803b1580156112c757600080fd5b505af11580156112db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112ff9190810190614347565b15156113205760405160e560020a62461bcd0281526004016104549061570a565b61132f60068201876002613aac565b506008810185905560098101849055604051600160a060020a038d1690600080516020615cec83398151915290611376906000908e908e908e908e908e908e908e906155b9565b60405180910390a250506007805460ff1916905550505050505050505050565b60075460009060ff16156113bf5760405160e560020a62461bcd028152600401610454906157ba565b506007805460ff191660011790558a51600160a060020a0316600090815260056020526040812090600c82015460ff1660028111156113fa57fe5b1461141a5760405160e560020a62461bcd0281526004016104549061577a565b600054600160a060020a031633148061143c57508b51600160a060020a031633145b151561145d5760405160e560020a62461bcd0281526004016104549061597a565b831561147e5760405160e560020a62461bcd0281526004016104549061582a565b6114b08c8c8c8c8c8c8c8c8c8c8c604080519081016040528060011515151581526020016001151515158152506133b8565b60068101548751116114d75760405160e560020a62461bcd028152600401610454906158aa565b6007810154602088015110156115025760405160e560020a62461bcd028152600401610454906156aa565b806002015461151b8c60015b60200201518d6000610824565b111561153c5760405160e560020a62461bcd028152600401610454906156ca565b60058101546115558b60015b60200201518c6000610824565b11156115765760405160e560020a62461bcd0281526004016104549061584a565b6007810154602088015114156115a457611591818c8b613852565b61159f816003018b8a613852565b6115bd565b6115af818c8b6138e0565b6115bd816003018b8a6138e0565b865160068201556008810186905560098101859055600a81018054600160a060020a031916331790556001546115f49042906130c0565b600b820155600c8101805460ff191660011790558b51600054600160a060020a0391821691600080516020615cac833981519152913391161461163857600161163b565b60005b6040805180820182528554815260018601546020808301919091528251808401845260038801548152600488015491810191909152600887015460098801549351611376959460068a019291615b1f565b60075460009060ff16156116b55760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff19166001179055600054600160a060020a03838116911614156116f35760405160e560020a62461bcd0281526004016104549061592a565b600160a060020a03821630141561171f5760405160e560020a62461bcd0281526004016104549061599a565b50600160a060020a038116600090815260056020526040812090600c82015460ff16600281111561174c57fe5b1461176c5760405160e560020a62461bcd0281526004016104549061577a565b600054600160a060020a031633148061178d575033600160a060020a038316145b15156117ae5760405160e560020a62461bcd0281526004016104549061597a565b600a81018054600160a060020a031916331790556001546117d690429063ffffffff6130c016565b600b820155600c8101805460ff19166001179055600054600160a060020a0383811691600080516020615cac83398151915291339116146110ef5760016110f2565b600080600080600080600061182b613aea565b600160a060020a03891660009081526005602052604090819020815161016081019092528161010081018260038282826020028201915b8154815260200190600101908083116118625750505091835250506040805160608101918290526020909201919060038481019182845b815481526020019060010190808311611899575050509183525050604080518082019182905260209092019190600684019060029082845b8154815260200190600101908083116118d15750505091835250506008820154602082015260098201546040820152600a820154600160a060020a03166060820152600b8201546080820152600c82015460a09091019060ff16600281111561193657fe5b600281111561194157fe5b905250604081015180516020909101516060830151608084015160a085015160c086015160e090960151949f939e50919c509a509850919650945092505050565b6007546000908190819060ff16156119af5760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff19166001179055600054600160a060020a03858116911614156119ed5760405160e560020a62461bcd0281526004016104549061592a565b600160a060020a038416301415611a195760405160e560020a62461bcd0281526004016104549061599a565b600160a060020a038416600090815260056020526040902092506002600c84015460ff166002811115611a4857fe5b14611a685760405160e560020a62461bcd0281526004016104549061590a565b42611a93611a82600a60015461394690919063ffffffff16565b600b8601549063ffffffff6130c016565b10611ab35760405160e560020a62461bcd0281526004016104549061569a565b611abe836002610f3b565b6003556002830154604051600160a060020a0386169180156108fc02916000818181858888f19350505050158015611afa573d6000803e3d6000fd5b508260020154915060008360020155611b17600384016002610fac565b6004908155600254600585015460405160e060020a63a9059cbb028152600160a060020a039092169263a9059cbb92611b549289929091016153cf565b602060405180830381600087803b158015611b6e57600080fd5b505af1158015611b82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611ba69190810190614347565b1515611bc75760405160e560020a62461bcd0281526004016104549061570a565b506005820180546000918290556009840182905560088401829055600b8401829055600c8401805460ff19169055604080518082018252855481526001860154602080830191909152825180840184526003880154815260048801549181019190915291519293600160a060020a038816937f02d2d0f262d032138bbd82feccd6d357a4441f394333cfa7d61792f44a70a0ed93611c72933393899389939160068d019181906154be565b60405180910390a250506007805460ff191690555050565b600560205260009081526040902060088101546009820154600a830154600b840154600c9094015492939192600160a060020a03909116919060ff1685565b6004805460025460405160e060020a6370a08231028152600093611d569392600160a060020a0316916370a0823191611d0491309101615393565b602060405180830381600087803b158015611d1e57600080fd5b505af1158015611d32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ef89190810190614365565b90505b90565b60075460009060ff1615611d855760405160e560020a62461bcd028152600401610454906157ba565b506007805460ff191660019081179091558b51600160a060020a0316600090815260056020526040902090600c82015460ff166002811115611dc357fe5b14611de35760405160e560020a62461bcd0281526004016104549061573a565b600b8101544210611e095760405160e560020a62461bcd028152600401610454906156fa565b600a810154600160a060020a0316331415611e395760405160e560020a62461bcd0281526004016104549061578a565b600054600160a060020a0316331480611e5b57508b51600160a060020a031633145b1515611e7c5760405160e560020a62461bcd0281526004016104549061588a565b8315611e9d5760405160e560020a62461bcd0281526004016104549061582a565b611ecf8c8c8c8c8c8c8c8c8c8c8c604080519081016040528060011515151581526020016001151515158152506133b8565b6006810154875111611ef65760405160e560020a62461bcd028152600401610454906158aa565b600781015460208801511015611f215760405160e560020a62461bcd028152600401610454906156aa565b8060020154611f318c600161150e565b1115611f525760405160e560020a62461bcd028152600401610454906156ca565b6005810154611f628b6001611548565b1115611f835760405160e560020a62461bcd0281526004016104549061584a565b600781015460208801511415611fb157611f9e818c8b613852565b611fac816003018b8a613852565b611fca565b611fbc818c8b6138e0565b611fca816003018b8a6138e0565b611fd5816001610ede565b8160020155611fe8600382016001610f13565b6005820155611ff8816001610f32565b6003558b516001820154604051600160a060020a039092169181156108fc0291906000818181858888f19350505050158015612038573d6000803e3d6000fd5b5060008181015560008160010155612054600382016001610fa0565b60049081556002548d518383015460405160e060020a63a9059cbb028152600160a060020a039093169363a9059cbb93612090939291016153cf565b602060405180830381600087803b1580156120aa57600080fd5b505af11580156120be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506120e29190810190614347565b15156121035760405160e560020a62461bcd0281526004016104549061570a565b6000600382018190556004820181905587516006830155600882018790556009820186905585111561214357600c8101805460ff19166002179055612157565b6000600b820155600c8101805460ff191690555b600a81018054600160a060020a03191690558b51600054600160a060020a0391821691600080516020615d2c8339815191529116331461163857600161163b565b60408051808201909152600f8152608960020a6e21b430b73732b61026b0b730b3b2b902602082015281565b600354600090611d569030319063ffffffff6130dd16565b600754600090819060ff16156122075760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff19166001179055600160a060020a038a16600090815260056020526040902091506002600c83015460ff16600281111561224357fe5b146122635760405160e560020a62461bcd0281526004016104549061590a565b600054600160a060020a0316331480612284575033600160a060020a038b16145b15156122a55760405160e560020a62461bcd028152600401610454906156ba565b88600160a060020a03168a600160a060020a031614806122d6575087600160a060020a03168a600160a060020a0316145b15156122f75760405160e560020a62461bcd028152600401610454906159fa565b602086015115801561230b57506020850151155b151561232c5760405160e560020a62461bcd0281526004016104549061587a565b50600160a060020a038089166000908152600660209081526040808320938b1683529281528282208983529052206005810154158015906123705750428160050154105b15156123915760405160e560020a62461bcd0281526004016104549061591a565b8060060189600160a060020a03168b600160a060020a0316146123b55760016123b8565b60005b60ff16600281106123c557fe5b602081049091015460ff601f9092166101000a900416156123fb5760405160e560020a62461bcd0281526004016104549061580a565b612411898989898960008a8a8a60080154612dd7565b8551600182015461242490836000610aae565b146124445760405160e560020a62461bcd028152600401610454906158ca565b8451600382015461245a90600284016000610aae565b1461247a5760405160e560020a62461bcd0281526004016104549061593a565b6124928160010154610ef88360000154856002610eea565b82600201556124b86002820160010154610ef86002840160000154600386016002610eea565b600583015560018101546124d190610ef8836000610f3b565b600355600160a060020a038a81169089161415612527576001810154604051600160a060020a038c169180156108fc02916000818181858888f19350505050158015612521573d6000803e3d6000fd5b50612579565b88600160a060020a03168a600160a060020a03161415612579578054604051600160a060020a038c169180156108fc02916000818181858888f19350505050158015612577573d6000803e3d6000fd5b505b600381015461259090610ef8600284016000610fac565b600455600160a060020a038a8116908916141561265857600254600382015460405160e060020a63a9059cbb028152600160a060020a039092169163a9059cbb916125e0918e91906004016153cf565b602060405180830381600087803b1580156125fa57600080fd5b505af115801561260e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126329190810190614347565b15156126535760405160e560020a62461bcd028152600401610454906159ba565b61271e565b88600160a060020a03168a600160a060020a0316141561271e57600280549082015460405160e060020a63a9059cbb028152600160a060020a039092169163a9059cbb916126ab918e91906004016153cf565b602060405180830381600087803b1580156126c557600080fd5b505af11580156126d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126fd9190810190614347565b151561271e5760405160e560020a62461bcd0281526004016104549061596a565b6001816006018a600160a060020a03168c600160a060020a031614612744576001612747565b60005b60ff166002811061275457fe5b602091828204019190066101000a81548160ff02191690831515021790555061278b600183600901546130dd90919063ffffffff16565b6009830181905515156127b357600060088301819055600b830155600c8201805460ff191690555b87600160a060020a031689600160a060020a03167ff45587a14ff8928bdd940cbf0564b42320b5e46a8fdecaf8a98a9eab63ab1f968c8a33604080519081016040528089600001600060038110151561280857fe5b0154815260018a015460209182015260408051808201825260038c0154815260048c01549281019290925260088b015460098c0154915161285397969594939260068e0192916153ea565b60405180910390a350506007805460ff191690555050505050505050565b600254600160a060020a031681565b600754600090819060ff16156128ab5760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff19166001179055600160a060020a038a16600090815260056020526040902091506002600c83015460ff1660028111156128e757fe5b146129075760405160e560020a62461bcd0281526004016104549061598a565b600054600160a060020a0316331480612928575033600160a060020a038b16145b15156129495760405160e560020a62461bcd028152600401610454906158ea565b88600160a060020a03168a600160a060020a0316148061297a575087600160a060020a03168a600160a060020a0316145b151561299b5760405160e560020a62461bcd028152600401610454906159fa565b60208601511580156129af57506020850151155b15156129d05760405160e560020a62461bcd0281526004016104549061587a565b50600160a060020a038089166000908152600660209081526040808320938b168352928152828220898352905220600581015415612a235760405160e560020a62461bcd0281526004016104549061579a565b612a39898989898960008a8a8a60080154612dd7565b612a4581876002613aac565b50612a566002808301908790613aac565b50600154612a6b90429063ffffffff6130c016565b60058201556004810154604051600160a060020a03808b1692908c1691600080516020615ccc83398151915291612853918f918d9133918991600283019190615463565b60075460009060ff1615612ad85760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff1916600117905587600260200201513414612b0e5760405160e560020a62461bcd028152600401610454906159ca565b6005600033600160a060020a0316600160a060020a031681526020019081526020016000209050612b4681878c8c8c8c8960006130f4565b604080518082018252338152600160a060020a038d1660208083019190915282518082018452600080825284518086019095526001855291840191909152612ba0928d918d918d918d918d918d918d918d918d91906133b8565b600254604080890151905160e060020a6323b872dd028152600160a060020a03909216916323b872dd91612bda91339130916004016153a7565b602060405180830381600087803b158015612bf457600080fd5b505af1158015612c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c2c9190810190614347565b1515612c4d5760405160e560020a62461bcd028152600401610454906158da565b612c5a818b8b8b8b613781565b6060880151604051600160a060020a038d169180156108fc02916000818181858888f19350505050158015612c93573d6000803e3d6000fd5b50600254606088015160405160e060020a63a9059cbb028152600160a060020a039092169163a9059cbb91612ccd918f91906004016153cf565b602060405180830381600087803b158015612ce757600080fd5b505af1158015612cfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d1f9190810190614347565b1515612d405760405160e560020a62461bcd0281526004016104549061570a565b612d4f60068201876002613aac565b5060088101859055600981018490556040513390600080516020615cec83398151915290612d90906001908e908e908e908e9060068a01908e908e90615627565b60405180910390a250506007805460ff19169055505050505050505050565b60015481565b604080518082019091526005815260d860020a64302e302e3102602082015281565b6000600160a060020a038a8116908a161415612e085760405160e560020a62461bcd028152600401610454906157aa565b600054600160a060020a038b8116911614801590612e345750600054600160a060020a038a8116911614155b1515612e555760405160e560020a62461bcd028152600401610454906158ba565b600160a060020a038a163014801590612e775750600160a060020a0389163014155b1515612e985760405160e560020a62461bcd028152600401610454906156ea565b308a8a8a8a8a8a6040516020018088600160a060020a0316600160a060020a0316606060020a02815260140187600160a060020a0316600160a060020a0316606060020a02815260140186600160a060020a0316600160a060020a0316606060020a02815260140185815260200184600260200280838360005b83811015612f2a578181015183820152602001612f12565b5050505090500183600260200280838360005b83811015612f55578181015183820152602001612f3d565b505050509050018281526020019750505050505050506040516020818303038152906040526040518082805190602001908083835b60208310612fa95780518252601f199092019160209182019101612f8a565b5181516020939093036101000a60001901801990911692169190911790526040519201829003822060e060020a631052506f028352945073b01c6adaf785f06f2c01bcfe782e30ceefa90a269350631052506f92506130119185915087908f90600401615530565b60206040518083038186803b15801561302957600080fd5b505af415801561303d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506130619190810190614347565b15156130825760405160e560020a62461bcd028152600401610454906156da565b81156130b457613093818584613974565b15156130b45760405160e560020a62461bcd0281526004016104549061575a565b50505050505050505050565b6000828201838110156130d257600080fd5b8091505b5092915050565b600080838311156130ed57600080fd5b5050900390565b6000600c89015460ff16600281111561310957fe5b146131295760405160e560020a62461bcd0281526004016104549061577a565b81158061313557508142105b15156131565760405160e560020a62461bcd0281526004016104549061594a565b600688015487511161317d5760405160e560020a62461bcd028152600401610454906158aa565b6007880154602088015110156131a85760405160e560020a62461bcd028152600401610454906156aa565b87600201546131b887600161081b565b11156131d95760405160e560020a62461bcd028152600401610454906156ca565b60058801546131e986600161085e565b111561320a5760405160e560020a62461bcd0281526004016104549061584a565b8015613289576132186121c4565b604085015161322990866000610824565b111561324a5760405160e560020a62461bcd028152600401610454906158fa565b613252611cc9565b604084015161326390856000610824565b11156132845760405160e560020a62461bcd028152600401610454906157fa565b6132df565b6132916121c4565b845111156132b45760405160e560020a62461bcd028152600401610454906158fa565b6132bc611cc9565b835111156132df5760405160e560020a62461bcd028152600401610454906157fa565b60608401516020808601519088015161330d92916133019182908b6000610824565b9063ffffffff6130c016565b604085015161332a906133018760005b60200201518c6002610aae565b101561334b5760405160e560020a62461bcd0281526004016104549061568a565b60608301516020808501519087015161336d92916133019182908a6000610824565b604084015161338d906133018660005b602002015160038d016002610aae565b10156133ae5760405160e560020a62461bcd0281526004016104549061576a565b5050505050505050565b600080548d51600160a060020a03908116911614156133ec5760405160e560020a62461bcd0281526004016104549061592a565b8c51600160a060020a03163014156134195760405160e560020a62461bcd0281526004016104549061599a565b308d8d8d8d8d8d8d8d8d604051602001808b600160a060020a0316600160a060020a0316606060020a0281526014018a600260200280838360005b8381101561346c578181015183820152602001613454565b5050505090500189600260200280838360005b8381101561349757818101518382015260200161347f565b5050505090500188600260200280838360005b838110156134c25781810151838201526020016134aa565b5050505090500187600460200280838360005b838110156134ed5781810151838201526020016134d5565b5050505090500186600460200280838360005b83811015613518578181015183820152602001613500565b5050505090500185600260200280838360005b8381101561354357818101518382015260200161352b565b5050505090500184600019166000191681526020018381526020018281526020019a50505050505050505050506040516020818303038152906040526040518082805190602001908083835b602083106135ae5780518252601f19909201916020918201910161358f565b5181516020939093036101000a600019018019909116921691909117905260405192018290039091209350849250600091506135e79050565b6020020151156136ad5760405160e060020a63dca9541902815273b01c6adaf785f06f2c01bcfe782e30ceefa90a269063dca954199061362d9084908890600401615510565b60206040518083038186803b15801561364557600080fd5b505af4158015613659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061367d9190810190613d80565b600054600160a060020a039081169116146136ad5760405160e560020a62461bcd0281526004016104549061572a565b6020820151156137725760405160e060020a63dca9541902815273b01c6adaf785f06f2c01bcfe782e30ceefa90a269063dca95419906136f39084908790600401615510565b60206040518083038186803b15801561370b57600080fd5b505af415801561371f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506137439190810190613d80565b8d51600160a060020a039081169116146137725760405160e560020a62461bcd028152600401610454906157da565b50505050505050505050505050565b61378c858584613852565b61379a856003018483613852565b60608201516020830151604084015184516003546137c49493610ef89390928492613301916130c0565b60035560608101516020820151604083015183516004546137f19493610ef89390928492613301916130c0565b6004556060820151602083015160408401516138199291610ef891829061330188600061331d565b60028601556060810151602082015160408301516138439291610ef891829061330187600061337d565b60038601600201555050505050565b6020810151815111156138915761388a61388282600160200201518360005b60200201519063ffffffff6130dd16565b836000610824565b8355613896565b815183555b6060810151604082015111156138cf576138c46138bc8260036020020151836002613871565b836001610824565b8360015b01556138db565b60208201518360015b01555b505050565b6020810151815111156138f6578151835561390b565b80516139089061388290836001613871565b83555b6060810151604082015111156139285760208201518360016138c8565b61393e6138bc8260026020020151836003613871565b8360016138d8565b60008083151561395957600091506130d6565b5082820282848281151561396957fe5b04146130d257600080fd5b6000838160405b85518111613a9f5785810151915081831015613a1657604080516020808201869052818301859052825180830384018152606090920192839052815191929182918401908083835b602083106139e25780518252601f1990920191602091820191016139c3565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250613a97565b604080516020808201859052818301869052825180830384018152606090920192839052815191929182918401908083835b60208310613a675780518252601f199092019160209182019101613a48565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902092505b60200161397b565b5050919091149392505050565b8260028101928215613ada579160200282015b82811115613ada578251825591602001919060010190613abf565b50613ae6929150613b42565b5090565b6101a060405190810160405280613aff613b5c565b8152602001613b0c613b5c565b8152602001613b19613b7b565b815260006020820181905260408201819052606082018190526080820181905260a09091015290565b611d5991905b80821115613ae65760008155600101613b48565b6060604051908101604052806003906020820280388339509192915050565b60408051808201825290600290829080388339509192915050565b6000613ba28235615bf6565b9392505050565b6000613ba28251615bf6565b6000601f82018313613bc657600080fd5b6002613bd9613bd482615b96565b615b70565b91508183856020840282011115613bef57600080fd5b60005b83811015613c1b5781613c058882613b96565b8452506020928301929190910190600101613bf2565b5050505092915050565b6000601f82018313613c3657600080fd5b6002613c44613bd482615b96565b91508183856020840282011115613c5a57600080fd5b60005b83811015613c1b5781613c708882613cf3565b8452506020928301929190910190600101613c5d565b6000601f82018313613c9757600080fd5b6004613ca5613bd482615b96565b91508183856020840282011115613cbb57600080fd5b60005b83811015613c1b5781613cd18882613cf3565b8452506020928301929190910190600101613cbe565b6000613ba28251615c14565b6000613ba28235611d59565b6000601f82018313613d1057600080fd5b8135613d1e613bd482615bb3565b91508082526020830160208301858383011115613d3a57600080fd5b613d45838284615c45565b50505092915050565b6000613ba28251611d59565b600060208284031215613d6c57600080fd5b6000613d788484613b96565b949350505050565b600060208284031215613d9257600080fd5b6000613d788484613ba9565b600080600080600080600080610140898b031215613dbb57600080fd5b6000613dc78b8b613b96565b9850506020613dd88b828c01613b96565b9750506040613de98b828c01613b96565b9650506060613dfa8b828c01613cf3565b9550506080613e0b8b828c01613c25565b94505060c0613e1c8b828c01613c25565b9350506101008901356001604060020a03811115613e3957600080fd5b613e458b828c01613cff565b9250506101208901356001604060020a03811115613e6257600080fd5b613e6e8b828c01613cff565b9150509295985092959890939650565b60008060008060008060008060008060006102808c8e031215613ea057600080fd5b6000613eac8e8e613b96565b9b50506020613ebd8e828f01613b96565b9a50506040613ece8e828f01613c25565b9950506080613edf8e828f01613c25565b98505060c0613ef08e828f01613c86565b975050610140613f028e828f01613c86565b9650506101c0613f148e828f01613c25565b955050610200613f268e828f01613cf3565b945050610220613f388e828f01613cf3565b935050610240613f4a8e828f01613cf3565b9250506102608c01356001604060020a03811115613f6757600080fd5b613f738e828f01613cff565b9150509295989b509295989b9093969950565b6000806000806000806000610120888a031215613fa257600080fd5b6000613fae8a8a613b96565b9750506020613fbf8a828b01613b96565b9650506040613fd08a828b01613cf3565b9550506060613fe18a828b01613c25565b94505060a0613ff28a828b01613c25565b93505060e06140038a828b01613cf3565b9250506101008801356001604060020a0381111561402057600080fd5b61402c8a828b01613cff565b91505092959891949750929550565b60008060008060008060008060008060006102008c8e03121561405d57600080fd5b60006140698e8e613b96565b9b5050602061407a8e828f01613bb5565b9a5050606061408b8e828f01613cf3565b995050608061409c8e828f01613c25565b98505060c06140ad8e828f01613c25565b9750506101008c01356001604060020a038111156140ca57600080fd5b6140d68e828f01613cff565b9650506101208c01356001604060020a038111156140f357600080fd5b6140ff8e828f01613cff565b9550506101406141118e828f01613c25565b9450506101806141238e828f01613c25565b9350506101c06141358e828f01613cf3565b9250506101e08c01356001604060020a03811115613f6757600080fd5b6000806000806000806000806000806102608b8d03121561417257600080fd5b600061417e8d8d613b96565b9a5050602061418f8d828e01613c25565b99505060606141a08d828e01613c25565b98505060a06141b18d828e01613c86565b9750506101206141c38d828e01613c86565b9650506101a06141d58d828e01613c25565b9550506101e06141e78d828e01613cf3565b9450506102006141f98d828e01613cf3565b93505061022061420b8d828e01613cf3565b9250506102408b01356001604060020a0381111561422857600080fd5b6142348d828e01613cff565b9150509295989b9194979a5092959850565b60008060008060008060008060008060006102a08c8e03121561426857600080fd5b60006142748e8e613bb5565b9b505060406142858e828f01613c25565b9a505060806142968e828f01613c25565b99505060c06142a78e828f01613c86565b9850506101406142b98e828f01613c86565b9750506101c06142cb8e828f01613c25565b9650506102006142dd8e828f01613cf3565b9550506102206142ef8e828f01613cf3565b9450506102406143018e828f01613cf3565b9350506102608c01356001604060020a0381111561431e57600080fd5b61432a8e828f01613cff565b9250506102808c01356001604060020a03811115613f6757600080fd5b60006020828403121561435957600080fd5b6000613d788484613ce7565b60006020828403121561437757600080fd5b6000613d788484613d4e565b6000806040838503121561439657600080fd5b60006143a28585613cf3565b92505060206143b385828601613cf3565b9150509250929050565b6143c681615bf6565b82525050565b6143d581615bda565b6143de82611d59565b60005b8281101561440e576143f4858351614499565b6143fd82615bea565b6020959095019491506001016143e1565b5050505050565b61441e81615bda565b61442782611d59565b60005b8281101561440e5761443d858354614499565b61444682615bf0565b60209590950194915060010161442a565b61446081615be0565b61446982611d59565b60005b8281101561440e5761447f858351614499565b61448882615bea565b60209590950194915060010161446c565b6143c681611d59565b6143c681615c19565b6143c681615c24565b6143c681615c2f565b60006144c882615be6565b8084526144dc816020860160208601615c51565b6144e581615c81565b9093016020019392505050565b60108152608060020a6f696e73756666696369656e742077656902602082015260400190565b603d8152600080516020615d0c83398151915260208201527f6173736564206279203130206368616c6c656e676520706572696f6473000000604082015260600190565b604681527f6f6e636861696e207478436f756e74206d75737420626520686967686572206f60208201527f7220657175616c20746f207468652063757272656e74206f6e636861696e2074604082015260d260020a651e10dbdd5b9d02606082015260800190565b602181527f6f6e6c7920687562206f7220757365722063616e20656d707479207468726561602082015260fa60020a601902604082015260600190565b60158152605a60020a741dd95a481b5d5cdd0818994818dbdb9cd95c9d995902602082015260400190565b60118152607a60020a701cda59db985d1d5c99481a5b9d985b1a5902602082015260400190565b602d81527f6368616e6e656c206d616e616765722063616e206e6f742062652073656e64656020820152609960020a6c391037b9103932b1b2b4bb32b902604082015260600190565b602981527f6368616e6e656c20636c6f73696e672074696d65206d757374206e6f74206861602082015260ba60020a681d99481c185cdcd95902604082015260600190565b602581527f7573657220746f6b656e207769746864726177616c207472616e736665722066602082015260da60020a64185a5b195902604082015260600190565b602481527f72656365697665722062616c616e636573206d6179206e657665722064656372602082015260e060020a636561736502604082015260600190565b60158152605a60020a741a1d58881cda59db985d1d5c99481a5b9d985b1a5902602082015260400190565b601a81527f6368616e6e656c206d75737420626520696e2064697370757465000000000000602082015260400190565b603a81527f75706461746564207765692062616c616e636573206d757374206d617463682060208201527f73756d206f6620746872656164207765692062616c616e636573000000000000604082015260600190565b603381527f696e697469616c20746872656164207374617465206973206e6f7420636f6e746020820152606a60020a72185a5b9959081a5b881d1a1c995859149bdbdd02604082015260600190565b60128152607160020a7134b739bab33334b1b4b2b73a103a37b5b2b702602082015260400190565b60148152606160020a7331b430b73732b61036bab9ba1031329037b832b702602082015260400190565b602481527f6368616c6c656e6765722063616e206e6f74206265206578697420696e697469602082015260e160020a6330ba37b902604082015260600190565b60208082527f74687265616420636c6f73696e672074696d65206d757374206265207a65726f9082015260400190565b601a81527f73656e6465722063616e206e6f74206265207265636569766572000000000000602082015260400190565b600f8152608960020a6e2932b2b73a3930b73a1031b0b6361702602082015260400190565b604781527f73756d206f66207570646174656420746f6b656e2062616c616e636573206d7560208201527f7374206d617463682073656e646572277320696e697469616c20746f6b656e20604082015260c860020a6662616c616e636502606082015260800190565b60168152605260020a751d5cd95c881cda59db985d1d5c99481a5b9d985b1a5902602082015260400190565b604481527f687562436f6e747261637457697468647261773a20436f6e747261637420746f60208201527f6b656e2066756e6473206e6f742073756666696369656e7420746f2077697468604082015260e060020a636472617702606082015260800190565b602881527f696e73756666696369656e74207265736572766520746f6b656e7320666f7220602082015260c060020a676465706f7369747302604082015260600190565b60178152604860020a76757365722063616e6e6f7420656d70747920747769636502602082015260400190565b602b81527f687562436f6e747261637457697468647261773a20546f6b656e207472616e73602082015260a860020a6a666572206661696c75726502604082015260600190565b602b81527f63616e2774207374617274206578697420776974682074696d652d73656e7369602082015260a860020a6a746976652073746174657302604082015260600190565b603e81527f7570646174656420746f6b656e2062616c616e636573206d757374206d61746360208201527f682073756d206f662074687265616420746f6b656e2062616c616e6365730000604082015260600190565b60188152604260020a771d1bdad95b9cc81b5d5cdd0818994818dbdb9cd95c9d995902602082015260400190565b604281527f687562436f6e747261637457697468647261773a20436f6e747261637420776560208201527f692066756e6473206e6f742073756666696369656e7420746f20776974686472604082015260f060020a61617702606082015260800190565b602881527f74687265616420636c6f73696e672074696d65206d757374206e6f7420686176602082015260c260020a6719481c185cdcd95902604082015260600190565b602681527f696e697469616c2072656365697665722062616c616e636573206d7573742062602082015260d060020a6565207a65726f02604082015260600190565b602581527f6368616c6c656e676572206d757374206265206569746865722075736572206f602082015260d960020a643910343ab102604082015260600190565b604381527f73756d206f662075706461746564207765692062616c616e636573206d75737460208201527f206d617463682073656e646572277320696e697469616c207765692062616c61604082015260e860020a626e636502606082015260800190565b603d81527f676c6f62616c207478436f756e74206d7573742062652068696768657220746860208201527f616e207468652063757272656e7420676c6f62616c207478436f756e74000000604082015260600190565b602181527f6875622063616e206e6f742062652073656e646572206f722072656365697665602082015260f960020a603902604082015260600190565b604281527f73756d206f6620746872656164207765692062616c616e636573206d7573742060208201527f6d617463682073656e646572277320696e697469616c207765692062616c616e604082015260f060020a61636502606082015260800190565b60198152603a60020a781d5cd95c881d1bdad95b8819195c1bdcda5d0819985a5b195902602082015260400190565b602981527f746872656164206578697420696e69746961746f72206d757374206265207573602082015260b960020a6832b91037b910343ab102604082015260600190565b602581527f696e73756666696369656e7420726573657276652077656920666f7220646570602082015260d860020a646f7369747302604082015260600190565b60218152600080516020615c8c833981519152602082015260f860020a606502604082015260600190565b602481527f54687265616420636c6f73696e672074696d65206d7573742068617665207061602082015260e260020a631cdcd95902604082015260600190565b60138152606960020a723ab9b2b91031b0b7103737ba10313290343ab102602082015260400190565b604681527f73756d206f662074687265616420746f6b656e2062616c616e636573206d757360208201527f74206d617463682073656e646572277320696e697469616c20746f6b656e2062604082015260d060020a65616c616e636502606082015260800190565b602b81527f7468652074696d656f7574206d757374206265207a65726f206f72206e6f7420602082015260aa60020a6a1a185d99481c185cdcd95902604082015260600190565b602c81527f7570646174656420746872656164207478436f756e74206d7573742062652068602082015260a460020a6b06967686572207468616e20302604082015260600190565b602e81527f75736572205b73656e6465725d20746f6b656e207769746864726177616c20746020820152609260020a6d1c985b9cd9995c8819985a5b195902604082015260600190565b602281527f6578697420696e69746961746f72206d7573742062652075736572206f722068602082015260f160020a613ab102604082015260600190565b60278152600080516020615c8c833981519152602082015260c860020a666520706861736502604082015260600190565b601f81527f757365722063616e206e6f74206265206368616e6e656c206d616e6167657200602082015260400190565b60558152600080516020615d0c83398151915260208201527f6173736564206f72206d73672e73656e646572206d757374206265206e6f6e2d6040820152605860020a74657869742d696e6974696174696e6720706172747902606082015260800190565b603081527f75736572205b72656365697665725d20746f6b656e207769746864726177616c6020820152608260020a6f081d1c985b9cd9995c8819985a5b195902604082015260600190565b602e81527f6d73672e76616c7565206973206e6f7420657175616c20746f2070656e64696e6020820152609260020a6d19c81d5cd95c8819195c1bdcda5d02604082015260600190565b603d81527f746872656164207478436f756e74206d7573742062652068696768657220746860208201527f616e207468652063757272656e7420746872656164207478436f756e74000000604082015260600190565b603481527f6f6e6c79206875622c2073656e6465722c206f722072656365697665722063616020820152606160020a73371031b0b636103a3434b990333ab731ba34b7b702604082015260600190565b602681527f75736572206d757374206265207468726561642073656e646572206f72207265602082015260d160020a6531b2b4bb32b902604082015260600190565b6143c681615c3a565b602081016153a182846143bd565b92915050565b606081016153b582866143bd565b6153c260208301856143bd565b613d786040830184614499565b604081016153dd82856143bd565b613ba26020830184614499565b61016081016153f9828b6143bd565b615406602083018a614499565b61541360408301896143bd565b61542060608301886143cc565b61542d60a08301876143cc565b61543a60e0830186614415565b615448610120830185614499565b615456610140830184614499565b9998505050505050505050565b610100810161547282896143bd565b61547f6020830188614499565b61548c60408301876143bd565b6154996060830186614415565b6154a660a0830185614415565b6154b360e0830184614499565b979650505050505050565b61016081016154cd828b6143bd565b6154da602083018a614499565b6154136040830189614499565b61010081016154f682896143bd565b6155036020830188614499565b61548c604083018761538a565b6040810161551e8285614499565b8181036020830152613d7881846144bd565b6060810161553e8286614499565b818103602083015261555081856144bd565b9050613d7860408301846143bd565b60a0810161556d8288614499565b61557a6020830187614499565b61558760408301866143bd565b6155946060830185614499565b6155a160808301846144ab565b9695505050505050565b602081016153a182846144a2565b61022081016155c8828b6144b4565b6155d5602083018a6143cc565b6155e260608301896143cc565b6155ef60a0830188614457565b6155fd610120830187614457565b61560b6101a08301866143cc565b6156196101e0830185614499565b615456610200830184614499565b6102208101615636828b6144b4565b615643602083018a6143cc565b61565060608301896143cc565b61565d60a0830188614457565b61566b610120830187614457565b61560b6101a0830186614415565b60208082528101613ba281846144bd565b602080825281016153a1816144f2565b602080825281016153a181614518565b602080825281016153a18161455c565b602080825281016153a1816145c4565b602080825281016153a181614601565b602080825281016153a18161462c565b602080825281016153a181614653565b602080825281016153a18161469c565b602080825281016153a1816146e1565b602080825281016153a181614722565b602080825281016153a181614762565b602080825281016153a18161478d565b602080825281016153a1816147bd565b602080825281016153a181614813565b602080825281016153a181614862565b602080825281016153a18161488a565b602080825281016153a1816148b4565b602080825281016153a1816148f4565b602080825281016153a181614924565b602080825281016153a181614954565b602080825281016153a181614979565b602080825281016153a1816149e2565b602080825281016153a181614a0e565b602080825281016153a181614a74565b602080825281016153a181614ab8565b602080825281016153a181614ae5565b602080825281016153a181614b2c565b602080825281016153a181614b73565b602080825281016153a181614bc9565b602080825281016153a181614bf7565b602080825281016153a181614c5b565b602080825281016153a181614c9f565b602080825281016153a181614ce1565b602080825281016153a181614d22565b602080825281016153a181614d87565b602080825281016153a181614ddd565b602080825281016153a181614e1a565b602080825281016153a181614e7e565b602080825281016153a181614ead565b602080825281016153a181614ef2565b602080825281016153a181614f33565b602080825281016153a181614f5e565b602080825281016153a181614f9e565b602080825281016153a181614fc7565b602080825281016153a18161502f565b602080825281016153a181615076565b602080825281016153a1816150be565b602080825281016153a181615108565b602080825281016153a181615146565b602080825281016153a181615177565b602080825281016153a1816151a7565b602080825281016153a18161520c565b602080825281016153a181615258565b602080825281016153a1816152a2565b602080825281016153a1816152f8565b602080825281016153a181615348565b602081016153a18284614499565b60e08101615a268288614499565b615a3360208301876143bd565b615a406040830186614415565b615a4d6080830185614415565b6155a160c0830184614499565b604081016153dd8285614499565b60e08101615a76828a614499565b615a836020830189614499565b615a906040830188614499565b615a9d6060830187614499565b615aaa60808301866143bd565b615ab760a0830185614499565b615ac460c08301846144ab565b98975050505050505050565b60c08101615ade8289614499565b615aeb6020830188614499565b615af86040830187614499565b615b056060830186614499565b615b126080830185614499565b6154b360a0830184614499565b6101208101615b2e828961538a565b615b3b60208301886143cc565b615b4860608301876143cc565b615b5560a0830186614415565b615b6260e0830185614499565b6154b3610100830184614499565b6040518181016001604060020a0381118282101715615b8e57600080fd5b604052919050565b60006001604060020a03821115615bac57600080fd5b5060200290565b60006001604060020a03821115615bc957600080fd5b506020601f91909101601f19160190565b50600290565b50600490565b5190565b60200190565b60010190565b600160a060020a031690565b600060038210613ae657fe5b60ff1690565b151590565b60006153a182615bf6565b60006153a182615c02565b60006153a182611d59565b60006153a182615c0e565b82818337506000910152565b60005b83811015615c6c578181015183820152602001615c54565b83811115615c7b576000848401525b50505050565b601f01601f19169056006368616e6e656c206d75737420626520696e20746872656164206469737075746e65112e059a868cb1c7c4aed27e34fbbe470d2df0cbaa09bb5f82e5cba029fadbf69f39706ae3cb4e5b9dbca5780e14ba4968cdd060d5c3268f335ad6c25761eace9ecdebd30bbfc243bdc30bfa016abfa8f627654b4989da4620271dc77b1c6368616e6e656c20636c6f73696e672074696d65206d75737420686176652070ff678da893f9e68225fd9be0e51123341ba6d50fe0df41edebef4e9c0d242f77a265627a7a72305820346bdebc5b65e540f2c06b10af9e3b0da5200dccdafe3e47d580b94d094ebdf96c6578706572696d656e74616cf50037000000000000000000000000526d0cd57a8b977d3628f12cdeceab12dd49297c00000000000000000000000000000000000000000000000000000000000151800000000000000000000000006b01c3170ae1efebee1a3159172cb3f7a5ecf9e5

Deployed Bytecode

0x6080604052600436106101235763ffffffff60e060020a6000350416629e8690811461012557806301dd7da9146101505780630955acd41461017057806325c29be01461019057806332b573e1146101b0578063365a86fc146101c557806345a92009146101e75780634e2a5c5a14610219578063686bf4601461023957806369f817761461025957806372cc174c1461027957806374c25c20146102995780637651a86b146102cc5780637dce34f7146102ec5780639bcf63cd1461031d578063a1e1fe9314610332578063a3f4df7e14610352578063ad872d0314610374578063b04993ef14610389578063bab46259146103a9578063c8b2f7d6146103cb578063ea682e37146103eb578063f3f480d9146103fe578063ffa1ad7414610413575b005b34801561013157600080fd5b5061013a610428565b6040516101479190615a0a565b60405180910390f35b34801561015c57600080fd5b5061012361016b366004614383565b61042e565b34801561017c57600080fd5b5061012361018b36600461403b565b610604565b34801561019c57600080fd5b506101236101ab366004613f86565b61099b565b3480156101bc57600080fd5b5061013a610c1e565b3480156101d157600080fd5b506101da610c24565b6040516101479190615393565b3480156101f357600080fd5b50610207610202366004613d5a565b610c33565b60405161014796959493929190615ad0565b34801561022557600080fd5b50610123610234366004613d5a565b610d8f565b34801561024557600080fd5b50610123610254366004613e7e565b611159565b34801561026557600080fd5b50610123610274366004614246565b611396565b34801561028557600080fd5b50610123610294366004613d5a565b61168c565b3480156102a557600080fd5b506102b96102b4366004613d5a565b611818565b6040516101479796959493929190615a68565b3480156102d857600080fd5b506101236102e7366004613d5a565b611982565b3480156102f857600080fd5b5061030c610307366004613d5a565b611c8a565b60405161014795949392919061555f565b34801561032957600080fd5b5061013a611cc9565b34801561033e57600080fd5b5061012361034d366004614246565b611d5c565b34801561035e57600080fd5b50610367612198565b6040516101479190615679565b34801561038057600080fd5b5061013a6121c4565b34801561039557600080fd5b506101236103a4366004613d9e565b6121dc565b3480156103b557600080fd5b506103be612871565b60405161014791906155ab565b3480156103d757600080fd5b506101236103e6366004613d9e565b612880565b6101236103f9366004614152565b612aaf565b34801561040a57600080fd5b5061013a612daf565b34801561041f57600080fd5b50610367612db5565b60035481565b60075460ff161561045d5760405160e560020a62461bcd028152600401610454906157ba565b60405180910390fd5b6007805460ff1916600117905560005433600160a060020a039091161461048357600080fd5b8161048c6121c4565b10156104ad5760405160e560020a62461bcd0281526004016104549061585a565b806104b6611cc9565b10156104d75760405160e560020a62461bcd028152600401610454906157ea565b60008054604051600160a060020a039091169184156108fc02918591818181858888f19350505050158015610510573d6000803e3d6000fd5b5060025460005460405160e060020a63a9059cbb028152600160a060020a039283169263a9059cbb9261054a9291169085906004016153cf565b602060405180830381600087803b15801561056457600080fd5b505af1158015610578573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061059c9190810190614347565b15156105bd5760405160e560020a62461bcd0281526004016104549061581a565b7f60a3ff34ec09137572f54ff0fde3035ae459c9bebfdb1643a897de83211ebdf082826040516105ee929190615a5a565b60405180910390a150506007805460ff19169055565b600754600090819060ff161561062f5760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff19166001179055600160a060020a038d16600090815260056020526040902091506002600c83015460ff16600281111561066b57fe5b1461068b5760405160e560020a62461bcd0281526004016104549061598a565b600054600160a060020a03163314806106ac575033600160a060020a038e16145b15156106cd5760405160e560020a62461bcd028152600401610454906158ea565b8b51600160a060020a038e8116911614806106f7575060208c0151600160a060020a038e81169116145b15156107185760405160e560020a62461bcd028152600401610454906159fa565b60208a015115801561072c57506020890151155b151561074d5760405160e560020a62461bcd0281526004016104549061587a565b8b51600160a060020a03166000908152600660205260408120908d60016020020151600160a060020a0316600160a060020a0316815260200190815260200160002060008c81526020019081526020016000209050806005015460001415156107cb5760405160e560020a62461bcd0281526004016104549061579a565b6107ef8c600060200201518d600160200201518d8d8d60008e8e8a60080154612dd7565b600084116108125760405160e560020a62461bcd0281526004016104549061595a565b89516108358760015b60200201518860005b60200201519063ffffffff6130c016565b146108555760405160e560020a62461bcd0281526004016104549061589a565b885161086b8660015b6020020151876000610824565b1461088b5760405160e560020a62461bcd028152600401610454906157ca565b8b516020808e015160408051928301905260008083526108b693928f918b918b918b91908b90612dd7565b6108c281876002613aac565b506108d36002808301908790613aac565b50600481018490556001546108ef90429063ffffffff6130c016565b60058201558b60016020020151600160a060020a03168c60006020020151600160a060020a0316600080516020615ccc8339815191528f8e6000809054906101000a9004600160a060020a0316600160a060020a031633600160a060020a03161461095b57600161095e565b60005b600487015460405161097a9493929189916002830191906154e7565b60405180910390a350506007805460ff191690555050505050505050505050565b60075460009060ff16156109c45760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff1916600117905560005433600160a060020a0390911614806109f4575033600160a060020a038916145b80610a07575033600160a060020a038816145b1515610a285760405160e560020a62461bcd028152600401610454906159ea565b50600160a060020a038088166000908152600660209081526040808320938a16835292815282822088835290522060058101544210610a7c5760405160e560020a62461bcd0281526004016104549061586a565b60048101548311610aa25760405160e560020a62461bcd028152600401610454906159da565b610abc81600101548260005b01549063ffffffff6130c016565b610ac786600161085e565b14610ae75760405160e560020a62461bcd0281526004016104549061574a565b6003810154610afb90600283016000610aae565b6020850151610b0c90866000610824565b14610b2c5760405160e560020a62461bcd0281526004016104549061583a565b6001810154602086015110801590610b4c57506003810154602085015110155b1515610b6d5760405160e560020a62461bcd0281526004016104549061571a565b610b928888888888886020604051908101604052806000815250896000600102612dd7565b610b9e81866002613aac565b50610baf6002808301908690613aac565b5060048101839055604051600160a060020a0380891691908a16907f738f3bb8a8a2b4d0dc29a4076d3a4e41e510cd1044877421546903039766ad1990610c02908a903390879060028201908b90615a18565b60405180910390a350506007805460ff19169055505050505050565b60045481565b600054600160a060020a031681565b600080600080600080610c44613aea565b600160a060020a03881660009081526005602052604090819020815161016081019092528161010081018260038282826020028201915b815481526020019060010190808311610c7b5750505091835250506040805160608101918290526020909201919060038481019182845b815481526020019060010190808311610cb2575050509183525050604080518082019182905260209092019190600684019060029082845b815481526020019060010190808311610cea5750505091835250506008820154602082015260098201546040820152600a820154600160a060020a03166060820152600b8201546080820152600c82015460a09091019060ff166002811115610d4f57fe5b6002811115610d5a57fe5b9052508051805160208083015160409384015194820151805192810151940151929d909c50939a509850909650945092505050565b60075460009060ff1615610db85760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff19166001179055600054600160a060020a0383811691161415610df65760405160e560020a62461bcd0281526004016104549061592a565b600160a060020a038216301415610e225760405160e560020a62461bcd0281526004016104549061599a565b50600160a060020a03811660009081526005602052604090206001600c82015460ff166002811115610e5057fe5b14610e705760405160e560020a62461bcd0281526004016104549061573a565b4281600b01541080610eb65750600a810154600160a060020a03163314801590610eb65750600054600160a060020a0316331480610eb6575033600160a060020a038316145b1515610ed75760405160e560020a62461bcd028152600401610454906159aa565b610f048160015b01548254610ef8908460025b01549063ffffffff6130dd16565b9063ffffffff6130dd16565b8160020155610f266003820160015b0154600383018054610ef8916002610eea565b6005820155610f4c8160015b0154610ef88360005b01546003549063ffffffff6130dd16565b6003556001810154604051600160a060020a0384169180156108fc02916000818181858888f19350505050158015610f88573d6000803e3d6000fd5b5060008181015560008160010155610fbd6003820160015b0154610ef86003840160005b01546004549063ffffffff6130dd16565b600455600254600160a060020a031663a9059cbb8360038401600101546040518363ffffffff1660e060020a028152600401610ffa9291906153cf565b602060405180830381600087803b15801561101457600080fd5b505af1158015611028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061104c9190810190614347565b151561106d5760405160e560020a62461bcd0281526004016104549061570a565b600060038201819055600482018190556009820154111561109c57600c8101805460ff191660021790556110b0565b6000600b820155600c8101805460ff191690555b600a81018054600160a060020a0319169055600054600160a060020a0383811691600080516020615d2c833981519152911633146110ef5760016110f2565b60005b6040805180820182528554815260018601546020808301919091528251808401845260038801548152600488015491810191909152600887015460098801549351611143959460068a019291615b1f565b60405180910390a250506007805460ff19169055565b60075460009060ff16156111825760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff1916600117905560005433600160a060020a03909116146111a857600080fd5b50600160a060020a038b1660009081526005602052604090206111d281878c8c8c8c8960016130f4565b604080518082018252600160a060020a03808f1682528d166020808301919091528251808201845260008082528451808601909552845260019184019190915261122d928d918d918d918d918d918d918d918d918d906133b8565b61123a818b8b8b8b613781565b6060880151604051600160a060020a038d169180156108fc02916000818181858888f19350505050158015611273573d6000803e3d6000fd5b50600254606088015160405160e060020a63a9059cbb028152600160a060020a039092169163a9059cbb916112ad918f91906004016153cf565b602060405180830381600087803b1580156112c757600080fd5b505af11580156112db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112ff9190810190614347565b15156113205760405160e560020a62461bcd0281526004016104549061570a565b61132f60068201876002613aac565b506008810185905560098101849055604051600160a060020a038d1690600080516020615cec83398151915290611376906000908e908e908e908e908e908e908e906155b9565b60405180910390a250506007805460ff1916905550505050505050505050565b60075460009060ff16156113bf5760405160e560020a62461bcd028152600401610454906157ba565b506007805460ff191660011790558a51600160a060020a0316600090815260056020526040812090600c82015460ff1660028111156113fa57fe5b1461141a5760405160e560020a62461bcd0281526004016104549061577a565b600054600160a060020a031633148061143c57508b51600160a060020a031633145b151561145d5760405160e560020a62461bcd0281526004016104549061597a565b831561147e5760405160e560020a62461bcd0281526004016104549061582a565b6114b08c8c8c8c8c8c8c8c8c8c8c604080519081016040528060011515151581526020016001151515158152506133b8565b60068101548751116114d75760405160e560020a62461bcd028152600401610454906158aa565b6007810154602088015110156115025760405160e560020a62461bcd028152600401610454906156aa565b806002015461151b8c60015b60200201518d6000610824565b111561153c5760405160e560020a62461bcd028152600401610454906156ca565b60058101546115558b60015b60200201518c6000610824565b11156115765760405160e560020a62461bcd0281526004016104549061584a565b6007810154602088015114156115a457611591818c8b613852565b61159f816003018b8a613852565b6115bd565b6115af818c8b6138e0565b6115bd816003018b8a6138e0565b865160068201556008810186905560098101859055600a81018054600160a060020a031916331790556001546115f49042906130c0565b600b820155600c8101805460ff191660011790558b51600054600160a060020a0391821691600080516020615cac833981519152913391161461163857600161163b565b60005b6040805180820182528554815260018601546020808301919091528251808401845260038801548152600488015491810191909152600887015460098801549351611376959460068a019291615b1f565b60075460009060ff16156116b55760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff19166001179055600054600160a060020a03838116911614156116f35760405160e560020a62461bcd0281526004016104549061592a565b600160a060020a03821630141561171f5760405160e560020a62461bcd0281526004016104549061599a565b50600160a060020a038116600090815260056020526040812090600c82015460ff16600281111561174c57fe5b1461176c5760405160e560020a62461bcd0281526004016104549061577a565b600054600160a060020a031633148061178d575033600160a060020a038316145b15156117ae5760405160e560020a62461bcd0281526004016104549061597a565b600a81018054600160a060020a031916331790556001546117d690429063ffffffff6130c016565b600b820155600c8101805460ff19166001179055600054600160a060020a0383811691600080516020615cac83398151915291339116146110ef5760016110f2565b600080600080600080600061182b613aea565b600160a060020a03891660009081526005602052604090819020815161016081019092528161010081018260038282826020028201915b8154815260200190600101908083116118625750505091835250506040805160608101918290526020909201919060038481019182845b815481526020019060010190808311611899575050509183525050604080518082019182905260209092019190600684019060029082845b8154815260200190600101908083116118d15750505091835250506008820154602082015260098201546040820152600a820154600160a060020a03166060820152600b8201546080820152600c82015460a09091019060ff16600281111561193657fe5b600281111561194157fe5b905250604081015180516020909101516060830151608084015160a085015160c086015160e090960151949f939e50919c509a509850919650945092505050565b6007546000908190819060ff16156119af5760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff19166001179055600054600160a060020a03858116911614156119ed5760405160e560020a62461bcd0281526004016104549061592a565b600160a060020a038416301415611a195760405160e560020a62461bcd0281526004016104549061599a565b600160a060020a038416600090815260056020526040902092506002600c84015460ff166002811115611a4857fe5b14611a685760405160e560020a62461bcd0281526004016104549061590a565b42611a93611a82600a60015461394690919063ffffffff16565b600b8601549063ffffffff6130c016565b10611ab35760405160e560020a62461bcd0281526004016104549061569a565b611abe836002610f3b565b6003556002830154604051600160a060020a0386169180156108fc02916000818181858888f19350505050158015611afa573d6000803e3d6000fd5b508260020154915060008360020155611b17600384016002610fac565b6004908155600254600585015460405160e060020a63a9059cbb028152600160a060020a039092169263a9059cbb92611b549289929091016153cf565b602060405180830381600087803b158015611b6e57600080fd5b505af1158015611b82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611ba69190810190614347565b1515611bc75760405160e560020a62461bcd0281526004016104549061570a565b506005820180546000918290556009840182905560088401829055600b8401829055600c8401805460ff19169055604080518082018252855481526001860154602080830191909152825180840184526003880154815260048801549181019190915291519293600160a060020a038816937f02d2d0f262d032138bbd82feccd6d357a4441f394333cfa7d61792f44a70a0ed93611c72933393899389939160068d019181906154be565b60405180910390a250506007805460ff191690555050565b600560205260009081526040902060088101546009820154600a830154600b840154600c9094015492939192600160a060020a03909116919060ff1685565b6004805460025460405160e060020a6370a08231028152600093611d569392600160a060020a0316916370a0823191611d0491309101615393565b602060405180830381600087803b158015611d1e57600080fd5b505af1158015611d32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ef89190810190614365565b90505b90565b60075460009060ff1615611d855760405160e560020a62461bcd028152600401610454906157ba565b506007805460ff191660019081179091558b51600160a060020a0316600090815260056020526040902090600c82015460ff166002811115611dc357fe5b14611de35760405160e560020a62461bcd0281526004016104549061573a565b600b8101544210611e095760405160e560020a62461bcd028152600401610454906156fa565b600a810154600160a060020a0316331415611e395760405160e560020a62461bcd0281526004016104549061578a565b600054600160a060020a0316331480611e5b57508b51600160a060020a031633145b1515611e7c5760405160e560020a62461bcd0281526004016104549061588a565b8315611e9d5760405160e560020a62461bcd0281526004016104549061582a565b611ecf8c8c8c8c8c8c8c8c8c8c8c604080519081016040528060011515151581526020016001151515158152506133b8565b6006810154875111611ef65760405160e560020a62461bcd028152600401610454906158aa565b600781015460208801511015611f215760405160e560020a62461bcd028152600401610454906156aa565b8060020154611f318c600161150e565b1115611f525760405160e560020a62461bcd028152600401610454906156ca565b6005810154611f628b6001611548565b1115611f835760405160e560020a62461bcd0281526004016104549061584a565b600781015460208801511415611fb157611f9e818c8b613852565b611fac816003018b8a613852565b611fca565b611fbc818c8b6138e0565b611fca816003018b8a6138e0565b611fd5816001610ede565b8160020155611fe8600382016001610f13565b6005820155611ff8816001610f32565b6003558b516001820154604051600160a060020a039092169181156108fc0291906000818181858888f19350505050158015612038573d6000803e3d6000fd5b5060008181015560008160010155612054600382016001610fa0565b60049081556002548d518383015460405160e060020a63a9059cbb028152600160a060020a039093169363a9059cbb93612090939291016153cf565b602060405180830381600087803b1580156120aa57600080fd5b505af11580156120be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506120e29190810190614347565b15156121035760405160e560020a62461bcd0281526004016104549061570a565b6000600382018190556004820181905587516006830155600882018790556009820186905585111561214357600c8101805460ff19166002179055612157565b6000600b820155600c8101805460ff191690555b600a81018054600160a060020a03191690558b51600054600160a060020a0391821691600080516020615d2c8339815191529116331461163857600161163b565b60408051808201909152600f8152608960020a6e21b430b73732b61026b0b730b3b2b902602082015281565b600354600090611d569030319063ffffffff6130dd16565b600754600090819060ff16156122075760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff19166001179055600160a060020a038a16600090815260056020526040902091506002600c83015460ff16600281111561224357fe5b146122635760405160e560020a62461bcd0281526004016104549061590a565b600054600160a060020a0316331480612284575033600160a060020a038b16145b15156122a55760405160e560020a62461bcd028152600401610454906156ba565b88600160a060020a03168a600160a060020a031614806122d6575087600160a060020a03168a600160a060020a0316145b15156122f75760405160e560020a62461bcd028152600401610454906159fa565b602086015115801561230b57506020850151155b151561232c5760405160e560020a62461bcd0281526004016104549061587a565b50600160a060020a038089166000908152600660209081526040808320938b1683529281528282208983529052206005810154158015906123705750428160050154105b15156123915760405160e560020a62461bcd0281526004016104549061591a565b8060060189600160a060020a03168b600160a060020a0316146123b55760016123b8565b60005b60ff16600281106123c557fe5b602081049091015460ff601f9092166101000a900416156123fb5760405160e560020a62461bcd0281526004016104549061580a565b612411898989898960008a8a8a60080154612dd7565b8551600182015461242490836000610aae565b146124445760405160e560020a62461bcd028152600401610454906158ca565b8451600382015461245a90600284016000610aae565b1461247a5760405160e560020a62461bcd0281526004016104549061593a565b6124928160010154610ef88360000154856002610eea565b82600201556124b86002820160010154610ef86002840160000154600386016002610eea565b600583015560018101546124d190610ef8836000610f3b565b600355600160a060020a038a81169089161415612527576001810154604051600160a060020a038c169180156108fc02916000818181858888f19350505050158015612521573d6000803e3d6000fd5b50612579565b88600160a060020a03168a600160a060020a03161415612579578054604051600160a060020a038c169180156108fc02916000818181858888f19350505050158015612577573d6000803e3d6000fd5b505b600381015461259090610ef8600284016000610fac565b600455600160a060020a038a8116908916141561265857600254600382015460405160e060020a63a9059cbb028152600160a060020a039092169163a9059cbb916125e0918e91906004016153cf565b602060405180830381600087803b1580156125fa57600080fd5b505af115801561260e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126329190810190614347565b15156126535760405160e560020a62461bcd028152600401610454906159ba565b61271e565b88600160a060020a03168a600160a060020a0316141561271e57600280549082015460405160e060020a63a9059cbb028152600160a060020a039092169163a9059cbb916126ab918e91906004016153cf565b602060405180830381600087803b1580156126c557600080fd5b505af11580156126d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126fd9190810190614347565b151561271e5760405160e560020a62461bcd0281526004016104549061596a565b6001816006018a600160a060020a03168c600160a060020a031614612744576001612747565b60005b60ff166002811061275457fe5b602091828204019190066101000a81548160ff02191690831515021790555061278b600183600901546130dd90919063ffffffff16565b6009830181905515156127b357600060088301819055600b830155600c8201805460ff191690555b87600160a060020a031689600160a060020a03167ff45587a14ff8928bdd940cbf0564b42320b5e46a8fdecaf8a98a9eab63ab1f968c8a33604080519081016040528089600001600060038110151561280857fe5b0154815260018a015460209182015260408051808201825260038c0154815260048c01549281019290925260088b015460098c0154915161285397969594939260068e0192916153ea565b60405180910390a350506007805460ff191690555050505050505050565b600254600160a060020a031681565b600754600090819060ff16156128ab5760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff19166001179055600160a060020a038a16600090815260056020526040902091506002600c83015460ff1660028111156128e757fe5b146129075760405160e560020a62461bcd0281526004016104549061598a565b600054600160a060020a0316331480612928575033600160a060020a038b16145b15156129495760405160e560020a62461bcd028152600401610454906158ea565b88600160a060020a03168a600160a060020a0316148061297a575087600160a060020a03168a600160a060020a0316145b151561299b5760405160e560020a62461bcd028152600401610454906159fa565b60208601511580156129af57506020850151155b15156129d05760405160e560020a62461bcd0281526004016104549061587a565b50600160a060020a038089166000908152600660209081526040808320938b168352928152828220898352905220600581015415612a235760405160e560020a62461bcd0281526004016104549061579a565b612a39898989898960008a8a8a60080154612dd7565b612a4581876002613aac565b50612a566002808301908790613aac565b50600154612a6b90429063ffffffff6130c016565b60058201556004810154604051600160a060020a03808b1692908c1691600080516020615ccc83398151915291612853918f918d9133918991600283019190615463565b60075460009060ff1615612ad85760405160e560020a62461bcd028152600401610454906157ba565b6007805460ff1916600117905587600260200201513414612b0e5760405160e560020a62461bcd028152600401610454906159ca565b6005600033600160a060020a0316600160a060020a031681526020019081526020016000209050612b4681878c8c8c8c8960006130f4565b604080518082018252338152600160a060020a038d1660208083019190915282518082018452600080825284518086019095526001855291840191909152612ba0928d918d918d918d918d918d918d918d918d91906133b8565b600254604080890151905160e060020a6323b872dd028152600160a060020a03909216916323b872dd91612bda91339130916004016153a7565b602060405180830381600087803b158015612bf457600080fd5b505af1158015612c08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c2c9190810190614347565b1515612c4d5760405160e560020a62461bcd028152600401610454906158da565b612c5a818b8b8b8b613781565b6060880151604051600160a060020a038d169180156108fc02916000818181858888f19350505050158015612c93573d6000803e3d6000fd5b50600254606088015160405160e060020a63a9059cbb028152600160a060020a039092169163a9059cbb91612ccd918f91906004016153cf565b602060405180830381600087803b158015612ce757600080fd5b505af1158015612cfb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d1f9190810190614347565b1515612d405760405160e560020a62461bcd0281526004016104549061570a565b612d4f60068201876002613aac565b5060088101859055600981018490556040513390600080516020615cec83398151915290612d90906001908e908e908e908e9060068a01908e908e90615627565b60405180910390a250506007805460ff19169055505050505050505050565b60015481565b604080518082019091526005815260d860020a64302e302e3102602082015281565b6000600160a060020a038a8116908a161415612e085760405160e560020a62461bcd028152600401610454906157aa565b600054600160a060020a038b8116911614801590612e345750600054600160a060020a038a8116911614155b1515612e555760405160e560020a62461bcd028152600401610454906158ba565b600160a060020a038a163014801590612e775750600160a060020a0389163014155b1515612e985760405160e560020a62461bcd028152600401610454906156ea565b308a8a8a8a8a8a6040516020018088600160a060020a0316600160a060020a0316606060020a02815260140187600160a060020a0316600160a060020a0316606060020a02815260140186600160a060020a0316600160a060020a0316606060020a02815260140185815260200184600260200280838360005b83811015612f2a578181015183820152602001612f12565b5050505090500183600260200280838360005b83811015612f55578181015183820152602001612f3d565b505050509050018281526020019750505050505050506040516020818303038152906040526040518082805190602001908083835b60208310612fa95780518252601f199092019160209182019101612f8a565b5181516020939093036101000a60001901801990911692169190911790526040519201829003822060e060020a631052506f028352945073b01c6adaf785f06f2c01bcfe782e30ceefa90a269350631052506f92506130119185915087908f90600401615530565b60206040518083038186803b15801561302957600080fd5b505af415801561303d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506130619190810190614347565b15156130825760405160e560020a62461bcd028152600401610454906156da565b81156130b457613093818584613974565b15156130b45760405160e560020a62461bcd0281526004016104549061575a565b50505050505050505050565b6000828201838110156130d257600080fd5b8091505b5092915050565b600080838311156130ed57600080fd5b5050900390565b6000600c89015460ff16600281111561310957fe5b146131295760405160e560020a62461bcd0281526004016104549061577a565b81158061313557508142105b15156131565760405160e560020a62461bcd0281526004016104549061594a565b600688015487511161317d5760405160e560020a62461bcd028152600401610454906158aa565b6007880154602088015110156131a85760405160e560020a62461bcd028152600401610454906156aa565b87600201546131b887600161081b565b11156131d95760405160e560020a62461bcd028152600401610454906156ca565b60058801546131e986600161085e565b111561320a5760405160e560020a62461bcd0281526004016104549061584a565b8015613289576132186121c4565b604085015161322990866000610824565b111561324a5760405160e560020a62461bcd028152600401610454906158fa565b613252611cc9565b604084015161326390856000610824565b11156132845760405160e560020a62461bcd028152600401610454906157fa565b6132df565b6132916121c4565b845111156132b45760405160e560020a62461bcd028152600401610454906158fa565b6132bc611cc9565b835111156132df5760405160e560020a62461bcd028152600401610454906157fa565b60608401516020808601519088015161330d92916133019182908b6000610824565b9063ffffffff6130c016565b604085015161332a906133018760005b60200201518c6002610aae565b101561334b5760405160e560020a62461bcd0281526004016104549061568a565b60608301516020808501519087015161336d92916133019182908a6000610824565b604084015161338d906133018660005b602002015160038d016002610aae565b10156133ae5760405160e560020a62461bcd0281526004016104549061576a565b5050505050505050565b600080548d51600160a060020a03908116911614156133ec5760405160e560020a62461bcd0281526004016104549061592a565b8c51600160a060020a03163014156134195760405160e560020a62461bcd0281526004016104549061599a565b308d8d8d8d8d8d8d8d8d604051602001808b600160a060020a0316600160a060020a0316606060020a0281526014018a600260200280838360005b8381101561346c578181015183820152602001613454565b5050505090500189600260200280838360005b8381101561349757818101518382015260200161347f565b5050505090500188600260200280838360005b838110156134c25781810151838201526020016134aa565b5050505090500187600460200280838360005b838110156134ed5781810151838201526020016134d5565b5050505090500186600460200280838360005b83811015613518578181015183820152602001613500565b5050505090500185600260200280838360005b8381101561354357818101518382015260200161352b565b5050505090500184600019166000191681526020018381526020018281526020019a50505050505050505050506040516020818303038152906040526040518082805190602001908083835b602083106135ae5780518252601f19909201916020918201910161358f565b5181516020939093036101000a600019018019909116921691909117905260405192018290039091209350849250600091506135e79050565b6020020151156136ad5760405160e060020a63dca9541902815273b01c6adaf785f06f2c01bcfe782e30ceefa90a269063dca954199061362d9084908890600401615510565b60206040518083038186803b15801561364557600080fd5b505af4158015613659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061367d9190810190613d80565b600054600160a060020a039081169116146136ad5760405160e560020a62461bcd0281526004016104549061572a565b6020820151156137725760405160e060020a63dca9541902815273b01c6adaf785f06f2c01bcfe782e30ceefa90a269063dca95419906136f39084908790600401615510565b60206040518083038186803b15801561370b57600080fd5b505af415801561371f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506137439190810190613d80565b8d51600160a060020a039081169116146137725760405160e560020a62461bcd028152600401610454906157da565b50505050505050505050505050565b61378c858584613852565b61379a856003018483613852565b60608201516020830151604084015184516003546137c49493610ef89390928492613301916130c0565b60035560608101516020820151604083015183516004546137f19493610ef89390928492613301916130c0565b6004556060820151602083015160408401516138199291610ef891829061330188600061331d565b60028601556060810151602082015160408301516138439291610ef891829061330187600061337d565b60038601600201555050505050565b6020810151815111156138915761388a61388282600160200201518360005b60200201519063ffffffff6130dd16565b836000610824565b8355613896565b815183555b6060810151604082015111156138cf576138c46138bc8260036020020151836002613871565b836001610824565b8360015b01556138db565b60208201518360015b01555b505050565b6020810151815111156138f6578151835561390b565b80516139089061388290836001613871565b83555b6060810151604082015111156139285760208201518360016138c8565b61393e6138bc8260026020020151836003613871565b8360016138d8565b60008083151561395957600091506130d6565b5082820282848281151561396957fe5b04146130d257600080fd5b6000838160405b85518111613a9f5785810151915081831015613a1657604080516020808201869052818301859052825180830384018152606090920192839052815191929182918401908083835b602083106139e25780518252601f1990920191602091820191016139c3565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250613a97565b604080516020808201859052818301869052825180830384018152606090920192839052815191929182918401908083835b60208310613a675780518252601f199092019160209182019101613a48565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902092505b60200161397b565b5050919091149392505050565b8260028101928215613ada579160200282015b82811115613ada578251825591602001919060010190613abf565b50613ae6929150613b42565b5090565b6101a060405190810160405280613aff613b5c565b8152602001613b0c613b5c565b8152602001613b19613b7b565b815260006020820181905260408201819052606082018190526080820181905260a09091015290565b611d5991905b80821115613ae65760008155600101613b48565b6060604051908101604052806003906020820280388339509192915050565b60408051808201825290600290829080388339509192915050565b6000613ba28235615bf6565b9392505050565b6000613ba28251615bf6565b6000601f82018313613bc657600080fd5b6002613bd9613bd482615b96565b615b70565b91508183856020840282011115613bef57600080fd5b60005b83811015613c1b5781613c058882613b96565b8452506020928301929190910190600101613bf2565b5050505092915050565b6000601f82018313613c3657600080fd5b6002613c44613bd482615b96565b91508183856020840282011115613c5a57600080fd5b60005b83811015613c1b5781613c708882613cf3565b8452506020928301929190910190600101613c5d565b6000601f82018313613c9757600080fd5b6004613ca5613bd482615b96565b91508183856020840282011115613cbb57600080fd5b60005b83811015613c1b5781613cd18882613cf3565b8452506020928301929190910190600101613cbe565b6000613ba28251615c14565b6000613ba28235611d59565b6000601f82018313613d1057600080fd5b8135613d1e613bd482615bb3565b91508082526020830160208301858383011115613d3a57600080fd5b613d45838284615c45565b50505092915050565b6000613ba28251611d59565b600060208284031215613d6c57600080fd5b6000613d788484613b96565b949350505050565b600060208284031215613d9257600080fd5b6000613d788484613ba9565b600080600080600080600080610140898b031215613dbb57600080fd5b6000613dc78b8b613b96565b9850506020613dd88b828c01613b96565b9750506040613de98b828c01613b96565b9650506060613dfa8b828c01613cf3565b9550506080613e0b8b828c01613c25565b94505060c0613e1c8b828c01613c25565b9350506101008901356001604060020a03811115613e3957600080fd5b613e458b828c01613cff565b9250506101208901356001604060020a03811115613e6257600080fd5b613e6e8b828c01613cff565b9150509295985092959890939650565b60008060008060008060008060008060006102808c8e031215613ea057600080fd5b6000613eac8e8e613b96565b9b50506020613ebd8e828f01613b96565b9a50506040613ece8e828f01613c25565b9950506080613edf8e828f01613c25565b98505060c0613ef08e828f01613c86565b975050610140613f028e828f01613c86565b9650506101c0613f148e828f01613c25565b955050610200613f268e828f01613cf3565b945050610220613f388e828f01613cf3565b935050610240613f4a8e828f01613cf3565b9250506102608c01356001604060020a03811115613f6757600080fd5b613f738e828f01613cff565b9150509295989b509295989b9093969950565b6000806000806000806000610120888a031215613fa257600080fd5b6000613fae8a8a613b96565b9750506020613fbf8a828b01613b96565b9650506040613fd08a828b01613cf3565b9550506060613fe18a828b01613c25565b94505060a0613ff28a828b01613c25565b93505060e06140038a828b01613cf3565b9250506101008801356001604060020a0381111561402057600080fd5b61402c8a828b01613cff565b91505092959891949750929550565b60008060008060008060008060008060006102008c8e03121561405d57600080fd5b60006140698e8e613b96565b9b5050602061407a8e828f01613bb5565b9a5050606061408b8e828f01613cf3565b995050608061409c8e828f01613c25565b98505060c06140ad8e828f01613c25565b9750506101008c01356001604060020a038111156140ca57600080fd5b6140d68e828f01613cff565b9650506101208c01356001604060020a038111156140f357600080fd5b6140ff8e828f01613cff565b9550506101406141118e828f01613c25565b9450506101806141238e828f01613c25565b9350506101c06141358e828f01613cf3565b9250506101e08c01356001604060020a03811115613f6757600080fd5b6000806000806000806000806000806102608b8d03121561417257600080fd5b600061417e8d8d613b96565b9a5050602061418f8d828e01613c25565b99505060606141a08d828e01613c25565b98505060a06141b18d828e01613c86565b9750506101206141c38d828e01613c86565b9650506101a06141d58d828e01613c25565b9550506101e06141e78d828e01613cf3565b9450506102006141f98d828e01613cf3565b93505061022061420b8d828e01613cf3565b9250506102408b01356001604060020a0381111561422857600080fd5b6142348d828e01613cff565b9150509295989b9194979a5092959850565b60008060008060008060008060008060006102a08c8e03121561426857600080fd5b60006142748e8e613bb5565b9b505060406142858e828f01613c25565b9a505060806142968e828f01613c25565b99505060c06142a78e828f01613c86565b9850506101406142b98e828f01613c86565b9750506101c06142cb8e828f01613c25565b9650506102006142dd8e828f01613cf3565b9550506102206142ef8e828f01613cf3565b9450506102406143018e828f01613cf3565b9350506102608c01356001604060020a0381111561431e57600080fd5b61432a8e828f01613cff565b9250506102808c01356001604060020a03811115613f6757600080fd5b60006020828403121561435957600080fd5b6000613d788484613ce7565b60006020828403121561437757600080fd5b6000613d788484613d4e565b6000806040838503121561439657600080fd5b60006143a28585613cf3565b92505060206143b385828601613cf3565b9150509250929050565b6143c681615bf6565b82525050565b6143d581615bda565b6143de82611d59565b60005b8281101561440e576143f4858351614499565b6143fd82615bea565b6020959095019491506001016143e1565b5050505050565b61441e81615bda565b61442782611d59565b60005b8281101561440e5761443d858354614499565b61444682615bf0565b60209590950194915060010161442a565b61446081615be0565b61446982611d59565b60005b8281101561440e5761447f858351614499565b61448882615bea565b60209590950194915060010161446c565b6143c681611d59565b6143c681615c19565b6143c681615c24565b6143c681615c2f565b60006144c882615be6565b8084526144dc816020860160208601615c51565b6144e581615c81565b9093016020019392505050565b60108152608060020a6f696e73756666696369656e742077656902602082015260400190565b603d8152600080516020615d0c83398151915260208201527f6173736564206279203130206368616c6c656e676520706572696f6473000000604082015260600190565b604681527f6f6e636861696e207478436f756e74206d75737420626520686967686572206f60208201527f7220657175616c20746f207468652063757272656e74206f6e636861696e2074604082015260d260020a651e10dbdd5b9d02606082015260800190565b602181527f6f6e6c7920687562206f7220757365722063616e20656d707479207468726561602082015260fa60020a601902604082015260600190565b60158152605a60020a741dd95a481b5d5cdd0818994818dbdb9cd95c9d995902602082015260400190565b60118152607a60020a701cda59db985d1d5c99481a5b9d985b1a5902602082015260400190565b602d81527f6368616e6e656c206d616e616765722063616e206e6f742062652073656e64656020820152609960020a6c391037b9103932b1b2b4bb32b902604082015260600190565b602981527f6368616e6e656c20636c6f73696e672074696d65206d757374206e6f74206861602082015260ba60020a681d99481c185cdcd95902604082015260600190565b602581527f7573657220746f6b656e207769746864726177616c207472616e736665722066602082015260da60020a64185a5b195902604082015260600190565b602481527f72656365697665722062616c616e636573206d6179206e657665722064656372602082015260e060020a636561736502604082015260600190565b60158152605a60020a741a1d58881cda59db985d1d5c99481a5b9d985b1a5902602082015260400190565b601a81527f6368616e6e656c206d75737420626520696e2064697370757465000000000000602082015260400190565b603a81527f75706461746564207765692062616c616e636573206d757374206d617463682060208201527f73756d206f6620746872656164207765692062616c616e636573000000000000604082015260600190565b603381527f696e697469616c20746872656164207374617465206973206e6f7420636f6e746020820152606a60020a72185a5b9959081a5b881d1a1c995859149bdbdd02604082015260600190565b60128152607160020a7134b739bab33334b1b4b2b73a103a37b5b2b702602082015260400190565b60148152606160020a7331b430b73732b61036bab9ba1031329037b832b702602082015260400190565b602481527f6368616c6c656e6765722063616e206e6f74206265206578697420696e697469602082015260e160020a6330ba37b902604082015260600190565b60208082527f74687265616420636c6f73696e672074696d65206d757374206265207a65726f9082015260400190565b601a81527f73656e6465722063616e206e6f74206265207265636569766572000000000000602082015260400190565b600f8152608960020a6e2932b2b73a3930b73a1031b0b6361702602082015260400190565b604781527f73756d206f66207570646174656420746f6b656e2062616c616e636573206d7560208201527f7374206d617463682073656e646572277320696e697469616c20746f6b656e20604082015260c860020a6662616c616e636502606082015260800190565b60168152605260020a751d5cd95c881cda59db985d1d5c99481a5b9d985b1a5902602082015260400190565b604481527f687562436f6e747261637457697468647261773a20436f6e747261637420746f60208201527f6b656e2066756e6473206e6f742073756666696369656e7420746f2077697468604082015260e060020a636472617702606082015260800190565b602881527f696e73756666696369656e74207265736572766520746f6b656e7320666f7220602082015260c060020a676465706f7369747302604082015260600190565b60178152604860020a76757365722063616e6e6f7420656d70747920747769636502602082015260400190565b602b81527f687562436f6e747261637457697468647261773a20546f6b656e207472616e73602082015260a860020a6a666572206661696c75726502604082015260600190565b602b81527f63616e2774207374617274206578697420776974682074696d652d73656e7369602082015260a860020a6a746976652073746174657302604082015260600190565b603e81527f7570646174656420746f6b656e2062616c616e636573206d757374206d61746360208201527f682073756d206f662074687265616420746f6b656e2062616c616e6365730000604082015260600190565b60188152604260020a771d1bdad95b9cc81b5d5cdd0818994818dbdb9cd95c9d995902602082015260400190565b604281527f687562436f6e747261637457697468647261773a20436f6e747261637420776560208201527f692066756e6473206e6f742073756666696369656e7420746f20776974686472604082015260f060020a61617702606082015260800190565b602881527f74687265616420636c6f73696e672074696d65206d757374206e6f7420686176602082015260c260020a6719481c185cdcd95902604082015260600190565b602681527f696e697469616c2072656365697665722062616c616e636573206d7573742062602082015260d060020a6565207a65726f02604082015260600190565b602581527f6368616c6c656e676572206d757374206265206569746865722075736572206f602082015260d960020a643910343ab102604082015260600190565b604381527f73756d206f662075706461746564207765692062616c616e636573206d75737460208201527f206d617463682073656e646572277320696e697469616c207765692062616c61604082015260e860020a626e636502606082015260800190565b603d81527f676c6f62616c207478436f756e74206d7573742062652068696768657220746860208201527f616e207468652063757272656e7420676c6f62616c207478436f756e74000000604082015260600190565b602181527f6875622063616e206e6f742062652073656e646572206f722072656365697665602082015260f960020a603902604082015260600190565b604281527f73756d206f6620746872656164207765692062616c616e636573206d7573742060208201527f6d617463682073656e646572277320696e697469616c207765692062616c616e604082015260f060020a61636502606082015260800190565b60198152603a60020a781d5cd95c881d1bdad95b8819195c1bdcda5d0819985a5b195902602082015260400190565b602981527f746872656164206578697420696e69746961746f72206d757374206265207573602082015260b960020a6832b91037b910343ab102604082015260600190565b602581527f696e73756666696369656e7420726573657276652077656920666f7220646570602082015260d860020a646f7369747302604082015260600190565b60218152600080516020615c8c833981519152602082015260f860020a606502604082015260600190565b602481527f54687265616420636c6f73696e672074696d65206d7573742068617665207061602082015260e260020a631cdcd95902604082015260600190565b60138152606960020a723ab9b2b91031b0b7103737ba10313290343ab102602082015260400190565b604681527f73756d206f662074687265616420746f6b656e2062616c616e636573206d757360208201527f74206d617463682073656e646572277320696e697469616c20746f6b656e2062604082015260d060020a65616c616e636502606082015260800190565b602b81527f7468652074696d656f7574206d757374206265207a65726f206f72206e6f7420602082015260aa60020a6a1a185d99481c185cdcd95902604082015260600190565b602c81527f7570646174656420746872656164207478436f756e74206d7573742062652068602082015260a460020a6b06967686572207468616e20302604082015260600190565b602e81527f75736572205b73656e6465725d20746f6b656e207769746864726177616c20746020820152609260020a6d1c985b9cd9995c8819985a5b195902604082015260600190565b602281527f6578697420696e69746961746f72206d7573742062652075736572206f722068602082015260f160020a613ab102604082015260600190565b60278152600080516020615c8c833981519152602082015260c860020a666520706861736502604082015260600190565b601f81527f757365722063616e206e6f74206265206368616e6e656c206d616e6167657200602082015260400190565b60558152600080516020615d0c83398151915260208201527f6173736564206f72206d73672e73656e646572206d757374206265206e6f6e2d6040820152605860020a74657869742d696e6974696174696e6720706172747902606082015260800190565b603081527f75736572205b72656365697665725d20746f6b656e207769746864726177616c6020820152608260020a6f081d1c985b9cd9995c8819985a5b195902604082015260600190565b602e81527f6d73672e76616c7565206973206e6f7420657175616c20746f2070656e64696e6020820152609260020a6d19c81d5cd95c8819195c1bdcda5d02604082015260600190565b603d81527f746872656164207478436f756e74206d7573742062652068696768657220746860208201527f616e207468652063757272656e7420746872656164207478436f756e74000000604082015260600190565b603481527f6f6e6c79206875622c2073656e6465722c206f722072656365697665722063616020820152606160020a73371031b0b636103a3434b990333ab731ba34b7b702604082015260600190565b602681527f75736572206d757374206265207468726561642073656e646572206f72207265602082015260d160020a6531b2b4bb32b902604082015260600190565b6143c681615c3a565b602081016153a182846143bd565b92915050565b606081016153b582866143bd565b6153c260208301856143bd565b613d786040830184614499565b604081016153dd82856143bd565b613ba26020830184614499565b61016081016153f9828b6143bd565b615406602083018a614499565b61541360408301896143bd565b61542060608301886143cc565b61542d60a08301876143cc565b61543a60e0830186614415565b615448610120830185614499565b615456610140830184614499565b9998505050505050505050565b610100810161547282896143bd565b61547f6020830188614499565b61548c60408301876143bd565b6154996060830186614415565b6154a660a0830185614415565b6154b360e0830184614499565b979650505050505050565b61016081016154cd828b6143bd565b6154da602083018a614499565b6154136040830189614499565b61010081016154f682896143bd565b6155036020830188614499565b61548c604083018761538a565b6040810161551e8285614499565b8181036020830152613d7881846144bd565b6060810161553e8286614499565b818103602083015261555081856144bd565b9050613d7860408301846143bd565b60a0810161556d8288614499565b61557a6020830187614499565b61558760408301866143bd565b6155946060830185614499565b6155a160808301846144ab565b9695505050505050565b602081016153a182846144a2565b61022081016155c8828b6144b4565b6155d5602083018a6143cc565b6155e260608301896143cc565b6155ef60a0830188614457565b6155fd610120830187614457565b61560b6101a08301866143cc565b6156196101e0830185614499565b615456610200830184614499565b6102208101615636828b6144b4565b615643602083018a6143cc565b61565060608301896143cc565b61565d60a0830188614457565b61566b610120830187614457565b61560b6101a0830186614415565b60208082528101613ba281846144bd565b602080825281016153a1816144f2565b602080825281016153a181614518565b602080825281016153a18161455c565b602080825281016153a1816145c4565b602080825281016153a181614601565b602080825281016153a18161462c565b602080825281016153a181614653565b602080825281016153a18161469c565b602080825281016153a1816146e1565b602080825281016153a181614722565b602080825281016153a181614762565b602080825281016153a18161478d565b602080825281016153a1816147bd565b602080825281016153a181614813565b602080825281016153a181614862565b602080825281016153a18161488a565b602080825281016153a1816148b4565b602080825281016153a1816148f4565b602080825281016153a181614924565b602080825281016153a181614954565b602080825281016153a181614979565b602080825281016153a1816149e2565b602080825281016153a181614a0e565b602080825281016153a181614a74565b602080825281016153a181614ab8565b602080825281016153a181614ae5565b602080825281016153a181614b2c565b602080825281016153a181614b73565b602080825281016153a181614bc9565b602080825281016153a181614bf7565b602080825281016153a181614c5b565b602080825281016153a181614c9f565b602080825281016153a181614ce1565b602080825281016153a181614d22565b602080825281016153a181614d87565b602080825281016153a181614ddd565b602080825281016153a181614e1a565b602080825281016153a181614e7e565b602080825281016153a181614ead565b602080825281016153a181614ef2565b602080825281016153a181614f33565b602080825281016153a181614f5e565b602080825281016153a181614f9e565b602080825281016153a181614fc7565b602080825281016153a18161502f565b602080825281016153a181615076565b602080825281016153a1816150be565b602080825281016153a181615108565b602080825281016153a181615146565b602080825281016153a181615177565b602080825281016153a1816151a7565b602080825281016153a18161520c565b602080825281016153a181615258565b602080825281016153a1816152a2565b602080825281016153a1816152f8565b602080825281016153a181615348565b602081016153a18284614499565b60e08101615a268288614499565b615a3360208301876143bd565b615a406040830186614415565b615a4d6080830185614415565b6155a160c0830184614499565b604081016153dd8285614499565b60e08101615a76828a614499565b615a836020830189614499565b615a906040830188614499565b615a9d6060830187614499565b615aaa60808301866143bd565b615ab760a0830185614499565b615ac460c08301846144ab565b98975050505050505050565b60c08101615ade8289614499565b615aeb6020830188614499565b615af86040830187614499565b615b056060830186614499565b615b126080830185614499565b6154b360a0830184614499565b6101208101615b2e828961538a565b615b3b60208301886143cc565b615b4860608301876143cc565b615b5560a0830186614415565b615b6260e0830185614499565b6154b3610100830184614499565b6040518181016001604060020a0381118282101715615b8e57600080fd5b604052919050565b60006001604060020a03821115615bac57600080fd5b5060200290565b60006001604060020a03821115615bc957600080fd5b506020601f91909101601f19160190565b50600290565b50600490565b5190565b60200190565b60010190565b600160a060020a031690565b600060038210613ae657fe5b60ff1690565b151590565b60006153a182615bf6565b60006153a182615c02565b60006153a182611d59565b60006153a182615c0e565b82818337506000910152565b60005b83811015615c6c578181015183820152602001615c54565b83811115615c7b576000848401525b50505050565b601f01601f19169056006368616e6e656c206d75737420626520696e20746872656164206469737075746e65112e059a868cb1c7c4aed27e34fbbe470d2df0cbaa09bb5f82e5cba029fadbf69f39706ae3cb4e5b9dbca5780e14ba4968cdd060d5c3268f335ad6c25761eace9ecdebd30bbfc243bdc30bfa016abfa8f627654b4989da4620271dc77b1c6368616e6e656c20636c6f73696e672074696d65206d75737420686176652070ff678da893f9e68225fd9be0e51123341ba6d50fe0df41edebef4e9c0d242f77a265627a7a72305820346bdebc5b65e540f2c06b10af9e3b0da5200dccdafe3e47d580b94d094ebdf96c6578706572696d656e74616cf50037

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000526d0cd57a8b977d3628f12cdeceab12dd49297c00000000000000000000000000000000000000000000000000000000000151800000000000000000000000006b01c3170ae1efebee1a3159172cb3f7a5ecf9e5

-----Decoded View---------------
Arg [0] : _hub (address): 0x526d0cd57a8b977D3628f12cDeceAb12dd49297C
Arg [1] : _challengePeriod (uint256): 86400
Arg [2] : _tokenAddress (address): 0x6B01c3170ae1EFEBEe1a3159172CB3F7A5ECf9E5

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000526d0cd57a8b977d3628f12cdeceab12dd49297c
Arg [1] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [2] : 0000000000000000000000006b01c3170ae1efebee1a3159172cb3f7a5ecf9e5


Libraries Used


Swarm Source

bzzr://346bdebc5b65e540f2c06b10af9e3b0da5200dccdafe3e47d580b94d094ebdf9

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.