ETH Price: $2,515.76 (-0.83%)

Transaction Decoder

Block:
9235570 at Jan-07-2020 08:08:06 PM +UTC
Transaction Fee:
0.000240336 ETH $0.60
Gas Used:
60,084 Gas / 4 Gwei

Emitted Events:

34 OysterPearl.Transfer( _from=[Sender] 0x343a3c7f789335c9ea60932d34be258f643678d9, _to=[Receiver] EtherDelta, _value=1000000000000000000000 )
35 EtherDelta.Deposit( token=OysterPearl, user=[Sender] 0x343a3c7f789335c9ea60932d34be258f643678d9, amount=1000000000000000000000, balance=1000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x1844b215...aaBA46ab9
0x343a3C7F...F643678d9
0.004759477281576316 Eth
Nonce: 295
0.004519141281576316 Eth
Nonce: 296
0.000240336
0x8d12A197...2A5CC6819
(EtherDelta 2)
(Ethermine)
751.520167357699226259 Eth751.520407693699226259 Eth0.000240336

Execution Trace

EtherDelta.depositToken( token=0x1844b21593262668B7248d0f57a220CaaBA46ab9, amount=1000000000000000000000 )
  • OysterPearl.transferFrom( _from=0x343a3C7F789335C9EA60932D34bE258F643678d9, _to=0x8d12A197cB00D4747a1fe03395095ce2A5CC6819, _value=1000000000000000000000 ) => ( success=True )
    File 1 of 2: EtherDelta
    pragma solidity ^0.4.9;
    
    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;
      }
    
      function assert(bool assertion) internal {
        if (!assertion) throw;
      }
    }
    
    contract Token {
      /// @return total amount of tokens
      function totalSupply() constant returns (uint256 supply) {}
    
      /// @param _owner The address from which the balance will be retrieved
      /// @return The balance
      function balanceOf(address _owner) constant returns (uint256 balance) {}
    
      /// @notice send `_value` token to `_to` from `msg.sender`
      /// @param _to The address of the recipient
      /// @param _value The amount of token to be transferred
      /// @return Whether the transfer was successful or not
      function transfer(address _to, uint256 _value) returns (bool success) {}
    
      /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
      /// @param _from The address of the sender
      /// @param _to The address of the recipient
      /// @param _value The amount of token to be transferred
      /// @return Whether the transfer was successful or not
      function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {}
    
      /// @notice `msg.sender` approves `_addr` to spend `_value` tokens
      /// @param _spender The address of the account able to transfer the tokens
      /// @param _value The amount of wei to be approved for transfer
      /// @return Whether the approval was successful or not
      function approve(address _spender, uint256 _value) returns (bool success) {}
    
      /// @param _owner The address of the account owning tokens
      /// @param _spender The address of the account able to transfer the tokens
      /// @return Amount of remaining tokens allowed to spent
      function allowance(address _owner, address _spender) constant returns (uint256 remaining) {}
    
      event Transfer(address indexed _from, address indexed _to, uint256 _value);
      event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    
      uint public decimals;
      string public name;
    }
    
    contract StandardToken is Token {
    
      function transfer(address _to, uint256 _value) returns (bool success) {
        //Default assumes totalSupply can't be over max (2^256 - 1).
        //If your token leaves out totalSupply and can issue more tokens as time goes on, you need to check if it doesn't wrap.
        //Replace the if with this one instead.
        if (balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
        //if (balances[msg.sender] >= _value && _value > 0) {
          balances[msg.sender] -= _value;
          balances[_to] += _value;
          Transfer(msg.sender, _to, _value);
          return true;
        } else { return false; }
      }
    
      function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        //same as above. Replace this line with the following if you want to protect against wrapping uints.
        if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
        //if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
          balances[_to] += _value;
          balances[_from] -= _value;
          allowed[_from][msg.sender] -= _value;
          Transfer(_from, _to, _value);
          return true;
        } else { return false; }
      }
    
      function balanceOf(address _owner) constant returns (uint256 balance) {
        return balances[_owner];
      }
    
      function approve(address _spender, uint256 _value) returns (bool success) {
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
      }
    
      function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
        return allowed[_owner][_spender];
      }
    
      mapping(address => uint256) balances;
    
      mapping (address => mapping (address => uint256)) allowed;
    
      uint256 public totalSupply;
    }
    
    contract ReserveToken is StandardToken, SafeMath {
      address public minter;
      function ReserveToken() {
        minter = msg.sender;
      }
      function create(address account, uint amount) {
        if (msg.sender != minter) throw;
        balances[account] = safeAdd(balances[account], amount);
        totalSupply = safeAdd(totalSupply, amount);
      }
      function destroy(address account, uint amount) {
        if (msg.sender != minter) throw;
        if (balances[account] < amount) throw;
        balances[account] = safeSub(balances[account], amount);
        totalSupply = safeSub(totalSupply, amount);
      }
    }
    
    contract AccountLevels {
      //given a user, returns an account level
      //0 = regular user (pays take fee and make fee)
      //1 = market maker silver (pays take fee, no make fee, gets rebate)
      //2 = market maker gold (pays take fee, no make fee, gets entire counterparty's take fee as rebate)
      function accountLevel(address user) constant returns(uint) {}
    }
    
    contract AccountLevelsTest is AccountLevels {
      mapping (address => uint) public accountLevels;
    
      function setAccountLevel(address user, uint level) {
        accountLevels[user] = level;
      }
    
      function accountLevel(address user) constant returns(uint) {
        return accountLevels[user];
      }
    }
    
    contract EtherDelta is SafeMath {
      address public admin; //the admin address
      address public feeAccount; //the account that will receive fees
      address public accountLevelsAddr; //the address of the AccountLevels contract
      uint public feeMake; //percentage times (1 ether)
      uint public feeTake; //percentage times (1 ether)
      uint public feeRebate; //percentage times (1 ether)
      mapping (address => mapping (address => uint)) public tokens; //mapping of token addresses to mapping of account balances (token=0 means Ether)
      mapping (address => mapping (bytes32 => bool)) public orders; //mapping of user accounts to mapping of order hashes to booleans (true = submitted by user, equivalent to offchain signature)
      mapping (address => mapping (bytes32 => uint)) public orderFills; //mapping of user accounts to mapping of order hashes to uints (amount of order that has been filled)
    
      event Order(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user);
      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);
      event Deposit(address token, address user, uint amount, uint balance);
      event Withdraw(address token, address user, uint amount, uint balance);
    
      function EtherDelta(address admin_, address feeAccount_, address accountLevelsAddr_, uint feeMake_, uint feeTake_, uint feeRebate_) {
        admin = admin_;
        feeAccount = feeAccount_;
        accountLevelsAddr = accountLevelsAddr_;
        feeMake = feeMake_;
        feeTake = feeTake_;
        feeRebate = feeRebate_;
      }
    
      function() {
        throw;
      }
    
      function changeAdmin(address admin_) {
        if (msg.sender != admin) throw;
        admin = admin_;
      }
    
      function changeAccountLevelsAddr(address accountLevelsAddr_) {
        if (msg.sender != admin) throw;
        accountLevelsAddr = accountLevelsAddr_;
      }
    
      function changeFeeAccount(address feeAccount_) {
        if (msg.sender != admin) throw;
        feeAccount = feeAccount_;
      }
    
      function changeFeeMake(uint feeMake_) {
        if (msg.sender != admin) throw;
        if (feeMake_ > feeMake) throw;
        feeMake = feeMake_;
      }
    
      function changeFeeTake(uint feeTake_) {
        if (msg.sender != admin) throw;
        if (feeTake_ > feeTake || feeTake_ < feeRebate) throw;
        feeTake = feeTake_;
      }
    
      function changeFeeRebate(uint feeRebate_) {
        if (msg.sender != admin) throw;
        if (feeRebate_ < feeRebate || feeRebate_ > feeTake) throw;
        feeRebate = feeRebate_;
      }
    
      function deposit() payable {
        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) {
        if (tokens[0][msg.sender] < amount) throw;
        tokens[0][msg.sender] = safeSub(tokens[0][msg.sender], amount);
        if (!msg.sender.call.value(amount)()) throw;
        Withdraw(0, msg.sender, amount, tokens[0][msg.sender]);
      }
    
      function depositToken(address token, uint amount) {
        //remember to call Token(address).approve(this, amount) or this contract will not be able to do the transfer on your behalf.
        if (token==0) throw;
        if (!Token(token).transferFrom(msg.sender, this, amount)) throw;
        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) {
        if (token==0) throw;
        if (tokens[token][msg.sender] < amount) throw;
        tokens[token][msg.sender] = safeSub(tokens[token][msg.sender], amount);
        if (!Token(token).transfer(msg.sender, amount)) throw;
        Withdraw(token, msg.sender, amount, tokens[token][msg.sender]);
      }
    
      function balanceOf(address token, address user) constant returns (uint) {
        return tokens[token][user];
      }
    
      function order(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce) {
        bytes32 hash = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce);
        orders[msg.sender][hash] = true;
        Order(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, msg.sender);
      }
    
      function trade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s, uint amount) {
        //amount is in amountGet terms
        bytes32 hash = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce);
        if (!(
          (orders[user][hash] || ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash),v,r,s) == user) &&
          block.number <= expires &&
          safeAdd(orderFills[user][hash], amount) <= amountGet
        )) throw;
        tradeBalances(tokenGet, amountGet, tokenGive, amountGive, user, amount);
        orderFills[user][hash] = safeAdd(orderFills[user][hash], amount);
        Trade(tokenGet, amount, tokenGive, amountGive * amount / amountGet, user, msg.sender);
      }
    
      function tradeBalances(address tokenGet, uint amountGet, address tokenGive, uint amountGive, address user, uint amount) private {
        uint feeMakeXfer = safeMul(amount, feeMake) / (1 ether);
        uint feeTakeXfer = safeMul(amount, feeTake) / (1 ether);
        uint feeRebateXfer = 0;
        if (accountLevelsAddr != 0x0) {
          uint accountLevel = AccountLevels(accountLevelsAddr).accountLevel(user);
          if (accountLevel==1) feeRebateXfer = safeMul(amount, feeRebate) / (1 ether);
          if (accountLevel==2) feeRebateXfer = feeTakeXfer;
        }
        tokens[tokenGet][msg.sender] = safeSub(tokens[tokenGet][msg.sender], safeAdd(amount, feeTakeXfer));
        tokens[tokenGet][user] = safeAdd(tokens[tokenGet][user], safeSub(safeAdd(amount, feeRebateXfer), feeMakeXfer));
        tokens[tokenGet][feeAccount] = safeAdd(tokens[tokenGet][feeAccount], safeSub(safeAdd(feeMakeXfer, feeTakeXfer), feeRebateXfer));
        tokens[tokenGive][user] = safeSub(tokens[tokenGive][user], safeMul(amountGive, amount) / amountGet);
        tokens[tokenGive][msg.sender] = safeAdd(tokens[tokenGive][msg.sender], safeMul(amountGive, amount) / amountGet);
      }
    
      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 (!(
          (orders[user][hash] || 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, uint8 v, bytes32 r, bytes32 s) 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 (!(orders[msg.sender][hash] || ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash),v,r,s) == msg.sender)) throw;
        orderFills[msg.sender][hash] = amountGet;
        Cancel(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, msg.sender, v, r, s);
      }
    }

    File 2 of 2: OysterPearl
    pragma solidity ^0.4.18;
    
    interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; }
    
    contract OysterPearl {
        // Public variables of PRL
        string public name;
        string public symbol;
        uint8 public decimals;
        uint256 public totalSupply;
        uint256 public funds;
        address public director;
        bool public saleClosed;
        bool public directorLock;
        uint256 public claimAmount;
        uint256 public payAmount;
        uint256 public feeAmount;
        uint256 public epoch;
        uint256 public retentionMax;
    
        // Array definitions
        mapping (address => uint256) public balances;
        mapping (address => mapping (address => uint256)) public allowance;
        mapping (address => bool) public buried;
        mapping (address => uint256) public claimed;
    
        // ERC20 event
        event Transfer(address indexed _from, address indexed _to, uint256 _value);
        
        // ERC20 event
        event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    
        // This notifies clients about the amount burnt
        event Burn(address indexed _from, uint256 _value);
        
        // This notifies clients about an address getting buried
        event Bury(address indexed _target, uint256 _value);
        
        // This notifies clients about a claim being made on a buried address
        event Claim(address indexed _target, address indexed _payout, address indexed _fee);
    
        /**
         * Constructor function
         *
         * Initializes contract
         */
        function OysterPearl() public {
            director = msg.sender;
            name = "Oyster Pearl";
            symbol = "PRL";
            decimals = 18;
            saleClosed = true;
            directorLock = false;
            funds = 0;
            totalSupply = 0;
            
            // Marketing share (5%)
            totalSupply += 25000000 * 10 ** uint256(decimals);
            
            // Devfund share (15%)
            totalSupply += 75000000 * 10 ** uint256(decimals);
            
            // Allocation to match PREPRL supply and reservation for discretionary use
            totalSupply += 8000000 * 10 ** uint256(decimals);
            
            // Assign reserved PRL supply to the director
            balances[director] = totalSupply;
            
            // Define default values for Oyster functions
            claimAmount = 5 * 10 ** (uint256(decimals) - 1);
            payAmount = 4 * 10 ** (uint256(decimals) - 1);
            feeAmount = 1 * 10 ** (uint256(decimals) - 1);
            
            // Seconds in a year
            epoch = 31536000;
            
            // Maximum time for a sector to remain stored
            retentionMax = 40 * 10 ** uint256(decimals);
        }
        
        /**
         * ERC20 balance function
         */
        function balanceOf(address _owner) public constant returns (uint256 balance) {
            return balances[_owner];
        }
        
        modifier onlyDirector {
            // Director can lock themselves out to complete decentralization of Oyster network
            // An alternative is that another smart contract could become the decentralized director
            require(!directorLock);
            
            // Only the director is permitted
            require(msg.sender == director);
            _;
        }
        
        modifier onlyDirectorForce {
            // Only the director is permitted
            require(msg.sender == director);
            _;
        }
        
        /**
         * Transfers the director to a new address
         */
        function transferDirector(address newDirector) public onlyDirectorForce {
            director = newDirector;
        }
        
        /**
         * Withdraw funds from the contract
         */
        function withdrawFunds() public onlyDirectorForce {
            director.transfer(this.balance);
        }
        
        /**
         * Permanently lock out the director to decentralize Oyster
         * Invocation is discretionary because Oyster might be better suited to
         * transition to an artificially intelligent smart contract director
         */
        function selfLock() public payable onlyDirector {
            // The sale must be closed before the director gets locked out
            require(saleClosed);
            
            // Prevents accidental lockout
            require(msg.value == 10 ether);
            
            // Permanently lock out the director
            directorLock = true;
        }
        
        /**
         * Director can alter the storage-peg and broker fees
         */
        function amendClaim(uint8 claimAmountSet, uint8 payAmountSet, uint8 feeAmountSet, uint8 accuracy) public onlyDirector returns (bool success) {
            require(claimAmountSet == (payAmountSet + feeAmountSet));
            
            claimAmount = claimAmountSet * 10 ** (uint256(decimals) - accuracy);
            payAmount = payAmountSet * 10 ** (uint256(decimals) - accuracy);
            feeAmount = feeAmountSet * 10 ** (uint256(decimals) - accuracy);
            return true;
        }
        
        /**
         * Director can alter the epoch time
         */
        function amendEpoch(uint256 epochSet) public onlyDirector returns (bool success) {
            // Set the epoch
            epoch = epochSet;
            return true;
        }
        
        /**
         * Director can alter the maximum time of storage retention
         */
        function amendRetention(uint8 retentionSet, uint8 accuracy) public onlyDirector returns (bool success) {
            // Set retentionMax
            retentionMax = retentionSet * 10 ** (uint256(decimals) - accuracy);
            return true;
        }
        
        /**
         * Director can close the crowdsale
         */
        function closeSale() public onlyDirector returns (bool success) {
            // The sale must be currently open
            require(!saleClosed);
            
            // Lock the crowdsale
            saleClosed = true;
            return true;
        }
    
        /**
         * Director can open the crowdsale
         */
        function openSale() public onlyDirector returns (bool success) {
            // The sale must be currently closed
            require(saleClosed);
            
            // Unlock the crowdsale
            saleClosed = false;
            return true;
        }
        
        /**
         * Oyster Protocol Function
         * More information at https://oyster.ws/OysterWhitepaper.pdf
         * 
         * Bury an address
         *
         * When an address is buried; only claimAmount can be withdrawn once per epoch
         */
        function bury() public returns (bool success) {
            // The address must be previously unburied
            require(!buried[msg.sender]);
            
            // An address must have at least claimAmount to be buried
            require(balances[msg.sender] >= claimAmount);
            
            // Prevent addresses with large balances from getting buried
            require(balances[msg.sender] <= retentionMax);
            
            // Set buried state to true
            buried[msg.sender] = true;
            
            // Set the initial claim clock to 1
            claimed[msg.sender] = 1;
            
            // Execute an event reflecting the change
            Bury(msg.sender, balances[msg.sender]);
            return true;
        }
        
        /**
         * Oyster Protocol Function
         * More information at https://oyster.ws/OysterWhitepaper.pdf
         * 
         * Claim PRL from a buried address
         *
         * If a prior claim wasn't made during the current epoch, then claimAmount can be withdrawn
         *
         * @param _payout the address of the website owner
         * @param _fee the address of the broker node
         */
        function claim(address _payout, address _fee) public returns (bool success) {
            // The claimed address must have already been buried
            require(buried[msg.sender]);
            
            // The payout and fee addresses must be different
            require(_payout != _fee);
            
            // The claimed address cannot pay itself
            require(msg.sender != _payout);
            
            // The claimed address cannot pay itself
            require(msg.sender != _fee);
            
            // It must be either the first time this address is being claimed or atleast epoch in time has passed
            require(claimed[msg.sender] == 1 || (block.timestamp - claimed[msg.sender]) >= epoch);
            
            // Check if the buried address has enough
            require(balances[msg.sender] >= claimAmount);
            
            // Reset the claim clock to the current block time
            claimed[msg.sender] = block.timestamp;
            
            // Save this for an assertion in the future
            uint256 previousBalances = balances[msg.sender] + balances[_payout] + balances[_fee];
            
            // Remove claimAmount from the buried address
            balances[msg.sender] -= claimAmount;
            
            // Pay the website owner that invoked the web node that found the PRL seed key
            balances[_payout] += payAmount;
            
            // Pay the broker node that unlocked the PRL
            balances[_fee] += feeAmount;
            
            // Execute events to reflect the changes
            Claim(msg.sender, _payout, _fee);
            Transfer(msg.sender, _payout, payAmount);
            Transfer(msg.sender, _fee, feeAmount);
            
            // Failsafe logic that should never be false
            assert(balances[msg.sender] + balances[_payout] + balances[_fee] == previousBalances);
            return true;
        }
        
        /**
         * Crowdsale function
         */
        function () public payable {
            // Check if crowdsale is still active
            require(!saleClosed);
            
            // Minimum amount is 1 finney
            require(msg.value >= 1 finney);
            
            // Price is 1 ETH = 5000 PRL
            uint256 amount = msg.value * 5000;
            
            // totalSupply limit is 500 million PRL
            require(totalSupply + amount <= (500000000 * 10 ** uint256(decimals)));
            
            // Increases the total supply
            totalSupply += amount;
            
            // Adds the amount to the balance
            balances[msg.sender] += amount;
            
            // Track ETH amount raised
            funds += msg.value;
            
            // Execute an event reflecting the change
            Transfer(this, msg.sender, amount);
        }
    
        /**
         * Internal transfer, can be called by this contract only
         */
        function _transfer(address _from, address _to, uint _value) internal {
            // Sending addresses cannot be buried
            require(!buried[_from]);
            
            // If the receiving address is buried, it cannot exceed retentionMax
            if (buried[_to]) {
                require(balances[_to] + _value <= retentionMax);
            }
            
            // Prevent transfer to 0x0 address, use burn() instead
            require(_to != 0x0);
            
            // Check if the sender has enough
            require(balances[_from] >= _value);
            
            // Check for overflows
            require(balances[_to] + _value > balances[_to]);
            
            // Save this for an assertion in the future
            uint256 previousBalances = balances[_from] + balances[_to];
            
            // Subtract from the sender
            balances[_from] -= _value;
            
            // Add the same to the recipient
            balances[_to] += _value;
            Transfer(_from, _to, _value);
            
            // Failsafe logic that should never be false
            assert(balances[_from] + balances[_to] == previousBalances);
        }
    
        /**
         * Transfer tokens
         *
         * Send `_value` tokens to `_to` from your account
         *
         * @param _to the address of the recipient
         * @param _value the amount to send
         */
        function transfer(address _to, uint256 _value) public {
            _transfer(msg.sender, _to, _value);
        }
    
        /**
         * Transfer tokens from other address
         *
         * Send `_value` tokens to `_to` in behalf of `_from`
         *
         * @param _from the address of the sender
         * @param _to the address of the recipient
         * @param _value the amount to send
         */
        function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
            // Check allowance
            require(_value <= allowance[_from][msg.sender]);
            allowance[_from][msg.sender] -= _value;
            _transfer(_from, _to, _value);
            return true;
        }
    
        /**
         * Set allowance for other address
         *
         * Allows `_spender` to spend no more than `_value` tokens on your behalf
         *
         * @param _spender the address authorized to spend
         * @param _value the max amount they can spend
         */
        function approve(address _spender, uint256 _value) public returns (bool success) {
            // Buried addresses cannot be approved
            require(!buried[msg.sender]);
            
            allowance[msg.sender][_spender] = _value;
            Approval(msg.sender, _spender, _value);
            return true;
        }
    
        /**
         * Set allowance for other address and notify
         *
         * Allows `_spender` to spend no more than `_value` tokens on your behalf, and then ping the contract about it
         *
         * @param _spender the address authorized to spend
         * @param _value the max amount they can spend
         * @param _extraData some extra information to send to the approved contract
         */
        function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) {
            tokenRecipient spender = tokenRecipient(_spender);
            if (approve(_spender, _value)) {
                spender.receiveApproval(msg.sender, _value, this, _extraData);
                return true;
            }
        }
    
        /**
         * Destroy tokens
         *
         * Remove `_value` tokens from the system irreversibly
         *
         * @param _value the amount of money to burn
         */
        function burn(uint256 _value) public returns (bool success) {
            // Buried addresses cannot be burnt
            require(!buried[msg.sender]);
            
            // Check if the sender has enough
            require(balances[msg.sender] >= _value);
            
            // Subtract from the sender
            balances[msg.sender] -= _value;
            
            // Updates totalSupply
            totalSupply -= _value;
            Burn(msg.sender, _value);
            return true;
        }
    
        /**
         * Destroy tokens from other account
         *
         * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
         *
         * @param _from the address of the sender
         * @param _value the amount of money to burn
         */
        function burnFrom(address _from, uint256 _value) public returns (bool success) {
            // Buried addresses cannot be burnt
            require(!buried[_from]);
            
            // Check if the targeted balance is enough
            require(balances[_from] >= _value);
            
            // Check allowance
            require(_value <= allowance[_from][msg.sender]);
            
            // Subtract from the targeted balance
            balances[_from] -= _value;
            
            // Subtract from the sender's allowance
            allowance[_from][msg.sender] -= _value;
            
            // Update totalSupply
            totalSupply -= _value;
            Burn(_from, _value);
            return true;
        }
    }