Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
dce7149
add verbosity for all hh tasks
ChristopherDedominici Feb 20, 2026
8e194d0
Create cyan-drinks-beg.md
ChristopherDedominici Feb 20, 2026
05bd623
set verbosity to have max logs from level 4
ChristopherDedominici Feb 24, 2026
18eb2f9
Merge branch 'edr-upgrade-25' of github.com:NomicFoundation/hardhat i…
ChristopherDedominici Feb 24, 2026
722cb9b
minor improvements
ChristopherDedominici Feb 24, 2026
71b8f0b
fix failing tests
ChristopherDedominici Feb 24, 2026
6d8c8a2
Merge branch 'main' of github.com:NomicFoundation/hardhat into edr-up…
ChristopherDedominici Feb 26, 2026
3f78af7
Merge branch 'main' of github.com:NomicFoundation/hardhat into edr-up…
ChristopherDedominici Mar 2, 2026
593a016
Merge branch 'main' of github.com:NomicFoundation/hardhat into edr-up…
ChristopherDedominici Mar 12, 2026
c917a3c
Merge branch 'main' of github.com:NomicFoundation/hardhat into edr-up…
ChristopherDedominici Mar 16, 2026
564d509
Merge branch 'main' of github.com:NomicFoundation/hardhat into edr-up…
ChristopherDedominici Mar 30, 2026
1141434
Merge branch 'edr-upgrade-25' of github.com:NomicFoundation/hardhat i…
ChristopherDedominici Mar 30, 2026
273318b
fix building error after merge
ChristopherDedominici Mar 30, 2026
7a9a64c
update changeset
ChristopherDedominici Mar 30, 2026
96b785c
Verbosity (-vvv) improve style (#8031)
ChristopherDedominici Mar 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/cyan-drinks-beg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@nomicfoundation/hardhat-utils": patch
"hardhat": patch
---

Added `--verbosity` (and `-v`, `-vv`, and the other shorthands) to all tasks, including TypeScript tests ([7983](https://github.com/NomicFoundation/hardhat/pull/7983)), ([7963](https://github.com/NomicFoundation/hardhat/issues/7963)).
93 changes: 93 additions & 0 deletions v-next/example-project/contracts/CallTypes.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "hardhat/console.sol";

/// @notice Demonstrates different EVM call types for trace output testing.
/// Used by scripts/demo-call-types.ts to exercise [CALL], [CREATE],
/// [STATICCALL], [DELEGATECALL], and [EVENT] trace tags.

/// @notice Helper contract with view and write functions
contract Logic {
event ValueSet(address indexed setter, uint256 value);

uint256 public value;

function setValue(uint256 _value) external {
console.log("Logic.setValue:", _value);
value = _value;
emit ValueSet(msg.sender, _value);
}

function getValue() external view returns (uint256) {
return value;
}

function pureAdd(uint256 a, uint256 b) external pure returns (uint256) {
return a + b;
}

function mustBePositive(uint256 _value) external {
require(_value > 0, "Value must be positive");
console.log("Logic.mustBePositive:", _value);
value = _value;
emit ValueSet(msg.sender, _value);
}
}

/// @notice Orchestrator that calls Logic, exercising multiple call types
contract Orchestrator {
event Orchestrated(uint256 result);

Logic public logic;

constructor(Logic _logic) {
logic = _logic;
}

/// @notice Regular external CALL to Logic.setValue
function doCall(uint256 _value) external {
logic.setValue(_value);
}

/// @notice Calls Logic.mustBePositive — reverts when _value == 0
function doCallThatReverts(uint256 _value) external {
logic.mustBePositive(_value);
}

/// @notice External view call to Logic → produces STATICCALL
function doStaticCall() external view returns (uint256) {
return logic.getValue();
}

/// @notice Explicit delegatecall to Logic.setValue → produces DELEGATECALL trace
function doDelegateCall(uint256 _value) external returns (bool success) {
bytes memory data = abi.encodeWithSelector(Logic.setValue.selector, _value);
(success, ) = address(logic).delegatecall(data);
}

/// @notice Mixed: DELEGATECALL + CALL (Logic.setValue) + STATICCALL (Logic.getValue)
function doAllCallTypes(uint256 a, uint256 b) external returns (uint256) {
// DELEGATECALL to Logic.pureAdd (uses pureAdd to avoid storage collision)
bytes memory data = abi.encodeWithSelector(Logic.pureAdd.selector, a, b);
address(logic).delegatecall(data);
// CALL to Logic.setValue
logic.setValue(a + b);
// STATICCALL to Logic.getValue
uint256 readBack = logic.getValue();
emit Orchestrated(readBack);
return readBack;
}
}

/// @notice Factory that creates contracts in a single transaction
contract CallTypesFactory {
event ContractsDeployed(address indexed logic, address indexed orchestrator);

function deploy() external returns (address, address) {
Logic logicContract = new Logic();
Orchestrator orch = new Orchestrator(logicContract);
emit ContractsDeployed(address(logicContract), address(orch));
return (address(logicContract), address(orch));
}
}
178 changes: 178 additions & 0 deletions v-next/example-project/scripts/demo-trace-output.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/**
* Comprehensive demo of all trace output features.
*
* Run with dedup (normal):
* pnpm hardhat run scripts/demo-trace-output.ts -vvvv
*
* Run without dedup (all traces):
* pnpm hardhat run scripts/demo-trace-output.ts -vvvvv
*
* For ANSI color output (red headers on failure, dim on success):
* FORCE_COLOR=3 pnpm hardhat run scripts/demo-trace-output.ts -vvvv
*
* What to look for:
* - All call kinds: CALL, CREATE, STATICCALL, DELEGATECALL
* - Connection labels: "Trace from connection #0 (default)", "#1 (node)"
* - -vvvv: dedup active — single counter.write.inc() → 1 trace (not 3)
* - -vvvvv: no dedup — estimateGas + sendTx both shown per write
* - Red header on failed RPC, dim on success
* - Batch-mined txs grouped under 1 "Traces from" header
*/
import hre from "hardhat";

// ═══════════════════════════════════════════════════════════════════════
// Setup: two connections to two independent EDR-simulated networks
// ═══════════════════════════════════════════════════════════════════════
const connA = await hre.network.connect("default");
const connB = await hre.network.connect("node");

const [counterA, counterB, revertContract] = await Promise.all([
connA.viem.deployContract("Counter", []),
connB.viem.deployContract("Counter", []),
connA.viem.deployContract("Revert", []),
]);

const logic = await connA.viem.deployContract("Logic", []);
const orchestrator = await connA.viem.deployContract("Orchestrator", [
logic.address,
]);
const factory = await connA.viem.deployContract("CallTypesFactory", []);

// ═══════════════════════════════════════════════════════════════════════
// 1. All call kinds — CALL, CREATE, STATICCALL, DELEGATECALL, events
// ═══════════════════════════════════════════════════════════════════════
console.log("\n╔══════════════════════════════════════════════════════╗");
console.log("║ 1 — All call kinds ║");
console.log("╚══════════════════════════════════════════════════════╝\n");

// CALL + event: Orchestrator → Logic.setValue (external CALL, emits ValueSet)
console.log(" 1a. CALL + event: Orchestrator.doCall(42)\n");
await orchestrator.write.doCall([42n]);

// STATICCALL: Orchestrator → Logic.getValue (view → STATICCALL)
console.log("\n 1b. STATICCALL: Orchestrator.doStaticCall()\n");
await orchestrator.read.doStaticCall();

// CREATE: deploy new contracts inline (via CallTypesFactory)
console.log("\n 1c. CREATE: CallTypesFactory.deploy()\n");
await factory.write.deploy();

// Mixed: DELEGATECALL + CALL + STATICCALL + event in one transaction
console.log(
"\n 1d. Mixed (all types in 1 tx): Orchestrator.doAllCallTypes(7, 3)\n",
);
await orchestrator.write.doAllCallTypes([7n, 3n]);

// DELEGATECALL: Orchestrator → Logic.setValue via delegatecall
// NOTE: This must come last — delegatecall overwrites Orchestrator's storage
// (slot 0 = logic address), making subsequent calls to logic.* fail.
console.log("\n 1e. DELEGATECALL: Orchestrator.doDelegateCall(42)\n");
await orchestrator.write.doDelegateCall([42n]);

// ═══════════════════════════════════════════════════════════════════════
// 2. Multi-connection — sequential txs on two networks
// Headers should show different connection labels / colors
// ═══════════════════════════════════════════════════════════════════════
console.log("\n╔══════════════════════════════════════════════════════╗");
console.log("║ 2 — Multi-connection, sequential ║");
console.log("╚══════════════════════════════════════════════════════╝\n");

await counterA.write.inc();
await counterB.write.inc();

// ═══════════════════════════════════════════════════════════════════════
// 3. Multi-connection — concurrent txs on both networks
// Traces from each connection are atomic (no interleaving)
// ═══════════════════════════════════════════════════════════════════════
console.log("\n╔══════════════════════════════════════════════════════╗");
console.log("║ 3 — Multi-connection, concurrent (3 txs each) ║");
console.log("╚══════════════════════════════════════════════════════╝\n");

await Promise.all([
counterA.write.inc(),
counterA.write.inc(),
counterA.write.inc(),
counterB.write.inc(),
counterB.write.inc(),
counterB.write.inc(),
]);

// ═══════════════════════════════════════════════════════════════════════
// 4. Batch mining with evm_mine — grouped traces under a single header
// "Traces from connection #N (network): evm_mine" (plural)
// ═══════════════════════════════════════════════════════════════════════
console.log("\n╔══════════════════════════════════════════════════════╗");
console.log("║ 4 — evm_mine: 5 txs in one block (grouping demo) ║");
console.log("╚══════════════════════════════════════════════════════╝\n");
console.log(' → expect 1 "Traces from" header + 5 traces below it\n');

await connA.provider.request({ method: "evm_setAutomine", params: [false] });
await Promise.all(Array.from({ length: 5 }, () => counterA.write.inc()));
await connA.provider.request({ method: "evm_mine", params: [] });
await connA.provider.request({ method: "evm_setAutomine", params: [true] });

// ═══════════════════════════════════════════════════════════════════════
// 5. Failed RPC calls — header should be red, method name highlighted
// ═══════════════════════════════════════════════════════════════════════
console.log("\n╔══════════════════════════════════════════════════════╗");
console.log("║ 5 — Failing calls (red header / method name) ║");
console.log("╚══════════════════════════════════════════════════════╝\n");

// 5a. Revert contract with known error message
console.log(" 5a. Revert.boom() — reverts with 'Boom':\n");
try {
await revertContract.read.boom();
} catch (e: any) {
console.log(` → Reverted: ${e.details ?? e.message}\n`);
}

// 5b. Invalid selector on Counter (no fallback)
console.log(" 5b. Invalid selector 0xdeadbeef on Counter:\n");
try {
await connA.provider.request({
method: "eth_call",
params: [{ to: counterA.address, data: "0xdeadbeef" }, "latest"],
});
} catch {
console.log(" → Reverted as expected\n");
}

// 5c. Orchestrator.doCallThatReverts(0) — nested revert
// Deploy fresh orchestrator since the earlier doDelegateCall corrupted storage
console.log(" 5c. Orchestrator.doCallThatReverts(0) — nested revert:\n");
const logic2 = await connA.viem.deployContract("Logic", []);
const orch2 = await connA.viem.deployContract("Orchestrator", [logic2.address]);
try {
await orch2.write.doCallThatReverts([0n]);
} catch (e: any) {
console.log(` → Reverted: ${e.details ?? e.message}\n`);
}

// ═══════════════════════════════════════════════════════════════════════
// 6. Deduplication — single write triggers estimateGas + sendTx + receipt
// but only ONE trace should appear
// ═══════════════════════════════════════════════════════════════════════
console.log("\n╔══════════════════════════════════════════════════════╗");
console.log("║ 6 — Deduplication ║");
console.log("╚══════════════════════════════════════════════════════╝\n");
console.log(" A single counter.write.inc() triggers 3 RPC calls:");
console.log(" 1. eth_estimateGas → suppressed at -vvvv, shown at -vvvvv");
console.log(" 2. eth_sendTransaction → always shown (this is the real tx)");
console.log(" 3. eth_getTransactionReceipt → no traces (read-only)");
console.log(
" At -vvvv: 1 trace. At -vvvvv: 2 traces (estimateGas + sendTx).\n",
);

await counterA.write.inc();

// ═══════════════════════════════════════════════════════════════════════
// Summary
// ═══════════════════════════════════════════════════════════════════════
console.log("\n╔══════════════════════════════════════════════════════╗");
console.log("║ Summary ║");
console.log("╚══════════════════════════════════════════════════════╝");
console.log("");
console.log(" -vvvv: dedup + suppression active (1 trace per write)");
console.log(" -vvvvv: no dedup (estimateGas + sendTx both shown)");
console.log("");
console.log("Done.");
2 changes: 1 addition & 1 deletion v-next/hardhat-utils/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { camelToSnakeCase } from "./string.js";
* with each option adhering to its definition in the globalOptionDefinitions.
*/
export function setGlobalOptionsAsEnvVariables<
T extends Record<keyof T, string | boolean | undefined>,
T extends Record<keyof T, string | boolean | number | undefined>,
>(globalOptions: T): void {
for (const [name, value] of Object.entries(globalOptions)) {
const envName = getEnvVariableNameFromGlobalOption(name);
Expand Down
16 changes: 15 additions & 1 deletion v-next/hardhat/src/internal/builtin-global-options.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { GlobalOptionDefinitions } from "../types/global-options.js";

import { globalFlag, globalOption } from "../config.js";
import { globalFlag, globalLevel, globalOption } from "../config.js";
import { ArgumentType } from "../types/arguments.js";

import { DEFAULT_VERBOSITY } from "./constants.js";

export const BUILTIN_GLOBAL_OPTIONS_DEFINITIONS: GlobalOptionDefinitions =
new Map([
[
Expand Down Expand Up @@ -49,6 +51,18 @@ export const BUILTIN_GLOBAL_OPTIONS_DEFINITIONS: GlobalOptionDefinitions =
}),
},
],
[
"verbosity",
{
pluginId: "builtin",
option: globalLevel({
name: "verbosity",
shortName: "v",
description: "Verbosity level of the output.",
defaultValue: DEFAULT_VERBOSITY,
}),
},
],
[
"version",
{
Expand Down
Loading
Loading