diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 2443a047..d1d210ea 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -128,7 +128,7 @@ jobs: - uses: actions/checkout@v3 with: submodules: recursive - - uses: OffchainLabs/actions/run-nitro-test-node@main + - uses: OffchainLabs/actions/run-nitro-test-node@output-logging - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 @@ -198,7 +198,7 @@ jobs: - uses: actions/checkout@v3 with: submodules: recursive - - uses: OffchainLabs/actions/run-nitro-test-node@main + - uses: OffchainLabs/actions/run-nitro-test-node@output-logging - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 diff --git a/audit-ci.jsonc b/audit-ci.jsonc index a399dcc4..e13a56c7 100644 --- a/audit-ci.jsonc +++ b/audit-ci.jsonc @@ -49,6 +49,8 @@ // undici - only used in hardhat, not used in prod "GHSA-wqq4-5wpv-mx2g", // get-func-name - only used in chai, not used in prod - "GHSA-4q6p-r6v2-jvc5" + "GHSA-4q6p-r6v2-jvc5", + // axios used only in sol2uml + "GHSA-wf5p-g6vw-rhxx" ] } \ No newline at end of file diff --git a/files/local/.env-sample b/files/local/.env-sample index 1d60cc48..61385fa7 100644 --- a/files/local/.env-sample +++ b/files/local/.env-sample @@ -9,9 +9,9 @@ ARB_URL="http://localhost:8547" NOVA_URL="http://localhost:8547" ETH_URL="http://localhost:8545" ## Test keys -ARB_KEY="cb5790da63720727af975f42c79f69918580209889225fa7128c92402a6d3a65" -ETH_KEY="cb5790da63720727af975f42c79f69918580209889225fa7128c92402a6d3a65" -NOVA_KEY="cb5790da63720727af975f42c79f69918580209889225fa7128c92402a6d3a65" +ARB_KEY="b6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659" +ETH_KEY="b6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659" +NOVA_KEY="b6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659" DEPLOY_CONFIG_FILE_LOCATION="./files/local/deployConfig.json" VESTED_RECIPIENTS_FILE_LOCATION="./files/local/vestingWalletRecipients.json" diff --git a/scripts/genNetwork.ts b/scripts/genNetwork.ts index e4229f75..a80bc46b 100644 --- a/scripts/genNetwork.ts +++ b/scripts/genNetwork.ts @@ -1,4 +1,4 @@ -import { Wallet, ethers } from "ethers"; +import { ethers } from "ethers"; import { setupNetworks, config, getSigner } from "../test-ts/testSetup"; import * as fs from "fs"; @@ -8,7 +8,7 @@ async function main() { const ethDeployer = getSigner(ethProvider, config.ethKey); const arbDeployer = getSigner(arbProvider, config.arbKey); - + const { l1Network, l2Network } = await setupNetworks( ethDeployer, arbDeployer, diff --git a/scripts/proposalTests.ts b/scripts/proposalTests.ts index d5e70653..998c2ea9 100644 --- a/scripts/proposalTests.ts +++ b/scripts/proposalTests.ts @@ -58,8 +58,8 @@ async function main() { const currentBlock = await arbProvider.getBlockNumber(); while ((await arbProvider.getBlockNumber()) - currentBlock < 2) { if (isLocal) { - await mineBlock(ethDeployer); - await mineBlock(arbDeployer); + await mineBlock(ethDeployer, "2blocketh"); + await mineBlock(arbDeployer, "2blockarb"); } await wait(1000); } diff --git a/src-ts/proposalPipeline.ts b/src-ts/proposalPipeline.ts index 9700eab2..6c5d2e34 100644 --- a/src-ts/proposalPipeline.ts +++ b/src-ts/proposalPipeline.ts @@ -11,6 +11,7 @@ import { UnreachableCaseError, getProvider, BaseGovernorExecuteStage, + L2TimelockExecutionSingleStage, } from "./proposalStage"; import { Signer } from "ethers"; import { Provider, TransactionReceipt } from "@ethersproject/abstract-provider"; @@ -28,6 +29,7 @@ export class StageFactory { return [ ...(await BaseGovernorExecuteStage.extractStages(receipt, this.arbOneSignerOrProvider)), ...(await L2TimelockExecutionBatchStage.extractStages(receipt, this.arbOneSignerOrProvider)), + ...(await L2TimelockExecutionSingleStage.extractStages(receipt, this.arbOneSignerOrProvider)), ...(await L1TimelockExecutionSingleStage.extractStages(receipt, this.l1SignerOrProvider)), ...(await L1TimelockExecutionBatchStage.extractStages(receipt, this.l1SignerOrProvider)), ...(await RetryableExecutionStage.extractStages(receipt, this.arbOneSignerOrProvider)), diff --git a/src-ts/proposalStage.ts b/src-ts/proposalStage.ts index c5c980a5..0915c410 100644 --- a/src-ts/proposalStage.ts +++ b/src-ts/proposalStage.ts @@ -21,6 +21,7 @@ import { L2ArbitrumGovernor__factory, GovernorUpgradeable__factory, SecurityCouncilNomineeElectionGovernor__factory, + ArbSys__factory, } from "../typechain-types"; import { Inbox__factory } from "@arbitrum/sdk/dist/lib/abi/factories/Inbox__factory"; import { EventArgs } from "@arbitrum/sdk/dist/lib/dataEntities/event"; @@ -34,6 +35,7 @@ import { ProposalQueuedEventObject, } from "../typechain-types/src/L2ArbitrumGovernor"; import { hasTimelock, hasVettingPeriod, getL1BlockNumberFromL2 } from "./utils"; +import { CallScheduledEvent } from "../typechain-types/src/ArbitrumTimelock"; type Provider = providers.Provider; @@ -356,30 +358,16 @@ export class GovernorQueueStage extends BaseGovernorExecuteStage { } } -/** - * When a timelock period has passed, execute the proposal action - */ -export class L2TimelockExecutionBatchStage implements ProposalStage { - public readonly name: string = "L2TimelockExecutionBatchStage"; +abstract class L2TimelockExecutionStage implements ProposalStage { public readonly identifier: string; - public constructor( - public readonly targets: string[], - public readonly values: BigNumber[], - public readonly callDatas: string[], - public readonly predecessor: string, - public readonly salt: string, - + constructor( + public readonly name: string, + public readonly operationId: string, public readonly timelockAddress: string, public readonly signerOrProvider: Signer | Provider ) { - this.identifier = L2TimelockExecutionBatchStage.hashOperationBatch( - targets, - values, - callDatas, - predecessor, - salt - ); + this.identifier = operationId; } public static async getProposalCreatedData( @@ -428,62 +416,6 @@ export class L2TimelockExecutionBatchStage implements ProposalStage { } } - public static async extractStages( - receipt: TransactionReceipt, - arbOneSignerOrProvider: Provider | Signer - ): Promise { - const govInterface = L2ArbitrumGovernor__factory.createInterface(); - const proposalStages: L2TimelockExecutionBatchStage[] = []; - for (const log of receipt.logs) { - if (log.topics.find((t) => t === govInterface.getEventTopic("ProposalQueued"))) { - const propQueuedObj = govInterface.parseLog(log) - .args as unknown as ProposalQueuedEventObject; - - // 10m ~ 1 month on arbitrum - const propCreatedStart = log.blockNumber - 10000000; - const propCreatedEnd = log.blockNumber; - - const propCreatedEvent = await this.getProposalCreatedData( - log.address, - propQueuedObj.proposalId.toHexString(), - await getProvider(arbOneSignerOrProvider)!, - propCreatedStart, - propCreatedEnd - ); - if (!propCreatedEvent) { - throw new Error( - `Could not find proposal created event: ${propQueuedObj.proposalId.toHexString()}` - ); - } - // calculate the operation id, and look for it in this receipt - const operationId = L2TimelockExecutionBatchStage.hashOperationBatch( - propCreatedEvent.targets, - (propCreatedEvent as any)[3], - propCreatedEvent.calldatas, - constants.HashZero, - id(propCreatedEvent.description) - ); - const timelockAddress = this.findTimelockAddress(operationId, receipt.logs); - if (!timelockAddress) { - throw new Error(`Could not find timelock address for operation id ${operationId}`); - } - // we know the operation id - const executeBatch = new L2TimelockExecutionBatchStage( - propCreatedEvent.targets, - (propCreatedEvent as any)[3], - propCreatedEvent.calldatas, - constants.HashZero, - id(propCreatedEvent.description), - timelockAddress, - arbOneSignerOrProvider - ); - proposalStages.push(executeBatch); - } - } - - return proposalStages; - } - public static hashOperation( target: string, value: BigNumber, @@ -541,58 +473,30 @@ export class L2TimelockExecutionBatchStage implements ProposalStage { public async status(): Promise { const timelock = ArbitrumTimelock__factory.connect(this.timelockAddress, this.signerOrProvider); - const operationId = await L2TimelockExecutionBatchStage.hashOperationBatch( - this.targets, - this.values, - this.callDatas, - this.predecessor, - this.salt - ); - // operation was cancelled if it doesn't exist - const exists = await timelock.isOperation(operationId); + const exists = await timelock.isOperation(this.operationId); if (!exists) return ProposalStageStatus.TERMINATED; // if it does exist it should be in one of the following states // check isOperationReady before pending because pending is a super set of ready - const ready = await timelock.isOperationReady(operationId); + const ready = await timelock.isOperationReady(this.operationId); if (ready) return ProposalStageStatus.READY; - const pending = await timelock.isOperationPending(operationId); + const pending = await timelock.isOperationPending(this.operationId); if (pending) return ProposalStageStatus.PENDING; - const done = await timelock.isOperationDone(operationId); + const done = await timelock.isOperationDone(this.operationId); if (done) return ProposalStageStatus.EXECUTED; throw new ProposalStageError( - `Proposal exists in unexpected state: ${operationId}`, - this.identifier, + `Proposal exists in unexpected state: ${this.operationId}`, + this.operationId, this.name ); } - public async execute(): Promise { - const timelock = ArbitrumTimelock__factory.connect(this.timelockAddress, this.signerOrProvider); - const tx = await timelock.functions.executeBatch( - this.targets, - this.values, - this.callDatas, - this.predecessor, - this.salt - ); - - await tx.wait(); - } - public async getExecuteReceipt(): Promise { const timelock = ArbitrumTimelock__factory.connect(this.timelockAddress, this.signerOrProvider); const provider = getProvider(this.signerOrProvider); - const operationId = await L2TimelockExecutionBatchStage.hashOperationBatch( - this.targets, - this.values, - this.callDatas, - this.predecessor, - this.salt - ); - const callExecutedFilter = timelock.filters.CallExecuted(operationId); + const callExecutedFilter = timelock.filters.CallExecuted(this.operationId); const logs = await provider!.getLogs({ fromBlock: 0, toBlock: "latest", @@ -610,6 +514,250 @@ export class L2TimelockExecutionBatchStage implements ProposalStage { const execReceipt = await this.getExecuteReceipt(); return `https://arbiscan.io/tx/${execReceipt.transactionHash}`; } + + public abstract execute(): Promise; +} + +/** + * When a timelock period has passed, execute the proposal action + */ +export class L2TimelockExecutionBatchStage extends L2TimelockExecutionStage { + public constructor( + public readonly targets: string[], + public readonly values: BigNumber[], + public readonly callDatas: string[], + public readonly predecessor: string, + public readonly salt: string, + + timelockAddress: string, + signerOrProvider: Signer | Provider + ) { + const operationId = L2TimelockExecutionBatchStage.hashOperationBatch( + targets, + values, + callDatas, + predecessor, + salt + ); + super("L2TimelockExecutionBatchStage", operationId, timelockAddress, signerOrProvider); + } + + public static async extractStages( + receipt: TransactionReceipt, + arbOneSignerOrProvider: Provider | Signer + ): Promise { + const govInterface = L2ArbitrumGovernor__factory.createInterface(); + const proposalStages: L2TimelockExecutionBatchStage[] = []; + for (const log of receipt.logs) { + if (log.topics.find((t) => t === govInterface.getEventTopic("ProposalQueued"))) { + const propQueuedObj = govInterface.parseLog(log) + .args as unknown as ProposalQueuedEventObject; + + // 10m ~ 1 month on arbitrum + const propCreatedStart = log.blockNumber - 10000000; + const propCreatedEnd = log.blockNumber; + + const propCreatedEvent = await this.getProposalCreatedData( + log.address, + propQueuedObj.proposalId.toHexString(), + await getProvider(arbOneSignerOrProvider)!, + propCreatedStart, + propCreatedEnd + ); + if (!propCreatedEvent) { + throw new Error( + `Could not find proposal created event: ${propQueuedObj.proposalId.toHexString()}` + ); + } + // calculate the operation id, and look for it in this receipt + const operationId = L2TimelockExecutionBatchStage.hashOperationBatch( + propCreatedEvent.targets, + (propCreatedEvent as any)[3], + propCreatedEvent.calldatas, + constants.HashZero, + id(propCreatedEvent.description) + ); + const timelockAddress = this.findTimelockAddress(operationId, receipt.logs); + if (!timelockAddress) { + // if we couldnt find the timelock address it's because the operation id was not found on a callscheduled event + // this could be because it was formed via batch instead of single, or vice versa, and is an expected result + continue; + } + // we know the operation id + const executeBatch = new L2TimelockExecutionBatchStage( + propCreatedEvent.targets, + (propCreatedEvent as any)[3], + propCreatedEvent.calldatas, + constants.HashZero, + id(propCreatedEvent.description), + timelockAddress, + arbOneSignerOrProvider + ); + proposalStages.push(executeBatch); + } + } + + return proposalStages; + } + + public async execute(): Promise { + const timelock = ArbitrumTimelock__factory.connect(this.timelockAddress, this.signerOrProvider); + const tx = await timelock.functions.executeBatch( + this.targets, + this.values, + this.callDatas, + this.predecessor, + this.salt + ); + + await tx.wait(); + } +} + +/** + * When a timelock period has passed, execute the proposal action + */ +export class L2TimelockExecutionSingleStage extends L2TimelockExecutionStage { + public constructor( + public readonly target: string, + public readonly value: BigNumber, + public readonly callData: string, + public readonly predecessor: string, + public readonly salt: string, + + timelockAddress: string, + signerOrProvider: Signer | Provider + ) { + const operationId = L2TimelockExecutionSingleStage.hashOperation( + target, + value, + callData, + predecessor, + salt + ); + super("L2TimelockExecutionSingleStage", operationId, timelockAddress, signerOrProvider); + } + + public static async extractStages( + receipt: TransactionReceipt, + arbOneSignerOrProvider: Provider | Signer + ): Promise { + const proposalStages: L2TimelockExecutionSingleStage[] = []; + const govInterface = L2ArbitrumGovernor__factory.createInterface(); + const timelockInterface = ArbitrumTimelock__factory.createInterface(); + + for (const log of receipt.logs) { + if (log.topics[0] === timelockInterface.getEventTopic("CallScheduled")) { + // try to parse the call scheduled event to get get the operation id and form as stage + // the data should be a call to arbsys sendTxToL1 + try { + const callScheduledArgs = timelockInterface.parseLog(log) + .args as CallScheduledEvent["args"]; + + const { data } = ArbSys__factory.createInterface().decodeFunctionData( + "sendTxToL1", + callScheduledArgs.data + ); + + const { salt } = this.decodeScheduleBatch(data); + + // calculate the id and check if that operation exists + const operationId = this.hashOperation( + callScheduledArgs.target, + callScheduledArgs[3], // cant use .value as ethers fails with this + callScheduledArgs.data, + callScheduledArgs.predecessor, + salt + ); + + if (operationId !== callScheduledArgs.id) { + throw new Error("Invalid operation id"); + } + + const timelockAddress = log.address; + const executeTimelock = new L2TimelockExecutionSingleStage( + callScheduledArgs.target, + callScheduledArgs[3], + callScheduledArgs.data, + callScheduledArgs.predecessor, + salt, + timelockAddress, + arbOneSignerOrProvider + ); + if ( + proposalStages.filter((s) => s.identifier === executeTimelock.identifier).length === 0 + ) { + proposalStages.push(executeTimelock); + } + } catch (err) { + // there are expected errors since the calldata may not be of the expected form for decoding + continue; + } + } else if (log.topics[0] === govInterface.getEventTopic("ProposalQueued")) { + const proposalId = ( + govInterface.parseLog(log).args as unknown as ProposalQueuedEventObject + ).proposalId.toHexString(); + + // 10m ~ 1 month on arbitrum + const propCreatedStart = log.blockNumber - 10000000; + const propCreatedEnd = log.blockNumber; + + const propCreatedEvent = await this.getProposalCreatedData( + log.address, + proposalId, + await getProvider(arbOneSignerOrProvider)!, + propCreatedStart, + propCreatedEnd + ); + if (!propCreatedEvent) { + throw new Error(`Could not find proposal created event: ${proposalId}`); + } + // calculate the operation id, and look for it in this receipt + const operationId = L2TimelockExecutionSingleStage.hashOperation( + propCreatedEvent.targets[0], + (propCreatedEvent as any)[3][0], + propCreatedEvent.calldatas[0], + constants.HashZero, + id(propCreatedEvent.description) + ); + const timelockAddress = this.findTimelockAddress(operationId, receipt.logs); + if (!timelockAddress) { + // if we couldnt find the timelock address it's because the operation id was not found on a callscheduled event + // this could be because it was formed via batch instead of single, or vice versa, and is an expected result + continue; + } + const executeTimelock = new L2TimelockExecutionSingleStage( + propCreatedEvent.targets[0], + (propCreatedEvent as any)[3][0], + propCreatedEvent.calldatas[0], + constants.HashZero, + id(propCreatedEvent.description), + timelockAddress, + arbOneSignerOrProvider + ); + if ( + proposalStages.filter((s) => s.identifier === executeTimelock.identifier).length === 0 + ) { + proposalStages.push(executeTimelock); + } + } + } + + return proposalStages; + } + + public async execute(): Promise { + const timelock = ArbitrumTimelock__factory.connect(this.timelockAddress, this.signerOrProvider); + const tx = await timelock.functions.execute( + this.target, + this.value, + this.callData, + this.predecessor, + this.salt + ); + + await tx.wait(); + } } /** @@ -646,7 +794,6 @@ export class L1OutboxStage implements ProposalStage { public async status(): Promise { const message = L2ToL1Message.fromEvent(this.l1SignerOrProvider, this.l2ToL1TxEvent); - const status = await message.status(this.l2Provider); switch (status) { diff --git a/test-ts/governance.test.ts b/test-ts/governance.test.ts index e36e131a..1b909dd1 100644 --- a/test-ts/governance.test.ts +++ b/test-ts/governance.test.ts @@ -217,7 +217,7 @@ describe("Governor", function () { l2GovernorContract, localMiners ); - }).timeout(360000); + }).timeout(600000); it("L2-L1-L2 monitoring value", async () => { const { l1Signer, l2Signer, l1Deployer, l2Deployer } = await testSetup(); @@ -240,7 +240,7 @@ describe("Governor", function () { l2GovernorContract, localMiners ); - }).timeout(360000); + }).timeout(600000); it("L2-L1 monitoring", async () => { const { l1Signer, l2Signer, l1Deployer, l2Deployer } = await testSetup(); @@ -263,7 +263,7 @@ describe("Governor", function () { l2GovernorContract, localMiners ); - }).timeout(360000); + }).timeout(600000); it("L2-L1-L2 monitoring", async () => { const { l1Signer, l2Signer, l1Deployer, l2Deployer } = await testSetup(); @@ -286,7 +286,7 @@ describe("Governor", function () { l2GovernorContract, localMiners ); - }).timeout(360000); + }).timeout(600000); it("L2-L1 proposal", async () => { const { l1Signer, l2Signer, l1Deployer, l2Deployer } = await testSetup(); @@ -307,7 +307,7 @@ describe("Governor", function () { l1TimelockContract, l2TimelockContract, ); - }).timeout(360000); + }).timeout(600000); it("L2-L1-L2 proposal", async () => { const { l1Signer, l2Signer, l1Deployer, l2Deployer } = await testSetup(); @@ -327,5 +327,5 @@ describe("Governor", function () { l2TimelockContract, l2UpgradeExecutor ); - }).timeout(360000); + }).timeout(600000); }); diff --git a/test-ts/integration.ts b/test-ts/integration.ts index 07b331bf..f26d62e8 100644 --- a/test-ts/integration.ts +++ b/test-ts/integration.ts @@ -32,16 +32,18 @@ import { const wait = async (ms: number) => new Promise((res) => setTimeout(res, ms)); -export const mineBlock = async (signer: Signer) => { +export const mineBlock = async (signer: Signer, tag: string) => { console.log( - `Mining block for ${await signer.getAddress()}:${(await signer.provider!.getNetwork()).chainId}` + `Mining block for ${tag}:${await signer.getAddress()}:${ + (await signer.provider!.getNetwork()).chainId + }` ); await (await signer.sendTransaction({ to: await signer.getAddress(), value: 0 })).wait(); }; -const mineUntilStop = async (miner: Signer, state: { mining: boolean }) => { +const mineUntilStop = async (miner: Signer, state: { mining: boolean }, tag: string) => { while (state.mining) { - await mineBlock(miner); + await mineBlock(miner, tag); await wait(15000); } }; @@ -234,6 +236,7 @@ const mineBlocksAndWaitForProposalState = async ( l2GovernorContract: L2ArbitrumGovernor, proposalId: string, state: number, + tag: string, localMiners?: { l1Signer: Signer; l2Signer: Signer; @@ -241,8 +244,8 @@ const mineBlocksAndWaitForProposalState = async ( ) => { while (true) { if (localMiners) { - await mineBlock(localMiners.l1Signer); - await mineBlock(localMiners.l2Signer); + await mineBlock(localMiners.l1Signer, tag + "-l1signer"); + await mineBlock(localMiners.l2Signer, tag + "-l2signer"); } else { await wait(1000); } @@ -350,13 +353,13 @@ export const l2L1MonitoringValueTest = async ( ).wait(); // wait a while then cast a vote - await mineBlocksAndWaitForProposalState(l2GovernorContract, proposal.id(), 1, localMiners); + await mineBlocksAndWaitForProposalState(l2GovernorContract, proposal.id(), 1, "waitforpropl2L1val", localMiners); await (await l2GovernorContract.connect(proposer).castVote(proposal.id(), 1)).wait(); const noteBefore = await noteStore.exists(noteId); expect(noteBefore, "Note exists before").to.be.false; - await mineBlocksUntilComplete(noteExists(noteStore, noteId), localMiners); + await mineBlocksUntilComplete(noteExists(noteStore, noteId), "waitfornotel2L1val", localMiners); const noteAfter = await noteStore.exists(noteId); expect(noteAfter, "Note exists after").to.be.true; @@ -364,6 +367,7 @@ export const l2L1MonitoringValueTest = async ( const mineBlocksUntilComplete = async ( completion: Promise, + tag: string, localMiners?: { l1Signer: Signer; l2Signer: Signer; @@ -383,8 +387,8 @@ const mineBlocksUntilComplete = async ( while (mining) { if (localMiners) { - await mineBlock(localMiners.l1Signer); - await mineBlock(localMiners.l2Signer); + await mineBlock(localMiners.l1Signer, tag + "-l1signer"); + await mineBlock(localMiners.l2Signer, tag + "-l2signer"); } await wait(500); } @@ -477,13 +481,13 @@ export const l2L1L2MonitoringValueTest = async ( ).wait(); // wait a while then cast a vote - await mineBlocksAndWaitForProposalState(l2GovernorContract, proposal.id(), 1, localMiners); + await mineBlocksAndWaitForProposalState(l2GovernorContract, proposal.id(), 1, "waitforpropl2L1L2val", localMiners); await (await l2GovernorContract.connect(proposer).castVote(proposal.id(), 1)).wait(); const noteBefore = await noteStore.exists(noteId); expect(noteBefore, "Note exists before").to.be.false; - await mineBlocksUntilComplete(noteExists(noteStore, noteId), localMiners); + await mineBlocksUntilComplete(noteExists(noteStore, noteId), "waitfornotel2L1L2val", localMiners); const noteAfter = await noteStore.exists(noteId); expect(noteAfter, "Note exists after").to.be.true; @@ -568,13 +572,13 @@ export const l2L1MonitoringTest = async ( await proposalMonitor.monitorSingleProposal(receipt); // wait a while then cast a vote - await mineBlocksAndWaitForProposalState(l2GovernorContract, proposal.id(), 1, localMiners); + await mineBlocksAndWaitForProposalState(l2GovernorContract, proposal.id(), 1, "waitforpropl2L1", localMiners); await (await l2GovernorContract.connect(proposer).castVote(proposal.id(), 1)).wait(); const noteBefore = await noteStore.exists(noteId); expect(noteBefore, "Note exists before").to.be.false; - await mineBlocksUntilComplete(noteExists(noteStore, noteId), localMiners); + await mineBlocksUntilComplete(noteExists(noteStore, noteId), "waitfornotel2L1",localMiners); const noteAfter = await noteStore.exists(noteId); expect(noteAfter, "Note exists after").to.be.true; @@ -661,13 +665,13 @@ export const l2L1L2MonitoringTest = async ( await proposalMonitor.monitorSingleProposal(receipt); // wait a while then cast a vote - await mineBlocksAndWaitForProposalState(l2GovernorContract, proposal.id(), 1, localMiners); + await mineBlocksAndWaitForProposalState(l2GovernorContract, proposal.id(), 1, "waitforpropL2L1L2", localMiners); await (await l2GovernorContract.connect(proposer).castVote(proposal.id(), 1)).wait(); const noteBefore = await noteStore.exists(noteId); expect(noteBefore, "Note exists before").to.be.false; - await mineBlocksUntilComplete(noteExists(noteStore, noteId), localMiners); + await mineBlocksUntilComplete(noteExists(noteStore, noteId), "waitfornoteL2L1L2", localMiners); const noteAfter = await noteStore.exists(noteId); expect(noteAfter, "Note exists after").to.be.true; @@ -690,8 +694,8 @@ const execL1Component = async ( const state = { mining: true }; await Promise.race([ - mineUntilStop(l1Deployer, state), - mineUntilStop(l2Deployer, state), + mineUntilStop(l1Deployer, state, "withdrawl1dep"), + mineUntilStop(l2Deployer, state, "withdrawl2dep"), withdrawMessage.waitUntilReadyToExecute(l2Signer.provider!), ]); state.mining = false; @@ -702,8 +706,8 @@ const execL1Component = async ( const opId = propFormNonEmpty.l1Gov.operationId; while (true) { - await mineBlock(l1Signer); - await mineBlock(l2Signer); + await mineBlock(l1Signer, "l1opreadyl1signer"); + await mineBlock(l2Signer, "l1opreadyl2signer"); if (await l1TimelockContract.isOperationReady(opId)) break; await wait(1000); } @@ -729,7 +733,6 @@ const execL1Component = async ( const rec = await tx.wait(); expect(await proposalSuccess(), "L1 proposal success").to.be.true; - return rec; }; @@ -754,7 +757,7 @@ const proposeAndExecuteL2 = async ( const proposalVotes = await l2GovernorContract.proposalVotes(proposalId); expect(proposalVotes, "Proposal exists").to.not.be.undefined; - await mineBlocksAndWaitForProposalState(l2GovernorContract, proposalId, 1, { + await mineBlocksAndWaitForProposalState(l2GovernorContract, proposalId, 1, "l2propstate1", { l1Signer: l1Deployer, l2Signer: l2Deployer, }); @@ -768,7 +771,7 @@ const proposeAndExecuteL2 = async ( .to.be.true; // wait for proposal to be in success state - await mineBlocksAndWaitForProposalState(l2GovernorContract, proposalId, 4, { + await mineBlocksAndWaitForProposalState(l2GovernorContract, proposalId, 4, "l2propstate4", { l1Signer: l1Deployer, l2Signer: l2Deployer, }); @@ -781,15 +784,15 @@ const proposeAndExecuteL2 = async ( }) ).wait(); - await mineBlocksAndWaitForProposalState(l2GovernorContract, proposalId, 5, { + await mineBlocksAndWaitForProposalState(l2GovernorContract, proposalId, 5, "l2propstate5", { l1Signer: l1Deployer, l2Signer: l2Deployer, }); const opIdBatch = propFormedNonEmpty.l2Gov.operationId; while (!(await l2TimelockContract.isOperationReady(opIdBatch))) { - await mineBlock(l1Deployer); - await mineBlock(l2Deployer); + await mineBlock(l1Deployer, "l2opreadyl1dep"); + await mineBlock(l2Deployer, "l2opreadyl2dep"); await wait(1000); }