Skip to content

Commit 7618b91

Browse files
authored
Fix balance and allowance checks in _burn and _burnFrom (#1218)
* fix off by one error in _burn and _burnFrom * add tests for off-by-one error * change amount used
1 parent 20cf885 commit 7618b91

File tree

2 files changed

+58
-50
lines changed

2 files changed

+58
-50
lines changed

contracts/token/ERC20/StandardToken.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ contract StandardToken is ERC20 {
178178
*/
179179
function _burn(address _account, uint256 _amount) internal {
180180
require(_account != 0);
181-
require(balances[_account] > _amount);
181+
require(_amount <= balances[_account]);
182182

183183
totalSupply_ = totalSupply_.sub(_amount);
184184
balances[_account] = balances[_account].sub(_amount);
@@ -193,7 +193,7 @@ contract StandardToken is ERC20 {
193193
* @param _amount The amount that will be burnt.
194194
*/
195195
function _burnFrom(address _account, uint256 _amount) internal {
196-
require(allowed[_account][msg.sender] > _amount);
196+
require(_amount <= allowed[_account][msg.sender]);
197197

198198
// Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
199199
// this function needs to emit an event with the updated approval.

test/token/ERC20/StandardToken.test.js

Lines changed: 56 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -498,49 +498,52 @@ contract('StandardToken', function ([_, owner, recipient, anotherAccount]) {
498498

499499
describe('_burn', function () {
500500
const initialSupply = new BigNumber(100);
501-
const amount = new BigNumber(50);
502501

503502
it('rejects a null account', async function () {
504-
await assertRevert(this.token.burn(ZERO_ADDRESS, amount));
503+
await assertRevert(this.token.burn(ZERO_ADDRESS, 1));
505504
});
506505

507506
describe('for a non null account', function () {
508507
it('rejects burning more than balance', async function () {
509508
await assertRevert(this.token.burn(owner, initialSupply.plus(1)));
510509
});
511510

512-
describe('for less amount than balance', function () {
513-
beforeEach('burning', async function () {
514-
const { logs } = await this.token.burn(owner, amount);
515-
this.logs = logs;
516-
});
517-
518-
it('decrements totalSupply', async function () {
519-
const expectedSupply = initialSupply.minus(amount);
520-
(await this.token.totalSupply()).should.be.bignumber.equal(expectedSupply);
521-
});
511+
const describeBurn = function (description, amount) {
512+
describe(description, function () {
513+
beforeEach('burning', async function () {
514+
const { logs } = await this.token.burn(owner, amount);
515+
this.logs = logs;
516+
});
522517

523-
it('decrements owner balance', async function () {
524-
const expectedBalance = initialSupply.minus(amount);
525-
(await this.token.balanceOf(owner)).should.be.bignumber.equal(expectedBalance);
526-
});
518+
it('decrements totalSupply', async function () {
519+
const expectedSupply = initialSupply.minus(amount);
520+
(await this.token.totalSupply()).should.be.bignumber.equal(expectedSupply);
521+
});
527522

528-
it('emits Transfer event', async function () {
529-
const event = expectEvent.inLogs(this.logs, 'Transfer', {
530-
from: owner,
531-
to: ZERO_ADDRESS,
523+
it('decrements owner balance', async function () {
524+
const expectedBalance = initialSupply.minus(amount);
525+
(await this.token.balanceOf(owner)).should.be.bignumber.equal(expectedBalance);
532526
});
533527

534-
event.args.value.should.be.bignumber.equal(amount);
528+
it('emits Transfer event', async function () {
529+
const event = expectEvent.inLogs(this.logs, 'Transfer', {
530+
from: owner,
531+
to: ZERO_ADDRESS,
532+
});
533+
534+
event.args.value.should.be.bignumber.equal(amount);
535+
});
535536
});
536-
});
537+
};
538+
539+
describeBurn('for entire balance', initialSupply);
540+
describeBurn('for less amount than balance', initialSupply.sub(1));
537541
});
538542
});
539543

540544
describe('_burnFrom', function () {
541545
const initialSupply = new BigNumber(100);
542546
const allowance = new BigNumber(70);
543-
const amount = new BigNumber(50);
544547

545548
const spender = anotherAccount;
546549

@@ -549,7 +552,7 @@ contract('StandardToken', function ([_, owner, recipient, anotherAccount]) {
549552
});
550553

551554
it('rejects a null account', async function () {
552-
await assertRevert(this.token.burnFrom(ZERO_ADDRESS, amount));
555+
await assertRevert(this.token.burnFrom(ZERO_ADDRESS, 1));
553556
});
554557

555558
describe('for a non null account', function () {
@@ -561,36 +564,41 @@ contract('StandardToken', function ([_, owner, recipient, anotherAccount]) {
561564
await assertRevert(this.token.burnFrom(owner, initialSupply.plus(1)));
562565
});
563566

564-
describe('for less amount than allowance', function () {
565-
beforeEach('burning', async function () {
566-
const { logs } = await this.token.burnFrom(owner, amount, { from: spender });
567-
this.logs = logs;
568-
});
569-
570-
it('decrements totalSupply', async function () {
571-
const expectedSupply = initialSupply.minus(amount);
572-
(await this.token.totalSupply()).should.be.bignumber.equal(expectedSupply);
573-
});
567+
const describeBurnFrom = function (description, amount) {
568+
describe(description, function () {
569+
beforeEach('burning', async function () {
570+
const { logs } = await this.token.burnFrom(owner, amount, { from: spender });
571+
this.logs = logs;
572+
});
574573

575-
it('decrements owner balance', async function () {
576-
const expectedBalance = initialSupply.minus(amount);
577-
(await this.token.balanceOf(owner)).should.be.bignumber.equal(expectedBalance);
578-
});
574+
it('decrements totalSupply', async function () {
575+
const expectedSupply = initialSupply.minus(amount);
576+
(await this.token.totalSupply()).should.be.bignumber.equal(expectedSupply);
577+
});
579578

580-
it('decrements spender allowance', async function () {
581-
const expectedAllowance = allowance.minus(amount);
582-
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(expectedAllowance);
583-
});
579+
it('decrements owner balance', async function () {
580+
const expectedBalance = initialSupply.minus(amount);
581+
(await this.token.balanceOf(owner)).should.be.bignumber.equal(expectedBalance);
582+
});
584583

585-
it('emits Transfer event', async function () {
586-
const event = expectEvent.inLogs(this.logs, 'Transfer', {
587-
from: owner,
588-
to: ZERO_ADDRESS,
584+
it('decrements spender allowance', async function () {
585+
const expectedAllowance = allowance.minus(amount);
586+
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(expectedAllowance);
589587
});
590588

591-
event.args.value.should.be.bignumber.equal(amount);
589+
it('emits Transfer event', async function () {
590+
const event = expectEvent.inLogs(this.logs, 'Transfer', {
591+
from: owner,
592+
to: ZERO_ADDRESS,
593+
});
594+
595+
event.args.value.should.be.bignumber.equal(amount);
596+
});
592597
});
593-
});
598+
};
599+
600+
describeBurnFrom('for entire allowance', allowance);
601+
describeBurnFrom('for less amount than allowance', allowance.sub(1));
594602
});
595603
});
596604
});

0 commit comments

Comments
 (0)