Multicall.test.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. const { ethers } = require('hardhat');
  2. const { expect } = require('chai');
  3. const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
  4. async function fixture() {
  5. const [holder, alice, bruce] = await ethers.getSigners();
  6. const amount = 12_000n;
  7. const helper = await ethers.deployContract('MulticallHelper');
  8. const mock = await ethers.deployContract('$ERC20MulticallMock', ['name', 'symbol']);
  9. await mock.$_mint(holder, amount);
  10. return { holder, alice, bruce, amount, mock, helper };
  11. }
  12. describe('Multicall', function () {
  13. beforeEach(async function () {
  14. Object.assign(this, await loadFixture(fixture));
  15. });
  16. it('batches function calls', async function () {
  17. expect(await this.mock.balanceOf(this.alice)).to.equal(0n);
  18. expect(await this.mock.balanceOf(this.bruce)).to.equal(0n);
  19. await expect(
  20. this.mock.multicall([
  21. this.mock.interface.encodeFunctionData('transfer', [this.alice.address, this.amount / 2n]),
  22. this.mock.interface.encodeFunctionData('transfer', [this.bruce.address, this.amount / 3n]),
  23. ]),
  24. )
  25. .to.emit(this.mock, 'Transfer')
  26. .withArgs(this.holder, this.alice, this.amount / 2n)
  27. .to.emit(this.mock, 'Transfer')
  28. .withArgs(this.holder, this.bruce, this.amount / 3n);
  29. expect(await this.mock.balanceOf(this.alice)).to.equal(this.amount / 2n);
  30. expect(await this.mock.balanceOf(this.bruce)).to.equal(this.amount / 3n);
  31. });
  32. it('returns an array with the result of each call', async function () {
  33. await this.mock.transfer(this.helper, this.amount);
  34. expect(await this.mock.balanceOf(this.helper)).to.equal(this.amount);
  35. await this.helper.checkReturnValues(this.mock, [this.alice, this.bruce], [this.amount / 2n, this.amount / 3n]);
  36. });
  37. it('reverts previous calls', async function () {
  38. expect(await this.mock.balanceOf(this.alice)).to.equal(0n);
  39. await expect(
  40. this.mock.multicall([
  41. this.mock.interface.encodeFunctionData('transfer', [this.alice.address, this.amount]),
  42. this.mock.interface.encodeFunctionData('transfer', [this.bruce.address, this.amount]),
  43. ]),
  44. )
  45. .to.be.revertedWithCustomError(this.mock, 'ERC20InsufficientBalance')
  46. .withArgs(this.holder, 0, this.amount);
  47. expect(await this.mock.balanceOf(this.alice)).to.equal(0n);
  48. });
  49. it('bubbles up revert reasons', async function () {
  50. await expect(
  51. this.mock.multicall([
  52. this.mock.interface.encodeFunctionData('transfer', [this.alice.address, this.amount]),
  53. this.mock.interface.encodeFunctionData('transfer', [this.bruce.address, this.amount]),
  54. ]),
  55. )
  56. .to.be.revertedWithCustomError(this.mock, 'ERC20InsufficientBalance')
  57. .withArgs(this.holder, 0, this.amount);
  58. });
  59. });