ETH Price: $2,050.98 (+6.91%)
Gas: 0.06 Gwei

Transaction Decoder

Block:
7087300 at Jan-18-2019 01:16:21 PM +UTC
Transaction Fee:
0.00619204 ETH $12.70
Gas Used:
619,204 Gas / 10 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x3CA8eAE3...36AF929A2
0.13527118 Eth
Nonce: 6
0.12907914 Eth
Nonce: 7
0.00619204
(Spark Pool)
16,160.97209298181880782 Eth16,160.97828502181880782 Eth0.00619204
0x993D6464...c4bA014D1
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 1487230210484448425357087519174659664868580430388013209810566555603218098851949022067479769285756792756204127723826475099699987154702557279402717929115414218291042596831679979833135362219896976843782597899396705863316107010159152365596336527728432812279397871246870423027624610227606826973579510165951998648647145494224630686238450778853801993627400902413920134026943053601140950212257337689950668448632100985700253823571434090667044606772567320158036818109416605883088411266897146237301129601065481815820243687029986297118313663168712021755724683640618357272248594449865736459295299886933232428709235540192283630835047086100874597595208945969960213578698538964981890916397470864332752827012532846121312507477945570849967055249403880244654286563871303961076753373234402744177543877061483041085694494736148393471072607464461286635188988684730459107285548705255624395562366419458211323977430780366326215831237588456104260060530189679670828750531357768959447066520304557299024477599325433711951277566647979524015166195917008707228810793633880242007741775056530015382572482902107462896822209849529466282755373964064638614959609271951179338923213799449747257507112864525332634953910779764615318998800220214221255927620629794761703117458256126429970380392376379722309318364857112123572294176479948733855754306308572256720256148153211149522379826460148245325658779657156139580956953720587278178483463199374507024087212901213872876919394346747620200280119785873187131319770230540454065277488909610243888988110180240825651503474057549825141394695879020905529195506438604714178733219379527279302100777875905562875203586513903420977571624414741673731387652761485048329275056433727660554846328726475385741598835179660878935563885507889025698432230678675904958785102460759905453207220722425895942067867010753556477271200931171720615777019647446991384904121975158615158343923773557377734882886622924836584555580195562383916233565819200573282829060410992884298380120433038573821601234073692783787503298029983201322285779355619530463374345565491970454996150007228329422718694479336506401958501950832389384877179945068479868685959537661676161430786576971175305213608812440834815449492923545897550169147714229766032517037405076518499707408327161026258382379217652940814151445973354280432364080765224593554842207139354674702557256662421223907903232939464828681021780713927954462251293010503223440090434434881191336638730085060364769107556730009765134512717284608940270185243628270292915402525998254446644018899191515707318632010151974432855124930772389086505913730846561819506218075172360196670143371345331013956138034533971066259616143010758367921503958254280169158902605390746166137301114691191076776762849362250280777162731722569513754830533275521881873655024609592462505667497737987019782846673108228811412250689772507207604116237955988713368676355550724004568307083816595793822400855475963340327320003133903030533790005185661214890287766685152533990548844921747477858999385323813336494293013879608962577078934076724636623754880431000387368507820702076495189966277624705463690971297620972775033244427260766570477730052358576400787393479262035224926666447019032510749818230259400936091405501265466659388702872608928705556680589827501489318006852877041056639303795045423308605698750042220775367176170147970866791528447210958678767904065176733087223339707796133740585599717196332636204457758731708520635539677924858121684825587177837188721915153418986517575781983994051637542842472983539069713324405280869801940032408438124926079832061814125779270011586832148284888852586506635392852411740058065979951569870993683237826148945961288182849491221497519373244890383815905407833623212271177275517088667482946088273756130443364228541562987506637553112949511598418113486170465702639887922205441298743883583029371370443940129778546837920787567615725838214591878815362873390676315904769128010903445130532965127561475376643475654020439784989360038912638355625523381788195858725834825731965739746805152796276144206590474112122222768085957726048900892068027312510465610591449851998359971489748510900049558875109362402403620699790282054425486666484889111877674652635786945154649959528254879797181143172812339917271673539624797392850904199471537018091802650285592348471929076430348008342559151818585198020603085027598619224039054402836777211879031770570410394776864747205460052655833545911347655433833608704262344896250398846760570162605680460177725790265749774888824247985839287808196166372877391873085954975387839813726269934597618096399254466597765705880407754707148172966046190201301673802929709197210512976237392927882098913313191586498583287432764905272709404466284047166707121299612902656956318746463550041705392446423290226439906262331677212459153695749371799435653908065229598728165991878935643436114126291142568896575398775885573402641959285524203756396499377244654829575303119168757965803813190952778757919271603740365915505977206152457359961355386642475401947579680597205502038318198229119064802702327042665047491113438808479756715463102953865785762192213122634542627901954533146875099074399329851750729060046315418658179651067123723547402130073606814598606656244574743742092246645037978596820096453068446431314022126929589151867575569932753242539168988724490489259971746134884393
0xDf72b12a...94D10F198

Execution Trace

Exchange.addNewUser( _userAccount=0x3CA8eAE3A1E3ff56801194d939197EC36AF929A2 ) => ( True )
  • 0x993d64649271f259a9747433f6334acc4ba014d1.60806040( )
    • WalletConnector.CALL( )
      File 1 of 2: Exchange
      pragma solidity ^0.4.15;
      
      /**
       * @title Log Various Error Types
       * @author Adam Lemmon <adam@oraclize.it>
       * @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 <adam@oraclize.it>
       * @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 <adam@oraclize.it>
       * @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);
        }
      }

      File 2 of 2: WalletConnector
      // File: contracts/utils/LoggingErrors.sol
      
      pragma solidity ^0.4.11;
      
      /**
       * @title Log Various Error Types
       * @author Adam Lemmon <adam@oraclize.it>
       * @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) {
          emit LogErrorString(_errorMessage);
          return false;
        }
      }
      
      // File: contracts/wallet/WalletConnector.sol
      
      pragma solidity ^0.4.15;
      
      
      /**
       * @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];
        }
      }