diff --git a/README.md b/README.md
index 284fa570..db48517c 100644
--- a/README.md
+++ b/README.md
@@ -95,6 +95,7 @@ module.exports = {
| Option
| Type
| Default
| Description
|
| ------ | ---- | ------- | ----------- |
| skipFiles | *Array* | `[]` | Array of contracts or folders (with paths expressed relative to the `contracts` directory) that should be skipped when doing instrumentation.(ex: `[ "Routers", "Networks/Polygon.sol"]`) :warning: **RUN THE HARDHAT CLEAN COMMAND AFTER UPDATING THIS** |
+| irMinimum | *Boolean* | `[]` | Speeds up test execution times when solc is run in `viaIR` mode. If your project successfully compiles while generating coverage with this option turned on (it may not!) it's worth using |
| modifierWhitelist | *String[]* | `[]` | List of modifier names (ex: `onlyOwner`) to exclude from branch measurement. (Useful for modifiers which prepare something instead of acting as a gate.)) |
| mocha | *Object* | `{ }` | [Mocha options][3] to merge into existing mocha config. `grep` and `invert` are useful for skipping certain tests under coverage using tags in the test descriptions. [More...][24]|
| measureStatementCoverage | *boolean* | `true` | Computes statement (in addition to line) coverage. [More...][34] |
@@ -113,9 +114,9 @@ module.exports = {
| onCompileComplete[*][14] | *Function* | | Hook run *after* compilation completes, *before* tests are run. Useful if you have secondary compilation steps or need to modify built artifacts. [More...][23]|
| onTestsComplete[*][14] | *Function* | | Hook run *after* the tests complete, *before* Istanbul reports are generated. [More...][23]|
| onIstanbulComplete[*][14] | *Function* | | Hook run *after* the Istanbul reports are generated, *before* the coverage task completes. Useful if you need to clean resources up. [More...][23]|
-| **:warning: DEPRECATED** | | | |
-| configureYulOptimizer | *Boolean* | false | **(Deprecated since 0.8.7)** Setting to `true` should resolve "stack too deep" compiler errors in large projects using ABIEncoderV2 |
-| solcOptimizerDetails | *Object* | `undefined` |**(Deprecated since 0.8.7))** Must be used in combination with `configureYulOptimizer`. Allows you to configure solc's [optimizer details][1001]. Useful if the default remedy for stack-too-deep errors doesn't work in your case (See [FAQ: Running out of stack][1002] ). |
+| **:warning: LOW LEVEL** | | | |
+| configureYulOptimizer | *Boolean* | false | Setting to `true` lets you specify optimizer details (see next option). If no details are defined it defaults to turning on the yul optimizer and enabling stack allocation |
+| solcOptimizerDetails | *Object* | `undefined` |Must be used in combination with `configureYulOptimizer`. Allows you to configure solc's [optimizer details][1001]. (See [FAQ: Running out of stack][1002] ). |
[* Advanced use][14]
diff --git a/lib/api.js b/lib/api.js
index 79ea611a..368312d3 100644
--- a/lib/api.js
+++ b/lib/api.js
@@ -56,6 +56,7 @@ class API {
this.viaIR = config.viaIR;
this.usingSolcV4 = config.usingSolcV4;
+ this.irMinimum = config.irMinimum;
this.solcOptimizerDetails = config.solcOptimizerDetails;
this.setLoggingLevel(config.silent);
diff --git a/plugins/hardhat.plugin.js b/plugins/hardhat.plugin.js
index 9bb18fb4..d612eefa 100644
--- a/plugins/hardhat.plugin.js
+++ b/plugins/hardhat.plugin.js
@@ -15,6 +15,7 @@ const {
// Toggled true for `coverage` task only.
let measureCoverage = false;
let configureYulOptimizer = false;
+let irMinimum = false;
let instrumentedSources;
let optimizerDetails;
@@ -70,12 +71,22 @@ subtask(TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOB_FOR_FILE).setAction(async (_,
// Beginning with v0.8.7, we let the optimizer run if viaIR is true and
// instrument using `abi.encode(bytes8 covHash)`. Otherwise turn the optimizer off.
- if (!settings.viaIR) settings.optimizer.enabled = false;
-
- // This sometimes fixed a stack-too-deep bug in ABIEncoderV2 for coverage plugin versions up to 0.8.6
+ if (!settings.viaIR || irMinimum) settings.optimizer.enabled = false;
+
+ // Almost identical to foundry's irMinimum option - may improve performance for projects compiling with viaIR
+ // Original discussion at: https://github.com/ethereum/solidity/issues/12533#issuecomment-1013073350
+ if (irMinimum) {
+ settings.optimizer.details = {
+ yul: true,
+ yulDetails: {
+ stackAllocation: true,
+ optimizerSteps: "",
+ },
+ }
+ // LEGACY: This sometimes fixed a stack-too-deep bug in ABIEncoderV2 for coverage plugin versions up to 0.8.6
// Although issue should be fixed in 0.8.7, am leaving this option in because it may still be necessary
// to configure optimizer details in some cases.
- if (configureYulOptimizer) {
+ } else if (configureYulOptimizer) {
if (optimizerDetails === undefined) {
settings.optimizer.details = {
yul: true,
@@ -142,6 +153,7 @@ task("coverage", "Generates a code coverage report for tests")
api = new API(utils.loadSolcoverJS(config));
optimizerDetails = api.solcOptimizerDetails;
+ irMinimum = api.irMinimum;
// Catch interrupt signals
process.on("SIGINT", nomiclabsUtils.finish.bind(null, config, api, true));
diff --git a/test/integration/standard.js b/test/integration/standard.js
index a23b34e5..05a84945 100644
--- a/test/integration/standard.js
+++ b/test/integration/standard.js
@@ -380,6 +380,22 @@ describe('Hardhat Plugin: standard use cases', function() {
verify.lineCoverage(expected);
})
+ it('compiles with irMinimum setting', async function(){
+ mock.installFullProject('irMinimum');
+ mock.hardhatSetupEnv(this);
+
+ await this.env.run("coverage");
+
+ const expected = [
+ {
+ file: mock.pathToContract(hardhatConfig, 'IRMinimum.sol'),
+ pct: 100
+ }
+ ];
+
+ verify.lineCoverage(expected);
+ })
+
it('locates .coverage_contracts correctly when dir is subfolder', async function(){
mock.installFullProject('contract-subfolders');
mock.hardhatSetupEnv(this);
diff --git a/test/sources/projects/irMinimum/.solcover.js b/test/sources/projects/irMinimum/.solcover.js
new file mode 100644
index 00000000..886d7c2f
--- /dev/null
+++ b/test/sources/projects/irMinimum/.solcover.js
@@ -0,0 +1,5 @@
+module.exports = {
+ silent: process.env.SILENT ? true : false,
+ istanbulReporter: ['json-summary', 'text'],
+ irMinimum: true,
+}
diff --git a/test/sources/projects/irMinimum/contracts/IRMinimum.sol b/test/sources/projects/irMinimum/contracts/IRMinimum.sol
new file mode 100644
index 00000000..8da38223
--- /dev/null
+++ b/test/sources/projects/irMinimum/contracts/IRMinimum.sol
@@ -0,0 +1,26 @@
+pragma solidity >=0.8.0 <0.9.0;
+
+contract ContractA {
+ // 15 fn args + 1 local variable assignment
+ // will trigger stack too deep error when optimizer is off.
+ function stackTooDeep(
+ uint _a,
+ uint _b,
+ uint _c,
+ uint _d,
+ uint _e,
+ uint _f,
+ uint _g,
+ uint _h,
+ uint _i,
+ uint _j,
+ uint _k,
+ uint _l,
+ uint _m,
+ uint _n,
+ uint _o
+ ) public {
+ uint x = _a;
+ }
+}
+
diff --git a/test/sources/projects/irMinimum/hardhat.config.js b/test/sources/projects/irMinimum/hardhat.config.js
new file mode 100644
index 00000000..d570af45
--- /dev/null
+++ b/test/sources/projects/irMinimum/hardhat.config.js
@@ -0,0 +1,16 @@
+require("@nomiclabs/hardhat-truffle5");
+require(__dirname + "/../plugins/nomiclabs.plugin");
+
+module.exports = {
+ solidity: {
+ version: "0.8.28",
+ settings: {
+ optimizer: {
+ enabled: true
+ },
+ evmVersion: "cancun",
+ viaIR: true
+ }
+ },
+ logger: process.env.SILENT ? { log: () => {} } : console,
+};
diff --git a/test/sources/projects/irMinimum/test/test_irMinimum.js b/test/sources/projects/irMinimum/test/test_irMinimum.js
new file mode 100644
index 00000000..18e5860e
--- /dev/null
+++ b/test/sources/projects/irMinimum/test/test_irMinimum.js
@@ -0,0 +1,29 @@
+const ContractA = artifacts.require("ContractA");
+
+contract("contracta", function(accounts) {
+ let a,b;
+
+ before(async () => {
+ a = await ContractA.new();
+ })
+
+ it('a:stackTooDeep', async function(){
+ await a.stackTooDeep(
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15
+ );
+ })
+});