Contract 0xf1c525a488a848b58b95d79da48c21ce434290f7

 

Contract Overview

Balance:
0.014793499743762032 Ether

EtherValue:
$1.84 (@ $124.30/ETH)
TxHash Block Age From To Value [TxFee]
0x16045a95d6df67b3c8b14dafe45e5aa491fe8d3573c648269cd61ad0331197b672307111 hr ago0x8725e59eef18409273fa50662e7c1b671e368a86  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.0029324372
0xa29b111f95e50c1f1695eabac284d27c819ee033d683480552666ff7141812cf72306891 hr 8 mins ago0x525bfbe25506495452c89d930d1fc0118292563b  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.0047955985
0x10682d3296a600a1c6f45e7d3bee7caebee6eb03795ad8b5e1d1f3c77aecb73872298745 hrs 50 mins ago0x0fea10885ce6d3db6951582685f9659ffd7003c9  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.004359635
0xaba2f3bcacbc834d640c4b580ff01f2254d153057e27ac59278ff50571624b6672297956 hrs 20 mins ago0x8725e59eef18409273fa50662e7c1b671e368a86  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.0054210114
0xe8e6d234b71613ab5e64b5ae5fbc1798c394e1f3f04e161c3202750b0949100672296157 hrs 17 mins ago0xd25fc802b86de224cc68b628fef142c68e1a435f  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.003114025
0x681bcb88924a4cde7414a63e399c0105f29e6af34c21170a4b3c746ae04b435a722887711 hrs 25 mins ago0x5b2acbda2f4c66a97aea0e217c59e10c790eb981  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.005605245
0xcb391566f77eed5679d0cdf9181a9f8181c921f05530f252adae465743fbd7be722886611 hrs 29 mins ago0xb9e1767c6910768c099d24048582fbeb76ab437f  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.005605245
0x8b4b4c6bd1a5cfa43335455a7ac390bbf430ca06652f5905b9cade8879f288b3722869612 hrs 25 mins ago0xe7206577b2ef560e020933e7e9f49912a31f80ad  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.00622805
0x75931153cbe0161da03c7f704c368b25dbb6a6e6b88cca7f6ad9ca12128fd842722865112 hrs 44 mins ago0xa0d82615ea0e5392eb5d3590fb4cdcb27f5824b9  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.00622805
0x57249a03bae0cdc30012dfbe3e01db25792ba5a15fa0b6dec3d653982b0ac211722827414 hrs 51 mins ago0x453dbe277d96840041eddee45ed762c84d9220d4  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.006850151
0x7cc0ff122bb218e11dff3a7eeb48c9419ec41c0f6bdf844f5ae8d47c6f724a0a722795616 hrs 41 mins ago0x9927eeab6c92d23e44975b0ad9583c4401c311af  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.00622805
0x02ecbec0dd21bbe996edcf11fc84fb24766390e302b085a1d862636e4dfa7761722791416 hrs 55 mins ago0xa311c665d1e1340c9a694e93870719b531624e4c  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.00622805
0xad9eb38e33207661b74354f5b4860f4f032c6020598ba7796600f79413f2c57a722790916 hrs 57 mins ago0xaa1f701f02ae27c5b3f178ad1f221450589aeeab  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.00622805
0xa8845a36bb60eb8371270b5ccb69bfee1d87be61d478b30a4c4daf31c278d85d722769818 hrs 12 mins ago0xa52fd887dfede09e54e866a841da397cf83bd5a8  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.00498244
0x802926147ad7b64a94cfbcbf789abe18f277b67c1814458377d65a68e25385ad722746619 hrs 21 mins ago0x9db9cef0a0ef1178e607060d588d67b59a7e215d  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.005605245
0x6672162bf9bdb1362bdfcfc46d1033a1c5cdd6a4b2ef0b2a329975d15728f87b722730120 hrs 19 mins ago0x8725e59eef18409273fa50662e7c1b671e368a86  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.00342756
0x83b8cbf80c635b8a3c1f5f109cc9e43f1764ba9394ebeb7363f8ec6691462e42722714421 hrs 15 mins ago0x66c33fa5a4c8a8945e7c372f185fbd3473c717d8  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.00498244
0x5d19416862c0d661be85e072bb7f98e10343709daceaed0656545ce0a3d3a173722706521 hrs 47 mins ago0x1e7af832c90b8b6f887b49833525200dc2fc7d4b  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.0046710375
0x44aa5452eb879dc39519a854249a66c74b74280070c3d7b6e3b59bccb9479114722691022 hrs 39 mins ago0xd0725a15bf4b6853e444c7ef2676c7b1eca3a786  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.004548664015
0xbf9b364bb31ee4459d0d3da349b540b410ddf692cf08e3ddb1960d3215e1292772264961 day 1 hr ago0x2d1566db0a9b31158cf1778bb4f55538a83a35d8  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.0050447205
0x1ff725e4db7105ecd07e0ef48018487566fe6e8b21d6f23212581a95a11c0ea872250711 day 9 hrs ago0x76cad0432dbd766c8b19c9c21a6c892eb83cdd45  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.004359635
0x1d3a9746230ba49da77bca47ee434fe3559593fd507684009da4df86fd49657c72249801 day 9 hrs ago0xb33ba04436bf1600623c6546aed8d1391baa0af2  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.004359187
0x91dfde2ac0ff677f821d505aa90679f430a4dbdf1c28b56b509f5a073c4164ba72247581 day 11 hrs ago0x8725e59eef18409273fa50662e7c1b671e368a86  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.003427065
0x7ffef8559fc6d1940e445b8894d0fa15e35565df386e5c6bb6f3401aa95eb2f172247421 day 11 hrs ago0x8725e59eef18409273fa50662e7c1b671e368a86  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.00350874
0x7ad1782dd67aa0906846e65f9d8eb862d5f4bd2f404e7af279a49166da045f8172247061 day 11 hrs ago0xc0de72d74d6d4db2ddeab6b3a083b0846a0127fc  IN   0xf1c525a488a848b58b95d79da48c21ce434290f70 Ether0.005605245
[ Download CSV Export 

Latest 25 Internal Transaction, Click here to view more Internal Transactions as a result of Contract Execution

Parent TxHash Block Age From To Value
0xa29b111f95e50c1f1695eabac284d27c819ee033d683480552666ff7141812cf72306891 hr 8 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x10682d3296a600a1c6f45e7d3bee7caebee6eb03795ad8b5e1d1f3c77aecb73872298745 hrs 50 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0xaba2f3bcacbc834d640c4b580ff01f2254d153057e27ac59278ff50571624b6672297956 hrs 20 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f70xf4b2d8154fccfcbf1e6b1681a1de27a6cd55357c4.2 Ether
0xaba2f3bcacbc834d640c4b580ff01f2254d153057e27ac59278ff50571624b6672297956 hrs 20 mins ago0x6d8a7f48ce5304e9613a6a7e2dde863b15f471b70xf1c525a488a848b58b95d79da48c21ce434290f74.2 Ether
0xaba2f3bcacbc834d640c4b580ff01f2254d153057e27ac59278ff50571624b6672297956 hrs 20 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f70xf4b2d8154fccfcbf1e6b1681a1de27a6cd55357c7.5 Ether
0xaba2f3bcacbc834d640c4b580ff01f2254d153057e27ac59278ff50571624b6672297956 hrs 20 mins ago0x6d8a7f48ce5304e9613a6a7e2dde863b15f471b70xf1c525a488a848b58b95d79da48c21ce434290f77.5 Ether
0xaba2f3bcacbc834d640c4b580ff01f2254d153057e27ac59278ff50571624b6672297956 hrs 20 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f70xf4b2d8154fccfcbf1e6b1681a1de27a6cd55357c0.3 Ether
0xaba2f3bcacbc834d640c4b580ff01f2254d153057e27ac59278ff50571624b6672297956 hrs 20 mins ago0x6d8a7f48ce5304e9613a6a7e2dde863b15f471b70xf1c525a488a848b58b95d79da48c21ce434290f70.3 Ether
0xe8e6d234b71613ab5e64b5ae5fbc1798c394e1f3f04e161c3202750b0949100672296157 hrs 17 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x681bcb88924a4cde7414a63e399c0105f29e6af34c21170a4b3c746ae04b435a722887711 hrs 25 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0xcb391566f77eed5679d0cdf9181a9f8181c921f05530f252adae465743fbd7be722886611 hrs 29 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x8b4b4c6bd1a5cfa43335455a7ac390bbf430ca06652f5905b9cade8879f288b3722869612 hrs 25 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x75931153cbe0161da03c7f704c368b25dbb6a6e6b88cca7f6ad9ca12128fd842722865112 hrs 44 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x57249a03bae0cdc30012dfbe3e01db25792ba5a15fa0b6dec3d653982b0ac211722827414 hrs 51 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x7cc0ff122bb218e11dff3a7eeb48c9419ec41c0f6bdf844f5ae8d47c6f724a0a722795616 hrs 41 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x02ecbec0dd21bbe996edcf11fc84fb24766390e302b085a1d862636e4dfa7761722791416 hrs 55 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0xad9eb38e33207661b74354f5b4860f4f032c6020598ba7796600f79413f2c57a722790916 hrs 57 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0xa8845a36bb60eb8371270b5ccb69bfee1d87be61d478b30a4c4daf31c278d85d722769818 hrs 12 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x802926147ad7b64a94cfbcbf789abe18f277b67c1814458377d65a68e25385ad722746619 hrs 21 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x83b8cbf80c635b8a3c1f5f109cc9e43f1764ba9394ebeb7363f8ec6691462e42722714421 hrs 15 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x5d19416862c0d661be85e072bb7f98e10343709daceaed0656545ce0a3d3a173722706521 hrs 47 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x44aa5452eb879dc39519a854249a66c74b74280070c3d7b6e3b59bccb9479114722691022 hrs 39 mins ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0xbf9b364bb31ee4459d0d3da349b540b410ddf692cf08e3ddb1960d3215e1292772264961 day 1 hr ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x1ff725e4db7105ecd07e0ef48018487566fe6e8b21d6f23212581a95a11c0ea872250711 day 9 hrs ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
0x1d3a9746230ba49da77bca47ee434fe3559593fd507684009da4df86fd49657c72249801 day 9 hrs ago0xf1c525a488a848b58b95d79da48c21ce434290f7  Contract Creation0 Ether
[ Download CSV Export 
Warning: The compiled contract might be susceptible to ExpExponentCleanup (medium/high-severity), EventStructWrongData (very low-severity) Solidity Compiler Bugs.

Contract Source Code Verified (Exact Match)
Contract Name: ExchangeV2
Compiler Version: v0.4.24+commit.e67f0147
Optimization Enabled: Yes
Runs (Optimizer):  200


Contract Source Code
pragma solidity ^0.4.24;

/**
 * @title Log Various Error Types
 * @author Adam Lemmon <[email protected]>
 * @dev Inherit this contract and your may now log errors easily
 * To support various error types, params, etc.
 */
contract LoggingErrors {
  /**
  * Events
  */
  event LogErrorString(string errorString);

  /**
  * Error cases
  */

  /**
   * @dev Default error to simply log the error message and return
   * @param _errorMessage The error message to log
   * @return ALWAYS false
   */
  function error(string _errorMessage) internal returns(bool) {
    LogErrorString(_errorMessage);
    return false;
  }
}

/**
 * @title Wallet Connector
 * @dev Connect the wallet contract to the correct Wallet Logic version
 */
contract WalletConnector is LoggingErrors {
  /**
   * Storage
   */
  address public owner_;
  address public latestLogic_;
  uint256 public latestVersion_;
  mapping(uint256 => address) public logicVersions_;
  uint256 public birthBlock_;

  /**
   * Events
   */
  event LogLogicVersionAdded(uint256 version);
  event LogLogicVersionRemoved(uint256 version);

  /**
   * @dev Constructor to set the latest logic address
   * @param _latestVersion Latest version of the wallet logic
   * @param _latestLogic Latest address of the wallet logic contract
   */
  function WalletConnector (
    uint256 _latestVersion,
    address _latestLogic
  ) public {
    owner_ = msg.sender;
    latestLogic_ = _latestLogic;
    latestVersion_ = _latestVersion;
    logicVersions_[_latestVersion] = _latestLogic;
    birthBlock_ = block.number;
  }

  /**
   * Add a new version of the logic contract
   * @param _version The version to be associated with the new contract.
   * @param _logic New logic contract.
   * @return Success of the transaction.
   */
  function addLogicVersion (
    uint256 _version,
    address _logic
  ) external
    returns(bool)
  {
    if (msg.sender != owner_)
      return error('msg.sender != owner, WalletConnector.addLogicVersion()');

    if (logicVersions_[_version] != 0)
      return error('Version already exists, WalletConnector.addLogicVersion()');

    // Update latest if this is the latest version
    if (_version > latestVersion_) {
      latestLogic_ = _logic;
      latestVersion_ = _version;
    }

    logicVersions_[_version] = _logic;
    LogLogicVersionAdded(_version);

    return true;
  }

  /**
   * @dev Remove a version. Cannot remove the latest version.
   * @param  _version The version to remove.
   */
  function removeLogicVersion(uint256 _version) external {
    require(msg.sender == owner_);
    require(_version != latestVersion_);
    delete logicVersions_[_version];
    LogLogicVersionRemoved(_version);
  }

  /**
   * Constants
   */

  /**
   * Called from user wallets in order to upgrade their logic.
   * @param _version The version to upgrade to. NOTE pass in 0 to upgrade to latest.
   * @return The address of the logic contract to upgrade to.
   */
  function getLogic(uint256 _version)
    external
    constant
    returns(address)
  {
    if (_version == 0)
      return latestLogic_;
    else
      return logicVersions_[_version];
  }
}

/**
 * @title Wallet to hold and trade ERC20 tokens and ether
 * @author Adam Lemmon <[email protected]>
 * @dev User wallet to interact with the exchange.
 * all tokens and ether held in this wallet, 1 to 1 mapping to user EOAs.
 */
contract WalletV2 is LoggingErrors {
  /**
   * Storage
   */
  // Vars included in wallet logic "lib", the order must match between Wallet and Logic
  address public owner_;
  address public exchange_;
  mapping(address => uint256) public tokenBalances_;

  address public logic_; // storage location 0x3 loaded for delegatecalls so this var must remain at index 3
  uint256 public birthBlock_;

  WalletConnector private connector_;

  /**
   * Events
   */
  event LogDeposit(address token, uint256 amount, uint256 balance);
  event LogWithdrawal(address token, uint256 amount, uint256 balance);

  /**
   * @dev Contract constructor. Set user as owner and connector address.
   * @param _owner The address of the user's EOA, wallets created from the exchange
   * so must past in the owner address, msg.sender == exchange.
   * @param _connector The wallet connector to be used to retrieve the wallet logic
   */
  function WalletV2(address _owner, address _connector) public {
    owner_ = _owner;
    connector_ = WalletConnector(_connector);
    exchange_ = msg.sender;
    logic_ = connector_.latestLogic_();
    birthBlock_ = block.number;
  }

  /**
   * @dev Fallback - Only enable funds to be sent from the exchange.
   * Ensures balances will be consistent.
   */
  function () external payable {
    require(msg.sender == exchange_);
  }

  /**
  * External
  */

  /**
   * @dev Deposit ether into this wallet, default to address 0 for consistent token lookup.
   */
  function depositEther()
    external
    payable
  {
    require(logic_.delegatecall(bytes4(sha3('deposit(address,uint256)')), 0, msg.value));
  }

  /**
   * @dev Deposit any ERC20 token into this wallet.
   * @param _token The address of the existing token contract.
   * @param _amount The amount of tokens to deposit.
   * @return Bool if the deposit was successful.
   */
  function depositERC20Token (
    address _token,
    uint256 _amount
  ) external
    returns(bool)
  {
    // ether
    if (_token == 0)
      return error('Cannot deposit ether via depositERC20, Wallet.depositERC20Token()');

    require(logic_.delegatecall(bytes4(sha3('deposit(address,uint256)')), _token, _amount));
    return true;
  }

  /**
   * @dev The result of an order, update the balance of this wallet.
   * @param _token The address of the token balance to update.
   * @param _amount The amount to update the balance by.
   * @param _subtractionFlag If true then subtract the token amount else add.
   * @return Bool if the update was successful.
   */
  function updateBalance (
    address _token,
    uint256 _amount,
    bool _subtractionFlag
  ) external
    returns(bool)
  {
    assembly {
      calldatacopy(0x40, 0, calldatasize)
      delegatecall(gas, sload(0x3), 0x40, calldatasize, 0, 32)
      return(0, 32)
      pop
    }
  }

  /**
   * User may update to the latest version of the exchange contract.
   * Note that multiple versions are NOT supported at this time and therefore if a
   * user does not wish to update they will no longer be able to use the exchange.
   * @param _exchange The new exchange.
   * @return Success of this transaction.
   */
  function updateExchange(address _exchange)
    external
    returns(bool)
  {
    if (msg.sender != owner_)
      return error('msg.sender != owner_, Wallet.updateExchange()');

    // If subsequent messages are not sent from this address all orders will fail
    exchange_ = _exchange;

    return true;
  }

  /**
   * User may update to a new or older version of the logic contract.
   * @param _version The versin to update to.
   * @return Success of this transaction.
   */
  function updateLogic(uint256 _version)
    external
    returns(bool)
  {
    if (msg.sender != owner_)
      return error('msg.sender != owner_, Wallet.updateLogic()');

    address newVersion = connector_.getLogic(_version);

    // Invalid version as defined by connector
    if (newVersion == 0)
      return error('Invalid version, Wallet.updateLogic()');

    logic_ = newVersion;
    return true;
  }

  /**
   * @dev Verify an order that the Exchange has received involving this wallet.
   * Internal checks and then authorize the exchange to move the tokens.
   * If sending ether will transfer to the exchange to broker the trade.
   * @param _token The address of the token contract being sold.
   * @param _amount The amount of tokens the order is for.
   * @param _fee The fee for the current trade.
   * @param _feeToken The token of which the fee is to be paid in.
   * @return If the order was verified or not.
   */
  function verifyOrder (
    address _token,
    uint256 _amount,
    uint256 _fee,
    address _feeToken
  ) external
    returns(bool)
  {
    assembly {
      calldatacopy(0x40, 0, calldatasize)
      delegatecall(gas, sload(0x3), 0x40, calldatasize, 0, 32)
      return(0, 32)
      pop
    }
  }

  /**
   * @dev Withdraw any token, including ether from this wallet to an EOA.
   * @param _token The address of the token to withdraw.
   * @param _amount The amount to withdraw.
   * @return Success of the withdrawal.
   */
  function withdraw(address _token, uint256 _amount)
    external
    returns(bool)
  {
    if(msg.sender != owner_)
      return error('msg.sender != owner, Wallet.withdraw()');

    assembly {
      calldatacopy(0x40, 0, calldatasize)
      delegatecall(gas, sload(0x3), 0x40, calldatasize, 0, 32)
      return(0, 32)
      pop
    }
  }

  /**
   * Constants
   */

  /**
   * @dev Get the balance for a specific token.
   * @param _token The address of the token contract to retrieve the balance of.
   * @return The current balance within this contract.
   */
  function balanceOf(address _token)
    public
    view
    returns(uint)
  {
    return tokenBalances_[_token];
  }
}

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {
  function mul(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a * b;
    assert(a == 0 || c / a == b);
    return c;
  }

  function div(uint256 a, uint256 b) internal constant returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  function sub(uint256 a, uint256 b) internal constant returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  function add(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

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

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

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

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

  /// @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) returns (bool success) {}

  /// @param _owner The address of the account owning tokens
  /// @param _spender The address of the account able to transfer the tokens
  /// @return Amount of remaining tokens allowed to spent
  function allowance(address _owner, address _spender) constant 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;
}

interface ExchangeV1 {
  function userAccountToWallet_(address) external returns(address);
}

interface BadERC20 {
  function transfer(address to, uint value) external;
  function transferFrom(address from, address to, uint256 value) external;
}

/**
 * @title Decentralized exchange for ether and ERC20 tokens.
 * @author Eidoo SAGL.
 * @dev All trades brokered by this contract.
 * Orders submitted by off chain order book and this contract handles
 * verification and execution of orders.
 * All value between parties is transferred via this exchange.
 * Methods arranged by visibility; external, public, internal, private and alphabatized within.
 *
 * New Exchange SC with eventually no fee and ERC20 tokens as quote
 */
contract ExchangeV2 is LoggingErrors {

  using SafeMath for uint256;

  /**
   * Data Structures
   */
  struct Order {
    address offerToken_;
    uint256 offerTokenTotal_;
    uint256 offerTokenRemaining_;  // Amount left to give
    address wantToken_;
    uint256 wantTokenTotal_;
    uint256 wantTokenReceived_;  // Amount received, note this may exceed want total
  }

  struct OrderStatus {
    uint256 expirationBlock_;
    uint256 wantTokenReceived_;    // Amount received, note this may exceed want total
    uint256 offerTokenRemaining_;  // Amount left to give
  }

  /**
   * Storage
   */
  address public previousExchangeAddress_;
  address private orderBookAccount_;
  address public owner_;
  uint256 public birthBlock_;
  address public edoToken_;
  address public walletConnector;

  mapping (address => uint256) public feeEdoPerQuote;
  mapping (address => uint256) public feeEdoPerQuoteDecimals;

  address public eidooWallet_;

  // Define if fee calculation must be skipped for a given trade. By default (false) fee must not be skipped.
  mapping(address => mapping(address => bool)) public mustSkipFee;

  /**
   * @dev Define in a trade who is the quote using a priority system:
   * values example
   *   0: not used as quote
   *  >0: used as quote
   *  if wanted and offered tokens have value > 0 the quote is the token with the bigger value
   */
  mapping(address => uint256) public quotePriority;

  mapping(bytes32 => OrderStatus) public orders_; // Map order hashes to order data struct
  mapping(address => address) public userAccountToWallet_; // User EOA to wallet addresses

  /**
   * Events
   */
  event LogFeeRateSet(address indexed token, uint256 rate, uint256 decimals);
  event LogQuotePrioritySet(address indexed quoteToken, uint256 priority);
  event LogMustSkipFeeSet(address indexed base, address indexed quote, bool mustSkipFee);
  event LogUserAdded(address indexed user, address walletAddress);
  event LogWalletDeposit(address indexed walletAddress, address token, uint256 amount, uint256 balance);
  event LogWalletWithdrawal(address indexed walletAddress, address token, uint256 amount, uint256 balance);

  event LogOrderExecutionSuccess(
    bytes32 indexed makerOrderId,
    bytes32 indexed takerOrderId,
    uint256 toMaker,
    uint256 toTaker
  );
  event LogOrderFilled(bytes32 indexed orderId, uint256 totalOfferRemaining, uint256 totalWantReceived);

  /**
   * @dev Contract constructor - CONFIRM matches contract name.  Set owner and addr of order book.
   * @param _bookAccount The EOA address for the order book, will submit ALL orders.
   * @param _edoToken Deployed edo token.
   * @param _edoPerWei Rate of edo tokens per wei.
   * @param _edoPerWeiDecimals Decimlas carried in edo rate.
   * @param _eidooWallet Wallet to pay fees to.
   * @param _previousExchangeAddress Previous exchange smart contract address.
   */
  constructor (
    address _bookAccount,
    address _edoToken,
    uint256 _edoPerWei,
    uint256 _edoPerWeiDecimals,
    address _eidooWallet,
    address _previousExchangeAddress,
    address _walletConnector
  ) public {
    orderBookAccount_ = _bookAccount;
    owner_ = msg.sender;
    birthBlock_ = block.number;
    edoToken_ = _edoToken;
    feeEdoPerQuote[address(0)] = _edoPerWei;
    feeEdoPerQuoteDecimals[address(0)] = _edoPerWeiDecimals;
    eidooWallet_ = _eidooWallet;
    quotePriority[address(0)] = 10;
    previousExchangeAddress_ = _previousExchangeAddress;
    require(_walletConnector != address (0), "WalletConnector address == 0");
    walletConnector = _walletConnector;
  }

  /**
   * @dev Fallback. wallets utilize to send ether in order to broker trade.
   */
  function () external payable { }

  /**
   * External
   */

  /**
   * @dev Returns the Wallet contract address associated to a user account. If the user account is not known, try to
   * migrate the wallet address from the old exchange instance. This function is equivalent to getWallet(), in addition
   * it stores the wallet address fetched from old the exchange instance.
   * @param userAccount The user account address
   * @return The address of the Wallet instance associated to the user account
   */
  function retrieveWallet(address userAccount)
    public
    returns(address walletAddress)
  {
    walletAddress = userAccountToWallet_[userAccount];
    if (walletAddress == address(0) && previousExchangeAddress_ != 0) {
      // Retrieve the wallet address from the old exchange.
      walletAddress = ExchangeV1(previousExchangeAddress_).userAccountToWallet_(userAccount);
      // TODO: in the future versions of the exchange the above line must be replaced with the following one
      //walletAddress = ExchangeV2(previousExchangeAddress_).retrieveWallet(userAccount);

      if (walletAddress != address(0)) {
        userAccountToWallet_[userAccount] = walletAddress;
      }
    }
  }

  /**
   * @dev Add a new user to the exchange, create a wallet for them.
   * Map their account address to the wallet contract for lookup.
   * @param userExternalOwnedAccount The address of the user"s EOA.
   * @return Success of the transaction, false if error condition met.
   */
  function addNewUser(address userExternalOwnedAccount)
    public
    returns (bool)
  {
    if (retrieveWallet(userExternalOwnedAccount) != address(0)) {
      return error("User already exists, Exchange.addNewUser()");
    }

    // Pass the userAccount address to wallet constructor so owner is not the exchange contract
    address userTradingWallet = new WalletV2(userExternalOwnedAccount, walletConnector);
    userAccountToWallet_[userExternalOwnedAccount] = userTradingWallet;
    emit LogUserAdded(userExternalOwnedAccount, userTradingWallet);
    return true;
  }

  /**
   * Execute orders in batches.
   * @param ownedExternalAddressesAndTokenAddresses Tokan and user addresses.
   * @param amountsExpirationsAndSalts Offer and want token amount and expiration and salt values.
   * @param vSignatures All order signature v values.
   * @param rAndSsignatures All order signature r and r values.
   * @return The success of this transaction.
   */
  function batchExecuteOrder(
    address[4][] ownedExternalAddressesAndTokenAddresses,
    uint256[8][] amountsExpirationsAndSalts, // Packing to save stack size
    uint8[2][] vSignatures,
    bytes32[4][] rAndSsignatures
  ) external
    returns(bool)
  {
    for (uint256 i = 0; i < amountsExpirationsAndSalts.length; i++) {
      require(
        executeOrder(
          ownedExternalAddressesAndTokenAddresses[i],
          amountsExpirationsAndSalts[i],
          vSignatures[i],
          rAndSsignatures[i]
        ),
        "Cannot execute order, Exchange.batchExecuteOrder()"
      );
    }

    return true;
  }

  /**
   * @dev Execute an order that was submitted by the external order book server.
   * The order book server believes it to be a match.
   * There are components for both orders, maker and taker, 2 signatures as well.
   * @param ownedExternalAddressesAndTokenAddresses The maker and taker external owned accounts addresses and offered tokens contracts.
   * [
   *   makerEOA
   *   makerOfferToken
   *   takerEOA
   *   takerOfferToken
   * ]
   * @param amountsExpirationsAndSalts The amount of tokens and the block number at which this order expires and a random number to mitigate replay.
   * [
   *   makerOffer
   *   makerWant
   *   takerOffer
   *   takerWant
   *   makerExpiry
   *   makerSalt
   *   takerExpiry
   *   takerSalt
   * ]
   * @param vSignatures ECDSA signature parameter.
   * [
   *   maker V
   *   taker V
   * ]
   * @param rAndSsignatures ECDSA signature parameters r ans s, maker 0, 1 and taker 2, 3.
   * [
   *   maker R
   *   maker S
   *   taker R
   *   taker S
   * ]
   * @return Success of the transaction, false if error condition met.
   * Like types grouped to eliminate stack depth error.
   */
  function executeOrder (
    address[4] ownedExternalAddressesAndTokenAddresses,
    uint256[8] amountsExpirationsAndSalts, // Packing to save stack size
    uint8[2] vSignatures,
    bytes32[4] rAndSsignatures
  ) public
    returns(bool)
  {
    // Only read wallet addresses from storage once
    // Need one more stack slot so squashing into array
    WalletV2[2] memory makerAndTakerTradingWallets = [
      WalletV2(retrieveWallet(ownedExternalAddressesAndTokenAddresses[0])), // maker
      WalletV2(retrieveWallet(ownedExternalAddressesAndTokenAddresses[2])) // taker
    ];

    // Basic pre-conditions, return if any input data is invalid
    if(!__executeOrderInputIsValid__(
      ownedExternalAddressesAndTokenAddresses,
      amountsExpirationsAndSalts,
      makerAndTakerTradingWallets[0], // maker
      makerAndTakerTradingWallets[1] // taker
    )) {
      return error("Input is invalid, Exchange.executeOrder()");
    }

    // Verify Maker and Taker signatures
    bytes32[2] memory makerAndTakerOrderHash = generateOrderHashes(
      ownedExternalAddressesAndTokenAddresses,
      amountsExpirationsAndSalts
    );

    // Check maker order signature
    if (!__signatureIsValid__(
      ownedExternalAddressesAndTokenAddresses[0],
      makerAndTakerOrderHash[0],
      vSignatures[0],
      rAndSsignatures[0],
      rAndSsignatures[1]
    )) {
      return error("Maker signature is invalid, Exchange.executeOrder()");
    }

    // Check taker order signature
    if (!__signatureIsValid__(
      ownedExternalAddressesAndTokenAddresses[2],
      makerAndTakerOrderHash[1],
      vSignatures[1],
      rAndSsignatures[2],
      rAndSsignatures[3]
    )) {
      return error("Taker signature is invalid, Exchange.executeOrder()");
    }

    // Exchange Order Verification and matching
    OrderStatus memory makerOrderStatus = orders_[makerAndTakerOrderHash[0]];
    OrderStatus memory takerOrderStatus = orders_[makerAndTakerOrderHash[1]];
    Order memory makerOrder;
    Order memory takerOrder;

    makerOrder.offerToken_ = ownedExternalAddressesAndTokenAddresses[1];
    makerOrder.offerTokenTotal_ = amountsExpirationsAndSalts[0];
    makerOrder.wantToken_ = ownedExternalAddressesAndTokenAddresses[3];
    makerOrder.wantTokenTotal_ = amountsExpirationsAndSalts[1];

    if (makerOrderStatus.expirationBlock_ > 0) {  // Check for existence
      // Orders still active
      if (makerOrderStatus.offerTokenRemaining_ == 0) {
        return error("Maker order is inactive, Exchange.executeOrder()");
      }
      makerOrder.offerTokenRemaining_ = makerOrderStatus.offerTokenRemaining_; // Amount to give
      makerOrder.wantTokenReceived_ = makerOrderStatus.wantTokenReceived_; // Amount received
    } else {
      makerOrder.offerTokenRemaining_ = amountsExpirationsAndSalts[0]; // Amount to give
      makerOrder.wantTokenReceived_ = 0; // Amount received
      makerOrderStatus.expirationBlock_ = amountsExpirationsAndSalts[4]; // maker order expiration block
    }

    takerOrder.offerToken_ = ownedExternalAddressesAndTokenAddresses[3];
    takerOrder.offerTokenTotal_ = amountsExpirationsAndSalts[2];
    takerOrder.wantToken_ = ownedExternalAddressesAndTokenAddresses[1];
    takerOrder.wantTokenTotal_ = amountsExpirationsAndSalts[3];

    if (takerOrderStatus.expirationBlock_ > 0) {  // Check for existence
      if (takerOrderStatus.offerTokenRemaining_ == 0) {
        return error("Taker order is inactive, Exchange.executeOrder()");
      }
      takerOrder.offerTokenRemaining_ = takerOrderStatus.offerTokenRemaining_;  // Amount to give
      takerOrder.wantTokenReceived_ = takerOrderStatus.wantTokenReceived_; // Amount received

    } else {
      takerOrder.offerTokenRemaining_ = amountsExpirationsAndSalts[2];  // Amount to give
      takerOrder.wantTokenReceived_ = 0; // Amount received
      takerOrderStatus.expirationBlock_ = amountsExpirationsAndSalts[6]; // taker order expiration block
    }

    // Check if orders are matching and are valid
    if (!__ordersMatch_and_AreVaild__(makerOrder, takerOrder)) {
      return error("Orders do not match, Exchange.executeOrder()");
    }

    // Trade amounts
    // [0] => toTakerAmount
    // [1] => toMakerAmount
    uint[2] memory toTakerAndToMakerAmount;
    toTakerAndToMakerAmount = __getTradeAmounts__(makerOrder, takerOrder);

    // TODO consider removing. Can this condition be met?
    if (toTakerAndToMakerAmount[0] < 1 || toTakerAndToMakerAmount[1] < 1) {
      return error("Token amount < 1, price ratio is invalid! Token value < 1, Exchange.executeOrder()");
    }

    uint calculatedFee = __calculateFee__(makerOrder, toTakerAndToMakerAmount[0], toTakerAndToMakerAmount[1]);

    // Check taker has sufficent EDO token balance to pay the fee
    if (
      takerOrder.offerToken_ == edoToken_ &&
      Token(edoToken_).balanceOf(makerAndTakerTradingWallets[1]) < calculatedFee.add(toTakerAndToMakerAmount[1])
    ) {
      return error("Taker has an insufficient EDO token balance to cover the fee AND the offer, Exchange.executeOrder()");
    } else if (Token(edoToken_).balanceOf(makerAndTakerTradingWallets[1]) < calculatedFee) {
      return error("Taker has an insufficient EDO token balance to cover the fee, Exchange.executeOrder()");
    }

    // Wallet Order Verification, reach out to the maker and taker wallets.
    if (
      !__ordersVerifiedByWallets__(
        ownedExternalAddressesAndTokenAddresses,
        toTakerAndToMakerAmount[1],
        toTakerAndToMakerAmount[0],
        makerAndTakerTradingWallets[0],
        makerAndTakerTradingWallets[1],
        calculatedFee
    )) {
      return error("Order could not be verified by wallets, Exchange.executeOrder()");
    }

    // Write to storage then external calls
    makerOrderStatus.offerTokenRemaining_ = makerOrder.offerTokenRemaining_.sub(toTakerAndToMakerAmount[0]);
    makerOrderStatus.wantTokenReceived_ = makerOrder.wantTokenReceived_.add(toTakerAndToMakerAmount[1]);

    takerOrderStatus.offerTokenRemaining_ = takerOrder.offerTokenRemaining_.sub(toTakerAndToMakerAmount[1]);
    takerOrderStatus.wantTokenReceived_ = takerOrder.wantTokenReceived_.add(toTakerAndToMakerAmount[0]);

    // Finally write orders to storage
    orders_[makerAndTakerOrderHash[0]] = makerOrderStatus;
    orders_[makerAndTakerOrderHash[1]] = takerOrderStatus;

    // Transfer the external value, ether <> tokens
    require(
      __executeTokenTransfer__(
        ownedExternalAddressesAndTokenAddresses,
        toTakerAndToMakerAmount[0],
        toTakerAndToMakerAmount[1],
        calculatedFee,
        makerAndTakerTradingWallets[0],
        makerAndTakerTradingWallets[1]
      ),
      "Cannot execute token transfer, Exchange.__executeTokenTransfer__()"
    );

    // Log the order id(hash), amount of offer given, amount of offer remaining
    emit LogOrderFilled(makerAndTakerOrderHash[0], makerOrderStatus.offerTokenRemaining_, makerOrderStatus.wantTokenReceived_);
    emit LogOrderFilled(makerAndTakerOrderHash[1], takerOrderStatus.offerTokenRemaining_, takerOrderStatus.wantTokenReceived_);
    emit LogOrderExecutionSuccess(makerAndTakerOrderHash[0], makerAndTakerOrderHash[1], toTakerAndToMakerAmount[1], toTakerAndToMakerAmount[0]);

    return true;
  }

  /**
   * @dev Set the fee rate for a specific quote
   * @param _quoteToken Quote token.
   * @param _edoPerQuote EdoPerQuote.
   * @param _edoPerQuoteDecimals EdoPerQuoteDecimals.
   * @return Success of the transaction.
   */
  function setFeeRate(
    address _quoteToken,
    uint256 _edoPerQuote,
    uint256 _edoPerQuoteDecimals
  ) external
    returns(bool)
  {
    if (msg.sender != owner_) {
      return error("msg.sender != owner, Exchange.setFeeRate()");
    }

    if (quotePriority[_quoteToken] == 0) {
      return error("quotePriority[_quoteToken] == 0, Exchange.setFeeRate()");
    }

    feeEdoPerQuote[_quoteToken] = _edoPerQuote;
    feeEdoPerQuoteDecimals[_quoteToken] = _edoPerQuoteDecimals;

    emit LogFeeRateSet(_quoteToken, _edoPerQuote, _edoPerQuoteDecimals);

    return true;
  }

  /**
   * @dev Set the wallet for fees to be paid to.
   * @param eidooWallet Wallet to pay fees to.
   * @return Success of the transaction.
   */
  function setEidooWallet(
    address eidooWallet
  ) external
    returns(bool)
  {
    if (msg.sender != owner_) {
      return error("msg.sender != owner, Exchange.setEidooWallet()");
    }
    eidooWallet_ = eidooWallet;
    return true;
  }

  /**
   * @dev Set a new order book account.
   * @param account The new order book account.
   */
  function setOrderBookAcount (
    address account
  ) external
    returns(bool)
  {
    if (msg.sender != owner_) {
      return error("msg.sender != owner, Exchange.setOrderBookAcount()");
    }
    orderBookAccount_ = account;
    return true;
  }

  /**
   * @dev Set if a base must skip fee calculation.
   * @param _baseTokenAddress The trade base token address that must skip fee calculation.
   * @param _quoteTokenAddress The trade quote token address that must skip fee calculation.
   * @param _mustSkipFee The trade base token address that must skip fee calculation.
   */
  function setMustSkipFee (
    address _baseTokenAddress,
    address _quoteTokenAddress,
    bool _mustSkipFee
  ) external
    returns(bool)
  {
    // Preserving same owner check style
    if (msg.sender != owner_) {
      return error("msg.sender != owner, Exchange.setMustSkipFee()");
    }
    mustSkipFee[_baseTokenAddress][_quoteTokenAddress] = _mustSkipFee;
    emit LogMustSkipFeeSet(_baseTokenAddress, _quoteTokenAddress, _mustSkipFee);
    return true;
  }

  /**
   * @dev Set quote priority token.
   * Set the sorting of token quote based on a priority.
   * @param _token The address of the token that was deposited.
   * @param _priority The amount of the token that was deposited.
   * @return Operation success.
   */

  function setQuotePriority(address _token, uint256 _priority)
    external
    returns(bool)
  {
    if (msg.sender != owner_) {
      return error("msg.sender != owner, Exchange.setQuotePriority()");
    }
    quotePriority[_token] = _priority;
    emit LogQuotePrioritySet(_token, _priority);
    return true;
  }

  /*
   Methods to catch events from external contracts, user wallets primarily
   */

  /**
   * @dev Simply log the event to track wallet interaction off-chain.
   * @param tokenAddress The address of the token that was deposited.
   * @param amount The amount of the token that was deposited.
   * @param tradingWalletBalance The updated balance of the wallet after deposit.
   */
  function walletDeposit(
    address tokenAddress,
    uint256 amount,
    uint256 tradingWalletBalance
  ) external
  {
    emit LogWalletDeposit(msg.sender, tokenAddress, amount, tradingWalletBalance);
  }

  /**
   * @dev Simply log the event to track wallet interaction off-chain.
   * @param tokenAddress The address of the token that was deposited.
   * @param amount The amount of the token that was deposited.
   * @param tradingWalletBalance The updated balance of the wallet after deposit.
   */
  function walletWithdrawal(
    address tokenAddress,
    uint256 amount,
    uint256 tradingWalletBalance
  ) external
  {
    emit LogWalletWithdrawal(msg.sender, tokenAddress, amount, tradingWalletBalance);
  }

  /**
   * Private
   */

  /**
   * Calculate the fee for the given trade. Calculated as the set % of the wei amount
   * converted into EDO tokens using the manually set conversion ratio.
   * @param makerOrder The maker order object.
   * @param toTakerAmount The amount of tokens going to the taker.
   * @param toMakerAmount The amount of tokens going to the maker.
   * @return The total fee to be paid in EDO tokens.
   */
  function __calculateFee__(
    Order makerOrder,
    uint256 toTakerAmount,
    uint256 toMakerAmount
  ) private
    view
    returns(uint256)
  {
    // weiAmount * (fee %) * (EDO/Wei) / (decimals in edo/wei) / (decimals in percentage)
    if (!__isSell__(makerOrder)) {
      // buy -> the quote is the offered token by the maker
      return mustSkipFee[makerOrder.wantToken_][makerOrder.offerToken_]
        ? 0
        : toTakerAmount.mul(feeEdoPerQuote[makerOrder.offerToken_]).div(10**feeEdoPerQuoteDecimals[makerOrder.offerToken_]);
    } else {
      // sell -> the quote is the wanted token by the maker
      return mustSkipFee[makerOrder.offerToken_][makerOrder.wantToken_]
        ? 0
        : toMakerAmount.mul(feeEdoPerQuote[makerOrder.wantToken_]).div(10**feeEdoPerQuoteDecimals[makerOrder.wantToken_]);
    }
  }

  /**
   * @dev Verify the input to order execution is valid.
   * @param ownedExternalAddressesAndTokenAddresses The maker and taker external owned accounts addresses and offered tokens contracts.
   * [
   *   makerEOA
   *   makerOfferToken
   *   takerEOA
   *   takerOfferToken
   * ]
   * @param amountsExpirationsAndSalts The amount of tokens and the block number at which this order expires and a random number to mitigate replay.
   * [
   *   makerOffer
   *   makerWant
   *   takerOffer
   *   takerWant
   *   makerExpiry
   *   makerSalt
   *   takerExpiry
   *   takerSalt
   * ]
   * @return Success if all checks pass.
   */
  function __executeOrderInputIsValid__(
    address[4] ownedExternalAddressesAndTokenAddresses,
    uint256[8] amountsExpirationsAndSalts,
    address makerTradingWallet,
    address takerTradingWallet
  ) private
    returns(bool)
  {
    // msg.send needs to be the orderBookAccount
    if (msg.sender != orderBookAccount_) {
      return error("msg.sender != orderBookAccount, Exchange.__executeOrderInputIsValid__()");
    }

    // Check expirations base on the block number
    if (block.number > amountsExpirationsAndSalts[4]) {
      return error("Maker order has expired, Exchange.__executeOrderInputIsValid__()");
    }

    if (block.number > amountsExpirationsAndSalts[6]) {
      return error("Taker order has expired, Exchange.__executeOrderInputIsValid__()");
    }

    // Operating on existing tradingWallets
    if (makerTradingWallet == address(0)) {
      return error("Maker wallet does not exist, Exchange.__executeOrderInputIsValid__()");
    }

    if (takerTradingWallet == address(0)) {
      return error("Taker wallet does not exist, Exchange.__executeOrderInputIsValid__()");
    }

    if (quotePriority[ownedExternalAddressesAndTokenAddresses[1]] == quotePriority[ownedExternalAddressesAndTokenAddresses[3]]) {
      return error("Quote token is omitted! Is not offered by either the Taker or Maker, Exchange.__executeOrderInputIsValid__()");
    }

    // Check that none of the amounts is = to 0
    if (
        amountsExpirationsAndSalts[0] == 0 ||
        amountsExpirationsAndSalts[1] == 0 ||
        amountsExpirationsAndSalts[2] == 0 ||
        amountsExpirationsAndSalts[3] == 0
      )
      return error("May not execute an order where token amount == 0, Exchange.__executeOrderInputIsValid__()");

    // // Confirm order ether amount >= min amount
    //  // Maker
    //  uint256 minOrderEthAmount = minOrderEthAmount_; // Single storage read
    //  if (_token_and_EOA_Addresses[1] == 0 && _amountsExpirationAndSalt[0] < minOrderEthAmount)
    //    return error('Maker order does not meet the minOrderEthAmount_ of ether, Exchange.__executeOrderInputIsValid__()');

    //  // Taker
    //  if (_token_and_EOA_Addresses[3] == 0 && _amountsExpirationAndSalt[2] < minOrderEthAmount)
    //    return error('Taker order does not meet the minOrderEthAmount_ of ether, Exchange.__executeOrderInputIsValid__()');

    return true;
  }

  /**
   * @dev Execute the external transfer of tokens.
   * @param ownedExternalAddressesAndTokenAddresses The maker and taker external owned accounts addresses and offered tokens contracts.
   * [
   *   makerEOA
   *   makerOfferToken
   *   takerEOA
   *   takerOfferToken
   * ]
   * @param toTakerAmount The amount of tokens to transfer to the taker.
   * @param toMakerAmount The amount of tokens to transfer to the maker.
   * @return Success if both wallets verify the order.
   */
  function __executeTokenTransfer__(
    address[4] ownedExternalAddressesAndTokenAddresses,
    uint256 toTakerAmount,
    uint256 toMakerAmount,
    uint256 fee,
    WalletV2 makerTradingWallet,
    WalletV2 takerTradingWallet
  ) private
    returns (bool)
  {
    // Wallet mapping balances
    address makerOfferTokenAddress = ownedExternalAddressesAndTokenAddresses[1];
    address takerOfferTokenAddress = ownedExternalAddressesAndTokenAddresses[3];

    // Taker to pay fee before trading
    if(fee != 0) {
      require(
        takerTradingWallet.updateBalance(edoToken_, fee, true),
        "Taker trading wallet cannot update balance with fee, Exchange.__executeTokenTransfer__()"
      );

      require(
        Token(edoToken_).transferFrom(takerTradingWallet, eidooWallet_, fee),
        "Cannot transfer fees from taker trading wallet to eidoo wallet, Exchange.__executeTokenTransfer__()"
      );
    }

    // Updating makerTradingWallet balance by the toTaker
    require(
      makerTradingWallet.updateBalance(makerOfferTokenAddress, toTakerAmount, true),
      "Maker trading wallet cannot update balance subtracting toTakerAmount, Exchange.__executeTokenTransfer__()"
    ); // return error("Unable to subtract maker token from maker wallet, Exchange.__executeTokenTransfer__()");

    // Updating takerTradingWallet balance by the toTaker
    require(
      takerTradingWallet.updateBalance(makerOfferTokenAddress, toTakerAmount, false),
      "Taker trading wallet cannot update balance adding toTakerAmount, Exchange.__executeTokenTransfer__()"
    ); // return error("Unable to add maker token to taker wallet, Exchange.__executeTokenTransfer__()");

    // Updating takerTradingWallet balance by the toMaker amount
    require(
      takerTradingWallet.updateBalance(takerOfferTokenAddress, toMakerAmount, true),
      "Taker trading wallet cannot update balance subtracting toMakerAmount, Exchange.__executeTokenTransfer__()"
    ); // return error("Unable to subtract taker token from taker wallet, Exchange.__executeTokenTransfer__()");

    // Updating makerTradingWallet balance by the toMaker amount
    require(
      makerTradingWallet.updateBalance(takerOfferTokenAddress, toMakerAmount, false),
      "Maker trading wallet cannot update balance adding toMakerAmount, Exchange.__executeTokenTransfer__()"
    ); // return error("Unable to add taker token to maker wallet, Exchange.__executeTokenTransfer__()");

    // Ether to the taker and tokens to the maker
    if (makerOfferTokenAddress == address(0)) {
      address(takerTradingWallet).transfer(toTakerAmount);
    } else {
      require(
        safeTransferFrom(makerOfferTokenAddress, makerTradingWallet, takerTradingWallet, toTakerAmount),
        "Token transfership from makerTradingWallet to takerTradingWallet failed, Exchange.__executeTokenTransfer__()"
      );
      assert(
        __tokenAndWalletBalancesMatch__(
          makerTradingWallet,
          takerTradingWallet,
          makerOfferTokenAddress
        )
      );
    }

    if (takerOfferTokenAddress == address(0)) {
      address(makerTradingWallet).transfer(toMakerAmount);
    } else {
      require(
        safeTransferFrom(takerOfferTokenAddress, takerTradingWallet, makerTradingWallet, toMakerAmount),
        "Token transfership from takerTradingWallet to makerTradingWallet failed, Exchange.__executeTokenTransfer__()"
      );
      assert(
        __tokenAndWalletBalancesMatch__(
          makerTradingWallet,
          takerTradingWallet,
          takerOfferTokenAddress
        )
      );
    }

    return true;
  }

  /**
   * @dev Calculates Keccak-256 hash of order with specified parameters.
   * @param ownedExternalAddressesAndTokenAddresses The orders maker EOA and current exchange address.
   * @param amountsExpirationsAndSalts The orders offer and want amounts and expirations with salts.
   * @return Keccak-256 hash of the passed order.
   */

  function generateOrderHashes(
    address[4] ownedExternalAddressesAndTokenAddresses,
    uint256[8] amountsExpirationsAndSalts
  ) public
    view
    returns (bytes32[2])
  {
    bytes32 makerOrderHash = keccak256(
      address(this),
      ownedExternalAddressesAndTokenAddresses[0], // _makerEOA
      ownedExternalAddressesAndTokenAddresses[1], // offerToken
      amountsExpirationsAndSalts[0],  // offerTokenAmount
      ownedExternalAddressesAndTokenAddresses[3], // wantToken
      amountsExpirationsAndSalts[1],  // wantTokenAmount
      amountsExpirationsAndSalts[4], // expiry
      amountsExpirationsAndSalts[5] // salt
    );

    bytes32 takerOrderHash = keccak256(
      address(this),
      ownedExternalAddressesAndTokenAddresses[2], // _makerEOA
      ownedExternalAddressesAndTokenAddresses[3], // offerToken
      amountsExpirationsAndSalts[2],  // offerTokenAmount
      ownedExternalAddressesAndTokenAddresses[1], // wantToken
      amountsExpirationsAndSalts[3],  // wantTokenAmount
      amountsExpirationsAndSalts[6], // expiry
      amountsExpirationsAndSalts[7] // salt
    );

    return [makerOrderHash, takerOrderHash];
  }

  /**
   * @dev Returns a bool representing a SELL or BUY order based on quotePriority.
   * @param _order The maker order data structure.
   * @return The bool indicating if the order is a SELL or BUY.
   */
  function __isSell__(Order _order) internal view returns (bool) {
    return quotePriority[_order.offerToken_] < quotePriority[_order.wantToken_];
  }

  /**
   * @dev Compute the tradeable amounts of the two verified orders.
   * Token amount is the __min__ remaining between want and offer of the two orders that isn"t ether.
   * Ether amount is then: etherAmount = tokenAmount * priceRatio, as ratio = eth / token.
   * @param makerOrder The maker order data structure.
   * @param takerOrder The taker order data structure.
   * @return The amount moving from makerOfferRemaining to takerWantRemaining and vice versa.
   */
  function __getTradeAmounts__(
    Order makerOrder,
    Order takerOrder
  ) internal
    view
    returns (uint256[2])
  {
    bool isMakerBuy = __isSell__(takerOrder);  // maker buy = taker sell
    uint256 priceRatio;
    uint256 makerAmountLeftToReceive;
    uint256 takerAmountLeftToReceive;

    uint toTakerAmount;
    uint toMakerAmount;

    if (makerOrder.offerTokenTotal_ >= makerOrder.wantTokenTotal_) {
      priceRatio = makerOrder.offerTokenTotal_.mul(2**128).div(makerOrder.wantTokenTotal_);
      if (isMakerBuy) {
        // MP > 1
        makerAmountLeftToReceive = makerOrder.wantTokenTotal_.sub(makerOrder.wantTokenReceived_);
        toMakerAmount = __min__(takerOrder.offerTokenRemaining_, makerAmountLeftToReceive);
        // add 2**128-1 in order to obtain a round up
        toTakerAmount = toMakerAmount.mul(priceRatio).add(2**128-1).div(2**128);
      } else {
        // MP < 1
        takerAmountLeftToReceive = takerOrder.wantTokenTotal_.sub(takerOrder.wantTokenReceived_);
        toTakerAmount = __min__(makerOrder.offerTokenRemaining_, takerAmountLeftToReceive);
        toMakerAmount = toTakerAmount.mul(2**128).div(priceRatio);
      }
    } else {
      priceRatio = makerOrder.wantTokenTotal_.mul(2**128).div(makerOrder.offerTokenTotal_);
      if (isMakerBuy) {
        // MP < 1
        makerAmountLeftToReceive = makerOrder.wantTokenTotal_.sub(makerOrder.wantTokenReceived_);
        toMakerAmount = __min__(takerOrder.offerTokenRemaining_, makerAmountLeftToReceive);
        toTakerAmount = toMakerAmount.mul(2**128).div(priceRatio);
      } else {
        // MP > 1
        takerAmountLeftToReceive = takerOrder.wantTokenTotal_.sub(takerOrder.wantTokenReceived_);
        toTakerAmount = __min__(makerOrder.offerTokenRemaining_, takerAmountLeftToReceive);
        // add 2**128-1 in order to obtain a round up
        toMakerAmount = toTakerAmount.mul(priceRatio).add(2**128-1).div(2**128);
      }
    }
    return [toTakerAmount, toMakerAmount];
  }

  /**
   * @dev Return the maximum of two uints
   * @param a Uint 1
   * @param b Uint 2
   * @return The grater value or a if equal
   */
  function __max__(uint256 a, uint256 b)
    private
    pure
    returns (uint256)
  {
    return a < b
      ? b
      : a;
  }

  /**
   * @dev Return the minimum of two uints
   * @param a Uint 1
   * @param b Uint 2
   * @return The smallest value or b if equal
   */
  function __min__(uint256 a, uint256 b)
    private
    pure
    returns (uint256)
  {
    return a < b
      ? a
      : b;
  }

  /**
   * @dev Confirm that the orders do match and are valid.
   * @param makerOrder The maker order data structure.
   * @param takerOrder The taker order data structure.
   * @return Bool if the orders passes all checks.
   */
  function __ordersMatch_and_AreVaild__(
    Order makerOrder,
    Order takerOrder
  ) private
    returns (bool)
  {
    // Confirm tokens match
    // NOTE potentially omit as matching handled upstream?
    if (makerOrder.wantToken_ != takerOrder.offerToken_) {
      return error("Maker wanted token does not match taker offer token, Exchange.__ordersMatch_and_AreVaild__()");
    }

    if (makerOrder.offerToken_ != takerOrder.wantToken_) {
      return error("Maker offer token does not match taker wanted token, Exchange.__ordersMatch_and_AreVaild__()");
    }

    // Price Ratios, to x decimal places hence * decimals, dependent on the size of the denominator.
    // Ratios are relative to eth, amount of ether for a single token, ie. ETH / GNO == 0.2 Ether per 1 Gnosis

    uint256 orderPrice;   // The price the maker is willing to accept
    uint256 offeredPrice; // The offer the taker has given

    // Ratio = larger amount / smaller amount
    if (makerOrder.offerTokenTotal_ >= makerOrder.wantTokenTotal_) {
      orderPrice = makerOrder.offerTokenTotal_.mul(2**128).div(makerOrder.wantTokenTotal_);
      offeredPrice = takerOrder.wantTokenTotal_.mul(2**128).div(takerOrder.offerTokenTotal_);

      // ie. Maker is offering 10 ETH for 100 GNO but taker is offering 100 GNO for 20 ETH, no match!
      // The taker wants more ether than the maker is offering.
      if (orderPrice < offeredPrice) {
        return error("Taker price is greater than maker price, Exchange.__ordersMatch_and_AreVaild__()");
      }
    } else {
      orderPrice = makerOrder.wantTokenTotal_.mul(2**128).div(makerOrder.offerTokenTotal_);
      offeredPrice = takerOrder.offerTokenTotal_.mul(2**128).div(takerOrder.wantTokenTotal_);

      // ie. Maker is offering 100 GNO for 10 ETH but taker is offering 5 ETH for 100 GNO, no match!
      // The taker is not offering enough ether for the maker
      if (orderPrice > offeredPrice) {
        return error("Taker price is less than maker price, Exchange.__ordersMatch_and_AreVaild__()");
      }
    }

    return true;
  }

  /**
   * @dev Ask each wallet to verify this order.
   * @param ownedExternalAddressesAndTokenAddresses The maker and taker external owned accounts addresses and offered tokens contracts.
   * [
   *   makerEOA
   *   makerOfferToken
   *   takerEOA
   *   takerOfferToken
   * ]
   * @param toMakerAmount The amount of tokens to be sent to the maker.
   * @param toTakerAmount The amount of tokens to be sent to the taker.
   * @param makerTradingWallet The maker trading wallet contract.
   * @param takerTradingWallet The taker trading wallet contract.
   * @param fee The fee to be paid for this trade, paid in full by taker.
   * @return Success if both wallets verify the order.
   */
  function __ordersVerifiedByWallets__(
    address[4] ownedExternalAddressesAndTokenAddresses,
    uint256 toMakerAmount,
    uint256 toTakerAmount,
    WalletV2 makerTradingWallet,
    WalletV2 takerTradingWallet,
    uint256 fee
  ) private
    returns (bool)
  {
    // Have the transaction verified by both maker and taker wallets
    // confirm sufficient balance to transfer, offerToken and offerTokenAmount
    if(!makerTradingWallet.verifyOrder(ownedExternalAddressesAndTokenAddresses[1], toTakerAmount, 0, 0)) {
      return error("Maker wallet could not verify the order, Exchange.____ordersVerifiedByWallets____()");
    }

    if(!takerTradingWallet.verifyOrder(ownedExternalAddressesAndTokenAddresses[3], toMakerAmount, fee, edoToken_)) {
      return error("Taker wallet could not verify the order, Exchange.____ordersVerifiedByWallets____()");
    }

    return true;
  }

  /**
   * @dev On chain verification of an ECDSA ethereum signature.
   * @param signer The EOA address of the account that supposedly signed the message.
   * @param orderHash The on-chain generated hash for the order.
   * @param v ECDSA signature parameter v.
   * @param r ECDSA signature parameter r.
   * @param s ECDSA signature parameter s.
   * @return Bool if the signature is valid or not.
   */
  function __signatureIsValid__(
    address signer,
    bytes32 orderHash,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) private
    pure
    returns (bool)
  {
    address recoveredAddr = ecrecover(
      keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", orderHash)),
      v,
      r,
      s
    );

    return recoveredAddr == signer;
  }

  /**
   * @dev Confirm wallet local balances and token balances match.
   * @param makerTradingWallet  Maker wallet address.
   * @param takerTradingWallet  Taker wallet address.
   * @param token  Token address to confirm balances match.
   * @return If the balances do match.
   */
  function __tokenAndWalletBalancesMatch__(
    address makerTradingWallet,
    address takerTradingWallet,
    address token
  ) private
    view
    returns(bool)
  {
    if (Token(token).balanceOf(makerTradingWallet) != WalletV2(makerTradingWallet).balanceOf(token)) {
      return false;
    }

    if (Token(token).balanceOf(takerTradingWallet) != WalletV2(takerTradingWallet).balanceOf(token)) {
      return false;
    }

    return true;
  }

  /**
   * @dev Wrapping the ERC20 transfer function to avoid missing returns.
   * @param _token The address of bad formed ERC20 token.
   * @param _from Transfer sender.
   * @param _to Transfer receiver.
   * @param _value Amount to be transfered.
   * @return Success of the safeTransfer.
   */
  function safeTransferFrom(
    address _token,
    address _from,
    address _to,
    uint256 _value
  )
    public
    returns (bool result)
  {
    BadERC20(_token).transferFrom(_from, _to, _value);

    assembly {
      switch returndatasize()
      case 0 {                      // This is our BadToken
        result := not(0)            // result is true
      }
      case 32 {                     // This is our GoodToken
        returndatacopy(0, 0, 32)
        result := mload(0)          // result == returndata of external call
      }
      default {                     // This is not an ERC20 token
        revert(0, 0)
      }
    }
  }
}

Contract ABI
[{"constant":false,"inputs":[{"name":"eidooWallet","type":"address"}],"name":"setEidooWallet","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"quotePriority","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"userAccount","type":"address"}],"name":"retrieveWallet","outputs":[{"name":"walletAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"ownedExternalAddressesAndTokenAddresses","type":"address[4]"},{"name":"amountsExpirationsAndSalts","type":"uint256[8]"}],"name":"generateOrderHashes","outputs":[{"name":"","type":"bytes32[2]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"ownedExternalAddressesAndTokenAddresses","type":"address[4][]"},{"name":"amountsExpirationsAndSalts","type":"uint256[8][]"},{"name":"vSignatures","type":"uint8[2][]"},{"name":"rAndSsignatures","type":"bytes32[4][]"}],"name":"batchExecuteOrder","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"}],"name":"setOrderBookAcount","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tokenAddress","type":"address"},{"name":"amount","type":"uint256"},{"name":"tradingWalletBalance","type":"uint256"}],"name":"walletWithdrawal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_baseTokenAddress","type":"address"},{"name":"_quoteTokenAddress","type":"address"},{"name":"_mustSkipFee","type":"bool"}],"name":"setMustSkipFee","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_priority","type":"uint256"}],"name":"setQuotePriority","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"edoToken_","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"birthBlock_","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"orders_","outputs":[{"name":"expirationBlock_","type":"uint256"},{"name":"wantTokenReceived_","type":"uint256"},{"name":"offerTokenRemaining_","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"mustSkipFee","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"feeEdoPerQuote","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"walletConnector","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"userAccountToWallet_","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"previousExchangeAddress_","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"eidooWallet_","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"userExternalOwnedAccount","type":"address"}],"name":"addNewUser","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ownedExternalAddressesAndTokenAddresses","type":"address[4]"},{"name":"amountsExpirationsAndSalts","type":"uint256[8]"},{"name":"vSignatures","type":"uint8[2]"},{"name":"rAndSsignatures","type":"bytes32[4]"}],"name":"executeOrder","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"tokenAddress","type":"address"},{"name":"amount","type":"uint256"},{"name":"tradingWalletBalance","type":"uint256"}],"name":"walletDeposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"safeTransferFrom","outputs":[{"name":"result","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"feeEdoPerQuoteDecimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner_","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_quoteToken","type":"address"},{"name":"_edoPerQuote","type":"uint256"},{"name":"_edoPerQuoteDecimals","type":"uint256"}],"name":"setFeeRate","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_bookAccount","type":"address"},{"name":"_edoToken","type":"address"},{"name":"_edoPerWei","type":"uint256"},{"name":"_edoPerWeiDecimals","type":"uint256"},{"name":"_eidooWallet","type":"address"},{"name":"_previousExchangeAddress","type":"address"},{"name":"_walletConnector","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token","type":"address"},{"indexed":false,"name":"rate","type":"uint256"},{"indexed":false,"name":"decimals","type":"uint256"}],"name":"LogFeeRateSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"quoteToken","type":"address"},{"indexed":false,"name":"priority","type":"uint256"}],"name":"LogQuotePrioritySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"base","type":"address"},{"indexed":true,"name":"quote","type":"address"},{"indexed":false,"name":"mustSkipFee","type":"bool"}],"name":"LogMustSkipFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"walletAddress","type":"address"}],"name":"LogUserAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"walletAddress","type":"address"},{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"balance","type":"uint256"}],"name":"LogWalletDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"walletAddress","type":"address"},{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"balance","type":"uint256"}],"name":"LogWalletWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"makerOrderId","type":"bytes32"},{"indexed":true,"name":"takerOrderId","type":"bytes32"},{"indexed":false,"name":"toMaker","type":"uint256"},{"indexed":false,"name":"toTaker","type":"uint256"}],"name":"LogOrderExecutionSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"orderId","type":"bytes32"},{"indexed":false,"name":"totalOfferRemaining","type":"uint256"},{"indexed":false,"name":"totalWantReceived","type":"uint256"}],"name":"LogOrderFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"errorString","type":"string"}],"name":"LogErrorString","type":"event"}]

Contract Creation Code
608060405234801561001057600080fd5b5060405160e08061474a8339810160409081528151602080840151928401516060850151608086015160a087015160c09097015160018054600160a060020a03808916600160a060020a031992831617909255600280548216331790554360035560048054838b1690831617905560008080527f54cdd369e4e8a8515e52ca72ec816c2101831ad1f18bf44102ed171459c9b4f88790557f6d5257204ebe7d88fd91ae87941cb2dd9d8062b64ae5a2bd2d28ec40b9fbf6df86905560088054848716908416179055600a978890527f13da86008ba1c6922daee3e07db95305ef49ebced9f5467a0b8613fcc6b343e3979097558654828b16911617909555949692949193909291908116151561018757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f57616c6c6574436f6e6e6563746f722061646472657373203d3d203000000000604482015290519081900360640190fd5b60058054600160a060020a03909216600160a060020a031990921691909117905550505050505061458d806101bd6000396000f300608060405260043610620001495763ffffffff60e060020a6000350416631d2627bb81146200014b5780631e57bc4a14620001835780632e16cf5414620001b957806341832bed14620001f95780634983542e14620002a25780634a8ef4bd14620002e957806357b394bf146200030d5780635d09e625146200033757806360bf46ea146200036657806363a3d383146200038d57806369820a8014620003a55780636e3706f414620003bd5780637fa8690614620003f657806384b96e04146200042057806397e364d91462000444578063b5f9b5cc146200045c578063ba2fecec1462000480578063bd09f1171462000498578063c1d5e84f14620004b0578063c825ec9714620004d4578063cfbe2cb31462000589578063d9fc4b6114620005b3578063dff0fae714620005e6578063e7663079146200060a578063f3182d6c1462000622575b005b3480156200015857600080fd5b506200016f600160a060020a03600435166200064c565b604080519115158252519081900360200190f35b3480156200019057600080fd5b50620001a7600160a060020a0360043516620006f1565b60408051918252519081900360200190f35b348015620001c657600080fd5b50620001dd600160a060020a036004351662000703565b60408051600160a060020a039092168252519081900360200190f35b3480156200020657600080fd5b506040805160808181019092526200026591369160049160849190839081908390829080828437505060408051610100818101909252949796958181019594509250600891508390839080828437509396506200082895505050505050565b6040518082600260200280838360005b838110156200028f57818101518382015260200162000275565b5050505090500191505060405180910390f35b348015620002af57600080fd5b506200016f60246004803582810192908201359181358083019290820135916044358083019290820135916064359182019101356200099f565b348015620002f657600080fd5b506200016f600160a060020a036004351662000b2b565b3480156200031a57600080fd5b5062000149600160a060020a036004351660243560443562000bc7565b3480156200034457600080fd5b506200016f600160a060020a0360043581169060243516604435151562000c18565b3480156200037357600080fd5b506200016f600160a060020a036004351660243562000d00565b3480156200039a57600080fd5b50620001dd62000dce565b348015620003b257600080fd5b50620001a762000ddd565b348015620003ca57600080fd5b50620003d860043562000de3565b60408051938452602084019290925282820152519081900360600190f35b3480156200040357600080fd5b506200016f600160a060020a036004358116906024351662000e04565b3480156200042d57600080fd5b50620001a7600160a060020a036004351662000e24565b3480156200045157600080fd5b50620001dd62000e36565b3480156200046957600080fd5b50620001dd600160a060020a036004351662000e45565b3480156200048d57600080fd5b50620001dd62000e60565b348015620004a557600080fd5b50620001dd62000e6f565b348015620004bd57600080fd5b506200016f600160a060020a036004351662000e7e565b348015620004e157600080fd5b506040805160808181019092526200016f91369160049160849190839081908390829080828437505060408051610100818101909252949796958181019594509250600891508390839080828437505060408051808201825294979695818101959450925060029150839083908082843750506040805160808181019092529497969581810195945092506004915083908390808284375093965062000fd795505050505050565b3480156200059657600080fd5b5062000149600160a060020a036004351660243560443562001b93565b348015620005c057600080fd5b506200016f600160a060020a036004358116906024358116906044351660643562001be4565b348015620005f357600080fd5b50620001a7600160a060020a036004351662001ca9565b3480156200061757600080fd5b50620001dd62001cbb565b3480156200062f57600080fd5b506200016f600160a060020a036004351660243560443562001cca565b600254600090600160a060020a03163314620006c057620006b8606060405190810160405280602e81526020016000805160206200454283398151915281526020017f744569646f6f57616c6c6574282900000000000000000000000000000000000081525062001e28565b9050620006ec565b506008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03831617905560015b919050565b600a6020526000908152604090205481565b600160a060020a038082166000908152600c60205260409020541680158015620007375750600054600160a060020a031615155b15620006ec5760008054604080517fb5f9b5cc000000000000000000000000000000000000000000000000000000008152600160a060020a0386811660048301529151919092169263b5f9b5cc92602480820193602093909283900390910190829087803b158015620007a957600080fd5b505af1158015620007be573d6000803e3d6000fd5b505050506040513d6020811015620007d557600080fd5b50519050600160a060020a03811615620006ec57600160a060020a039182166000908152600c60205260409020805473ffffffffffffffffffffffffffffffffffffffff19169282169290921790915590565b6200083262003b0d565b6000803085826020020151866001602002015186600060200201518860036020020151886001602002015189600460200201518a60056020020151604080516c01000000000000000000000000600160a060020a039a8b1681028252988a168902601482015296891688026028880152603c87019590955292909616909402605c8401526070830193909352609082019390935260b081019190915290519081900360d00190209150308560026020020151866003602002015186600260200201518860016020020151886003602002015189600660200201518a600760209081029190910151604080516c01000000000000000000000000600160a060020a039b8c1681028252998b168a026014820152978a1689026028890152603c88019690965293909716909502605c8501526070840152609083019390935260b082019290925281519081900360d001812081830190925284815291820181905290935090505b505092915050565b6000805b8681101562000b1b5762000a958a8a83818110620009bd57fe5b9050608002016004806020026040519081016040528092919082600460200280828437508d93508c925086915050818110620009f557fe5b905061010002016008806020026040519081016040528092919082600860200280828437508c93508b92508791505081811062000a2e57fe5b9050604002016002806020026040519081016040528092919082600260200280828437508b93508a92508891505081811062000a6657fe5b90506080020160048060200260405190810160405280929190826004602002808284375062000fd79350505050565b151562000b12576040805160e560020a62461bcd02815260206004820152603260248201527f43616e6e6f742065786563757465206f726465722c2045786368616e67652e6260448201527f61746368457865637574654f7264657228290000000000000000000000000000606482015290519081900360840190fd5b600101620009a3565b5060019998505050505050505050565b600254600090600160a060020a0316331462000b9757620006b8606060405190810160405280603281526020016000805160206200454283398151915281526020017f744f72646572426f6f6b41636f756e742829000000000000000000000000000081525062001e28565b5060018054600160a060020a03831673ffffffffffffffffffffffffffffffffffffffff19909116178155919050565b60408051600160a060020a038516815260208101849052808201839052905133917fe8d885fd2147a6ac7d644cd3c3a5f2413dbd8e515b61702b1cc1551188176b3c919081900360600190a2505050565b600254600090600160a060020a0316331462000c8c5762000c84606060405190810160405280602e81526020016000805160206200454283398151915281526020017f744d757374536b6970466565282900000000000000000000000000000000000081525062001e28565b905062000cf9565b600160a060020a03848116600081815260096020908152604080832094881680845294825291829020805460ff1916871515908117909155825190815291517f4eba14c78c101c2e2b3b430030103c27bd9ce14c04b7747ffb8b3b4cdeb948b49281900390910190a35060015b9392505050565b600254600090600160a060020a0316331462000d745762000d6c606060405190810160405280603081526020016000805160206200454283398151915281526020017f7451756f74655072696f7269747928290000000000000000000000000000000081525062001e28565b905062000dc8565b600160a060020a0383166000818152600a6020908152604091829020859055815185815291517fadba5bc51f565bc23062c2968481f023e22fd162f18b0146ff7e9393ffd2ed409281900390910190a25060015b92915050565b600454600160a060020a031681565b60035481565b600b6020526000908152604090208054600182015460029092015490919083565b600960209081526000928352604080842090915290825290205460ff1681565b60066020526000908152604090205481565b600554600160a060020a031681565b600c60205260009081526040902054600160a060020a031681565b600054600160a060020a031681565b600854600160a060020a031681565b6000808062000e8d8462000703565b600160a060020a03161462000f0b5762000f03606060405190810160405280602a81526020017f5573657220616c7265616479206578697374732c2045786368616e67652e616481526020017f644e65775573657228290000000000000000000000000000000000000000000081525062001e28565b915062000fd1565b6005548390600160a060020a031662000f2362003b28565b600160a060020a03928316815291166020820152604080519182900301906000f08015801562000f57573d6000803e3d6000fd5b50600160a060020a038481166000818152600c6020908152604091829020805473ffffffffffffffffffffffffffffffffffffffff191694861694851790558151938452905193945090927f341c3eb6378732c9923fd02ea04564f599626c0f9b3fc49526dfd712d7cf7a549281900390910190a2600191505b50919050565b600062000fe362003b0d565b62000fed62003b0d565b62000ff762003b39565b6200100162003b39565b6200100b62003b5b565b6200101562003b5b565b6200101f62003b0d565b60408051808201909152600090806200103f8f845b602002015162000703565b600160a060020a031681526020016200105a8f600262001034565b600160a060020a03169052805160208201519199506200107e918f918f9162001ece565b1515620010f457620010ec606060405190810160405280602981526020017f496e70757420697320696e76616c69642c2045786368616e67652e657865637581526020017f74654f726465722829000000000000000000000000000000000000000000000081525062001e28565b985062001b83565b620011008d8d62000828565b8d5181518d518d51939a506200111f938e60015b602002015162002326565b15156200118d57620010ec606060405190810160405280603381526020017f4d616b6572207369676e617475726520697320696e76616c69642c204578636881526020017f616e67652e657865637574654f7264657228290000000000000000000000000081525062001e28565b6040808e0151602089810151908e0151928d0151620011b093908e600362001114565b15156200121e57620010ec606060405190810160405280603381526020017f54616b6572207369676e617475726520697320696e76616c69642c204578636881526020017f616e67652e657865637574654f7264657228290000000000000000000000000081525062001e28565b86516000908152600b60208181526040808420815160608101835281548152600180830154948201949094526002909101549181019190915298509091908990602090810291909101518252818101929092526040908101600020815160608101835281548152600180830154948201949094526002909101549181019190915295508d906020020151600160a060020a031684528b600060209081029190910151908501528c60036020020151600160a060020a031660608501528b6001602002015160808501528551600010156200137f57604086015115156200136557620010ec606060405190810160405280603081526020017f4d616b6572206f7264657220697320696e6163746976652c2045786368616e6781526020017f652e657865637574654f7264657228290000000000000000000000000000000081525062001e28565b60408087015190850152602086015160a085015262001395565b8b516040850152600060a085015260808c015186525b6060808e0151600160a060020a03908116855260408e01516020868101919091528f015116848201528c015160808401528451600010156200145e57604085015115156200144457620010ec606060405190810160405280603081526020017f54616b6572206f7264657220697320696e6163746976652c2045786368616e6781526020017f652e657865637574654f7264657228290000000000000000000000000000000081525062001e28565b60408086015190840152602085015160a084015262001477565b6040808d015190840152600060a084015260c08c015185525b6200148384846200244f565b1515620014f157620010ec606060405190810160405280602c81526020017f4f726465727320646f206e6f74206d617463682c2045786368616e67652e657881526020017f65637574654f726465722829000000000000000000000000000000000000000081525062001e28565b620014fd8484620027a3565b80519092506001118062001515575060208201516001115b15620015a857620010ec608060405190810160405280605281526020017f546f6b656e20616d6f756e74203c20312c20707269636520726174696f20697381526020017f20696e76616c69642120546f6b656e2076616c7565203c20312c20457863686181526020017f6e67652e657865637574654f726465722829000000000000000000000000000081525062001e28565b81516020830151620015bc918691620029cb565b6004548451919250600160a060020a0391821691161480156200168157506020820151620015ec90829062002aee565b600454600160a060020a03166370a082318a600160200201516040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b1580156200165157600080fd5b505af115801562001666573d6000803e3d6000fd5b505050506040513d60208110156200167d57600080fd5b5051105b156200173a57620010ec60a060405190810160405280606381526020017f54616b65722068617320616e20696e73756666696369656e742045444f20746f81526020017f6b656e2062616c616e636520746f20636f766572207468652066656520414e4481526020017f20746865206f666665722c2045786368616e67652e657865637574654f72646581526020017f722829000000000000000000000000000000000000000000000000000000000081525062001e28565b6004548190600160a060020a03166370a082318a600160200201516040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b158015620017a157600080fd5b505af1158015620017b6573d6000803e3d6000fd5b505050506040513d6020811015620017cd57600080fd5b505110156200186357620010ec608060405190810160405280605581526020017f54616b65722068617320616e20696e73756666696369656e742045444f20746f81526020017f6b656e2062616c616e636520746f20636f76657220746865206665652c20457881526020017f6368616e67652e657865637574654f726465722829000000000000000000000081525062001e28565b6200188f8d836001602002015184600060200201518b600060200201518c600160200201518662002afe565b1515620018fd57620010ec606060405190810160405280603f81526020017f4f7264657220636f756c64206e6f74206265207665726966696564206279207781526020017f616c6c6574732c2045786368616e67652e657865637574654f7264657228290081525062001e28565b815160408501516200190f9162002d9c565b6040870152602082015160a0850151620019299162002aee565b60208701526200194c826001602002015160408501519063ffffffff62002d9c16565b6040860152815160a0840151620019639162002aee565b60208681019190915287516000908152600b80835260408083208a518155938a0151600180860191909155908a015160029094019390935587929091908a9060209081029190910151825281810192909252604090810160009081208451815592840151600184015592015160029091015562001a02908e90849060200201518460016020020151848c600060200201518d6001602002015162002daf565b151562001aa5576040805160e560020a62461bcd02815260206004820152604260248201527f43616e6e6f74206578656375746520746f6b656e207472616e736665722c204560448201527f786368616e67652e5f5f65786563757465546f6b656e5472616e736665725f5f60648201527f2829000000000000000000000000000000000000000000000000000000000000608482015290519081900360a40190fd5b865160408088015160208981015183519283529082015281517fbc99ec61d80589c90dda14a2b09b9d0ddcdd61292e3745b9967c10bdd131d952929181900390910190a260208088015160408088015188840151825191825293810193909352805191927fbc99ec61d80589c90dda14a2b09b9d0ddcdd61292e3745b9967c10bdd131d952929081900390910190a2602080880151885184830151855160408051928352948201528351929391927f33f1634e907a90025026a538736ad65b4c862890df9e35a35c67cd55b0cfc8d0929181900390910190a3600198505b5050505050505050949350505050565b60408051600160a060020a038516815260208101849052808201839052905133917f0ecba04e3ac59da620bc63359f7754b6504cf198bac1987a1ac5123c47cf2a36919081900360600190a2505050565b604080517f23b872dd000000000000000000000000000000000000000000000000000000008152600160a060020a03858116600483015284811660248301526044820184905291516000928716916323b872dd916064808301928692919082900301818387803b15801562001c5857600080fd5b505af115801562001c6d573d6000803e3d6000fd5b505050503d6000811462001c89576020811462001c9457600080fd5b600019915062001ca0565b60206000803e60005191505b50949350505050565b60076020526000908152604090205481565b600254600160a060020a031681565b600254600090600160a060020a0316331462001d365762000c84606060405190810160405280602a81526020016000805160206200454283398151915281526020017f744665655261746528290000000000000000000000000000000000000000000081525062001e28565b600160a060020a0384166000908152600a6020526040902054151562001dbd5762000c84606060405190810160405280603681526020017f71756f74655072696f726974795b5f71756f7465546f6b656e5d203d3d20302c81526020017f2045786368616e67652e7365744665655261746528290000000000000000000081525062001e28565b600160a060020a03841660008181526006602090815260408083208790556007825291829020859055815186815290810185905281517f4087c0a471bb6f7904a5b325dccb8fdfe192681804f34182e0d7b17610a9871f929181900390910190a25060019392505050565b60007f551303dd5f39cbfe6daba6b3e27754b8a7d72f519756a2cde2b92c2bbde159a7826040518080602001828103825283818151815260200191508051906020019080838360005b8381101562001e8b57818101518382015260200162001e71565b50505050905090810190601f16801562001eb95780820380516001836020036101000a031916815260200191505b509250505060405180910390a1506000919050565b600154600090600160a060020a0316331462001f795762001f71608060405190810160405280604781526020017f6d73672e73656e64657220213d206f72646572426f6f6b4163636f756e742c2081526020017f45786368616e67652e5f5f657865637574654f72646572496e7075744973566181526020017f6c69645f5f28290000000000000000000000000000000000000000000000000081525062001e28565b90506200231e565b608084015143111562001fed5762001f71606060405190810160405280604081526020017f4d616b6572206f726465722068617320657870697265642c2045786368616e6781526020017f652e5f5f657865637574654f72646572496e707574497356616c69645f5f282981525062001e28565b60c0840151431115620020615762001f71606060405190810160405280604081526020017f54616b6572206f726465722068617320657870697265642c2045786368616e6781526020017f652e5f5f657865637574654f72646572496e707574497356616c69645f5f282981525062001e28565b600160a060020a0383161515620020e95762001f71608060405190810160405280604481526020017f4d616b65722077616c6c657420646f6573206e6f742065786973742c2045786381526020017f68616e67652e5f5f657865637574654f72646572496e707574497356616c6964815260200160e060020a635f5f28290281525062001e28565b600160a060020a0382161515620021715762001f71608060405190810160405280604481526020017f54616b65722077616c6c657420646f6573206e6f742065786973742c2045786381526020017f68616e67652e5f5f657865637574654f72646572496e707574497356616c6964815260200160e060020a635f5f28290281525062001e28565b6060850151600160a060020a039081166000908152600a60209081526040808320549189015190931682529190205414156200225a5762001f7160a060405190810160405280606c81526020017f51756f746520746f6b656e206973206f6d697474656421204973206e6f74206f81526020017f66666572656420627920656974686572207468652054616b6572206f72204d6181526020017f6b65722c2045786368616e67652e5f5f657865637574654f72646572496e707581526020017f74497356616c69645f5f2829000000000000000000000000000000000000000081525062001e28565b835115806200226b57506020840151155b806200227957506040840151155b806200228757506060840151155b156200231a5762001f71608060405190810160405280605981526020017f4d6179206e6f74206578656375746520616e206f72646572207768657265207481526020017f6f6b656e20616d6f756e74203d3d20302c2045786368616e67652e5f5f65786581526020017f637574654f72646572496e707574497356616c69645f5f28290000000000000081525062001e28565b5060015b949350505050565b60008060018660405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c0182600019166000191681526020019150506040516020818303038152906040526040518082805190602001908083835b60208310620023ac5780518252601f1990920191602091820191016200238b565b51815160209384036101000a60001901801990921691161790526040805192909401829003822060008084528383018087529190915260ff8d1683860152606083018c9052608083018b9052935160a08084019750919550601f1981019492819003909101925090865af115801562002429573d6000803e3d6000fd5b5050604051601f190151600160a060020a03908116981697909714979650505050505050565b60008060008360000151600160a060020a03168560600151600160a060020a03161415156200250d5762002505608060405190810160405280605c81526020017f4d616b65722077616e74656420746f6b656e20646f6573206e6f74206d61746381526020017f682074616b6572206f6666657220746f6b656e2c2045786368616e67652e5f5f81526020017f6f72646572734d617463685f616e645f4172655661696c645f5f28290000000081525062001e28565b925062000997565b60608401518551600160a060020a03908116911614620025b45762002505608060405190810160405280605c81526020017f4d616b6572206f6666657220746f6b656e20646f6573206e6f74206d6174636881526020017f2074616b65722077616e74656420746f6b656e2c2045786368616e67652e5f5f81526020017f6f72646572734d617463685f616e645f4172655661696c645f5f28290000000081525062001e28565b6080850151602086015110620026bd57620025f78560800151620025ea608060020a88602001516200382390919063ffffffff16565b9063ffffffff6200384a16565b91506200261f8460200151620025ea608060020a87608001516200382390919063ffffffff16565b905080821015620026b75762002505608060405190810160405280605081526020017f54616b65722070726963652069732067726561746572207468616e206d616b6581526020017f722070726963652c2045786368616e67652e5f5f6f72646572734d617463685f81526020017f616e645f4172655661696c645f5f28290000000000000000000000000000000081525062001e28565b6200231a565b620026e38560200151620025ea608060020a88608001516200382390919063ffffffff16565b91506200270b8460800151620025ea608060020a87602001516200382390919063ffffffff16565b9050808211156200231a5762002505608060405190810160405280604d81526020017f54616b6572207072696365206973206c657373207468616e206d616b6572207081526020017f726963652c2045786368616e67652e5f5f6f72646572734d617463685f616e6481526020017f5f4172655661696c645f5f28290000000000000000000000000000000000000081525062001e28565b620027ad62003b0d565b600080600080600080620027c18862003862565b955088608001518960200151101515620028cb57620027fb8960800151620025ea608060020a8c602001516200382390919063ffffffff16565b94508515620028785760a089015160808a01516200281f9163ffffffff62002d9c16565b9350620028318860400151856200388f565b905062002870608060020a620025ea6fffffffffffffffffffffffffffffffff62002863858a63ffffffff6200382316565b9063ffffffff62002aee16565b9150620028c5565b60a08801516080890151620028939163ffffffff62002d9c16565b9250620028a58960400151846200388f565b9150620028c285620025ea84608060020a63ffffffff6200382316565b90505b620029ae565b620028f18960200151620025ea608060020a8c608001516200382390919063ffffffff16565b945085156200294c5760a089015160808a0151620029159163ffffffff62002d9c16565b9350620029278860400151856200388f565b90506200294485620025ea83608060020a63ffffffff6200382316565b9150620029ae565b60a08801516080890151620029679163ffffffff62002d9c16565b9250620029798960400151846200388f565b9150620029ab608060020a620025ea6fffffffffffffffffffffffffffffffff62002863868a63ffffffff6200382316565b90505b604080518082019091529182526020820152979650505050505050565b6000620029d88462003862565b151562002a6d576060840151600160a060020a03908116600090815260096020908152604080832088519094168352929052205460ff1662002a64578351600160a060020a0390811660009081526007602090815260408083205488519094168352600690915290205462002a5e91600a0a90620025ea90869063ffffffff6200382316565b62000c84565b50600062000cf9565b8351600160a060020a03908116600090815260096020908152604080832060608901519094168352929052205460ff1662002a6457606084018051600160a060020a039081166000908152600760209081526040808320549451909316825260069052205462002a5e91600a0a90620025ea90859063ffffffff6200382316565b60008282018381101562000cf957fe5b602080870151604080517f4e7343ea000000000000000000000000000000000000000000000000000000008152600160a060020a03928316600482015260248101889052600060448201819052606482018190529151919392871692634e7343ea9260848084019382900301818787803b15801562002b7c57600080fd5b505af115801562002b91573d6000803e3d6000fd5b505050506040513d602081101562002ba857600080fd5b5051151562002c465762002c3e608060405190810160405280605381526020017f4d616b65722077616c6c657420636f756c64206e6f742076657269667920746881526020017f65206f726465722c2045786368616e67652e5f5f5f5f6f72646572735665726981526020017f66696564427957616c6c6574735f5f5f5f28290000000000000000000000000081525062001e28565b905062002d92565b606087015160048054604080517f4e7343ea000000000000000000000000000000000000000000000000000000008152600160a060020a0394851693810193909352602483018a90526044830186905290831660648301525191851691634e7343ea916084808201926020929091908290030181600087803b15801562002ccc57600080fd5b505af115801562002ce1573d6000803e3d6000fd5b505050506040513d602081101562002cf857600080fd5b5051151562002d8e5762002c3e608060405190810160405280605381526020017f54616b65722077616c6c657420636f756c64206e6f742076657269667920746881526020017f65206f726465722c2045786368616e67652e5f5f5f5f6f72646572735665726981526020017f66696564427957616c6c6574735f5f5f5f28290000000000000000000000000081525062001e28565b5060015b9695505050505050565b60008282111562002da957fe5b50900390565b602086015160608701516000919085156200306c57600480546040805160e060020a6341228803028152600160a060020a03928316938101939093526024830189905260016044840152519086169163412288039160648083019260209291908290030181600087803b15801562002e2657600080fd5b505af115801562002e3b573d6000803e3d6000fd5b505050506040513d602081101562002e5257600080fd5b5051151562002ef7576040805160e560020a62461bcd02815260206004820152605860248201527f54616b65722074726164696e672077616c6c65742063616e6e6f74207570646160448201527f74652062616c616e63652077697468206665652c2045786368616e67652e5f5f60648201527f65786563757465546f6b656e5472616e736665725f5f28290000000000000000608482015290519081900360a40190fd5b60048054600854604080517f23b872dd000000000000000000000000000000000000000000000000000000008152600160a060020a03898116958201959095529184166024830152604482018a90525192909116916323b872dd916064808201926020929091908290030181600087803b15801562002f7557600080fd5b505af115801562002f8a573d6000803e3d6000fd5b505050506040513d602081101562002fa157600080fd5b505115156200306c576040805160e560020a62461bcd02815260206004820152606360248201527f43616e6e6f74207472616e7366657220666565732066726f6d2074616b65722060448201527f74726164696e672077616c6c657420746f206569646f6f2077616c6c65742c2060648201527f45786368616e67652e5f5f65786563757465546f6b656e5472616e736665725f60848201527f5f2829000000000000000000000000000000000000000000000000000000000060a482015290519081900360c40190fd5b6040805160e060020a6341228803028152600160a060020a038481166004830152602482018b9052600160448301529151918716916341228803916064808201926020929091908290030181600087803b158015620030ca57600080fd5b505af1158015620030df573d6000803e3d6000fd5b505050506040513d6020811015620030f657600080fd5b50511515620031c1576040805160e560020a62461bcd02815260206004820152606960248201527f4d616b65722074726164696e672077616c6c65742063616e6e6f74207570646160448201527f74652062616c616e6365207375627472616374696e6720746f54616b6572416d60648201527f6f756e742c2045786368616e67652e5f5f65786563757465546f6b656e54726160848201527f6e736665725f5f2829000000000000000000000000000000000000000000000060a482015290519081900360c40190fd5b6040805160e060020a6341228803028152600160a060020a038481166004830152602482018b9052600060448301819052925190871692634122880392606480820193602093909283900390910190829087803b1580156200322257600080fd5b505af115801562003237573d6000803e3d6000fd5b505050506040513d60208110156200324e57600080fd5b5051151562003304576040805160e560020a62461bcd028152602060048201526064602482018190527f54616b65722074726164696e672077616c6c65742063616e6e6f74207570646160448301527f74652062616c616e636520616464696e6720746f54616b6572416d6f756e742c908201527f2045786368616e67652e5f5f65786563757465546f6b656e5472616e73666572608482015260e060020a635f5f28290260a482015290519081900360c40190fd5b6040805160e060020a6341228803028152600160a060020a038381166004830152602482018a9052600160448301529151918616916341228803916064808201926020929091908290030181600087803b1580156200336257600080fd5b505af115801562003377573d6000803e3d6000fd5b505050506040513d60208110156200338e57600080fd5b5051151562003459576040805160e560020a62461bcd02815260206004820152606960248201527f54616b65722074726164696e672077616c6c65742063616e6e6f74207570646160448201527f74652062616c616e6365207375627472616374696e6720746f4d616b6572416d60648201527f6f756e742c2045786368616e67652e5f5f65786563757465546f6b656e54726160848201527f6e736665725f5f2829000000000000000000000000000000000000000000000060a482015290519081900360c40190fd5b6040805160e060020a6341228803028152600160a060020a038381166004830152602482018a9052600060448301819052925190881692634122880392606480820193602093909283900390910190829087803b158015620034ba57600080fd5b505af1158015620034cf573d6000803e3d6000fd5b505050506040513d6020811015620034e657600080fd5b505115156200359c576040805160e560020a62461bcd028152602060048201526064602482018190527f4d616b65722074726164696e672077616c6c65742063616e6e6f74207570646160448301527f74652062616c616e636520616464696e6720746f4d616b6572416d6f756e742c908201527f2045786368616e67652e5f5f65786563757465546f6b656e5472616e73666572608482015260e060020a635f5f28290260a482015290519081900360c40190fd5b600160a060020a0382161515620035eb57604051600160a060020a0385169089156108fc02908a906000818181858888f19350505050158015620035e4573d6000803e3d6000fd5b50620036d8565b620035f98286868b62001be4565b1515620036c2576040805160e560020a62461bcd02815260206004820152606c60248201527f546f6b656e207472616e73666572736869702066726f6d206d616b657254726160448201527f64696e6757616c6c657420746f2074616b657254726164696e6757616c6c657460648201527f206661696c65642c2045786368616e67652e5f5f65786563757465546f6b656e60848201527f5472616e736665725f5f2829000000000000000000000000000000000000000060a482015290519081900360c40190fd5b620036cf858584620038a7565b1515620036d857fe5b600160a060020a03811615156200372757604051600160a060020a0386169088156108fc029089906000818181858888f1935050505015801562003720573d6000803e3d6000fd5b5062003814565b620037358185878a62001be4565b1515620037fe576040805160e560020a62461bcd02815260206004820152606c60248201527f546f6b656e207472616e73666572736869702066726f6d2074616b657254726160448201527f64696e6757616c6c657420746f206d616b657254726164696e6757616c6c657460648201527f206661696c65642c2045786368616e67652e5f5f65786563757465546f6b656e60848201527f5472616e736665725f5f2829000000000000000000000000000000000000000060a482015290519081900360c40190fd5b6200380b858583620038a7565b15156200381457fe5b50600198975050505050505050565b60008282028315806200384157508284828115156200383e57fe5b04145b151562000cf957fe5b60008082848115156200385957fe5b04949350505050565b6060810151600160a060020a039081166000908152600a6020526040808220549351909216815220541090565b6000818310620038a0578162000cf9565b5090919050565b600083600160a060020a03166370a08231836040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b1580156200390557600080fd5b505af11580156200391a573d6000803e3d6000fd5b505050506040513d60208110156200393157600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152600160a060020a0387811660048301529151918516916370a08231916024808201926020929091908290030181600087803b1580156200399957600080fd5b505af1158015620039ae573d6000803e3d6000fd5b505050506040513d6020811015620039c557600080fd5b505114620039d65750600062000cf9565b82600160a060020a03166370a08231836040518263ffffffff1660e060020a0281526004018082600160a060020a0316600160a060020a03168152602001915050602060405180830381600087803b15801562003a3257600080fd5b505af115801562003a47573d6000803e3d6000fd5b505050506040513d602081101562003a5e57600080fd5b5051604080517f70a08231000000000000000000000000000000000000000000000000000000008152600160a060020a0386811660048301529151918516916370a08231916024808201926020929091908290030181600087803b15801562003ac657600080fd5b505af115801562003adb573d6000803e3d6000fd5b505050506040513d602081101562003af257600080fd5b50511462003b035750600062000cf9565b5060019392505050565b60408051808201825290600290829080388339509192915050565b60405161099d8062003ba583390190565b6060604051908101604052806000815260200160008152602001600081525090565b60c0604051908101604052806000600160a060020a0316815260200160008152602001600081526020016000600160a060020a03168152602001600081526020016000815250905600608060405234801561001057600080fd5b5060405160408061099d833981016040818152825160209384015160008054600160a060020a03808516600160a060020a03199283161783556005805482861690841617908190556001805490931633179092557facfdd2c500000000000000000000000000000000000000000000000000000000875294519396929594169363acfdd2c5936004808301949391928390030190829087803b1580156100b557600080fd5b505af11580156100c9573d6000803e3d6000fd5b505050506040513d60208110156100df57600080fd5b505160038054600160a060020a031916600160a060020a03909216919091179055505043600455610888806101156000396000f3006080604052600436106100ab5763ffffffff60e060020a6000350416632039d9fd81146100c457806322d40b13146100fc578063412288031461012d5780634e7343ea14610156578063648a0c911461018557806369820a80146101a657806370a08231146101cd57806398ea5fca146101ee578063c0668179146101f6578063d767ee4d1461020b578063e766307914610223578063f3fef3a314610238578063f6b1b18b1461025c575b600154600160a060020a031633146100c257600080fd5b005b3480156100d057600080fd5b506100e8600160a060020a036004351660243561027d565b604080519115158252519081900360200190f35b34801561010857600080fd5b506101116103b7565b60408051600160a060020a039092168252519081900360200190f35b34801561013957600080fd5b506100e8600160a060020a036004351660243560443515156103c6565b34801561016257600080fd5b506100e8600160a060020a036004358116906024359060443590606435166103c6565b34801561019157600080fd5b506100e8600160a060020a03600435166103e0565b3480156101b257600080fd5b506101bb61048e565b60408051918252519081900360200190f35b3480156101d957600080fd5b506101bb600160a060020a0360043516610494565b6100c26104af565b34801561020257600080fd5b5061011161053b565b34801561021757600080fd5b506100e860043561054a565b34801561022f57600080fd5b50610111610708565b34801561024457600080fd5b506100e8600160a060020a0360043516602435610717565b34801561026857600080fd5b506101bb600160a060020a03600435166107a7565b6000600160a060020a03831615156103215761031a608060405190810160405280604181526020017f43616e6e6f74206465706f73697420657468657220766961206465706f73697481526020017f45524332302c2057616c6c65742e6465706f7369744552433230546f6b656e2881526020017f29000000000000000000000000000000000000000000000000000000000000008152506107b9565b90506103b1565b600354604080517f6465706f73697428616464726573732c75696e743235362900000000000000008152815190819003601801812063ffffffff60e060020a918290049081169091028252600160a060020a03878116600484015260248301879052925192909316929160448083019260009291908290030181865af49250505015156103ad57600080fd5b5060015b92915050565b600354600160a060020a031681565b6000366000604037602060003660406003545af460206000f35b60008054600160a060020a0316331461045f57610458606060405190810160405280602d81526020017f6d73672e73656e64657220213d206f776e65725f2c2057616c6c65742e75706481526020017f61746545786368616e67652829000000000000000000000000000000000000008152506107b9565b9050610489565b506001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161781555b919050565b60045481565b600160a060020a031660009081526002602052604090205490565b600354604080517f6465706f73697428616464726573732c75696e743235362900000000000000008152815190819003601801812063ffffffff60e060020a9182900490811690910282526000600483018190523460248401529251600160a060020a039094169390926044808401939192918290030181865af492505050151561053957600080fd5b565b600154600160a060020a031681565b600080548190600160a060020a031633146105cb576105c4606060405190810160405280602a81526020017f6d73672e73656e64657220213d206f776e65725f2c2057616c6c65742e75706481526020017f6174654c6f6769632829000000000000000000000000000000000000000000008152506107b9565b9150610702565b600554604080517fd526d332000000000000000000000000000000000000000000000000000000008152600481018690529051600160a060020a039092169163d526d332916024808201926020929091908290030181600087803b15801561063257600080fd5b505af1158015610646573d6000803e3d6000fd5b505050506040513d602081101561065c57600080fd5b50519050600160a060020a03811615156106d5576105c4606060405190810160405280602581526020017f496e76616c69642076657273696f6e2c2057616c6c65742e7570646174654c6f81526020017f67696328290000000000000000000000000000000000000000000000000000008152506107b9565b6003805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038316179055600191505b50919050565b600054600160a060020a031681565b60008054600160a060020a0316331461078f5761031a606060405190810160405280602681526020017f6d73672e73656e64657220213d206f776e65722c2057616c6c65742e7769746881526020017f64726177282900000000000000000000000000000000000000000000000000008152506107b9565b366000604037602060003660406003545af460206000f35b60026020526000908152604090205481565b60007f551303dd5f39cbfe6daba6b3e27754b8a7d72f519756a2cde2b92c2bbde159a7826040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081a578181015183820152602001610802565b50505050905090810190601f1680156108475780820380516001836020036101000a031916815260200191505b509250505060405180910390a15060009190505600a165627a7a7230582043b086d6774163e8090d8e83bbedc2efb6cd81da046f89c36eadd97a1290289500296d73672e73656e64657220213d206f776e65722c2045786368616e67652e7365a165627a7a723058201b78e72f81af3ef1bff7cd5a611071ab45a834e77b9e50fc9c35d503ec9feec500290000000000000000000000008725e59eef18409273fa50662e7c1b671e368a86000000000000000000000000ced4e93198734ddaff8492d525bd258d49eb388e00000000000000000000000000000000000000000000000000000000000c3500000000000000000000000000000000000000000000000000000000000000000600000000000000000000000006504d6f4cb6ec9cff5675c515212ebd17c3d83f000000000000000000000000df72b12a5f7f5a02e9949c475a8d90694d10f19800000000000000000000000003d6e7b2f48120fd57a89ff0bbd56e9ec39af21c


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

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000008725e59eef18409273fa50662e7c1b671e368a86
Arg [1] : 000000000000000000000000ced4e93198734ddaff8492d525bd258d49eb388e
Arg [2] : 00000000000000000000000000000000000000000000000000000000000c3500
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [4] : 00000000000000000000000006504d6f4cb6ec9cff5675c515212ebd17c3d83f
Arg [5] : 000000000000000000000000df72b12a5f7f5a02e9949c475a8d90694d10f198
Arg [6] : 00000000000000000000000003d6e7b2f48120fd57a89ff0bbd56e9ec39af21c


   Swarm Source:
bzzr://1b78e72f81af3ef1bff7cd5a611071ab45a834e77b9e50fc9c35d503ec9feec5
Block Age transaction Difficulty GasUsed Reward
Block Age Uncle Number Difficulty GasUsed Reward
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.