ETH Price: $2,584.23 (-4.32%)

Contract

0x66EAd8d4EFA8eFB8413AE489207b929924298cEA
 

Overview

ETH Balance

0.000000049999895 ETH

Eth Value

Less Than $0.01 (@ $2,584.23/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw130585632021-08-19 22:53:531268 days ago1629413633IN
0x66EAd8d4...924298cEA
0 ETH0.0021985742
Withdraw115697472021-01-01 17:11:221498 days ago1609521082IN
0x66EAd8d4...924298cEA
0 ETH0.0041076688
Deposit ERC20Tok...115451772020-12-28 22:32:351502 days ago1609194755IN
0x66EAd8d4...924298cEA
0 ETH0.004961563
Withdraw114586932020-12-15 16:21:501515 days ago1608049310IN
0x66EAd8d4...924298cEA
0 ETH0.0050282577
Update Exchange104643532020-07-15 13:27:501668 days ago1594819670IN
0x66EAd8d4...924298cEA
0 ETH0.0018341164
Withdraw100595412020-05-13 18:55:291731 days ago1589396129IN
0x66EAd8d4...924298cEA
0 ETH0.0012324417
Update Logic88348972019-10-29 15:57:261928 days ago1572364646IN
0x66EAd8d4...924298cEA
0 ETH0.0004542615
Deposit ERC20Tok...84080182019-08-23 18:00:551995 days ago1566583255IN
0x66EAd8d4...924298cEA
0 ETH0.000489446.5
Update Exchange83758952019-08-18 18:08:092000 days ago1566151689IN
0x66EAd8d4...924298cEA
0 ETH0.000086123.0003
Withdraw78425242019-05-27 15:31:162083 days ago1558971076IN
0x66EAd8d4...924298cEA
0 ETH0.0004553213
Deposit ERC20Tok...78296022019-05-25 15:28:372085 days ago1558798117IN
0x66EAd8d4...924298cEA
0 ETH0.0007381610
Withdraw78116442019-05-22 20:14:282088 days ago1558556068IN
0x66EAd8d4...924298cEA
0 ETH0.0027171719
Withdraw78116382019-05-22 20:13:412088 days ago1558556021IN
0x66EAd8d4...924298cEA
0 ETH0.0006933119
Deposit ERC20Tok...78111322019-05-22 18:12:202088 days ago1558548740IN
0x66EAd8d4...924298cEA
0 ETH0.001642710
Deposit Ether77935472019-05-19 23:45:072090 days ago1558309507IN
0x66EAd8d4...924298cEA
8 ETH0.000275797.75
Withdraw77672462019-05-15 21:04:172095 days ago1557954257IN
0x66EAd8d4...924298cEA
0 ETH0.0006620613
Deposit Ether77413042019-05-11 20:15:272099 days ago1557605727IN
0x66EAd8d4...924298cEA
6.5 ETH0.000156584.4
Deposit Ether77273842019-05-09 16:13:112101 days ago1557418391IN
0x66EAd8d4...924298cEA
10 ETH0.00024917
Deposit Ether77270072019-05-09 14:41:432101 days ago1557412903IN
0x66EAd8d4...924298cEA
6 ETH0.00035417
Update Logic74838012019-04-01 17:01:372139 days ago1554138097IN
0x66EAd8d4...924298cEA
0 ETH0.000121134
Update Exchange71052442019-01-21 19:48:362209 days ago1548100116IN
0x66EAd8d4...924298cEA
0 ETH0.000114824

Latest 21 internal transactions

Advanced mode:
Parent Transaction Hash Block
From
To
130585632021-08-19 22:53:531268 days ago1629413633
0x66EAd8d4...924298cEA
0.1799989 ETH
114586932020-12-15 16:21:501515 days ago1608049310
0x66EAd8d4...924298cEA
5.5 ETH
100583352020-05-13 14:30:131731 days ago1589380213
0x66EAd8d4...924298cEA
2.37279208 ETH
100583032020-05-13 14:22:311731 days ago1589379751
0x66EAd8d4...924298cEA
3.18442105 ETH
100582642020-05-13 14:12:551731 days ago1589379175
0x66EAd8d4...924298cEA
3.13526315 ETH
100580542020-05-13 13:24:401731 days ago1589376280
0x66EAd8d4...924298cEA
0.16016018 ETH
100557022020-05-13 4:45:541731 days ago1589345154
0x66EAd8d4...924298cEA
0.13377265 ETH
100553042020-05-13 3:14:001731 days ago1589339640
0x66EAd8d4...924298cEA
0.15975025 ETH
100553042020-05-13 3:14:001731 days ago1589339640
0x66EAd8d4...924298cEA
0.13420731 ETH
100553042020-05-13 3:14:001731 days ago1589339640
0x66EAd8d4...924298cEA
0.10981718 ETH
100553042020-05-13 3:14:001731 days ago1589339640
0x66EAd8d4...924298cEA
0.10981718 ETH
100546662020-05-13 0:54:461731 days ago1589331286
0x66EAd8d4...924298cEA
1 ETH
84115992019-08-24 7:18:401994 days ago1566631120
0x66EAd8d4...924298cEA
7.20933829 ETH
84115972019-08-24 7:18:181994 days ago1566631098
0x66EAd8d4...924298cEA
1.47066171 ETH
84115972019-08-24 7:18:181994 days ago1566631098
0x66EAd8d4...924298cEA
7.5 ETH
78425242019-05-27 15:31:162083 days ago1558971076
0x66EAd8d4...924298cEA
8.566 ETH
77612332019-05-14 22:41:312096 days ago1557873691
0x66EAd8d4...924298cEA
3.5 ETH
77612312019-05-14 22:40:452096 days ago1557873645
0x66EAd8d4...924298cEA
2.5 ETH
77337062019-05-10 16:00:312100 days ago1557504031
0x66EAd8d4...924298cEA
10.034 ETH
77320132019-05-10 9:27:132100 days ago1557480433
0x66EAd8d4...924298cEA
5.9 ETH
67526502018-11-22 16:23:562269 days ago1542903836  Contract Creation0 ETH
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x0409b14c...0cef72662
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Wallet

Compiler Version
v0.4.24+commit.e67f0147

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2018-10-01
*/

pragma solidity ^0.4.15;

/**
 * @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 Wallet 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_;

  // Address updated at deploy time
  WalletConnector private connector_ = WalletConnector(0x03d6e7b2f48120fd57a89ff0bbd56e9ec39af21c);

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

  /**
   * @dev Contract consturtor. 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.
   */
  function Wallet(address _owner) public {
    owner_ = _owner;
    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
    constant
    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;
}


/**
 * @title Decentralized exchange for ether and ERC20 tokens.
 * @author Adam Lemmon <[email protected]>
 * @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.
 */
contract Exchange is LoggingErrors {

  using SafeMath for uint256;

  /**
   * Data Structures
   */
  struct Order {
    bool active_;  // True: active, False: filled or cancelled
    address offerToken_;
    uint256 offerTokenTotal_;
    uint256 offerTokenRemaining_;  // Amount left to give
    address wantToken_;
    uint256 wantTokenTotal_;
    uint256 wantTokenReceived_;  // Amount received, note this may exceed want total
  }

  /**
   * Storage
   */
  address private orderBookAccount_;
  address private owner_;
  uint256 public minOrderEthAmount_;
  uint256 public birthBlock_;
  address public edoToken_;
  uint256 public edoPerWei_;
  uint256 public edoPerWeiDecimals_;
  address public eidooWallet_;
  mapping(bytes32 => Order) public orders_; // Map order hashes to order data struct
  mapping(address => address) public userAccountToWallet_; // User EOA to wallet addresses

  /**
   * Events
   */
  event LogEdoRateSet(uint256 rate);
  event LogOrderExecutionSuccess();
  event LogOrderFilled(bytes32 indexed orderId, uint256 fillAmount, uint256 fillRemaining);
  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);

  /**
   * @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 _minOrderEthAmount Minimum amount of ether that each order must contain.
   * @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.
   */
  function Exchange(
    address _bookAccount,
    uint256 _minOrderEthAmount,
    address _edoToken,
    uint256 _edoPerWei,
    uint256 _edoPerWeiDecimals,
    address _eidooWallet
  ) public {
    orderBookAccount_ = _bookAccount;
    minOrderEthAmount_ = _minOrderEthAmount;
    owner_ = msg.sender;
    birthBlock_ = block.number;
    edoToken_ = _edoToken;
    edoPerWei_ = _edoPerWei;
    edoPerWeiDecimals_ = _edoPerWeiDecimals;
    eidooWallet_ = _eidooWallet;
  }

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

  /**
   * External
   */

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

    // Pass the userAccount address to wallet constructor so owner is not the exchange contract
    address userWallet = new Wallet(_userAccount);

    userAccountToWallet_[_userAccount] = userWallet;

    LogUserAdded(_userAccount, userWallet);

    return true;
  }

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

    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 _token_and_EOA_Addresses The addresses of the maker and taker EOAs and offered token contracts.
   * [makerEOA, makerOfferToken, takerEOA, takerOfferToken]
   * @param _amountsExpirationAndSalt The amount of tokens, [makerOffer, makerWant, takerOffer, takerWant].
   * and the block number at which this order expires
   * and a random number to mitigate replay. [makerExpiry, makerSalt, takerExpiry, takerSalt]
   * @param _sig_v ECDSA signature parameter v, maker 0 and taker 1.
   * @param _sig_r_and_s ECDSA signature parameters r ans s, maker 0, 1 and taker 2, 3.
   * @return Success of the transaction, false if error condition met.
   * Like types grouped to eliminate stack depth error
   */
  function executeOrder (
    address[4] _token_and_EOA_Addresses,
    uint256[8] _amountsExpirationAndSalt, // Packing to save stack size
    uint8[2] _sig_v,
    bytes32[4] _sig_r_and_s
  ) public
    returns(bool)
  {
    // Only read wallet addresses from storage once
    // Need one more stack slot so squashing into array
    Wallet[2] memory wallets = [
      Wallet(userAccountToWallet_[_token_and_EOA_Addresses[0]]), // maker
      Wallet(userAccountToWallet_[_token_and_EOA_Addresses[2]]) // taker
    ];

    // Basic pre-conditions, return if any input data is invalid
    if(!__executeOrderInputIsValid__(
      _token_and_EOA_Addresses,
      _amountsExpirationAndSalt,
      wallets[0],
      wallets[1]
    ))
      return error('Input is invalid, Exchange.executeOrder()');

    // Verify Maker and Taker signatures
    bytes32 makerOrderHash;
    bytes32 takerOrderHash;
    (makerOrderHash, takerOrderHash) = __generateOrderHashes__(_token_and_EOA_Addresses, _amountsExpirationAndSalt);

    if (!__signatureIsValid__(
      _token_and_EOA_Addresses[0],
      makerOrderHash,
      _sig_v[0],
      _sig_r_and_s[0],
      _sig_r_and_s[1]
    ))
      return error('Maker signature is invalid, Exchange.executeOrder()');

    if (!__signatureIsValid__(
      _token_and_EOA_Addresses[2],
      takerOrderHash,
      _sig_v[1],
      _sig_r_and_s[2],
      _sig_r_and_s[3]
    ))
      return error('Taker signature is invalid, Exchange.executeOrder()');

    // Exchange Order Verification and matching.
    Order memory makerOrder = orders_[makerOrderHash];
    Order memory takerOrder = orders_[takerOrderHash];

    if (makerOrder.wantTokenTotal_ == 0) {  // Check for existence
      makerOrder.active_ = true;
      makerOrder.offerToken_ = _token_and_EOA_Addresses[1];
      makerOrder.offerTokenTotal_ = _amountsExpirationAndSalt[0];
      makerOrder.offerTokenRemaining_ = _amountsExpirationAndSalt[0]; // Amount to give
      makerOrder.wantToken_ = _token_and_EOA_Addresses[3];
      makerOrder.wantTokenTotal_ = _amountsExpirationAndSalt[1];
      makerOrder.wantTokenReceived_ = 0; // Amount received
    }

    if (takerOrder.wantTokenTotal_ == 0) {  // Check for existence
      takerOrder.active_ = true;
      takerOrder.offerToken_ = _token_and_EOA_Addresses[3];
      takerOrder.offerTokenTotal_ = _amountsExpirationAndSalt[2];
      takerOrder.offerTokenRemaining_ = _amountsExpirationAndSalt[2];  // Amount to give
      takerOrder.wantToken_ = _token_and_EOA_Addresses[1];
      takerOrder.wantTokenTotal_ = _amountsExpirationAndSalt[3];
      takerOrder.wantTokenReceived_ = 0; // Amount received
    }

    if (!__ordersMatch_and_AreVaild__(makerOrder, takerOrder))
      return error('Orders do not match, Exchange.executeOrder()');

    // Trade amounts
    uint256 toTakerAmount;
    uint256 toMakerAmount;
    (toTakerAmount, toMakerAmount) = __getTradeAmounts__(makerOrder, takerOrder);

    // TODO consider removing. Can this condition be met?
    if (toTakerAmount < 1 || toMakerAmount < 1)
      return error('Token amount < 1, price ratio is invalid! Token value < 1, Exchange.executeOrder()');

    // Taker is offering edo tokens so ensure sufficient balance in order to offer edo and pay fee in edo
    if (
        takerOrder.offerToken_ == edoToken_ &&
        Token(edoToken_).balanceOf(wallets[1]) < __calculateFee__(makerOrder, toTakerAmount, toMakerAmount).add(toMakerAmount)
      ) {
        return error('Taker has an insufficient EDO token balance to cover the fee AND the offer, Exchange.executeOrder()');
    // Taker has sufficent EDO token balance to pay the fee
    } else if (Token(edoToken_).balanceOf(wallets[1]) < __calculateFee__(makerOrder, toTakerAmount, toMakerAmount))
      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__(
        _token_and_EOA_Addresses,
        toMakerAmount,
        toTakerAmount,
        wallets[0],
        wallets[1],
        __calculateFee__(makerOrder, toTakerAmount, toMakerAmount)
      ))
      return error('Order could not be verified by wallets, Exchange.executeOrder()');

    // Order Execution, Order Fully Verified by this point, time to execute!
    // Local order structs
    __updateOrders__(makerOrder, takerOrder, toTakerAmount, toMakerAmount);

    // Write to storage then external calls
    //  Update orders active flag if filled
    if (makerOrder.offerTokenRemaining_ == 0)
      makerOrder.active_ = false;

    if (takerOrder.offerTokenRemaining_ == 0)
      takerOrder.active_ = false;

    // Finally write orders to storage
    orders_[makerOrderHash] = makerOrder;
    orders_[takerOrderHash] = takerOrder;

    // Transfer the external value, ether <> tokens
    require(
      __executeTokenTransfer__(
        _token_and_EOA_Addresses,
        toTakerAmount,
        toMakerAmount,
        __calculateFee__(makerOrder, toTakerAmount, toMakerAmount),
        wallets[0],
        wallets[1]
      )
    );

    // Log the order id(hash), amount of offer given, amount of offer remaining
    LogOrderFilled(makerOrderHash, toTakerAmount, makerOrder.offerTokenRemaining_);
    LogOrderFilled(takerOrderHash, toMakerAmount, takerOrder.offerTokenRemaining_);

    LogOrderExecutionSuccess();

    return true;
  }

  /**
   * @dev Set the rate of wei per edo token in or to calculate edo fee
   * @param _edoPerWei Rate of edo tokens per wei.
   * @return Success of the transaction.
   */
  function setEdoRate(
    uint256 _edoPerWei
  ) external
    returns(bool)
  {
    if (msg.sender != owner_)
      return error('msg.sender != owner, Exchange.setEdoRate()');

    edoPerWei_ = _edoPerWei;

    LogEdoRateSet(edoPerWei_);

    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 the minimum amount of ether required per order.
   * @param _minOrderEthAmount Min amount of ether required per order.
   * @return Success of the transaction.
   */
  function setMinOrderEthAmount (
    uint256 _minOrderEthAmount
  ) external
    returns(bool)
  {
    if (msg.sender != owner_)
      return error('msg.sender != owner, Exchange.setMinOrderEtherAmount()');

    minOrderEthAmount_ = _minOrderEthAmount;

    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;
  }

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

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

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

  /**
   * 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 _toTaker The amount of tokens going to the taker.
   * @param _toMaker The amount of tokens going to the maker.
   * @return The total fee to be paid in EDO tokens.
   */
  function __calculateFee__(
    Order _makerOrder,
    uint256 _toTaker,
    uint256 _toMaker
  ) private
    constant
    returns(uint256)
  {
    // weiAmount * (fee %) * (EDO/Wei) / (decimals in edo/wei) / (decimals in percentage)
    if (_makerOrder.offerToken_ == address(0)) {
      return _toTaker.mul(edoPerWei_).div(10**edoPerWeiDecimals_);
    } else {
      return _toMaker.mul(edoPerWei_).div(10**edoPerWeiDecimals_);
    }
  }

  /**
   * @dev Verify the input to order execution is valid.
   * @param _token_and_EOA_Addresses The addresses of the maker and taker EOAs and offered token contracts.
   * [makerEOA, makerOfferToken, takerEOA, takerOfferToken]
   * @param _amountsExpirationAndSalt The amount of tokens, [makerOffer, makerWant, takerOffer, takerWant].
   * as well as The block number at which this order expires, maker[4] and taker[6].
   * @return Success if all checks pass.
   */
  function __executeOrderInputIsValid__(
    address[4] _token_and_EOA_Addresses,
    uint256[8] _amountsExpirationAndSalt,
    address _makerWallet,
    address _takerWallet
  ) private
    constant
    returns(bool)
  {
    if (msg.sender != orderBookAccount_)
      return error('msg.sender != orderBookAccount, Exchange.__executeOrderInputIsValid__()');

    if (block.number > _amountsExpirationAndSalt[4])
      return error('Maker order has expired, Exchange.__executeOrderInputIsValid__()');

    if (block.number > _amountsExpirationAndSalt[6])
      return error('Taker order has expired, Exchange.__executeOrderInputIsValid__()');

    // Wallets
    if (_makerWallet == address(0))
      return error('Maker wallet does not exist, Exchange.__executeOrderInputIsValid__()');

    if (_takerWallet == address(0))
      return error('Taker wallet does not exist, Exchange.__executeOrderInputIsValid__()');

    // Tokens, addresses and amounts, ether exists
    if (_token_and_EOA_Addresses[1] != address(0) && _token_and_EOA_Addresses[3] != address(0))
      return error('Ether omitted! Is not offered by either the Taker or Maker, Exchange.__executeOrderInputIsValid__()');

    if (_token_and_EOA_Addresses[1] == address(0) && _token_and_EOA_Addresses[3] == address(0))
      return error('Taker and Maker offer token are both ether, Exchange.__executeOrderInputIsValid__()');

    if (
        _amountsExpirationAndSalt[0] == 0 ||
        _amountsExpirationAndSalt[1] == 0 ||
        _amountsExpirationAndSalt[2] == 0 ||
        _amountsExpirationAndSalt[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 _token_and_EOA_Addresses The addresses of the maker and taker EOAs and offered token 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] _token_and_EOA_Addresses,
    uint256 _toTakerAmount,
    uint256 _toMakerAmount,
    uint256 _fee,
    Wallet _makerWallet,
    Wallet _takerWallet
  ) private
    returns (bool)
  {
    // Wallet mapping balances
    address makerOfferToken = _token_and_EOA_Addresses[1];
    address takerOfferToken = _token_and_EOA_Addresses[3];

    // Taker to pay fee before trading
    require(_takerWallet.updateBalance(edoToken_, _fee, true));  // Subtraction flag
    require(Token(edoToken_).transferFrom(_takerWallet, eidooWallet_, _fee));

    // Move the toTakerAmount from the maker to the taker
    require(_makerWallet.updateBalance(makerOfferToken, _toTakerAmount, true));  // Subtraction flag
      /*return error('Unable to subtract maker token from maker wallet, Exchange.__executeTokenTransfer__()');*/

    require(_takerWallet.updateBalance(makerOfferToken, _toTakerAmount, false));
      /*return error('Unable to add maker token to taker wallet, Exchange.__executeTokenTransfer__()');*/

    // Move the toMakerAmount from the taker to the maker
    require(_takerWallet.updateBalance(takerOfferToken, _toMakerAmount, true));  // Subtraction flag
      /*return error('Unable to subtract taker token from taker wallet, Exchange.__executeTokenTransfer__()');*/

    require(_makerWallet.updateBalance(takerOfferToken, _toMakerAmount, false));
      /*return error('Unable to add taker token to maker wallet, Exchange.__executeTokenTransfer__()');*/

    // Contract ether balances and token contract balances
    // Ether to the taker and tokens to the maker
    if (makerOfferToken == address(0)) {
      _takerWallet.transfer(_toTakerAmount);
      require(
        Token(takerOfferToken).transferFrom(_takerWallet, _makerWallet, _toMakerAmount)
      );
      assert(
        __tokenAndWalletBalancesMatch__(_makerWallet, _takerWallet, takerOfferToken)
      );

    // Ether to the maker and tokens to the taker
    } else if (takerOfferToken == address(0)) {
      _makerWallet.transfer(_toMakerAmount);
      require(
        Token(makerOfferToken).transferFrom(_makerWallet, _takerWallet, _toTakerAmount)
      );
      assert(
        __tokenAndWalletBalancesMatch__(_makerWallet, _takerWallet, makerOfferToken)
      );

    // Something went wrong one had to have been ether
    } else revert();

    return true;
  }

  /**
   * @dev compute the log10 of a given number, takes the floor, ie. 2.5 = 2
   * @param _number The number to compute the log 10 of.
   * @return The floored log 10.
   */
  function __flooredLog10__(uint _number)
    public
    constant
    returns (uint256)
  {
    uint unit = 0;
    while (_number / (10**unit) >= 10)
      unit++;
    return unit;
  }

  /**
   * @dev Calculates Keccak-256 hash of order with specified parameters.
   * @param _token_and_EOA_Addresses The addresses of the order, [makerEOA, makerOfferToken, makerWantToken].
   * @param _amountsExpirationAndSalt The amount of tokens as well as
   * the block number at which this order expires and random salt number.
   * @return Keccak-256 hash of each order.
   */
  function __generateOrderHashes__(
    address[4] _token_and_EOA_Addresses,
    uint256[8] _amountsExpirationAndSalt
  ) private
    constant
    returns (bytes32, bytes32)
  {
    bytes32 makerOrderHash = keccak256(
      address(this),
      _token_and_EOA_Addresses[0], // _makerEOA
      _token_and_EOA_Addresses[1], // offerToken
      _amountsExpirationAndSalt[0],  // offerTokenAmount
      _token_and_EOA_Addresses[3], // wantToken
      _amountsExpirationAndSalt[1],  // wantTokenAmount
      _amountsExpirationAndSalt[4], // expiry
      _amountsExpirationAndSalt[5] // salt
    );


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

    return (makerOrderHash, takerOrderHash);
  }

  /**
   * @dev Returns the price ratio for this order.
   * The ratio is calculated with the largest value as the numerator, this aids
   * to significantly reduce rounding errors.
   * @param _makerOrder The maker order data structure.
   * @return The ratio to `_decimals` decimal places.
   */
  function __getOrderPriceRatio__(Order _makerOrder, uint256 _decimals)
    private
    constant
    returns (uint256 orderPriceRatio)
  {
    if (_makerOrder.offerTokenTotal_ >= _makerOrder.wantTokenTotal_) {
      orderPriceRatio = _makerOrder.offerTokenTotal_.mul(10**_decimals).div(_makerOrder.wantTokenTotal_);
    } else {
      orderPriceRatio = _makerOrder.wantTokenTotal_.mul(10**_decimals).div(_makerOrder.offerTokenTotal_);
    }
  }

  /**
   * @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.
   * TODO: consider rounding errors, etc
   */
  function __getTradeAmounts__(
    Order _makerOrder,
    Order _takerOrder
  ) private
    constant
    returns (uint256 toTakerAmount, uint256 toMakerAmount)
  {
    bool ratioIsWeiPerTok = __ratioIsWeiPerTok__(_makerOrder);
    uint256 decimals = __flooredLog10__(__max__(_makerOrder.offerTokenTotal_, _makerOrder.wantTokenTotal_)) + 1;
    uint256 priceRatio = __getOrderPriceRatio__(_makerOrder, decimals);

    // Amount left for order to receive
    uint256 makerAmountLeftToReceive = _makerOrder.wantTokenTotal_.sub(_makerOrder.wantTokenReceived_);
    uint256 takerAmountLeftToReceive = _takerOrder.wantTokenTotal_.sub(_takerOrder.wantTokenReceived_);

    // wei/tok and taker receiving wei or tok/wei and taker receiving tok
    if (
        ratioIsWeiPerTok && _takerOrder.wantToken_ == address(0) ||
        !ratioIsWeiPerTok && _takerOrder.wantToken_ != address(0)
    ) {
      // In the case that the maker is offering more than the taker wants for the same quantity being offered
      // For example: maker offer 20 wei for 10 tokens but taker offers 10 tokens for 10 wei
      // Taker receives 20 wei for the 10 tokens, both orders filled
      if (
        _makerOrder.offerTokenRemaining_ > takerAmountLeftToReceive &&
        makerAmountLeftToReceive <= _takerOrder.offerTokenRemaining_
      ) {
        toTakerAmount = __max__(_makerOrder.offerTokenRemaining_, takerAmountLeftToReceive);
      } else {
        toTakerAmount = __min__(_makerOrder.offerTokenRemaining_, takerAmountLeftToReceive);
      }

      toMakerAmount = toTakerAmount.mul(10**decimals).div(priceRatio);

    // wei/tok and maker receiving wei or tok/wei and maker receiving tok
    } else {
      toMakerAmount = __min__(_takerOrder.offerTokenRemaining_, makerAmountLeftToReceive);
      toTakerAmount = toMakerAmount.mul(10**decimals).div(priceRatio);
    }
  }

  /**
   * @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
    constant
    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
    constant
    returns (uint256)
  {
    return _a < _b ? _a : _b;
  }

  /**
   * @dev Define if the ratio to be used is wei/tok to tok/wei. Largest uint will
   * always act as the numerator.
   * @param _makerOrder The maker order object.
   * @return If the ratio is wei/tok or not.
   */
  function __ratioIsWeiPerTok__(Order _makerOrder)
    private
    constant
    returns (bool)
  {
    bool offerIsWei = _makerOrder.offerToken_ == address(0) ? true : false;

    // wei/tok
    if (offerIsWei && _makerOrder.offerTokenTotal_ >= _makerOrder.wantTokenTotal_) {
      return true;

    } else if (!offerIsWei && _makerOrder.wantTokenTotal_ >= _makerOrder.offerTokenTotal_) {
      return true;

    // tok/wei. otherwise wanting wei && offer > want, OR offer wei && want > offer
    } else {
      return false;
    }
  }

  /**
   * @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
    constant
    returns (bool)
  {
    // Orders still active
    if (!_makerOrder.active_)
      return error('Maker order is inactive, Exchange.__ordersMatch_and_AreVaild__()');

    if (!_takerOrder.active_)
      return error('Taker order is inactive, Exchange.__ordersMatch_and_AreVaild__()');

    // 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
    uint256 decimals = _makerOrder.offerToken_ == address(0) ? __flooredLog10__(_makerOrder.wantTokenTotal_) : __flooredLog10__(_makerOrder.offerTokenTotal_);

    // Ratio = larger amount / smaller amount
    if (_makerOrder.offerTokenTotal_ >= _makerOrder.wantTokenTotal_) {
      orderPrice = _makerOrder.offerTokenTotal_.mul(10**decimals).div(_makerOrder.wantTokenTotal_);
      offeredPrice = _takerOrder.wantTokenTotal_.mul(10**decimals).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(10**decimals).div(_makerOrder.offerTokenTotal_);
      offeredPrice = _takerOrder.offerTokenTotal_.mul(10**decimals).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 _token_and_EOA_Addresses The addresses of the maker and taker EOAs and offered token 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 _makerWallet The maker's wallet contract.
   * @param _takerWallet The taker's 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] _token_and_EOA_Addresses,
    uint256 _toMakerAmount,
    uint256 _toTakerAmount,
    Wallet _makerWallet,
    Wallet _takerWallet,
    uint256 _fee
  ) private
    constant
    returns (bool)
  {
    // Have the transaction verified by both maker and taker wallets
    // confirm sufficient balance to transfer, offerToken and offerTokenAmount
    if(!_makerWallet.verifyOrder(_token_and_EOA_Addresses[1], _toTakerAmount, 0, 0))
      return error('Maker wallet could not verify the order, Exchange.__ordersVerifiedByWallets__()');

    if(!_takerWallet.verifyOrder(_token_and_EOA_Addresses[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
    constant
    returns (bool)
  {
    address recoveredAddr = ecrecover(
      keccak256('\x19Ethereum Signed Message:\n32', _orderHash),
      _v, _r, _s
    );

    return recoveredAddr == _signer;
  }

  /**
   * @dev Confirm wallet local balances and token balances match.
   * @param _makerWallet  Maker wallet address.
   * @param _takerWallet  Taker wallet address.
   * @param _token  Token address to confirm balances match.
   * @return If the balances do match.
   */
  function __tokenAndWalletBalancesMatch__(
    address _makerWallet,
    address _takerWallet,
    address _token
  ) private
    constant
    returns(bool)
  {
    if (Token(_token).balanceOf(_makerWallet) != Wallet(_makerWallet).balanceOf(_token))
      return false;

    if (Token(_token).balanceOf(_takerWallet) != Wallet(_takerWallet).balanceOf(_token))
      return false;

    return true;
  }

  /**
   * @dev Update the order structs.
   * @param _makerOrder The maker order data structure.
   * @param _takerOrder The taker order data structure.
   * @param _toTakerAmount The amount of tokens to be moved to the taker.
   * @param _toTakerAmount The amount of tokens to be moved to the maker.
   * @return Success if the update succeeds.
   */
  function __updateOrders__(
    Order _makerOrder,
    Order _takerOrder,
    uint256 _toTakerAmount,
    uint256 _toMakerAmount
  ) private
  {
    // taker => maker
    _makerOrder.wantTokenReceived_ = _makerOrder.wantTokenReceived_.add(_toMakerAmount);
    _takerOrder.offerTokenRemaining_ = _takerOrder.offerTokenRemaining_.sub(_toMakerAmount);

    // maker => taker
    _takerOrder.wantTokenReceived_ = _takerOrder.wantTokenReceived_.add(_toTakerAmount);
    _makerOrder.offerTokenRemaining_ = _makerOrder.offerTokenRemaining_.sub(_toTakerAmount);
  }
}

Contract Security Audit

Contract ABI

[{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"}],"name":"depositERC20Token","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"logic_","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_subtractionFlag","type":"bool"}],"name":"updateBalance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_fee","type":"uint256"},{"name":"_feeToken","type":"address"}],"name":"verifyOrder","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_exchange","type":"address"}],"name":"updateExchange","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"birthBlock_","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_token","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"depositEther","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"exchange_","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_version","type":"uint256"}],"name":"updateLogic","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner_","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"tokenBalances_","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_owner","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"balance","type":"uint256"}],"name":"LogDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"balance","type":"uint256"}],"name":"LogWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"errorString","type":"string"}],"name":"LogErrorString","type":"event"}]

Deployed Bytecode

0x6080604052600436106100ab5763ffffffff60e060020a6000350416632039d9fd81146100c457806322d40b13146100fc578063412288031461012d5780634e7343ea14610156578063648a0c911461018557806369820a80146101a657806370a08231146101cd57806398ea5fca146101ee578063c0668179146101f6578063d767ee4d1461020b578063e766307914610223578063f3fef3a314610238578063f6b1b18b1461025c575b600154600160a060020a031633146100c257600080fd5b005b3480156100d057600080fd5b506100e8600160a060020a036004351660243561027d565b604080519115158252519081900360200190f35b34801561010857600080fd5b506101116103b7565b60408051600160a060020a039092168252519081900360200190f35b34801561013957600080fd5b506100e8600160a060020a036004351660243560443515156103c6565b34801561016257600080fd5b506100e8600160a060020a036004358116906024359060443590606435166103c6565b34801561019157600080fd5b506100e8600160a060020a03600435166103e0565b3480156101b257600080fd5b506101bb61048e565b60408051918252519081900360200190f35b3480156101d957600080fd5b506101bb600160a060020a0360043516610494565b6100c26104af565b34801561020257600080fd5b5061011161053b565b34801561021757600080fd5b506100e860043561054a565b34801561022f57600080fd5b50610111610708565b34801561024457600080fd5b506100e8600160a060020a0360043516602435610717565b34801561026857600080fd5b506101bb600160a060020a03600435166107a7565b6000600160a060020a03831615156103215761031a608060405190810160405280604181526020017f43616e6e6f74206465706f73697420657468657220766961206465706f73697481526020017f45524332302c2057616c6c65742e6465706f7369744552433230546f6b656e2881526020017f29000000000000000000000000000000000000000000000000000000000000008152506107b9565b90506103b1565b600354604080517f6465706f73697428616464726573732c75696e743235362900000000000000008152815190819003601801812063ffffffff60e060020a918290049081169091028252600160a060020a03878116600484015260248301879052925192909316929160448083019260009291908290030181865af49250505015156103ad57600080fd5b5060015b92915050565b600354600160a060020a031681565b6000366000604037602060003660406003545af460206000f35b60008054600160a060020a0316331461045f57610458606060405190810160405280602d81526020017f6d73672e73656e64657220213d206f776e65725f2c2057616c6c65742e75706481526020017f61746545786368616e67652829000000000000000000000000000000000000008152506107b9565b9050610489565b506001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0383161781555b919050565b60045481565b600160a060020a031660009081526002602052604090205490565b600354604080517f6465706f73697428616464726573732c75696e743235362900000000000000008152815190819003601801812063ffffffff60e060020a9182900490811690910282526000600483018190523460248401529251600160a060020a039094169390926044808401939192918290030181865af492505050151561053957600080fd5b565b600154600160a060020a031681565b600080548190600160a060020a031633146105cb576105c4606060405190810160405280602a81526020017f6d73672e73656e64657220213d206f776e65725f2c2057616c6c65742e75706481526020017f6174654c6f6769632829000000000000000000000000000000000000000000008152506107b9565b9150610702565b600554604080517fd526d332000000000000000000000000000000000000000000000000000000008152600481018690529051600160a060020a039092169163d526d332916024808201926020929091908290030181600087803b15801561063257600080fd5b505af1158015610646573d6000803e3d6000fd5b505050506040513d602081101561065c57600080fd5b50519050600160a060020a03811615156106d5576105c4606060405190810160405280602581526020017f496e76616c69642076657273696f6e2c2057616c6c65742e7570646174654c6f81526020017f67696328290000000000000000000000000000000000000000000000000000008152506107b9565b6003805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038316179055600191505b50919050565b600054600160a060020a031681565b60008054600160a060020a0316331461078f5761031a606060405190810160405280602681526020017f6d73672e73656e64657220213d206f776e65722c2057616c6c65742e7769746881526020017f64726177282900000000000000000000000000000000000000000000000000008152506107b9565b366000604037602060003660406003545af460206000f35b60026020526000908152604090205481565b60007f551303dd5f39cbfe6daba6b3e27754b8a7d72f519756a2cde2b92c2bbde159a7826040518080602001828103825283818151815260200191508051906020019080838360005b8381101561081a578181015183820152602001610802565b50505050905090810190601f1680156108475780820380516001836020036101000a031916815260200191505b509250505060405180910390a15060009190505600a165627a7a7230582091ab9932f462dc19180e8d269e9c4a96d60c0eb6d96e71ec4fa9987efb568c460029

Swarm Source

bzzr://91ab9932f462dc19180e8d269e9c4a96d60c0eb6d96e71ec4fa9987efb568c46

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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