Transaction Hash:
Block:
8911994 at Nov-11-2019 03:03:53 AM +UTC
Transaction Fee:
0.000605242 ETH
$1.51
Gas Used:
55,022 Gas / 11 Gwei
Emitted Events:
71 |
OysterPearl.Transfer( _from=[Sender] 0x343a3c7f789335c9ea60932d34be258f643678d9, _to=[Receiver] TokenStore, _value=441000000000000000000 )
|
72 |
TokenStore.Deposit( token=OysterPearl, user=[Sender] 0x343a3c7f789335c9ea60932d34be258f643678d9, amount=441000000000000000000, balance=441000000000000000000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x1844b215...aaBA46ab9 | |||||
0x1cE7AE55...ee6Ee33D8 | (Token.Store) | ||||
0x343a3C7F...F643678d9 |
0.009137692281576316 Eth
Nonce: 283
|
0.008532450281576316 Eth
Nonce: 284
| 0.000605242 | ||
0xD224cA0c...503B79f53
Miner
| (UUPool) | 24.102300667458681475 Eth | 24.102905909458681475 Eth | 0.000605242 |
Execution Trace
TokenStore.depositToken( _token=0x1844b21593262668B7248d0f57a220CaaBA46ab9, _amount=441000000000000000000 )
-
OysterPearl.transferFrom( _from=0x343a3C7F789335C9EA60932D34bE258F643678d9, _to=0x1cE7AE555139c5EF5A57CC8d814a867ee6Ee33D8, _value=441000000000000000000 ) => ( success=True )
depositToken[TokenStore (ln:183)]
transferFrom[TokenStore (ln:187)]
revert[TokenStore (ln:188)]
safeAdd[TokenStore (ln:190)]
Deposit[TokenStore (ln:191)]
File 1 of 2: TokenStore
File 2 of 2: OysterPearl
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 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; } }