Latest 2 txns

TxHash Age From To Value [TxFee]
0x83a7a499498173228d721e53dcd78cfd2fd9abbf8b4830716fc40ec222b46fc110 days 8 hrs ago0x1511acc875895713ae9bbf06671aae1e3c3670b8  IN   0xe679d9ccadd3be4ed187267ca4ff0437a2f9223e0 Ether0.000044251
0xeca5a8e6d4b4ae91ee4d7f56ee71dec600ed95a0dc9cfd28765e4976aee49a2510 days 8 hrs ago0x1511acc875895713ae9bbf06671aae1e3c3670b8  IN    Contract Creation0 Ether0.004166298


[ Download CSV Export  ] 
 Internal Transactions as a result of Contract Execution
View All
ParentTxHash Block Age From To Value
Contract Source Code Verified (Exact Match)
Contract Name: dexBlue
Compiler Version: v0.4.25+commit.59dbf8f1
Optimization Enabled: Yes
Runs (Optimiser):  200



  Contract Source Code   Find Similiar Contracts

pragma solidity 0.4.25;
pragma experimental ABIEncoderV2;

contract dexBlue{
    
    // Events

    /** @notice The event, emitted when a trade is settled
      * @param  index Implying the index of the settled trade in the trade array passed to matchTrades() 
      */
    event TradeSettled(uint8 index);

    /** @notice The event, emitted when a trade settlement failed
      * @param  index Implying the index of the failed trade in the trade array passed to matchTrades() 
      */
    event TradeFailed(uint8 index);

    /** @notice The event, emitted after a successful deposit of ETH or token
      * @param  account  The address, which initiated the deposit
      * @param  token    The address of the deposited token (ETH is address(0))
      * @param  amount   The amount deposited in this transaction 
      */
    event Deposit(address account, address token, uint256 amount);

    /** @notice The event, emitted after a successful (multi-sig) withdrawal of deposited ETH or token
      * @param  account  The address, which initiated the withdrawal
      * @param  token    The address of the token which is withdrawn (ETH is address(0))
      * @param  amount   The amount withdrawn in this transaction 
      */
    event Withdrawal(address account, address token, uint256 amount);

    /** @notice The event, emitted after a user successfully blocked tokens or ETH for a single signature withdrawal
      * @param  account  The address controlling the tokens
      * @param  token    The address of the token which is blocked (ETH is address(0))
      * @param  amount   The amount blocked in this transaction 
      */
    event BlockedForSingleSigWithdrawal(address account, address token, uint256 amount);

    /** @notice The event, emitted after a successful single-sig withdrawal of deposited ETH or token
      * @param  account  The address, which initiated the withdrawal
      * @param  token    The address of the token which is withdrawn (ETH is address(0))
      * @param  amount   The amount withdrawn in this transaction 
      */
    event SingleSigWithdrawal(address account, address token, uint256 amount);

    /** @notice The event, emitted once the feeCollector address initiated a withdrawal of collected tokens or ETH via feeWithdrawal()
      * @param  token    The address of the token which is withdrawn (ETH is address(0))
      * @param  amount   The amount withdrawn in this transaction 
      */
    event FeeWithdrawal(address token, uint256 amount);

    /** @notice The event, emitted once an on-chain cancellation of an order was performed
      * @param  hash    The invalidated orders hash 
      */
    event OrderCanceled(bytes32 hash);
   
    /** @notice The event, emitted once a address delegation or dedelegation was performed
      * @param  delegator The delegating address,
      * @param  delegate  The delegated address,
      * @param  status    Whether the transaction delegated an address (true) or inactivated an active delegation (false) 
      */
    event DelegateStatus(address delegator, address delegate, bool status);


    // Mappings 

    mapping(address => mapping(address => uint256)) balances;                           // Users balances (token address > user address > balance amount) (ETH is address(0))
    mapping(address => mapping(address => uint256)) blocked_for_single_sig_withdrawal;  // Users balances they blocked to withdraw without arbiters multi-sig (token address > user address > balance amount) (ETH is address(0))
    mapping(address => uint256) last_blocked_timestamp;                                 // The last timestamp a user blocked tokens to withdraw without arbiters multi-sig
    mapping(bytes32 => bool) processed_withdrawals;                                     // Processed withdrawal hashes
    mapping(bytes32 => uint256) matched;                                                // Orders matched sell_amounts to prevent multiple-/over- matches of the same orders
    mapping(address => address) delegates;                                              // Delegated order signing addresses


    // EIP712 (signTypedData)

    // EIP712 Domain
    struct EIP712_Domain {
        string  name;
        string  version;
        uint256 chainId;
        address verifyingContract;
    }
    bytes32 constant EIP712_DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
    bytes32          EIP712_DOMAIN_SEPARATOR;
    // Order typehash
    bytes32 constant EIP712_ORDER_TYPEHASH = keccak256("Order(address buyTokenAddress,address sellTokenAddress,uint256 buyTokenAmount,uint256 sellTokenAmount,uint64 nonce)");
    // Withdrawal typehash
    bytes32 constant EIP712_WITHDRAWAL_TYPEHASH = keccak256("Withdrawal(address token,uint256 amount,uint64 nonce)");
        

    // Utility functions:

    /** @notice Get the balance of a user for a specific token
      * @param  token  The token address (ETH is token address(0))
      * @param  holder The address holding the token
      * @return The amount of the specified token held by the user 
      */
    function getBalance(address token, address holder) constant public returns(uint256){
        return balances[token][holder];
    }
    
    /** @notice Get the balance a user blocked for a single-signature withdrawal (ETH is token address(0))
      * @param  token  The token address (ETH is token address(0))
      * @param  holder The address holding the token
      * @return The amount of the specified token blocked by the user 
      */
    function getBlocked(address token, address holder) constant public returns(uint256){
        return blocked_for_single_sig_withdrawal[token][holder];
    }
    
    /** @notice Returns the timestamp of the last blocked balance
      * @param  user  Address of the user which blocked funds
      * @return The last unix timestamp the user blocked funds at, which starts the waiting period for single-sig withdrawals 
      */
    function getLastBlockedTimestamp(address user) constant public returns(uint256){
        return last_blocked_timestamp[user];
    }


    // Deposit functions:

    /** @notice Deposit Ether into the smart contract 
      */
    function depositEther() public payable{
        balances[address(0)][msg.sender] += msg.value;      // Add the received ETH to the users balance
        emit Deposit(msg.sender, address(0), msg.value);    // Emit a deposit event
    }
    
    /** @notice Fallback function to credit ETH sent to the contract without data 
      */
    function() public payable{
        depositEther();                                     // Call the deposit function to credit ETH sent in this transaction
    }
    
    /** @notice Deposit ERC20 tokens into the smart contract (remember to set allowance in the token contract first)
      * @param  token   The address of the token to deposit
      * @param  amount  The amount of tokens to deposit 
      */
    function depositToken(address token, uint256 amount) public {
        Token(token).transferFrom(msg.sender, address(this), amount);    // Deposit ERC20
        require(
            checkERC20TransferSuccess(),                                 // Check whether the ERC20 token transfer was successful
            "ERC20 token transfer failed."
        );
        balances[token][msg.sender] += amount;                           // Credit the deposited token to users balance
        emit Deposit(msg.sender, token, amount);                         // Emit a deposit event
    }
        
    // Multi-sig withdrawal functions:

    /** @notice User-submitted withdrawal with arbiters signature, which withdraws to the users address
      * @param  token   The token to withdraw (ETH is address(address(0)))
      * @param  amount  The amount of tokens to withdraw
      * @param  nonce   The nonce (to salt the hash)
      * @param  v       Multi-signature v
      * @param  r       Multi-signature r
      * @param  s       Multi-signature s 
      */
    function multiSigWithdrawal(address token, uint256 amount, uint64 nonce, uint8 v, bytes32 r, bytes32 s) public {
        bytes32 hash = keccak256(abi.encodePacked(                      // Calculate the withdrawal hash from the parameters
            "\x19Ethereum Signed Message:\n32", 
            keccak256(abi.encodePacked(
                msg.sender,
                token,
                amount,
                nonce,
                address(this)
            ))
        ));
        if(
            !processed_withdrawals[hash]                                // Check if the withdrawal was initiated before
            && arbiters[ecrecover(hash, v,r,s)]                         // Check if the multi-sig is valid
            && balances[token][msg.sender] >= amount                    // Check if the user holds the required balance
        ){
            processed_withdrawals[hash]  = true;                        // Mark this withdrawal as processed
            balances[token][msg.sender] -= amount;                      // Substract withdrawn token from users balance
            if(token == address(0)){                                    // Withdraw ETH
                require(
                    msg.sender.send(amount),
                    "Sending of ETH failed."
                );
            }else{                                                      // Withdraw an ERC20 token
                Token(token).transfer(msg.sender, amount);              // Transfer the ERC20 token
                require(
                    checkERC20TransferSuccess(),                        // Check whether the ERC20 token transfer was successful
                    "ERC20 token transfer failed."
                );
            }

            blocked_for_single_sig_withdrawal[token][msg.sender] = 0;   // Set possible previous manual blocking of these funds to 0
        
            emit Withdrawal(msg.sender,token,amount);                   // Emit a Withdrawal event
        }else{
            revert();                                                   // Revert the transaction if checks fail
        }
    }    

    /** @notice User-submitted withdrawal with arbiters signature, which sends tokens to specified address
      * @param  token              The token to withdraw (ETH is address(address(0)))
      * @param  amount             The amount of tokens to withdraw
      * @param  nonce              The nonce (to salt the hash)
      * @param  v                  Multi-signature v
      * @param  r                  Multi-signature r
      * @param  s                  Multi-signature s
      * @param  receiving_address  The address to send the withdrawn token/ETH to
      */
    function multiSigSend(address token, uint256 amount, uint64 nonce, uint8 v, bytes32 r, bytes32 s, address receiving_address) public {
        bytes32 hash = keccak256(abi.encodePacked(                      // Calculate the withdrawal hash from the parameters 
            "\x19Ethereum Signed Message:\n32", 
            keccak256(abi.encodePacked(
                msg.sender,
                token,
                amount,
                nonce,
                address(this)
            ))
        ));
        if(
            !processed_withdrawals[hash]                                // Check if the withdrawal was initiated before
            && arbiters[ecrecover(hash, v,r,s)]                         // Check if the multi-sig is valid
            && balances[token][msg.sender] >= amount                    // Check if the user holds the required balance
        ){
            processed_withdrawals[hash]  = true;                        // Mark this withdrawal as processed
            balances[token][msg.sender] -= amount;                      // Substract the withdrawn balance from the users balance
            if(token == address(0)){                                    // Process an ETH withdrawal
                require(
                    receiving_address.send(amount),
                    "Sending of ETH failed."
                );
            }else{                                                      // Withdraw an ERC20 token
                Token(token).transfer(receiving_address, amount);       // Transfer the ERC20 token
                require(
                    checkERC20TransferSuccess(),                        // Check whether the ERC20 token transfer was successful
                    "ERC20 token transfer failed."
                );
            }

            blocked_for_single_sig_withdrawal[token][msg.sender] = 0;   // Set possible previous manual blocking of these funds to 0
            
            emit Withdrawal(msg.sender,token,amount);                   // Emit a Withdrawal event
        }else{
            revert();                                                   // Revert the transaction if checks fail
        }
    }

    /** @notice User-submitted transfer with arbiters signature, which sends tokens to another addresses account in the smart contract
      * @param  token              The token to transfer (ETH is address(address(0)))
      * @param  amount             The amount of tokens to transfer
      * @param  nonce              The nonce (to salt the hash)
      * @param  v                  Multi-signature v
      * @param  r                  Multi-signature r
      * @param  s                  Multi-signature s
      * @param  receiving_address  The address to transfer the token/ETH to
      */
    function multiSigTransfer(address token, uint256 amount, uint64 nonce, uint8 v, bytes32 r, bytes32 s, address receiving_address) public {
        bytes32 hash = keccak256(abi.encodePacked(                      // Calculate the withdrawal/transfer hash from the parameters 
            "\x19Ethereum Signed Message:\n32", 
            keccak256(abi.encodePacked(
                msg.sender,
                token,
                amount,
                nonce,
                address(this)
            ))
        ));
        if(
            !processed_withdrawals[hash]                                // Check if the withdrawal was initiated before
            && arbiters[ecrecover(hash, v,r,s)]                         // Check if the multi-sig is valid
            && balances[token][msg.sender] >= amount                    // Check if the user holds the required balance
        ){
            processed_withdrawals[hash]         = true;                 // Mark this withdrawal as processed
            balances[token][msg.sender]        -= amount;               // Substract the balance from the withdrawing account
            balances[token][receiving_address] += amount;               // Add the balance to the receiving account
            
            blocked_for_single_sig_withdrawal[token][msg.sender] = 0;   // Set possible previous manual blocking of these funds to 0
            
            emit Withdrawal(msg.sender,token,amount);                   // Emit a Withdrawal event
            emit Deposit(receiving_address,token,amount);               // Emit a Deposit event
        }else{
            revert();                                                   // Revert the transaction if checks fail
        }
    }

    /** @notice Arbiter submitted withdrawal with users multi-sig to users address
      * @param  token   The token to withdraw (ETH is address(address(0)))
      * @param  amount  The amount of tokens to withdraw
      * @param  fee     The fee, covering the gas cost of the arbiter
      * @param  nonce   The nonce (to salt the hash)
      * @param  v       Multi-signature v (either 27 or 28. To identify the different signing schemes an offset of 10 is applied for EIP712)
      * @param  r       Multi-signature r
      * @param  s       Multi-signature s
      */
    function userSigWithdrawal(address token, uint256 amount, uint256 fee, uint64 nonce, uint8 v, bytes32 r, bytes32 s) public {            
        bytes32 hash;
        if(v < 30){                                                     // Standard signing scheme (personal.sign())
            hash = keccak256(abi.encodePacked(                          // Restore multi-sig hash
                "\x19Ethereum Signed Message:\n32",
                keccak256(abi.encodePacked(
                    token,
                    amount,
                    nonce,
                    address(this)
                ))
            ));
        }else{                                                          // EIP712 signing scheme
            v -= 10;                                                    // Remove offset
            hash = keccak256(abi.encodePacked(                          // Restore multi-sig hash
                "\x19\x01",
                EIP712_DOMAIN_SEPARATOR,
                keccak256(abi.encode(
                    EIP712_WITHDRAWAL_TYPEHASH,
                    token,
                    amount,
                    nonce
                ))
            ));
        }
        address account = ecrecover(hash, v, r, s);                     // Restore signing address
        if(
            !processed_withdrawals[hash]                                // Check if the withdrawal was initiated before
            && arbiters[msg.sender]                                     // Check if transaction comes from arbiter
            && fee <= amount / 50                                       // Check if fee is not too big
            && balances[token][account] >= amount                       // Check if the user holds the required tokens
        ){
            processed_withdrawals[hash]    = true;
            balances[token][account]      -= amount;
            balances[token][feeCollector] += fee;                       // Fee to cover gas costs for the withdrawal
            if(token == address(0)){                                    // Send ETH
                require(
                    account.send(amount - fee),
                    "Sending of ETH failed."
                );
            }else{
                Token(token).transfer(account, amount - fee);           // Withdraw ERC20
                require(
                    checkERC20TransferSuccess(),                        // Check if the transfer was successful
                    "ERC20 token transfer failed."
                );
            }
        
            blocked_for_single_sig_withdrawal[token][account] = 0;      // Set possible previous manual blocking of these funds to 0
            
            emit Withdrawal(account,token,amount);                      // Emit a Withdrawal event
        }else{
            revert();                                                   // Revert the transaction is checks fail
        }
    }
    
    // Single-sig withdrawal functions:

    /** @notice Allows user to block funds for single-sig withdrawal after 24h waiting period 
      *         (This period is necessary to ensure all trades backed by these funds will be settled.)
      * @param  token   The address of the token to block (ETH is address(address(0)))
      * @param  amount  The amount of the token to block
      */
    function blockFundsForSingleSigWithdrawal(address token, uint256 amount) public {
        if (balances[token][msg.sender] - blocked_for_single_sig_withdrawal[token][msg.sender] >= amount){  // Check if the user holds the required funds
            blocked_for_single_sig_withdrawal[token][msg.sender] += amount;         // Block funds for manual withdrawal
            last_blocked_timestamp[msg.sender] = block.timestamp;                   // Start 24h waiting period
            emit BlockedForSingleSigWithdrawal(msg.sender,token,amount);            // Emit BlockedForSingleSigWithdrawal event
        }else{
            revert();                                                               // Revert the transaction if the user does not hold the required balance
        }
    }
    
    /** @notice Allows user to withdraw funds previously blocked after 24h
      */
    function initiateSingleSigWithdrawal(address token, uint256 amount) public {
        if (
            balances[token][msg.sender] >= amount                                   // Check if the user holds the funds
            && blocked_for_single_sig_withdrawal[token][msg.sender] >= amount       // Check if these funds are blocked
            && last_blocked_timestamp[msg.sender] + 86400 <= block.timestamp        // Check if the one day waiting period has passed
        ){
            balances[token][msg.sender] -= amount;                                  // Substract the tokens from users balance
            blocked_for_single_sig_withdrawal[token][msg.sender] -= amount;         // Substract the tokens from users blocked balance
            if(token == address(0)){                                                // Withdraw ETH
                require(
                    msg.sender.send(amount),
                    "Sending of ETH failed."
                );
            }else{                                                                  // Withdraw ERC20 tokens
                Token(token).transfer(msg.sender, amount);                          // Transfer the ERC20 tokens
                require(
                    checkERC20TransferSuccess(),                                    // Check if the transfer was successful
                    "ERC20 token transfer failed."
                );
            }
            emit SingleSigWithdrawal(msg.sender,token,amount);                      // Emit a SingleSigWithdrawal event
        }else{
            revert();                                                               // Revert the transaction if the required checks fail
        }
    } 


    //Trade settlement structs and function
    
    struct OrderInput{
        uint8       buy_token;      // The token, the order signee wants to buy
        uint8       sell_token;     // The token, the order signee wants to sell
        uint256     buy_amount;     // The total amount the signee wants to buy
        uint256     sell_amount;    // The total amount the signee wants to give for the amount he wants to buy (the orders "rate" is implied by the ratio between the two amounts)
        uint64      nonce;          // Random number to give each order an individual hash and signature
        int8        v;              // Signature v (either 27 or 28)
                                    // To identify the different signing schemes an offset of 10 is applied for EIP712.
                                    // To identify whether the order was signed by a delegated signing address, the number is either positive or negative.
        bytes32     r;              // Signature r
        bytes32     s;              // Signature s
    }
    
    struct TradeInput{
        uint8       maker_order;    // The index of the maker order
        uint8       taker_order;    // The index of the taker order
        uint256     maker_amount;   // The amount the maker gives in return for the taker's tokens
        uint256     taker_amount;   // The amount the taker gives in return for the maker's tokens
        uint256     maker_fee;      // The trading fee of the maker + a share in the settlement (gas) cost
        uint256     taker_fee;      // The trading fee of the taker + a share in the settlement (gas) cost
        uint256     maker_rebate;   // A optional rebate for the maker (portion of takers fee) as an incentive
    }

    /** @notice Allows an arbiter to settle trades between two user-signed orders
      * @param  addresses  Array of all addresses involved in the transactions
      * @param  orders     Array of all orders involved in the transactions
      * @param  trades     Array of the trades to be settled
      */   
    function matchTrades(address[] addresses, OrderInput[] orders, TradeInput[] trades) public {
        require(arbiters[msg.sender] && marketActive);      // Check if msg.sender is an arbiter and the market is active
        
        //Restore signing addresses
        uint len = orders.length;                           // Length of orders array to loop through
        bytes32[]  memory hashes = new bytes32[](len);      // Array of the restored order hashes
        address[]  memory signee = new address[](len);      // Array of the restored order signees
        OrderInput memory order;                            // Memory slot to cache orders while looping (otherwise the Stack would be too deep)
        address    addressCache1;                           // Memory slot 1 to cache addresses while looping (otherwise the Stack would be too deep)
        address    addressCache2;                           // Memory slot 2 to cache addresses while looping (otherwise the Stack would be too deep)
        bool       delegated;
        
        for(uint8 i = 0; i < len; i++){                     // Loop through the orders array to restore all signees
            order         = orders[i];                      // Cache order
            addressCache1 = addresses[order.buy_token];     // Cache orders buy token
            addressCache2 = addresses[order.sell_token];    // Cache orders sell token
            
            if(order.v < 0){                                // Check if the order is signed by a delegate
                delegated = true;                           
                order.v  *= -1;                             // Restore the negated v
            }else{
                delegated = false;
            }
            
            if(order.v < 30){                               // Order is hashed after signature scheme personal.sign()
                hashes[i] = keccak256(abi.encodePacked(     // Restore the hash of this order
                    "\x19Ethereum Signed Message:\n32",
                    keccak256(abi.encodePacked(
                        addressCache1,
                        addressCache2,
                        order.buy_amount,
                        order.sell_amount,
                        order.nonce,        
                        address(this)                       // This contract's address
                    ))
                ));
            }else{                                          // Order is hashed after EIP712
                order.v -= 10;                              // Remove signature format identifying offset
                hashes[i] = keccak256(abi.encodePacked(
                    "\x19\x01",
                    EIP712_DOMAIN_SEPARATOR,
                    keccak256(abi.encode(
                        EIP712_ORDER_TYPEHASH,
                        addressCache1,
                        addressCache2,
                        order.buy_amount,
                        order.sell_amount,
                        order.nonce
                    ))
                ));
            }
            signee[i] = ecrecover(                          // Restore the signee of this order
                hashes[i],                                  // Order hash
                uint8(order.v),                             // Signature v
                order.r,                                    // Signature r
                order.s                                     // Signature s
            );
            // When the signature was delegated restore delegating address
            if(delegated){
                signee[i] = delegates[signee[i]];
            }
        }
        
        // Settle Trades after check
        len = trades.length;                                            // Length of the trades array to loop through
        TradeInput memory trade;                                        // Memory slot to cache trades while looping
        uint maker_index;                                               // Memory slot to cache the trade's maker order index
        uint taker_index;                                               // Memory slot to cache the trade's taker order index
        
        for(i = 0; i < len; i++){                                       // Loop through trades to settle after checks
            trade = trades[i];                                          // Cache trade
            maker_index = trade.maker_order;                            // Cache maker order index
            taker_index = trade.taker_order;                            // Cache taker order index
            addressCache1 = addresses[orders[maker_index].buy_token];   // Cache first of the two swapped token addresses
            addressCache2 = addresses[orders[taker_index].buy_token];   // Cache second of the two swapped token addresses
            
            if( // Check if the arbiter has matched following the conditions of the two order signees
                // Do maker and taker want to trade the same tokens with each other
                    orders[maker_index].buy_token == orders[taker_index].sell_token
                && orders[taker_index].buy_token == orders[maker_index].sell_token
                
                // Do maker and taker hold the required balances
                && balances[addressCache2][signee[maker_index]] >= trade.maker_amount - trade.maker_rebate
                && balances[addressCache1][signee[taker_index]] >= trade.taker_amount
                
                // Are they both matched at a rate better or equal to the one they signed
                && trade.maker_amount - trade.maker_rebate <= orders[maker_index].sell_amount * trade.taker_amount / orders[maker_index].buy_amount + 1  // Check maker doesn't overpay (+ 1 to deal with rouding errors for very smal amounts)
                && trade.taker_amount <= orders[taker_index].sell_amount * trade.maker_amount / orders[taker_index].buy_amount + 1                       // Check taker doesn't overpay (+ 1 to deal with rouding errors for very smal amounts)
                
                // Check if the matched amount + previously matched trades doesn't exceed the amount specified by the order signee
                && trade.taker_amount + matched[hashes[taker_index]] <= orders[taker_index].sell_amount
                && trade.maker_amount - trade.maker_rebate + matched[hashes[maker_index]] <= orders[maker_index].sell_amount
                    
                // Check if the charged fee is not too high
                && trade.maker_fee <= trade.taker_amount / 100
                && trade.taker_fee <= trade.maker_amount / 50
                
                // Check if maker_rebate is smaller than or equal to the taker's fee which compensates it
                && trade.maker_rebate <= trade.taker_fee
            ){
                // Settle the trade:
                
                // Substract sold amounts
                balances[addressCache2][signee[maker_index]] -= trade.maker_amount - trade.maker_rebate;    // Substract maker's sold amount minus the makers rebate
                balances[addressCache1][signee[taker_index]] -= trade.taker_amount;                         // Substract taker's sold amount
                
                // Add bought amounts
                balances[addressCache1][signee[maker_index]] += trade.taker_amount - trade.maker_fee;       // Give the maker his bought amount minus the fee
                balances[addressCache2][signee[taker_index]] += trade.maker_amount - trade.taker_fee;       // Give the taker his bought amount minus the fee
                
                // Save bought amounts to prevent double matching
                matched[hashes[maker_index]] += trade.maker_amount;                                         // Prevent maker order from being reused
                matched[hashes[taker_index]] += trade.taker_amount;                                         // Prevent taker order from being reused
                
                // Give fee to feeCollector
                balances[addressCache2][feeCollector] += trade.taker_fee - trade.maker_rebate;              // Give the feeColletor the taker fee minus the maker rebate 
                balances[addressCache1][feeCollector] += trade.maker_fee;                                   // Give the feeColletor the maker fee
                
                // Set possible previous manual blocking of these funds to 0
                blocked_for_single_sig_withdrawal[addressCache2][signee[maker_index]] = 0;                  // If the maker tried to block funds which he/she used in this order we have to unblock them
                blocked_for_single_sig_withdrawal[addressCache1][signee[taker_index]] = 0;                  // If the taker tried to block funds which he/she used in this order we have to unblock them
                
                emit TradeSettled(i);                                                                       // Emit tradeSettled Event to confirm the trade was settled
            }else{
                emit TradeFailed(i);                                                                        // Emit tradeFailed Event because the trade checks failed
            }
        }
    }


    // Order cancellation functions

    /** @notice Give the user the option to perform multiple on-chain cancellations of orders at once with arbiters multi-sig
      * @param  orderHashes Array of orderHashes of the orders to be canceled
      * @param  v           Multi-sig v
      * @param  r           Multi-sig r
      * @param  s           Multi-sig s
      */
    function multiSigOrderBatchCancel(bytes32[] orderHashes, uint8 v, bytes32 r, bytes32 s) public {
        if(
            arbiters[                                               // Check if the signee is an arbiter
                ecrecover(                                          // Restore the signing address
                    keccak256(abi.encodePacked(                     // Restore the signed hash (hash of all orderHashes)
                        "\x19Ethereum Signed Message:\n32", 
                        keccak256(abi.encodePacked(orderHashes))
                    )),
                    v, r, s
                )
            ]
        ){
            uint len = orderHashes.length;
            for(uint8 i = 0; i < len; i++){
                matched[orderHashes[i]] = 2**256 - 1;               // Set the matched amount of all orders to the maximum
                emit OrderCanceled(orderHashes[i]);                 // emit OrderCanceled event
            }
        }else{
            revert();
        }
    }
        
    /** @notice Give arbiters the option to perform on-chain multiple cancellations of orders at once  
      * @param orderHashes Array of hashes of the orders to be canceled
      */
    function orderBatchCancel(bytes32[] orderHashes) public {
        if(
            arbiters[msg.sender]                        // Check if the sender is an arbiter
        ){
            uint len = orderHashes.length;
            for(uint8 i = 0; i < len; i++){
                matched[orderHashes[i]] = 2**256 - 1;   // Set the matched amount of all orders to the maximum
                emit OrderCanceled(orderHashes[i]);     // emit OrderCanceled event
            }
        }else{
            revert();
        }
    }
        
        
    // Signature delegation

    /** @notice delegate an address to allow it to sign orders on your behalf
      * @param delegate  The address to delegate
      */
    function delegateAddress(address delegate) public {
        // set as delegate
        require(delegates[delegate] == address(0), "Address is already a delegate");
        delegates[delegate] = msg.sender;
        
        emit DelegateStatus(msg.sender, delegate, true);
    }
    
    /** @notice revoke the delegation of an address
      * @param  delegate  The delegated address
      * @param  v         Multi-sig v
      * @param  r         Multi-sig r
      * @param  s         Multi-sig s
      */
    function revokeDelegation(address delegate, uint8 v, bytes32 r, bytes32 s) public {
        bytes32 hash = keccak256(abi.encodePacked(              // Restore the signed hash
            "\x19Ethereum Signed Message:\n32", 
            keccak256(abi.encodePacked(
                delegate,
                msg.sender,
                address(this)
            ))
        ));

        require(arbiters[ecrecover(hash, v, r, s)], "MultiSig is not from known arbiter");  // Check if signee is an arbiter
        
        delegates[delegate] = address(1);       // set to 1 not 0 to prevent double delegation, which would make old signed order valid for the new delegator
        
        emit DelegateStatus(msg.sender, delegate, false);
    }
    

    // Management functions:

    address owner;                      // Contract owner address (has the right to nominate arbiters and the feeCollectors addresses)   
    address feeCollector;               // feeCollector address
    bool marketActive = true;           // Make it possible to pause the market
    bool feeCollectorLocked = false;    // Make it possible to lock the feeCollector address (to allow to change the feeCollector to a fee distribution contract)
    mapping(address => bool) arbiters;  // Mapping of arbiters
    
    /** @notice Constructor function
      */
    constructor() public {
        owner = msg.sender;             // Nominate sender to be the contract owner
        feeCollector = msg.sender;      // Nominate sender to be the standart feeCollector
        arbiters[msg.sender] = true;    // Nominate sender to be an arbiter
        
        // create EIP712 domain seperator
        EIP712_Domain memory eip712Domain = EIP712_Domain({
            name              : "dex.blue",
            version           : "1",
            chainId           : 1,
            verifyingContract : this
        });
        EIP712_DOMAIN_SEPARATOR = keccak256(abi.encode(
            EIP712_DOMAIN_TYPEHASH,
            keccak256(bytes(eip712Domain.name)),
            keccak256(bytes(eip712Domain.version)),
            eip712Domain.chainId,
            eip712Domain.verifyingContract
        ));
    }
    
    /** @notice Allows the owner to nominate or denominate trade arbitting addresses
      * @param  arbiter The arbiter whose status to change
      * @param  status  Whether the address should be an arbiter (true) or not (false)
      */
    function nominateArbiter(address arbiter, bool status) public {
        require(msg.sender == owner);                           // Check if sender is owner
        arbiters[arbiter] = status;                             // Update address status
    }

    /** @notice Allows the owner to pause / unpause the market
      * @param  state  Whether the the market should be active (true) or paused (false)
      */
    function setMarketActiveState(bool state) public {
        require(msg.sender == owner);                           // Check if sender is owner
        marketActive = state;                                   // pause / unpause market
    }
    
    /** @notice Allows the owner to nominate the feeCollector address
      * @param  collector The address to nominate as feeCollector
      */
    function nominateFeeCollector(address collector) public {
        require(msg.sender == owner && !feeCollectorLocked);    // Check if sender is owner and feeCollector address is not locked
        feeCollector = collector;                               // Update feeCollector address
    }
    
    /** @notice Allows the owner to lock the feeCollector address
  */
    function lockFeeCollector() public {
        require(msg.sender == owner);                           // Check if sender is owner
        feeCollectorLocked = true;                              // Lock feeCollector address
    }
    
    /** @notice Get the feeCollectors address
      * @return The feeCollectors address
      */
    function getFeeCollector() public constant returns (address){
        return feeCollector;
    }

    /** @notice Allows the feeCollector to directly withdraw his funds (would allow a fee distribution contract to withdraw collected fees)
      * @param  token   The token to withdraw
      * @param  amount  The amount of tokens to withdraw
  */
    function feeWithdrawal(address token, uint256 amount) public {
        if (
            msg.sender == feeCollector                              // Check if the sender is the feeCollector
            && balances[token][feeCollector] >= amount              // Check if feeCollector has the sufficient balance
        ){
            balances[token][feeCollector] -= amount;                // Substract the feeCollectors balance
            if(token == address(0)){                                // Is the withdrawal token ETH
                require(
                    feeCollector.send(amount),                      // Withdraw ETH
                    "Sending of ETH failed."
                );
            }else{
                Token(token).transfer(feeCollector, amount);        // Withdraw ERC20
                require(                                            // Revert if the withdrawal failed
                    checkERC20TransferSuccess(),
                    "ERC20 token transfer failed."
                );
            }
            emit FeeWithdrawal(token,amount);                       // Emit FeeWithdrawal event
        }else{
            revert();                                               // Revert the transaction if the checks fail
        }
    }
    
    // We have to check returndatasize after ERC20 tokens transfers, as some tokens are implemented badly (dont return a boolean)
    function checkERC20TransferSuccess() pure private returns(bool){
        uint256 success = 0;

        assembly {
            switch returndatasize               // Check the number of bytes the token contract returned
                case 0 {                        // Nothing returned, but contract did not throw > assume our transfer succeeded
                    success := 1
                }
                case 32 {                       // 32 bytes returned, result is the returned bool
                    returndatacopy(0, 0, 32)
                    success := mload(0)
                }
        }

        return success != 0;
    }
}




// Standart ERC20 token interface to interact with ERC20 token contracts
// To support badly implemented tokens (which dont return a boolean on the transfer functions)
// we have to expect a badly implemented token and then check with checkERC20TransferSuccess() whether the transfer succeeded

contract Token {
    /** @return total amount of tokens
      */
    function totalSupply() constant public returns (uint256 supply) {}

    /** @param _owner The address from which the balance will be retrieved
      * @return The balance
      */
    function balanceOf(address _owner) constant public returns (uint256 balance) {}

    /** @notice send `_value` token to `_to` from `msg.sender`
      * @param  _to     The address of the recipient
      * @param  _value  The amount of tokens to be transferred
      * @return Whether the transfer was successful or not
      */
    function transfer(address _to, uint256 _value) public {}

    /** @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 tokens to be transferred
      * @return Whether the transfer was successful or not
      */
    function transferFrom(address _from, address _to, uint256 _value)  public {}

    /** @notice `msg.sender` approves `_addr` 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) public 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 spend
      */
    function allowance(address _owner, address _spender) constant public returns (uint256 remaining) {}

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

    uint public decimals;
    string public name;
}

    Contract ABI  
[{"constant":false,"inputs":[{"name":"state","type":"bool"}],"name":"setMarketActiveState","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getFeeCollector","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"collector","type":"address"}],"name":"nominateFeeCollector","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"amount","type":"uint256"}],"name":"feeWithdrawal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"amount","type":"uint256"}],"name":"depositToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"amount","type":"uint256"},{"name":"nonce","type":"uint64"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"receiving_address","type":"address"}],"name":"multiSigTransfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"delegate","type":"address"}],"name":"delegateAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"addresses","type":"address[]"},{"components":[{"name":"buy_token","type":"uint8"},{"name":"sell_token","type":"uint8"},{"name":"buy_amount","type":"uint256"},{"name":"sell_amount","type":"uint256"},{"name":"nonce","type":"uint64"},{"name":"v","type":"int8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"orders","type":"tuple[]"},{"components":[{"name":"maker_order","type":"uint8"},{"name":"taker_order","type":"uint8"},{"name":"maker_amount","type":"uint256"},{"name":"taker_amount","type":"uint256"},{"name":"maker_fee","type":"uint256"},{"name":"taker_fee","type":"uint256"},{"name":"maker_rebate","type":"uint256"}],"name":"trades","type":"tuple[]"}],"name":"matchTrades","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"amount","type":"uint256"},{"name":"nonce","type":"uint64"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"receiving_address","type":"address"}],"name":"multiSigSend","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"orderHashes","type":"bytes32[]"}],"name":"orderBatchCancel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"arbiter","type":"address"},{"name":"status","type":"bool"}],"name":"nominateArbiter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"lockFeeCollector","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"user","type":"address"}],"name":"getLastBlockedTimestamp","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"orderHashes","type":"bytes32[]"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"multiSigOrderBatchCancel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"amount","type":"uint256"}],"name":"blockFundsForSingleSigWithdrawal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"depositEther","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"amount","type":"uint256"},{"name":"nonce","type":"uint64"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"multiSigWithdrawal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"amount","type":"uint256"}],"name":"initiateSingleSigWithdrawal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"token","type":"address"},{"name":"amount","type":"uint256"},{"name":"fee","type":"uint256"},{"name":"nonce","type":"uint64"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"userSigWithdrawal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"holder","type":"address"}],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"delegate","type":"address"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"revokeDelegation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"token","type":"address"},{"name":"holder","type":"address"}],"name":"getBlocked","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"index","type":"uint8"}],"name":"TradeSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"index","type":"uint8"}],"name":"TradeFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"},{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"},{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"},{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"BlockedForSingleSigWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"},{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"SingleSigWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"FeeWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"hash","type":"bytes32"}],"name":"OrderCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"delegator","type":"address"},{"indexed":false,"name":"delegate","type":"address"},{"indexed":false,"name":"status","type":"bool"}],"name":"DelegateStatus","type":"event"}]

  Contract Creation Code Switch To Opcodes View
60806040526008805460a860020a60ff021960a060020a60ff021990911674010000000000000000000000000000000000000000171690553480156200004457600080fd5b506200004f620002d0565b5060078054600160a060020a0319908116339081179092556008805490911682178155600091825260096020908152604092839020805460ff19166001908117909155835160c081018552608081019384527f6465782e626c756500000000000000000000000000000000000000000000000060a0820152928352835180850185528181527f310000000000000000000000000000000000000000000000000000000000000081840152838301528284015230606083015282517f454950373132446f6d61696e28737472696e67206e616d652c737472696e672081527f76657273696f6e2c75696e7432353620636861696e49642c6164647265737320818301527f766572696679696e67436f6e7472616374290000000000000000000000000000818501529251928390036052018320825180519394919390928291908401908083835b60208310620001b65780518252601f19909201916020918201910162000195565b51815160209384036101000a6000190180199092169116179052604051919093018190038120878401518051919650945090928392508401908083835b60208310620002145780518252601f199092019160209182019101620001f3565b51815160209384036101000a6000190180199092169116179052604080519290940182900382209389015160608a01516200025999989750949550939250016200031e565b6040516020818303038152906040526040518082805190602001908083835b60208310620002995780518252601f19909201916020918201910162000278565b5181516020939093036101000a60001901801990911692169190911790526040519201829003909120600655506200038392505050565b6080604051908101604052806060815260200160608152602001600081526020016000600160a060020a031681525090565b6200030d8162000374565b82525050565b6200030d8162000380565b60a081016200032e828862000313565b6200033d602083018762000313565b6200034c604083018662000313565b6200035b606083018562000313565b6200036a608083018462000302565b9695505050505050565b600160a060020a031690565b90565b613a9c80620003936000396000f3006080604052600436106101275763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630562b1a4811461013157806312fde4b7146101515780632c580a1f1461017c5780632e2263291461019c578063338b5dea146101bc57806349c35605146101dc5780634a0c3c3b146101fc578063555a3bbf1461021c5780635d7bdccd1461023c57806366da6e5b1461025c5780636849dbe51461027c57806372521dcd1461029c578063862f9f5a146102b1578063888d0e1d146102de57806394785a0c146102fe57806398ea5fca146101275780639e8923721461031e578063a2c38a231461033e578063bc2f79eb1461035e578063d4fac45d1461037e578063ebf26a421461039e578063f6188339146103be575b61012f6103de565b005b34801561013d57600080fd5b5061012f61014c3660046136d4565b610451565b34801561015d57600080fd5b506101666104a8565b604051610173919061380b565b60405180910390f35b34801561018857600080fd5b5061012f610197366004613301565b6104b7565b3480156101a857600080fd5b5061012f6101b7366004613391565b610527565b3480156101c857600080fd5b5061012f6101d7366004613391565b6106d3565b3480156101e857600080fd5b5061012f6101f73660046134e4565b6107dd565b34801561020857600080fd5b5061012f610217366004613301565b610b83565b34801561022857600080fd5b5061012f6102373660046135d2565b610c35565b34801561024857600080fd5b5061012f6102573660046134e4565b6119f4565b34801561026857600080fd5b5061012f610277366004613666565b611d63565b34801561028857600080fd5b5061012f610297366004613361565b611e20565b3480156102a857600080fd5b5061012f611e62565b3480156102bd57600080fd5b506102d16102cc366004613301565b611eb2565b6040516101739190613884565b3480156102ea57600080fd5b5061012f6102f936600461369b565b611ecd565b34801561030a57600080fd5b5061012f610319366004613391565b612110565b34801561032a57600080fd5b5061012f61033936600461345d565b6121b7565b34801561034a57600080fd5b5061012f610359366004613391565b61252e565b34801561036a57600080fd5b5061012f6103793660046133c1565b6126f3565b34801561038a57600080fd5b506102d1610399366004613327565b612c25565b3480156103aa57600080fd5b5061012f6103b9366004613571565b612c50565b3480156103ca57600080fd5b506102d16103d9366004613327565b612e8a565b3360008181527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604080822080543490810190915590517f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62936104479390929091613841565b60405180910390a1565b600754600160a060020a0316331461046857600080fd5b60088054911515740100000000000000000000000000000000000000000274ff000000000000000000000000000000000000000019909216919091179055565b600854600160a060020a031690565b600754600160a060020a0316331480156104ed57506008547501000000000000000000000000000000000000000000900460ff16155b15156104f857600080fd5b6008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600854600160a060020a0316331480156105675750600160a060020a03808316600090815260208181526040808320600854909416835292905220548111155b156106ca57600160a060020a038083166000818152602081815260408083206008549095168352939052919091208054839003905515156105fa57600854604051600160a060020a039091169082156108fc029083906000818181858888f1935050505015156105f55760405160e560020a62461bcd0281526004016105ec9061395f565b60405180910390fd5b61068c565b60085460405160e060020a63a9059cbb028152600160a060020a038481169263a9059cbb9261063192909116908590600401613869565b600060405180830381600087803b15801561064b57600080fd5b505af115801561065f573d6000803e3d6000fd5b5050505061066b612eb5565b151561068c5760405160e560020a62461bcd0281526004016105ec9061398f565b7fee33a3a9cb48e4ff209f8b1c67c4632f1dbbf55aeff8e6f17d957ade7a6fb17c82826040516106bd929190613869565b60405180910390a16106cf565b600080fd5b5050565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152600160a060020a038316906323b872dd9061071c90339030908690600401613841565b600060405180830381600087803b15801561073657600080fd5b505af115801561074a573d6000803e3d6000fd5b50505050610756612eb5565b15156107775760405160e560020a62461bcd0281526004016105ec9061398f565b600160a060020a0382166000908152602081815260408083203380855292529182902080548401905590517f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62916107d19185908590613841565b60405180910390a15050565b604080516c01000000000000000000000000338102602080840191909152600160a060020a038b1682026034840152604883018a905260c060020a67ffffffffffffffff8a1602606884015230919091026070830152825160648184030181526084909201928390528151600093918291908401908083835b602083106108755780518252601f199092019160209182019101610856565b51815160209384036101000a600019018019909216911617905260408051929094018290038220600080516020613a2383398151915283830152603c8084019190915284518084039091018152605c9092019384905281519195509293508392850191508083835b602083106108fc5780518252601f1990920191602091820191016108dd565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008181526003909252929020549194505060ff161591505080156109b75750600960006001838888886040516000815260200160405260405161096b949392919061392a565b60206040516020810390808403906000865af115801561098f573d6000803e3d6000fd5b505060408051601f190151600160a060020a03168352602083019390935250016000205460ff165b80156109e45750600160a060020a0388166000908152602081815260408083203384529091529020548711155b156106ca57600160036000836000191660001916815260200190815260200160002060006101000a81548160ff021916908315150217905550866000808a600160a060020a0316600160a060020a03168152602001908152602001600020600033600160a060020a0316600160a060020a0316815260200190815260200160002060008282540392505081905550866000808a600160a060020a0316600160a060020a03168152602001908152602001600020600084600160a060020a0316600160a060020a03168152602001908152602001600020600082825401925050819055506000600160008a600160a060020a0316600160a060020a03168152602001908152602001600020600033600160a060020a0316600160a060020a0316815260200190815260200160002081905550600080516020613a43833981519152338989604051610b3693929190613841565b60405180910390a17f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62828989604051610b7193929190613841565b60405180910390a15050505050505050565b600160a060020a038181166000908152600560205260409020541615610bbe5760405160e560020a62461bcd0281526004016105ec9061396f565b600160a060020a03811660009081526005602052604090819020805473ffffffffffffffffffffffffffffffffffffffff19163390811790915590517f4cb8e0239d1e27be8d3440c681240f004fa60c61a26c18b327554b46592dbbc891610c2a918490600190613819565b60405180910390a150565b6000606080610c42612ee9565b600080600080610c50612f2d565b33600090815260096020526040812054819060ff168015610c8b575060085474010000000000000000000000000000000000000000900460ff165b1515610c9657600080fd5b8c519a508a604051908082528060200260200182016040528015610cc4578160200160208202803883390190505b5099508a604051908082528060200260200182016040528015610cf1578160200160208202803883390190505b509850600093505b8a8460ff161015611245578c8460ff16815181101515610d1557fe5b9060200190602002015197508d886000015160ff16815181101515610d3657fe5b9060200190602002015196508d886020015160ff16815181101515610d5757fe5b90602001906020020151955060008860a0015160000b1215610d8d5760a0880180516000908103810b900b905260019450610d92565b600094505b601e8860a0015160000b1215610f275760408881015160608a015160808b01518351600160a060020a038c81166c01000000000000000000000000908102602080850191909152918d16810260348401526048830195909552606882019390935267ffffffffffffffff90911660c060020a0260888201523090920260908301528251808303608401815260a490920192839052815191929182918401908083835b60208310610e535780518252601f199092019160209182019101610e34565b51815160209384036101000a600019018019909216911617905260408051929094018290038220600080516020613a2383398151915283830152603c8084019190915284518084039091018152605c9092019384905281519195509293508392850191508083835b60208310610eda5780518252601f199092019160209182019101610ebb565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390208a8560ff16815181101515610f1857fe5b6020908102909101015261112e565b60a08801805160091901600090810b900b9052600654604080517f4f72646572286164647265737320627579546f6b656e416464726573732c616481527f64726573732073656c6c546f6b656e416464726573732c75696e7432353620626020808301919091527f7579546f6b656e416d6f756e742c75696e743235362073656c6c546f6b656e41828401527f6d6f756e742c75696e743634206e6f6e636529000000000000000000000000006060808401919091528351928390036073018320938d0151908d015160808e015161100795948e948e9493929101613892565b6040516020818303038152906040526040518082805190602001908083835b602083106110455780518252601f199092019160209182019101611026565b51815160209384036101000a6000190180199092169116179052604080519290940182900382207f190100000000000000000000000000000000000000000000000000000000000083830152602283019790975260428083019790975283518083039097018752606290910192839052855192945084935085019190508083835b602083106110e55780518252601f1990920191602091820191016110c6565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390208a8560ff1681518110151561112357fe5b602090810290910101525b60018a8560ff1681518110151561114157fe5b906020019060200201518960a001518a60c001518b60e0015160405160008152602001604052604051611177949392919061392a565b60206040516020810390808403906000865af115801561119b573d6000803e3d6000fd5b50505060206040510351898560ff168151811015156111b657fe5b600160a060020a03909216602092830290910190910152841561123a57600560008a8660ff168151811015156111e857fe5b6020908102909101810151600160a060020a03908116835290820192909252604001600020548a519116908a9060ff871690811061122257fe5b600160a060020a039092166020928302909101909101525b600190930192610cf9565b8b519a50600093505b8a8460ff1610156119e4578b8460ff1681518110151561126a57fe5b906020019060200201519250826000015160ff169150826020015160ff1690508d8d8381518110151561129957fe5b906020019060200201516000015160ff168151811015156112b657fe5b9060200190602002015196508d8d828151811015156112d157fe5b906020019060200201516000015160ff168151811015156112ee57fe5b9060200190602002015195508c8181518110151561130857fe5b906020019060200201516020015160ff168d8381518110151561132757fe5b602090810290910101515160ff1614801561137a57508c8281518110151561134b57fe5b906020019060200201516020015160ff168d8281518110151561136a57fe5b602090810290910101515160ff16145b80156113ee57508260c0015183604001510360008088600160a060020a0316600160a060020a0316815260200190815260200160002060008b858151811015156113c057fe5b90602001906020020151600160a060020a0316600160a060020a031681526020019081526020016000205410155b801561145157506060830151600160a060020a03881660009081526020819052604081208b519091908c908590811061142357fe5b90602001906020020151600160a060020a0316600160a060020a031681526020019081526020016000205410155b80156114b157508c8281518110151561146657fe5b906020019060200201516040015183606001518e8481518110151561148757fe5b90602001906020020151606001510281151561149f57fe5b046001018360c0015184604001510311155b801561150b57508c818151811015156114c657fe5b906020019060200201516040015183604001518e838151811015156114e757fe5b9060200190602002015160600151028115156114ff57fe5b04600101836060015111155b801561156357508c8181518110151561152057fe5b9060200190602002015160600151600460008c8481518110151561154057fe5b602090810290910181015182528101919091526040016000205460608501510111155b80156115c857508c8281518110151561157857fe5b9060200190602002015160600151600460008c8581518110151561159857fe5b9060200190602002015160001916600019168152602001908152602001600020548460c001518560400151030111155b80156115e05750606083015160649004836080015111155b80156115f857506040830151603290048360a0015111155b801561160c57508260a001518360c0015111155b156119a1578260c0015183604001510360008088600160a060020a0316600160a060020a0316815260200190815260200160002060008b8581518110151561165057fe5b90602001906020020151600160a060020a0316600160a060020a0316815260200190815260200160002060008282540392505081905550826060015160008089600160a060020a0316600160a060020a0316815260200190815260200160002060008b848151811015156116c057fe5b90602001906020020151600160a060020a0316600160a060020a0316815260200190815260200160002060008282540392505081905550826080015183606001510360008089600160a060020a0316600160a060020a0316815260200190815260200160002060008b8581518110151561173657fe5b90602001906020020151600160a060020a0316600160a060020a03168152602001908152602001600020600082825401925050819055508260a0015183604001510360008088600160a060020a0316600160a060020a0316815260200190815260200160002060008b848151811015156117ac57fe5b90602001906020020151600160a060020a0316600160a060020a03168152602001908152602001600020600082825401925050819055508260400151600460008c858151811015156117fa57fe5b602090810290910181015182528101919091526040016000908120805490920190915560608401518b5190916004918d908590811061183557fe5b602090810290910181015182528181019290925260409081016000908120805490940190935560c086015160a0870151600160a060020a03808c1680875286865284872060088054841689529087528588208054959094039490940190925560808901518d821687528686528487209354909116865291845282852080549092019091558352600190915281208a5182908c90869081106118d257fe5b90602001906020020151600160a060020a0316600160a060020a031681526020019081526020016000208190555060006001600089600160a060020a0316600160a060020a0316815260200190815260200160002060008b8481518110151561193757fe5b90602001906020020151600160a060020a0316600160a060020a03168152602001908152602001600020819055507f8ad6722e47fa4ed412d2581f997c77f89055264ff482b1ecaad374e375f7e08684604051611994919061399f565b60405180910390a16119d9565b7ff2c028745c4bf2c35a094e47e3bf2025379a9d043be3624baeac0f2e9a8155eb846040516119d0919061399f565b60405180910390a15b60019093019261124e565b5050505050505050505050505050565b604080516c01000000000000000000000000338102602080840191909152600160a060020a038b1682026034840152604883018a905260c060020a67ffffffffffffffff8a1602606884015230919091026070830152825160648184030181526084909201928390528151600093918291908401908083835b60208310611a8c5780518252601f199092019160209182019101611a6d565b51815160209384036101000a600019018019909216911617905260408051929094018290038220600080516020613a2383398151915283830152603c8084019190915284518084039091018152605c9092019384905281519195509293508392850191508083835b60208310611b135780518252601f199092019160209182019101611af4565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008181526003909252929020549194505060ff16159150508015611bce57506009600060018388888860405160008152602001604052604051611b82949392919061392a565b60206040516020810390808403906000865af1158015611ba6573d6000803e3d6000fd5b505060408051601f190151600160a060020a03168352602083019390935250016000205460ff165b8015611bfb5750600160a060020a0388166000908152602081815260408083203384529091529020548711155b156106ca576000818152600360209081526040808320805460ff19166001179055600160a060020a038b16808452838352818420338552909252909120805489900390551515611c9057604051600160a060020a0383169088156108fc029089906000818181858888f193505050501515611c8b5760405160e560020a62461bcd0281526004016105ec9061395f565b611d1c565b60405160e060020a63a9059cbb028152600160a060020a0389169063a9059cbb90611cc19085908b90600401613869565b600060405180830381600087803b158015611cdb57600080fd5b505af1158015611cef573d6000803e3d6000fd5b50505050611cfb612eb5565b1515611d1c5760405160e560020a62461bcd0281526004016105ec9061398f565b600160a060020a0388166000908152600160209081526040808320338085529252808320929092559051600080516020613a4383398151915291610b71918b908b90613841565b33600090815260096020526040812054819060ff16156106ca575050805160005b818160ff161015611e1b5760001960046000858460ff16815181101515611da757fe5b602090810290910181015182528101919091526040016000205582517f30ad15c39984aa59d60d4089cbbbaa503c4c9e0fa0e3bdf62a5bab180fcb974d90849060ff8416908110611df457fe5b90602001906020020151604051611e0b9190613884565b60405180910390a1600101611d84565b505050565b600754600160a060020a03163314611e3757600080fd5b600160a060020a03919091166000908152600960205260409020805460ff1916911515919091179055565b600754600160a060020a03163314611e7957600080fd5b6008805475ff00000000000000000000000000000000000000000019167501000000000000000000000000000000000000000000179055565b600160a060020a031660009081526002602052604090205490565b6000806009600060018860405160200180828051906020019060200280838360005b83811015611f07578181015183820152602001611eef565b505050509050019150506040516020818303038152906040526040518082805190602001908083835b60208310611f4f5780518252601f199092019160209182019101611f30565b51815160209384036101000a600019018019909216911617905260408051929094018290038220600080516020613a2383398151915283830152603c8084019190915284518084039091018152605c9092019384905281519195509293508392850191508083835b60208310611fd65780518252601f199092019160209182019101611fb7565b51815160209384036101000a6000190180199092169116179052604080519290940182900382206000835291019283905261201a945092508b918b91508a9061392a565b60206040516020810390808403906000865af115801561203e573d6000803e3d6000fd5b505060408051601f190151600160a060020a03168352602083019390935250016000205460ff16156106ca575050835160005b818160ff1610156121085760001960046000888460ff1681518110151561209457fe5b602090810290910181015182528101919091526040016000205585517f30ad15c39984aa59d60d4089cbbbaa503c4c9e0fa0e3bdf62a5bab180fcb974d90879060ff84169081106120e157fe5b906020019060200201516040516120f89190613884565b60405180910390a1600101612071565b505050505050565b600160a060020a038216600081815260016020908152604080832033808552908352818420549484528383528184209084529091529020540381116106ca57600160a060020a03821660009081526001602090815260408083203380855290835281842080548601905560029092529182902042905590517f3164b497762cc91ae73104303c2e7a8891d4b66d48a184659a791bbb4eb090a0916106bd9185908590613841565b604080516c01000000000000000000000000338102602080840191909152600160a060020a038a16820260348401526048830189905260c060020a67ffffffffffffffff891602606884015230919091026070830152825160648184030181526084909201928390528151600093918291908401908083835b6020831061224f5780518252601f199092019160209182019101612230565b51815160209384036101000a600019018019909216911617905260408051929094018290038220600080516020613a2383398151915283830152603c8084019190915284518084039091018152605c9092019384905281519195509293508392850191508083835b602083106122d65780518252601f1990920191602091820191016122b7565b51815160209384036101000a6000190180199092169116179052604080519290940182900390912060008181526003909252929020549194505060ff1615915050801561239157506009600060018387878760405160008152602001604052604051612345949392919061392a565b60206040516020810390808403906000865af1158015612369573d6000803e3d6000fd5b505060408051601f190151600160a060020a03168352602083019390935250016000205460ff165b80156123be5750600160a060020a0387166000908152602081815260408083203384529091529020548611155b156106ca576000818152600360209081526040808320805460ff19166001179055600160a060020a038a1680845283835281842033855290925290912080548890039055151561244a57604051339087156108fc029088906000818181858888f1935050505015156124455760405160e560020a62461bcd0281526004016105ec9061395f565b6124d6565b60405160e060020a63a9059cbb028152600160a060020a0388169063a9059cbb9061247b9033908a90600401613869565b600060405180830381600087803b15801561249557600080fd5b505af11580156124a9573d6000803e3d6000fd5b505050506124b5612eb5565b15156124d65760405160e560020a62461bcd0281526004016105ec9061398f565b600160a060020a0387166000908152600160209081526040808320338085529252808320929092559051600080516020613a438339815191529161251d918a908a90613841565b60405180910390a150505050505050565b600160a060020a03821660009081526020818152604080832033845290915290205481118015906125825750600160a060020a03821660009081526001602090815260408083203384529091529020548111155b80156125a4575033600090815260026020526040902054426201518090910111155b156106ca57600160a060020a038216600081815260208181526040808320338085529083528184208054879003905584845260018352818420908452909152902080548390039055151561263457604051339082156108fc029083906000818181858888f19350505050151561262f5760405160e560020a62461bcd0281526004016105ec9061395f565b6126c0565b60405160e060020a63a9059cbb028152600160a060020a0383169063a9059cbb906126659033908590600401613869565b600060405180830381600087803b15801561267f57600080fd5b505af1158015612693573d6000803e3d6000fd5b5050505061269f612eb5565b15156126c05760405160e560020a62461bcd0281526004016105ec9061398f565b7feadfbee5f7c5470e351e606774e86dd5d5b4dde5bfb2fa4fc541c2304cc427a83383836040516106bd93929190613841565b600080601e8560ff16101561284b57604080516c01000000000000000000000000600160a060020a038c168102602080840191909152603483018c905260c060020a67ffffffffffffffff8b160260548401523091909102605c83015282516050818403018152607090920192839052815191929182918401908083835b602083106127905780518252601f199092019160209182019101612771565b51815160209384036101000a600019018019909216911617905260408051929094018290038220600080516020613a2383398151915283830152603c8084019190915284518084039091018152605c9092019384905281519195509293508392850191508083835b602083106128175780518252601f1990920191602091820191016127f8565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902091506129d1565b600654604080517f5769746864726177616c286164647265737320746f6b656e2c75696e7432353681527f20616d6f756e742c75696e743634206e6f6e63652900000000000000000000006020808301919091529151908190036035018120600919909801976128c39290918d918d918c91016138ec565b6040516020818303038152906040526040518082805190602001908083835b602083106129015780518252601f1990920191602091820191016128e2565b51815160209384036101000a6000190180199092169116179052604080519290940182900382207f190100000000000000000000000000000000000000000000000000000000000083830152602283019790975260428083019790975283518083039097018752606290910192839052855192945084935085019190508083835b602083106129a15780518252601f199092019160209182019101612982565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902091505b600182868686604051600081526020016040526040516129f4949392919061392a565b60206040516020810390808403906000865af1158015612a18573d6000803e3d6000fd5b505060408051601f19015160008581526003602052919091205490925060ff161590508015612a5657503360009081526009602052604090205460ff165b8015612a655750603288048711155b8015612a945750600160a060020a03808a16600090815260208181526040808320938516835292905220548811155b156106ca576000828152600360209081526040808320805460ff19166001179055600160a060020a038c8116808552848452828520868316865290935281842080548d900390556008541683529091208054890190551515612b3c57604051600160a060020a03821690888a0380156108fc02916000818181858888f193505050501515612b375760405160e560020a62461bcd0281526004016105ec9061395f565b612bca565b60405160e060020a63a9059cbb028152600160a060020a038a169063a9059cbb90612b6f9084908b8d0390600401613869565b600060405180830381600087803b158015612b8957600080fd5b505af1158015612b9d573d6000803e3d6000fd5b50505050612ba9612eb5565b1515612bca5760405160e560020a62461bcd0281526004016105ec9061398f565b600160a060020a03808a16600090815260016020908152604080832093851683529290528181205551600080516020613a4383398151915290612c129083908c908c90613841565b60405180910390a1505050505050505050565b600160a060020a03808316600090815260208181526040808320938516835292905220545b92915050565b604080516c01000000000000000000000000600160a060020a03871681026020808401919091523382026034840152309190910260488301528251603c818403018152605c909201928390528151600093918291908401908083835b60208310612ccb5780518252601f199092019160209182019101612cac565b51815160209384036101000a600019018019909216911617905260408051929094018290038220600080516020613a2383398151915283830152603c8084019190915284518084039091018152605c9092019384905281519195509293508392850191508083835b60208310612d525780518252601f199092019160209182019101612d33565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902090506009600060018387878760405160008152602001604052604051612da8949392919061392a565b60206040516020810390808403906000865af1158015612dcc573d6000803e3d6000fd5b505060408051601f190151600160a060020a03168352602083019390935250016000205460ff161515612e145760405160e560020a62461bcd0281526004016105ec9061397f565b600160a060020a038516600090815260056020526040808220805473ffffffffffffffffffffffffffffffffffffffff19166001179055517f4cb8e0239d1e27be8d3440c681240f004fa60c61a26c18b327554b46592dbbc891612e7b9133918991613819565b60405180910390a15050505050565b600160a060020a03918216600090815260016020908152604080832093909416825291909152205490565b6000803d8015612ecc5760208114612ed557612ee1565b60019150612ee1565b60206000803e60005191505b501515919050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b60e060405190810160405280600060ff168152602001600060ff16815260200160008152602001600081526020016000815260200160008152602001600081525090565b6000612f7d82356139f5565b9392505050565b6000601f82018313612f9557600080fd5b8135612fa8612fa3826139d4565b6139ad565b91508181835260208401935060208101905083856020840282011115612fcd57600080fd5b60005b83811015612ff95781612fe38882612f71565b8452506020928301929190910190600101612fd0565b5050505092915050565b6000601f8201831361301457600080fd5b8135613022612fa3826139d4565b9150818183526020840193506020810190508385602084028201111561304757600080fd5b60005b83811015612ff9578161305d8882613165565b845250602092830192919091019060010161304a565b6000601f8201831361308457600080fd5b8135613092612fa3826139d4565b91508181835260208401935060208101905083856101008402820111156130b857600080fd5b60005b83811015612ff957816130ce888261317d565b84525060209092019161010091909101906001016130bb565b6000601f820183136130f857600080fd5b8135613106612fa3826139d4565b915081818352602084019350602081019050838560e084028201111561312b57600080fd5b60005b83811015612ff95781613141888261323e565b84525060209092019160e0919091019060010161312e565b6000612f7d8235613a01565b6000612f7d8235613a06565b6000612f7d8235613a1c565b6000610100828403121561319057600080fd5b61319b6101006139ad565b905060006131a984846132f5565b82525060206131ba848483016132f5565b60208301525060406131ce84828501613165565b60408301525060606131e284828501613165565b60608301525060806131f6848285016132e9565b60808301525060a061320a84828501613171565b60a08301525060c061321e84828501613165565b60c08301525060e061323284828501613165565b60e08301525092915050565b600060e0828403121561325057600080fd5b61325a60e06139ad565b9050600061326884846132f5565b8252506020613279848483016132f5565b602083015250604061328d84828501613165565b60408301525060606132a184828501613165565b60608301525060806132b584828501613165565b60808301525060a06132c984828501613165565b60a08301525060c06132dd84828501613165565b60c08301525092915050565b6000612f7d8235613a09565b6000612f7d8235613a16565b60006020828403121561331357600080fd5b600061331f8484612f71565b949350505050565b6000806040838503121561333a57600080fd5b60006133468585612f71565b925050602061335785828601612f71565b9150509250929050565b6000806040838503121561337457600080fd5b60006133808585612f71565b925050602061335785828601613159565b600080604083850312156133a457600080fd5b60006133b08585612f71565b925050602061335785828601613165565b600080600080600080600060e0888a0312156133dc57600080fd5b60006133e88a8a612f71565b97505060206133f98a828b01613165565b965050604061340a8a828b01613165565b955050606061341b8a828b016132e9565b945050608061342c8a828b016132f5565b93505060a061343d8a828b01613165565b92505060c061344e8a828b01613165565b91505092959891949750929550565b60008060008060008060c0878903121561347657600080fd5b60006134828989612f71565b965050602061349389828a01613165565b95505060406134a489828a016132e9565b94505060606134b589828a016132f5565b93505060806134c689828a01613165565b92505060a06134d789828a01613165565b9150509295509295509295565b600080600080600080600060e0888a0312156134ff57600080fd5b600061350b8a8a612f71565b975050602061351c8a828b01613165565b965050604061352d8a828b016132e9565b955050606061353e8a828b016132f5565b945050608061354f8a828b01613165565b93505060a06135608a828b01613165565b92505060c061344e8a828b01612f71565b6000806000806080858703121561358757600080fd5b60006135938787612f71565b94505060206135a4878288016132f5565b93505060406135b587828801613165565b92505060606135c687828801613165565b91505092959194509250565b6000806000606084860312156135e757600080fd5b833567ffffffffffffffff8111156135fe57600080fd5b61360a86828701612f84565b935050602084013567ffffffffffffffff81111561362757600080fd5b61363386828701613073565b925050604084013567ffffffffffffffff81111561365057600080fd5b61365c868287016130e7565b9150509250925092565b60006020828403121561367857600080fd5b813567ffffffffffffffff81111561368f57600080fd5b61331f84828501613003565b600080600080608085870312156136b157600080fd5b843567ffffffffffffffff8111156136c857600080fd5b61359387828801613003565b6000602082840312156136e657600080fd5b600061331f8484613159565b6136fb816139f5565b82525050565b6136fb81613a01565b6136fb81613a06565b601681527f53656e64696e67206f6620455448206661696c65642e00000000000000000000602082015260400190565b601d81527f4164647265737320697320616c726561647920612064656c6567617465000000602082015260400190565b602281527f4d756c7469536967206973206e6f742066726f6d206b6e6f776e20617262697460208201527f6572000000000000000000000000000000000000000000000000000000000000604082015260600190565b601c81527f455243323020746f6b656e207472616e73666572206661696c65642e00000000602082015260400190565b6136fb81613a09565b6136fb81613a16565b60208101612c4a82846136f2565b6060810161382782866136f2565b61383460208301856136f2565b61331f6040830184613701565b6060810161384f82866136f2565b61385c60208301856136f2565b61331f604083018461370a565b6040810161387782856136f2565b612f7d602083018461370a565b60208101612c4a828461370a565b60c081016138a0828961370a565b6138ad60208301886136f2565b6138ba60408301876136f2565b6138c7606083018661370a565b6138d4608083018561370a565b6138e160a08301846137f9565b979650505050505050565b608081016138fa828761370a565b61390760208301866136f2565b613914604083018561370a565b61392160608301846137f9565b95945050505050565b60808101613938828761370a565b6139456020830186613802565b613952604083018561370a565b613921606083018461370a565b60208082528101612c4a81613713565b60208082528101612c4a81613743565b60208082528101612c4a81613773565b60208082528101612c4a816137c9565b60208101612c4a8284613802565b60405181810167ffffffffffffffff811182821017156139cc57600080fd5b604052919050565b600067ffffffffffffffff8211156139eb57600080fd5b5060209081020190565b600160a060020a031690565b151590565b90565b67ffffffffffffffff1690565b60ff1690565b60000b90560019457468657265756d205369676e6564204d6573736167653a0a3332000000002717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398a265627a7a7230582005ac64da0bc2a1953968bc6fd98ea4a383d11d73b86360a202386bd43314b80f6c6578706572696d656e74616cf50037

   Swarm Source:
bzzr://05ac64da0bc2a1953968bc6fd98ea4a383d11d73b86360a202386bd43314b80f

 

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