Latest 2 txns

TxHash Age From To Value [TxFee]
0x12a93e3848edb693371dec07300c437074a8e1427a475139be9ab316bed97e9910 days 10 hrs ago0x1b1ce693e7289fc40753393cfce2ec7f8e0e3ca3  IN   0x6f7aab0ba0b38b95bd1363a61ec4448df27fc92a0 Ether0.036669564
0x0d9c01f30c952c57fcf509195d728e3a32a731bd491c6a0cc96cf8294b10491e10 days 10 hrs ago0x1b1ce693e7289fc40753393cfce2ec7f8e0e3ca3  IN    Contract Creation0 Ether0.056439504


[ Download CSV Export  ] 
 Internal Transactions as a result of Contract Execution
 Latest 1 Internal Transaction

ParentTxHash Block Age From To Value
0x12a93e3848edb693371dec07300c437074a8e1427a475139be9ab316bed97e99385600610 days 10 hrs ago0x6f7aab0ba0b38b95bd1363a61ec4448df27fc92a  Contract Creation0 Ether
[ Download CSV Export  ] 
Contract Source Code Verified (Exact Match)
Contract Name: TokenNetworkRegistry
Compiler Version: v0.5.2+commit.1df8f40c
Optimization Enabled: No
Runs (Optimiser):  200



  Contract Source Code   Find Similiar Contracts

pragma solidity ^0.5.2;


/// @title Utils
/// @notice Utils contract for various helpers used by the Raiden Network smart
/// contracts.
contract Utils {
    string constant public contract_version = "0.6.0";

    /// @notice Check if a contract exists
    /// @param contract_address The address to check whether a contract is
    /// deployed or not
    /// @return True if a contract exists, false otherwise
    function contractExists(address contract_address) public view returns (bool) {
        uint size;

        assembly {
            size := extcodesize(contract_address)
        }

        return size > 0;
    }
}

interface Token {

    /// @return total amount of tokens
    function totalSupply() external view returns (uint256 supply);

    /// @param _owner The address from which the balance will be retrieved
    /// @return The balance
    function balanceOf(address _owner) external view returns (uint256 balance);

    /// @notice send `_value` token to `_to` from `msg.sender`
    /// @param _to The address of the recipient
    /// @param _value The amount of token to be transferred
    /// @return Whether the transfer was successful or not
    function transfer(address _to, uint256 _value) external returns (bool success);

    /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
    /// @param _from The address of the sender
    /// @param _to The address of the recipient
    /// @param _value The amount of token to be transferred
    /// @return Whether the transfer was successful or not
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);

    /// @notice `msg.sender` approves `_spender` to spend `_value` tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @param _value The amount of wei to be approved for transfer
    /// @return Whether the approval was successful or not
    function approve(address _spender, uint256 _value) external returns (bool success);

    /// @param _owner The address of the account owning tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @return Amount of remaining tokens allowed to spent
    function allowance(address _owner, address _spender) external view returns (uint256 remaining);

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);

    // Optionally implemented function to show the number of decimals for the token
    function decimals() external view returns (uint8 decimals);
}


library ECVerify {

    function ecverify(bytes32 hash, bytes memory signature)
        internal
        pure
        returns (address signature_address)
    {
        require(signature.length == 65);

        bytes32 r;
        bytes32 s;
        uint8 v;

        // The signature format is a compact form of:
        //   {bytes32 r}{bytes32 s}{uint8 v}
        // Compact means, uint8 is not padded to 32 bytes.
        assembly {
            r := mload(add(signature, 32))
            s := mload(add(signature, 64))

            // Here we are loading the last 32 bytes, including 31 bytes following the signature.
            v := byte(0, mload(add(signature, 96)))
        }

        // Version of signature should be 27 or 28, but 0 and 1 are also possible
        if (v < 27) {
            v += 27;
        }

        require(v == 27 || v == 28);

        signature_address = ecrecover(hash, v, r, s);

        // ecrecover returns zero on error
        require(signature_address != address(0x0));

        return signature_address;
    }
}

/// @title SecretRegistry
/// @notice SecretRegistry contract for registering secrets from Raiden Network
/// clients.
contract SecretRegistry {

    string constant public contract_version = "0.6.0";

    // keccak256(secret) => block number at which the secret was revealed
    mapping(bytes32 => uint256) private secrethash_to_block;

    event SecretRevealed(bytes32 indexed secrethash, bytes32 secret);

    /// @notice Registers a hash time lock secret and saves the block number.
    /// This allows the lock to be unlocked after the expiration block.
    /// @param secret The secret used to lock the hash time lock.
    /// @return true if secret was registered, false if the secret was already
    /// registered.
    function registerSecret(bytes32 secret) public returns (bool) {
        bytes32 secrethash = keccak256(abi.encodePacked(secret));
        if (secret == bytes32(0x0) || secrethash_to_block[secrethash] > 0) {
            return false;
        }
        secrethash_to_block[secrethash] = block.number;
        emit SecretRevealed(secrethash, secret);
        return true;
    }

    /// @notice Registers multiple hash time lock secrets and saves the block
    /// number.
    /// @param secrets The array of secrets to be registered.
    /// @return true if all secrets could be registered, false otherwise.
    function registerSecretBatch(bytes32[] memory secrets) public returns (bool) {
        bool completeSuccess = true;
        for(uint i = 0; i < secrets.length; i++) {
            if(!registerSecret(secrets[i])) {
                completeSuccess = false;
            }
        }
        return completeSuccess;
    }

    /// @notice Get the stored block number at which the secret was revealed.
    /// @param secrethash The hash of the registered secret `keccak256(secret)`.
    /// @return The block number at which the secret was revealed.
    function getSecretRevealBlockHeight(bytes32 secrethash) public view returns (uint256) {
        return secrethash_to_block[secrethash];
    }
}

/// @title TokenNetwork
/// @notice Stores and manages all the Raiden Network channels that use the
/// token specified
/// in this TokenNetwork contract.
contract TokenNetwork is Utils {

    string constant public contract_version = "0.6.0";

    // Instance of the token used by the channels
    Token public token;

    // Instance of SecretRegistry used for storing secrets revealed in a
    // mediating transfer.
    SecretRegistry public secret_registry;

    // Chain ID as specified by EIP155 used in balance proof signatures to
    // avoid replay attacks
    uint256 public chain_id;

    uint256 public settlement_timeout_min;
    uint256 public settlement_timeout_max;

    uint256 constant public MAX_SAFE_UINT256 = (
        115792089237316195423570985008687907853269984665640564039457584007913129639935
    );

    // Red Eyes release deposit limits
    // The combined deposit of one channel is limited to 0.15 ETH.
    // So 0.075 ETH per participant.
    uint256 constant public channel_participant_deposit_limit = 75000000000000000 wei;
    // The total combined deposit of all channels across the whole network is
    // limited to 250 ETH.
    uint256 constant public token_network_deposit_limit = 250000000000000000000 wei;

    // Global, monotonically increasing counter that keeps track of all the
    // opened channels in this contract
    uint256 public channel_counter;

    string public constant signature_prefix = '\x19Ethereum Signed Message:\n';

    // Only for the limited Red Eyes release
    address public deprecation_executor;
    bool public safety_deprecation_switch = false;

    // channel_identifier => Channel
    // channel identifier is the channel_counter value at the time of opening
    // the channel
    mapping (uint256 => Channel) public channels;

    // This is needed to enforce one channel per pair of participants
    // The key is keccak256(participant1_address, participant2_address)
    mapping (bytes32 => uint256) public participants_hash_to_channel_identifier;

    // We keep the unlock data in a separate mapping to allow channel data
    // structures to be removed when settling uncooperatively. If there are
    // locked pending transfers, we need to store data needed to unlock them at
    // a later time.
    // The key is `keccak256(uint256 channel_identifier, address participant,
    // address partner)` Where `participant` is the participant that sent the
    // pending transfers We need `partner` for knowing where to send the
    // claimable tokens
    mapping(bytes32 => UnlockData) private unlock_identifier_to_unlock_data;

    struct Participant {
        // Total amount of tokens transferred to this smart contract through
        // the `setTotalDeposit` function, for a specific channel, in the
        // participant's benefit.
        // This is a strictly monotonic value. Note that direct token transfer
        // into the contract cannot be tracked and will be stuck.
        uint256 deposit;

        // Total amount of tokens withdrawn by the participant during the
        // lifecycle of this channel.
        // This is a strictly monotonic value.
        uint256 withdrawn_amount;

        // This is a value set to true after the channel has been closed, only
        // if this is the participant who closed the channel.
        bool is_the_closer;

        // keccak256 of the balance data provided after a closeChannel or an
        // updateNonClosingBalanceProof call
        bytes32 balance_hash;

        // Monotonically increasing counter of the off-chain transfers,
        // provided along with the balance_hash
        uint256 nonce;
    }

    enum ChannelState {
        NonExistent, // 0
        Opened,      // 1
        Closed,      // 2
        Settled,     // 3; Note: The channel has at least one pending unlock
        Removed      // 4; Note: Channel data is removed, there are no pending unlocks
    }

    enum MessageTypeId {
        None,
        BalanceProof,
        BalanceProofUpdate,
        Withdraw,
        CooperativeSettle
    }

    struct Channel {
        // After opening the channel this value represents the settlement
        // window. This is the number of blocks that need to be mined between
        // closing the channel uncooperatively and settling the channel.
        // After the channel has been uncooperatively closed, this value
        // represents the block number after which settleChannel can be called.
        uint256 settle_block_number;

        ChannelState state;

        mapping(address => Participant) participants;
    }

    struct SettlementData {
        uint256 deposit;
        uint256 withdrawn;
        uint256 transferred;
        uint256 locked;
    }

    struct UnlockData {
        // Merkle root of the pending transfers tree from the Raiden client
        bytes32 locksroot;
        // Total amount of tokens locked in the pending transfers corresponding
        // to the `locksroot`
        uint256 locked_amount;
    }

    event ChannelOpened(
        uint256 indexed channel_identifier,
        address indexed participant1,
        address indexed participant2,
        uint256 settle_timeout
    );

    event ChannelNewDeposit(
        uint256 indexed channel_identifier,
        address indexed participant,
        uint256 total_deposit
    );

    // total_withdraw is how much the participant has withdrawn during the
    // lifetime of the channel. The actual amount which the participant withdrew
    // is `total_withdraw - total_withdraw_from_previous_event_or_zero`
    /* event ChannelWithdraw(
        uint256 indexed channel_identifier,
        address indexed participant,
        uint256 total_withdraw
    ); */

    event ChannelClosed(
        uint256 indexed channel_identifier,
        address indexed closing_participant,
        uint256 indexed nonce
    );

    event ChannelUnlocked(
        uint256 indexed channel_identifier,
        address indexed participant,
        address indexed partner,
        bytes32 locksroot,
        uint256 unlocked_amount,
        uint256 returned_tokens
    );

    event NonClosingBalanceProofUpdated(
        uint256 indexed channel_identifier,
        address indexed closing_participant,
        uint256 indexed nonce
    );

    event ChannelSettled(
        uint256 indexed channel_identifier,
        uint256 participant1_amount,
        uint256 participant2_amount
    );

    modifier onlyDeprecationExecutor() {
        require(msg.sender == deprecation_executor);
        _;
    }

    modifier isSafe() {
        require(safety_deprecation_switch == false);
        _;
    }

    modifier isOpen(uint256 channel_identifier) {
        require(channels[channel_identifier].state == ChannelState.Opened);
        _;
    }

    modifier settleTimeoutValid(uint256 timeout) {
        require(timeout >= settlement_timeout_min);
        require(timeout <= settlement_timeout_max);
        _;
    }

    constructor(
        address _token_address,
        address _secret_registry,
        uint256 _chain_id,
        uint256 _settlement_timeout_min,
        uint256 _settlement_timeout_max,
        address _deprecation_executor
    )
        public
    {
        require(_token_address != address(0x0));
        require(_secret_registry != address(0x0));
        require(_deprecation_executor != address(0x0));
        require(_chain_id > 0);
        require(_settlement_timeout_min > 0);
        require(_settlement_timeout_max > _settlement_timeout_min);
        require(contractExists(_token_address));
        require(contractExists(_secret_registry));

        token = Token(_token_address);

        secret_registry = SecretRegistry(_secret_registry);
        chain_id = _chain_id;
        settlement_timeout_min = _settlement_timeout_min;
        settlement_timeout_max = _settlement_timeout_max;

        // Make sure the contract is indeed a token contract
        require(token.totalSupply() > 0);

        deprecation_executor = _deprecation_executor;
    }

    function deprecate() isSafe onlyDeprecationExecutor public {
        safety_deprecation_switch = true;
    }

    /// @notice Opens a new channel between `participant1` and `participant2`.
    /// Can be called by anyone.
    /// @param participant1 Ethereum address of a channel participant.
    /// @param participant2 Ethereum address of the other channel participant.
    /// @param settle_timeout Number of blocks that need to be mined between a
    /// call to closeChannel and settleChannel.
    function openChannel(address participant1, address participant2, uint256 settle_timeout)
        isSafe
        settleTimeoutValid(settle_timeout)
        public
        returns (uint256)
    {
        bytes32 pair_hash;
        uint256 channel_identifier;

        // Red Eyes release token network limit
        require(token.balanceOf(address(this)) < token_network_deposit_limit);

        // First increment the counter
        // There will never be a channel with channel_identifier == 0
        channel_counter += 1;
        channel_identifier = channel_counter;

        pair_hash = getParticipantsHash(participant1, participant2);

        // There must only be one channel opened between two participants at
        // any moment in time.
        require(participants_hash_to_channel_identifier[pair_hash] == 0);
        participants_hash_to_channel_identifier[pair_hash] = channel_identifier;

        Channel storage channel = channels[channel_identifier];

        // We always increase the channel counter, therefore no channel data can already exist,
        // corresponding to this channel_identifier. This check must never fail.
        assert(channel.settle_block_number == 0);
        assert(channel.state == ChannelState.NonExistent);

        // Store channel information
        channel.settle_block_number = settle_timeout;
        channel.state = ChannelState.Opened;

        emit ChannelOpened(
            channel_identifier,
            participant1,
            participant2,
            settle_timeout
        );

        return channel_identifier;
    }

    /// @notice Sets the channel participant total deposit value.
    /// Can be called by anyone.
    /// @param channel_identifier Identifier for the channel on which this
    /// operation takes place.
    /// @param participant Channel participant whose deposit is being set.
    /// @param total_deposit The total amount of tokens that the participant
    /// will have as a deposit.
    /// @param partner Channel partner address, needed to compute the total
    /// channel deposit.
    function setTotalDeposit(
        uint256 channel_identifier,
        address participant,
        uint256 total_deposit,
        address partner
    )
        isSafe
        isOpen(channel_identifier)
        public
    {
        require(channel_identifier == getChannelIdentifier(participant, partner));
        require(total_deposit > 0);
        require(total_deposit <= channel_participant_deposit_limit);

        uint256 added_deposit;
        uint256 channel_deposit;

        Channel storage channel = channels[channel_identifier];
        Participant storage participant_state = channel.participants[participant];
        Participant storage partner_state = channel.participants[partner];

        // Calculate the actual amount of tokens that will be transferred
        added_deposit = total_deposit - participant_state.deposit;

        // The actual amount of tokens that will be transferred must be > 0
        require(added_deposit > 0);

        // Underflow check; we use <= because added_deposit == total_deposit for the first deposit

        require(added_deposit <= total_deposit);

        // This should never fail at this point. Added check for security, because we directly set
        // the participant_state.deposit = total_deposit, while we transfer `added_deposit` tokens.
        assert(participant_state.deposit + added_deposit == total_deposit);

        // Red Eyes release token network limit
        require(token.balanceOf(address(this)) + added_deposit <= token_network_deposit_limit);

        // Update the participant's channel deposit
        participant_state.deposit = total_deposit;

        // Calculate the entire channel deposit, to avoid overflow
        channel_deposit = participant_state.deposit + partner_state.deposit;
        // Overflow check
        require(channel_deposit >= participant_state.deposit);

        emit ChannelNewDeposit(
            channel_identifier,
            participant,
            participant_state.deposit
        );

        // Do the transfer
        require(token.transferFrom(msg.sender, address(this), added_deposit));
    }

    /* /// @notice Allows `participant` to withdraw tokens from the channel that he
    /// has with `partner`, without closing it. Can be called by anyone. Can
    /// only be called once per each signed withdraw message.
    /// @param channel_identifier Identifier for the channel on which this
    /// operation takes place.
    /// @param participant Channel participant, who will receive the withdrawn
    /// amount.
    /// @param total_withdraw Total amount of tokens that are marked as
    /// withdrawn from the channel during the channel lifecycle.
    /// @param participant_signature Participant's signature on the withdraw
    /// data.
    /// @param partner_signature Partner's signature on the withdraw data.
    function setTotalWithdraw(
        uint256 channel_identifier,
        address participant,
        uint256 total_withdraw,
        bytes participant_signature,
        bytes partner_signature
    )
        isOpen(channel_identifier)
        external
    {
        uint256 total_deposit;
        uint256 current_withdraw;
        address partner;

        require(total_withdraw > 0);

        // Authenticate both channel partners via there signatures:
        require(participant == recoverAddressFromWithdrawMessage(
            channel_identifier,
            participant,
            total_withdraw,
            participant_signature
        ));
        partner = recoverAddressFromWithdrawMessage(
            channel_identifier,
            participant,
            total_withdraw,
            partner_signature
        );

        // Validate that authenticated partners and the channel identifier match
        require(channel_identifier == getChannelIdentifier(participant, partner));

        // Read channel state after validating the function input
        Channel storage channel = channels[channel_identifier];
        Participant storage participant_state = channel.participants[participant];
        Participant storage partner_state = channel.participants[partner];

        total_deposit = participant_state.deposit + partner_state.deposit;

        // Entire withdrawn amount must not be bigger than the current channel deposit
        require((total_withdraw + partner_state.withdrawn_amount) <= total_deposit);
        require(total_withdraw <= (total_withdraw + partner_state.withdrawn_amount));

        // Using the total_withdraw (monotonically increasing) in the signed
        // message ensures that we do not allow replay attack to happen, by
        // using the same withdraw proof twice.
        // Next two lines enforce the monotonicity of total_withdraw and check for an underflow:
        // (we use <= because current_withdraw == total_withdraw for the first withdraw)
        current_withdraw = total_withdraw - participant_state.withdrawn_amount;
        require(current_withdraw <= total_withdraw);

        // The actual amount of tokens that will be transferred must be > 0 to disable the reuse of
        // withdraw messages completely.
        require(current_withdraw > 0);

        // This should never fail at this point. Added check for security, because we directly set
        // the participant_state.withdrawn_amount = total_withdraw,
        // while we transfer `current_withdraw` tokens.
        assert(participant_state.withdrawn_amount + current_withdraw == total_withdraw);

        emit ChannelWithdraw(
            channel_identifier,
            participant,
            total_withdraw
        );

        // Do the state change and tokens transfer
        participant_state.withdrawn_amount = total_withdraw;
        require(token.transfer(participant, current_withdraw));

        // This should never happen, as we have an overflow check in setTotalDeposit
        assert(total_deposit >= participant_state.deposit);
        assert(total_deposit >= partner_state.deposit);

        // A withdraw should never happen if a participant already has a
        // balance proof in storage. This should never fail as we use isOpen.
        assert(participant_state.nonce == 0);
        assert(partner_state.nonce == 0);

    } */

    /// @notice Close the channel defined by the two participant addresses. Only
    /// a participant may close the channel, providing a balance proof signed by
    /// its partner. Callable only once.
    /// @param channel_identifier Identifier for the channel on which this
    /// operation takes place.
    /// @param partner Channel partner of the `msg.sender`, who provided the
    /// signature.
    /// @param balance_hash Hash of (transferred_amount, locked_amount,
    /// locksroot).
    /// @param additional_hash Computed from the message. Used for message
    /// authentication.
    /// @param nonce Strictly monotonic value used to order transfers.
    /// @param signature Partner's signature of the balance proof data.
    function closeChannel(
        uint256 channel_identifier,
        address partner,
        bytes32 balance_hash,
        uint256 nonce,
        bytes32 additional_hash,
        bytes memory signature
    )
        isOpen(channel_identifier)
        public
    {
        require(channel_identifier == getChannelIdentifier(msg.sender, partner));

        address recovered_partner_address;

        Channel storage channel = channels[channel_identifier];

        channel.state = ChannelState.Closed;
        channel.participants[msg.sender].is_the_closer = true;

        // This is the block number at which the channel can be settled.
        channel.settle_block_number += uint256(block.number);

        // Nonce 0 means that the closer never received a transfer, therefore
        // never received a balance proof, or he is intentionally not providing
        // the latest transfer, in which case the closing party is going to
        // lose the tokens that were transferred to him.
        if (nonce > 0) {
            recovered_partner_address = recoverAddressFromBalanceProof(
                channel_identifier,
                balance_hash,
                nonce,
                additional_hash,
                signature
            );
            // Signature must be from the channel partner
            require(partner == recovered_partner_address);

            updateBalanceProofData(
                channel,
                recovered_partner_address,
                nonce,
                balance_hash
            );
        }

        emit ChannelClosed(channel_identifier, msg.sender, nonce);
    }

    /// @notice Called on a closed channel, the function allows the non-closing
    /// participant to provide the last balance proof, which modifies the
    /// closing participant's state. Can be called multiple times by anyone.
    /// @param channel_identifier Identifier for the channel on which this
    /// operation takes place.
    /// @param closing_participant Channel participant who closed the channel.
    /// @param non_closing_participant Channel participant who needs to update
    /// the balance proof.
    /// @param balance_hash Hash of (transferred_amount, locked_amount,
    /// locksroot).
    /// @param additional_hash Computed from the message. Used for message
    /// authentication.
    /// @param nonce Strictly monotonic value used to order transfers.
    /// @param closing_signature Closing participant's signature of the balance
    /// proof data.
    /// @param non_closing_signature Non-closing participant signature of the
    /// balance proof data.
    function updateNonClosingBalanceProof(
        uint256 channel_identifier,
        address closing_participant,
        address non_closing_participant,
        bytes32 balance_hash,
        uint256 nonce,
        bytes32 additional_hash,
        bytes calldata closing_signature,
        bytes calldata non_closing_signature
    )
        external
    {
        require(channel_identifier == getChannelIdentifier(
            closing_participant,
            non_closing_participant
        ));
        require(balance_hash != bytes32(0x0));
        require(nonce > 0);

        address recovered_non_closing_participant;
        address recovered_closing_participant;

        Channel storage channel = channels[channel_identifier];

        require(channel.state == ChannelState.Closed);

        // Calling this function after the settlement window is forbidden to
        // fix the following race condition:
        //
        // 1 A badly configured node A, that doesn't have a monitoring service
        //   and is temporarily offline does not call update during the
        //   settlement window.
        // 2 The well behaved partner B, who called close, sees the
        //   settlement window is over and calls settle. At this point the B's
        //   balance proofs which should be provided by A is missing, so B will
        //   call settle with its balance proof zeroed out.
        // 3 A restarts and calls update, which will change B's balance
        //   proof.
        // 4 At this point, the transactions from 2 and 3 are racing, and one
        //   of them will fail.
        //
        // To avoid the above race condition, which would require special
        // handling on both nodes, the call to update is forbidden after the
        // settlement window. This does not affect safety, since we assume the
        // nodes are always properly configured and have a monitoring service
        // available to call update on the user's behalf.
        require(channel.settle_block_number >= block.number);

        // We need the signature from the non-closing participant to allow
        // anyone to make this transaction. E.g. a monitoring service.
        recovered_non_closing_participant = recoverAddressFromBalanceProofUpdateMessage(
            channel_identifier,
            balance_hash,
            nonce,
            additional_hash,
            closing_signature,
            non_closing_signature
        );
        require(non_closing_participant == recovered_non_closing_participant);

        recovered_closing_participant = recoverAddressFromBalanceProof(
            channel_identifier,
            balance_hash,
            nonce,
            additional_hash,
            closing_signature
        );
        require(closing_participant == recovered_closing_participant);

        Participant storage closing_participant_state = channel.participants[closing_participant];
        // Make sure the first signature is from the closing participant
        require(closing_participant_state.is_the_closer);

        // Update the balance proof data for the closing_participant
        updateBalanceProofData(channel, closing_participant, nonce, balance_hash);

        emit NonClosingBalanceProofUpdated(
            channel_identifier,
            closing_participant,
            nonce
        );
    }

    /// @notice Settles the balance between the two parties. Note that arguments
    /// order counts: `participant1_transferred_amount +
    /// participant1_locked_amount` <= `participant2_transferred_amount +
    /// participant2_locked_amount`
    /// @param channel_identifier Identifier for the channel on which this
    /// operation takes place.
    /// @param participant1 Channel participant.
    /// @param participant1_transferred_amount The latest known amount of tokens
    /// transferred from `participant1` to `participant2`.
    /// @param participant1_locked_amount Amount of tokens owed by
    /// `participant1` to `participant2`, contained in locked transfers that
    /// will be retrieved by calling `unlock` after the channel is settled.
    /// @param participant1_locksroot The latest known merkle root of the
    /// pending hash-time locks of `participant1`, used to validate the unlocked
    /// proofs.
    /// @param participant2 Other channel participant.
    /// @param participant2_transferred_amount The latest known amount of tokens
    /// transferred from `participant2` to `participant1`.
    /// @param participant2_locked_amount Amount of tokens owed by
    /// `participant2` to `participant1`, contained in locked transfers that
    /// will be retrieved by calling `unlock` after the channel is settled.
    /// @param participant2_locksroot The latest known merkle root of the
    /// pending hash-time locks of `participant2`, used to validate the unlocked
    /// proofs.
    function settleChannel(
        uint256 channel_identifier,
        address participant1,
        uint256 participant1_transferred_amount,
        uint256 participant1_locked_amount,
        bytes32 participant1_locksroot,
        address participant2,
        uint256 participant2_transferred_amount,
        uint256 participant2_locked_amount,
        bytes32 participant2_locksroot
    )
        public
    {
        // There are several requirements that this function MUST enforce:
        // - it MUST never fail; therefore, any overflows or underflows must be
        // handled gracefully
        // - it MUST ensure that if participants use the latest valid balance proofs,
        // provided by the official Raiden client, the participants will be able
        // to receive correct final balances at the end of the channel lifecycle
        // - it MUST ensure that the participants cannot cheat by providing an
        // old, valid balance proof of their partner; meaning that their partner MUST
        // receive at least the amount of tokens that he would have received if
        // the latest valid balance proofs are used.
        // - the contract cannot determine if a balance proof is invalid (values
        // are not within the constraints enforced by the official Raiden client),
        // therefore it cannot ensure correctness. Users MUST use the official
        // Raiden clients for signing balance proofs.

        require(channel_identifier == getChannelIdentifier(participant1, participant2));

        bytes32 pair_hash;

        pair_hash = getParticipantsHash(participant1, participant2);
        Channel storage channel = channels[channel_identifier];

        require(channel.state == ChannelState.Closed);

        // Settlement window must be over
        require(channel.settle_block_number < block.number);

        Participant storage participant1_state = channel.participants[participant1];
        Participant storage participant2_state = channel.participants[participant2];

        require(verifyBalanceHashData(
            participant1_state,
            participant1_transferred_amount,
            participant1_locked_amount,
            participant1_locksroot
        ));

        require(verifyBalanceHashData(
            participant2_state,
            participant2_transferred_amount,
            participant2_locked_amount,
            participant2_locksroot
        ));

        // We are calculating the final token amounts that need to be
        // transferred to the participants now and the amount of tokens that
        // need to remain locked in the contract. These tokens can be unlocked
        // by calling `unlock`.
        // participant1_transferred_amount = the amount of tokens that
        //   participant1 will receive in this transaction.
        // participant2_transferred_amount = the amount of tokens that
        //   participant2 will receive in this transaction.
        // participant1_locked_amount = the amount of tokens remaining in the
        //   contract, representing pending transfers from participant1 to participant2.
        // participant2_locked_amount = the amount of tokens remaining in the
        //   contract, representing pending transfers from participant2 to participant1.
        // We are reusing variables due to the local variables number limit.
        // For better readability this can be refactored further.
        (
            participant1_transferred_amount,
            participant2_transferred_amount,
            participant1_locked_amount,
            participant2_locked_amount
        ) = getSettleTransferAmounts(
            participant1_state,
            participant1_transferred_amount,
            participant1_locked_amount,
            participant2_state,
            participant2_transferred_amount,
            participant2_locked_amount
        );

        // Remove the channel data from storage
        delete channel.participants[participant1];
        delete channel.participants[participant2];
        delete channels[channel_identifier];

        // Remove the pair's channel counter
        delete participants_hash_to_channel_identifier[pair_hash];

        // Store balance data needed for `unlock`, including the calculated
        // locked amounts remaining in the contract.
        storeUnlockData(
            channel_identifier,
            participant1,
            participant2,
            participant1_locked_amount,
            participant1_locksroot
        );
        storeUnlockData(
            channel_identifier,
            participant2,
            participant1,
            participant2_locked_amount,
            participant2_locksroot
        );

        emit ChannelSettled(
            channel_identifier,
            participant1_transferred_amount,
            participant2_transferred_amount
        );

        // Do the actual token transfers
        if (participant1_transferred_amount > 0) {
            require(token.transfer(participant1, participant1_transferred_amount));
        }

        if (participant2_transferred_amount > 0) {
            require(token.transfer(participant2, participant2_transferred_amount));
        }
    }

    /// @notice Unlocks all pending off-chain transfers from `partner` to
    /// `participant` and sends the locked tokens corresponding to locks with
    /// secrets registered on-chain to the `participant`. Locked tokens
    /// corresponding to locks where the secret was not revealed on-chain will
    /// return to the `partner`. Anyone can call unlock.
    /// @param channel_identifier Identifier for the channel on which this
    /// operation takes place.
    /// @param participant Address who will receive the claimable unlocked
    /// tokens.
    /// @param partner Address who sent the pending transfers and will receive
    /// the unclaimable unlocked tokens.
    /// @param merkle_tree_leaves The entire merkle tree of pending transfers
    /// that `partner` sent to `participant`.
    function unlock(
        uint256 channel_identifier,
        address participant,
        address partner,
        bytes memory merkle_tree_leaves
    )
        public
    {
        // Channel represented by channel_identifier must be settled and
        // channel data deleted
        require(channel_identifier != getChannelIdentifier(participant, partner));

        // After the channel is settled the storage is cleared, therefore the
        // value will be NonExistent and not Settled. The value Settled is used
        // for the external APIs
        require(channels[channel_identifier].state == ChannelState.NonExistent);

        require(merkle_tree_leaves.length > 0);

        bytes32 unlock_key;
        bytes32 computed_locksroot;
        uint256 unlocked_amount;
        uint256 locked_amount;
        uint256 returned_tokens;

        // Calculate the locksroot for the pending transfers and the amount of
        // tokens corresponding to the locked transfers with secrets revealed
        // on chain.
        (computed_locksroot, unlocked_amount) = getMerkleRootAndUnlockedAmount(
            merkle_tree_leaves
        );

        // The partner must have a non-empty locksroot on-chain that must be
        // the same as the computed locksroot.
        // Get the amount of tokens that have been left in the contract, to
        // account for the pending transfers `partner` -> `participant`.
        unlock_key = getUnlockIdentifier(channel_identifier, partner, participant);
        UnlockData storage unlock_data = unlock_identifier_to_unlock_data[unlock_key];
        locked_amount = unlock_data.locked_amount;

        // Locksroot must be the same as the computed locksroot
        require(unlock_data.locksroot == computed_locksroot);

        // There are no pending transfers if the locked_amount is 0.
        // Transaction must fail
        require(locked_amount > 0);

        // Make sure we don't transfer more tokens than previously reserved in
        // the smart contract.
        unlocked_amount = min(unlocked_amount, locked_amount);

        // Transfer the rest of the tokens back to the partner
        returned_tokens = locked_amount - unlocked_amount;

        // Remove partner's unlock data
        delete unlock_identifier_to_unlock_data[unlock_key];

        emit ChannelUnlocked(
            channel_identifier,
            participant,
            partner,
            computed_locksroot,
            unlocked_amount,
            returned_tokens
        );

        // Transfer the unlocked tokens to the participant. unlocked_amount can
        // be 0
        if (unlocked_amount > 0) {
            require(token.transfer(participant, unlocked_amount));
        }

        // Transfer the rest of the tokens back to the partner
        if (returned_tokens > 0) {
            require(token.transfer(partner, returned_tokens));
        }

        // At this point, this should always be true
        assert(locked_amount >= returned_tokens);
        assert(locked_amount >= unlocked_amount);
    }

    /* /// @notice Cooperatively settles the balances between the two channel
    /// participants and transfers the agreed upon token amounts to the
    /// participants. After this the channel lifecycle has ended and no more
    /// operations can be done on it.
    /// @param channel_identifier Identifier for the channel on which this
    /// operation takes place.
    /// @param participant1_address Address of channel participant.
    /// @param participant1_balance Amount of tokens that `participant1_address`
    /// must receive when the channel is settled and removed.
    /// @param participant2_address Address of the other channel participant.
    /// @param participant2_balance Amount of tokens that `participant2_address`
    /// must receive when the channel is settled and removed.
    /// @param participant1_signature Signature of `participant1_address` on the
    /// cooperative settle message.
    /// @param participant2_signature Signature of `participant2_address` on the
    /// cooperative settle message.
    function cooperativeSettle(
        uint256 channel_identifier,
        address participant1_address,
        uint256 participant1_balance,
        address participant2_address,
        uint256 participant2_balance,
        bytes participant1_signature,
        bytes participant2_signature
    )
        public
    {
        require(channel_identifier == getChannelIdentifier(
            participant1_address,
            participant2_address
        ));
        bytes32 pair_hash;
        address participant1;
        address participant2;
        uint256 total_available_deposit;

        pair_hash = getParticipantsHash(participant1_address, participant2_address);
        Channel storage channel = channels[channel_identifier];

        require(channel.state == ChannelState.Opened);

        participant1 = recoverAddressFromCooperativeSettleSignature(
            channel_identifier,
            participant1_address,
            participant1_balance,
            participant2_address,
            participant2_balance,
            participant1_signature
        );
        // The provided address must be the same as the recovered one
        require(participant1 == participant1_address);

        participant2 = recoverAddressFromCooperativeSettleSignature(
            channel_identifier,
            participant1_address,
            participant1_balance,
            participant2_address,
            participant2_balance,
            participant2_signature
        );
        // The provided address must be the same as the recovered one
        require(participant2 == participant2_address);

        Participant storage participant1_state = channel.participants[participant1];
        Participant storage participant2_state = channel.participants[participant2];

        total_available_deposit = getChannelAvailableDeposit(
            participant1_state,
            participant2_state
        );
        // The sum of the provided balances must be equal to the total
        // available deposit
        require(total_available_deposit == (participant1_balance + participant2_balance));
        // Overflow check for the balances addition from the above check.
        // This overflow should never happen if the token.transfer function is implemented
        // correctly. We do not control the token implementation, therefore we add this
        // check for safety.
        require(participant1_balance <= participant1_balance + participant2_balance);

        // Remove channel data from storage before doing the token transfers
        delete channel.participants[participant1];
        delete channel.participants[participant2];
        delete channels[channel_identifier];

        // Remove the pair's channel counter
        delete participants_hash_to_channel_identifier[pair_hash];

        emit ChannelSettled(channel_identifier, participant1_balance, participant2_balance);

        // Do the token transfers
        if (participant1_balance > 0) {
            require(token.transfer(participant1, participant1_balance));
        }

        if (participant2_balance > 0) {
            require(token.transfer(participant2, participant2_balance));
        }
    } */

    /// @notice Returns the unique identifier for the channel given by the
    /// contract.
    /// @param participant Address of a channel participant.
    /// @param partner Address of the other channel participant.
    /// @return Unique identifier for the channel. It can be 0 if channel does
    /// not exist.
    function getChannelIdentifier(address participant, address partner)
        view
        public
        returns (uint256)
    {
        require(participant != address(0x0));
        require(partner != address(0x0));
        require(participant != partner);

        bytes32 pair_hash = getParticipantsHash(participant, partner);
        return participants_hash_to_channel_identifier[pair_hash];
    }

    /// @dev Returns the channel specific data.
    /// @param channel_identifier Identifier for the channel on which this
    /// operation takes place.
    /// @param participant1 Address of a channel participant.
    /// @param participant2 Address of the other channel participant.
    /// @return Channel settle_block_number and state.
    function getChannelInfo(
        uint256 channel_identifier,
        address participant1,
        address participant2
    )
        view
        external
        returns (uint256, ChannelState)
    {
        bytes32 unlock_key1;
        bytes32 unlock_key2;

        Channel storage channel = channels[channel_identifier];
        ChannelState state = channel.state;  // This must **not** update the storage

        if (state == ChannelState.NonExistent &&
            channel_identifier > 0 &&
            channel_identifier <= channel_counter
        ) {
            // The channel has been settled, channel data is removed Therefore,
            // the channel state in storage is actually `0`, or `NonExistent`
            // However, for this view function, we return `Settled`, in order
            // to provide a consistent external API
            state = ChannelState.Settled;

            // We might still have data stored for future unlock operations
            // Only if we do not, we can consider the channel as `Removed`
            unlock_key1 = getUnlockIdentifier(channel_identifier, participant1, participant2);
            UnlockData storage unlock_data1 = unlock_identifier_to_unlock_data[unlock_key1];

            unlock_key2 = getUnlockIdentifier(channel_identifier, participant2, participant1);
            UnlockData storage unlock_data2 = unlock_identifier_to_unlock_data[unlock_key2];

            if (unlock_data1.locked_amount == 0 && unlock_data2.locked_amount == 0) {
                state = ChannelState.Removed;
            }
        }

        return (
            channel.settle_block_number,
            state
        );
    }

    /// @dev Returns the channel specific data.
    /// @param channel_identifier Identifier for the channel on which this
    /// operation takes place.
    /// @param participant Address of the channel participant whose data will be
    /// returned.
    /// @param partner Address of the channel partner.
    /// @return Participant's deposit, withdrawn_amount, whether the participant
    /// has called `closeChannel` or not, balance_hash, nonce, locksroot,
    /// locked_amount.
    function getChannelParticipantInfo(
            uint256 channel_identifier,
            address participant,
            address partner
    )
        view
        external
        returns (uint256, uint256, bool, bytes32, uint256, bytes32, uint256)
    {
        bytes32 unlock_key;

        Participant storage participant_state = channels[channel_identifier].participants[
            participant
        ];
        unlock_key = getUnlockIdentifier(channel_identifier, participant, partner);
        UnlockData storage unlock_data = unlock_identifier_to_unlock_data[unlock_key];

        return (
            participant_state.deposit,
            participant_state.withdrawn_amount,
            participant_state.is_the_closer,
            participant_state.balance_hash,
            participant_state.nonce,
            unlock_data.locksroot,
            unlock_data.locked_amount
        );
    }

    /// @dev Get the hash of the participant addresses, ordered
    /// lexicographically.
    /// @param participant Address of a channel participant.
    /// @param partner Address of the other channel participant.
    function getParticipantsHash(address participant, address partner)
        pure
        public
        returns (bytes32)
    {
        require(participant != address(0x0));
        require(partner != address(0x0));
        require(participant != partner);

        if (participant < partner) {
            return keccak256(abi.encodePacked(participant, partner));
        } else {
            return keccak256(abi.encodePacked(partner, participant));
        }
    }

    /// @dev Get the hash of the channel identifier and the participant
    /// addresses (whose ordering matters). The hash might be useful for
    /// the partner to look up the appropriate UnlockData to claim.
    /// @param channel_identifier Identifier for the channel which the
    /// UnlockData is about.
    /// @param participant Sender of the pending transfers that the UnlockData
    /// represents.
    /// @param partner Receiver of the pending transfers that the UnlockData
    /// represents.
    function getUnlockIdentifier(
        uint256 channel_identifier,
        address participant,
        address partner
    )
        pure
        public
        returns (bytes32)
    {
        require(participant != partner);
        return keccak256(abi.encodePacked(channel_identifier, participant, partner));
    }

    function updateBalanceProofData(
        Channel storage channel,
        address participant,
        uint256 nonce,
        bytes32 balance_hash
    )
        internal
    {
        Participant storage participant_state = channel.participants[participant];

        // Multiple calls to updateNonClosingBalanceProof can be made and we
        // need to store the last known balance proof data
        require(nonce > participant_state.nonce);

        participant_state.nonce = nonce;
        participant_state.balance_hash = balance_hash;
    }

    function storeUnlockData(
        uint256 channel_identifier,
        address participant,
        address partner,
        uint256 locked_amount,
        bytes32 locksroot
    )
        internal
    {
        // If there are transfers to unlock, store the locksroot and total
        // amount of tokens
        if (locked_amount == 0 || locksroot == 0) {
            return;
        }

        bytes32 key = getUnlockIdentifier(channel_identifier, participant, partner);
        UnlockData storage unlock_data = unlock_identifier_to_unlock_data[key];
        unlock_data.locksroot = locksroot;
        unlock_data.locked_amount = locked_amount;
    }

    function getChannelAvailableDeposit(
        Participant storage participant1_state,
        Participant storage participant2_state
    )
        view
        internal
        returns (uint256 total_available_deposit)
    {
        total_available_deposit = (
            participant1_state.deposit +
            participant2_state.deposit -
            participant1_state.withdrawn_amount -
            participant2_state.withdrawn_amount
        );
    }

    /// @dev Function that calculates the amount of tokens that the participants
    /// will receive when calling settleChannel.
    /// Check https://github.com/raiden-network/raiden-contracts/issues/188 for the settlement
    /// algorithm analysis and explanations.
    function getSettleTransferAmounts(
        Participant storage participant1_state,
        uint256 participant1_transferred_amount,
        uint256 participant1_locked_amount,
        Participant storage participant2_state,
        uint256 participant2_transferred_amount,
        uint256 participant2_locked_amount
    )
        view
        private
        returns (uint256, uint256, uint256, uint256)
    {
        // The scope of this function is to compute the settlement amounts that
        // the two channel participants will receive when calling settleChannel
        // and the locked amounts that remain in the contract, to account for
        // the pending, not finalized transfers, that will be received by the
        // participants when calling `unlock`.

        // The amount of tokens that participant1 MUST receive at the end of
        // the channel lifecycle (after settleChannel and unlock) is:
        // B1 = D1 - W1 + T2 - T1 + Lc2 - Lc1

        // The amount of tokens that participant2 MUST receive at the end of
        // the channel lifecycle (after settleChannel and unlock) is:
        // B2 = D2 - W2 + T1 - T2 + Lc1 - Lc2

        // B1 + B2 = TAD = D1 + D2 - W1 - W2
        // TAD = total available deposit at settlement time

        // L1 = Lc1 + Lu1
        // L2 = Lc2 + Lu2

        // where:
        // B1 = final balance of participant1 after the channel is removed
        // D1 = total amount deposited by participant1 into the channel
        // W1 = total amount withdrawn by participant1 from the channel
        // T2 = total amount transferred by participant2 to participant1 (finalized transfers)
        // T1 = total amount transferred by participant1 to participant2 (finalized transfers)
        // L1 = total amount of tokens locked in pending transfers, sent by
        //   participant1 to participant2
        // L2 = total amount of tokens locked in pending transfers, sent by
        //   participant2 to participant1
        // Lc2 = the amount that can be claimed by participant1 from the pending
        //   transfers (that have not been finalized off-chain), sent by
        //   participant2 to participant1. These are part of the locked amount
        //   value from participant2's balance proof. They are considered claimed
        //   if the secret corresponding to these locked transfers was registered
        //   on-chain, in the SecretRegistry contract, before the lock's expiration.
        // Lu1 = unclaimable locked amount from L1
        // Lc1 = the amount that can be claimed by participant2 from the pending
        //   transfers (that have not been finalized off-chain),
        //   sent by participant1 to participant2
        // Lu2 = unclaimable locked amount from L2

        // Notes:
        // 1) The unclaimble tokens from a locked amount will return to the sender.
        // At the time of calling settleChannel, the TokenNetwork contract does
        // not know what locked amounts are claimable or unclaimable.
        // 2) There are some Solidity constraints that make the calculations
        // more difficult: attention to overflows and underflows, that MUST be
        // handled without throwing.

        // Cases that require attention:
        // case1. If participant1 does NOT provide a balance proof or provides
        // an old balance proof.  participant2_transferred_amount can be [0,
        // real_participant2_transferred_amount) We MUST NOT punish
        // participant2.
        // case2. If participant2 does NOT provide a balance proof or provides
        // an old balance proof.  participant1_transferred_amount can be [0,
        // real_participant1_transferred_amount) We MUST NOT punish
        // participant1.
        // case3. If neither participants provide a balance proof, we just
        // subtract their withdrawn amounts from their deposits.

        // This is why, the algorithm implemented in Solidity is:
        // (explained at each step, below)
        // RmaxP1 = (T2 + L2) - (T1 + L1) + D1 - W1
        // RmaxP1 = min(TAD, RmaxP1)
        // RmaxP2 = TAD - RmaxP1
        // SL2 = min(RmaxP1, L2)
        // S1 = RmaxP1 - SL2
        // SL1 = min(RmaxP2, L1)
        // S2 = RmaxP2 - SL1

        // where:
        // RmaxP1 = due to possible over/underflows that only appear when using
        //    old balance proofs & the fact that settlement balance calculation
        //    is symmetric (we can calculate either RmaxP1 and RmaxP2 first,
        //    order does not affect result), this is a convention used to determine
        //    the maximum receivable amount of participant1 at settlement time
        // S1 = amount received by participant1 when calling settleChannel
        // SL1 = the maximum amount from L1 that can be locked in the
        //   TokenNetwork contract when calling settleChannel (due to overflows
        //   that only happen when using old balance proofs)
        // S2 = amount received by participant2 when calling settleChannel
        // SL2 = the maximum amount from L2 that can be locked in the
        //   TokenNetwork contract when calling settleChannel (due to overflows
        //   that only happen when using old balance proofs)

        uint256 participant1_amount;
        uint256 participant2_amount;
        uint256 total_available_deposit;

        SettlementData memory participant1_settlement;
        SettlementData memory participant2_settlement;

        participant1_settlement.deposit = participant1_state.deposit;
        participant1_settlement.withdrawn = participant1_state.withdrawn_amount;
        participant1_settlement.transferred = participant1_transferred_amount;
        participant1_settlement.locked = participant1_locked_amount;

        participant2_settlement.deposit = participant2_state.deposit;
        participant2_settlement.withdrawn = participant2_state.withdrawn_amount;
        participant2_settlement.transferred = participant2_transferred_amount;
        participant2_settlement.locked = participant2_locked_amount;

        // TAD = D1 + D2 - W1 - W2 = total available deposit at settlement time
        total_available_deposit = getChannelAvailableDeposit(
            participant1_state,
            participant2_state
        );

        // RmaxP1 = (T2 + L2) - (T1 + L1) + D1 - W1
        // This amount is the maximum possible amount that participant1 can
        // receive at settlement time and also contains the entire locked amount
        //  of the pending transfers from participant2 to participant1.
        participant1_amount = getMaxPossibleReceivableAmount(
            participant1_settlement,
            participant2_settlement
        );

        // RmaxP1 = min(TAD, RmaxP1)
        // We need to bound this to the available channel deposit in order to
        // not send tokens from other channels. The only case where TAD is
        // smaller than RmaxP1 is when at least one balance proof is old.
        participant1_amount = min(participant1_amount, total_available_deposit);

        // RmaxP2 = TAD - RmaxP1
        // Now it is safe to subtract without underflow
        participant2_amount = total_available_deposit - participant1_amount;

        // SL2 = min(RmaxP1, L2)
        // S1 = RmaxP1 - SL2
        // Both operations are done by failsafe_subtract
        // We take out participant2's pending transfers locked amount, bounding
        // it by the maximum receivable amount of participant1
        (participant1_amount, participant2_locked_amount) = failsafe_subtract(
            participant1_amount,
            participant2_locked_amount
        );

        // SL1 = min(RmaxP2, L1)
        // S2 = RmaxP2 - SL1
        // Both operations are done by failsafe_subtract
        // We take out participant1's pending transfers locked amount, bounding
        // it by the maximum receivable amount of participant2
        (participant2_amount, participant1_locked_amount) = failsafe_subtract(
            participant2_amount,
            participant1_locked_amount
        );

        // This should never throw:
        // S1 and S2 MUST be smaller than TAD
        assert(participant1_amount <= total_available_deposit);
        assert(participant2_amount <= total_available_deposit);
        // S1 + S2 + SL1 + SL2 == TAD
        assert(total_available_deposit == (
            participant1_amount +
            participant2_amount +
            participant1_locked_amount +
            participant2_locked_amount
        ));

        return (
            participant1_amount,
            participant2_amount,
            participant1_locked_amount,
            participant2_locked_amount
        );
    }

    function getMaxPossibleReceivableAmount(
        SettlementData memory participant1_settlement,
        SettlementData memory participant2_settlement
    )
        pure
        internal
        returns (uint256)
    {
        uint256 participant1_max_transferred;
        uint256 participant2_max_transferred;
        uint256 participant1_net_max_received;
        uint256 participant1_max_amount;

        // This is the maximum possible amount that participant1 could transfer
        // to participant2, if all the pending lock secrets have been
        // registered
        participant1_max_transferred = failsafe_addition(
            participant1_settlement.transferred,
            participant1_settlement.locked
        );

        // This is the maximum possible amount that participant2 could transfer
        // to participant1, if all the pending lock secrets have been
        // registered
        participant2_max_transferred = failsafe_addition(
            participant2_settlement.transferred,
            participant2_settlement.locked
        );

        // We enforce this check artificially, in order to get rid of hard
        // to deal with over/underflows. Settlement balance calculation is
        // symmetric (we can calculate either RmaxP1 and RmaxP2 first, order does
        // not affect result). This means settleChannel must be called with
        // ordered values.
        require(participant2_max_transferred >= participant1_max_transferred);

        assert(participant1_max_transferred >= participant1_settlement.transferred);
        assert(participant2_max_transferred >= participant2_settlement.transferred);

        // This is the maximum amount that participant1 can receive at settlement time
        participant1_net_max_received = (
            participant2_max_transferred -
            participant1_max_transferred
        );

        // Next, we add the participant1's deposit and subtract the already
        // withdrawn amount
        participant1_max_amount = failsafe_addition(
            participant1_net_max_received,
            participant1_settlement.deposit
        );

        // Subtract already withdrawn amount
        (participant1_max_amount, ) = failsafe_subtract(
            participant1_max_amount,
            participant1_settlement.withdrawn
        );
        return participant1_max_amount;
    }

    function verifyBalanceHashData(
        Participant storage participant,
        uint256 transferred_amount,
        uint256 locked_amount,
        bytes32 locksroot
    )
        view
        internal
        returns (bool)
    {
        // When no balance proof has been provided, we need to check this
        // separately because hashing values of 0 outputs a value != 0
        if (participant.balance_hash == 0 &&
            transferred_amount == 0 &&
            locked_amount == 0 &&
            locksroot == 0
        ) {
            return true;
        }

        // Make sure the hash of the provided state is the same as the stored
        // balance_hash
        return participant.balance_hash == keccak256(abi.encodePacked(
            transferred_amount,
            locked_amount,
            locksroot
        ));
    }

    function recoverAddressFromBalanceProof(
        uint256 channel_identifier,
        bytes32 balance_hash,
        uint256 nonce,
        bytes32 additional_hash,
        bytes memory signature
    )
        view
        internal
        returns (address signature_address)
    {
        // Length of the actual message: 20 + 32 + 32 + 32 + 32 + 32 + 32
        string memory message_length = '212';

        bytes32 message_hash = keccak256(abi.encodePacked(
            signature_prefix,
            message_length,
            address(this),
            chain_id,
            uint256(MessageTypeId.BalanceProof),
            channel_identifier,
            balance_hash,
            nonce,
            additional_hash
        ));

        signature_address = ECVerify.ecverify(message_hash, signature);
    }

    function recoverAddressFromBalanceProofUpdateMessage(
        uint256 channel_identifier,
        bytes32 balance_hash,
        uint256 nonce,
        bytes32 additional_hash,
        bytes memory closing_signature,
        bytes memory non_closing_signature
    )
        view
        internal
        returns (address signature_address)
    {
        // Length of the actual message: 20 + 32 + 32 + 32 + 32 + 32 + 32 + 65
        string memory message_length = '277';

        bytes32 message_hash = keccak256(abi.encodePacked(
            signature_prefix,
            message_length,
            address(this),
            chain_id,
            uint256(MessageTypeId.BalanceProofUpdate),
            channel_identifier,
            balance_hash,
            nonce,
            additional_hash,
            closing_signature
        ));

        signature_address = ECVerify.ecverify(message_hash, non_closing_signature);
    }

    /* function recoverAddressFromCooperativeSettleSignature(
        uint256 channel_identifier,
        address participant1,
        uint256 participant1_balance,
        address participant2,
        uint256 participant2_balance,
        bytes signature
    )
        view
        internal
        returns (address signature_address)
    {
        // Length of the actual message: 20 + 32 + 32 + 32 + 20 + 32 + 20 + 32
        string memory message_length = '220';

        bytes32 message_hash = keccak256(abi.encodePacked(
            signature_prefix,
            message_length,
            address(this),
            chain_id,
            uint256(MessageTypeId.CooperativeSettle),
            channel_identifier,
            participant1,
            participant1_balance,
            participant2,
            participant2_balance
        ));

        signature_address = ECVerify.ecverify(message_hash, signature);
    } */

    /* function recoverAddressFromWithdrawMessage(
        uint256 channel_identifier,
        address participant,
        uint256 total_withdraw,
        bytes signature
    )
        view
        internal
        returns (address signature_address)
    {
        // Length of the actual message: 20 + 32 + 32 + 32 + 20 + 32
        string memory message_length = '168';

        bytes32 message_hash = keccak256(abi.encodePacked(
            signature_prefix,
            message_length,
            address(this),
            chain_id,
            uint256(MessageTypeId.Withdraw),
            channel_identifier,
            participant,
            total_withdraw
        ));

        signature_address = ECVerify.ecverify(message_hash, signature);
    } */

    /// @dev Calculates the merkle root for the pending transfers data and
    /// calculates the amount of tokens that can be unlocked because the secret
    /// was registered on-chain.
    function getMerkleRootAndUnlockedAmount(bytes memory merkle_tree_leaves)
        view
        internal
        returns (bytes32, uint256)
    {
        uint256 length = merkle_tree_leaves.length;

        // each merkle_tree lock component has this form:
        // (locked_amount || expiration_block || secrethash) = 3 * 32 bytes
        require(length % 96 == 0);

        uint256 i;
        uint256 total_unlocked_amount;
        uint256 unlocked_amount;
        bytes32 lockhash;
        bytes32 merkle_root;

        bytes32[] memory merkle_layer = new bytes32[](length / 96 + 1);

        for (i = 32; i < length; i += 96) {
            (lockhash, unlocked_amount) = getLockDataFromMerkleTree(merkle_tree_leaves, i);
            total_unlocked_amount += unlocked_amount;
            merkle_layer[i / 96] = lockhash;
        }

        length /= 96;

        while (length > 1) {
            if (length % 2 != 0) {
                merkle_layer[length] = merkle_layer[length - 1];
                length += 1;
            }

            for (i = 0; i < length - 1; i += 2) {
                if (merkle_layer[i] == merkle_layer[i + 1]) {
                    lockhash = merkle_layer[i];
                } else if (merkle_layer[i] < merkle_layer[i + 1]) {
                    lockhash = keccak256(abi.encodePacked(merkle_layer[i], merkle_layer[i + 1]));
                } else {
                    lockhash = keccak256(abi.encodePacked(merkle_layer[i + 1], merkle_layer[i]));
                }
                merkle_layer[i / 2] = lockhash;
            }
            length = i / 2;
        }

        merkle_root = merkle_layer[0];

        return (merkle_root, total_unlocked_amount);
    }

    function getLockDataFromMerkleTree(bytes memory merkle_tree_leaves, uint256 offset)
        view
        internal
        returns (bytes32, uint256)
    {
        uint256 expiration_block;
        uint256 locked_amount;
        uint256 reveal_block;
        bytes32 secrethash;
        bytes32 lockhash;

        if (merkle_tree_leaves.length <= offset) {
            return (lockhash, 0);
        }

        assembly {
            expiration_block := mload(add(merkle_tree_leaves, offset))
            locked_amount := mload(add(merkle_tree_leaves, add(offset, 32)))
            secrethash := mload(add(merkle_tree_leaves, add(offset, 64)))
        }

        // Calculate the lockhash for computing the merkle root
        lockhash = keccak256(abi.encodePacked(expiration_block, locked_amount, secrethash));

        // Check if the lock's secret was revealed in the SecretRegistry The
        // secret must have been revealed in the SecretRegistry contract before
        // the lock's expiration_block in order for the hash time lock transfer
        // to be successful.
        reveal_block = secret_registry.getSecretRevealBlockHeight(secrethash);
        if (reveal_block == 0 || expiration_block <= reveal_block) {
            locked_amount = 0;
        }

        return (lockhash, locked_amount);
    }

    function min(uint256 a, uint256 b) pure internal returns (uint256)
    {
        return a > b ? b : a;
    }

    function max(uint256 a, uint256 b) pure internal returns (uint256)
    {
        return a > b ? a : b;
    }

    /// @dev Special subtraction function that does not fail when underflowing.
    /// @param a Minuend
    /// @param b Subtrahend
    /// @return Minimum between the result of the subtraction and 0, the maximum
    /// subtrahend for which no underflow occurs.
    function failsafe_subtract(uint256 a, uint256 b)
        pure
        internal
        returns (uint256, uint256)
    {
        return a > b ? (a - b, b) : (0, a);
    }

    /// @dev Special addition function that does not fail when overflowing.
    /// @param a Addend
    /// @param b Addend
    /// @return Maximum between the result of the addition or the maximum
    /// uint256 value.
    function failsafe_addition(uint256 a, uint256 b)
        pure
        internal
        returns (uint256)
    {
        uint256 sum = a + b;
        return sum >= a ? sum : MAX_SAFE_UINT256;
    }
}


/// @title TokenNetworkRegistry
/// @notice The TokenNetwork Registry deploys new TokenNetwork contracts for the
/// Raiden Network protocol.
contract TokenNetworkRegistry is Utils {

    string constant public contract_version = "0.6.0";
    address public secret_registry_address;
    uint256 public chain_id;
    uint256 public settlement_timeout_min;
    uint256 public settlement_timeout_max;

    // Only for the limited Red Eyes release
    address public deprecation_executor;
    bool public token_network_created = false;

    // Token address => TokenNetwork address
    mapping(address => address) public token_to_token_networks;

    event TokenNetworkCreated(address indexed token_address, address indexed token_network_address);

    modifier canCreateTokenNetwork() {
        require(token_network_created == false);
        _;
    }

    constructor(
        address _secret_registry_address,
        uint256 _chain_id,
        uint256 _settlement_timeout_min,
        uint256 _settlement_timeout_max
    )
        public
    {
        require(_chain_id > 0);
        require(_settlement_timeout_min > 0);
        require(_settlement_timeout_max > 0);
        require(_settlement_timeout_max > _settlement_timeout_min);
        require(_secret_registry_address != address(0x0));
        require(contractExists(_secret_registry_address));
        secret_registry_address = _secret_registry_address;
        chain_id = _chain_id;
        settlement_timeout_min = _settlement_timeout_min;
        settlement_timeout_max = _settlement_timeout_max;

        deprecation_executor = msg.sender;
    }

    /// @notice Deploy a new TokenNetwork contract for the Token deployed at
    /// `_token_address`.
    /// @param _token_address Ethereum address of an already deployed token, to
    /// be used in the new TokenNetwork contract.
    function createERC20TokenNetwork(address _token_address)
        canCreateTokenNetwork
        external
        returns (address token_network_address)
    {
        require(token_to_token_networks[_token_address] == address(0x0));

        // We limit the number of token networks to 1 for the Bug Bounty release
        token_network_created = true;

        TokenNetwork token_network;

        // Token contract checks are in the corresponding TokenNetwork contract
        token_network = new TokenNetwork(
            _token_address,
            secret_registry_address,
            chain_id,
            settlement_timeout_min,
            settlement_timeout_max,
            deprecation_executor
        );

        token_network_address = address(token_network);

        token_to_token_networks[_token_address] = token_network_address;
        emit TokenNetworkCreated(_token_address, token_network_address);

        return token_network_address;
    }
}

    Contract ABI  
[{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"token_to_token_networks","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"settlement_timeout_max","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"deprecation_executor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"chain_id","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token_address","type":"address"}],"name":"createERC20TokenNetwork","outputs":[{"name":"token_network_address","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"contract_address","type":"address"}],"name":"contractExists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contract_version","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token_network_created","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"settlement_timeout_min","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"secret_registry_address","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_secret_registry_address","type":"address"},{"name":"_chain_id","type":"uint256"},{"name":"_settlement_timeout_min","type":"uint256"},{"name":"_settlement_timeout_max","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token_address","type":"address"},{"indexed":true,"name":"token_network_address","type":"address"}],"name":"TokenNetworkCreated","type":"event"}]

  Contract Creation Code Switch To Opcodes View
60806040526000600460146101000a81548160ff02191690831515021790555034801561002b57600080fd5b506040516080806144a98339810180604052608081101561004b57600080fd5b810190808051906020019092919080519060200190929190805190602001909291908051906020019092919050505060008311151561008957600080fd5b60008211151561009857600080fd5b6000811115156100a757600080fd5b81811115156100b557600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141515156100f157600080fd5b610109846101b3640100000000026401000000009004565b151561011457600080fd5b836000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600181905550816002819055508060038190555033600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505050506101c6565b600080823b905060008111915050919050565b6142d4806101d56000396000f3fe608060405234801561001057600080fd5b50600436106100bb576000357c0100000000000000000000000000000000000000000000000000000000900480637709bc78116100835780637709bc781461024e578063b32c65c8146102aa578063b61c40831461032d578063b8378f751461034f578063d0ad4bec1461036d576100bb565b80630fabd9e7146100c0578063224df42f1461014457806323aa8174146101625780633af973b1146101ac5780634cf71a04146101ca575b600080fd5b610102600480360360208110156100d657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506103b7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61014c6103ea565b6040518082815260200191505060405180910390f35b61016a6103f0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101b4610416565b6040518082815260200191505060405180910390f35b61020c600480360360208110156101e057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061041c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6102906004803603602081101561026457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610701565b604051808215151515815260200191505060405180910390f35b6102b2610714565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102f25780820151818401526020810190506102d7565b50505050905090810190601f16801561031f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61033561074d565b604051808215151515815260200191505060405180910390f35b610357610760565b6040518082815260200191505060405180910390f35b610375610766565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60056020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60035481565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015481565b6000801515600460149054906101000a900460ff16151514151561043f57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415156104d957600080fd5b6001600460146101000a81548160ff0219169083151502179055506000826000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600154600254600354600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661054d61078b565b808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018581526020018481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019650505050505050604051809103906000f08015801561061a573d6000803e3d6000fd5b50905080915081600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167ff11a7558a113d9627989c5edf26cbd19143b7375248e621c8e30ac9e0847dc3f60405160405180910390a381915050919050565b600080823b905060008111915050919050565b6040805190810160405280600581526020017f302e362e3000000000000000000000000000000000000000000000000000000081525081565b600460149054906101000a900460ff1681565b60025481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b604051613b0d8061079c8339019056fe60806040526000600660146101000a81548160ff0219169083151502179055503480156200002c57600080fd5b5060405160c08062003b0d833981018060405260c08110156200004e57600080fd5b81019080805190602001909291908051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614151515620000ce57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16141515156200010b57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515156200014857600080fd5b6000841115156200015857600080fd5b6000831115156200016857600080fd5b82821115156200017757600080fd5b620001918662000376640100000000026401000000009004565b15156200019d57600080fd5b620001b78562000376640100000000026401000000009004565b1515620001c357600080fd5b856000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555084600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555083600281905550826003819055508160048190555060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040160206040518083038186803b158015620002df57600080fd5b505afa158015620002f4573d6000803e3d6000fd5b505050506040513d60208110156200030b57600080fd5b81019080805190602001909291905050501115156200032957600080fd5b80600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050505062000389565b600080823b905060008111915050919050565b61377480620003996000396000f3fe608060405234801561001057600080fd5b50600436106101e1576000357c0100000000000000000000000000000000000000000000000000000000900480637c4734f411610116578063b8378f75116100b4578063ee4516d91161008e578063ee4516d914610aa7578063fadc554b14610b57578063fc0c546a14610c8e578063fe49ba1c14610cd8576101e1565b8063b8378f751461092f578063db45479b1461094d578063e5949b5d14610a50576101e1565b8063938bcd67116100f0578063938bcd67146107675780639cadb159146107df578063b32c65c81461088a578063b7506d701461090d576101e1565b80637c4734f4146105d5578063838d6e051461064d57806387234237146106e4576101e1565b80634845be761161018357806363ea01431161015d57806363ea0143146104c5578063679b37631461053d57806371e759921461055b5780637709bc7814610579576101e1565b80634845be7614610447578063524bef8a146104655780635d6e441b146104a7576101e1565b8063224df42f116101bf578063224df42f1461037757806323aa81741461039557806324d73a93146103df5780633af973b114610429576101e1565b806303d9d253146101e65780630a798f24146102eb5780630fcc0c281461036d575b600080fd5b6102e9600480360360808110156101fc57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561026357600080fd5b82018360208201111561027557600080fd5b8035906020019184600183028401116401000000008311171561029757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610d5a565b005b6103576004803603606081101561030157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611128565b6040518082815260200191505060405180910390f35b6103756113d5565b005b61037f611470565b6040518082815260200191505060405180910390f35b61039d611476565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103e761149c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6104316114c2565b6040518082815260200191505060405180910390f35b61044f6114c8565b6040518082815260200191505060405180910390f35b6104916004803603602081101561047b57600080fd5b81019080803590602001909291905050506114d5565b6040518082815260200191505060405180910390f35b6104af6114ed565b6040518082815260200191505060405180910390f35b61053b600480360360808110156104db57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506114f9565b005b610545611951565b6040518082815260200191505060405180910390f35b610563611957565b6040518082815260200191505060405180910390f35b6105bb6004803603602081101561058f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061197b565b604051808215151515815260200191505060405180910390f35b610637600480360360408110156105eb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061198e565b6040518082815260200191505060405180910390f35b6106b96004803603606081101561066357600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611bd0565b604051808381526020018260048111156106cf57fe5b60ff1681526020019250505060405180910390f35b6106ec611cc3565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561072c578082015181840152602081019050610711565b50505050905090810190601f1680156107595780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6107c96004803603604081101561077d57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611cfc565b6040518082815260200191505060405180910390f35b61088860048036036101208110156107f657600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050611ddb565b005b6108926122ff565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108d25780820151818401526020810190506108b7565b50505050905090810190601f1680156108ff5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610915612338565b604051808215151515815260200191505060405180910390f35b61093761234b565b6040518082815260200191505060405180910390f35b610a4e600480360360c081101561096357600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190803590602001906401000000008111156109c857600080fd5b8201836020820111156109da57600080fd5b803590602001918460018302840111640100000000831117156109fc57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050612351565b005b610a7c60048036036020811015610a6657600080fd5b810190808035906020019092919050505061250d565b60405180838152602001826004811115610a9257fe5b60ff1681526020019250505060405180910390f35b610b1360048036036060811015610abd57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061253e565b604051808881526020018781526020018615151515815260200185815260200184815260200183815260200182815260200197505050505050505060405180910390f35b610c8c6004803603610100811015610b6e57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190640100000000811115610bf357600080fd5b820183602082011115610c0557600080fd5b80359060200191846001830284011164010000000083111715610c2757600080fd5b909192939192939080359060200190640100000000811115610c4857600080fd5b820183602082011115610c5a57600080fd5b80359060200191846001830284011164010000000083111715610c7c57600080fd5b9091929391929390505050612613565b005b610c966128d1565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610d4460048036036060811015610cee57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506128f6565b6040518082815260200191505060405180910390f35b610d648383611cfc565b8414151515610d7257600080fd5b60006004811115610d7f57fe5b6007600086815260200190815260200160002060010160009054906101000a900460ff166004811115610dae57fe5b141515610dba57600080fd5b60008151111515610dca57600080fd5b6000806000806000610ddb866129e9565b8094508195505050610dee89888a6128f6565b9450600060096000878152602001908152602001600020905080600101549250848160000154141515610e2057600080fd5b600083111515610e2f57600080fd5b610e398484612cfe565b9350838303915060096000878152602001908152602001600020600080820160009055600182016000905550508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff168b7f8c03cf01b3d4e6068cc494e6fe02aa9e3d4af069d37c32ecc3b241af5c37e6c088888760405180848152602001838152602001828152602001935050505060405180910390a46000841115610ff0576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8a866040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015610fa957600080fd5b505af1158015610fbd573d6000803e3d6000fd5b505050506040513d6020811015610fd357600080fd5b81019080805190602001909291905050501515610fef57600080fd5b5b6000821115611104576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156110bd57600080fd5b505af11580156110d1573d6000803e3d6000fd5b505050506040513d60208110156110e757600080fd5b8101908080519060200190929190505050151561110357600080fd5b5b81831015151561111057fe5b83831015151561111c57fe5b50505050505050505050565b6000801515600660149054906101000a900460ff16151514151561114b57600080fd5b81600354811015151561115d57600080fd5b600454811115151561116e57600080fd5b600080680d8d726b7177a800006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561123557600080fd5b505afa158015611249573d6000803e3d6000fd5b505050506040513d602081101561125f57600080fd5b810190808051906020019092919050505010151561127c57600080fd5b6001600560008282540192505081905550600554905061129c878761198e565b9150600060086000848152602001908152602001600020541415156112c057600080fd5b8060086000848152602001908152602001600020819055506000600760008381526020019081526020016000209050600081600001541415156112ff57fe5b6000600481111561130c57fe5b8160010160009054906101000a900460ff16600481111561132957fe5b14151561133257fe5b85816000018190555060018160010160006101000a81548160ff0219169083600481111561135c57fe5b02179055508673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16837f669a4b0ac0b9994c0f82ed4dbe07bb421fe74e5951725af4f139c7443ebf049d896040518082815260200191505060405180910390a4819450505050509392505050565b60001515600660149054906101000a900460ff1615151415156113f757600080fd5b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561145357600080fd5b6001600660146101000a81548160ff021916908315150217905550565b60045481565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025481565b680d8d726b7177a8000081565b60086020528060005260406000206000915090505481565b67010a741a4627800081565b60001515600660149054906101000a900460ff16151514151561151b57600080fd5b836001600481111561152957fe5b6007600083815260200190815260200160002060010160009054906101000a900460ff16600481111561155857fe5b14151561156457600080fd5b61156e8483611cfc565b8514151561157b57600080fd5b60008311151561158a57600080fd5b67010a741a4627800083111515156115a157600080fd5b600080600060076000898152602001908152602001600020905060008160020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008260020160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905081600001548803945060008511151561165d57600080fd5b87851115151561166c57600080fd5b878583600001540114151561167d57fe5b680d8d726b7177a80000856000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561174257600080fd5b505afa158015611756573d6000803e3d6000fd5b505050506040513d602081101561176c57600080fd5b8101908080519060200190929190505050011115151561178b57600080fd5b87826000018190555080600001548260000154019350816000015484101515156117b457600080fd5b8873ffffffffffffffffffffffffffffffffffffffff168a7f2b55547a3b586ab51f65ee9ce4927fa6d25191388299988e89e059a02f9dd44584600001546040518082815260200191505060405180910390a36000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b1580156118ff57600080fd5b505af1158015611913573d6000803e3d6000fd5b505050506040513d602081101561192957600080fd5b8101908080519060200190929190505050151561194557600080fd5b50505050505050505050565b60055481565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b600080823b905060008111915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141515156119cb57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515611a0757600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515611a4257600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161015611b22578282604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140192505050604051602081830303815290604052805190602001209050611bca565b8183604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401925050506040516020818303038152906040528051906020012090505b92915050565b600080600080600060076000898152602001908152602001600020905060008160010160009054906101000a900460ff16905060006004811115611c1057fe5b816004811115611c1c57fe5b148015611c295750600089115b8015611c3757506005548911155b15611cad5760039050611c4b8989896128f6565b93506000600960008681526020019081526020016000209050611c6f8a898b6128f6565b9350600060096000868152602001908152602001600020905060008260010154148015611ca0575060008160010154145b15611caa57600492505b50505b8160000154819550955050505050935093915050565b6040805190810160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525081565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515611d3957600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515611d7557600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515611db057600080fd5b6000611dbc848461198e565b9050600860008281526020019081526020016000205491505092915050565b611de58885611cfc565b89141515611df257600080fd5b6000611dfe898661198e565b90506000600760008c8152602001908152602001600020905060026004811115611e2457fe5b8160010160009054906101000a900460ff166004811115611e4157fe5b141515611e4d57600080fd5b438160000154101515611e5f57600080fd5b60008160020160008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008260020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050611ef5828c8c8c612d17565b1515611f0057600080fd5b611f0c81888888612d17565b1515611f1757600080fd5b611f25828c8c848b8b612da0565b809950819d50829a50839e50505050508260020160008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008082016000905560018201600090556002820160006101000a81549060ff02191690556003820160009055600482016000905550508260020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008082016000905560018201600090556002820160006101000a81549060ff0219169055600382016000905560048201600090555050600760008e81526020019081526020016000206000808201600090556001820160006101000a81549060ff02191690555050600860008581526020019081526020016000206000905561207b8d8d8a8d8d612eaf565b6120888d898e8989612eaf565b8c7f0e239ef20c651bd0bc45e6f6a5fd46252d77d39d6602103e347add00cabdb0b48c89604051808381526020018281526020019250505060405180910390a260008b11156121dc576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8d8d6040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561219557600080fd5b505af11580156121a9573d6000803e3d6000fd5b505050506040513d60208110156121bf57600080fd5b810190808051906020019092919050505015156121db57600080fd5b5b60008711156122f0576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89896040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156122a957600080fd5b505af11580156122bd573d6000803e3d6000fd5b505050506040513d60208110156122d357600080fd5b810190808051906020019092919050505015156122ef57600080fd5b5b50505050505050505050505050565b6040805190810160405280600581526020017f302e362e3000000000000000000000000000000000000000000000000000000081525081565b600660149054906101000a900460ff1681565b60035481565b856001600481111561235f57fe5b6007600083815260200190815260200160002060010160009054906101000a900460ff16600481111561238e57fe5b14151561239a57600080fd5b6123a43387611cfc565b871415156123b157600080fd5b600080600760008a8152602001908152602001600020905060028160010160006101000a81548160ff021916908360048111156123ea57fe5b021790555060018160020160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160006101000a81548160ff02191690831515021790555043816000016000828254019250508190555060008611156124bd576124748988888888612f0d565b91508173ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff161415156124b057600080fd5b6124bc8183888a6130e3565b5b853373ffffffffffffffffffffffffffffffffffffffff168a7f5fe3d4a343010393184843ef4873386b572e844e89f6b41c9f60f5ab912fbdfe60405160405180910390a4505050505050505050565b60076020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16905082565b6000806000806000806000806000600760008d815260200190815260200160002060020160008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506125ac8c8c8c6128f6565b91506000600960008481526020019081526020016000209050816000015482600101548360020160009054906101000a900460ff16846003015485600401548560000154866001015499509950995099509950995099505050509397509397509397909450565b61261d8989611cfc565b8a14151561262a57600080fd5b6000600102871415151561263d57600080fd5b60008611151561264c57600080fd5b6000806000600760008e815260200190815260200160002090506002600481111561267357fe5b8160010160009054906101000a900460ff16600481111561269057fe5b14151561269c57600080fd5b438160000154101515156126af57600080fd5b6127458d8b8b8b8b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050613153565b92508273ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff1614151561278157600080fd5b6127d28d8b8b8b8b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612f0d565b91508173ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff1614151561280e57600080fd5b60008160020160008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060020160009054906101000a900460ff16151561287057600080fd5b61287c828e8c8e6130e3565b898d73ffffffffffffffffffffffffffffffffffffffff168f7f09bd10d8ee6f30d654401133d6eac60e091a0d8e13f54005754de9394c11fbd360405160405180910390a45050505050505050505050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561293357600080fd5b838383604051602001808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140193505050506040516020818303038152906040528051906020012090509392505050565b6000806000835190506000606082811515612a0057fe5b06141515612a0d57600080fd5b600080600080600060606001606088811515612a2557fe5b0401604051908082528060200260200182016040528015612a555781602001602082028038833980820191505090505b509050602095505b86861015612ab057612a6f8a8761337f565b809550819450505083850194508281606088811515612a8a57fe5b04815181101515612a9757fe5b9060200190602002018181525050606086019550612a5d565b606087811515612abc57fe5b0496505b6001871115612cd1576000600288811515612ad757fe5b06141515612b1d578060018803815181101515612af057fe5b906020019060200201518188815181101515612b0857fe5b90602001906020020181815250506001870196505b600095505b60018703861015612cbd578060018701815181101515612b3e57fe5b906020019060200201518187815181101515612b5657fe5b906020019060200201511415612b85578086815181101515612b7457fe5b906020019060200201519250612c89565b8060018701815181101515612b9657fe5b906020019060200201518187815181101515612bae57fe5b906020019060200201511015612c25578086815181101515612bcc57fe5b906020019060200201518160018801815181101515612be757fe5b906020019060200201516040516020018083815260200182815260200192505050604051602081830303815290604052805190602001209250612c88565b8060018701815181101515612c3657fe5b906020019060200201518187815181101515612c4e57fe5b9060200190602002015160405160200180838152602001828152602001925050506040516020818303038152906040528051906020012092505b5b8281600288811515612c9757fe5b04815181101515612ca457fe5b9060200190602002018181525050600286019550612b22565b600286811515612cc957fe5b049650612ac0565b806000815181101515612ce057fe5b90602001906020020151915081859850985050505050505050915091565b6000818311612d0d5782612d0f565b815b905092915050565b6000806001028560030154148015612d2f5750600084145b8015612d3b5750600083145b8015612d4a5750600060010282145b15612d585760019050612d98565b8383836040516020018084815260200183815260200182815260200193505050506040516020818303038152906040528051906020012085600301541490505b949350505050565b6000806000806000806000612db361371f565b612dbb61371f565b8e600001548260000181815250508e600101548260200181815250508d8260400181815250508c8260600181815250508b600001548160000181815250508b600101548160200181815250508a81604001818152505089816060018181525050612e258f8d6134f1565b9250612e318282613512565b9450612e3d8584612cfe565b94508483039350612e4e858b6135a6565b809b508196505050612e60848e6135a6565b809e508195505050828511151515612e7457fe5b828411151515612e8057fe5b898d858701010183141515612e9157fe5b84848e8c985098509850985050505050509650965096509692505050565b6000821480612ec15750600060010281145b15612ecb57612f06565b6000612ed88686866128f6565b9050600060096000838152602001908152602001600020905082816000018190555083816001018190555050505b5050505050565b600060606040805190810160405280600381526020017f3231320000000000000000000000000000000000000000000000000000000000815250905060006040805190810160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a000000000000815250823060025460016004811115612f9357fe5b8c8c8c8c604051602001808a805190602001908083835b602083101515612fcf5780518252602082019150602081019050602083039250612faa565b6001836020036101000a03801982511681845116808217855250505050505090500189805190602001908083835b6020831015156130225780518252602082019150602081019050602083039250612ffd565b6001836020036101000a0380198251168184511680821785525050505050509050018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140187815260200186815260200185815260200184815260200183815260200182815260200199505050505050505050506040516020818303038152906040528051906020012090506130d681856135cb565b9250505095945050505050565b60008460020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905080600401548311151561313a57600080fd5b8281600401819055508181600301819055505050505050565b600060606040805190810160405280600381526020017f3237370000000000000000000000000000000000000000000000000000000000815250905060006040805190810160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a0000000000008152508230600254600260048111156131d957fe5b8d8d8d8d8d604051602001808b805190602001908083835b60208310151561321657805182526020820191506020810190506020830392506131f1565b6001836020036101000a0380198251168184511680821785525050505050509050018a805190602001908083835b6020831015156132695780518252602082019150602081019050602083039250613244565b6001836020036101000a0380198251168184511680821785525050505050509050018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140188815260200187815260200186815260200185815260200184815260200183815260200182805190602001908083835b60208310151561332157805182526020820191506020810190506020830392506132fc565b6001836020036101000a0380198251168184511680821785525050505050509050019a505050505050505050505060405160208183030381529060405280519060200120905061337181856135cb565b925050509695505050505050565b60008060008060008060008789511115156133a8578060008090509650965050505050506134ea565b878901519450602088018901519350604088018901519150848483604051602001808481526020018381526020018281526020019350505050604051602081830303815290604052805190602001209050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c1f62946836040518263ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018082815260200191505060206040518083038186803b15801561348857600080fd5b505afa15801561349c573d6000803e3d6000fd5b505050506040513d60208110156134b257600080fd5b8101908080519060200190929190505050925060008314806134d45750828511155b156134de57600093505b80849650965050505050505b9250929050565b60008160010154836001015483600001548560000154010303905092915050565b600080600080600061352c876040015188606001516136de565b9350613540866040015187606001516136de565b925083831015151561355157600080fd5b8660400151841015151561356157fe5b8560400151831015151561357157fe5b83830391506135848288600001516136de565b90506135948188602001516135a6565b50809150508094505050505092915050565b6000808284116135bb576000848191506135c0565b828403835b915091509250929050565b6000604182511415156135dd57600080fd5b60008060006020850151925060408501519150606085015160001a9050601b8160ff16101561360d57601b810190505b601b8160ff1614806136225750601c8160ff16145b151561362d57600080fd5b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561368a573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141515156136d257600080fd5b83935050505092915050565b600080828401905083811015613714577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613716565b805b91505092915050565b60806040519081016040528060008152602001600081526020016000815260200160008152509056fea165627a7a723058202d9dfe53ab7e9dd9a3c79f1b677cd63d5ffce18e676ecff6d4e9d8c57a0149800029a165627a7a72305820fd79cb992c82f3592273aaf1c22034d0b08e7aac8b38f38bf9d2f4de18d39dbc0029000000000000000000000000b06670589ad705c6c30e314610f63afe5d638e14000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000879a4

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

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000b06670589ad705c6c30e314610f63afe5d638e14
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [2] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [3] : 00000000000000000000000000000000000000000000000000000000000879a4


   Swarm Source:
bzzr://fd79cb992c82f3592273aaf1c22034d0b08e7aac8b38f38bf9d2f4de18d39dbc

 

View All
Block Age transaction Difficulty GasUsed Reward
View All
Block Age UncleNumber Difficulty GasUsed Reward