ETH Price: $1,890.91 (-0.14%)
Gas: 0.78 Gwei

Transaction Decoder

Block:
7518260 at Apr-07-2019 02:12:53 AM +UTC
Transaction Fee:
0.000692678 ETH $1.31
Gas Used:
346,339 Gas / 2 Gwei

Account State Difference:

  Address   Before After State Difference Code
(xnpool)
1,807.040661688767825552 Eth1,807.041354366767825552 Eth0.000692678
0xe2367674...39dDA8318
0.02128428176 Eth
Nonce: 9
0.02059160376 Eth
Nonce: 10
0.000692678

Execution Trace

InstantTrade.instantTrade( _tokenGet=0xa1A6f16D26aa53aEC17E4001fD8CB6E6d5B17Ff7, _amountGet=189449540, _tokenGive=0x0000000000000000000000000000000000000000, _amountGive=206499998600000000, _expires=7519415, _nonce=2056504859, _user=0x83FBd8dEE540EF99e5766aaBD0C917a1992Df37C, _v=28, _r=5EE8692C3AFCA19E00C1472E1DDE2519DE3E56D0B1B179CFBF18E832466F0094, _s=58154F8A9A86DE00E53645F39E582313541655625F40A0D3C8DFB554E006B71C, _amount=15000000, _store=0x1cE7AE555139c5EF5A57CC8d814a867ee6Ee33D8 )
  • MainToken.transferFrom( _from=0xe2367674c62e672a6cb5fc803dB6B3239dDA8318, _to=0xE17dBB844Ba602E189889D941D1297184ce63664, _value=15060000 ) => ( _success=True )
  • MainToken.approve( _spender=0x1cE7AE555139c5EF5A57CC8d814a867ee6Ee33D8, _value=15060000 ) => ( True )
  • TokenStore.depositToken( _token=0xa1A6f16D26aa53aEC17E4001fD8CB6E6d5B17Ff7, _amount=15060000 )
    • MainToken.transferFrom( _from=0xE17dBB844Ba602E189889D941D1297184ce63664, _to=0x1cE7AE555139c5EF5A57CC8d814a867ee6Ee33D8, _value=15060000 ) => ( _success=True )
    • TokenStore.trade( _tokenGet=0xa1A6f16D26aa53aEC17E4001fD8CB6E6d5B17Ff7, _amountGet=189449540, _tokenGive=0x0000000000000000000000000000000000000000, _amountGive=206499998600000000, _expires=7519415, _nonce=2056504859, _user=0x83FBd8dEE540EF99e5766aaBD0C917a1992Df37C, _v=28, _r=5EE8692C3AFCA19E00C1472E1DDE2519DE3E56D0B1B179CFBF18E832466F0094, _s=58154F8A9A86DE00E53645F39E582313541655625F40A0D3C8DFB554E006B71C, _amount=15000000 )
      • Null: 0x000...002.1ce7ae55( )
      • Null: 0x000...001.c13116ff( )
      • AccountModifiers.tradeModifiers( _maker=0x83FBd8dEE540EF99e5766aaBD0C917a1992Df37C, _taker=0xE17dBB844Ba602E189889D941D1297184ce63664 ) => ( 0, 0 )
        File 1 of 4: InstantTrade
        pragma solidity ^0.4.19;
        
        // ERC20 token protocol, see more details at
        // https://theethereum.wiki/w/index.php/ERC20_Token_Standard
        // And also https://github.com/ethereum/eips/issues/20
        
        contract Token {
        
          string public name;
          string public symbol;
          uint8 public decimals;
        
          function totalSupply() constant returns (uint256 supply);
          function balanceOf(address _owner) constant returns (uint256 balance);
          function transfer(address _to, uint256 _value) returns (bool success);
          function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
          function approve(address _spender, uint256 _value) returns (bool success);
          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);
        }
        
        // Safe mathematics to make the code more readable
        
        contract SafeMath {
          function safeMul(uint a, uint b) internal returns (uint) {
            uint c = a * b;
            assert(a == 0 || c / a == b);
            return c;
          }
        
          function safeSub(uint a, uint b) internal returns (uint) {
            assert(b <= a);
            return a - b;
          }
        
          function safeAdd(uint a, uint b) internal returns (uint) {
            uint c = a + b;
            assert(c>=a && c>=b);
            return c;
          }
        }
        
        // Ownable interface to simplify owner checks
        
        contract Ownable {
          address public owner;
        
          function Ownable() {
            owner = msg.sender;
          }
        
          modifier onlyOwner() {
            require(msg.sender == owner);
            _;
          }
        
          function transferOwnership(address _newOwner) onlyOwner {
            require(_newOwner != address(0));
            owner = _newOwner;
          }
        }
        
        // Interface for trading discounts and rebates for specific accounts
        
        contract AccountModifiersInterface {
          function accountModifiers(address _user) constant returns(uint takeFeeDiscount, uint rebatePercentage);
          function tradeModifiers(address _maker, address _taker) constant returns(uint takeFeeDiscount, uint rebatePercentage);
        }
        
        // Interface for trade tacker
        
        contract TradeTrackerInterface {
          function tradeComplete(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, address _get, address _give, uint _takerFee, uint _makerRebate);
        }
        
        // Exchange contract
        
        contract TokenStore is SafeMath, Ownable {
        
          // The account that will receive fees
          address feeAccount;
        
          // The account that stores fee discounts/rebates
          address accountModifiers;
        
          // Trade tracker account
          address tradeTracker;
        
          // We charge only the takers and this is the fee, percentage times 1 ether
          uint public fee;
        
          // Mapping of token addresses to mapping of account balances (token 0 means Ether)
          mapping (address => mapping (address => uint)) public tokens;
        
          // Mapping of user accounts to mapping of order hashes to uints (amount of order that has been filled)
          mapping (address => mapping (bytes32 => uint)) public orderFills;
        
          // Address of a next and previous versions of the contract, also status of the contract
          // can be used for user-triggered fund migrations
          address public successor;
          address public predecessor;
          bool public deprecated;
          uint16 public version;
        
          // Logging events
          // Note: Order creation is handled off-chain, see explanation further below
          event Cancel(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s);
          event Trade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, address get, address give, uint nonce);
          event Deposit(address token, address user, uint amount, uint balance);
          event Withdraw(address token, address user, uint amount, uint balance);
          event FundsMigrated(address user);
        
          function TokenStore(uint _fee, address _predecessor) {
            feeAccount = owner;
            fee = _fee;
            predecessor = _predecessor;
            deprecated = false;
            if (predecessor != address(0)) {
              version = TokenStore(predecessor).version() + 1;
            } else {
              version = 1;
            }
          }
        
          // Throw on default handler to prevent direct transactions of Ether
          function() {
            revert();
          }
        
          modifier deprecable() {
            require(!deprecated);
            _;
          }
        
          function deprecate(bool _deprecated, address _successor) onlyOwner {
            deprecated = _deprecated;
            successor = _successor;
          }
        
          function changeFeeAccount(address _feeAccount) onlyOwner {
            require(_feeAccount != address(0));
            feeAccount = _feeAccount;
          }
        
          function changeAccountModifiers(address _accountModifiers) onlyOwner {
            accountModifiers = _accountModifiers;
          }
        
          function changeTradeTracker(address _tradeTracker) onlyOwner {
            tradeTracker = _tradeTracker;
          }
        
          // Fee can only be decreased!
          function changeFee(uint _fee) onlyOwner {
            require(_fee <= fee);
            fee = _fee;
          }
        
          // Allows a user to get her current discount/rebate
          function getAccountModifiers() constant returns(uint takeFeeDiscount, uint rebatePercentage) {
            if (accountModifiers != address(0)) {
              return AccountModifiersInterface(accountModifiers).accountModifiers(msg.sender);
            } else {
              return (0, 0);
            }
          }
        
          ////////////////////////////////////////////////////////////////////////////////
          // Deposits, withdrawals, balances
          ////////////////////////////////////////////////////////////////////////////////
        
          function deposit() payable deprecable {
            tokens[0][msg.sender] = safeAdd(tokens[0][msg.sender], msg.value);
            Deposit(0, msg.sender, msg.value, tokens[0][msg.sender]);
          }
        
          function withdraw(uint _amount) {
            require(tokens[0][msg.sender] >= _amount);
            tokens[0][msg.sender] = safeSub(tokens[0][msg.sender], _amount);
            if (!msg.sender.call.value(_amount)()) {
              revert();
            }
            Withdraw(0, msg.sender, _amount, tokens[0][msg.sender]);
          }
        
          function depositToken(address _token, uint _amount) deprecable {
            // Note that Token(_token).approve(this, _amount) needs to be called
            // first or this contract will not be able to do the transfer.
            require(_token != 0);
            if (!Token(_token).transferFrom(msg.sender, this, _amount)) {
              revert();
            }
            tokens[_token][msg.sender] = safeAdd(tokens[_token][msg.sender], _amount);
            Deposit(_token, msg.sender, _amount, tokens[_token][msg.sender]);
          }
        
          function withdrawToken(address _token, uint _amount) {
            require(_token != 0);
            require(tokens[_token][msg.sender] >= _amount);
            tokens[_token][msg.sender] = safeSub(tokens[_token][msg.sender], _amount);
            if (!Token(_token).transfer(msg.sender, _amount)) {
              revert();
            }
            Withdraw(_token, msg.sender, _amount, tokens[_token][msg.sender]);
          }
        
          function balanceOf(address _token, address _user) constant returns (uint) {
            return tokens[_token][_user];
          }
        
          ////////////////////////////////////////////////////////////////////////////////
          // Trading
          ////////////////////////////////////////////////////////////////////////////////
        
          // Note: Order creation happens off-chain but the orders are signed by creators,
          // we validate the contents and the creator address in the logic below
        
          function trade(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive,
              uint _expires, uint _nonce, address _user, uint8 _v, bytes32 _r, bytes32 _s, uint _amount) {
            bytes32 hash = sha256(this, _tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce);
            // Check order signatures and expiration, also check if not fulfilled yet
        		if (ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash), _v, _r, _s) != _user ||
              block.number > _expires ||
              safeAdd(orderFills[_user][hash], _amount) > _amountGet) {
              revert();
            }
            tradeBalances(_tokenGet, _amountGet, _tokenGive, _amountGive, _user, msg.sender, _amount);
            orderFills[_user][hash] = safeAdd(orderFills[_user][hash], _amount);
            Trade(_tokenGet, _amount, _tokenGive, _amountGive * _amount / _amountGet, _user, msg.sender, _nonce);
          }
        
          function tradeBalances(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive,
              address _user, address _caller, uint _amount) private {
        
            uint feeTakeValue = safeMul(_amount, fee) / (1 ether);
            uint rebateValue = 0;
            uint tokenGiveValue = safeMul(_amountGive, _amount) / _amountGet; // Proportionate to request ratio
        
            // Apply modifiers
            if (accountModifiers != address(0)) {
              var (feeTakeDiscount, rebatePercentage) = AccountModifiersInterface(accountModifiers).tradeModifiers(_user, _caller);
              // Check that the discounts/rebates are never higher then 100%
              if (feeTakeDiscount > 100) {
                feeTakeDiscount = 0;
              }
              if (rebatePercentage > 100) {
                rebatePercentage = 0;
              }
              feeTakeValue = safeMul(feeTakeValue, 100 - feeTakeDiscount) / 100;  // discounted fee
              rebateValue = safeMul(rebatePercentage, feeTakeValue) / 100;        // % of actual taker fee
            }
        
            tokens[_tokenGet][_user] = safeAdd(tokens[_tokenGet][_user], safeAdd(_amount, rebateValue));
            tokens[_tokenGet][_caller] = safeSub(tokens[_tokenGet][_caller], safeAdd(_amount, feeTakeValue));
            tokens[_tokenGive][_user] = safeSub(tokens[_tokenGive][_user], tokenGiveValue);
            tokens[_tokenGive][_caller] = safeAdd(tokens[_tokenGive][_caller], tokenGiveValue);
            tokens[_tokenGet][feeAccount] = safeAdd(tokens[_tokenGet][feeAccount], safeSub(feeTakeValue, rebateValue));
        
            if (tradeTracker != address(0)) {
              TradeTrackerInterface(tradeTracker).tradeComplete(_tokenGet, _amount, _tokenGive, tokenGiveValue, _user, _caller, feeTakeValue, rebateValue);
            }
          }
        
          function testTrade(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, uint _expires,
              uint _nonce, address _user, uint8 _v, bytes32 _r, bytes32 _s, uint _amount, address _sender) constant returns(bool) {
            if (tokens[_tokenGet][_sender] < _amount ||
              availableVolume(_tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce, _user, _v, _r, _s) < _amount) {
              return false;
            }
            return true;
          }
        
          function availableVolume(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, uint _expires,
              uint _nonce, address _user, uint8 _v, bytes32 _r, bytes32 _s) constant returns(uint) {
            bytes32 hash = sha256(this, _tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce);
            if (ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash), _v, _r, _s) != _user ||
              block.number > _expires) {
              return 0;
            }
            uint available1 = safeSub(_amountGet, orderFills[_user][hash]);
            uint available2 = safeMul(tokens[_tokenGive][_user], _amountGet) / _amountGive;
            if (available1 < available2) return available1;
            return available2;
          }
        
          function amountFilled(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, uint _expires,
              uint _nonce, address _user) constant returns(uint) {
            bytes32 hash = sha256(this, _tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce);
            return orderFills[_user][hash];
          }
        
          function cancelOrder(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, uint _expires,
              uint _nonce, uint8 _v, bytes32 _r, bytes32 _s) {
            bytes32 hash = sha256(this, _tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce);
            if (!(ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash), _v, _r, _s) == msg.sender)) {
              revert();
            }
            orderFills[msg.sender][hash] = _amountGet;
            Cancel(_tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce, msg.sender, _v, _r, _s);
          }
        
          ////////////////////////////////////////////////////////////////////////////////
          // Migrations
          ////////////////////////////////////////////////////////////////////////////////
        
          // User-triggered (!) fund migrations in case contract got updated
          // Similar to withdraw but we use a successor account instead
          // As we don't store user tokens list on chain, it has to be passed from the outside
          function migrateFunds(address[] _tokens) {
        
            // Get the latest successor in the chain
            require(successor != address(0));
            TokenStore newExchange = TokenStore(successor);
            for (uint16 n = 0; n < 20; n++) {  // We will look past 20 contracts in the future
              address nextSuccessor = newExchange.successor();
              if (nextSuccessor == address(this)) {  // Circular succession
                revert();
              }
              if (nextSuccessor == address(0)) { // We reached the newest, stop
                break;
              }
              newExchange = TokenStore(nextSuccessor);
            }
        
            // Ether
            uint etherAmount = tokens[0][msg.sender];
            if (etherAmount > 0) {
              tokens[0][msg.sender] = 0;
              newExchange.depositForUser.value(etherAmount)(msg.sender);
            }
        
            // Tokens
            for (n = 0; n < _tokens.length; n++) {
              address token = _tokens[n];
              require(token != address(0)); // 0 = Ether, we handle it above
              uint tokenAmount = tokens[token][msg.sender];
              if (tokenAmount == 0) {
                continue;
              }
              if (!Token(token).approve(newExchange, tokenAmount)) {
                revert();
              }
              tokens[token][msg.sender] = 0;
              newExchange.depositTokenForUser(token, tokenAmount, msg.sender);
            }
        
            FundsMigrated(msg.sender);
          }
        
          // This is used for migrations only. To be called by previous exchange only,
          // user-triggered, on behalf of the user called the migrateFunds method.
          // Note that it does exactly the same as depositToken, but as this is called
          // by a previous generation of exchange itself, we credit internally not the
          // previous exchange, but the user it was called for.
          function depositForUser(address _user) payable deprecable {
            require(_user != address(0));
            require(msg.value > 0);
            TokenStore caller = TokenStore(msg.sender);
            require(caller.version() > 0); // Make sure it's an exchange account
            tokens[0][_user] = safeAdd(tokens[0][_user], msg.value);
          }
        
          function depositTokenForUser(address _token, uint _amount, address _user) deprecable {
            require(_token != address(0));
            require(_user != address(0));
            require(_amount > 0);
            TokenStore caller = TokenStore(msg.sender);
            require(caller.version() > 0); // Make sure it's an exchange account
            if (!Token(_token).transferFrom(msg.sender, this, _amount)) {
              revert();
            }
            tokens[_token][_user] = safeAdd(tokens[_token][_user], _amount);
          }
        }
        
        contract InstantTrade is SafeMath, Ownable {
        
          // This is needed so we can withdraw funds from other smart contracts
          function() payable {
          }
          
          // End to end trading in a single call
          function instantTrade(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive,
              uint _expires, uint _nonce, address _user, uint8 _v, bytes32 _r, bytes32 _s, uint _amount, address _store) payable {
            
            // Fix max fee (0.4%) and always reserve it
            uint totalValue = safeMul(_amount, 1004) / 1000;
            
            // Paying with Ethereum or token? Deposit to the actual store
            if (_tokenGet == address(0)) {
              // Check amount of ether sent to make sure it's correct
              if (msg.value != totalValue) {
                revert();
              }
              TokenStore(_store).deposit.value(totalValue)();
            } else {
              // Assuming user already approved transfer, transfer first to this contract
              if (!Token(_tokenGet).transferFrom(msg.sender, this, totalValue)) {
                revert();
              }
              // Allow now actual store to deposit
              if (!Token(_tokenGet).approve(_store, totalValue)) {
                revert();
              }
              TokenStore(_store).depositToken(_tokenGet, totalValue);
            }
            
            // Trade
            TokenStore(_store).trade(_tokenGet, _amountGet, _tokenGive, _amountGive,
              _expires, _nonce, _user, _v, _r, _s, _amount);
            
            // Check how much did we get and how much should we send back
            totalValue = TokenStore(_store).balanceOf(_tokenGive, this);
            uint customerValue = safeMul(_amountGive, _amount) / _amountGet;
            
            // Now withdraw all the funds into this contract and then pass to the user
            if (_tokenGive == address(0)) {
              TokenStore(_store).withdraw(totalValue);
              msg.sender.transfer(customerValue);
            } else {
              TokenStore(_store).withdrawToken(_tokenGive, totalValue);
              if (!Token(_tokenGive).transfer(msg.sender, customerValue)) {
                revert();
              }
            }
          }
          
          function withdrawFees(address _token) onlyOwner {
            if (_token == address(0)) {
              msg.sender.transfer(this.balance);
            } else {
              uint amount = Token(_token).balanceOf(this);
              if (!Token(_token).transfer(msg.sender, amount)) {
                revert();
              }
            }
          }  
        }

        File 2 of 4: MainToken
        /*
         * This file was generated by MyWish Platform (https://mywish.io/)
         * The complete code could be found at https://github.com/MyWishPlatform/
         * Copyright (C) 2018 MyWish
         *
         * This program is free software: you can redistribute it and/or modify
         * it under the terms of the GNU Lesser General Public License as published by
         * the Free Software Foundation, either version 3 of the License, or
         * (at your option) any later version.
         *
         * This program is distributed in the hope that it will be useful,
         * but WITHOUT ANY WARRANTY; without even the implied warranty of
         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
         * GNU Lesser General Public License for more details.
         *
         * You should have received a copy of the GNU Lesser General Public License
         * along with this program. If not, see <http://www.gnu.org/licenses/>.
         */
        pragma solidity ^0.4.23;
        
        
        /**
         * @title ERC20Basic
         * @dev Simpler version of ERC20 interface
         * @dev see https://github.com/ethereum/EIPs/issues/179
         */
        contract ERC20Basic {
          function totalSupply() public view returns (uint256);
          function balanceOf(address who) public view returns (uint256);
          function transfer(address to, uint256 value) public returns (bool);
          event Transfer(address indexed from, address indexed to, uint256 value);
        }
        
        
        
        /**
         * @title SafeMath
         * @dev Math operations with safety checks that throw on error
         */
        library SafeMath {
        
          /**
          * @dev Multiplies two numbers, throws on overflow.
          */
          function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
            // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
            if (a == 0) {
              return 0;
            }
        
            c = a * b;
            assert(c / a == b);
            return c;
          }
        
          /**
          * @dev Integer division of two numbers, truncating the quotient.
          */
          function div(uint256 a, uint256 b) internal pure 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 a / b;
          }
        
          /**
          * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
          */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            assert(b <= a);
            return a - b;
          }
        
          /**
          * @dev Adds two numbers, throws on overflow.
          */
          function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
            c = a + b;
            assert(c >= a);
            return c;
          }
        }
        
        
        
        /**
         * @title Basic token
         * @dev Basic version of StandardToken, with no allowances.
         */
        contract BasicToken is ERC20Basic {
          using SafeMath for uint256;
        
          mapping(address => uint256) balances;
        
          uint256 totalSupply_;
        
          /**
          * @dev total number of tokens in existence
          */
          function totalSupply() public view returns (uint256) {
            return totalSupply_;
          }
        
          /**
          * @dev transfer token for a specified address
          * @param _to The address to transfer to.
          * @param _value The amount to be transferred.
          */
          function transfer(address _to, uint256 _value) public returns (bool) {
            require(_to != address(0));
            require(_value <= balances[msg.sender]);
        
            balances[msg.sender] = balances[msg.sender].sub(_value);
            balances[_to] = balances[_to].add(_value);
            emit Transfer(msg.sender, _to, _value);
            return true;
          }
        
          /**
          * @dev Gets the balance of the specified address.
          * @param _owner The address to query the the balance of.
          * @return An uint256 representing the amount owned by the passed address.
          */
          function balanceOf(address _owner) public view returns (uint256) {
            return balances[_owner];
          }
        
        }
        
        
        /**
         * @title ERC20 interface
         * @dev see https://github.com/ethereum/EIPs/issues/20
         */
        contract ERC20 is ERC20Basic {
          function allowance(address owner, address spender)
            public view returns (uint256);
        
          function transferFrom(address from, address to, uint256 value)
            public returns (bool);
        
          function approve(address spender, uint256 value) public returns (bool);
          event Approval(
            address indexed owner,
            address indexed spender,
            uint256 value
          );
        }
        
        
        /**
         * @title Standard ERC20 token
         *
         * @dev Implementation of the basic standard token.
         * @dev https://github.com/ethereum/EIPs/issues/20
         * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
         */
        contract StandardToken is ERC20, BasicToken {
        
          mapping (address => mapping (address => uint256)) internal allowed;
        
        
          /**
           * @dev Transfer tokens from one address to another
           * @param _from address The address which you want to send tokens from
           * @param _to address The address which you want to transfer to
           * @param _value uint256 the amount of tokens to be transferred
           */
          function transferFrom(
            address _from,
            address _to,
            uint256 _value
          )
            public
            returns (bool)
          {
            require(_to != address(0));
            require(_value <= balances[_from]);
            require(_value <= allowed[_from][msg.sender]);
        
            balances[_from] = balances[_from].sub(_value);
            balances[_to] = balances[_to].add(_value);
            allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
            emit Transfer(_from, _to, _value);
            return true;
          }
        
          /**
           * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
           *
           * Beware that changing an allowance with this method brings the risk that someone may use both the old
           * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
           * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
           * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
           * @param _spender The address which will spend the funds.
           * @param _value The amount of tokens to be spent.
           */
          function approve(address _spender, uint256 _value) public returns (bool) {
            allowed[msg.sender][_spender] = _value;
            emit Approval(msg.sender, _spender, _value);
            return true;
          }
        
          /**
           * @dev Function to check the amount of tokens that an owner allowed to a spender.
           * @param _owner address The address which owns the funds.
           * @param _spender address The address which will spend the funds.
           * @return A uint256 specifying the amount of tokens still available for the spender.
           */
          function allowance(
            address _owner,
            address _spender
           )
            public
            view
            returns (uint256)
          {
            return allowed[_owner][_spender];
          }
        
          /**
           * @dev Increase the amount of tokens that an owner allowed to a spender.
           *
           * approve should be called when allowed[_spender] == 0. To increment
           * allowed value is better to use this function to avoid 2 calls (and wait until
           * the first transaction is mined)
           * From MonolithDAO Token.sol
           * @param _spender The address which will spend the funds.
           * @param _addedValue The amount of tokens to increase the allowance by.
           */
          function increaseApproval(
            address _spender,
            uint _addedValue
          )
            public
            returns (bool)
          {
            allowed[msg.sender][_spender] = (
              allowed[msg.sender][_spender].add(_addedValue));
            emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
            return true;
          }
        
          /**
           * @dev Decrease the amount of tokens that an owner allowed to a spender.
           *
           * approve should be called when allowed[_spender] == 0. To decrement
           * allowed value is better to use this function to avoid 2 calls (and wait until
           * the first transaction is mined)
           * From MonolithDAO Token.sol
           * @param _spender The address which will spend the funds.
           * @param _subtractedValue The amount of tokens to decrease the allowance by.
           */
          function decreaseApproval(
            address _spender,
            uint _subtractedValue
          )
            public
            returns (bool)
          {
            uint oldValue = allowed[msg.sender][_spender];
            if (_subtractedValue > oldValue) {
              allowed[msg.sender][_spender] = 0;
            } else {
              allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
            }
            emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
            return true;
          }
        
        }
        
        
        
        /**
         * @title Ownable
         * @dev The Ownable contract has an owner address, and provides basic authorization control
         * functions, this simplifies the implementation of "user permissions".
         */
        contract Ownable {
          address public owner;
        
        
          event OwnershipRenounced(address indexed previousOwner);
          event OwnershipTransferred(
            address indexed previousOwner,
            address indexed newOwner
          );
        
        
          /**
           * @dev The Ownable constructor sets the original `owner` of the contract to the sender
           * account.
           */
          constructor() public {
            owner = msg.sender;
          }
        
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
            require(msg.sender == owner);
            _;
          }
        
          /**
           * @dev Allows the current owner to relinquish control of the contract.
           */
          function renounceOwnership() public onlyOwner {
            emit OwnershipRenounced(owner);
            owner = address(0);
          }
        
          /**
           * @dev Allows the current owner to transfer control of the contract to a newOwner.
           * @param _newOwner The address to transfer ownership to.
           */
          function transferOwnership(address _newOwner) public onlyOwner {
            _transferOwnership(_newOwner);
          }
        
          /**
           * @dev Transfers control of the contract to a newOwner.
           * @param _newOwner The address to transfer ownership to.
           */
          function _transferOwnership(address _newOwner) internal {
            require(_newOwner != address(0));
            emit OwnershipTransferred(owner, _newOwner);
            owner = _newOwner;
          }
        }
        
        
        /**
         * @title Mintable token
         * @dev Simple ERC20 Token example, with mintable token creation
         * @dev Issue: * https://github.com/OpenZeppelin/openzeppelin-solidity/issues/120
         * Based on code by TokenMarketNet: https://github.com/TokenMarketNet/ico/blob/master/contracts/MintableToken.sol
         */
        contract MintableToken is StandardToken, Ownable {
          event Mint(address indexed to, uint256 amount);
          event MintFinished();
        
          bool public mintingFinished = false;
        
        
          modifier canMint() {
            require(!mintingFinished);
            _;
          }
        
          modifier hasMintPermission() {
            require(msg.sender == owner);
            _;
          }
        
          /**
           * @dev Function to mint tokens
           * @param _to The address that will receive the minted tokens.
           * @param _amount The amount of tokens to mint.
           * @return A boolean that indicates if the operation was successful.
           */
          function mint(
            address _to,
            uint256 _amount
          )
            hasMintPermission
            canMint
            public
            returns (bool)
          {
            totalSupply_ = totalSupply_.add(_amount);
            balances[_to] = balances[_to].add(_amount);
            emit Mint(_to, _amount);
            emit Transfer(address(0), _to, _amount);
            return true;
          }
        
          /**
           * @dev Function to stop minting new tokens.
           * @return True if the operation was successful.
           */
          function finishMinting() onlyOwner canMint public returns (bool) {
            mintingFinished = true;
            emit MintFinished();
            return true;
          }
        }
        
        
        contract FreezableToken is StandardToken {
            // freezing chains
            mapping (bytes32 => uint64) internal chains;
            // freezing amounts for each chain
            mapping (bytes32 => uint) internal freezings;
            // total freezing balance per address
            mapping (address => uint) internal freezingBalance;
        
            event Freezed(address indexed to, uint64 release, uint amount);
            event Released(address indexed owner, uint amount);
        
            /**
             * @dev Gets the balance of the specified address include freezing tokens.
             * @param _owner The address to query the the balance of.
             * @return An uint256 representing the amount owned by the passed address.
             */
            function balanceOf(address _owner) public view returns (uint256 balance) {
                return super.balanceOf(_owner) + freezingBalance[_owner];
            }
        
            /**
             * @dev Gets the balance of the specified address without freezing tokens.
             * @param _owner The address to query the the balance of.
             * @return An uint256 representing the amount owned by the passed address.
             */
            function actualBalanceOf(address _owner) public view returns (uint256 balance) {
                return super.balanceOf(_owner);
            }
        
            function freezingBalanceOf(address _owner) public view returns (uint256 balance) {
                return freezingBalance[_owner];
            }
        
            /**
             * @dev gets freezing count
             * @param _addr Address of freeze tokens owner.
             */
            function freezingCount(address _addr) public view returns (uint count) {
                uint64 release = chains[toKey(_addr, 0)];
                while (release != 0) {
                    count++;
                    release = chains[toKey(_addr, release)];
                }
            }
        
            /**
             * @dev gets freezing end date and freezing balance for the freezing portion specified by index.
             * @param _addr Address of freeze tokens owner.
             * @param _index Freezing portion index. It ordered by release date descending.
             */
            function getFreezing(address _addr, uint _index) public view returns (uint64 _release, uint _balance) {
                for (uint i = 0; i < _index + 1; i++) {
                    _release = chains[toKey(_addr, _release)];
                    if (_release == 0) {
                        return;
                    }
                }
                _balance = freezings[toKey(_addr, _release)];
            }
        
            /**
             * @dev freeze your tokens to the specified address.
             *      Be careful, gas usage is not deterministic,
             *      and depends on how many freezes _to address already has.
             * @param _to Address to which token will be freeze.
             * @param _amount Amount of token to freeze.
             * @param _until Release date, must be in future.
             */
            function freezeTo(address _to, uint _amount, uint64 _until) public {
                require(_to != address(0));
                require(_amount <= balances[msg.sender]);
        
                balances[msg.sender] = balances[msg.sender].sub(_amount);
        
                bytes32 currentKey = toKey(_to, _until);
                freezings[currentKey] = freezings[currentKey].add(_amount);
                freezingBalance[_to] = freezingBalance[_to].add(_amount);
        
                freeze(_to, _until);
                emit Transfer(msg.sender, _to, _amount);
                emit Freezed(_to, _until, _amount);
            }
        
            /**
             * @dev release first available freezing tokens.
             */
            function releaseOnce() public {
                bytes32 headKey = toKey(msg.sender, 0);
                uint64 head = chains[headKey];
                require(head != 0);
                require(uint64(block.timestamp) > head);
                bytes32 currentKey = toKey(msg.sender, head);
        
                uint64 next = chains[currentKey];
        
                uint amount = freezings[currentKey];
                delete freezings[currentKey];
        
                balances[msg.sender] = balances[msg.sender].add(amount);
                freezingBalance[msg.sender] = freezingBalance[msg.sender].sub(amount);
        
                if (next == 0) {
                    delete chains[headKey];
                } else {
                    chains[headKey] = next;
                    delete chains[currentKey];
                }
                emit Released(msg.sender, amount);
            }
        
            /**
             * @dev release all available for release freezing tokens. Gas usage is not deterministic!
             * @return how many tokens was released
             */
            function releaseAll() public returns (uint tokens) {
                uint release;
                uint balance;
                (release, balance) = getFreezing(msg.sender, 0);
                while (release != 0 && block.timestamp > release) {
                    releaseOnce();
                    tokens += balance;
                    (release, balance) = getFreezing(msg.sender, 0);
                }
            }
        
            function toKey(address _addr, uint _release) internal pure returns (bytes32 result) {
                // WISH masc to increase entropy
                result = 0x5749534800000000000000000000000000000000000000000000000000000000;
                assembly {
                    result := or(result, mul(_addr, 0x10000000000000000))
                    result := or(result, _release)
                }
            }
        
            function freeze(address _to, uint64 _until) internal {
                require(_until > block.timestamp);
                bytes32 key = toKey(_to, _until);
                bytes32 parentKey = toKey(_to, uint64(0));
                uint64 next = chains[parentKey];
        
                if (next == 0) {
                    chains[parentKey] = _until;
                    return;
                }
        
                bytes32 nextKey = toKey(_to, next);
                uint parent;
        
                while (next != 0 && _until > next) {
                    parent = next;
                    parentKey = nextKey;
        
                    next = chains[nextKey];
                    nextKey = toKey(_to, next);
                }
        
                if (_until == next) {
                    return;
                }
        
                if (next != 0) {
                    chains[key] = next;
                }
        
                chains[parentKey] = _until;
            }
        }
        
        
        /**
         * @title Burnable Token
         * @dev Token that can be irreversibly burned (destroyed).
         */
        contract BurnableToken is BasicToken {
        
          event Burn(address indexed burner, uint256 value);
        
          /**
           * @dev Burns a specific amount of tokens.
           * @param _value The amount of token to be burned.
           */
          function burn(uint256 _value) public {
            _burn(msg.sender, _value);
          }
        
          function _burn(address _who, uint256 _value) internal {
            require(_value <= balances[_who]);
            // no need to require value <= totalSupply, since that would imply the
            // sender's balance is greater than the totalSupply, which *should* be an assertion failure
        
            balances[_who] = balances[_who].sub(_value);
            totalSupply_ = totalSupply_.sub(_value);
            emit Burn(_who, _value);
            emit Transfer(_who, address(0), _value);
          }
        }
        
        
        
        /**
         * @title Pausable
         * @dev Base contract which allows children to implement an emergency stop mechanism.
         */
        contract Pausable is Ownable {
          event Pause();
          event Unpause();
        
          bool public paused = false;
        
        
          /**
           * @dev Modifier to make a function callable only when the contract is not paused.
           */
          modifier whenNotPaused() {
            require(!paused);
            _;
          }
        
          /**
           * @dev Modifier to make a function callable only when the contract is paused.
           */
          modifier whenPaused() {
            require(paused);
            _;
          }
        
          /**
           * @dev called by the owner to pause, triggers stopped state
           */
          function pause() onlyOwner whenNotPaused public {
            paused = true;
            emit Pause();
          }
        
          /**
           * @dev called by the owner to unpause, returns to normal state
           */
          function unpause() onlyOwner whenPaused public {
            paused = false;
            emit Unpause();
          }
        }
        
        
        contract FreezableMintableToken is FreezableToken, MintableToken {
            /**
             * @dev Mint the specified amount of token to the specified address and freeze it until the specified date.
             *      Be careful, gas usage is not deterministic,
             *      and depends on how many freezes _to address already has.
             * @param _to Address to which token will be freeze.
             * @param _amount Amount of token to mint and freeze.
             * @param _until Release date, must be in future.
             * @return A boolean that indicates if the operation was successful.
             */
            function mintAndFreeze(address _to, uint _amount, uint64 _until) public onlyOwner canMint returns (bool) {
                totalSupply_ = totalSupply_.add(_amount);
        
                bytes32 currentKey = toKey(_to, _until);
                freezings[currentKey] = freezings[currentKey].add(_amount);
                freezingBalance[_to] = freezingBalance[_to].add(_amount);
        
                freeze(_to, _until);
                emit Mint(_to, _amount);
                emit Freezed(_to, _until, _amount);
                emit Transfer(msg.sender, _to, _amount);
                return true;
            }
        }
        
        
        
        contract Consts {
            uint public constant TOKEN_DECIMALS = 6;
            uint8 public constant TOKEN_DECIMALS_UINT8 = 6;
            uint public constant TOKEN_DECIMAL_MULTIPLIER = 10 ** TOKEN_DECIMALS;
        
            string public constant TOKEN_NAME = "1irst";
            string public constant TOKEN_SYMBOL = "FST";
            bool public constant PAUSED = false;
            address public constant TARGET_USER = 0x89cc23D79ef2B11E46b9ce72CcCF6839fa6a43C8;
            
            bool public constant CONTINUE_MINTING = false;
        }
        
        
        
        
        contract MainToken is Consts, FreezableMintableToken, BurnableToken, Pausable
            
        {
            
            event Initialized();
            bool public initialized = false;
        
            constructor() public {
                init();
                transferOwnership(TARGET_USER);
            }
            
        
            function name() public pure returns (string _name) {
                return TOKEN_NAME;
            }
        
            function symbol() public pure returns (string _symbol) {
                return TOKEN_SYMBOL;
            }
        
            function decimals() public pure returns (uint8 _decimals) {
                return TOKEN_DECIMALS_UINT8;
            }
        
            function transferFrom(address _from, address _to, uint256 _value) public returns (bool _success) {
                require(!paused);
                return super.transferFrom(_from, _to, _value);
            }
        
            function transfer(address _to, uint256 _value) public returns (bool _success) {
                require(!paused);
                return super.transfer(_to, _value);
            }
        
            
            function init() private {
                require(!initialized);
                initialized = true;
        
                if (PAUSED) {
                    pause();
                }
        
                
                address[1] memory addresses = [address(0x89cc23d79ef2b11e46b9ce72cccf6839fa6a43c8)];
                uint[1] memory amounts = [uint(100000000000000)];
                uint64[1] memory freezes = [uint64(0)];
        
                for (uint i = 0; i < addresses.length; i++) {
                    if (freezes[i] == 0) {
                        mint(addresses[i], amounts[i]);
                    } else {
                        mintAndFreeze(addresses[i], amounts[i], freezes[i]);
                    }
                }
                
        
                if (!CONTINUE_MINTING) {
                    finishMinting();
                }
        
                emit Initialized();
            }
            
        }

        File 3 of 4: TokenStore
        pragma solidity ^0.4.11;
        
        // ERC20 token protocol, see more details at
        // https://theethereum.wiki/w/index.php/ERC20_Token_Standard
        // And also https://github.com/ethereum/eips/issues/20
        
        contract Token {
          function totalSupply() constant returns (uint256 supply);
          function balanceOf(address _owner) constant returns (uint256 balance);
          function transfer(address _to, uint256 _value) returns (bool success);
          function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
          function approve(address _spender, uint256 _value) returns (bool success);
          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);
        }
        
        // Safe mathematics to make the code more readable
        
        contract SafeMath {
          function safeMul(uint a, uint b) internal returns (uint) {
            uint c = a * b;
            assert(a == 0 || c / a == b);
            return c;
          }
        
          function safeSub(uint a, uint b) internal returns (uint) {
            assert(b <= a);
            return a - b;
          }
        
          function safeAdd(uint a, uint b) internal returns (uint) {
            uint c = a + b;
            assert(c>=a && c>=b);
            return c;
          }
        }
        
        // Ownable interface to simplify owner checks
        
        contract Ownable {
          address public owner;
        
          function Ownable() {
            owner = msg.sender;
          }
        
          modifier onlyOwner() {
            require(msg.sender == owner);
            _;
          }
        
          function transferOwnership(address _newOwner) onlyOwner {
            require(_newOwner != address(0));
            owner = _newOwner;
          }
        }
        
        // Interface for trading discounts and rebates for specific accounts
        
        contract AccountModifiersInterface {
          function accountModifiers(address _user) constant returns(uint takeFeeDiscount, uint rebatePercentage);
          function tradeModifiers(address _maker, address _taker) constant returns(uint takeFeeDiscount, uint rebatePercentage);
        }
        
        // Interface for trade tacker
        
        contract TradeTrackerInterface {
          function tradeComplete(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, address _get, address _give, uint _takerFee, uint _makerRebate);
        }
        
        // Exchange contract
        
        contract TokenStore is SafeMath, Ownable {
        
          // The account that will receive fees
          address feeAccount;
        
          // The account that stores fee discounts/rebates
          address accountModifiers;
          
          // Trade tracker account
          address tradeTracker;
        
          // We charge only the takers and this is the fee, percentage times 1 ether
          uint public fee;
        
          // Mapping of token addresses to mapping of account balances (token 0 means Ether)
          mapping (address => mapping (address => uint)) public tokens;
        
          // Mapping of user accounts to mapping of order hashes to uints (amount of order that has been filled)
          mapping (address => mapping (bytes32 => uint)) public orderFills;
          
          // Address of a next and previous versions of the contract, also status of the contract
          // can be used for user-triggered fund migrations
          address public successor;
          address public predecessor;
          bool public deprecated;
          uint16 public version;
        
          // Logging events
          // Note: Order creation is handled off-chain, see explanation further below
          event Cancel(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s);
          event Trade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, address get, address give, uint nonce);
          event Deposit(address token, address user, uint amount, uint balance);
          event Withdraw(address token, address user, uint amount, uint balance);
          event FundsMigrated(address user);
        
          function TokenStore(uint _fee, address _predecessor) {
            feeAccount = owner;
            fee = _fee;
            predecessor = _predecessor;
            deprecated = false;
            if (predecessor != address(0)) {
              version = TokenStore(predecessor).version() + 1;
            } else {
              version = 1;
            }
          }
        
          // Throw on default handler to prevent direct transactions of Ether
          function() {
            revert();
          }
          
          modifier deprecable() {
            require(!deprecated);
            _;
          }
        
          function deprecate(bool _deprecated, address _successor) onlyOwner {
            deprecated = _deprecated;
            successor = _successor;
          }
        
          function changeFeeAccount(address _feeAccount) onlyOwner {
            require(_feeAccount != address(0));
            feeAccount = _feeAccount;
          }
        
          function changeAccountModifiers(address _accountModifiers) onlyOwner {
            accountModifiers = _accountModifiers;
          }
          
          function changeTradeTracker(address _tradeTracker) onlyOwner {
            tradeTracker = _tradeTracker;
          }
        
          // Fee can only be decreased!
          function changeFee(uint _fee) onlyOwner {
            require(_fee <= fee);
            fee = _fee;
          }
          
          // Allows a user to get her current discount/rebate
          function getAccountModifiers() constant returns(uint takeFeeDiscount, uint rebatePercentage) {
            if (accountModifiers != address(0)) {
              return AccountModifiersInterface(accountModifiers).accountModifiers(msg.sender);
            } else {
              return (0, 0);
            }
          }
          
          ////////////////////////////////////////////////////////////////////////////////
          // Deposits, withdrawals, balances
          ////////////////////////////////////////////////////////////////////////////////
        
          function deposit() payable deprecable {
            tokens[0][msg.sender] = safeAdd(tokens[0][msg.sender], msg.value);
            Deposit(0, msg.sender, msg.value, tokens[0][msg.sender]);
          }
        
          function withdraw(uint _amount) {
            require(tokens[0][msg.sender] >= _amount);
            tokens[0][msg.sender] = safeSub(tokens[0][msg.sender], _amount);
            if (!msg.sender.call.value(_amount)()) {
              revert();
            }
            Withdraw(0, msg.sender, _amount, tokens[0][msg.sender]);
          }
        
          function depositToken(address _token, uint _amount) deprecable {
            // Note that Token(_token).approve(this, _amount) needs to be called
            // first or this contract will not be able to do the transfer.
            require(_token != 0);
            if (!Token(_token).transferFrom(msg.sender, this, _amount)) {
              revert();
            }
            tokens[_token][msg.sender] = safeAdd(tokens[_token][msg.sender], _amount);
            Deposit(_token, msg.sender, _amount, tokens[_token][msg.sender]);
          }
        
          function withdrawToken(address _token, uint _amount) {
            require(_token != 0);
            require(tokens[_token][msg.sender] >= _amount);
            tokens[_token][msg.sender] = safeSub(tokens[_token][msg.sender], _amount);
            if (!Token(_token).transfer(msg.sender, _amount)) {
              revert();
            }
            Withdraw(_token, msg.sender, _amount, tokens[_token][msg.sender]);
          }
        
          function balanceOf(address _token, address _user) constant returns (uint) {
            return tokens[_token][_user];
          }
          
          ////////////////////////////////////////////////////////////////////////////////
          // Trading
          ////////////////////////////////////////////////////////////////////////////////
        
          // Note: Order creation happens off-chain but the orders are signed by creators,
          // we validate the contents and the creator address in the logic below
        
          function trade(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive,
              uint _expires, uint _nonce, address _user, uint8 _v, bytes32 _r, bytes32 _s, uint _amount) {
            bytes32 hash = sha256(this, _tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce);
            // Check order signatures and expiration, also check if not fulfilled yet
        		if (ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash), _v, _r, _s) != _user ||
              block.number > _expires ||
              safeAdd(orderFills[_user][hash], _amount) > _amountGet) {
              revert();
            }
            tradeBalances(_tokenGet, _amountGet, _tokenGive, _amountGive, _user, msg.sender, _amount);
            orderFills[_user][hash] = safeAdd(orderFills[_user][hash], _amount);
            Trade(_tokenGet, _amount, _tokenGive, _amountGive * _amount / _amountGet, _user, msg.sender, _nonce);
          }
          
          function tradeBalances(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive,
              address _user, address _caller, uint _amount) private {
        
            uint feeTakeValue = safeMul(_amount, fee) / (1 ether);
            uint rebateValue = 0;
            uint tokenGiveValue = safeMul(_amountGive, _amount) / _amountGet; // Proportionate to request ratio
        
            // Apply modifiers
            if (accountModifiers != address(0)) {
              var (feeTakeDiscount, rebatePercentage) = AccountModifiersInterface(accountModifiers).tradeModifiers(_user, _caller);
              // Check that the discounts/rebates are never higher then 100%
              if (feeTakeDiscount > 100) {
                feeTakeDiscount = 0;
              }
              if (rebatePercentage > 100) {
                rebatePercentage = 0;
              }
              feeTakeValue = safeMul(feeTakeValue, 100 - feeTakeDiscount) / 100;  // discounted fee
              rebateValue = safeMul(rebatePercentage, feeTakeValue) / 100;        // % of actual taker fee
            }
            
            tokens[_tokenGet][_user] = safeAdd(tokens[_tokenGet][_user], safeAdd(_amount, rebateValue));
            tokens[_tokenGet][_caller] = safeSub(tokens[_tokenGet][_caller], safeAdd(_amount, feeTakeValue));
            tokens[_tokenGive][_user] = safeSub(tokens[_tokenGive][_user], tokenGiveValue);
            tokens[_tokenGive][_caller] = safeAdd(tokens[_tokenGive][_caller], tokenGiveValue);
            tokens[_tokenGet][feeAccount] = safeAdd(tokens[_tokenGet][feeAccount], safeSub(feeTakeValue, rebateValue));
            
            if (tradeTracker != address(0)) {
              TradeTrackerInterface(tradeTracker).tradeComplete(_tokenGet, _amount, _tokenGive, tokenGiveValue, _user, _caller, feeTakeValue, rebateValue);
            }
          }
        
          function testTrade(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, uint _expires,
              uint _nonce, address _user, uint8 _v, bytes32 _r, bytes32 _s, uint _amount, address _sender) constant returns(bool) {
            if (tokens[_tokenGet][_sender] < _amount ||
              availableVolume(_tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce, _user, _v, _r, _s) < _amount) {
              return false;
            }
            return true;
          }
        
          function availableVolume(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, uint _expires,
              uint _nonce, address _user, uint8 _v, bytes32 _r, bytes32 _s) constant returns(uint) {
            bytes32 hash = sha256(this, _tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce);
            if (ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash), _v, _r, _s) != _user ||
              block.number > _expires) {
              return 0;
            }
            uint available1 = safeSub(_amountGet, orderFills[_user][hash]);
            uint available2 = safeMul(tokens[_tokenGive][_user], _amountGet) / _amountGive;
            if (available1 < available2) return available1;
            return available2;
          }
        
          function amountFilled(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, uint _expires,
              uint _nonce, address _user) constant returns(uint) {
            bytes32 hash = sha256(this, _tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce);
            return orderFills[_user][hash];
          }
        
          function cancelOrder(address _tokenGet, uint _amountGet, address _tokenGive, uint _amountGive, uint _expires,
              uint _nonce, uint8 _v, bytes32 _r, bytes32 _s) {
            bytes32 hash = sha256(this, _tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce);
            if (!(ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash), _v, _r, _s) == msg.sender)) {
              revert();
            }
            orderFills[msg.sender][hash] = _amountGet;
            Cancel(_tokenGet, _amountGet, _tokenGive, _amountGive, _expires, _nonce, msg.sender, _v, _r, _s);
          }
          
          ////////////////////////////////////////////////////////////////////////////////
          // Migrations
          ////////////////////////////////////////////////////////////////////////////////
        
          // User-triggered (!) fund migrations in case contract got updated
          // Similar to withdraw but we use a successor account instead
          // As we don't store user tokens list on chain, it has to be passed from the outside
          function migrateFunds(address[] _tokens) {
          
            // Get the latest successor in the chain
            require(successor != address(0));
            TokenStore newExchange = TokenStore(successor);
            for (uint16 n = 0; n < 20; n++) {  // We will look past 20 contracts in the future
              address nextSuccessor = newExchange.successor();
              if (nextSuccessor == address(this)) {  // Circular succession
                revert();
              }
              if (nextSuccessor == address(0)) { // We reached the newest, stop
                break;
              }
              newExchange = TokenStore(nextSuccessor);
            }
        
            // Ether
            uint etherAmount = tokens[0][msg.sender];
            if (etherAmount > 0) {
              tokens[0][msg.sender] = 0;
              newExchange.depositForUser.value(etherAmount)(msg.sender);
            }
        
            // Tokens
            for (n = 0; n < _tokens.length; n++) {
              address token = _tokens[n];
              require(token != address(0)); // 0 = Ether, we handle it above
              uint tokenAmount = tokens[token][msg.sender];
              if (tokenAmount == 0) {
                continue;
              }
              if (!Token(token).approve(newExchange, tokenAmount)) {
                revert();
              }
              tokens[token][msg.sender] = 0;
              newExchange.depositTokenForUser(token, tokenAmount, msg.sender);
            }
        
            FundsMigrated(msg.sender);
          }
        
          // This is used for migrations only. To be called by previous exchange only,
          // user-triggered, on behalf of the user called the migrateFunds method.
          // Note that it does exactly the same as depositToken, but as this is called
          // by a previous generation of exchange itself, we credit internally not the
          // previous exchange, but the user it was called for.
          function depositForUser(address _user) payable deprecable {
            require(_user != address(0));
            require(msg.value > 0);
            TokenStore caller = TokenStore(msg.sender);
            require(caller.version() > 0); // Make sure it's an exchange account
            tokens[0][_user] = safeAdd(tokens[0][_user], msg.value);
          }
        
          function depositTokenForUser(address _token, uint _amount, address _user) deprecable {
            require(_token != address(0));
            require(_user != address(0));
            require(_amount > 0);
            TokenStore caller = TokenStore(msg.sender);
            require(caller.version() > 0); // Make sure it's an exchange account
            if (!Token(_token).transferFrom(msg.sender, this, _amount)) {
              revert();
            }
            tokens[_token][_user] = safeAdd(tokens[_token][_user], _amount);
          }
        }

        File 4 of 4: AccountModifiers
        pragma solidity ^0.4.13;
        
        contract Ownable {
          address public owner;
        
          function Ownable() {
            owner = msg.sender;
          }
        
          modifier onlyOwner() {
            require(msg.sender == owner);
            _;
          }
        
          function transferOwnership(address newOwner) onlyOwner {
            if (newOwner != address(0)) {
              owner = newOwner;
            }
          }
        }
        
        contract AccountModifiers is Ownable {
        
          uint defaultTakerFeeDiscount;
          uint defaultRebatePercentage;
          
          mapping (address => uint) takerFeeDiscounts;   // in % of taker fee (Eg: 100 for 100%)
          mapping (address => uint) rebatePercentages;   // in % of taker fee charged
          
          function setDefaults(uint _defaultTakerFeeDiscount, uint _defaultRebatePercentage) onlyOwner {
            defaultTakerFeeDiscount = _defaultTakerFeeDiscount;
            defaultRebatePercentage = _defaultRebatePercentage;
          }
        
          function setModifiers(address _user, uint _takeFeeDiscount, uint _rebatePercentage) onlyOwner {
            takerFeeDiscounts[_user] = _takeFeeDiscount;
            rebatePercentages[_user] = _rebatePercentage;
          }
        
          function takerFeeDiscount(address _user) internal constant returns (uint) {
            return defaultTakerFeeDiscount > takerFeeDiscounts[_user] ? defaultTakerFeeDiscount : takerFeeDiscounts[_user];
          }
        
          function rebatePercentage(address _user) internal constant returns (uint) {
            return defaultRebatePercentage > rebatePercentages[_user] ? defaultRebatePercentage : rebatePercentages[_user];
          }
        
          function accountModifiers(address _user) constant returns(uint, uint) {
            return (takerFeeDiscount(_user), rebatePercentage(_user));
          }
        
          function tradeModifiers(address _maker, address _taker) constant returns(uint, uint) {
            return (takerFeeDiscount(_taker), rebatePercentage(_maker));
          }
        }