diff --git a/contracts/crowdsale/emission/AllowanceCrowdsale.sol b/contracts/crowdsale/emission/AllowanceCrowdsale.sol index e271076a8..4b0665cba 100644 --- a/contracts/crowdsale/emission/AllowanceCrowdsale.sol +++ b/contracts/crowdsale/emission/AllowanceCrowdsale.sol @@ -2,7 +2,6 @@ pragma solidity ^0.4.24; import "../Crowdsale.sol"; import "../../token/ERC20/ERC20.sol"; -import "../../token/ERC20/ERC20Basic.sol"; import "../../token/ERC20/SafeERC20.sol"; import "../../math/SafeMath.sol"; diff --git a/contracts/lifecycle/TokenDestructible.sol b/contracts/lifecycle/TokenDestructible.sol index 0a43590a0..38aabcbb1 100644 --- a/contracts/lifecycle/TokenDestructible.sol +++ b/contracts/lifecycle/TokenDestructible.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.24; import "../ownership/Ownable.sol"; -import "../token/ERC20/ERC20Basic.sol"; +import "../token/ERC20/ERC20.sol"; /** @@ -16,7 +16,7 @@ contract TokenDestructible is Ownable { /** * @notice Terminate contract and refund to owner - * @param _tokens List of addresses of ERC20 or ERC20Basic token contracts to + * @param _tokens List of addresses of ERC20 token contracts to refund. * @notice The called token contracts could try to re-enter this contract. Only supply token contracts you trust. @@ -25,7 +25,7 @@ contract TokenDestructible is Ownable { // Transfer tokens to owner for (uint256 i = 0; i < _tokens.length; i++) { - ERC20Basic token = ERC20Basic(_tokens[i]); + ERC20 token = ERC20(_tokens[i]); uint256 balance = token.balanceOf(this); token.transfer(owner, balance); } diff --git a/contracts/mocks/BasicTokenMock.sol b/contracts/mocks/BasicTokenMock.sol deleted file mode 100644 index 400ce9105..000000000 --- a/contracts/mocks/BasicTokenMock.sol +++ /dev/null @@ -1,15 +0,0 @@ -pragma solidity ^0.4.24; - - -import "../token/ERC20/BasicToken.sol"; - - -// mock class using BasicToken -contract BasicTokenMock is BasicToken { - - constructor(address _initialAccount, uint256 _initialBalance) public { - balances[_initialAccount] = _initialBalance; - totalSupply_ = _initialBalance; - } - -} diff --git a/contracts/mocks/ERC223TokenMock.sol b/contracts/mocks/ERC223TokenMock.sol index 3ba5e7c77..410348cc0 100644 --- a/contracts/mocks/ERC223TokenMock.sol +++ b/contracts/mocks/ERC223TokenMock.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "../token/ERC20/BasicToken.sol"; +import "../token/ERC20/StandardToken.sol"; contract ERC223ContractInterface { @@ -8,7 +8,7 @@ contract ERC223ContractInterface { } -contract ERC223TokenMock is BasicToken { +contract ERC223TokenMock is StandardToken { constructor(address _initialAccount, uint256 _initialBalance) public { balances[_initialAccount] = _initialBalance; diff --git a/contracts/mocks/StandardBurnableTokenMock.sol b/contracts/mocks/StandardBurnableTokenMock.sol deleted file mode 100644 index 42cc6ae0e..000000000 --- a/contracts/mocks/StandardBurnableTokenMock.sol +++ /dev/null @@ -1,13 +0,0 @@ -pragma solidity ^0.4.24; - -import "../token/ERC20/StandardBurnableToken.sol"; - - -contract StandardBurnableTokenMock is StandardBurnableToken { - - constructor(address _initialAccount, uint _initialBalance) public { - balances[_initialAccount] = _initialBalance; - totalSupply_ = _initialBalance; - } - -} diff --git a/contracts/ownership/CanReclaimToken.sol b/contracts/ownership/CanReclaimToken.sol index e854e221e..37a78918c 100644 --- a/contracts/ownership/CanReclaimToken.sol +++ b/contracts/ownership/CanReclaimToken.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.24; import "./Ownable.sol"; -import "../token/ERC20/ERC20Basic.sol"; +import "../token/ERC20/ERC20.sol"; import "../token/ERC20/SafeERC20.sol"; @@ -12,13 +12,13 @@ import "../token/ERC20/SafeERC20.sol"; * This will prevent any accidental loss of tokens. */ contract CanReclaimToken is Ownable { - using SafeERC20 for ERC20Basic; + using SafeERC20 for ERC20; /** - * @dev Reclaim all ERC20Basic compatible tokens - * @param _token ERC20Basic The address of the token contract + * @dev Reclaim all ERC20 compatible tokens + * @param _token ERC20 The address of the token contract */ - function reclaimToken(ERC20Basic _token) external onlyOwner { + function reclaimToken(ERC20 _token) external onlyOwner { uint256 balance = _token.balanceOf(this); _token.safeTransfer(owner, balance); } diff --git a/contracts/ownership/HasNoTokens.sol b/contracts/ownership/HasNoTokens.sol index 8724b5101..563a64047 100644 --- a/contracts/ownership/HasNoTokens.sol +++ b/contracts/ownership/HasNoTokens.sol @@ -7,7 +7,7 @@ import "./CanReclaimToken.sol"; * @title Contracts that should not own Tokens * @author Remco Bloemen * @dev This blocks incoming ERC223 tokens to prevent accidental loss of tokens. - * Should tokens (any ERC20Basic compatible) end up in the contract, it allows the + * Should tokens (any ERC20 compatible) end up in the contract, it allows the * owner to reclaim the tokens. */ contract HasNoTokens is CanReclaimToken { diff --git a/contracts/token/ERC20/BasicToken.sol b/contracts/token/ERC20/BasicToken.sol deleted file mode 100644 index b40f10ece..000000000 --- a/contracts/token/ERC20/BasicToken.sol +++ /dev/null @@ -1,50 +0,0 @@ -pragma solidity ^0.4.24; - - -import "./ERC20Basic.sol"; -import "../../math/SafeMath.sol"; - - -/** - * @title Basic token - * @dev Basic version of StandardToken, with no allowances. - */ -contract BasicToken is ERC20Basic { - using SafeMath for uint256; - - mapping(address => uint256) internal balances; - - uint256 internal 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(_value <= balances[msg.sender]); - require(_to != address(0)); - - 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]; - } - -} diff --git a/contracts/token/ERC20/BurnableToken.sol b/contracts/token/ERC20/BurnableToken.sol index 9e5d39960..ad49ff11d 100644 --- a/contracts/token/ERC20/BurnableToken.sol +++ b/contracts/token/ERC20/BurnableToken.sol @@ -1,13 +1,13 @@ pragma solidity ^0.4.24; -import "./BasicToken.sol"; +import "./StandardToken.sol"; /** * @title Burnable Token * @dev Token that can be irreversibly burned (destroyed). */ -contract BurnableToken is BasicToken { +contract BurnableToken is StandardToken { event Burn(address indexed burner, uint256 value); @@ -19,6 +19,19 @@ contract BurnableToken is BasicToken { _burn(msg.sender, _value); } + /** + * @dev Burns a specific amount of tokens from the target address and decrements allowance + * @param _from address The address which you want to send tokens from + * @param _value uint256 The amount of token to be burned + */ + function burnFrom(address _from, uint256 _value) public { + require(_value <= allowed[_from][msg.sender]); + // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted, + // this function needs to emit an event with the updated approval. + allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); + _burn(_from, _value); + } + function _burn(address _who, uint256 _value) internal { require(_value <= balances[_who]); // no need to require value <= totalSupply, since that would imply the @@ -29,4 +42,4 @@ contract BurnableToken is BasicToken { emit Burn(_who, _value); emit Transfer(_who, address(0), _value); } -} +} \ No newline at end of file diff --git a/contracts/token/ERC20/ERC20.sol b/contracts/token/ERC20/ERC20.sol index 04e90d86c..7b152953f 100644 --- a/contracts/token/ERC20/ERC20.sol +++ b/contracts/token/ERC20/ERC20.sol @@ -1,20 +1,32 @@ pragma solidity ^0.4.24; -import "./ERC20Basic.sol"; - /** * @title ERC20 interface * @dev see https://github.com/ethereum/EIPs/issues/20 */ -contract ERC20 is ERC20Basic { +contract ERC20 { + function totalSupply() public view returns (uint256); + + function balanceOf(address _who) public view returns (uint256); + function allowance(address _owner, address _spender) public view returns (uint256); + function transfer(address _to, uint256 _value) public returns (bool); + + function approve(address _spender, uint256 _value) + public returns (bool); + 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, diff --git a/contracts/token/ERC20/ERC20Basic.sol b/contracts/token/ERC20/ERC20Basic.sol deleted file mode 100644 index 1b2d94255..000000000 --- a/contracts/token/ERC20/ERC20Basic.sol +++ /dev/null @@ -1,14 +0,0 @@ -pragma solidity ^0.4.24; - - -/** - * @title ERC20Basic - * @dev Simpler version of ERC20 interface - * 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); -} diff --git a/contracts/token/ERC20/SafeERC20.sol b/contracts/token/ERC20/SafeERC20.sol index 206d19f74..92aaa0fd2 100644 --- a/contracts/token/ERC20/SafeERC20.sol +++ b/contracts/token/ERC20/SafeERC20.sol @@ -1,6 +1,6 @@ pragma solidity ^0.4.24; -import "./ERC20Basic.sol"; +import "./StandardToken.sol"; import "./ERC20.sol"; @@ -12,7 +12,7 @@ import "./ERC20.sol"; */ library SafeERC20 { function safeTransfer( - ERC20Basic _token, + ERC20 _token, address _to, uint256 _value ) diff --git a/contracts/token/ERC20/StandardBurnableToken.sol b/contracts/token/ERC20/StandardBurnableToken.sol deleted file mode 100644 index b0725fd64..000000000 --- a/contracts/token/ERC20/StandardBurnableToken.sol +++ /dev/null @@ -1,25 +0,0 @@ -pragma solidity ^0.4.24; - -import "./BurnableToken.sol"; -import "./StandardToken.sol"; - - -/** - * @title Standard Burnable Token - * @dev Adds burnFrom method to ERC20 implementations - */ -contract StandardBurnableToken is BurnableToken, StandardToken { - - /** - * @dev Burns a specific amount of tokens from the target address and decrements allowance - * @param _from address The address which you want to send tokens from - * @param _value uint256 The amount of token to be burned - */ - function burnFrom(address _from, uint256 _value) public { - require(_value <= allowed[_from][msg.sender]); - // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted, - // this function needs to emit an event with the updated approval. - allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); - _burn(_from, _value); - } -} diff --git a/contracts/token/ERC20/StandardToken.sol b/contracts/token/ERC20/StandardToken.sol index ff09e12ea..88b215473 100644 --- a/contracts/token/ERC20/StandardToken.sol +++ b/contracts/token/ERC20/StandardToken.sol @@ -1,7 +1,7 @@ pragma solidity ^0.4.24; -import "./BasicToken.sol"; import "./ERC20.sol"; +import "../../math/SafeMath.sol"; /** @@ -11,10 +11,77 @@ import "./ERC20.sol"; * https://github.com/ethereum/EIPs/issues/20 * Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol */ -contract StandardToken is ERC20, BasicToken { +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 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]; + } + + /** + * @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 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(_value <= balances[msg.sender]); + require(_to != address(0)); + + balances[msg.sender] = balances[msg.sender].sub(_value); + balances[_to] = balances[_to].add(_value); + emit Transfer(msg.sender, _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 Transfer tokens from one address to another @@ -41,38 +108,6 @@ contract StandardToken is ERC20, BasicToken { 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 diff --git a/contracts/token/ERC20/TokenTimelock.sol b/contracts/token/ERC20/TokenTimelock.sol index ad2f60ede..2e3cd6dd5 100644 --- a/contracts/token/ERC20/TokenTimelock.sol +++ b/contracts/token/ERC20/TokenTimelock.sol @@ -9,10 +9,10 @@ import "./SafeERC20.sol"; * beneficiary to extract the tokens after a given release time */ contract TokenTimelock { - using SafeERC20 for ERC20Basic; + using SafeERC20 for ERC20; // ERC20 basic token contract being held - ERC20Basic public token; + ERC20 public token; // beneficiary of tokens after they are released address public beneficiary; @@ -21,7 +21,7 @@ contract TokenTimelock { uint256 public releaseTime; constructor( - ERC20Basic _token, + ERC20 _token, address _beneficiary, uint256 _releaseTime ) diff --git a/contracts/token/ERC20/TokenVesting.sol b/contracts/token/ERC20/TokenVesting.sol index 66a917558..2ceaa3135 100644 --- a/contracts/token/ERC20/TokenVesting.sol +++ b/contracts/token/ERC20/TokenVesting.sol @@ -2,7 +2,6 @@ pragma solidity ^0.4.24; -import "./ERC20Basic.sol"; import "./SafeERC20.sol"; import "../../ownership/Ownable.sol"; import "../../math/SafeMath.sol"; @@ -16,7 +15,7 @@ import "../../math/SafeMath.sol"; */ contract TokenVesting is Ownable { using SafeMath for uint256; - using SafeERC20 for ERC20Basic; + using SafeERC20 for ERC20; event Released(uint256 amount); event Revoked(); @@ -66,7 +65,7 @@ contract TokenVesting is Ownable { * @notice Transfers vested tokens to beneficiary. * @param _token ERC20 token which is being vested */ - function release(ERC20Basic _token) public { + function release(ERC20 _token) public { uint256 unreleased = releasableAmount(_token); require(unreleased > 0); @@ -83,7 +82,7 @@ contract TokenVesting is Ownable { * remain in the contract, the rest are returned to the owner. * @param _token ERC20 token which is being vested */ - function revoke(ERC20Basic _token) public onlyOwner { + function revoke(ERC20 _token) public onlyOwner { require(revocable); require(!revoked[_token]); @@ -103,7 +102,7 @@ contract TokenVesting is Ownable { * @dev Calculates the amount that has already vested but hasn't been released yet. * @param _token ERC20 token which is being vested */ - function releasableAmount(ERC20Basic _token) public view returns (uint256) { + function releasableAmount(ERC20 _token) public view returns (uint256) { return vestedAmount(_token).sub(released[_token]); } @@ -111,8 +110,8 @@ contract TokenVesting is Ownable { * @dev Calculates the amount that has already vested. * @param _token ERC20 token which is being vested */ - function vestedAmount(ERC20Basic _token) public view returns (uint256) { - uint256 currentBalance = _token.balanceOf(address(this)); + function vestedAmount(ERC20 _token) public view returns (uint256) { + uint256 currentBalance = _token.balanceOf(this); uint256 totalBalance = currentBalance.add(released[_token]); if (block.timestamp < cliff) { diff --git a/test/ownership/CanReclaimToken.test.js b/test/ownership/CanReclaimToken.test.js index 3fe166bbc..8afa2f281 100644 --- a/test/ownership/CanReclaimToken.test.js +++ b/test/ownership/CanReclaimToken.test.js @@ -1,7 +1,7 @@ const { expectThrow } = require('../helpers/expectThrow'); const CanReclaimToken = artifacts.require('CanReclaimToken'); -const BasicTokenMock = artifacts.require('BasicTokenMock'); +const StandardTokenMock = artifacts.require('StandardTokenMock'); contract('CanReclaimToken', function ([_, owner, anyone]) { let token = null; @@ -9,8 +9,9 @@ contract('CanReclaimToken', function ([_, owner, anyone]) { beforeEach(async function () { // Create contract and token - token = await BasicTokenMock.new(owner, 100, { from: owner }); + token = await StandardTokenMock.new(owner, 100, { from: owner }); canReclaimToken = await CanReclaimToken.new({ from: owner }); + // Force token into contract await token.transfer(canReclaimToken.address, 10, { from: owner }); const startBalance = await token.balanceOf(canReclaimToken.address); diff --git a/test/token/ERC20/BasicToken.test.js b/test/token/ERC20/BasicToken.test.js deleted file mode 100644 index 4a2d3bdc1..000000000 --- a/test/token/ERC20/BasicToken.test.js +++ /dev/null @@ -1,82 +0,0 @@ -const { assertRevert } = require('../../helpers/assertRevert'); -const BasicToken = artifacts.require('BasicTokenMock'); - -contract('StandardToken', function ([_, owner, recipient, anotherAccount]) { - const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; - - beforeEach(async function () { - this.token = await BasicToken.new(owner, 100); - }); - - describe('total supply', function () { - it('returns the total amount of tokens', async function () { - const totalSupply = await this.token.totalSupply(); - - assert.equal(totalSupply, 100); - }); - }); - - describe('balanceOf', function () { - describe('when the requested account has no tokens', function () { - it('returns zero', async function () { - const balance = await this.token.balanceOf(anotherAccount); - - assert.equal(balance, 0); - }); - }); - - describe('when the requested account has some tokens', function () { - it('returns the total amount of tokens', async function () { - const balance = await this.token.balanceOf(owner); - - assert.equal(balance, 100); - }); - }); - }); - - describe('transfer', function () { - describe('when the recipient is not the zero address', function () { - const to = recipient; - - describe('when the sender does not have enough balance', function () { - const amount = 101; - - it('reverts', async function () { - await assertRevert(this.token.transfer(to, amount, { from: owner })); - }); - }); - - describe('when the sender has enough balance', function () { - const amount = 100; - - it('transfers the requested amount', async function () { - await this.token.transfer(to, amount, { from: owner }); - - const senderBalance = await this.token.balanceOf(owner); - assert.equal(senderBalance, 0); - - const recipientBalance = await this.token.balanceOf(to); - assert.equal(recipientBalance, amount); - }); - - it('emits a transfer event', async function () { - const { logs } = await this.token.transfer(to, amount, { from: owner }); - - assert.equal(logs.length, 1); - assert.equal(logs[0].event, 'Transfer'); - assert.equal(logs[0].args.from, owner); - assert.equal(logs[0].args.to, to); - assert(logs[0].args.value.eq(amount)); - }); - }); - }); - - describe('when the recipient is the zero address', function () { - const to = ZERO_ADDRESS; - - it('reverts', async function () { - await assertRevert(this.token.transfer(to, 100, { from: owner })); - }); - }); - }); -}); diff --git a/test/token/ERC20/BurnableToken.behaviour.js b/test/token/ERC20/BurnableToken.behaviour.js index 6a852aa42..0bf3aa2ad 100644 --- a/test/token/ERC20/BurnableToken.behaviour.js +++ b/test/token/ERC20/BurnableToken.behaviour.js @@ -8,8 +8,8 @@ require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -function shouldBehaveLikeBurnableToken (owner, initialBalance) { - describe('as a basic burnable token', function () { +function shouldBehaveLikeBurnableToken (owner, initialBalance, [burner]) { + describe('burn', function () { describe('when the given amount is not greater than balance of the sender', function () { const amount = 100; @@ -44,6 +44,57 @@ function shouldBehaveLikeBurnableToken (owner, initialBalance) { }); }); }); + + describe('burnFrom', function () { + describe('on success', function () { + const amount = 100; + + beforeEach(async function () { + await this.token.approve(burner, 300, { from: owner }); + const { logs } = await this.token.burnFrom(owner, amount, { from: burner }); + this.logs = logs; + }); + + it('burns the requested amount', async function () { + const balance = await this.token.balanceOf(owner); + balance.should.be.bignumber.equal(initialBalance - amount); + }); + + it('decrements allowance', async function () { + const allowance = await this.token.allowance(owner, burner); + allowance.should.be.bignumber.equal(200); + }); + + it('emits a burn event', async function () { + const event = await inLogs(this.logs, 'Burn'); + event.args.burner.should.eq(owner); + event.args.value.should.be.bignumber.equal(amount); + }); + + it('emits a transfer event', async function () { + const event = await inLogs(this.logs, 'Transfer'); + event.args.from.should.eq(owner); + event.args.to.should.eq(ZERO_ADDRESS); + event.args.value.should.be.bignumber.equal(amount); + }); + }); + + describe('when the given amount is greater than the balance of the sender', function () { + const amount = initialBalance + 1; + it('reverts', async function () { + await this.token.approve(burner, amount, { from: owner }); + await assertRevert(this.token.burnFrom(owner, amount, { from: burner })); + }); + }); + + describe('when the given amount is greater than the allowance', function () { + const amount = 100; + it('reverts', async function () { + await this.token.approve(burner, amount - 1, { from: owner }); + await assertRevert(this.token.burnFrom(owner, amount, { from: burner })); + }); + }); + }); } module.exports = { diff --git a/test/token/ERC20/BurnableToken.test.js b/test/token/ERC20/BurnableToken.test.js index 001212872..a636bc84c 100644 --- a/test/token/ERC20/BurnableToken.test.js +++ b/test/token/ERC20/BurnableToken.test.js @@ -1,12 +1,12 @@ const { shouldBehaveLikeBurnableToken } = require('./BurnableToken.behaviour'); const BurnableTokenMock = artifacts.require('BurnableTokenMock'); -contract('BurnableToken', function ([_, owner]) { +contract('BurnableToken', function ([_, owner, ...otherAccounts]) { const initialBalance = 1000; beforeEach(async function () { this.token = await BurnableTokenMock.new(owner, initialBalance, { from: owner }); }); - shouldBehaveLikeBurnableToken(owner, initialBalance); + shouldBehaveLikeBurnableToken(owner, initialBalance, otherAccounts); }); diff --git a/test/token/ERC20/StandardBurnableToken.test.js b/test/token/ERC20/StandardBurnableToken.test.js deleted file mode 100644 index 13fdbe36d..000000000 --- a/test/token/ERC20/StandardBurnableToken.test.js +++ /dev/null @@ -1,72 +0,0 @@ -const { assertRevert } = require('../../helpers/assertRevert'); -const { inLogs } = require('../../helpers/expectEvent'); -const { shouldBehaveLikeBurnableToken } = require('./BurnableToken.behaviour'); - -const StandardBurnableTokenMock = artifacts.require('StandardBurnableTokenMock'); -const BigNumber = web3.BigNumber; -const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; - -require('chai') - .use(require('chai-bignumber')(BigNumber)) - .should(); - -contract('StandardBurnableToken', function ([_, owner, burner]) { - const initialBalance = 1000; - - beforeEach(async function () { - this.token = await StandardBurnableTokenMock.new(owner, initialBalance); - }); - - shouldBehaveLikeBurnableToken(owner, initialBalance); - - describe('burnFrom', function () { - describe('on success', function () { - const amount = 100; - - beforeEach(async function () { - await this.token.approve(burner, 300, { from: owner }); - const { logs } = await this.token.burnFrom(owner, amount, { from: burner }); - this.logs = logs; - }); - - it('burns the requested amount', async function () { - const balance = await this.token.balanceOf(owner); - balance.should.be.bignumber.equal(initialBalance - amount); - }); - - it('decrements allowance', async function () { - const allowance = await this.token.allowance(owner, burner); - allowance.should.be.bignumber.equal(200); - }); - - it('emits a burn event', async function () { - const event = await inLogs(this.logs, 'Burn'); - event.args.burner.should.eq(owner); - event.args.value.should.be.bignumber.equal(amount); - }); - - it('emits a transfer event', async function () { - const event = await inLogs(this.logs, 'Transfer'); - event.args.from.should.eq(owner); - event.args.to.should.eq(ZERO_ADDRESS); - event.args.value.should.be.bignumber.equal(amount); - }); - }); - - describe('when the given amount is greater than the balance of the sender', function () { - const amount = initialBalance + 1; - it('reverts', async function () { - await this.token.approve(burner, amount, { from: owner }); - await assertRevert(this.token.burnFrom(owner, amount, { from: burner })); - }); - }); - - describe('when the given amount is greater than the allowance', function () { - const amount = 100; - it('reverts', async function () { - await this.token.approve(burner, amount - 1, { from: owner }); - await assertRevert(this.token.burnFrom(owner, amount, { from: burner })); - }); - }); - }); -}); diff --git a/test/token/ERC20/StandardToken.test.js b/test/token/ERC20/StandardToken.test.js index 9aa97cae9..2d1119f5e 100644 --- a/test/token/ERC20/StandardToken.test.js +++ b/test/token/ERC20/StandardToken.test.js @@ -1,11 +1,11 @@ const { assertRevert } = require('../../helpers/assertRevert'); -const StandardTokenMock = artifacts.require('StandardTokenMock'); +const StandardToken = artifacts.require('StandardTokenMock'); contract('StandardToken', function ([_, owner, recipient, anotherAccount]) { const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; beforeEach(async function () { - this.token = await StandardTokenMock.new(owner, 100); + this.token = await StandardToken.new(owner, 100); }); describe('total supply', function () {