From 330c39b66218de5fa4f0f62d4824ae3c710bb40f Mon Sep 17 00:00:00 2001 From: Renan Souza Date: Thu, 23 Nov 2023 20:45:45 +0000 Subject: [PATCH] Implement revert tests for VestingWallet (#4733) Co-authored-by: ernestognw Co-authored-by: Hadrien Croubois --- test/finance/VestingWallet.behavior.js | 10 ++++ test/finance/VestingWallet.test.js | 78 +++++++++++++++++--------- 2 files changed, 60 insertions(+), 28 deletions(-) diff --git a/test/finance/VestingWallet.behavior.js b/test/finance/VestingWallet.behavior.js index c1e0f8013..d4863bc52 100644 --- a/test/finance/VestingWallet.behavior.js +++ b/test/finance/VestingWallet.behavior.js @@ -34,6 +34,16 @@ function shouldBehaveLikeVesting() { released = vested; } }); + + it('should revert on transaction failure', async function () { + const { args, error } = await this.setupFailure(); + + for (const timestamp of this.schedule) { + await time.forward.timestamp(timestamp); + + await expect(this.mock.release(...args)).to.be.revertedWithCustomError(...error); + } + }); } module.exports = { diff --git a/test/finance/VestingWallet.test.js b/test/finance/VestingWallet.test.js index e3739dd90..fa60faea7 100644 --- a/test/finance/VestingWallet.test.js +++ b/test/finance/VestingWallet.test.js @@ -13,7 +13,54 @@ async function fixture() { const [sender, beneficiary] = await ethers.getSigners(); const mock = await ethers.deployContract('VestingWallet', [beneficiary, start, duration]); - return { mock, amount, duration, start, sender, beneficiary }; + + const token = await ethers.deployContract('$ERC20', ['Name', 'Symbol']); + await token.$_mint(mock, amount); + await sender.sendTransaction({ to: mock, value: amount }); + + const pausableToken = await ethers.deployContract('$ERC20Pausable', ['Name', 'Symbol']); + const beneficiaryMock = await ethers.deployContract('EtherReceiverMock'); + + const env = { + eth: { + checkRelease: async (tx, amount) => { + await expect(tx).to.emit(mock, 'EtherReleased').withArgs(amount); + await expect(tx).to.changeEtherBalances([mock, beneficiary], [-amount, amount]); + }, + setupFailure: async () => { + await beneficiaryMock.setAcceptEther(false); + await mock.connect(beneficiary).transferOwnership(beneficiaryMock); + return { args: [], error: [mock, 'FailedInnerCall'] }; + }, + releasedEvent: 'EtherReleased', + argsVerify: [], + args: [], + }, + token: { + checkRelease: async (tx, amount) => { + await expect(tx).to.emit(token, 'Transfer').withArgs(mock.target, beneficiary.address, amount); + await expect(tx).to.changeTokenBalances(token, [mock, beneficiary], [-amount, amount]); + }, + setupFailure: async () => { + await pausableToken.$_pause(); + return { + args: [ethers.Typed.address(pausableToken)], + error: [pausableToken, 'EnforcedPause'], + }; + }, + releasedEvent: 'ERC20Released', + argsVerify: [token.target], + args: [ethers.Typed.address(token.target)], + }, + }; + + const schedule = Array(64) + .fill() + .map((_, i) => (BigInt(i) * duration) / 60n + start); + + const vestingFn = timestamp => min(amount, (amount * (timestamp - start)) / duration); + + return { mock, duration, start, beneficiary, schedule, vestingFn, env }; } describe('VestingWallet', function () { @@ -35,23 +82,9 @@ describe('VestingWallet', function () { }); describe('vesting schedule', function () { - beforeEach(function () { - this.schedule = Array(64) - .fill() - .map((_, i) => (BigInt(i) * this.duration) / 60n + this.start); - this.vestingFn = timestamp => min(this.amount, (this.amount * (timestamp - this.start)) / this.duration); - }); - describe('Eth vesting', function () { beforeEach(async function () { - await this.sender.sendTransaction({ to: this.mock, value: this.amount }); - - this.getBalance = signer => ethers.provider.getBalance(signer); - this.checkRelease = (tx, amount) => expect(tx).to.changeEtherBalances([this.beneficiary], [amount]); - - this.releasedEvent = 'EtherReleased'; - this.args = []; - this.argsVerify = []; + Object.assign(this, this.env.eth); }); shouldBehaveLikeVesting(); @@ -59,18 +92,7 @@ describe('VestingWallet', function () { describe('ERC20 vesting', function () { beforeEach(async function () { - this.token = await ethers.deployContract('$ERC20', ['Name', 'Symbol']); - await this.token.$_mint(this.mock, this.amount); - - this.getBalance = account => this.token.balanceOf(account); - this.checkRelease = async (tx, amount) => { - await expect(tx).to.emit(this.token, 'Transfer').withArgs(this.mock.target, this.beneficiary.address, amount); - await expect(tx).to.changeTokenBalances(this.token, [this.mock, this.beneficiary], [-amount, amount]); - }; - - this.releasedEvent = 'ERC20Released'; - this.args = [ethers.Typed.address(this.token.target)]; - this.argsVerify = [this.token.target]; + Object.assign(this, this.env.token); }); shouldBehaveLikeVesting();