Implement recommendations from 5.0 audit Phase 1A (#4398)

Co-authored-by: Francisco Giordano <fg@frang.io>
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
This commit is contained in:
Ernesto García
2023-07-03 12:02:06 -06:00
committed by GitHub
parent 06861dce54
commit bb64458928
38 changed files with 779 additions and 666 deletions

View File

@ -46,145 +46,145 @@ contract('ERC20', function (accounts) {
describe('when the spender is not the zero address', function () {
const spender = recipient;
function shouldDecreaseApproval(amount) {
describe('when there was no approved amount before', function () {
function shouldDecreaseApproval(value) {
describe('when there was no approved value before', function () {
it('reverts', async function () {
const allowance = await this.token.allowance(initialHolder, spender);
await expectRevertCustomError(
this.token.decreaseAllowance(spender, amount, { from: initialHolder }),
this.token.decreaseAllowance(spender, value, { from: initialHolder }),
'ERC20FailedDecreaseAllowance',
[spender, allowance, amount],
[spender, allowance, value],
);
});
});
describe('when the spender had an approved amount', function () {
const approvedAmount = amount;
describe('when the spender had an approved value', function () {
const approvedValue = value;
beforeEach(async function () {
await this.token.approve(spender, approvedAmount, { from: initialHolder });
await this.token.approve(spender, approvedValue, { from: initialHolder });
});
it('emits an approval event', async function () {
expectEvent(
await this.token.decreaseAllowance(spender, approvedAmount, { from: initialHolder }),
await this.token.decreaseAllowance(spender, approvedValue, { 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 });
it('decreases the spender allowance subtracting the requested value', async function () {
await this.token.decreaseAllowance(spender, approvedValue.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 });
await this.token.decreaseAllowance(spender, approvedValue, { 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 }),
this.token.decreaseAllowance(spender, approvedValue.addn(1), { from: initialHolder }),
'ERC20FailedDecreaseAllowance',
[spender, approvedAmount, approvedAmount.addn(1)],
[spender, approvedValue, approvedValue.addn(1)],
);
});
});
}
describe('when the sender has enough balance', function () {
const amount = initialSupply;
const value = initialSupply;
shouldDecreaseApproval(amount);
shouldDecreaseApproval(value);
});
describe('when the sender does not have enough balance', function () {
const amount = initialSupply.addn(1);
const value = initialSupply.addn(1);
shouldDecreaseApproval(amount);
shouldDecreaseApproval(value);
});
});
describe('when the spender is the zero address', function () {
const amount = initialSupply;
const value = initialSupply;
const spender = ZERO_ADDRESS;
it('reverts', async function () {
await expectRevertCustomError(
this.token.decreaseAllowance(spender, amount, { from: initialHolder }),
this.token.decreaseAllowance(spender, value, { from: initialHolder }),
'ERC20FailedDecreaseAllowance',
[spender, 0, amount],
[spender, 0, value],
);
});
});
});
describe('increase allowance', function () {
const amount = initialSupply;
const value = initialSupply;
describe('when the spender is not the zero address', function () {
const spender = recipient;
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', {
expectEvent(await this.token.increaseAllowance(spender, value, { from: initialHolder }), 'Approval', {
owner: initialHolder,
spender: spender,
value: amount,
value: value,
});
});
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 there was no approved value before', function () {
it('approves the requested value', async function () {
await this.token.increaseAllowance(spender, value, { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount);
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(value);
});
});
describe('when the spender had an approved amount', function () {
describe('when the spender had an approved value', 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 });
it('increases the spender allowance adding the requested value', async function () {
await this.token.increaseAllowance(spender, value, { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount.addn(1));
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(value.addn(1));
});
});
});
describe('when the sender does not have enough balance', function () {
const amount = initialSupply.addn(1);
const value = initialSupply.addn(1);
it('emits an approval event', async function () {
expectEvent(await this.token.increaseAllowance(spender, amount, { from: initialHolder }), 'Approval', {
expectEvent(await this.token.increaseAllowance(spender, value, { from: initialHolder }), 'Approval', {
owner: initialHolder,
spender: spender,
value: amount,
value: value,
});
});
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 there was no approved value before', function () {
it('approves the requested value', async function () {
await this.token.increaseAllowance(spender, value, { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount);
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(value);
});
});
describe('when the spender had an approved amount', function () {
describe('when the spender had an approved value', 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 });
it('increases the spender allowance adding the requested value', async function () {
await this.token.increaseAllowance(spender, value, { from: initialHolder });
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount.addn(1));
expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(value.addn(1));
});
});
});
@ -195,7 +195,7 @@ contract('ERC20', function (accounts) {
it('reverts', async function () {
await expectRevertCustomError(
this.token.increaseAllowance(spender, amount, { from: initialHolder }),
this.token.increaseAllowance(spender, value, { from: initialHolder }),
'ERC20InvalidSpender',
[ZERO_ADDRESS],
);
@ -204,11 +204,9 @@ contract('ERC20', function (accounts) {
});
describe('_mint', function () {
const amount = new BN(50);
const value = new BN(50);
it('rejects a null account', async function () {
await expectRevertCustomError(this.token.$_mint(ZERO_ADDRESS, amount), 'ERC20InvalidReceiver', [
ZERO_ADDRESS,
]);
await expectRevertCustomError(this.token.$_mint(ZERO_ADDRESS, value), 'ERC20InvalidReceiver', [ZERO_ADDRESS]);
});
it('rejects overflow', async function () {
@ -221,22 +219,22 @@ contract('ERC20', function (accounts) {
describe('for a non zero account', function () {
beforeEach('minting', async function () {
this.receipt = await this.token.$_mint(recipient, amount);
this.receipt = await this.token.$_mint(recipient, value);
});
it('increments totalSupply', async function () {
const expectedSupply = initialSupply.add(amount);
const expectedSupply = initialSupply.add(value);
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);
expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(value);
});
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);
expect(event.args.value).to.be.bignumber.equal(value);
});
});
});
@ -257,81 +255,81 @@ contract('ERC20', function (accounts) {
);
});
const describeBurn = function (description, amount) {
const describeBurn = function (description, value) {
describe(description, function () {
beforeEach('burning', async function () {
this.receipt = await this.token.$_burn(initialHolder, amount);
this.receipt = await this.token.$_burn(initialHolder, value);
});
it('decrements totalSupply', async function () {
const expectedSupply = initialSupply.sub(amount);
const expectedSupply = initialSupply.sub(value);
expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply);
});
it('decrements initialHolder balance', async function () {
const expectedBalance = initialSupply.sub(amount);
const expectedBalance = initialSupply.sub(value);
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);
expect(event.args.value).to.be.bignumber.equal(value);
});
});
};
describeBurn('for entire balance', initialSupply);
describeBurn('for less amount than balance', initialSupply.subn(1));
describeBurn('for less value than balance', initialSupply.subn(1));
});
});
describe('_update', function () {
const amount = new BN(1);
const value = 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', {
expectEvent(await this.token.$_update(ZERO_ADDRESS, initialHolder, value), 'Transfer', {
from: ZERO_ADDRESS,
to: initialHolder,
value: amount,
value: value,
});
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));
expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.add(value));
expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.add(value));
});
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', {
expectEvent(await this.token.$_update(initialHolder, ZERO_ADDRESS, value), 'Transfer', {
from: initialHolder,
to: ZERO_ADDRESS,
value: amount,
value: value,
});
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));
expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.sub(value));
expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.sub(value));
});
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);
await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, value);
expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply);
expectEvent(await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, amount), 'Transfer', {
expectEvent(await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, value), 'Transfer', {
from: ZERO_ADDRESS,
to: ZERO_ADDRESS,
value: amount,
value: value,
});
});
});
describe('_transfer', function () {
shouldBehaveLikeERC20Transfer(initialHolder, recipient, initialSupply, function (from, to, amount) {
return this.token.$_transfer(from, to, amount);
shouldBehaveLikeERC20Transfer(initialHolder, recipient, initialSupply, function (from, to, value) {
return this.token.$_transfer(from, to, value);
});
describe('when the sender is the zero address', function () {
@ -346,8 +344,8 @@ contract('ERC20', function (accounts) {
});
describe('_approve', function () {
shouldBehaveLikeERC20Approve(initialHolder, recipient, initialSupply, function (owner, spender, amount) {
return this.token.$_approve(owner, spender, amount);
shouldBehaveLikeERC20Approve(initialHolder, recipient, initialSupply, function (owner, spender, value) {
return this.token.$_approve(owner, spender, value);
});
describe('when the owner is the zero address', function () {