Skip to content

Commit

Permalink
Add a waitForTransaction to time helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
beaurancourt committed Jan 30, 2024
1 parent e9a1348 commit c8e5d00
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ extendEnvironment((hre) => {
return ownable(hre)
}),
time: lazyObject(() => {
return time()
return time(hre)
}),
signers: lazyObject(() => {
return signers(hre)
Expand Down
34 changes: 33 additions & 1 deletion src/time.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { HardhatRuntimeEnvironment } from "hardhat/types"
import {
mine,
mineUpTo,
Expand Down Expand Up @@ -30,6 +31,8 @@ export interface HardhatTimeHelpers {
* @param {number} blocks
*/
mineBlocksTo(blocks: number): Promise<number>

waitForTransaction(txHash: string, confirmations?: number): Promise<boolean>
}

/**
Expand Down Expand Up @@ -86,12 +89,41 @@ export async function mineBlocksTo(targetBlock: number): Promise<number> {
return await timeHelpers.latestBlock()
}

export default function (): HardhatTimeHelpers {
export async function waitForTransaction(
hre: HardhatRuntimeEnvironment,
txHash: string,
confirmations: number = 1
): Promise<boolean> {
if (hre.network.name === "hardhat") {
return true
}

const { provider } = hre.ethers
const transaction = await provider.getTransaction(txHash)
if (!transaction) {
throw new Error(`Transaction ${txHash} not found`)
}

let currentConfirmations = await transaction.confirmations()
while (currentConfirmations < confirmations) {
// wait 1s between each check to save API compute units
// eslint-disable-next-line no-await-in-loop, no-promise-executor-return
await new Promise((resolve) => setTimeout(resolve, 1000))
// eslint-disable-next-line no-await-in-loop
currentConfirmations = await transaction.confirmations()
}

return true
}

export default function (hre: HardhatRuntimeEnvironment): HardhatTimeHelpers {
return {
lastBlockNumber: () => lastBlockNumber(),
lastBlockTime: () => lastBlockTime(),
increaseTime: (time: number) => increaseTime(time),
mineBlocks: (blocks: number) => mineBlocks(blocks),
mineBlocksTo: (targetBlock: number) => mineBlocksTo(targetBlock),
waitForTransaction: (txHash: string, confirmations?: number) =>
waitForTransaction(hre, txHash, confirmations),
}
}
57 changes: 57 additions & 0 deletions test/time.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import { useEnvironment } from "./helpers"

import type { HardhatTimeHelpers } from "../src/time"
import type { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"
import type { HardhatEthersHelpers } from "@nomicfoundation/hardhat-ethers/types"
import type { ethers as ethersT } from "ethers"

import { mine } from "@nomicfoundation/hardhat-network-helpers"

import chai from "chai"
chai.use(require("chai-as-promised"))
const { expect } = chai

function timeout(ms: number) {
return new Promise((resolve) => {
setTimeout(() => {
resolve("Timed out after " + ms + " ms")
}, ms)
})
}

describe("time helpers", function () {
context("default hardhat project", function () {
useEnvironment("hardhat-project")
Expand Down Expand Up @@ -114,5 +127,49 @@ describe("time helpers", function () {
)
})
})

describe("waitForTransaction function", function () {
let ethers: typeof ethersT & HardhatEthersHelpers
let signer: HardhatEthersSigner
let transactionResponse: ethersT.TransactionResponse

beforeEach(async function () {
ethers = this.hre.ethers
signer = (await ethers.getSigners())[0]

const tx = {
to: signer.address, // Sending the transaction to the signer's own address
value: ethers.parseEther("0.01"), // Small amount of Ether, can also be 0
}
transactionResponse = await signer.sendTransaction(tx)
})

it("returns immediately on hardhat", async function () {
const waitResult = await Promise.race([
timeHelpers.waitForTransaction(transactionResponse.hash, 5),
timeout(300),
])
expect(waitResult).to.be.true
})

it("does not return immediately on non-hardhat networks", async function () {
this.hre.network.name = "not-hardhat"
const waitResult = await Promise.race([
timeHelpers.waitForTransaction(transactionResponse.hash, 5),
timeout(1000),
])
expect(waitResult).to.equal("Timed out after 1000 ms")
})

it("returns after the transaction is mined", async function () {
this.hre.network.name = "not-hardhat"
await mine(6)
const waitResult = await Promise.race([
timeHelpers.waitForTransaction(transactionResponse.hash, 5),
timeout(1000),
])
expect(waitResult).to.be.true
})
})
})
})

0 comments on commit c8e5d00

Please sign in to comment.