Skip to content

Commit 84e63bb

Browse files
authored
Fix decrease allowance and add non-zero address precondition to approve (#1293)
* rename {increase,decrease}Approval to {increase,decrease}Allowance * add non-zero spender check to approve and {increase,decrease}Allowance * Updated tests to reflect the new behavior. * fix wrong test description * fix old function names * Fixed linter error. * Fixed typo.
1 parent e7e8d8e commit 84e63bb

File tree

4 files changed

+60
-121
lines changed

4 files changed

+60
-121
lines changed

contracts/token/ERC20/ERC20.sol

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ contract ERC20 is IERC20 {
7878
* @param _value The amount of tokens to be spent.
7979
*/
8080
function approve(address _spender, uint256 _value) public returns (bool) {
81+
require(_spender != address(0));
82+
8183
allowed_[msg.sender][_spender] = _value;
8284
emit Approval(msg.sender, _spender, _value);
8385
return true;
@@ -117,13 +119,15 @@ contract ERC20 is IERC20 {
117119
* @param _spender The address which will spend the funds.
118120
* @param _addedValue The amount of tokens to increase the allowance by.
119121
*/
120-
function increaseApproval(
122+
function increaseAllowance(
121123
address _spender,
122124
uint256 _addedValue
123125
)
124126
public
125127
returns (bool)
126128
{
129+
require(_spender != address(0));
130+
127131
allowed_[msg.sender][_spender] = (
128132
allowed_[msg.sender][_spender].add(_addedValue));
129133
emit Approval(msg.sender, _spender, allowed_[msg.sender][_spender]);
@@ -139,19 +143,17 @@ contract ERC20 is IERC20 {
139143
* @param _spender The address which will spend the funds.
140144
* @param _subtractedValue The amount of tokens to decrease the allowance by.
141145
*/
142-
function decreaseApproval(
146+
function decreaseAllowance(
143147
address _spender,
144148
uint256 _subtractedValue
145149
)
146150
public
147151
returns (bool)
148152
{
149-
uint256 oldValue = allowed_[msg.sender][_spender];
150-
if (_subtractedValue >= oldValue) {
151-
allowed_[msg.sender][_spender] = 0;
152-
} else {
153-
allowed_[msg.sender][_spender] = oldValue.sub(_subtractedValue);
154-
}
153+
require(_spender != address(0));
154+
155+
allowed_[msg.sender][_spender] = (
156+
allowed_[msg.sender][_spender].sub(_subtractedValue));
155157
emit Approval(msg.sender, _spender, allowed_[msg.sender][_spender]);
156158
return true;
157159
}

contracts/token/ERC20/ERC20Pausable.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,25 +44,25 @@ contract ERC20Pausable is ERC20, Pausable {
4444
return super.approve(_spender, _value);
4545
}
4646

47-
function increaseApproval(
47+
function increaseAllowance(
4848
address _spender,
4949
uint _addedValue
5050
)
5151
public
5252
whenNotPaused
5353
returns (bool success)
5454
{
55-
return super.increaseApproval(_spender, _addedValue);
55+
return super.increaseAllowance(_spender, _addedValue);
5656
}
5757

58-
function decreaseApproval(
58+
function decreaseAllowance(
5959
address _spender,
6060
uint _subtractedValue
6161
)
6262
public
6363
whenNotPaused
6464
returns (bool success)
6565
{
66-
return super.decreaseApproval(_spender, _subtractedValue);
66+
return super.decreaseAllowance(_spender, _subtractedValue);
6767
}
6868
}

test/token/ERC20/ERC20.test.js

Lines changed: 40 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -158,20 +158,8 @@ contract('ERC20', function ([_, owner, recipient, anotherAccount]) {
158158
const amount = 100;
159159
const spender = ZERO_ADDRESS;
160160

161-
it('approves the requested amount', async function () {
162-
await this.token.approve(spender, amount, { from: owner });
163-
164-
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
165-
});
166-
167-
it('emits an approval event', async function () {
168-
const { logs } = await this.token.approve(spender, amount, { from: owner });
169-
170-
logs.length.should.equal(1);
171-
logs[0].event.should.equal('Approval');
172-
logs[0].args.owner.should.equal(owner);
173-
logs[0].args.spender.should.equal(spender);
174-
logs[0].args.value.should.be.bignumber.equal(amount);
161+
it('reverts', async function () {
162+
await assertRevert(this.token.approve(spender, amount, { from: owner }));
175163
});
176164
});
177165
});
@@ -261,122 +249,83 @@ contract('ERC20', function ([_, owner, recipient, anotherAccount]) {
261249
});
262250
});
263251

264-
describe('decrease approval', function () {
252+
describe('decrease allowance', function () {
265253
describe('when the spender is not the zero address', function () {
266254
const spender = recipient;
267255

268-
describe('when the sender has enough balance', function () {
269-
const amount = 100;
270-
271-
it('emits an approval event', async function () {
272-
const { logs } = await this.token.decreaseApproval(spender, amount, { from: owner });
273-
274-
logs.length.should.equal(1);
275-
logs[0].event.should.equal('Approval');
276-
logs[0].args.owner.should.equal(owner);
277-
logs[0].args.spender.should.equal(spender);
278-
logs[0].args.value.should.be.bignumber.equal(0);
279-
});
280-
256+
function shouldDecreaseApproval (amount) {
281257
describe('when there was no approved amount before', function () {
282-
it('keeps the allowance to zero', async function () {
283-
await this.token.decreaseApproval(spender, amount, { from: owner });
284-
285-
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(0);
258+
it('reverts', async function () {
259+
await assertRevert(this.token.decreaseAllowance(spender, amount, { from: owner }));
286260
});
287261
});
288262

289263
describe('when the spender had an approved amount', function () {
290264
const approvedAmount = amount;
291265

292266
beforeEach(async function () {
293-
await this.token.approve(spender, approvedAmount, { from: owner });
267+
({ logs: this.logs } = await this.token.approve(spender, approvedAmount, { from: owner }));
268+
});
269+
270+
it('emits an approval event', async function () {
271+
const { logs } = await this.token.decreaseAllowance(spender, approvedAmount, { from: owner });
272+
273+
logs.length.should.equal(1);
274+
logs[0].event.should.equal('Approval');
275+
logs[0].args.owner.should.equal(owner);
276+
logs[0].args.spender.should.equal(spender);
277+
logs[0].args.value.should.be.bignumber.equal(0);
294278
});
295279

296280
it('decreases the spender allowance subtracting the requested amount', async function () {
297-
await this.token.decreaseApproval(spender, approvedAmount - 5, { from: owner });
281+
await this.token.decreaseAllowance(spender, approvedAmount - 1, { from: owner });
298282

299-
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(5);
283+
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(1);
300284
});
301285

302286
it('sets the allowance to zero when all allowance is removed', async function () {
303-
await this.token.decreaseApproval(spender, approvedAmount, { from: owner });
287+
await this.token.decreaseAllowance(spender, approvedAmount, { from: owner });
304288
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(0);
305289
});
306290

307-
it('sets the allowance to zero when more than the full allowance is removed', async function () {
308-
await this.token.decreaseApproval(spender, approvedAmount + 5, { from: owner });
309-
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(0);
291+
it('reverts when more than the full allowance is removed', async function () {
292+
await assertRevert(this.token.decreaseAllowance(spender, approvedAmount + 1, { from: owner }));
310293
});
311294
});
295+
}
296+
297+
describe('when the sender has enough balance', function () {
298+
const amount = 100;
299+
300+
shouldDecreaseApproval(amount);
312301
});
313302

314303
describe('when the sender does not have enough balance', function () {
315304
const amount = 101;
316305

317-
it('emits an approval event', async function () {
318-
const { logs } = await this.token.decreaseApproval(spender, amount, { from: owner });
319-
320-
logs.length.should.equal(1);
321-
logs[0].event.should.equal('Approval');
322-
logs[0].args.owner.should.equal(owner);
323-
logs[0].args.spender.should.equal(spender);
324-
logs[0].args.value.should.be.bignumber.equal(0);
325-
});
326-
327-
describe('when there was no approved amount before', function () {
328-
it('keeps the allowance to zero', async function () {
329-
await this.token.decreaseApproval(spender, amount, { from: owner });
330-
331-
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(0);
332-
});
333-
});
334-
335-
describe('when the spender had an approved amount', function () {
336-
beforeEach(async function () {
337-
await this.token.approve(spender, amount + 1, { from: owner });
338-
});
339-
340-
it('decreases the spender allowance subtracting the requested amount', async function () {
341-
await this.token.decreaseApproval(spender, amount, { from: owner });
342-
343-
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(1);
344-
});
345-
});
306+
shouldDecreaseApproval(amount);
346307
});
347308
});
348309

349310
describe('when the spender is the zero address', function () {
350311
const amount = 100;
351312
const spender = ZERO_ADDRESS;
352313

353-
it('decreases the requested amount', async function () {
354-
await this.token.decreaseApproval(spender, amount, { from: owner });
355-
356-
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(0);
357-
});
358-
359-
it('emits an approval event', async function () {
360-
const { logs } = await this.token.decreaseApproval(spender, amount, { from: owner });
361-
362-
logs.length.should.equal(1);
363-
logs[0].event.should.equal('Approval');
364-
logs[0].args.owner.should.equal(owner);
365-
logs[0].args.spender.should.equal(spender);
366-
logs[0].args.value.should.be.bignumber.equal(0);
314+
it('reverts', async function () {
315+
await assertRevert(this.token.decreaseAllowance(spender, amount, { from: owner }));
367316
});
368317
});
369318
});
370319

371-
describe('increase approval', function () {
320+
describe('increase allowance', function () {
372321
const amount = 100;
373322

374323
describe('when the spender is not the zero address', function () {
375324
const spender = recipient;
376325

377326
describe('when the sender has enough balance', function () {
378327
it('emits an approval event', async function () {
379-
const { logs } = await this.token.increaseApproval(spender, amount, { from: owner });
328+
const { logs } = await this.token.increaseAllowance(spender, amount, { from: owner });
380329

381330
logs.length.should.equal(1);
382331
logs[0].event.should.equal('Approval');
@@ -387,7 +336,7 @@ contract('ERC20', function ([_, owner, recipient, anotherAccount]) {
387336

388337
describe('when there was no approved amount before', function () {
389338
it('approves the requested amount', async function () {
390-
await this.token.increaseApproval(spender, amount, { from: owner });
339+
await this.token.increaseAllowance(spender, amount, { from: owner });
391340

392341
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
393342
});
@@ -399,7 +348,7 @@ contract('ERC20', function ([_, owner, recipient, anotherAccount]) {
399348
});
400349

401350
it('increases the spender allowance adding the requested amount', async function () {
402-
await this.token.increaseApproval(spender, amount, { from: owner });
351+
await this.token.increaseAllowance(spender, amount, { from: owner });
403352

404353
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount + 1);
405354
});
@@ -410,7 +359,7 @@ contract('ERC20', function ([_, owner, recipient, anotherAccount]) {
410359
const amount = 101;
411360

412361
it('emits an approval event', async function () {
413-
const { logs } = await this.token.increaseApproval(spender, amount, { from: owner });
362+
const { logs } = await this.token.increaseAllowance(spender, amount, { from: owner });
414363

415364
logs.length.should.equal(1);
416365
logs[0].event.should.equal('Approval');
@@ -421,7 +370,7 @@ contract('ERC20', function ([_, owner, recipient, anotherAccount]) {
421370

422371
describe('when there was no approved amount before', function () {
423372
it('approves the requested amount', async function () {
424-
await this.token.increaseApproval(spender, amount, { from: owner });
373+
await this.token.increaseAllowance(spender, amount, { from: owner });
425374

426375
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
427376
});
@@ -433,7 +382,7 @@ contract('ERC20', function ([_, owner, recipient, anotherAccount]) {
433382
});
434383

435384
it('increases the spender allowance adding the requested amount', async function () {
436-
await this.token.increaseApproval(spender, amount, { from: owner });
385+
await this.token.increaseAllowance(spender, amount, { from: owner });
437386

438387
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount + 1);
439388
});
@@ -444,20 +393,8 @@ contract('ERC20', function ([_, owner, recipient, anotherAccount]) {
444393
describe('when the spender is the zero address', function () {
445394
const spender = ZERO_ADDRESS;
446395

447-
it('approves the requested amount', async function () {
448-
await this.token.increaseApproval(spender, amount, { from: owner });
449-
450-
(await this.token.allowance(owner, spender)).should.be.bignumber.equal(amount);
451-
});
452-
453-
it('emits an approval event', async function () {
454-
const { logs } = await this.token.increaseApproval(spender, amount, { from: owner });
455-
456-
logs.length.should.equal(1);
457-
logs[0].event.should.equal('Approval');
458-
logs[0].args.owner.should.equal(owner);
459-
logs[0].args.spender.should.equal(spender);
460-
logs[0].args.value.should.be.bignumber.equal(amount);
396+
it('reverts', async function () {
397+
await assertRevert(this.token.increaseAllowance(spender, amount, { from: owner }));
461398
});
462399
});
463400
});

test/token/ERC20/ERC20Pausable.test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA
196196
});
197197

198198
it('allows to decrease approval when unpaused', async function () {
199-
await this.token.decreaseApproval(anotherAccount, 40, { from: pauser });
199+
await this.token.decreaseAllowance(anotherAccount, 40, { from: pauser });
200200

201201
(await this.token.allowance(pauser, anotherAccount)).should.be.bignumber.equal(60);
202202
});
@@ -205,15 +205,15 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA
205205
await this.token.pause({ from: pauser });
206206
await this.token.unpause({ from: pauser });
207207

208-
await this.token.decreaseApproval(anotherAccount, 40, { from: pauser });
208+
await this.token.decreaseAllowance(anotherAccount, 40, { from: pauser });
209209

210210
(await this.token.allowance(pauser, anotherAccount)).should.be.bignumber.equal(60);
211211
});
212212

213213
it('reverts when trying to transfer when paused', async function () {
214214
await this.token.pause({ from: pauser });
215215

216-
await assertRevert(this.token.decreaseApproval(anotherAccount, 40, { from: pauser }));
216+
await assertRevert(this.token.decreaseAllowance(anotherAccount, 40, { from: pauser }));
217217
});
218218
});
219219

@@ -223,7 +223,7 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA
223223
});
224224

225225
it('allows to increase approval when unpaused', async function () {
226-
await this.token.increaseApproval(anotherAccount, 40, { from: pauser });
226+
await this.token.increaseAllowance(anotherAccount, 40, { from: pauser });
227227

228228
(await this.token.allowance(pauser, anotherAccount)).should.be.bignumber.equal(140);
229229
});
@@ -232,15 +232,15 @@ contract('ERC20Pausable', function ([_, pauser, otherPauser, recipient, anotherA
232232
await this.token.pause({ from: pauser });
233233
await this.token.unpause({ from: pauser });
234234

235-
await this.token.increaseApproval(anotherAccount, 40, { from: pauser });
235+
await this.token.increaseAllowance(anotherAccount, 40, { from: pauser });
236236

237237
(await this.token.allowance(pauser, anotherAccount)).should.be.bignumber.equal(140);
238238
});
239239

240240
it('reverts when trying to increase approval when paused', async function () {
241241
await this.token.pause({ from: pauser });
242242

243-
await assertRevert(this.token.increaseApproval(anotherAccount, 40, { from: pauser }));
243+
await assertRevert(this.token.increaseAllowance(anotherAccount, 40, { from: pauser }));
244244
});
245245
});
246246
});

0 commit comments

Comments
 (0)