StandardToken encapsulation (#1197)

* make StandardToken state variables private

* simplify mocks

* document new internal functions

* fix link to ERC20 document

* revert order of Transfer and Mint events

* Revert "simplify mocks"

This reverts commit 371fe3e567.

* add tests for new internal functions

* add check for null account

* add checks for balances and allowance

* add inline docs to BurnableToken._burn

* remove redundant checks and clarify why
This commit is contained in:
Francisco Giordano
2018-08-16 13:03:40 -03:00
committed by GitHub
parent 8d11dcc0e5
commit 4dcdd293e8
12 changed files with 230 additions and 43 deletions

View File

@ -1,4 +1,5 @@
const { expectThrow } = require('../../helpers/expectThrow');
const expectEvent = require('../../helpers/expectEvent');
const BigNumber = web3.BigNumber;
@ -15,8 +16,8 @@ function shouldBehaveLikeCappedToken (minter, [anyone], cap) {
});
it('should mint when amount is less than cap', async function () {
const result = await this.token.mint(anyone, cap.sub(1), { from });
result.logs[0].event.should.equal('Mint');
const { logs } = await this.token.mint(anyone, cap.sub(1), { from });
expectEvent.inLogs(logs, 'Mint');
});
it('should fail to mint if the ammount exceeds the cap', async function () {

View File

@ -1,4 +1,5 @@
const { assertRevert } = require('../../helpers/assertRevert');
const expectEvent = require('../../helpers/expectEvent');
const BigNumber = web3.BigNumber;
@ -7,6 +8,8 @@ require('chai')
.should();
function shouldBehaveLikeMintableToken (owner, minter, [anyone]) {
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
describe('as a basic mintable token', function () {
describe('after token creation', function () {
it('sender should be token owner', async function () {
@ -104,11 +107,16 @@ function shouldBehaveLikeMintableToken (owner, minter, [anyone]) {
it('emits a mint and a transfer event', async function () {
const { logs } = await this.token.mint(owner, amount, { from });
logs.length.should.eq(2);
logs[0].event.should.eq('Mint');
logs[0].args.to.should.eq(owner);
logs[0].args.amount.should.be.bignumber.equal(amount);
logs[1].event.should.eq('Transfer');
const mintEvent = expectEvent.inLogs(logs, 'Mint', {
to: owner,
});
mintEvent.args.amount.should.be.bignumber.equal(amount);
const transferEvent = expectEvent.inLogs(logs, 'Transfer', {
from: ZERO_ADDRESS,
to: owner,
});
transferEvent.args.value.should.be.bignumber.equal(amount);
});
});

View File

@ -1,4 +1,6 @@
const { assertRevert } = require('../../helpers/assertRevert');
const expectEvent = require('../../helpers/expectEvent');
const StandardToken = artifacts.require('StandardTokenMock');
const BigNumber = web3.BigNumber;
@ -68,11 +70,12 @@ contract('StandardToken', function ([_, owner, recipient, anotherAccount]) {
it('emits a transfer event', async function () {
const { logs } = await this.token.transfer(to, amount, { from: owner });
logs.length.should.eq(1);
logs[0].event.should.eq('Transfer');
logs[0].args.from.should.eq(owner);
logs[0].args.to.should.eq(to);
logs[0].args.value.should.be.bignumber.equal(amount);
const event = expectEvent.inLogs(logs, 'Transfer', {
from: owner,
to: to,
});
event.args.value.should.be.bignumber.equal(amount);
});
});
});
@ -486,4 +489,136 @@ contract('StandardToken', function ([_, owner, recipient, anotherAccount]) {
});
});
});
describe('_mint', function () {
const initialSupply = new BigNumber(100);
const amount = new BigNumber(50);
it('rejects a null account', async function () {
await assertRevert(this.token.mint(ZERO_ADDRESS, amount));
});
describe('for a non null account', function () {
beforeEach('minting', async function () {
const { logs } = await this.token.mint(recipient, amount);
this.logs = logs;
});
it('increments totalSupply', async function () {
const expectedSupply = initialSupply.plus(amount);
(await this.token.totalSupply()).should.be.bignumber.equal(expectedSupply);
});
it('increments recipient balance', async function () {
(await this.token.balanceOf(recipient)).should.be.bignumber.equal(amount);
});
it('emits Transfer event', async function () {
const event = expectEvent.inLogs(this.logs, 'Transfer', {
from: ZERO_ADDRESS,
to: recipient,
});
event.args.value.should.be.bignumber.equal(amount);
});
});
});
describe('_burn', function () {
const initialSupply = new BigNumber(100);
const amount = new BigNumber(50);
it('rejects a null account', async function () {
await assertRevert(this.token.burn(ZERO_ADDRESS, amount));
});
describe('for a non null account', function () {
it('rejects burning more than balance', async function () {
await assertRevert(this.token.burn(owner, initialSupply.plus(1)));
});
describe('for less amount than balance', function () {
beforeEach('burning', async function () {
const { logs } = await this.token.burn(owner, amount);
this.logs = logs;
});
it('decrements totalSupply', async function () {
const expectedSupply = initialSupply.minus(amount);
(await this.token.totalSupply()).should.be.bignumber.equal(expectedSupply);
});
it('decrements owner balance', async function () {
const expectedBalance = initialSupply.minus(amount);
(await this.token.balanceOf(owner)).should.be.bignumber.equal(expectedBalance);
});
it('emits Transfer event', async function () {
const event = expectEvent.inLogs(this.logs, 'Transfer', {
from: owner,
to: ZERO_ADDRESS,
});
event.args.value.should.be.bignumber.equal(amount);
});
});
});
});
describe('_burnFrom', function () {
const initialSupply = new BigNumber(100);
const allowance = new BigNumber(70);
const amount = new BigNumber(50);
const spender = anotherAccount;
beforeEach('approving', async function () {
await this.token.approve(spender, allowance, { from: owner });
});
it('rejects a null account', async function () {
await assertRevert(this.token.burnFrom(ZERO_ADDRESS, amount));
});
describe('for a non null account', function () {
it('rejects burning more than allowance', async function () {
await assertRevert(this.token.burnFrom(owner, allowance.plus(1)));
});
it('rejects burning more than balance', async function () {
await assertRevert(this.token.burnFrom(owner, initialSupply.plus(1)));
});
describe('for less amount than allowance', function () {
beforeEach('burning', async function () {
const { logs } = await this.token.burnFrom(owner, amount, { from: spender });
this.logs = logs;
});
it('decrements totalSupply', async function () {
const expectedSupply = initialSupply.minus(amount);
(await this.token.totalSupply()).should.be.bignumber.equal(expectedSupply);
});
it('decrements owner balance', async function () {
const expectedBalance = initialSupply.minus(amount);
(await this.token.balanceOf(owner)).should.be.bignumber.equal(expectedBalance);
});
it('decrements spender allowance', async function () {
const expectedAllowance = allowance.minus(amount);
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(expectedAllowance);
});
it('emits Transfer event', async function () {
const event = expectEvent.inLogs(this.logs, 'Transfer', {
from: owner,
to: ZERO_ADDRESS,
});
event.args.value.should.be.bignumber.equal(amount);
});
});
});
});
});