diff --git a/contracts/token/ApprovalReceiver.sol b/contracts/token/ApprovalReceiver.sol new file mode 100644 index 0000000..866e1b0 --- /dev/null +++ b/contracts/token/ApprovalReceiver.sol @@ -0,0 +1,5 @@ +pragma solidity ^0.4.11; + +contract ApprovalReceiver { + function receiveApproval(address from, uint value, address tokenContract, bytes extraData) returns (bool); +} diff --git a/contracts/token/StandardToken.sol b/contracts/token/StandardToken.sol index b80c513..484cfeb 100644 --- a/contracts/token/StandardToken.sol +++ b/contracts/token/StandardToken.sol @@ -9,25 +9,34 @@ contract StandardToken is ERC20Token { mapping (address => mapping (address => uint256)) allowed; constructor() internal { } - + function transfer( address _to, uint256 _value - ) - external + ) + external returns (bool success) { - return transfer(msg.sender, _to, _value); + return transfer(msg.sender, _to, _value); } - function approve(address _spender, uint256 _value) - external - returns (bool success) - { - allowed[msg.sender][_spender] = _value; - emit Approval(msg.sender, _spender, _value); - return true; - } + /** + * @dev Aprove the passed address to spend the specified amount of tokens on behalf of msg.sender. + * @param _spender The address which will spend the funds. + * @param _value The amount of tokens to be spent. + */ + function approve(address _spender, uint256 _value) returns (bool) { + + // To change the approve amount you first have to reduce the addresses` + // allowance to zero by calling `approve(_spender, 0)` if it is not + // already 0 to mitigate the race condition described here: + // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + require((_value == 0) || (allowed[msg.sender][_spender] == 0)); + + allowed[msg.sender][_spender] = _value; + Approval(msg.sender, _spender, _value); + return true; + } function transferFrom( address _from, @@ -38,35 +47,35 @@ contract StandardToken is ERC20Token { returns (bool success) { if (balances[_from] >= _value && - allowed[_from][msg.sender] >= _value && + allowed[_from][msg.sender] >= _value && _value > 0) { allowed[_from][msg.sender] -= _value; return transfer(_from, _to, _value); - } else { - return false; + } else { + return false; } } - function allowance(address _owner, address _spender) - external - view + function allowance(address _owner, address _spender) + external + view returns (uint256 remaining) { return allowed[_owner][_spender]; } - function balanceOf(address _owner) - external - view - returns (uint256 balance) + function balanceOf(address _owner) + external + view + returns (uint256 balance) { return balances[_owner]; } - - function totalSupply() - external - view - returns(uint256 currentTotalSupply) + + function totalSupply() + external + view + returns(uint256 currentTotalSupply) { return supply; } @@ -74,7 +83,7 @@ contract StandardToken is ERC20Token { function mint( address _to, uint256 _amount - ) + ) internal { balances[_to] += _amount; @@ -83,11 +92,11 @@ contract StandardToken is ERC20Token { } function transfer( - address _from, + address _from, address _to, uint256 _value ) - internal + internal returns (bool success) { if (balances[_from] >= _value && _value > 0) { @@ -95,8 +104,8 @@ contract StandardToken is ERC20Token { balances[_to] += _value; emit Transfer(_from, _to, _value); return true; - } else { - return false; + } else { + return false; } } diff --git a/contracts/token/TestToken.sol b/contracts/token/TestToken.sol index 2afff21..0845c45 100644 --- a/contracts/token/TestToken.sol +++ b/contracts/token/TestToken.sol @@ -1,19 +1,26 @@ pragma solidity ^0.4.23; import "./StandardToken.sol"; +import './ApprovalReceiver.sol'; /** * @notice ERC20Token for test scripts, can be minted by anyone. */ contract TestToken is StandardToken { - + constructor() public { } /** - * @notice any caller can mint any `_amount` + * @notice any caller can mint any `_amount` * @param _amount how much to be minted */ function mint(uint256 _amount) public { mint(msg.sender, _amount); } + + function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) { + assert(approve(_spender, _value)); + return ApprovalReceiver(_spender).receiveApproval(msg.sender, _value, this, _extraData); + } + }