ETH Price: $2,038.90 (-6.13%)
Gas: 0.1 Gwei

Transaction Decoder

Block:
5437163 at Apr-14-2018 04:48:53 AM +UTC
Transaction Fee:
0.000156144 ETH $0.32
Gas Used:
78,072 Gas / 2 Gwei

Emitted Events:

32 TomoCoin.Transfer( from=[Receiver] Exchange, to=0xcd8c3b4F361ef283Bf20aD06ABd7b3e5906AdBb7, value=341453409678568993651 )
33 Exchange.Withdraw( token=TomoCoin, user=0xcd8c3b4F361ef283Bf20aD06ABd7b3e5906AdBb7, amount=341453409678568993651, balance=0 )

Account State Difference:

  Address   Before After State Difference Code
0x2a0c0DBE...44050c208
(IDEX)
(Nanopool)
5,187.363880267920309588 Eth5,187.364036411920309588 Eth0.000156144
0x8b353021...709A3C3dC
0xcEcEaA8e...28dD55a32
17.120930478377705264 Eth
Nonce: 934104
17.120774334377705264 Eth
Nonce: 934105
0.000156144

Execution Trace

Exchange.adminWithdraw( token=0x8b353021189375591723E7384262F45709A3C3dC, amount=341655159902032916741, user=0xcd8c3b4F361ef283Bf20aD06ABd7b3e5906AdBb7, nonce=26, v=28, r=781183E0302FD6EDD7AE50466B7077A19D41515BF38044A94E5360CDC5BC7FE0, s=69D35259E57A4C12D24C032CA60539E95FD317C11DE2A7D2FC14E619FF0578AF, feeWithdrawal=590508346257008 ) => ( success=False )
  • Null: 0x000...001.985f4e1d( )
  • TomoCoin.transfer( _to=0xcd8c3b4F361ef283Bf20aD06ABd7b3e5906AdBb7, _value=341453409678568993651 ) => ( success=True )
    File 1 of 2: Exchange
    pragma solidity ^0.4.16;
    
    contract Token {
        bytes32 public standard;
        bytes32 public name;
        bytes32 public symbol;
        uint256 public totalSupply;
        uint8 public decimals;
        bool public allowTransactions;
        mapping (address => uint256) public balanceOf;
        mapping (address => mapping (address => uint256)) public allowance;
        function transfer(address _to, uint256 _value) returns (bool success);
        function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success);
        function approve(address _spender, uint256 _value) returns (bool success);
        function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
    }
    
    contract Exchange {
      function assert(bool assertion) {
        if (!assertion) throw;
      }
      function safeMul(uint a, uint b) returns (uint) {
        uint c = a * b;
        assert(a == 0 || c / a == b);
        return c;
      }
    
      function safeSub(uint a, uint b) returns (uint) {
        assert(b <= a);
        return a - b;
      }
    
      function safeAdd(uint a, uint b) returns (uint) {
        uint c = a + b;
        assert(c>=a && c>=b);
        return c;
      }
      address public owner;
      mapping (address => uint256) public invalidOrder;
      event SetOwner(address indexed previousOwner, address indexed newOwner);
      modifier onlyOwner {
        assert(msg.sender == owner);
        _;
      }
      function setOwner(address newOwner) onlyOwner {
        SetOwner(owner, newOwner);
        owner = newOwner;
      }
      function getOwner() returns (address out) {
        return owner;
      }
      function invalidateOrdersBefore(address user, uint256 nonce) onlyAdmin {
        if (nonce < invalidOrder[user]) throw;
        invalidOrder[user] = nonce;
      }
    
      mapping (address => mapping (address => uint256)) public tokens; //mapping of token addresses to mapping of account balances
    
      mapping (address => bool) public admins;
      mapping (address => uint256) public lastActiveTransaction;
      mapping (bytes32 => uint256) public orderFills;
      address public feeAccount;
      uint256 public inactivityReleasePeriod;
      mapping (bytes32 => bool) public traded;
      mapping (bytes32 => bool) public withdrawn;
      event Order(address tokenBuy, uint256 amountBuy, address tokenSell, uint256 amountSell, uint256 expires, uint256 nonce, address user, uint8 v, bytes32 r, bytes32 s);
      event Cancel(address tokenBuy, uint256 amountBuy, address tokenSell, uint256 amountSell, uint256 expires, uint256 nonce, address user, uint8 v, bytes32 r, bytes32 s);
      event Trade(address tokenBuy, uint256 amountBuy, address tokenSell, uint256 amountSell, address get, address give);
      event Deposit(address token, address user, uint256 amount, uint256 balance);
      event Withdraw(address token, address user, uint256 amount, uint256 balance);
    
      function setInactivityReleasePeriod(uint256 expiry) onlyAdmin returns (bool success) {
        if (expiry > 1000000) throw;
        inactivityReleasePeriod = expiry;
        return true;
      }
    
      function Exchange(address feeAccount_) {
        owner = msg.sender;
        feeAccount = feeAccount_;
        inactivityReleasePeriod = 100000;
      }
    
      function setAdmin(address admin, bool isAdmin) onlyOwner {
        admins[admin] = isAdmin;
      }
    
      modifier onlyAdmin {
        if (msg.sender != owner && !admins[msg.sender]) throw;
        _;
      }
    
      function() external {
        throw;
      }
    
      function depositToken(address token, uint256 amount) {
        tokens[token][msg.sender] = safeAdd(tokens[token][msg.sender], amount);
        lastActiveTransaction[msg.sender] = block.number;
        if (!Token(token).transferFrom(msg.sender, this, amount)) throw;
        Deposit(token, msg.sender, amount, tokens[token][msg.sender]);
      }
    
      function deposit() payable {
        tokens[address(0)][msg.sender] = safeAdd(tokens[address(0)][msg.sender], msg.value);
        lastActiveTransaction[msg.sender] = block.number;
        Deposit(address(0), msg.sender, msg.value, tokens[address(0)][msg.sender]);
      }
    
      function withdraw(address token, uint256 amount) returns (bool success) {
        if (safeSub(block.number, lastActiveTransaction[msg.sender]) < inactivityReleasePeriod) throw;
        if (tokens[token][msg.sender] < amount) throw;
        tokens[token][msg.sender] = safeSub(tokens[token][msg.sender], amount);
        if (token == address(0)) {
          if (!msg.sender.send(amount)) throw;
        } else {
          if (!Token(token).transfer(msg.sender, amount)) throw;
        }
        Withdraw(token, msg.sender, amount, tokens[token][msg.sender]);
      }
    
      function adminWithdraw(address token, uint256 amount, address user, uint256 nonce, uint8 v, bytes32 r, bytes32 s, uint256 feeWithdrawal) onlyAdmin returns (bool success) {
        bytes32 hash = keccak256(this, token, amount, user, nonce);
        if (withdrawn[hash]) throw;
        withdrawn[hash] = true;
        if (ecrecover(keccak256("\x19Ethereum Signed Message:\n32", hash), v, r, s) != user) throw;
        if (feeWithdrawal > 50 finney) feeWithdrawal = 50 finney;
        if (tokens[token][user] < amount) throw;
        tokens[token][user] = safeSub(tokens[token][user], amount);
        tokens[token][feeAccount] = safeAdd(tokens[token][feeAccount], safeMul(feeWithdrawal, amount) / 1 ether);
        amount = safeMul((1 ether - feeWithdrawal), amount) / 1 ether;
        if (token == address(0)) {
          if (!user.send(amount)) throw;
        } else {
          if (!Token(token).transfer(user, amount)) throw;
        }
        lastActiveTransaction[user] = block.number;
        Withdraw(token, user, amount, tokens[token][user]);
      }
    
      function balanceOf(address token, address user) constant returns (uint256) {
        return tokens[token][user];
      }
    
      function trade(uint256[8] tradeValues, address[4] tradeAddresses, uint8[2] v, bytes32[4] rs) onlyAdmin returns (bool success) {
        /* amount is in amountBuy terms */
        /* tradeValues
           [0] amountBuy
           [1] amountSell
           [2] expires
           [3] nonce
           [4] amount
           [5] tradeNonce
           [6] feeMake
           [7] feeTake
         tradeAddressses
           [0] tokenBuy
           [1] tokenSell
           [2] maker
           [3] taker
         */
        if (invalidOrder[tradeAddresses[2]] > tradeValues[3]) throw;
        bytes32 orderHash = keccak256(this, tradeAddresses[0], tradeValues[0], tradeAddresses[1], tradeValues[1], tradeValues[2], tradeValues[3], tradeAddresses[2]);
        if (ecrecover(keccak256("\x19Ethereum Signed Message:\n32", orderHash), v[0], rs[0], rs[1]) != tradeAddresses[2]) throw;
        bytes32 tradeHash = keccak256(orderHash, tradeValues[4], tradeAddresses[3], tradeValues[5]); 
        if (ecrecover(keccak256("\x19Ethereum Signed Message:\n32", tradeHash), v[1], rs[2], rs[3]) != tradeAddresses[3]) throw;
        if (traded[tradeHash]) throw;
        traded[tradeHash] = true;
        if (tradeValues[6] > 100 finney) tradeValues[6] = 100 finney;
        if (tradeValues[7] > 100 finney) tradeValues[7] = 100 finney;
        if (safeAdd(orderFills[orderHash], tradeValues[4]) > tradeValues[0]) throw;
        if (tokens[tradeAddresses[0]][tradeAddresses[3]] < tradeValues[4]) throw;
        if (tokens[tradeAddresses[1]][tradeAddresses[2]] < (safeMul(tradeValues[1], tradeValues[4]) / tradeValues[0])) throw;
        tokens[tradeAddresses[0]][tradeAddresses[3]] = safeSub(tokens[tradeAddresses[0]][tradeAddresses[3]], tradeValues[4]);
        tokens[tradeAddresses[0]][tradeAddresses[2]] = safeAdd(tokens[tradeAddresses[0]][tradeAddresses[2]], safeMul(tradeValues[4], ((1 ether) - tradeValues[6])) / (1 ether));
        tokens[tradeAddresses[0]][feeAccount] = safeAdd(tokens[tradeAddresses[0]][feeAccount], safeMul(tradeValues[4], tradeValues[6]) / (1 ether));
        tokens[tradeAddresses[1]][tradeAddresses[2]] = safeSub(tokens[tradeAddresses[1]][tradeAddresses[2]], safeMul(tradeValues[1], tradeValues[4]) / tradeValues[0]);
        tokens[tradeAddresses[1]][tradeAddresses[3]] = safeAdd(tokens[tradeAddresses[1]][tradeAddresses[3]], safeMul(safeMul(((1 ether) - tradeValues[7]), tradeValues[1]), tradeValues[4]) / tradeValues[0] / (1 ether));
        tokens[tradeAddresses[1]][feeAccount] = safeAdd(tokens[tradeAddresses[1]][feeAccount], safeMul(safeMul(tradeValues[7], tradeValues[1]), tradeValues[4]) / tradeValues[0] / (1 ether));
        orderFills[orderHash] = safeAdd(orderFills[orderHash], tradeValues[4]);
        lastActiveTransaction[tradeAddresses[2]] = block.number;
        lastActiveTransaction[tradeAddresses[3]] = block.number;
      }
    }

    File 2 of 2: TomoCoin
    pragma solidity 0.4.19;
    
    // ================= Ownable Contract start =============================
    /*
     * Ownable
     *
     * Base contract with an owner.
     * Provides onlyOwner modifier, which prevents function from running if it is called by anyone other than the owner.
     */
    contract Ownable {
      address public owner;
    
      function Ownable() public {
        owner = msg.sender;
      }
    
      modifier onlyOwner() {
        require(msg.sender == owner);
        _;
      }
    
      function transferOwnership(address newOwner) public onlyOwner {
        if (newOwner != address(0)) {
          owner = newOwner;
        }
      }
    }
    // ================= Ownable Contract end ===============================
    
    // ================= Safemath Lib ============================
    library SafeMath {
    
      /**
      * @dev Multiplies two numbers, throws on overflow.
      */
      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
          return 0;
        }
        uint256 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 c;
      }
    
      /**
      * @dev Substracts 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) {
        uint256 c = a + b;
        assert(c >= a);
        return c;
      }
    }
    // ================= Safemath Lib end ==============================
    
    // ================= ERC20 Token Contract start =========================
    /*
     * ERC20 interface
     * see https://github.com/ethereum/EIPs/issues/20
     */
    contract ERC20 {
      function totalSupply() public view returns (uint256);
      function balanceOf(address who) public view returns (uint256);
      function transfer(address to, uint256 value) public returns (bool);
      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 Transfer(address indexed from, address indexed to, uint256 value);
      event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    // ================= ERC20 Token Contract end ===========================
    
    // ================= Standard Token Contract start ======================
    contract StandardToken is ERC20 {
      using SafeMath for uint256;
    
      mapping(address => uint256) balances;
      mapping (address => mapping (address => uint256)) internal allowed;
    
      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]);
    
        // SafeMath.sub will throw if there is not enough balance.
        balances[msg.sender] = balances[msg.sender].sub(_value);
        balances[_to] = balances[_to].add(_value);
        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 balance) {
        return balances[_owner];
      }
    
    
      /**
       * @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);
        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;
        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];
      }
    }
    // ================= Standard Token Contract end ========================
    
    // ================= Pausable Token Contract start ======================
    /**
     * @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 allow actions only when the contract IS paused
      */
      modifier whenNotPaused() {
        require (!paused);
        _;
      }
    
      /**
      * @dev modifier to allow actions only when the contract IS NOT paused
      */
      modifier whenPaused {
        require (paused) ;
        _;
      }
    
      /**
      * @dev called by the owner to pause, triggers stopped state
      */
      function pause() public onlyOwner whenNotPaused returns (bool) {
        paused = true;
        Pause();
        return true;
      }
    
      /**
      * @dev called by the owner to unpause, returns to normal state
      */
      function unpause() public onlyOwner whenPaused returns (bool) {
        paused = false;
        Unpause();
        return true;
      }
    }
    // ================= Pausable Token Contract end ========================
    
    // ================= Tomocoin  start =======================
    contract TomoCoin is StandardToken, Pausable {
      string public constant name = 'Tomocoin';
      string public constant symbol = 'TOMO';
      uint256 public constant decimals = 18;
      address public tokenSaleAddress;
      address public tomoDepositAddress; // multisig wallet
    
      uint256 public constant tomoDeposit = 100000000 * 10**decimals;
    
      function TomoCoin(address _tomoDepositAddress) public { 
        tomoDepositAddress = _tomoDepositAddress;
    
        balances[tomoDepositAddress] = tomoDeposit;
        Transfer(0x0, tomoDepositAddress, tomoDeposit);
        totalSupply_ = tomoDeposit;
      }
    
      function transfer(address _to, uint256 _value) public whenNotPaused returns (bool success) {
        return super.transfer(_to,_value);
      }
    
      function approve(address _spender, uint256 _value) public whenNotPaused returns (bool success) {
        return super.approve(_spender, _value);
      }
    
      function balanceOf(address _owner) public view returns (uint256 balance) {
        return super.balanceOf(_owner);
      }
    
      // Setup Token Sale Smart Contract
      function setTokenSaleAddress(address _tokenSaleAddress) public onlyOwner {
        if (_tokenSaleAddress != address(0)) {
          tokenSaleAddress = _tokenSaleAddress;
        }
      }
    
      function mint(address _recipient, uint256 _value) public whenNotPaused returns (bool success) {
          require(_value > 0);
          // This function is only called by Token Sale Smart Contract
          require(msg.sender == tokenSaleAddress);
    
          balances[tomoDepositAddress] = balances[tomoDepositAddress].sub(_value);
          balances[ _recipient ] = balances[_recipient].add(_value);
    
          Transfer(tomoDepositAddress, _recipient, _value);
          return true;
      }
    }
    // ================= Ico Token Contract end =======================
    
    
    // ================= Whitelist start ====================
    contract TomoContributorWhitelist is Ownable {
        mapping(address => uint256) public whitelist;
    
        function TomoContributorWhitelist() public {}
    
        event ListAddress( address _user, uint256 cap, uint256 _time );
    
        function listAddress( address _user, uint256 cap ) public onlyOwner {
            whitelist[_user] = cap;
            ListAddress( _user, cap, now );
        }
    
        function listAddresses( address[] _users, uint256[] _caps ) public onlyOwner {
            for( uint i = 0 ; i < _users.length ; i++ ) {
                listAddress( _users[i], _caps[i] );
            }
        }
    
        function getCap( address _user ) public view returns(uint) {
            return whitelist[_user];
        }
    }
    // ================= Whitelist end ====================
    
    // ================= Actual Sale Contract Start ====================
    contract TomoTokenSale is Pausable {
      using SafeMath for uint256;
    
      TomoCoin tomo;
      TomoContributorWhitelist whitelist;
      mapping(address => uint256) public participated;
    
      address public ethFundDepositAddress;
      address public tomoDepositAddress;
    
      uint256 public constant tokenCreationCap = 4000000 * 10**18;
      uint256 public totalTokenSold = 0;
      uint256 public constant fundingStartTime = 1519876800; // 2018/03/01 04:00:00
      uint256 public constant fundingPoCEndTime = 1519963200; // 2018/03/02 04:00:00
      uint256 public constant fundingEndTime = 1520136000; // 2018/03/04 04:00:00
      uint256 public constant minContribution = 0.1 ether;
      uint256 public constant maxContribution = 10 ether;
      uint256 public constant tokenExchangeRate = 3200;
      uint256 public constant maxCap = tokenExchangeRate * maxContribution;
    
      bool public isFinalized;
    
      event MintTomo(address from, address to, uint256 val);
      event RefundTomo(address to, uint256 val);
    
      function TomoTokenSale(
        TomoCoin _tomoCoinAddress,
        TomoContributorWhitelist _tomoContributorWhitelistAddress,
        address _ethFundDepositAddress,
        address _tomoDepositAddress
      ) public
      {
        tomo = TomoCoin(_tomoCoinAddress);
        whitelist = TomoContributorWhitelist(_tomoContributorWhitelistAddress);
        ethFundDepositAddress = _ethFundDepositAddress;
        tomoDepositAddress = _tomoDepositAddress;
    
        isFinalized = false;
      }
    
      function buy(address to, uint256 val) internal returns (bool success) {
        MintTomo(tomoDepositAddress, to, val);
        return tomo.mint(to, val);
      }
    
      function () public payable {    
        createTokens(msg.sender, msg.value);
      }
    
      function createTokens(address _beneficiary, uint256 _value) internal whenNotPaused {
        require (now >= fundingStartTime);
        require (now <= fundingEndTime);
        require (_value >= minContribution);
        require (_value <= maxContribution);
        require (!isFinalized);
    
        uint256 tokens = _value.mul(tokenExchangeRate);
    
        uint256 cap = whitelist.getCap(_beneficiary);
        require (cap > 0);
    
        uint256 tokensToAllocate = 0;
        uint256 tokensToRefund = 0;
        uint256 etherToRefund = 0;
    
        // running while PoC Buying Time
        if (now <= fundingPoCEndTime) {
          tokensToAllocate = cap.sub(participated[_beneficiary]);
        } else {
          tokensToAllocate = maxCap.sub(participated[_beneficiary]);
        }
    
        // calculate refund if over max cap or individual cap
        if (tokens > tokensToAllocate) {
          tokensToRefund = tokens.sub(tokensToAllocate);
          etherToRefund = tokensToRefund.div(tokenExchangeRate);
        } else {
          // user can buy amount they want
          tokensToAllocate = tokens;
        }
    
        uint256 checkedTokenSold = totalTokenSold.add(tokensToAllocate);
    
        // if reaches hard cap
        if (tokenCreationCap < checkedTokenSold) {
          tokensToAllocate = tokenCreationCap.sub(totalTokenSold);
          tokensToRefund   = tokens.sub(tokensToAllocate);
          etherToRefund = tokensToRefund.div(tokenExchangeRate);
          totalTokenSold = tokenCreationCap;
        } else {
          totalTokenSold = checkedTokenSold;
        }
    
        // save to participated data
        participated[_beneficiary] = participated[_beneficiary].add(tokensToAllocate);
    
        // allocate tokens
        require(buy(_beneficiary, tokensToAllocate));
        if (etherToRefund > 0) {
          // refund in case user buy over hard cap, individual cap
          RefundTomo(msg.sender, etherToRefund);
          msg.sender.transfer(etherToRefund);
        }
        ethFundDepositAddress.transfer(this.balance);
        return;
      }
    
      /// @dev Ends the funding period and sends the ETH home
      function finalize() external onlyOwner {
        require (!isFinalized);
        // move to operational
        isFinalized = true;
        ethFundDepositAddress.transfer(this.balance);
      }
    }