import { Wallet } from 'ethers' import { ethers, waffle } from 'hardhat' import { TestMulticall } from '../typechain/TestMulticall' import { expect } from './shared/expect' import snapshotGasCost from './shared/snapshotGasCost' describe('Multicall', async () => { let wallets: Wallet[] let multicall: TestMulticall before('get wallets', async () => { wallets = await (ethers as any).getSigners() }) beforeEach('create multicall', async () => { const multicallTestFactory = await ethers.getContractFactory('TestMulticall') multicall = (await multicallTestFactory.deploy()) as TestMulticall }) it('revert messages are returned', async () => { await expect( multicall.multicall([multicall.interface.encodeFunctionData('functionThatRevertsWithError', ['abcdef'])]) ).to.be.revertedWith('abcdef') }) it('return data is properly encoded', async () => { const [data] = await multicall.callStatic.multicall([ multicall.interface.encodeFunctionData('functionThatReturnsTuple', ['1', '2']), ]) const { tuple: { a, b }, } = multicall.interface.decodeFunctionResult('functionThatReturnsTuple', data) expect(b).to.eq(1) expect(a).to.eq(2) }) describe('context is preserved', () => { it('msg.value', async () => { await multicall.multicall([multicall.interface.encodeFunctionData('pays')], { value: 3 }) expect(await multicall.paid()).to.eq(3) }) it('msg.value used twice', async () => { await multicall.multicall( [multicall.interface.encodeFunctionData('pays'), multicall.interface.encodeFunctionData('pays')], { value: 3 } ) expect(await multicall.paid()).to.eq(6) }) it('msg.sender', async () => { expect(await multicall.returnSender()).to.eq(wallets[0].address) }) }) it('gas cost of pay w/o multicall', async () => { await snapshotGasCost(multicall.pays({ value: 3 })) }) it('gas cost of pay w/ multicall', async () => { await snapshotGasCost(multicall.multicall([multicall.interface.encodeFunctionData('pays')], { value: 3 })) }) })