github NomicFoundation/hardhat hardhat-core-v2.4.0
Hardhat v2.4.0

latest releases: hardhat@2.22.5, @nomicfoundation/hardhat-verify@2.0.8, @nomicfoundation/hardhat-network-helpers@1.0.11...
2 years ago

This release adds support for Solidity 0.8.x, as well as multiple new features for customizing the behavior of the Hardhat Network.

New error messages

Some error messages returned by Hardhat have changed. If you have tests that check the exact message of a Hardhat error, you may need to update them.

For example, before this release a require(false, "this is the reason") statement would've generated this error message:

Error: VM Exception while processing transaction: revert this is the reason

In this new version, the error message will be:

Error: VM Exception while processing transaction: reverted with reason string 'this is the reason'

You'll also get different error messages for panic errors (for example, if you are using solidity 0.8.0 and divide by zero) and for custom errors. See below to learn more about these new features.

New supported solidity features

Custom errors

Hardhat now recognizes custom errors. For example, given this contract:

contract Foo {
  error MyCustomError(uint code, string message);

  function test() public {
    revert MyCustomError(42, "failed for some reason");
  }
}

If you deploy Foo and call its test method, you'll now get a stack trace like this:

Error: VM Exception while processing transaction: reverted with custom error 'MyCustomError(42, "failed for some reason")'
    at Foo.test (contracts/Foo.sol:5)

Keep in mind that Hardhat can only recognize custom errors that are defined within your project. If you use mainnet forking and call some external contract that reverts with a custom error, Hardhat won't be able to parse it, and it will show an unrecognized error instead.

Panic codes

Solidity 0.8.0 introduced the concept of panic codes. In previous solidity versions, internal errors like dividing by zero were signaled by an invalid opcode being executed. The problem with this was that there wasn't a way to detect what kind of internal error was thrown and, worse, an error like this would consume all the remaining gas available in the transaction. Now, instead of using an invalid opcode, these errors use the revert opcode (the same used by the require function) and include a code that indicates what was the problem that caused the error.

For example, if you deploy this contract:

contract Foo {
  function test(uint x) public {
    uint y = 1 / x;
  }
}

and then you call the test function with value 0, Hardhat will now show a stack trace like this:

Error: VM Exception while processing transaction: reverted with panic code 0x12 (Division or modulo division by zero)
    at Foo.test (contracts/Foo.sol:3)

Top level functions

Hardhat now understands and generates correct stack traces when a top-level function is part of the call stack.

Customizing Hardhat Network's behavior

Arbitrary account modifications

Hardhat v2.4.0 includes several new RPC methods that let you modify anything about an address:

hardhat_setNonce

This method lets you change the nonce of an account. For example:

await network.provider.send("hardhat_setNonce", ["0x0d2026b3EE6eC71FC6746ADb6311F6d3Ba1C000B", "0x21"])

This will result in account 0x0d20...000B having a nonce of 33.

You can only use this method to increase the nonce of an account; you can't set a lower value than the account's current nonce.

hardhat_setBalance

This method lets you change the balance of an account. For example:

await network.provider.send("hardhat_setBalance", ["0x0d2026b3EE6eC71FC6746ADb6311F6d3Ba1C000B", "0x1000"])

This will result in account 0x0d20...000B having a balance of 4096 wei.

hardhat_setCode

This method lets you set the bytecode of an address. For example:

await network.provider.send("hardhat_setCode", ["0x0d2026b3EE6eC71FC6746ADb6311F6d3Ba1C000B", "0xa1a2a3..."])

This will result in account 0x0d20...000B becoming a smart contract with bytecode a1a2a3.... If that address was already a smart contract, then its code will be replaced by the specified one.

hardhat_setStorageAt

This method lets you modify any position in the storage of a smart contract. For example:

await network.provider.send("hardhat_setStorageAt", [
  "0x0d2026b3EE6eC71FC6746ADb6311F6d3Ba1C000B",
  "0x0",
  "0x0000000000000000000000000000000000000000000000000000000000000001"
])

This will set the first storage position inside that contract to 1.

The mapping between a smart contract's variables and its storage position is not straightforward except in some very simple cases. For example, if you deploy this contract:

contract Foo {
  uint public x;
}

And you set the first storage position to 1 (as shown in the previous snippet), then calling foo.x() will return 1.

Minimum gas price

You can now configure Hardhat Network so that it only mines transactions that have a gas price equal to or above a given threshold. If automining is enabled, transactions with a lower gas price will be rejected. If automining is disabled, this transactions will be kept in the mempool but they won't be mined.

To configure the minimum gas price, set the minGasPrice property in the Hardhat Network configuration:

module.exports = {
  networks: {
    hardhat: {
      minGasPrice: 1_000_000_000
    }
  }
}

You can also change this value in runtime using the new hardhat_setMinGasPrice RPC method:

await network.provider.send("hardhat_setMinGasPrice", ["0x77359400"])

Transaction replacement

Hardhat now supports transaction replacement when automining is disabled. This means that if you send a transaction from the same address and with the same nonce as another transaction already present in the mempool, but with a higher gas price, this transaction will be replaced. The new gas price needs to be at least 10% higher than the gas price of the current transaction.

Dropping transactions

There is a new hardhat_dropTransaction RPC method that can be used to remove transactions from the mempool:

const txHash = "0xabc..."
const result = await network.provider.send("hardhat_dropTransaction", [txHash])

There are three possible scenarios when this method is used:

  • txHash corresponds to a transaction in the mempool. In this case, the transaction will be removed and result will be true.
  • txHash doesn't correspond to a transaction. In this case nothing will happen and result will be false.
  • txHash corresponds to a mined transaction. In this case an InvalidArgumentsError will be thrown.

Other changes

  • Hardhat now supports the HTTP_PROXY and HTTPS_PROXY environment variables. This is only used to download the Solidity compilers, not for JSON-RPC networks or mainnet forking. Thanks @cdesch for working on this! (PR #1291, issue #1280)

  • When the balance of an account was set to a hexadecimal value, Hardhat would throw a very opaque error. Now a better error message is shown. Thanks to @Bidon15 for this contribution! (PR #1458, issue #1427)

  • Forking from xDai will cache data to disk if you ping a block older with 38 confirmations or more. Thanks to @jacobrosenthal for this! (PR #1557)

Don't miss a new hardhat release

NewReleases is sending notifications on new releases.