VestingWallet.test.js 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. const { ethers } = require('hardhat');
  2. const { expect } = require('chai');
  3. const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
  4. const { bigint: time } = require('../helpers/time');
  5. const { min } = require('../helpers/math');
  6. const { shouldBehaveLikeVesting } = require('./VestingWallet.behavior');
  7. async function fixture() {
  8. const amount = ethers.parseEther('100');
  9. const duration = time.duration.years(4);
  10. const start = (await time.clock.timestamp()) + time.duration.hours(1);
  11. const [sender, beneficiary] = await ethers.getSigners();
  12. const mock = await ethers.deployContract('VestingWallet', [beneficiary, start, duration]);
  13. return { mock, amount, duration, start, sender, beneficiary };
  14. }
  15. describe('VestingWallet', function () {
  16. beforeEach(async function () {
  17. Object.assign(this, await loadFixture(fixture));
  18. });
  19. it('rejects zero address for beneficiary', async function () {
  20. await expect(ethers.deployContract('VestingWallet', [ethers.ZeroAddress, this.start, this.duration]))
  21. .revertedWithCustomError(this.mock, 'OwnableInvalidOwner')
  22. .withArgs(ethers.ZeroAddress);
  23. });
  24. it('check vesting contract', async function () {
  25. expect(await this.mock.owner()).to.be.equal(this.beneficiary.address);
  26. expect(await this.mock.start()).to.be.equal(this.start);
  27. expect(await this.mock.duration()).to.be.equal(this.duration);
  28. expect(await this.mock.end()).to.be.equal(this.start + this.duration);
  29. });
  30. describe('vesting schedule', function () {
  31. beforeEach(function () {
  32. this.schedule = Array(64)
  33. .fill()
  34. .map((_, i) => (BigInt(i) * this.duration) / 60n + this.start);
  35. this.vestingFn = timestamp => min(this.amount, (this.amount * (timestamp - this.start)) / this.duration);
  36. });
  37. describe('Eth vesting', function () {
  38. beforeEach(async function () {
  39. await this.sender.sendTransaction({ to: this.mock, value: this.amount });
  40. this.getBalance = signer => ethers.provider.getBalance(signer);
  41. this.checkRelease = (tx, amount) => expect(tx).to.changeEtherBalances([this.beneficiary], [amount]);
  42. this.releasedEvent = 'EtherReleased';
  43. this.args = [];
  44. this.argsVerify = [];
  45. });
  46. shouldBehaveLikeVesting();
  47. });
  48. describe('ERC20 vesting', function () {
  49. beforeEach(async function () {
  50. this.token = await ethers.deployContract('$ERC20', ['Name', 'Symbol']);
  51. await this.token.$_mint(this.mock, this.amount);
  52. this.getBalance = account => this.token.balanceOf(account);
  53. this.checkRelease = async (tx, amount) => {
  54. await expect(tx).to.emit(this.token, 'Transfer').withArgs(this.mock.target, this.beneficiary.address, amount);
  55. await expect(tx).to.changeTokenBalances(this.token, [this.mock, this.beneficiary], [-amount, amount]);
  56. };
  57. this.releasedEvent = 'ERC20Released';
  58. this.args = [ethers.Typed.address(this.token.target)];
  59. this.argsVerify = [this.token.target];
  60. });
  61. shouldBehaveLikeVesting();
  62. });
  63. });
  64. });