UNPKG

@hyperlane-xyz/core

Version:

Core solidity contracts for Hyperlane

145 lines (126 loc) 5.13 kB
import { expect } from 'chai' import { ethers } from 'hardhat' import { ValidatorWalletCreator, ValidatorWalletCreator__factory, ValidatorWallet, RollupMock, RollupMock__factory, } from '../../build/types' import { initializeAccounts } from './utils' type ArrayElement<A> = A extends readonly (infer T)[] ? T : never describe('Validator Wallet', () => { let accounts: Awaited<ReturnType<typeof initializeAccounts>> let owner: ArrayElement<typeof accounts> let executor: ArrayElement<typeof accounts> let rollupOwner: ArrayElement<typeof accounts> let walletCreator: ValidatorWalletCreator let wallet: ValidatorWallet let rollupMock1: RollupMock let rollupMock2: RollupMock before(async () => { accounts = await initializeAccounts() const WalletCreator: ValidatorWalletCreator__factory = await ethers.getContractFactory('ValidatorWalletCreator') walletCreator = await WalletCreator.deploy() await walletCreator.deployed() owner = accounts[0] executor = accounts[1] rollupOwner = accounts[2] const walletCreationTx = await (await walletCreator.createWallet([])).wait() const events = walletCreationTx.logs .filter( curr => curr.topics[0] === walletCreator.interface.getEventTopic('WalletCreated') ) .map(curr => walletCreator.interface.parseLog(curr)) if (events.length !== 1) throw new Error('No Events!') const walletAddr = events[0].args.walletAddress const Wallet = await ethers.getContractFactory('ValidatorWallet') wallet = (await Wallet.attach(walletAddr)) as ValidatorWallet await wallet.setExecutor([await executor.getAddress()], [true]) await wallet.transferOwnership(await owner.getAddress()) const RollupMock = (await ethers.getContractFactory( 'RollupMock' )) as RollupMock__factory rollupMock1 = (await RollupMock.deploy( await rollupOwner.getAddress() )) as RollupMock rollupMock2 = (await RollupMock.deploy( await rollupOwner.getAddress() )) as RollupMock await accounts[0].sendTransaction({ to: wallet.address, value: ethers.utils.parseEther('5'), }) }) it('should validate destination addresses', async function () { const addrs = [ '0x1234567812345678123456781234567812345678', '0x0000000000000000000000000000000000000000', '0x0123000000000000000000000000000000000000', ] await wallet.setAllowedExecutorDestinations(addrs, [true, true, true]) expect(await wallet.allowedExecutorDestinations(addrs[0])).to.be.true expect(await wallet.allowedExecutorDestinations(addrs[1])).to.be.true expect(await wallet.allowedExecutorDestinations(addrs[2])).to.be.true expect( await wallet.allowedExecutorDestinations( '0x1114567812345678123456781234567812341111' ) ).to.be.false // should fail if random destination address on executor, but should work for the owner const rand = '0x1114567812345678123456781234567899941111' await expect(wallet.connect(executor).validateExecuteTransaction(rand)).to .be.reverted await wallet.connect(owner).validateExecuteTransaction(rand) for (const addr of addrs) { await wallet.connect(owner).validateExecuteTransaction(addr) await wallet.connect(executor).validateExecuteTransaction(addr) // TODO: update waffle once released with fix for custom errors https://github.com/TrueFiEng/Waffle/pull/719 await expect(wallet.connect(executor).validateExecuteTransaction(rand)).to .be.reverted } }) it('should not allow executor to execute certain txs', async function () { const data = rollupMock1.interface.encodeFunctionData('withdrawStakerFunds') await expect( wallet.connect(executor).executeTransaction(data, rollupMock1.address, 0) ).to.be.revertedWith( `OnlyOwnerDestination("${await owner.getAddress()}", "${await executor.getAddress()}", "${ rollupMock1.address }")` ) await expect( wallet.connect(owner).executeTransaction(data, rollupMock1.address, 0) ).to.emit(rollupMock1, 'WithdrawTriggered') await wallet.setAllowedExecutorDestinations([rollupMock1.address], [true]) await expect( wallet.connect(executor).executeTransaction(data, rollupMock1.address, 0) ).to.emit(rollupMock1, 'WithdrawTriggered') }) it('should reject batch if single tx is not allowed by executor', async function () { const data = [ rollupMock1.interface.encodeFunctionData('removeOldZombies', [0]), rollupMock2.interface.encodeFunctionData('withdrawStakerFunds'), ] await wallet.setAllowedExecutorDestinations( [rollupMock1.address, rollupMock2.address], [true, false] ) await expect( wallet .connect(executor) .executeTransactions( data, [rollupMock1.address, rollupMock2.address], [0, 0] ) ).to.be.revertedWith( `OnlyOwnerDestination("${await owner.getAddress()}", "${await executor.getAddress()}", "${ rollupMock2.address }")` ) }) })