false
true
0

Contract Address Details

0x985377478341Fa9D4f09A8ec95b58B4C7Fb80C6E

Contract Name
FastExitHandlerMigration
Creator
0x8db6b6–155388 at 0x74e359–0119cc
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
26350870
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
This contract has been partially verified via Sourcify. View contract in Sourcify repository
Contract name:
FastExitHandlerMigration




Optimization enabled
true
Compiler version
v0.5.2+commit.1df8f40c




Optimization runs
200
EVM Version
byzantium




Verified at
2026-04-22T18:08:24.365311Z

FastExitHandlerMigration.sol

/**
 *Submitted for verification at Etherscan.io on 2019-06-20
*/

/**
 *Submitted for verification at Etherscan.io on 2019-02-09
*/

/**
 * Copyright (c) 2018-present, Leap DAO (leapdao.org)
 *
 * This source code is licensed under the Mozilla Public License, version 2,
 * found in the LICENSE file in the root directory of this source tree.
 */

pragma solidity 0.5.2;

/**
 * @title Math
 * @dev Assorted math operations
 */
library Math {
    /**
    * @dev Returns the largest of two numbers.
    */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
    * @dev Returns the smallest of two numbers.
    */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
    * @dev Calculates the average of two numbers. Since these are integers,
    * averages of an even and odd number cannot be represented, and will be
    * rounded down.
    */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}


contract Bridge {

  event NewHeight(uint256 height, bytes32 indexed root);
  event NewOperator(address operator);

  struct Period {
    uint32 height;  // the height of last block in period
    uint32 timestamp;
  }

  bytes32 constant GENESIS = 0x4920616d207665727920616e6772792c20627574206974207761732066756e21;

  bytes32 public tipHash; // hash of first period that has extended chain to some height
  uint256 public genesisBlockNumber;
  uint256 parentBlockInterval; // how often epochs can be submitted max
  uint256 public lastParentBlock; // last ethereum block when epoch was submitted
  address public operator; // the operator contract

  mapping(bytes32 => Period) public periods;

  function getParentBlockInterval() public view returns (uint256) {
    return parentBlockInterval;
  }

  function setParentBlockInterval(uint256 _parentBlockInterval) public {
    parentBlockInterval = _parentBlockInterval;
  }

  function submitPeriod(
    bytes32 _prevHash, 
    bytes32 _root) 
  public returns (uint256 newHeight) {

  }
}

contract Initializable {

  /**
   * @dev Indicates that the contract has been initialized.
   */
  bool private initialized;

  /**
   * @dev Indicates that the contract is in the process of being initialized.
   */
  bool private initializing;

  /**
   * @dev Modifier to use in the initializer function of a contract.
   */
  modifier initializer() {
    require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");

    bool wasInitializing = initializing;
    initializing = true;
    initialized = true;

    _;

    initializing = wasInitializing;
  }

  /// @dev Returns true if and only if the function is running in the constructor
  function isConstructor() private view returns (bool) {
    // extcodesize checks the size of the code stored in an address, and
    // address returns the current address. Since the code is still not
    // deployed when running a constructor, any checks on its code size will
    // yield zero, making it an effective way to detect if a contract is
    // under construction or not.
    uint256 cs;
    assembly { cs := extcodesize(address) }
    return cs == 0;
  }

  // Reserved storage space to allow for layout changes in the future.
  uint256[50] private ______gap;
}

/**
 * @title Adminable
 *
 * @dev Helper contract to support initializer functions. To use it, replace
 * the constructor with a function that has the `initializer` modifier.
 * WARNING: Unlike constructors, initializer functions must be manually
 * invoked. This applies both to deploying an Initializable contract, as well
 * as extending an Initializable contract via inheritance.
 * WARNING: When used with inheritance, manual care must be taken to not invoke
 * a parent initializer twice, or ensure that all initializers are idempotent,
 * because this is not dealt with automatically as with constructors.
 */
contract Adminable is Initializable {

  /**
   * @dev Storage slot with the admin of the contract.
   * This is the keccak-256 hash of "org.zeppelinos.proxy.admin", and is
   * validated in the constructor.
   */
  bytes32 private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b;

  /**
   * @dev Modifier to check whether the `msg.sender` is the admin.
   * If it is, it will run the function. Otherwise, fails.
   */
  modifier ifAdmin() {
    require(msg.sender == _admin());
    _;
  }

  function admin() external view returns (address) {
    return _admin();
  }

    /**
   * @return The admin slot.
   */
  function _admin() internal view returns (address adm) {
    bytes32 slot = ADMIN_SLOT;
    assembly {
      adm := sload(slot)
    }
  }
}


/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
interface ERC20 {
    function transfer(address to, uint256 value) external returns (bool);

    function approve(address spender, uint256 value) external returns (bool);

    function transferFrom(address from, address to, uint256 value) external returns (bool);

    function totalSupply() external view returns (uint256);

    function balanceOf(address who) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);
}

/**
 * @title IERC165
 * @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
 */
interface ERC165 {
    /**
     * @notice Query if a contract implements an interface
     * @param interfaceId The interface identifier, as specified in ERC-165
     * @dev Interface identification is specified in ERC-165. This function
     * uses less than 30,000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

contract TransferrableToken is ERC165 {
  function transferFrom(address _from, address _to, uint256 _valueOrTokenId) public;
  function approve(address _to, uint256 _value) public;
}


library SafeMath {
    /**
    * @dev Multiplies two unsigned integers, reverts on overflow.
    */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
            return 0;
        }

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

        return c;
    }

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

        return c;
    }

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

        return c;
    }

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

        return c;
    }

    /**
    * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
    * reverts when dividing by zero.
    */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0);
        return a % b;
    }
}



/**
 * @title PriorityQueue
 * @dev A priority queue implementation
 */

library PriorityQueue {
  using SafeMath for uint256;

  struct Token {
    TransferrableToken addr;
    uint256[] heapList;
    uint256 currentSize;
  }

  function insert(Token storage self, uint256 k) public {
    self.heapList.push(k);
    self.currentSize = self.currentSize.add(1);
    percUp(self, self.currentSize);
  }

  function minChild(Token storage self, uint256 i) public view returns (uint256) {
    if (i.mul(2).add(1) > self.currentSize) {
      return i.mul(2);
    } else {
      if (self.heapList[i.mul(2)] < self.heapList[i.mul(2).add(1)]) {
        return i.mul(2);
      } else {
        return i.mul(2).add(1);
      }
    }
  }

  function getMin(Token storage self) public view returns (uint256) {
    return self.heapList[1];
  }

  function delMin(Token storage self) public returns (uint256) {
    uint256 retVal = self.heapList[1];
    self.heapList[1] = self.heapList[self.currentSize];
    delete self.heapList[self.currentSize];
    self.currentSize = self.currentSize.sub(1);
    percDown(self, 1);
    self.heapList.length = self.heapList.length.sub(1);
    return retVal;
  }

  // solium-disable-next-line security/no-assign-params
  function percUp(Token storage self, uint256 i) private {
    uint256 j = i;
    uint256 newVal = self.heapList[i];
    while (newVal < self.heapList[i.div(2)]) {
      self.heapList[i] = self.heapList[i.div(2)];
      i = i.div(2);
    }
    if (i != j) self.heapList[i] = newVal;
  }

  // solium-disable-next-line security/no-assign-params
  function percDown(Token storage self, uint256 i) private {
    uint256 j = i;
    uint256 newVal = self.heapList[i];
    uint256 mc = minChild(self, i);
    while (mc <= self.currentSize && newVal > self.heapList[mc]) {
      self.heapList[i] = self.heapList[mc];
      i = mc;
      mc = minChild(self, i);
    }
    if (i != j) self.heapList[i] = newVal;
  }

}

contract Vault is Adminable {

  event NewToken(address indexed tokenAddr, uint16 color);

  Bridge public bridge;

  uint16 public erc20TokenCount;
  uint16 public nftTokenCount;

  mapping(uint16 => PriorityQueue.Token) public tokens;
  mapping(address => bool) public tokenColors;

  function initialize(Bridge _bridge) public initializer {
    bridge = _bridge;
  } 

  function getTokenAddr(uint16 _color) public view returns (address) {
    return address(tokens[_color].addr);
  }

  function registerToken(address _token, bool _isERC721) public ifAdmin {
    // make sure token is not 0x0 and that it has not been registered yet
    require(_token != address(0), "Tried to register 0x0 address");
    require(!tokenColors[_token], "Token already registered");
    uint16 color;
    if (_isERC721) {
      require(TransferrableToken(_token).supportsInterface(0x80ac58cd) == true, "Not an ERC721 token");
      color = 32769 + nftTokenCount; // NFT color namespace starts from 2^15 + 1
      nftTokenCount += 1;
    } else {
      require(ERC20(_token).totalSupply() >= 0, "Not an ERC20 token");
      color = erc20TokenCount;
      erc20TokenCount += 1;
    }
    uint256[] memory arr = new uint256[](1);
    tokenColors[_token] = true;
    tokens[color] = PriorityQueue.Token({
      addr: TransferrableToken(_token),
      heapList: arr,
      currentSize: 0
    });
    emit NewToken(_token, color);
  }

  // solium-disable-next-line mixedcase
  uint256[50] private ______gap;

}

contract DepositHandler is Vault {

  event NewDeposit(
    uint32 indexed depositId, 
    address indexed depositor, 
    uint256 indexed color, 
    uint256 amount
  );
  event MinGasPrice(uint256 minGasPrice);

  struct Deposit {
    uint64 time;
    uint16 color;
    address owner;
    uint256 amount;
  }

  uint32 public depositCount;
  uint256 public minGasPrice;

  mapping(uint32 => Deposit) public deposits;

  function setMinGasPrice(uint256 _minGasPrice) public ifAdmin {
    minGasPrice = _minGasPrice;
    emit MinGasPrice(minGasPrice);
  }

   /**
   * @notice Add to the network `(_amountOrTokenId)` amount of a `(_color)` tokens
   * or `(_amountOrTokenId)` token id if `(_color)` is NFT.
   * @dev Token should be registered with the Bridge first.
   * @param _owner Account to transfer tokens from
   * @param _amountOrTokenId Amount (for ERC20) or token ID (for ERC721) to transfer
   * @param _color Color of the token to deposit
   */
  function deposit(address _owner, uint256 _amountOrTokenId, uint16 _color) public {
    TransferrableToken token = tokens[_color].addr;
    require(address(token) != address(0), "Token color not registered");
    require(_amountOrTokenId > 0 || _color > 32769, "no 0 deposits for fungible tokens");
    token.transferFrom(_owner, address(this), _amountOrTokenId);

    bytes32 tipHash = bridge.tipHash();
    uint256 timestamp;
    (, timestamp) = bridge.periods(tipHash);

    depositCount++;
    deposits[depositCount] = Deposit({
      time: uint32(timestamp),
      owner: _owner,
      color: _color,
      amount: _amountOrTokenId
    });
    emit NewDeposit(
      depositCount, 
      _owner, 
      _color, 
      _amountOrTokenId
    );
  }

  // solium-disable-next-line mixedcase
  uint256[50] private ______gap;
}


library TxLib {

  uint constant internal WORD_SIZE = 32;
  uint constant internal ONES = ~uint(0);
  enum TxType { None0, None1, Deposit, Transfer, None4, None5,
  None6, None7, None8, None9, None10, None11, None12, SpendCond }

  struct Outpoint {
    bytes32 hash;
    uint8 pos;
  }

  struct Input {
    Outpoint outpoint;
    bytes32 r;
    bytes32 s;
    uint8 v;
    bytes script;
    bytes msgData;
  }

  struct Output {
    uint256 value;
    uint16 color;
    address owner;
    bytes32 stateRoot;
  }

  struct Tx {
    TxType txType;
    Input[] ins;
    Output[] outs;
  }

  function parseInput(
    TxType _type, bytes memory _txData, uint256 _pos, uint256 offset, Input[] memory _ins
  ) internal pure returns (uint256 newOffset) {
    bytes32 inputData;
    uint8 index;
    if (_type == TxType.Deposit) {
      assembly {
        // load the depositId (4 bytes) starting from byte 2 of tx
        inputData := mload(add(add(offset, 4), _txData))
      }
      inputData = bytes32(uint256(uint32(uint256(inputData))));
      index = 0;
      newOffset = offset + 4;
    } else {
      assembly {
        // load the prevHash (32 bytes) from input
        inputData := mload(add(add(offset, 32), _txData))
        // load the output index (1 byte) from input
        index := mload(add(add(offset, 33), _txData))
      }
      newOffset = offset + 33;
    }
    Outpoint memory outpoint = Outpoint(inputData, index);
    bytes memory data = new bytes(0);
    Input memory input = Input(outpoint, 0, 0, 0, data, data); // solium-disable-line arg-overflow
    if (_type == TxType.SpendCond) {
      uint16 len;
      assembly {
        len := mload(add(add(offset, 35), _txData)) 
      }
      // read msgData
      data = new bytes(len);  
      uint src;
      uint dest;
      assembly {  
        src := add(add(add(offset, 35), 0x20), _txData) 
        dest := add(data, 0x20) 
      }
      memcopy(src, dest, len);  
      input.msgData = data;  
      newOffset = offset + 37 + len;

      assembly {
        len := mload(add(newOffset, _txData)) 
      }

      // read script
      data = new bytes(len);
      assembly {  
        src := add(add(add(newOffset, 0), 0x20), _txData) 
        dest := add(data, 0x20) 
      }
      memcopy(src, dest, len);  
      input.script = data;
      newOffset = newOffset + len;
    }
    if (_type == TxType.Transfer) {
      bytes32 r;
      bytes32 s;
      uint8 v;
      assembly {
        r := mload(add(add(offset, 65), _txData))
        s := mload(add(add(offset, 97), _txData))
        v := mload(add(add(offset, 98), _txData))
      }
      input.r = r;
      input.s = s;
      input.v = v;
      newOffset = offset + 33 + 65;
    }
    _ins[_pos] = input;
  }

  // Copies 'len' bytes from 'srcPtr' to 'destPtr'.
  // NOTE: This function does not check if memory is allocated, it only copies the bytes.
  function memcopy(uint srcPtr, uint destPtr, uint len) internal pure {
    uint offset = 0;
    uint size = len / WORD_SIZE;
    // Copy word-length chunks while possible.
    for (uint i = 0; i < size; i++) {
      offset = i * WORD_SIZE;
      assembly {
        mstore(add(destPtr, offset), mload(add(srcPtr, offset)))
      }
    }
    offset = size*WORD_SIZE;
    uint mask = ONES << 8*(32 - len % WORD_SIZE);
    assembly {
      let nSrc := add(srcPtr, offset)
      let nDest := add(destPtr, offset)
      mstore(nDest, or(and(mload(nSrc), mask), and(mload(nDest), not(mask))))
    }
  }

  function parseOutput(
    bytes memory _txData, uint256 _pos, uint256 offset, Output[] memory _outs
  ) internal pure returns (uint256 newOffset) {
    uint256 value;
    uint16 color;
    address owner;
    assembly {
      value := mload(add(add(offset, 32), _txData))
      color := mload(add(add(offset, 34), _txData))
      owner := mload(add(add(offset, 54), _txData))
    }
    Output memory output = Output(value, color, owner, 0);  // solium-disable-line arg-overflow
    _outs[_pos] = output;
    newOffset = offset + 54;
  }

  function parseTx(bytes memory _txData) internal pure returns (Tx memory txn) {
    // read type
    TxType txType;
    uint256 a;
    assembly {
      a := mload(add(0x20, _txData))
    }
    a = a >> 248; // get first byte
    if (a == 2) {
      txType = TxType.Deposit;
    } else if (a == 3) {
      txType = TxType.Transfer;
    } else if (a == 13) {
      txType = TxType.SpendCond;
    } else {
      revert("unknown tx type");
    }
    // read ins and outs
    assembly {
        a := mload(add(0x21, _txData))
    }
    a = a >> 252; // get ins-length nibble
    Input[] memory ins = new Input[](a);
    uint256 offset = 2;
    for (uint i = 0; i < ins.length; i++) {
      offset = parseInput(txType, _txData, i, offset, ins); // solium-disable-line arg-overflow
    }
    assembly {
        a := mload(add(0x21, _txData))
    }
    a = (a >> 248) & 0x0f; // get outs-length nibble
    Output[] memory outs = new Output[](a);
    for (uint256 i = 0; i < outs.length; i++) {
      offset = parseOutput(_txData, i, offset, outs); // solium-disable-line arg-overflow
    }
    txn = Tx(txType, ins, outs);
  }

  function getSigHash(bytes memory _txData) internal pure returns (bytes32 sigHash) {
    uint256 a;
    assembly {
      a := mload(add(0x20, _txData))
    }
    a = a >> 248;
    // if not transfer, sighash is just tx hash
    require(a == 3);
    // read ins
    assembly {
        a := mload(add(0x21, _txData))
    }
    a = a >> 252; // get ins-length nibble
    bytes memory sigData = new bytes(_txData.length);
    assembly {
      // copy type
      mstore8(add(sigData, 32), byte(0, mload(add(_txData, 32))))
      // copy #inputs / #outputs
      mstore8(add(sigData, 33), byte(1, mload(add(_txData, 32))))
      let offset := 0
      for
        { let i := 0 }
        lt(i, a)
        { i := add(i, 1) }
        {
          mstore(add(sigData, add(34, offset)), mload(add(_txData, add(34, offset))))
          mstore8(add(sigData, add(66, offset)), byte(0, mload(add(_txData, add(66, offset)))))
          offset := add(offset, add(33, 65))
        }
      for
        { let i := add(34, offset) }
        lt(i, add(64, mload(_txData)))
        { i := add(i, 0x20) }
        {
          mstore(add(sigData, i), mload(add(_txData, i)))
        }
    }

    return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", uint2str(_txData.length), sigData));
  }

  // solium-disable-next-line security/no-assign-params
  function getMerkleRoot(
    bytes32 _leaf, uint256 _index, uint256 _offset, bytes32[] memory _proof
  ) internal pure returns (bytes32) {
    bytes32 temp;
    for (uint256 i = _offset; i < _proof.length; i++) {
      temp = _proof[i];
      if (_index % 2 == 0) {
        assembly {
          mstore(0, _leaf)
          mstore(0x20, temp)
          _leaf := keccak256(0, 0x40)
        }
      } else {
        assembly {
          mstore(0, temp)
          mstore(0x20, _leaf)
          _leaf := keccak256(0, 0x40)
        }
      }
      _index = _index / 2;
    }
    return _leaf;
  }

  //validate that transaction is included to the period (merkle proof)
  function validateProof(
    uint256 _cdOffset, bytes32[] memory _proof
  ) internal pure returns (uint64 txPos, bytes32 txHash, bytes memory txData) {
    uint256 offset = uint8(uint256(_proof[1] >> 248));
    uint256 txLength = uint16(uint256(_proof[1] >> 224));

    txData = new bytes(txLength);
    assembly {
      calldatacopy(add(txData, 0x20), add(68, add(offset, _cdOffset)), txLength)
    }
    txHash = keccak256(txData);
    txPos = uint64(uint256(_proof[1] >> 160));
    bytes32 root = getMerkleRoot(
      txHash, 
      txPos, 
      uint8(uint256(_proof[1] >> 240)),
      _proof
    ); 
    require(root == _proof[0]);
  }

  function recoverTxSigner(uint256 offset, bytes32[] memory _proof) internal pure returns (address dest) {
    uint16 txLength = uint16(uint256(_proof[1] >> 224));
    bytes memory txData = new bytes(txLength);
    bytes32 r;
    bytes32 s;
    uint8 v;
    assembly {
      calldatacopy(add(txData, 32), add(114, offset), 43)
      r := calldataload(add(157, offset))
      s := calldataload(add(189, offset))
      v := calldataload(add(190, offset))
      calldatacopy(add(txData, 140), add(222, offset), 28) // 32 + 43 + 65
    }
    dest = ecrecover(getSigHash(txData), v, r, s); // solium-disable-line arg-overflow
  }

  // https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol#L886
  // solium-disable-next-line security/no-assign-params
  function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
    if (_i == 0) {
      return "0";
    }
    uint j = _i;
    uint len;
    while (j != 0) {
      len++;
      j /= 10;
    }
    bytes memory bstr = new bytes(len);
    uint k = len - 1;
    while (_i != 0) {
      bstr[k--] = byte(uint8(48 + _i % 10));
      _i /= 10;
    }
    return string(bstr);
  }

}

contract ExitHandler is DepositHandler {

  using PriorityQueue for PriorityQueue.Token;

  event ExitStarted(
    bytes32 indexed txHash, 
    uint8 indexed outIndex, 
    uint256 indexed color, 
    address exitor, 
    uint256 amount
  );

  struct Exit {
    uint256 amount;
    uint16 color;
    address owner;
    bool finalized;
    uint32 priorityTimestamp;
    uint256 stake;
  }

  uint256 public exitDuration;
  uint256 public exitStake;
  uint256 public nftExitCounter;

  /**
   * UTXO → Exit mapping. Contains exits for both NFT and ERC20 colors
   */
  mapping(bytes32 => Exit) public exits;

  function initializeWithExit(
    Bridge _bridge, 
    uint256 _exitDuration, 
    uint256 _exitStake) public initializer {
    initialize(_bridge);
    exitDuration = _exitDuration;
    exitStake = _exitStake;
    emit MinGasPrice(0);
  }

  function setExitStake(uint256 _exitStake) public ifAdmin {
    exitStake = _exitStake;
  }

  function setExitDuration(uint256 _exitDuration) public ifAdmin {
    exitDuration = _exitDuration;
  }

  function startExit(
    bytes32[] memory _youngestInputProof, bytes32[] memory _proof,
    uint8 _outputIndex, uint8 _inputIndex
  ) public payable {
    require(msg.value >= exitStake, "Not enough ether sent to pay for exit stake");
    uint32 timestamp;
    (, timestamp) = bridge.periods(_proof[0]);
    require(timestamp > 0, "The referenced period was not submitted to bridge");

    if (_youngestInputProof.length > 0) {
      (, timestamp) = bridge.periods(_youngestInputProof[0]);
      require(timestamp > 0, "The referenced period was not submitted to bridge");
    }

    // check exiting tx inclusion in the root chain block
    bytes32 txHash;
    bytes memory txData;
    uint64 txPos;
    (txPos, txHash, txData) = TxLib.validateProof(32 * (_youngestInputProof.length + 2) + 64, _proof);

    // parse exiting tx and check if it is exitable
    TxLib.Tx memory exitingTx = TxLib.parseTx(txData);
    TxLib.Output memory out = exitingTx.outs[_outputIndex];

    bytes32 utxoId = bytes32(uint256(_outputIndex) << 120 | uint120(uint256(txHash)));
    require(out.owner == msg.sender, "Only UTXO owner can start exit");
    require(out.value > 0, "UTXO has no value");
    require(exits[utxoId].amount == 0, "The exit for UTXO has already been started");
    require(!exits[utxoId].finalized, "The exit for UTXO has already been finalized");

    uint256 priority;
    if (_youngestInputProof.length > 0) {
      // check youngest input tx inclusion in the root chain block
      bytes32 inputTxHash;
      (txPos, inputTxHash,) = TxLib.validateProof(96, _youngestInputProof);
      require(
        inputTxHash == exitingTx.ins[_inputIndex].outpoint.hash, 
        "Input from the proof is not referenced in exiting tx"
      );
      
      if (isNft(out.color)) {
        priority = (nftExitCounter << 128) | uint128(uint256(utxoId));
        nftExitCounter++;
      } else {      
        priority = getERC20ExitPriority(timestamp, utxoId, txPos);
      }
    } else {
      require(exitingTx.txType == TxLib.TxType.Deposit, "Expected deposit tx");
      if (isNft(out.color)) {
        priority = (nftExitCounter << 128) | uint128(uint256(utxoId));
        nftExitCounter++;
      } else {      
        priority = getERC20ExitPriority(timestamp, utxoId, txPos);
      }
    }

    tokens[out.color].insert(priority);

    exits[utxoId] = Exit({
      owner: out.owner,
      color: out.color,
      amount: out.value,
      finalized: false,
      stake: exitStake,
      priorityTimestamp: timestamp
    });
    emit ExitStarted(
      txHash, 
      _outputIndex, 
      out.color, 
      out.owner, 
      out.value
    );
  }

  function startDepositExit(uint256 _depositId) public payable {
    require(msg.value >= exitStake, "Not enough ether sent to pay for exit stake");
    // check that deposit exits
    Deposit memory deposit = deposits[uint32(_depositId)];
    require(deposit.owner == msg.sender, "Only deposit owner can start exit");
    require(deposit.amount > 0, "deposit has no value");
    require(exits[bytes32(_depositId)].amount == 0, "The exit of deposit has already been started");
    require(!exits[bytes32(_depositId)].finalized, "The exit for deposit has already been finalized");
    
    uint256 priority;
    if (isNft(deposit.color)) {
      priority = (nftExitCounter << 128) | uint128(_depositId);
      nftExitCounter++;
    } else {      
      priority = getERC20ExitPriority(uint32(deposit.time), bytes32(_depositId), 0);
    }

    tokens[deposit.color].insert(priority);

    exits[bytes32(_depositId)] = Exit({
      owner: deposit.owner,
      color: deposit.color,
      amount: deposit.amount,
      finalized: false,
      stake: exitStake,
      priorityTimestamp: uint32(now)
    });
    emit ExitStarted(
      bytes32(_depositId), 
      0, 
      deposit.color, 
      deposit.owner, 
      deposit.amount
    );
  }

  // @dev Finalizes exit for the chosen color with the highest priority
  function finalizeExits(uint16 _color) public {
    bytes32 utxoId;
    uint256 exitableAt;
    Exit memory currentExit;

    (utxoId, exitableAt) = getNextExit(_color);

    require(tokens[_color].currentSize > 0, "Queue empty for color.");

    for (uint i = 0; i<20; i++) {
      // if queue is empty or top exit cannot be exited yet, stop
      if (exitableAt > block.timestamp) {
        return;
      }

      currentExit = exits[utxoId];

      if (currentExit.owner != address(0) || currentExit.amount != 0) { // exit was not removed
        // Note: for NFTs, the amount is actually the NFT id (both uint256)
        if (isNft(currentExit.color)) {
          tokens[currentExit.color].addr.transferFrom(address(this), currentExit.owner, currentExit.amount);
        } else {
          tokens[currentExit.color].addr.approve(address(this), currentExit.amount);
          tokens[currentExit.color].addr.transferFrom(address(this), currentExit.owner, currentExit.amount);
        }
        // Pay exit stake
        address(uint160(currentExit.owner)).send(currentExit.stake);

      }

      tokens[currentExit.color].delMin();
      exits[utxoId].finalized = true;

      if (tokens[currentExit.color].currentSize > 0) {
        (utxoId, exitableAt) = getNextExit(_color);
      } else {
        return;
      }
    }
  }

  // @dev For backwards compatibility reasons...
  function finalizeTopExit(uint16 _color) public {
    finalizeExits(_color);
  }

  function challengeExit(
    bytes32[] memory _proof, 
    bytes32[] memory _prevProof, 
    uint8 _outputIndex,
    uint8 _inputIndex
  ) public {
    // validate exiting tx
    uint256 offset = 32 * (_proof.length + 2);
    bytes32 txHash1;
    bytes memory txData;
    (, txHash1, txData) = TxLib.validateProof(offset + 64, _prevProof);
    bytes32 utxoId = bytes32(uint256(_outputIndex) << 120 | uint120(uint256(txHash1)));
    
    TxLib.Tx memory txn;
    if (_proof.length > 0) {
      // validate spending tx
      bytes32 txHash;
      (, txHash, txData) = TxLib.validateProof(96, _proof);
      txn = TxLib.parseTx(txData);

      // make sure one is spending the other one
      require(txHash1 == txn.ins[_inputIndex].outpoint.hash);
      require(_outputIndex == txn.ins[_inputIndex].outpoint.pos);

      // if transfer, make sure signature correct
      if (txn.txType == TxLib.TxType.Transfer) {
        bytes32 sigHash = TxLib.getSigHash(txData);
        address signer = ecrecover(
          sigHash, 
          txn.ins[_inputIndex].v, 
          txn.ins[_inputIndex].r, 
          txn.ins[_inputIndex].s
        );
        require(exits[utxoId].owner == signer);
      } else {
        revert("unknown tx type");
      }
    } else {
      // challenging deposit exit
      txn = TxLib.parseTx(txData);
      utxoId = txn.ins[_inputIndex].outpoint.hash;
      if (txn.txType == TxLib.TxType.Deposit) {
        // check that deposit was included correctly
        // only then it should be usable for challenge
        Deposit memory deposit = deposits[uint32(uint256(utxoId))];
        require(deposit.amount == txn.outs[0].value, "value mismatch");
        require(deposit.owner == txn.outs[0].owner, "owner mismatch");
        require(deposit.color == txn.outs[0].color, "color mismatch");
        // todo: check timely inclusion of deposit tx
        // this will prevent grieving attacks by the operator
      } else {
        revert("unexpected tx type");
      }
    }

    require(exits[utxoId].amount > 0, "exit not found");
    require(!exits[utxoId].finalized, "The exit has already been finalized");

    // award stake to challanger
    msg.sender.transfer(exits[utxoId].stake);
    // delete invalid exit
    delete exits[utxoId];
  }

  function challengeYoungestInput(
    bytes32[] memory _youngerInputProof,
    bytes32[] memory _exitingTxProof, 
    uint8 _outputIndex, 
    uint8 _inputIndex
  ) public {
    // validate exiting input tx
    bytes32 txHash;
    bytes memory txData;
    (, txHash, txData) = TxLib.validateProof(32 * (_youngerInputProof.length + 2) + 64, _exitingTxProof);
    bytes32 utxoId = bytes32(uint256(_outputIndex) << 120 | uint120(uint256(txHash)));

    // check the exit exists
    require(exits[utxoId].amount > 0, "There is no exit for this UTXO");

    TxLib.Tx memory exitingTx = TxLib.parseTx(txData);

    // validate younger input tx
    (,txHash,) = TxLib.validateProof(96, _youngerInputProof);
    
    // check younger input is actually an input of exiting tx
    require(txHash == exitingTx.ins[_inputIndex].outpoint.hash, "Given output is not referenced in exiting tx");
    
    uint32 youngerInputTimestamp;
    (,youngerInputTimestamp) = bridge.periods(_youngerInputProof[0]);
    require(youngerInputTimestamp > 0, "The referenced period was not submitted to bridge");

    require(exits[utxoId].priorityTimestamp < youngerInputTimestamp, "Challenged input should be older");

    // award stake to challanger
    msg.sender.transfer(exits[utxoId].stake);
    // delete invalid exit
    delete exits[utxoId];
  }

  function getNextExit(uint16 _color) internal view returns (bytes32 utxoId, uint256 exitableAt) {
    uint256 priority = tokens[_color].getMin();
    utxoId = bytes32(uint256(uint128(priority)));
    exitableAt = priority >> 192;
  }

  function isNft(uint16 _color) internal pure returns (bool) {
    return _color > 32768; // 2^15
  }

  function getERC20ExitPriority(
    uint32 timestamp, bytes32 utxoId, uint64 txPos
  ) internal view returns (uint256 priority) {
    uint256 exitableAt = Math.max(timestamp + (2 * exitDuration), block.timestamp + exitDuration);
    return (exitableAt << 192) | uint256(txPos) << 128 | uint128(uint256(utxoId));
  }

  // solium-disable-next-line mixedcase
  uint256[50] private ______gap;
}

contract FastExitHandlerMigration is ExitHandler {

  struct Data {
    uint32 timestamp;
    bytes32 txHash;
    uint64 txPos;
    bytes32 utxoId;
  }

  function deposit(address, uint256, uint16) public {
    revert("not implemented");
  }

  function startExit(bytes32[] memory, bytes32[] memory, uint8, uint8) public payable {
    revert("not implemented");
  }

  function startDepositExit(uint256) public payable {
    revert("not implemented");
  }

  function startBoughtExit(bytes32[] memory, bytes32[] memory, uint8, uint8, bytes32[] memory) public payable {
    revert("not implemented");
  }



  modifier onlyMultisig() {
    // replace this on mainnet: 
    require(msg.sender == 0xC5cDcD5470AEf35fC33BDDff3f8eCeC027F95B1d, "msg.sender not multisig");
    _;
  }

  function withdrawSupply(address _token) public onlyMultisig {
    require(_token != address(0), "not real address");
    ERC20 token = ERC20(_token);
    token.transfer(msg.sender, token.balanceOf(address(this)));
  }

}
        

Compiler Settings

{"remappings":[],"optimizer":{"runs":200,"enabled":true},"libraries":{},"evmVersion":"byzantium","compilationTarget":{"FastExitHandlerMigration.sol":"FastExitHandlerMigration"}}
              

Contract ABI

[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":""}],"name":"depositCount","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"challengeYoungestInput","inputs":[{"type":"bytes32[]","name":"_youngerInputProof"},{"type":"bytes32[]","name":"_exitingTxProof"},{"type":"uint8","name":"_outputIndex"},{"type":"uint8","name":"_inputIndex"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"exitStake","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint64","name":"time"},{"type":"uint16","name":"color"},{"type":"address","name":"owner"},{"type":"uint256","name":"amount"}],"name":"deposits","inputs":[{"type":"uint32","name":""}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"challengeExit","inputs":[{"type":"bytes32[]","name":"_proof"},{"type":"bytes32[]","name":"_prevProof"},{"type":"uint8","name":"_outputIndex"},{"type":"uint8","name":"_inputIndex"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"registerToken","inputs":[{"type":"address","name":"_token"},{"type":"bool","name":"_isERC721"}],"constant":false},{"type":"function","stateMutability":"payable","payable":true,"outputs":[],"name":"startBoughtExit","inputs":[{"type":"bytes32[]","name":""},{"type":"bytes32[]","name":""},{"type":"uint8","name":""},{"type":"uint8","name":""},{"type":"bytes32[]","name":""}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint16","name":""}],"name":"nftTokenCount","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"nftExitCounter","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"finalizeExits","inputs":[{"type":"uint16","name":"_color"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setMinGasPrice","inputs":[{"type":"uint256","name":"_minGasPrice"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"exitDuration","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setExitStake","inputs":[{"type":"uint256","name":"_exitStake"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initializeWithExit","inputs":[{"type":"address","name":"_bridge"},{"type":"uint256","name":"_exitDuration"},{"type":"uint256","name":"_exitStake"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint16","name":""}],"name":"erc20TokenCount","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"finalizeTopExit","inputs":[{"type":"uint16","name":"_color"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_bridge"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"deposit","inputs":[{"type":"address","name":""},{"type":"uint256","name":""},{"type":"uint16","name":""}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"minGasPrice","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getTokenAddr","inputs":[{"type":"uint16","name":"_color"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"bridge","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setExitDuration","inputs":[{"type":"uint256","name":"_exitDuration"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"tokenColors","inputs":[{"type":"address","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"addr"},{"type":"uint256","name":"currentSize"}],"name":"tokens","inputs":[{"type":"uint16","name":""}],"constant":true},{"type":"function","stateMutability":"payable","payable":true,"outputs":[],"name":"startDepositExit","inputs":[{"type":"uint256","name":""}],"constant":false},{"type":"function","stateMutability":"payable","payable":true,"outputs":[],"name":"startExit","inputs":[{"type":"bytes32[]","name":""},{"type":"bytes32[]","name":""},{"type":"uint8","name":""},{"type":"uint8","name":""}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"admin","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"withdrawSupply","inputs":[{"type":"address","name":"_token"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"amount"},{"type":"uint16","name":"color"},{"type":"address","name":"owner"},{"type":"bool","name":"finalized"},{"type":"uint32","name":"priorityTimestamp"},{"type":"uint256","name":"stake"}],"name":"exits","inputs":[{"type":"bytes32","name":""}],"constant":true},{"type":"event","name":"ExitStarted","inputs":[{"type":"bytes32","name":"txHash","indexed":true},{"type":"uint8","name":"outIndex","indexed":true},{"type":"uint256","name":"color","indexed":true},{"type":"address","name":"exitor","indexed":false},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"NewDeposit","inputs":[{"type":"uint32","name":"depositId","indexed":true},{"type":"address","name":"depositor","indexed":true},{"type":"uint256","name":"color","indexed":true},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"MinGasPrice","inputs":[{"type":"uint256","name":"minGasPrice","indexed":false}],"anonymous":false},{"type":"event","name":"NewToken","inputs":[{"type":"address","name":"tokenAddr","indexed":true},{"type":"uint16","name":"color","indexed":false}],"anonymous":false}]
              

Contract Creation Code

Verify & Publish
0x608060405234801561001057600080fd5b50613055806100206000396000f3fe6080604052600436106101c65760003560e060020a90048063bc48bc22116100fb578063eabd686811610099578063f6169e3511610068578063f6169e3514610a32578063f851a44014610b69578063ff293da214610b7e578063ffa696d314610bb1576101c6565b8063eabd686814610953578063eefc30831461097d578063f3c20de0146109c4578063f5239f6414610a15576101c6565b8063d2d0e066116100d5578063d2d0e0661461089c578063d96ed505146108df578063db9ed47e146108f4578063e78cea921461093e576101c6565b8063bc48bc2214610826578063c215f1be1461083b578063c4d66de814610869576101c6565b80637695d79b1161016857806390ac18661161014257806390ac18661461077e5780639eeaa7f4146107a8578063ac3d8558146107bd578063ba27a911146107e7576101c6565b80637695d79b1461070f57806378e706451461073b5780638290fe2514610750576101c6565b80635bae510d116101a45780635bae510d1461036657806365f0b9b5146103d25780636710b83f14610516578063690505a714610551576101c6565b80632dfdf0b5146101cb578063374a5435146101f95780633882f7421461033f575b600080fd5b3480156101d757600080fd5b506101e0610c1f565b6040805163ffffffff9092168252519081900360200190f35b34801561020557600080fd5b5061033d6004803603608081101561021c57600080fd5b81019060208101813564010000000081111561023757600080fd5b82018360208201111561024957600080fd5b8035906020019184602083028401116401000000008311171561026b57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156102bb57600080fd5b8201836020820111156102cd57600080fd5b803590602001918460208302840111640100000000831117156102ef57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505060ff8335811694506020909301359092169150610c2b9050565b005b34801561034b57600080fd5b50610354610f48565b60408051918252519081900360200190f35b34801561037257600080fd5b506103966004803603602081101561038957600080fd5b503563ffffffff16610f4e565b6040805167ffffffffffffffff909516855261ffff9093166020850152600160a060020a03909116838301526060830152519081900360800190f35b3480156103de57600080fd5b5061033d600480360360808110156103f557600080fd5b81019060208101813564010000000081111561041057600080fd5b82018360208201111561042257600080fd5b8035906020019184602083028401116401000000008311171561044457600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561049457600080fd5b8201836020820111156104a657600080fd5b803590602001918460208302840111640100000000831117156104c857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505060ff8335811694506020909301359092169150610f9d9050565b34801561052257600080fd5b5061033d6004803603604081101561053957600080fd5b50600160a060020a03813516906020013515156115c8565b61033d600480360360a081101561056757600080fd5b81019060208101813564010000000081111561058257600080fd5b82018360208201111561059457600080fd5b803590602001918460208302840111640100000000831117156105b657600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561060657600080fd5b82018360208201111561061857600080fd5b8035906020019184602083028401116401000000008311171561063a57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929560ff853581169660208701359091169591945092506060810191506040013564010000000081111561069d57600080fd5b8201836020820111156106af57600080fd5b803590602001918460208302840111640100000000831117156106d157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611a16945050505050565b34801561071b57600080fd5b50610724611a66565b6040805161ffff9092168252519081900360200190f35b34801561074757600080fd5b50610354611a77565b34801561075c57600080fd5b5061033d6004803603602081101561077357600080fd5b503561ffff16611a7d565b34801561078a57600080fd5b5061033d600480360360208110156107a157600080fd5b5035611f09565b3480156107b457600080fd5b50610354611f60565b3480156107c957600080fd5b5061033d600480360360208110156107e057600080fd5b5035611f66565b3480156107f357600080fd5b5061033d6004803603606081101561080a57600080fd5b50600160a060020a038135169060208101359060400135611f87565b34801561083257600080fd5b50610724612072565b34801561084757600080fd5b5061033d6004803603602081101561085e57600080fd5b503561ffff16612094565b34801561087557600080fd5b5061033d6004803603602081101561088c57600080fd5b5035600160a060020a031661209d565b3480156108a857600080fd5b5061033d600480360360608110156108bf57600080fd5b508035600160a060020a0316906020810135906040013561ffff16611a16565b3480156108eb57600080fd5b5061035461215f565b34801561090057600080fd5b506109226004803603602081101561091757600080fd5b503561ffff16612165565b60408051600160a060020a039092168252519081900360200190f35b34801561094a57600080fd5b50610922612188565b34801561095f57600080fd5b5061033d6004803603602081101561097657600080fd5b5035612197565b34801561098957600080fd5b506109b0600480360360208110156109a057600080fd5b5035600160a060020a03166121b8565b604080519115158252519081900360200190f35b3480156109d057600080fd5b506109f2600480360360208110156109e757600080fd5b503561ffff166121cd565b60408051600160a060020a03909316835260208301919091528051918290030190f35b61033d60048036036020811015610a2b57600080fd5b5035611a16565b61033d60048036036080811015610a4857600080fd5b810190602081018135640100000000811115610a6357600080fd5b820183602082011115610a7557600080fd5b80359060200191846020830284011164010000000083111715610a9757600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610ae757600080fd5b820183602082011115610af957600080fd5b80359060200191846020830284011164010000000083111715610b1b57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505060ff8335811694506020909301359092169150611a169050565b348015610b7557600080fd5b506109226121f2565b348015610b8a57600080fd5b5061033d60048036036020811015610ba157600080fd5b5035600160a060020a0316612202565b348015610bbd57600080fd5b50610bdb60048036036020811015610bd457600080fd5b50356123e1565b6040805196875261ffff9095166020870152600160a060020a0390931685850152901515606085015263ffffffff16608084015260a0830152519081900360c00190f35b60685463ffffffff1681565b60006060610c43865160020160200260400186612445565b6f0100000000000000000000000000000060ff8816026effffffffffffffffffffffffffffff831617600081815260a06020526040812054939650919450925010610cd8576040805160e560020a62461bcd02815260206004820152601e60248201527f5468657265206973206e6f206578697420666f722074686973205554584f0000604482015290519081900360640190fd5b610ce0612e42565b610ce983612587565b9050610cf6606089612445565b5060208301518051919650915060ff8716908110610d1057fe5b6020908102909101015151518414610d5c5760405160e560020a62461bcd02815260040180806020018281038252602c815260200180612fad602c913960400191505060405180910390fd5b6033548851600091600160a060020a03169063c222ef6d908b9084908110610d8057fe5b906020019060200201516040518263ffffffff1660e060020a02815260040180828152602001915050604080518083038186803b158015610dc057600080fd5b505afa158015610dd4573d6000803e3d6000fd5b505050506040513d6040811015610dea57600080fd5b50602001519050600063ffffffff821611610e395760405160e560020a62461bcd028152600401808060200182810382526031815260200180612f7c6031913960400191505060405180910390fd5b600083815260a0602052604090206001015463ffffffff808316770100000000000000000000000000000000000000000000009092041610610ec5576040805160e560020a62461bcd02815260206004820181905260248201527f4368616c6c656e67656420696e7075742073686f756c64206265206f6c646572604482015290519081900360640190fd5b600083815260a06020526040808220600201549051339282156108fc02929190818181858888f19350505050158015610f02573d6000803e3d6000fd5b505050600090815260a0602052604081208181556001810180547affffffffffffffffffffffffffffffffffffffffffffffffffffff1916905560020155505050505050565b609e5481565b606a602052600090815260409020805460019091015467ffffffffffffffff82169168010000000000000000810461ffff16916a0100000000000000000000909104600160a060020a03169084565b835160020160200260006060610fb66040840187612445565b9093509150506f0100000000000000000000000000000060ff8616026effffffffffffffffffffffffffffff831617610fed612e42565b6000895111156111f757600061100460608b612445565b95509150611013905084612587565b915081602001518760ff1681518110151561102a57fe5b602090810290910101515151851461104157600080fd5b6020820151805160ff891690811061105557fe5b602090810290910181015151015160ff89811691161461107457600080fd5b60038251600d81111561108357fe5b14156111a157600061109485612705565b9050600060018285602001518b60ff168151811015156110b057fe5b906020019060200201516060015186602001518c60ff168151811015156110d357fe5b906020019060200201516020015187602001518d60ff168151811015156110f657fe5b906020019060200201516040015160405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561115b573d6000803e3d6000fd5b505060408051601f190151600088815260a06020529190912060010154909250600160a060020a03808416620100009092041614905061119a57600080fd5b50506111f1565b6040805160e560020a62461bcd02815260206004820152600f60248201527f756e6b6e6f776e20747820747970650000000000000000000000000000000000604482015290519081900360640190fd5b50611486565b61120083612587565b905080602001518660ff1681518110151561121757fe5b602090810290910101515151915060028151600d81111561123457fe5b141561143657611242612e64565b5063ffffffff82166000908152606a602090815260408083208151608081018352815467ffffffffffffffff8116825268010000000000000000810461ffff16948201949094526a0100000000000000000000909304600160a060020a03168383015260010154606083015283015180519192909181106112bf57fe5b6020908102909101015151606082015114611324576040805160e560020a62461bcd02815260206004820152600e60248201527f76616c7565206d69736d61746368000000000000000000000000000000000000604482015290519081900360640190fd5b60408201518051600090811061133657fe5b9060200190602002015160400151600160a060020a03168160400151600160a060020a03161415156113b2576040805160e560020a62461bcd02815260206004820152600e60248201527f6f776e6572206d69736d61746368000000000000000000000000000000000000604482015290519081900360640190fd5b6040820151805160009081106113c457fe5b906020019060200201516020015161ffff16816020015161ffff161415156111f1576040805160e560020a62461bcd02815260206004820152600e60248201527f636f6c6f72206d69736d61746368000000000000000000000000000000000000604482015290519081900360640190fd5b6040805160e560020a62461bcd02815260206004820152601260248201527f756e657870656374656420747820747970650000000000000000000000000000604482015290519081900360640190fd5b600082815260a06020526040812054116114ea576040805160e560020a62461bcd02815260206004820152600e60248201527f65786974206e6f7420666f756e64000000000000000000000000000000000000604482015290519081900360640190fd5b600082815260a0602052604090206001015460b060020a900460ff16156115455760405160e560020a62461bcd028152600401808060200182810382526023815260200180612fd96023913960400191505060405180910390fd5b600082815260a06020526040808220600201549051339282156108fc02929190818181858888f19350505050158015611582573d6000803e3d6000fd5b5050600090815260a0602052604081208181556001810180547affffffffffffffffffffffffffffffffffffffffffffffffffffff191690556002015550505050505050565b6115d06128e5565b600160a060020a031633146115e457600080fd5b600160a060020a0382161515611644576040805160e560020a62461bcd02815260206004820152601d60248201527f547269656420746f207265676973746572203078302061646472657373000000604482015290519081900360640190fd5b600160a060020a03821660009081526035602052604090205460ff16156116b5576040805160e560020a62461bcd02815260206004820152601860248201527f546f6b656e20616c726561647920726567697374657265640000000000000000604482015290519081900360640190fd5b6000811561180857604080517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f80ac58cd0000000000000000000000000000000000000000000000000000000060048201529051600160a060020a038516916301ffc9a7916024808301926020929190829003018186803b15801561173c57600080fd5b505afa158015611750573d6000803e3d6000fd5b505050506040513d602081101561176657600080fd5b505115156001146117c1576040805160e560020a62461bcd02815260206004820152601360248201527f4e6f7420616e2045524337323120746f6b656e00000000000000000000000000604482015290519081900360640190fd5b506033805477ffff0000000000000000000000000000000000000000000019811660b060020a9182900461ffff908116600181019091169092021790915561800101611916565b600083600160a060020a03166318160ddd6040518163ffffffff1660e060020a02815260040160206040518083038186803b15801561184657600080fd5b505afa15801561185a573d6000803e3d6000fd5b505050506040513d602081101561187057600080fd5b505110156118c8576040805160e560020a62461bcd02815260206004820152601260248201527f4e6f7420616e20455243323020746f6b656e0000000000000000000000000000604482015290519081900360640190fd5b506033805475ffff0000000000000000000000000000000000000000198116740100000000000000000000000000000000000000009182900461ffff90811660018101909116909202179091555b60408051600180825281830190925260609160208083019080388339505050600160a060020a0385811660008181526035602090815260408083208054600160ff199091168117909155815160608101835294855284830187815285830185905261ffff8a16855260348452919093208451815473ffffffffffffffffffffffffffffffffffffffff1916961695909517855551805195965092946119c2939285019290910190612e8b565b50604091820151600290910155805161ffff841681529051600160a060020a038616917ffe74dea79bde70d1990ddb655bac45735b14f495ddc508cfab80b7729aa9d668919081900360200190a250505050565b6040805160e560020a62461bcd02815260206004820152600f60248201527f6e6f7420696d706c656d656e7465640000000000000000000000000000000000604482015290519081900360640190fd5b60335460b060020a900461ffff1681565b609f5481565b600080611a88612ed6565b611a918461290a565b61ffff861660009081526034602052604081206002015492955090935010611b03576040805160e560020a62461bcd02815260206004820152601660248201527f517565756520656d70747920666f7220636f6c6f722e00000000000000000000604482015290519081900360640190fd5b60005b6014811015611f015742831115611b205750505050611f06565b600084815260a06020818152604092839020835160c08101855281548152600182015461ffff811693820193909352620100008304600160a060020a031694810185905260b060020a830460ff16151560608201527701000000000000000000000000000000000000000000000090920463ffffffff16608083015260020154918101919091529250151580611bb65750815115155b15611ddf57611bc882602001516129f1565b15611c745760208083015161ffff166000908152603490915260408082205481850151855183517f23b872dd000000000000000000000000000000000000000000000000000000008152306004820152600160a060020a039283166024820152604481019190915292519116926323b872dd926064808201939182900301818387803b158015611c5757600080fd5b505af1158015611c6b573d6000803e3d6000fd5b50505050611dae565b60208083015161ffff1660009081526034909152604080822054845182517f095ea7b300000000000000000000000000000000000000000000000000000000815230600482015260248101919091529151600160a060020a039091169263095ea7b3926044808201939182900301818387803b158015611cf357600080fd5b505af1158015611d07573d6000803e3d6000fd5b5050505060208281015161ffff166000908152603490915260408082205481850151855183517f23b872dd000000000000000000000000000000000000000000000000000000008152306004820152600160a060020a039283166024820152604481019190915292519116926323b872dd926064808201939182900301818387803b158015611d9557600080fd5b505af1158015611da9573d6000803e3d6000fd5b505050505b8160400151600160a060020a03166108fc8360a001519081150290604051600060405180830381858888f150505050505b60208083015161ffff1660009081526034825260409081902081517f09cbc02000000000000000000000000000000000000000000000000000000000815260048101919091529051732c84bbdc7b9202949b7fbb0db29153190f23d1a5926309cbc0209260248082019391829003018186803b158015611e5e57600080fd5b505af4158015611e72573d6000803e3d6000fd5b505050506040513d6020811015611e8857600080fd5b5050600084815260a060209081526040808320600101805476ff00000000000000000000000000000000000000000000191660b060020a1790558482015161ffff16835260349091528120600201541115611ef057611ee68561290a565b9094509250611ef9565b50505050611f06565b600101611b06565b505050505b50565b611f116128e5565b600160a060020a03163314611f2557600080fd5b60698190556040805182815290517f85feea100eda69e1c4fe1b228ed4d7229f3e9e9ebf7d30893d71de8165c46abb9181900360200190a150565b609d5481565b611f6e6128e5565b600160a060020a03163314611f8257600080fd5b609e55565b600054610100900460ff1680611fa05750611fa06129ff565b80611fae575060005460ff16155b1515611fee5760405160e560020a62461bcd02815260040180806020018281038252602e815260200180612ffc602e913960400191505060405180910390fd5b60008054600161010061ff00198316811760ff1916919091179092550460ff166120178461209d565b609d839055609e829055604080516000815290517f85feea100eda69e1c4fe1b228ed4d7229f3e9e9ebf7d30893d71de8165c46abb9181900360200190a1600080549115156101000261ff0019909216919091179055505050565b60335474010000000000000000000000000000000000000000900461ffff1681565b611f0681611a7d565b600054610100900460ff16806120b657506120b66129ff565b806120c4575060005460ff16155b15156121045760405160e560020a62461bcd02815260040180806020018281038252602e815260200180612ffc602e913960400191505060405180910390fd5b600080546033805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03949094169390931790925561ff001980831661010090811760ff19166001179091169281900460ff16151502919091179055565b60695481565b61ffff8116600090815260346020526040902054600160a060020a03165b919050565b603354600160a060020a031681565b61219f6128e5565b600160a060020a031633146121b357600080fd5b609d55565b60356020526000908152604090205460ff1681565b60346020526000908152604090208054600290910154600160a060020a039091169082565b60006121fc6128e5565b90505b90565b73c5cdcd5470aef35fc33bddff3f8ecec027f95b1d331461226d576040805160e560020a62461bcd02815260206004820152601760248201527f6d73672e73656e646572206e6f74206d756c7469736967000000000000000000604482015290519081900360640190fd5b600160a060020a03811615156122cd576040805160e560020a62461bcd02815260206004820152601060248201527f6e6f74207265616c206164647265737300000000000000000000000000000000604482015290519081900360640190fd5b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290518291600160a060020a0383169163a9059cbb91339184916370a08231916024808301926020929190829003018186803b15801561233857600080fd5b505afa15801561234c573d6000803e3d6000fd5b505050506040513d602081101561236257600080fd5b50516040805160e060020a63ffffffff8616028152600160a060020a03909316600484015260248301919091525160448083019260209291908290030181600087803b1580156123b157600080fd5b505af11580156123c5573d6000803e3d6000fd5b505050506040513d60208110156123db57600080fd5b50505050565b60a060205260009081526040902080546001820154600290920154909161ffff811691620100008204600160a060020a03169160b060020a810460ff16917701000000000000000000000000000000000000000000000090910463ffffffff169086565b6000806060600060f885600181518110151561245d57fe5b90602001906020020151908060020a82049150506001900460ff169050600060e086600181518110151561248d57fe5b90602001906020020151908060020a82049150506001900461ffff169050806040519080825280601f01601f1916602001820160405280156124d6576020820181803883390190505b5092508087830160440160208501378280519060200120935060a086600181518110151561250057fe5b90602001906020020151908060020a82049150506001900494506000612557858767ffffffffffffffff1660f08a600181518110151561253c57fe5b6020908102909101015160ff60029290920a9004168a612a05565b905086600081518110151561256857fe5b60209081029091010151811461257d57600080fd5b5050509250925092565b61258f612e42565b602082015160009060f860020a900460028114156125b057600291506125d0565b80600314156125c257600391506125d0565b80600d14156111a157600d91505b506021830151604080517f100000000000000000000000000000000000000000000000000000000000000090920480835260208082028401019091529060609082801561263757816020015b612624612f0b565b81526020019060019003908161261c5790505b509050600260005b825181101561265f576126558588838587612a74565b915060010161263f565b5060218601516040805160f860020a909204600f16808352602080820284010190915293506060908480156126ae57816020015b61269b612e64565b8152602001906001900390816126935790505b50905060005b81518110156126d3576126c988828585612c73565b92506001016126b4565b5060606040519081016040528086600d8111156126ec57fe5b8152602081019490945260409093015250949350505050565b602081015160009060f860020a90046003811461272157600080fd5b506021820151825160408051828152601f19601f84011681016020019091527f100000000000000000000000000000000000000000000000000000000000000090920491606091801561277b576020820181803883390190505b509050602084015160001a6020820153602084015160011a60218201536000805b838110156127cf578582016022818101518585019182015260429182015160001a9101536062919091019060010161279c565b50806022015b85516040018110156127f15785810151838201526020016127d5565b50506127fd8451612ced565b8160405160200180807f19457468657265756d205369676e6564204d6573736167653a0a000000000000815250601a0183805190602001908083835b602083106128585780518252601f199092019160209182019101612839565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b602083106128a05780518252601f199092019160209182019101612881565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040528051906020012092505050919050565b7f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b5490565b61ffff8116600090815260346020908152604080832081517f2e5f2ace0000000000000000000000000000000000000000000000000000000081526004810191909152905183928392732c84bbdc7b9202949b7fbb0db29153190f23d1a592632e5f2ace92602480840193919291829003018186803b15801561298c57600080fd5b505af41580156129a0573d6000803e3d6000fd5b505050506040513d60208110156129b657600080fd5b50516fffffffffffffffffffffffffffffffff8116957801000000000000000000000000000000000000000000000000909104945092505050565b61800061ffff821611919050565b303b1590565b600080835b8351811015612a69578381815181101515612a2157fe5b602090810290910101519150600286061515612a4b57866000528160205260406000209650612a5b565b8160005286602052604060002096505b600286049550600101612a0a565b509495945050505050565b60008080600288600d811115612a8657fe5b1415612aa85750505060048483018101519083019063ffffffff166000612abe565b5050508184016020810151602191820151918401915b612ac6612f4a565b5060408051808201825283815260ff831660208083019190915282516000815290810190925290612af5612f0b565b506040805160c08101825283815260006020820181905291810182905260608101919091526080810182905260a08101829052600d8b600d811115612b3657fe5b1415612c0a57878a01602301516040805161ffff8316808252601f19601f8201168201602001909252908015612b73576020820181803883390190505b509250888b0160430160208401612b8f828261ffff8616612de9565b848460a001819052508261ffff168b6025010198508c89015192508261ffff166040519080825280601f01601f191660200182016040528015612bd9576020820181803883390190505b5094505060208c8901810191508401612bf7828261ffff8616612de9565b50506080820183905261ffff1695909501945b60038b600d811115612c1857fe5b1415612c4b57878a01604181015160618201516062928301516020850192909252604084015260ff166060830152880195505b80878a815181101515612c5a57fe5b6020908102909101015250939998505050505050505050565b8184016020810151602282015160369092015160009290612c92612e64565b506040805160808101825284815261ffff84166020820152600160a060020a03831691810191909152600060608201528551819087908a908110612cd257fe5b60209081029091010152505060369094019695505050505050565b6060811515612d30575060408051808201909152600181527f30000000000000000000000000000000000000000000000000000000000000006020820152612183565b8160005b8115612d4857600101600a82049150612d34565b6060816040519080825280601f01601f191660200182016040528015612d75576020820181803883390190505b50905060001982015b8515612de057815160001982019160f860020a6030600a8a060102918491908110612da557fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a86049550612d7e565b50949350505050565b600060208204815b81811015612e0f576020810286810151868201529250600101612df1565b506020908102938401805195909401516008601f9094169091039290920260020a60000391821691199390931617905250565b6040805160608101909152806000815260200160608152602001606081525090565b60408051608081018252600080825260208201819052918101829052606081019190915290565b828054828255906000526020600020908101928215612ec6579160200282015b82811115612ec6578251825591602001919060010190612eab565b50612ed2929150612f61565b5090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60e060405190810160405280612f1f612f4a565b8152600060208201819052604082018190526060808301919091526080820181905260a09091015290565b604080518082019091526000808252602082015290565b6121ff91905b80821115612ed25760008155600101612f6756fe546865207265666572656e63656420706572696f6420776173206e6f74207375626d697474656420746f20627269646765476976656e206f7574707574206973206e6f74207265666572656e63656420696e2065786974696e6720747854686520657869742068617320616c7265616479206265656e2066696e616c697a6564436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564a165627a7a723058203b95f5a4944122e81b6e1d53b8f7798764d3c6402db0df21ae37ec0c995ec0ad0029

Deployed ByteCode

0x6080604052600436106101c65760003560e060020a90048063bc48bc22116100fb578063eabd686811610099578063f6169e3511610068578063f6169e3514610a32578063f851a44014610b69578063ff293da214610b7e578063ffa696d314610bb1576101c6565b8063eabd686814610953578063eefc30831461097d578063f3c20de0146109c4578063f5239f6414610a15576101c6565b8063d2d0e066116100d5578063d2d0e0661461089c578063d96ed505146108df578063db9ed47e146108f4578063e78cea921461093e576101c6565b8063bc48bc2214610826578063c215f1be1461083b578063c4d66de814610869576101c6565b80637695d79b1161016857806390ac18661161014257806390ac18661461077e5780639eeaa7f4146107a8578063ac3d8558146107bd578063ba27a911146107e7576101c6565b80637695d79b1461070f57806378e706451461073b5780638290fe2514610750576101c6565b80635bae510d116101a45780635bae510d1461036657806365f0b9b5146103d25780636710b83f14610516578063690505a714610551576101c6565b80632dfdf0b5146101cb578063374a5435146101f95780633882f7421461033f575b600080fd5b3480156101d757600080fd5b506101e0610c1f565b6040805163ffffffff9092168252519081900360200190f35b34801561020557600080fd5b5061033d6004803603608081101561021c57600080fd5b81019060208101813564010000000081111561023757600080fd5b82018360208201111561024957600080fd5b8035906020019184602083028401116401000000008311171561026b57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156102bb57600080fd5b8201836020820111156102cd57600080fd5b803590602001918460208302840111640100000000831117156102ef57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505060ff8335811694506020909301359092169150610c2b9050565b005b34801561034b57600080fd5b50610354610f48565b60408051918252519081900360200190f35b34801561037257600080fd5b506103966004803603602081101561038957600080fd5b503563ffffffff16610f4e565b6040805167ffffffffffffffff909516855261ffff9093166020850152600160a060020a03909116838301526060830152519081900360800190f35b3480156103de57600080fd5b5061033d600480360360808110156103f557600080fd5b81019060208101813564010000000081111561041057600080fd5b82018360208201111561042257600080fd5b8035906020019184602083028401116401000000008311171561044457600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561049457600080fd5b8201836020820111156104a657600080fd5b803590602001918460208302840111640100000000831117156104c857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505060ff8335811694506020909301359092169150610f9d9050565b34801561052257600080fd5b5061033d6004803603604081101561053957600080fd5b50600160a060020a03813516906020013515156115c8565b61033d600480360360a081101561056757600080fd5b81019060208101813564010000000081111561058257600080fd5b82018360208201111561059457600080fd5b803590602001918460208302840111640100000000831117156105b657600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561060657600080fd5b82018360208201111561061857600080fd5b8035906020019184602083028401116401000000008311171561063a57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929560ff853581169660208701359091169591945092506060810191506040013564010000000081111561069d57600080fd5b8201836020820111156106af57600080fd5b803590602001918460208302840111640100000000831117156106d157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611a16945050505050565b34801561071b57600080fd5b50610724611a66565b6040805161ffff9092168252519081900360200190f35b34801561074757600080fd5b50610354611a77565b34801561075c57600080fd5b5061033d6004803603602081101561077357600080fd5b503561ffff16611a7d565b34801561078a57600080fd5b5061033d600480360360208110156107a157600080fd5b5035611f09565b3480156107b457600080fd5b50610354611f60565b3480156107c957600080fd5b5061033d600480360360208110156107e057600080fd5b5035611f66565b3480156107f357600080fd5b5061033d6004803603606081101561080a57600080fd5b50600160a060020a038135169060208101359060400135611f87565b34801561083257600080fd5b50610724612072565b34801561084757600080fd5b5061033d6004803603602081101561085e57600080fd5b503561ffff16612094565b34801561087557600080fd5b5061033d6004803603602081101561088c57600080fd5b5035600160a060020a031661209d565b3480156108a857600080fd5b5061033d600480360360608110156108bf57600080fd5b508035600160a060020a0316906020810135906040013561ffff16611a16565b3480156108eb57600080fd5b5061035461215f565b34801561090057600080fd5b506109226004803603602081101561091757600080fd5b503561ffff16612165565b60408051600160a060020a039092168252519081900360200190f35b34801561094a57600080fd5b50610922612188565b34801561095f57600080fd5b5061033d6004803603602081101561097657600080fd5b5035612197565b34801561098957600080fd5b506109b0600480360360208110156109a057600080fd5b5035600160a060020a03166121b8565b604080519115158252519081900360200190f35b3480156109d057600080fd5b506109f2600480360360208110156109e757600080fd5b503561ffff166121cd565b60408051600160a060020a03909316835260208301919091528051918290030190f35b61033d60048036036020811015610a2b57600080fd5b5035611a16565b61033d60048036036080811015610a4857600080fd5b810190602081018135640100000000811115610a6357600080fd5b820183602082011115610a7557600080fd5b80359060200191846020830284011164010000000083111715610a9757600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610ae757600080fd5b820183602082011115610af957600080fd5b80359060200191846020830284011164010000000083111715610b1b57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505060ff8335811694506020909301359092169150611a169050565b348015610b7557600080fd5b506109226121f2565b348015610b8a57600080fd5b5061033d60048036036020811015610ba157600080fd5b5035600160a060020a0316612202565b348015610bbd57600080fd5b50610bdb60048036036020811015610bd457600080fd5b50356123e1565b6040805196875261ffff9095166020870152600160a060020a0390931685850152901515606085015263ffffffff16608084015260a0830152519081900360c00190f35b60685463ffffffff1681565b60006060610c43865160020160200260400186612445565b6f0100000000000000000000000000000060ff8816026effffffffffffffffffffffffffffff831617600081815260a06020526040812054939650919450925010610cd8576040805160e560020a62461bcd02815260206004820152601e60248201527f5468657265206973206e6f206578697420666f722074686973205554584f0000604482015290519081900360640190fd5b610ce0612e42565b610ce983612587565b9050610cf6606089612445565b5060208301518051919650915060ff8716908110610d1057fe5b6020908102909101015151518414610d5c5760405160e560020a62461bcd02815260040180806020018281038252602c815260200180612fad602c913960400191505060405180910390fd5b6033548851600091600160a060020a03169063c222ef6d908b9084908110610d8057fe5b906020019060200201516040518263ffffffff1660e060020a02815260040180828152602001915050604080518083038186803b158015610dc057600080fd5b505afa158015610dd4573d6000803e3d6000fd5b505050506040513d6040811015610dea57600080fd5b50602001519050600063ffffffff821611610e395760405160e560020a62461bcd028152600401808060200182810382526031815260200180612f7c6031913960400191505060405180910390fd5b600083815260a0602052604090206001015463ffffffff808316770100000000000000000000000000000000000000000000009092041610610ec5576040805160e560020a62461bcd02815260206004820181905260248201527f4368616c6c656e67656420696e7075742073686f756c64206265206f6c646572604482015290519081900360640190fd5b600083815260a06020526040808220600201549051339282156108fc02929190818181858888f19350505050158015610f02573d6000803e3d6000fd5b505050600090815260a0602052604081208181556001810180547affffffffffffffffffffffffffffffffffffffffffffffffffffff1916905560020155505050505050565b609e5481565b606a602052600090815260409020805460019091015467ffffffffffffffff82169168010000000000000000810461ffff16916a0100000000000000000000909104600160a060020a03169084565b835160020160200260006060610fb66040840187612445565b9093509150506f0100000000000000000000000000000060ff8616026effffffffffffffffffffffffffffff831617610fed612e42565b6000895111156111f757600061100460608b612445565b95509150611013905084612587565b915081602001518760ff1681518110151561102a57fe5b602090810290910101515151851461104157600080fd5b6020820151805160ff891690811061105557fe5b602090810290910181015151015160ff89811691161461107457600080fd5b60038251600d81111561108357fe5b14156111a157600061109485612705565b9050600060018285602001518b60ff168151811015156110b057fe5b906020019060200201516060015186602001518c60ff168151811015156110d357fe5b906020019060200201516020015187602001518d60ff168151811015156110f657fe5b906020019060200201516040015160405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561115b573d6000803e3d6000fd5b505060408051601f190151600088815260a06020529190912060010154909250600160a060020a03808416620100009092041614905061119a57600080fd5b50506111f1565b6040805160e560020a62461bcd02815260206004820152600f60248201527f756e6b6e6f776e20747820747970650000000000000000000000000000000000604482015290519081900360640190fd5b50611486565b61120083612587565b905080602001518660ff1681518110151561121757fe5b602090810290910101515151915060028151600d81111561123457fe5b141561143657611242612e64565b5063ffffffff82166000908152606a602090815260408083208151608081018352815467ffffffffffffffff8116825268010000000000000000810461ffff16948201949094526a0100000000000000000000909304600160a060020a03168383015260010154606083015283015180519192909181106112bf57fe5b6020908102909101015151606082015114611324576040805160e560020a62461bcd02815260206004820152600e60248201527f76616c7565206d69736d61746368000000000000000000000000000000000000604482015290519081900360640190fd5b60408201518051600090811061133657fe5b9060200190602002015160400151600160a060020a03168160400151600160a060020a03161415156113b2576040805160e560020a62461bcd02815260206004820152600e60248201527f6f776e6572206d69736d61746368000000000000000000000000000000000000604482015290519081900360640190fd5b6040820151805160009081106113c457fe5b906020019060200201516020015161ffff16816020015161ffff161415156111f1576040805160e560020a62461bcd02815260206004820152600e60248201527f636f6c6f72206d69736d61746368000000000000000000000000000000000000604482015290519081900360640190fd5b6040805160e560020a62461bcd02815260206004820152601260248201527f756e657870656374656420747820747970650000000000000000000000000000604482015290519081900360640190fd5b600082815260a06020526040812054116114ea576040805160e560020a62461bcd02815260206004820152600e60248201527f65786974206e6f7420666f756e64000000000000000000000000000000000000604482015290519081900360640190fd5b600082815260a0602052604090206001015460b060020a900460ff16156115455760405160e560020a62461bcd028152600401808060200182810382526023815260200180612fd96023913960400191505060405180910390fd5b600082815260a06020526040808220600201549051339282156108fc02929190818181858888f19350505050158015611582573d6000803e3d6000fd5b5050600090815260a0602052604081208181556001810180547affffffffffffffffffffffffffffffffffffffffffffffffffffff191690556002015550505050505050565b6115d06128e5565b600160a060020a031633146115e457600080fd5b600160a060020a0382161515611644576040805160e560020a62461bcd02815260206004820152601d60248201527f547269656420746f207265676973746572203078302061646472657373000000604482015290519081900360640190fd5b600160a060020a03821660009081526035602052604090205460ff16156116b5576040805160e560020a62461bcd02815260206004820152601860248201527f546f6b656e20616c726561647920726567697374657265640000000000000000604482015290519081900360640190fd5b6000811561180857604080517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f80ac58cd0000000000000000000000000000000000000000000000000000000060048201529051600160a060020a038516916301ffc9a7916024808301926020929190829003018186803b15801561173c57600080fd5b505afa158015611750573d6000803e3d6000fd5b505050506040513d602081101561176657600080fd5b505115156001146117c1576040805160e560020a62461bcd02815260206004820152601360248201527f4e6f7420616e2045524337323120746f6b656e00000000000000000000000000604482015290519081900360640190fd5b506033805477ffff0000000000000000000000000000000000000000000019811660b060020a9182900461ffff908116600181019091169092021790915561800101611916565b600083600160a060020a03166318160ddd6040518163ffffffff1660e060020a02815260040160206040518083038186803b15801561184657600080fd5b505afa15801561185a573d6000803e3d6000fd5b505050506040513d602081101561187057600080fd5b505110156118c8576040805160e560020a62461bcd02815260206004820152601260248201527f4e6f7420616e20455243323020746f6b656e0000000000000000000000000000604482015290519081900360640190fd5b506033805475ffff0000000000000000000000000000000000000000198116740100000000000000000000000000000000000000009182900461ffff90811660018101909116909202179091555b60408051600180825281830190925260609160208083019080388339505050600160a060020a0385811660008181526035602090815260408083208054600160ff199091168117909155815160608101835294855284830187815285830185905261ffff8a16855260348452919093208451815473ffffffffffffffffffffffffffffffffffffffff1916961695909517855551805195965092946119c2939285019290910190612e8b565b50604091820151600290910155805161ffff841681529051600160a060020a038616917ffe74dea79bde70d1990ddb655bac45735b14f495ddc508cfab80b7729aa9d668919081900360200190a250505050565b6040805160e560020a62461bcd02815260206004820152600f60248201527f6e6f7420696d706c656d656e7465640000000000000000000000000000000000604482015290519081900360640190fd5b60335460b060020a900461ffff1681565b609f5481565b600080611a88612ed6565b611a918461290a565b61ffff861660009081526034602052604081206002015492955090935010611b03576040805160e560020a62461bcd02815260206004820152601660248201527f517565756520656d70747920666f7220636f6c6f722e00000000000000000000604482015290519081900360640190fd5b60005b6014811015611f015742831115611b205750505050611f06565b600084815260a06020818152604092839020835160c08101855281548152600182015461ffff811693820193909352620100008304600160a060020a031694810185905260b060020a830460ff16151560608201527701000000000000000000000000000000000000000000000090920463ffffffff16608083015260020154918101919091529250151580611bb65750815115155b15611ddf57611bc882602001516129f1565b15611c745760208083015161ffff166000908152603490915260408082205481850151855183517f23b872dd000000000000000000000000000000000000000000000000000000008152306004820152600160a060020a039283166024820152604481019190915292519116926323b872dd926064808201939182900301818387803b158015611c5757600080fd5b505af1158015611c6b573d6000803e3d6000fd5b50505050611dae565b60208083015161ffff1660009081526034909152604080822054845182517f095ea7b300000000000000000000000000000000000000000000000000000000815230600482015260248101919091529151600160a060020a039091169263095ea7b3926044808201939182900301818387803b158015611cf357600080fd5b505af1158015611d07573d6000803e3d6000fd5b5050505060208281015161ffff166000908152603490915260408082205481850151855183517f23b872dd000000000000000000000000000000000000000000000000000000008152306004820152600160a060020a039283166024820152604481019190915292519116926323b872dd926064808201939182900301818387803b158015611d9557600080fd5b505af1158015611da9573d6000803e3d6000fd5b505050505b8160400151600160a060020a03166108fc8360a001519081150290604051600060405180830381858888f150505050505b60208083015161ffff1660009081526034825260409081902081517f09cbc02000000000000000000000000000000000000000000000000000000000815260048101919091529051732c84bbdc7b9202949b7fbb0db29153190f23d1a5926309cbc0209260248082019391829003018186803b158015611e5e57600080fd5b505af4158015611e72573d6000803e3d6000fd5b505050506040513d6020811015611e8857600080fd5b5050600084815260a060209081526040808320600101805476ff00000000000000000000000000000000000000000000191660b060020a1790558482015161ffff16835260349091528120600201541115611ef057611ee68561290a565b9094509250611ef9565b50505050611f06565b600101611b06565b505050505b50565b611f116128e5565b600160a060020a03163314611f2557600080fd5b60698190556040805182815290517f85feea100eda69e1c4fe1b228ed4d7229f3e9e9ebf7d30893d71de8165c46abb9181900360200190a150565b609d5481565b611f6e6128e5565b600160a060020a03163314611f8257600080fd5b609e55565b600054610100900460ff1680611fa05750611fa06129ff565b80611fae575060005460ff16155b1515611fee5760405160e560020a62461bcd02815260040180806020018281038252602e815260200180612ffc602e913960400191505060405180910390fd5b60008054600161010061ff00198316811760ff1916919091179092550460ff166120178461209d565b609d839055609e829055604080516000815290517f85feea100eda69e1c4fe1b228ed4d7229f3e9e9ebf7d30893d71de8165c46abb9181900360200190a1600080549115156101000261ff0019909216919091179055505050565b60335474010000000000000000000000000000000000000000900461ffff1681565b611f0681611a7d565b600054610100900460ff16806120b657506120b66129ff565b806120c4575060005460ff16155b15156121045760405160e560020a62461bcd02815260040180806020018281038252602e815260200180612ffc602e913960400191505060405180910390fd5b600080546033805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03949094169390931790925561ff001980831661010090811760ff19166001179091169281900460ff16151502919091179055565b60695481565b61ffff8116600090815260346020526040902054600160a060020a03165b919050565b603354600160a060020a031681565b61219f6128e5565b600160a060020a031633146121b357600080fd5b609d55565b60356020526000908152604090205460ff1681565b60346020526000908152604090208054600290910154600160a060020a039091169082565b60006121fc6128e5565b90505b90565b73c5cdcd5470aef35fc33bddff3f8ecec027f95b1d331461226d576040805160e560020a62461bcd02815260206004820152601760248201527f6d73672e73656e646572206e6f74206d756c7469736967000000000000000000604482015290519081900360640190fd5b600160a060020a03811615156122cd576040805160e560020a62461bcd02815260206004820152601060248201527f6e6f74207265616c206164647265737300000000000000000000000000000000604482015290519081900360640190fd5b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290518291600160a060020a0383169163a9059cbb91339184916370a08231916024808301926020929190829003018186803b15801561233857600080fd5b505afa15801561234c573d6000803e3d6000fd5b505050506040513d602081101561236257600080fd5b50516040805160e060020a63ffffffff8616028152600160a060020a03909316600484015260248301919091525160448083019260209291908290030181600087803b1580156123b157600080fd5b505af11580156123c5573d6000803e3d6000fd5b505050506040513d60208110156123db57600080fd5b50505050565b60a060205260009081526040902080546001820154600290920154909161ffff811691620100008204600160a060020a03169160b060020a810460ff16917701000000000000000000000000000000000000000000000090910463ffffffff169086565b6000806060600060f885600181518110151561245d57fe5b90602001906020020151908060020a82049150506001900460ff169050600060e086600181518110151561248d57fe5b90602001906020020151908060020a82049150506001900461ffff169050806040519080825280601f01601f1916602001820160405280156124d6576020820181803883390190505b5092508087830160440160208501378280519060200120935060a086600181518110151561250057fe5b90602001906020020151908060020a82049150506001900494506000612557858767ffffffffffffffff1660f08a600181518110151561253c57fe5b6020908102909101015160ff60029290920a9004168a612a05565b905086600081518110151561256857fe5b60209081029091010151811461257d57600080fd5b5050509250925092565b61258f612e42565b602082015160009060f860020a900460028114156125b057600291506125d0565b80600314156125c257600391506125d0565b80600d14156111a157600d91505b506021830151604080517f100000000000000000000000000000000000000000000000000000000000000090920480835260208082028401019091529060609082801561263757816020015b612624612f0b565b81526020019060019003908161261c5790505b509050600260005b825181101561265f576126558588838587612a74565b915060010161263f565b5060218601516040805160f860020a909204600f16808352602080820284010190915293506060908480156126ae57816020015b61269b612e64565b8152602001906001900390816126935790505b50905060005b81518110156126d3576126c988828585612c73565b92506001016126b4565b5060606040519081016040528086600d8111156126ec57fe5b8152602081019490945260409093015250949350505050565b602081015160009060f860020a90046003811461272157600080fd5b506021820151825160408051828152601f19601f84011681016020019091527f100000000000000000000000000000000000000000000000000000000000000090920491606091801561277b576020820181803883390190505b509050602084015160001a6020820153602084015160011a60218201536000805b838110156127cf578582016022818101518585019182015260429182015160001a9101536062919091019060010161279c565b50806022015b85516040018110156127f15785810151838201526020016127d5565b50506127fd8451612ced565b8160405160200180807f19457468657265756d205369676e6564204d6573736167653a0a000000000000815250601a0183805190602001908083835b602083106128585780518252601f199092019160209182019101612839565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b602083106128a05780518252601f199092019160209182019101612881565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040528051906020012092505050919050565b7f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b5490565b61ffff8116600090815260346020908152604080832081517f2e5f2ace0000000000000000000000000000000000000000000000000000000081526004810191909152905183928392732c84bbdc7b9202949b7fbb0db29153190f23d1a592632e5f2ace92602480840193919291829003018186803b15801561298c57600080fd5b505af41580156129a0573d6000803e3d6000fd5b505050506040513d60208110156129b657600080fd5b50516fffffffffffffffffffffffffffffffff8116957801000000000000000000000000000000000000000000000000909104945092505050565b61800061ffff821611919050565b303b1590565b600080835b8351811015612a69578381815181101515612a2157fe5b602090810290910101519150600286061515612a4b57866000528160205260406000209650612a5b565b8160005286602052604060002096505b600286049550600101612a0a565b509495945050505050565b60008080600288600d811115612a8657fe5b1415612aa85750505060048483018101519083019063ffffffff166000612abe565b5050508184016020810151602191820151918401915b612ac6612f4a565b5060408051808201825283815260ff831660208083019190915282516000815290810190925290612af5612f0b565b506040805160c08101825283815260006020820181905291810182905260608101919091526080810182905260a08101829052600d8b600d811115612b3657fe5b1415612c0a57878a01602301516040805161ffff8316808252601f19601f8201168201602001909252908015612b73576020820181803883390190505b509250888b0160430160208401612b8f828261ffff8616612de9565b848460a001819052508261ffff168b6025010198508c89015192508261ffff166040519080825280601f01601f191660200182016040528015612bd9576020820181803883390190505b5094505060208c8901810191508401612bf7828261ffff8616612de9565b50506080820183905261ffff1695909501945b60038b600d811115612c1857fe5b1415612c4b57878a01604181015160618201516062928301516020850192909252604084015260ff166060830152880195505b80878a815181101515612c5a57fe5b6020908102909101015250939998505050505050505050565b8184016020810151602282015160369092015160009290612c92612e64565b506040805160808101825284815261ffff84166020820152600160a060020a03831691810191909152600060608201528551819087908a908110612cd257fe5b60209081029091010152505060369094019695505050505050565b6060811515612d30575060408051808201909152600181527f30000000000000000000000000000000000000000000000000000000000000006020820152612183565b8160005b8115612d4857600101600a82049150612d34565b6060816040519080825280601f01601f191660200182016040528015612d75576020820181803883390190505b50905060001982015b8515612de057815160001982019160f860020a6030600a8a060102918491908110612da557fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a86049550612d7e565b50949350505050565b600060208204815b81811015612e0f576020810286810151868201529250600101612df1565b506020908102938401805195909401516008601f9094169091039290920260020a60000391821691199390931617905250565b6040805160608101909152806000815260200160608152602001606081525090565b60408051608081018252600080825260208201819052918101829052606081019190915290565b828054828255906000526020600020908101928215612ec6579160200282015b82811115612ec6578251825591602001919060010190612eab565b50612ed2929150612f61565b5090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60e060405190810160405280612f1f612f4a565b8152600060208201819052604082018190526060808301919091526080820181905260a09091015290565b604080518082019091526000808252602082015290565b6121ff91905b80821115612ed25760008155600101612f6756fe546865207265666572656e63656420706572696f6420776173206e6f74207375626d697474656420746f20627269646765476976656e206f7574707574206973206e6f74207265666572656e63656420696e2065786974696e6720747854686520657869742068617320616c7265616479206265656e2066696e616c697a6564436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564a165627a7a723058203b95f5a4944122e81b6e1d53b8f7798764d3c6402db0df21ae37ec0c995ec0ad0029