Do not emit Approval event when calling transferFrom (#4370)

Co-authored-by: Ernesto García <ernestognw@gmail.com>
Co-authored-by: Francisco <fg@frang.io>
This commit is contained in:
Hadrien Croubois
2023-06-22 18:41:56 +02:00
committed by GitHub
parent 6ddacdbde8
commit 1e0e4e20bb
6 changed files with 357 additions and 307 deletions

View File

@ -0,0 +1,5 @@
---
'openzeppelin-solidity': major
---
`ERC20`: Remove `Approval` event previously emitted in `transferFrom` to indicate that part of the allowance was consumed. With this change, allowances are no longer reconstructible from events. See the code for guidelines on how to re-enable this event if needed.

View File

@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "../../token/ERC20/ERC20.sol";
abstract contract ERC20ApprovalMock is ERC20 {
function _approve(address owner, address spender, uint256 amount, bool) internal virtual override {
super._approve(owner, spender, amount, true);
}
}

View File

@ -311,6 +311,27 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
_approve(owner, spender, amount, true);
}
/**
* @dev Alternative version of {_approve} with an optional flag that can enable or disable the Approval event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to true
* using the following override:
* ```
* function _approve(address owner, address spender, uint256 amount, bool) internal virtual override {
* super._approve(owner, spender, amount, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 amount, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
@ -318,7 +339,9 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
if (emitEvent) {
emit Approval(owner, spender, amount);
}
}
/**
@ -336,7 +359,7 @@ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
revert ERC20InsufficientAllowance(spender, currentAllowance, amount);
}
unchecked {
_approve(owner, spender, currentAllowance - amount);
_approve(owner, spender, currentAllowance - amount, false);
}
}
}

View File

@ -4,7 +4,10 @@ const { ZERO_ADDRESS, MAX_UINT256 } = constants;
const { expectRevertCustomError } = require('../../helpers/customError');
function shouldBehaveLikeERC20(initialSupply, initialHolder, recipient, anotherAccount) {
function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) {
const [initialHolder, recipient, anotherAccount] = accounts;
const { forcedApproval } = opts;
describe('total supply', function () {
it('returns the total amount of tokens', async function () {
expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply);
@ -70,13 +73,22 @@ function shouldBehaveLikeERC20(initialSupply, initialHolder, recipient, anotherA
});
});
it('emits an approval event', async function () {
expectEvent(await this.token.transferFrom(tokenOwner, to, amount, { from: spender }), 'Approval', {
owner: tokenOwner,
spender: spender,
value: await this.token.allowance(tokenOwner, spender),
if (forcedApproval) {
it('emits an approval event', async function () {
expectEvent(await this.token.transferFrom(tokenOwner, to, amount, { from: spender }), 'Approval', {
owner: tokenOwner,
spender: spender,
value: await this.token.allowance(tokenOwner, spender),
});
});
});
} else {
it('does not emit an approval event', async function () {
expectEvent.notEmitted(
await this.token.transferFrom(tokenOwner, to, amount, { from: spender }),
'Approval',
);
});
}
});
describe('when the token owner does not have enough balance', function () {

View File

@ -9,357 +9,357 @@ const {
} = require('./ERC20.behavior');
const { expectRevertCustomError } = require('../../helpers/customError');
const ERC20 = artifacts.require('$ERC20');
const ERC20Decimals = artifacts.require('$ERC20DecimalsMock');
const TOKENS = [
{ Token: artifacts.require('$ERC20') },
{ Token: artifacts.require('$ERC20ApprovalMock'), forcedApproval: true },
];
contract('ERC20', function (accounts) {
const [initialHolder, recipient, anotherAccount] = accounts;
const [initialHolder, recipient] = accounts;
const name = 'My Token';
const symbol = 'MTKN';
const initialSupply = new BN(100);
beforeEach(async function () {
this.token = await ERC20.new(name, symbol);
await this.token.$_mint(initialHolder, initialSupply);
});
for (const { Token, forcedApproval } of TOKENS) {
describe(`using ${Token._json.contractName}`, function () {
beforeEach(async function () {
this.token = await Token.new(name, symbol);
await this.token.$_mint(initialHolder, initialSupply);
});
it('has a name', async function () {
expect(await this.token.name()).to.equal(name);
});
shouldBehaveLikeERC20(initialSupply, accounts, { forcedApproval });
it('has a symbol', async function () {
expect(await this.token.symbol()).to.equal(symbol);
});
it('has a name', async function () {
expect(await this.token.name()).to.equal(name);
});
it('has 18 decimals', async function () {
expect(await this.token.decimals()).to.be.bignumber.equal('18');
});
it('has a symbol', async function () {
expect(await this.token.symbol()).to.equal(symbol);
});
describe('set decimals', function () {
const decimals = new BN(6);
it('has 18 decimals', async function () {
expect(await this.token.decimals()).to.be.bignumber.equal('18');
});
it('can set decimals during construction', async function () {
const token = await ERC20Decimals.new(name, symbol, decimals);
expect(await token.decimals()).to.be.bignumber.equal(decimals);
});
});
describe('decrease allowance', function () {
describe('when the spender is not the zero address', function () {
const spender = recipient;
shouldBehaveLikeERC20(initialSupply, initialHolder, recipient, anotherAccount);
function shouldDecreaseApproval(amount) {
describe('when there was no approved amount before', function () {
it('reverts', async function () {
const allowance = await this.token.allowance(initialHolder, spender);
await expectRevertCustomError(
this.token.decreaseAllowance(spender, amount, { from: initialHolder }),
'ERC20FailedDecreaseAllowance',
[spender, allowance, amount],
);
});
});
describe('decrease allowance', function () {
describe('when the spender is not the zero address', function () {
const spender = recipient;
describe('when the spender had an approved amount', function () {
const approvedAmount = amount;
beforeEach(async function () {
await this.token.approve(spender, approvedAmount, { from: initialHolder });
});
it('emits an approval event', async function () {
expectEvent(
await this.token.decreaseAllowance(spender, approvedAmount, { from: initialHolder }),
'Approval',
{ owner: initialHolder, spender: spender, value: new BN(0) },
);
});
it('decreases the spender allowance subtracting the requested amount', async function () {
await this.token.decreaseAllowance(spender, approvedAmount.subn(1), { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal('1');
});
it('sets the allowance to zero when all allowance is removed', async function () {
await this.token.decreaseAllowance(spender, approvedAmount, { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal('0');
});
it('reverts when more than the full allowance is removed', async function () {
await expectRevertCustomError(
this.token.decreaseAllowance(spender, approvedAmount.addn(1), { from: initialHolder }),
'ERC20FailedDecreaseAllowance',
[spender, approvedAmount, approvedAmount.addn(1)],
);
});
});
}
describe('when the sender has enough balance', function () {
const amount = initialSupply;
shouldDecreaseApproval(amount);
});
describe('when the sender does not have enough balance', function () {
const amount = initialSupply.addn(1);
shouldDecreaseApproval(amount);
});
});
describe('when the spender is the zero address', function () {
const amount = initialSupply;
const spender = ZERO_ADDRESS;
function shouldDecreaseApproval(amount) {
describe('when there was no approved amount before', function () {
it('reverts', async function () {
const allowance = await this.token.allowance(initialHolder, spender);
await expectRevertCustomError(
this.token.decreaseAllowance(spender, amount, { from: initialHolder }),
'ERC20FailedDecreaseAllowance',
[spender, allowance, amount],
[spender, 0, amount],
);
});
});
});
describe('when the spender had an approved amount', function () {
const approvedAmount = amount;
beforeEach(async function () {
await this.token.approve(spender, approvedAmount, { from: initialHolder });
});
it('emits an approval event', async function () {
expectEvent(
await this.token.decreaseAllowance(spender, approvedAmount, { from: initialHolder }),
'Approval',
{ owner: initialHolder, spender: spender, value: new BN(0) },
);
});
it('decreases the spender allowance subtracting the requested amount', async function () {
await this.token.decreaseAllowance(spender, approvedAmount.subn(1), { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal('1');
});
it('sets the allowance to zero when all allowance is removed', async function () {
await this.token.decreaseAllowance(spender, approvedAmount, { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal('0');
});
it('reverts when more than the full allowance is removed', async function () {
await expectRevertCustomError(
this.token.decreaseAllowance(spender, approvedAmount.addn(1), { from: initialHolder }),
'ERC20FailedDecreaseAllowance',
[spender, approvedAmount, approvedAmount.addn(1)],
);
});
});
}
describe('when the sender has enough balance', function () {
describe('increase allowance', function () {
const amount = initialSupply;
shouldDecreaseApproval(amount);
});
describe('when the spender is not the zero address', function () {
const spender = recipient;
describe('when the sender does not have enough balance', function () {
const amount = initialSupply.addn(1);
describe('when the sender has enough balance', function () {
it('emits an approval event', async function () {
expectEvent(await this.token.increaseAllowance(spender, amount, { from: initialHolder }), 'Approval', {
owner: initialHolder,
spender: spender,
value: amount,
});
});
shouldDecreaseApproval(amount);
});
});
describe('when there was no approved amount before', function () {
it('approves the requested amount', async function () {
await this.token.increaseAllowance(spender, amount, { from: initialHolder });
describe('when the spender is the zero address', function () {
const amount = initialSupply;
const spender = ZERO_ADDRESS;
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount);
});
});
it('reverts', async function () {
await expectRevertCustomError(
this.token.decreaseAllowance(spender, amount, { from: initialHolder }),
'ERC20FailedDecreaseAllowance',
[spender, 0, amount],
);
});
});
});
describe('when the spender had an approved amount', function () {
beforeEach(async function () {
await this.token.approve(spender, new BN(1), { from: initialHolder });
});
describe('increase allowance', function () {
const amount = initialSupply;
it('increases the spender allowance adding the requested amount', async function () {
await this.token.increaseAllowance(spender, amount, { from: initialHolder });
describe('when the spender is not the zero address', function () {
const spender = recipient;
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount.addn(1));
});
});
});
describe('when the sender has enough balance', function () {
it('emits an approval event', async function () {
expectEvent(await this.token.increaseAllowance(spender, amount, { from: initialHolder }), 'Approval', {
owner: initialHolder,
spender: spender,
value: amount,
describe('when the sender does not have enough balance', function () {
const amount = initialSupply.addn(1);
it('emits an approval event', async function () {
expectEvent(await this.token.increaseAllowance(spender, amount, { from: initialHolder }), 'Approval', {
owner: initialHolder,
spender: spender,
value: amount,
});
});
describe('when there was no approved amount before', function () {
it('approves the requested amount', async function () {
await this.token.increaseAllowance(spender, amount, { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount);
});
});
describe('when the spender had an approved amount', function () {
beforeEach(async function () {
await this.token.approve(spender, new BN(1), { from: initialHolder });
});
it('increases the spender allowance adding the requested amount', async function () {
await this.token.increaseAllowance(spender, amount, { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount.addn(1));
});
});
});
});
describe('when there was no approved amount before', function () {
it('approves the requested amount', async function () {
await this.token.increaseAllowance(spender, amount, { from: initialHolder });
describe('when the spender is the zero address', function () {
const spender = ZERO_ADDRESS;
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount);
});
});
describe('when the spender had an approved amount', function () {
beforeEach(async function () {
await this.token.approve(spender, new BN(1), { from: initialHolder });
});
it('increases the spender allowance adding the requested amount', async function () {
await this.token.increaseAllowance(spender, amount, { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount.addn(1));
it('reverts', async function () {
await expectRevertCustomError(
this.token.increaseAllowance(spender, amount, { from: initialHolder }),
'ERC20InvalidSpender',
[ZERO_ADDRESS],
);
});
});
});
describe('when the sender does not have enough balance', function () {
const amount = initialSupply.addn(1);
it('emits an approval event', async function () {
expectEvent(await this.token.increaseAllowance(spender, amount, { from: initialHolder }), 'Approval', {
owner: initialHolder,
spender: spender,
value: amount,
});
describe('_mint', function () {
const amount = new BN(50);
it('rejects a null account', async function () {
await expectRevertCustomError(this.token.$_mint(ZERO_ADDRESS, amount), 'ERC20InvalidReceiver', [
ZERO_ADDRESS,
]);
});
describe('when there was no approved amount before', function () {
it('approves the requested amount', async function () {
await this.token.increaseAllowance(spender, amount, { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount);
});
it('rejects overflow', async function () {
const maxUint256 = new BN('2').pow(new BN(256)).subn(1);
await expectRevert(
this.token.$_mint(recipient, maxUint256),
'reverted with panic code 0x11 (Arithmetic operation underflowed or overflowed outside of an unchecked block)',
);
});
describe('when the spender had an approved amount', function () {
beforeEach(async function () {
await this.token.approve(spender, new BN(1), { from: initialHolder });
describe('for a non zero account', function () {
beforeEach('minting', async function () {
this.receipt = await this.token.$_mint(recipient, amount);
});
it('increases the spender allowance adding the requested amount', async function () {
await this.token.increaseAllowance(spender, amount, { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount.addn(1));
});
});
});
});
describe('when the spender is the zero address', function () {
const spender = ZERO_ADDRESS;
it('reverts', async function () {
await expectRevertCustomError(
this.token.increaseAllowance(spender, amount, { from: initialHolder }),
'ERC20InvalidSpender',
[ZERO_ADDRESS],
);
});
});
});
describe('_mint', function () {
const amount = new BN(50);
it('rejects a null account', async function () {
await expectRevertCustomError(this.token.$_mint(ZERO_ADDRESS, amount), 'ERC20InvalidReceiver', [ZERO_ADDRESS]);
});
it('rejects overflow', async function () {
const maxUint256 = new BN('2').pow(new BN(256)).subn(1);
await expectRevert(
this.token.$_mint(recipient, maxUint256),
'reverted with panic code 0x11 (Arithmetic operation underflowed or overflowed outside of an unchecked block)',
);
});
describe('for a non zero account', function () {
beforeEach('minting', async function () {
this.receipt = await this.token.$_mint(recipient, amount);
});
it('increments totalSupply', async function () {
const expectedSupply = initialSupply.add(amount);
expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply);
});
it('increments recipient balance', async function () {
expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(amount);
});
it('emits Transfer event', async function () {
const event = expectEvent(this.receipt, 'Transfer', { from: ZERO_ADDRESS, to: recipient });
expect(event.args.value).to.be.bignumber.equal(amount);
});
});
});
describe('_burn', function () {
it('rejects a null account', async function () {
await expectRevertCustomError(this.token.$_burn(ZERO_ADDRESS, new BN(1)), 'ERC20InvalidSender', [ZERO_ADDRESS]);
});
describe('for a non zero account', function () {
it('rejects burning more than balance', async function () {
await expectRevertCustomError(
this.token.$_burn(initialHolder, initialSupply.addn(1)),
'ERC20InsufficientBalance',
[initialHolder, initialSupply, initialSupply.addn(1)],
);
});
const describeBurn = function (description, amount) {
describe(description, function () {
beforeEach('burning', async function () {
this.receipt = await this.token.$_burn(initialHolder, amount);
});
it('decrements totalSupply', async function () {
const expectedSupply = initialSupply.sub(amount);
it('increments totalSupply', async function () {
const expectedSupply = initialSupply.add(amount);
expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply);
});
it('decrements initialHolder balance', async function () {
const expectedBalance = initialSupply.sub(amount);
expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(expectedBalance);
it('increments recipient balance', async function () {
expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(amount);
});
it('emits Transfer event', async function () {
const event = expectEvent(this.receipt, 'Transfer', { from: initialHolder, to: ZERO_ADDRESS });
const event = expectEvent(this.receipt, 'Transfer', { from: ZERO_ADDRESS, to: recipient });
expect(event.args.value).to.be.bignumber.equal(amount);
});
});
};
describeBurn('for entire balance', initialSupply);
describeBurn('for less amount than balance', initialSupply.subn(1));
});
});
describe('_update', function () {
const amount = new BN(1);
it('from is the zero address', async function () {
const balanceBefore = await this.token.balanceOf(initialHolder);
const totalSupply = await this.token.totalSupply();
expectEvent(await this.token.$_update(ZERO_ADDRESS, initialHolder, amount), 'Transfer', {
from: ZERO_ADDRESS,
to: initialHolder,
value: amount,
});
expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.add(amount));
expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.add(amount));
});
it('to is the zero address', async function () {
const balanceBefore = await this.token.balanceOf(initialHolder);
const totalSupply = await this.token.totalSupply();
describe('_burn', function () {
it('rejects a null account', async function () {
await expectRevertCustomError(this.token.$_burn(ZERO_ADDRESS, new BN(1)), 'ERC20InvalidSender', [
ZERO_ADDRESS,
]);
});
expectEvent(await this.token.$_update(initialHolder, ZERO_ADDRESS, amount), 'Transfer', {
from: initialHolder,
to: ZERO_ADDRESS,
value: amount,
describe('for a non zero account', function () {
it('rejects burning more than balance', async function () {
await expectRevertCustomError(
this.token.$_burn(initialHolder, initialSupply.addn(1)),
'ERC20InsufficientBalance',
[initialHolder, initialSupply, initialSupply.addn(1)],
);
});
const describeBurn = function (description, amount) {
describe(description, function () {
beforeEach('burning', async function () {
this.receipt = await this.token.$_burn(initialHolder, amount);
});
it('decrements totalSupply', async function () {
const expectedSupply = initialSupply.sub(amount);
expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply);
});
it('decrements initialHolder balance', async function () {
const expectedBalance = initialSupply.sub(amount);
expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(expectedBalance);
});
it('emits Transfer event', async function () {
const event = expectEvent(this.receipt, 'Transfer', { from: initialHolder, to: ZERO_ADDRESS });
expect(event.args.value).to.be.bignumber.equal(amount);
});
});
};
describeBurn('for entire balance', initialSupply);
describeBurn('for less amount than balance', initialSupply.subn(1));
});
});
expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.sub(amount));
expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.sub(amount));
});
it('from and to are the zero address', async function () {
const totalSupply = await this.token.totalSupply();
describe('_update', function () {
const amount = new BN(1);
await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, amount);
it('from is the zero address', async function () {
const balanceBefore = await this.token.balanceOf(initialHolder);
const totalSupply = await this.token.totalSupply();
expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply);
expectEvent(await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, amount), 'Transfer', {
from: ZERO_ADDRESS,
to: ZERO_ADDRESS,
value: amount,
expectEvent(await this.token.$_update(ZERO_ADDRESS, initialHolder, amount), 'Transfer', {
from: ZERO_ADDRESS,
to: initialHolder,
value: amount,
});
expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.add(amount));
expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.add(amount));
});
it('to is the zero address', async function () {
const balanceBefore = await this.token.balanceOf(initialHolder);
const totalSupply = await this.token.totalSupply();
expectEvent(await this.token.$_update(initialHolder, ZERO_ADDRESS, amount), 'Transfer', {
from: initialHolder,
to: ZERO_ADDRESS,
value: amount,
});
expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.sub(amount));
expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.sub(amount));
});
it('from and to are the zero address', async function () {
const totalSupply = await this.token.totalSupply();
await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, amount);
expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply);
expectEvent(await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, amount), 'Transfer', {
from: ZERO_ADDRESS,
to: ZERO_ADDRESS,
value: amount,
});
});
});
describe('_transfer', function () {
shouldBehaveLikeERC20Transfer(initialHolder, recipient, initialSupply, function (from, to, amount) {
return this.token.$_transfer(from, to, amount);
});
describe('when the sender is the zero address', function () {
it('reverts', async function () {
await expectRevertCustomError(
this.token.$_transfer(ZERO_ADDRESS, recipient, initialSupply),
'ERC20InvalidSender',
[ZERO_ADDRESS],
);
});
});
});
describe('_approve', function () {
shouldBehaveLikeERC20Approve(initialHolder, recipient, initialSupply, function (owner, spender, amount) {
return this.token.$_approve(owner, spender, amount);
});
describe('when the owner is the zero address', function () {
it('reverts', async function () {
await expectRevertCustomError(
this.token.$_approve(ZERO_ADDRESS, recipient, initialSupply),
'ERC20InvalidApprover',
[ZERO_ADDRESS],
);
});
});
});
});
});
describe('_transfer', function () {
shouldBehaveLikeERC20Transfer(initialHolder, recipient, initialSupply, function (from, to, amount) {
return this.token.$_transfer(from, to, amount);
});
describe('when the sender is the zero address', function () {
it('reverts', async function () {
await expectRevertCustomError(
this.token.$_transfer(ZERO_ADDRESS, recipient, initialSupply),
'ERC20InvalidSender',
[ZERO_ADDRESS],
);
});
});
});
describe('_approve', function () {
shouldBehaveLikeERC20Approve(initialHolder, recipient, initialSupply, function (owner, spender, amount) {
return this.token.$_approve(owner, spender, amount);
});
describe('when the owner is the zero address', function () {
it('reverts', async function () {
await expectRevertCustomError(
this.token.$_approve(ZERO_ADDRESS, recipient, initialSupply),
'ERC20InvalidApprover',
[ZERO_ADDRESS],
);
});
});
});
}
});

View File

@ -10,7 +10,7 @@ const ERC20Decimals = artifacts.require('$ERC20DecimalsMock');
const ERC20Wrapper = artifacts.require('$ERC20Wrapper');
contract('ERC20Wrapper', function (accounts) {
const [initialHolder, recipient, anotherAccount] = accounts;
const [initialHolder, receiver] = accounts;
const name = 'My Token';
const symbol = 'MTKN';
@ -85,7 +85,7 @@ contract('ERC20Wrapper', function (accounts) {
it('to other account', async function () {
await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
const { tx } = await this.token.depositFor(anotherAccount, initialSupply, { from: initialHolder });
const { tx } = await this.token.depositFor(receiver, initialSupply, { from: initialHolder });
await expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
from: initialHolder,
to: this.token.address,
@ -93,7 +93,7 @@ contract('ERC20Wrapper', function (accounts) {
});
await expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: ZERO_ADDRESS,
to: anotherAccount,
to: receiver,
value: initialSupply,
});
});
@ -144,10 +144,10 @@ contract('ERC20Wrapper', function (accounts) {
});
it('to other account', async function () {
const { tx } = await this.token.withdrawTo(anotherAccount, initialSupply, { from: initialHolder });
const { tx } = await this.token.withdrawTo(receiver, initialSupply, { from: initialHolder });
await expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
from: this.token.address,
to: anotherAccount,
to: receiver,
value: initialSupply,
});
await expectEvent.inTransaction(tx, this.token, 'Transfer', {
@ -163,10 +163,10 @@ contract('ERC20Wrapper', function (accounts) {
await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
const { tx } = await this.token.$_recover(anotherAccount);
const { tx } = await this.token.$_recover(receiver);
await expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: ZERO_ADDRESS,
to: anotherAccount,
to: receiver,
value: '0',
});
});
@ -174,10 +174,10 @@ contract('ERC20Wrapper', function (accounts) {
it('something to recover', async function () {
await this.underlying.transfer(this.token.address, initialSupply, { from: initialHolder });
const { tx } = await this.token.$_recover(anotherAccount);
const { tx } = await this.token.$_recover(receiver);
await expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: ZERO_ADDRESS,
to: anotherAccount,
to: receiver,
value: initialSupply,
});
});
@ -189,6 +189,6 @@ contract('ERC20Wrapper', function (accounts) {
await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
});
shouldBehaveLikeERC20(initialSupply, initialHolder, recipient, anotherAccount);
shouldBehaveLikeERC20(initialSupply, accounts);
});
});