Skip to content

Gas statistics for your test runs

Hardhat can optionally show statistics on the gas consumed by your contracts’ public functions during a test run. Use the --gas-stats flag when running your tests to display this information.

You can pass the --gas-stats flag to either the test task or to one of its subtasks (e.g., test solidity):

Terminal window
npx hardhat test --gas-stats
npx hardhat test solidity --gas-stats
npx hardhat test nodejs --gas-stats

This prints a table like the following:

╔═══════════════════════════════════════════════════════════════════════════════════════╗
║ Gas Usage Statistics ║
╚═══════════════════════════════════════════════════════════════════════════════════════╝
╔═══════════════════════════════════════════════════════════════════════════════════════╗
║ contracts/Calculator.sol:Calculator ║
╟───────────────────────────────────┬────────┬─────────┬────────┬────────┬──────────────╢
║ Function name │ Min │ Average │ Median │ Max │ #calls ║
╟───────────────────────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ divide │ 44316 │ 44316 │ 44316 │ 44316 │ 1 ║
║ multiply(uint256,uint256) │ 44254 │ 44254 │ 44254 │ 44254 │ 2 ║
║ multiply(uint256,uint256,uint256) │ 44875 │ 44875 │ 44875 │ 44875 │ 1 ║
║ reset │ 21485 │ 21485 │ 21485 │ 21485 │ 1 ║
║ result │ 23510 │ 23510 │ 23510 │ 23510 │ 6 ║
║ subtract │ 44213 │ 44213 │ 44213 │ 44213 │ 1 ║
╟───────────────────────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ Deployment │ Min │ Average │ Median │ Max │ #deployments ║
╟───────────────────────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ │ 288115 │ 288115 │ 288115 │ 288115 │ 1 ║
╚═══════════════════════════════════╧════════╧═════════╧════════╧════════╧══════════════╝
╔═══════════════════════════════════════════════════════════════════════════════════════╗
║ contracts/Counter.sol:Counter ║
╟───────────────────────────────────┬────────┬─────────┬────────┬────────┬──────────────╢
║ Function name │ Min │ Average │ Median │ Max │ #calls ║
╟───────────────────────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ add(uint256) │ 43915 │ 43915 │ 43915 │ 43915 │ 1 ║
║ add(uint256,bool) │ 44284 │ 44419 │ 44419 │ 44554 │ 2 ║
║ inc │ 43482 │ 43482 │ 43482 │ 43482 │ 1 ║
║ x │ 23466 │ 23466 │ 23466 │ 23466 │ 5 ║
╟───────────────────────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ Deployment │ Min │ Average │ Median │ Max │ #deployments ║
╟───────────────────────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ │ 234940 │ 234940 │ 234940 │ 234940 │ 1 ║
╚═══════════════════════════════════╧════════╧═════════╧════════╧════════╧══════════════╝

The statistics are collected from the functions called by the tests you executed. This means that running test solidity --gas-stats will produce a different result than running test nodejs --gas-stats, because different tests will have been run.

To save gas statistics to a JSON file, pass the --gas-stats-json <path> flag:

Terminal window
npx hardhat test --gas-stats-json gas-stats.json
npx hardhat test solidity --gas-stats-json gas-stats.json
npx hardhat test nodejs --gas-stats-json gas-stats.json

This flag works independently of --gas-stats, so either or both can be used together. For example, to print the table to the terminal and also save the results to a file:

Terminal window
npx hardhat test --gas-stats --gas-stats-json gas-stats.json

The JSON file has the following structure:

{
"contracts": {
"contracts/Calculator.sol:Calculator": {
"sourceName": "contracts/Calculator.sol",
"contractName": "Calculator",
"deployment": {
"min": 288115,
"max": 288115,
"avg": 288115,
"median": 288115,
"count": 1
},
"functions": {
"divide": {
"min": 44316,
"max": 44316,
"avg": 44316,
"median": 44316,
"count": 1
},
"multiply(uint256,uint256)": {
"min": 44254,
"max": 44254,
"avg": 44254,
"median": 44254,
"count": 2
}
// ...
}
},
"contracts/Counter.sol:Counter": {
"sourceName": "contracts/Counter.sol",
"contractName": "Counter",
"deployment": {
"min": 234940,
"max": 234940,
"avg": 234940,
"median": 234940,
"count": 1
},
"functions": {
"add(uint256)": {
"min": 43915,
"max": 43915,
"avg": 43915,
"median": 43915,
"count": 1
},
"add(uint256,bool)": {
"min": 44284,
"max": 44554,
"avg": 44419,
"median": 44419,
"count": 2
}
// ...
}
}
}
}

The gas statistics table shows the following information for each function and deployment:

  • count: Number of times the function was called or the contract was deployed
  • min: Minimum gas consumed in a single call
  • max: Maximum gas consumed in a single call
  • avg: Average gas consumed across all calls
  • median: Median gas consumed across all calls

Gas statistics only include public functions that are called directly by your tests. If a public function is called by another function but not directly by a test, it won’t be included in the statistics.

For example, consider this contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Counter {
uint256 public count;
function inc() public {
_incInternal();
}
function _incInternal() private {
count++;
}
function incBy(uint256 value) public {
count += value;
}
function reset() public {
count = 0;
}
}

And this test:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./Counter.sol";
contract CounterTest {
Counter counter;
function setUp() public {
counter = new Counter();
}
function testInc() public {
counter.inc();
}
function testIncBy() public {
counter.incBy(5);
}
}

The output will be:

╔═════════════════════════════════════════════════════════════════════╗
║ Gas Usage Statistics ║
╚═════════════════════════════════════════════════════════════════════╝
╔═════════════════════════════════════════════════════════════════════╗
║ contracts/Counter.sol:Counter ║
╟─────────────────┬────────┬─────────┬────────┬────────┬──────────────╢
║ Function name │ Min │ Average │ Median │ Max │ #calls ║
╟─────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ inc │ 43484 │ 43484 │ 43484 │ 43484 │ 1 ║
║ incBy │ 43937 │ 43937 │ 43937 │ 43937 │ 1 ║
╟─────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ Deployment │ Min │ Average │ Median │ Max │ #deployments ║
╟─────────────────┼────────┼─────────┼────────┼────────┼──────────────╢
║ │ 179915 │ 179915 │ 179915 │ 179915 │ 1 ║
╚═════════════════╧════════╧═════════╧════════╧════════╧══════════════╝

The statistics include inc and incBy because they’re called directly by the tests. The reset() function doesn’t appear because it’s never called by the tests. The _incInternal() function doesn’t appear because it’s private and only called by inc(), not directly by the tests.