build(solidity): raise hardhat to 2.29, which Node 24 needs - #4204
Conversation
The last dependency step. smock capped this at 2.19.5 and is gone, so the
ceiling is lifted: hardhat 2.29 is the current 2.x line, and 2.26+ is what Node
24 requires -- below it, Hardhat's solc download fails on Node 24 with HH502,
because npm's undici and Node 24's bundled undici share a global-dispatcher
symbol.
Verified on both runtimes, both packages:
Node 22 Node 24
ecdsa 673 / 44 / 0 673 / 44 / 0
random-beacon 955 / 0 / 0 955 / 0 / 0
Identical to the pre-bump results, so nothing regressed and the PR is safe to
land before or after the Node bump in #4201.
Worth noting the wall clock, since it is the other thing 2.29 brings: the
random-beacon suite goes from 3m to 23s and ecdsa from 2m to 31s. That is EDR,
the Rust execution engine, backported into the 2.x line.
Two tests needed adjusting, both the same cause. `challengeDkgResult` has an
inline gas check, and two tests deliberately underfund the call to trigger it.
hardhat 2.29 defaults to a newer hardfork, where EIP-7623's intrinsic calldata
floor is enforced *before* execution:
ProviderError: Transaction requires gas floor of 161720 but got limit of 100000
so the node rejected the transaction outright and the contract's own check
never ran -- the tests passed for the wrong reason, or rather stopped testing
anything. The limits move to just above each floor (100000 -> 170000 and
200000 -> 220000), which keeps them far short of what the call needs to
complete, so both still revert inside the contract as intended.
The alternative was pinning the hardfork back to what 2.19.5 defaulted to.
Rejected: mainnet is past it, and running the suite against an older EVM than
production is a worse trade than adjusting two gas limits.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughHardhat is upgraded from 2.19.5 to 2.29.0 in two Solidity packages. Two ChangesHardhat gas-floor compatibility
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related issues
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The end of the chain, and the reason for it. Five workflows, two Dockerfiles and two `engines` fields go from Node 18.15.0 -- end of life since 2025-04-30 -- straight to 24.11.1, the current LTS, supported until 2028-04-30. This was not reachable before. Node 24 needs hardhat >= 2.26, because below it Hardhat's solc download fails with HH502: npm's undici and Node 24's bundled undici share a global-dispatcher symbol, so the download reaches Node's internal dispatcher, which rejects `maxRedirections`. hardhat >= 2.21 in turn broke @defi-wonderland/smock, and no smock version ever reached 2.26. The dependency was archived, so no version ever would. That is why #4203 removed it and #4204 raised hardhat before this commit could exist. The failure that started it, now passing on the same machine and the same runtime -- cold compiler cache, which is what a CI runner always has: before Error HH502: Couldn't download compiler versions list. after Compiled 75 Solidity files successfully Verified, whole suite, both packages, on Node 24.11.1: ecdsa 673 passing / 44 pending / 0 failing random-beacon 955 passing / 0 pending / 0 failing Docker base images are pinned to `node:24.11.1-alpine` rather than the floating `node:24-alpine`, matching the exact version CI pins, so the two runtimes cannot drift apart. This supersedes #4201, which moved the same nine files from 18 to 22 while 24 was still out of reach. If that lands first this needs a one-token rebase per site; if this chain lands, #4201 can be closed. BREAKING CHANGE: the solidity packages now require Node >= 24.0.0. Contributors on Node 18 or 20 will need to upgrade. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
piotr-roslaniec
left a comment
There was a problem hiding this comment.
Self-approve as repo admin. hardhat 2.19.5 -> 2.29.0 in both packages. 6 files, 664 +/- 2046. yarn.lock updates remove @chainsafe/* (replaced by @ethereumjs/*). Two test gas-limit adjustments (100000->170000, 200000->220000) explained in-line with EIP-7623 floor reasoning.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@solidity/ecdsa/test/WalletRegistry.WalletCreation.test.ts`:
- Around line 3018-3026: Update the comment above the challengeDkgResult call in
the gas-limit test to state that gasLimit 220000 clears Hardhat’s pre-execution
calldata floor and exercises the contract-level gas check; remove language
implying the test asserts rejection below that floor.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 1bb7817c-8f09-4bed-92fd-6b3fc5280a87
⛔ Files ignored due to path filters (2)
solidity/ecdsa/yarn.lockis excluded by!**/yarn.lock,!**/*.locksolidity/random-beacon/yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (4)
solidity/ecdsa/package.jsonsolidity/ecdsa/test/WalletRegistry.CustomErrors.test.tssolidity/ecdsa/test/WalletRegistry.WalletCreation.test.tssolidity/random-beacon/package.json
| // Above EIP-7623's intrinsic calldata floor, which hardhat | ||
| // 2.29 enforces before execution -- below it the node rejects | ||
| // the transaction outright and the contract's own gas check | ||
| // never runs, which is what this asserts on. Still far short of | ||
| // what `challengeDkgResult` needs to complete. | ||
| await expect( | ||
| walletRegistry | ||
| .connect(thirdParty) | ||
| .challengeDkgResult(dkgResult, { gasLimit: 200000 }) | ||
| .challengeDkgResult(dkgResult, { gasLimit: 220000 }) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate file =="
fd -a 'WalletRegistry.WalletCreation.test.ts' . || true
echo "== relevant lines =="
FILE="$(fd 'WalletRegistry.WalletCreation.test.ts' . | head -n 1)"
if [ -n "${FILE:-}" ]; then
wc -l "$FILE"
sed -n '2980,3055p' "$FILE" | cat -n | sed 's/^/ /'
fi
echo "== nearby expect assertions =="
rg -n "challengeDkgResult|gasLimit: 220000|EIP-7623|intrinsic calldata floor|below it|contract's own gas check" "$FILE" || true
echo "== repo version/config hints =="
for f in package.json pnpm-lock.yaml yarn.lock package-lock.json hardhat.config.* tsconfig.json; do
[ -f "$f" ] && printf '\n-- %s --\n' "$f" && sed -n '1,220p' "$f" | rg -n '"hardhat"|"hardhat-ethers"|2\.29|hardhat-ethers|hardhat-verify|gasReporter|gasLimit' -C 2 || true
doneRepository: threshold-network/keep-core
Length of output: 6585
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== hardhat deps across tracked files =="
rg -n '"hardhat"|"hardhat-ethers"|hardhat-version|gasLimit' --glob '!node_modules' --glob '!dist' --glob '!build' . | head -n 200 || true
echo "== package manifests =="
git ls-files '*package.json' | while read -r f; do
echo "-- $f --"
sed -n '1,240p' "$f" | jq -r '
["dependencies","devDependencies","peerDependencies"][] // empty
as $section
| ("[" + $section + "]: " + (.[$section] | tostring))
' 2>/dev/null | rg "hardhat|hardhat-ethers" || true
done
echo "== hardhat config gas settings =="
git ls-files 'hardhat.config.*' | while read -r f; do
echo "-- $f --"
sed -n '1,260p' "$f" | rg -n "gasLimit|hardhat|evmVersion|fork|mempool|gasMultiplier|gasPrice|maxFee|gas" -C 3 || true
doneRepository: threshold-network/keep-core
Length of output: 50384
🌐 Web query:
Hardhat 2.29 EIP-7623 intrinsic calldata floor gasMinimum documentation
💡 Result:
As of July 27, 2026, Hardhat v2.29.0 does not contain specific implementation logic or documentation regarding the intrinsic calldata floor gas requirement introduced by EIP-7623 [1][2]. The v2.29.0 release was a minor update focused on Mocha compatibility and TypeScript initialization [1]. EIP-7623: Increase calldata cost is an Ethereum standard that mandates a change in how transaction gas is calculated, specifically by introducing a minimum gas floor for data-heavy transactions [3][4]. Under this EIP, transactions that do not exceed a certain threshold of gas spent on EVM operations relative to gas spent on calldata are subject to an increased calldata cost (10/40 gas per byte) [3][4]. This ensures that data-heavy transactions contribute more appropriately to the network's gas usage, effectively reducing the maximum block size [3][4]. While node software and core development libraries (such as Geth) have moved to implement this logic [5], Hardhat's core package (v2.29.0) does not explicitly detail support for this intrinsic gas floor in its release notes or documentation [1][6][7]. Users relying on Hardhat for testing environments that require EIP-7623 compliance should monitor ongoing updates to Hardhat's Ethereum Development Runtime (EDR) or subsequent Hardhat versions, as EIP support in Hardhat is typically rolled out through these components [6][7][8].
Citations:
- 1: https://newreleases.io/project/github/NomicFoundation/hardhat/release/hardhat@2.29.0
- 2: chore(deps-dev): bump hardhat from 2.28.6 to 2.29.0 RigoBlock/v3-contracts#936
- 3: https://eips.ethereum.org/EIPS/eip-7623
- 4: https://raw.githubusercontent.com/ethereum/EIPs/master/EIPS/eip-7623.md
- 5: covalenthq/bsp-geth@0e1a19d
- 6: https://github.com/NomicFoundation/hardhat/releases
- 7: https://github.com/NomicFoundation/hardhat/blob/main/packages/hardhat/CHANGELOG.md
- 8: Support gas snapshots for Solidity tests NomicFoundation/hardhat#7769
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== tracked package manifests =="
git ls-files '*package.json' | sed -n '1,120p'
echo "== hardhat dependency lines in tracked manifests only =="
git ls-files '*package.json' \
| xargs -r rg -n '"hardhat"|"hardhat-ethers"|`@nomicfoundation/hardhat-network`'| head -n 200 || true
echo "== package-manager/config lock summary =="
for f in package-lock.json pnpm-lock.yaml yarn.lock bun.lockb bun.lock README.md; do
[ -e "$f" ] && printf '\n-- %s --\n' "$f" && sed -n '1,180p' "$f" | rg -n 'hardhat|hardhat-ethers|`@nomicfoundation/hardhat-network`|lockfileVersion|packageManager' -C 2 || true
done
echo "== test gas-limit comments context nearby =="
sed -n '3008,3032p' solidity/ecdsa/test/WalletRegistry.WalletCreation.test.ts | cat -nRepository: threshold-network/keep-core
Length of output: 1909
Clarify which gas-failure path this test covers.
gasLimit: 220000 clears the pre-execution gas minimum, so this test is meant to exercise the contract-level challengeDkgResult gas check, not the Hardhat rejection for transactions below that minimum. Update the comment to avoid describing the below-floor rejection as the behavior under test.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@solidity/ecdsa/test/WalletRegistry.WalletCreation.test.ts` around lines 3018
- 3026, Update the comment above the challengeDkgResult call in the gas-limit
test to state that gasLimit 220000 clears Hardhat’s pre-execution calldata floor
and exercises the contract-level gas check; remove language implying the test
asserts rejection below that floor.
Stacked on #4203. The last dependency step: hardhat 2.19.5 → 2.29.0 in
both packages.
smock capped this at 2.19.5. It is gone as of #4203, so the ceiling lifts —
and 2.26+ is what Node 24 requires. Below it, Hardhat's solc download fails on
Node 24 with
HH502, because npm's undici and Node 24's bundled undici share aglobal-dispatcher symbol.
Verified
Whole suite, both packages, both runtimes:
ecdsarandom-beaconIdentical to the pre-bump results, so nothing regressed — and it is safe to
land before or after the Node bump in #4201, in either order.
The other thing 2.29 brings
random-beaconecdsaThat is EDR, the Rust execution engine, backported into the 2.x line.
Two tests needed adjusting
challengeDkgResulthas an inline gas check, and two tests deliberatelyunderfund the call to trigger it. hardhat 2.29 defaults to a newer hardfork,
where EIP-7623's intrinsic calldata floor is enforced before execution:
The node rejected the transaction outright, so the contract's own check never
ran — the tests had stopped testing the thing they name. The limits move to
just above each floor (
100000 → 170000,200000 → 220000), still far shortof what the call needs to complete, so both revert inside the contract as
intended.
The alternative was pinning the hardfork back to 2.19.5's default. Rejected:
mainnet is past it, and running the suite against an older EVM than production
is a worse trade than adjusting two gas limits.
After this
Node 22 → 24 in the five workflows, two Dockerfiles and two
enginesfields —a small follow-up, and the reason the whole chain existed. #4201 already moved
those from 18 to 22; this makes 24 reachable for the first time.
Summary by CodeRabbit
Chores
Tests