Move foundry's compiler settings back under [profile.default] - #38
Conversation
TOML assigns a key to the header above it. `solc`, `evm_version`, `optimizer`, `optimizer_runs`, `bytecode_hash` and `cbor_metadata` sat below `[soldeer]`, so they were soldeer config and forge fell back to its own defaults for all six. All of foundry's headers now precede `[dependencies]` and `[soldeer]`, so no foundry key can be captured by a soldeer header. `[fuzz]` moves with them; it was already being read, since foundry accepts it at the root wherever it sits. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan includes up to 1 review per rolling hour; 0 remain after this review. WalkthroughChangesFoundry configuration
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to This is a localized compiler-configuration correction in foundry.toml, with the declared settings restored and validation reported for configuration output and tests. No actionable merge-blocking risk remains beyond normal checks and review. Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 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 |
Closes #37.
TOML assigns every key to the header above it. Since the soldeer migration
(73a6669, 2026-05-09) inserted
[dependencies]and[soldeer]between[profile.default]and the rest of the file,solc,evm_version,optimizer,optimizer_runs,bytecode_hashandcbor_metadatahave beensoldeer config, and forge has used its own defaults for all six.
This moves every foundry header above
[dependencies]and[soldeer], so nofoundry key can be captured by a soldeer header.
[fuzz]moves with them: itwas already being read (foundry accepts it at the root wherever it sits), but
leaving it below
[soldeer]would leave the same shape in the file for thenext key to be appended into.
forge config, before and afternix develop -c forge config, onmainand on this branch:mainsolcauto_detect_solc = true)"0.8.25"0.8.25evm_version"osaka""cancun"cancunoptimizerfalsetruetrueoptimizer_runs20010000001000000bytecode_hash"ipfs""none"nonecbor_metadatatruefalsefalse[fuzz] runs204820482048Every key now reports the file's value. Forge emits no unknown-section warning
either way, which is why this was silent.
What actually moves in the bytecode
Both configs built from an empty
out/cachewithforge build --forceonthe same toolchain.
Two of the six settings turn out to have been inert but harmless. The old
build's artifact metadata reads
solc 0.8.25+commit.b61c2a91andevmVersion: cancun—auto_detect_solcresolved to 0.8.25 because the testpins
pragma solidity =0.8.25, and foundry clamps the EVM version down to thenewest one the selected solc supports, which for 0.8.25 is cancun. The
osakathat
forge configreported never reached the compiler.What did move is the optimizer and the metadata — old
optimizer {enabled: false, runs: 200},bytecodeHash: ipfs; new{enabled: true, runs: 1000000},bytecodeHash: none:mainmainLibCtPopLibCtPopTestLibCtPop's deployed artifact is only the non-callable library stub — bothits functions are
internal— so most of its 86 bytes were the IPFS metadatahash that
bytecode_hash = "none"was meant to suppress.Nothing in the repo pins bytecode, and the gas snapshot is already correct
src/is oneinternal-only library, there is noscript/, and there is noaddress, code hash or CREATE2 salt constant anywhere in the tree. Nothing needs
regenerating on that count.
.gas-snapshotdoes not need regenerating either, because it was written underthe settings this branch restores.
forge snapshothere reproduces thecommitted numbers exactly for all six tests the file contains:
(
testCtPopShuffledis a fuzz mean; 144,902 vs 144,925 is input noise, not acode change.)
It is separately stale in one respect that predates and outlives this PR:
testCtPopLoneHighBitandtestMaskConstantsRederived, added in 5846438 on2026-07-18, were never snapped. Nothing in CI reads the file —
rainix-sol-testruns
forge testonly — so it has been drifting unchecked. Left alone hererather than folded into a compiler-settings change.
Consumers of the published package are unaffected
Soldeer publishes source, not artifacts.
.soldeerignoreexcludes/out,/foundry.toml,/cache,/dependenciesand/test, so a published revisionis
src/**plus README and LICENSES.LibCtPop's two functions are bothinternal, so they are inlined into the consumer's own compilation unit andcompiled entirely under the consumer's settings. No published revision has ever
carried this repo's compiler settings or any bytecode built from them, so there
is nothing for a consumer to re-pull or re-verify. (#37 says every published
revision was compiled unoptimised; that is not what a Soldeer revision
contains. Corrected on the issue.)
What the defect did cost
This repo's own build and CI ran unoptimised, at
optimizer_runs = 200, withan IPFS metadata hash in every artifact — so builds were not byte-reproducible
across machines, which is exactly what
bytecode_hash = "none"andcbor_metadata = falsewere there to guarantee. The EVM version was right byaccident, and the source is plain arithmetic with no assembly and no
cancun-only opcode, so no test was exercising the wrong instruction set.
Sibling sweep
#37 asks for a sweep. Every
foundry.tomlon the default branch of all 186non-archived repos across rainlanguage, cyclofinance, S01-Issuer,
ST0x-Technology and gildlab — 54 files, 48 at a repo root plus 6 nested (rainix's CI fixture,
rain.subgraph.docker's example, and four in the
foundry/pyth-crosschainupstream forks) — checked for a foundry profile key sitting under a
[dependencies],[soldeer]or[external.*]header.rain.math.binaryis the only one. Nothing filed for the others.QA
from inside the EVM, so the discriminating check is the one foundry.toml compiler settings sit inside [soldeer], so forge ignores every one of them #37 names —
nix develop -c forge config, run ona47d3e7(base) and on this branch.All six keys report foundry defaults on base and the file's values here; the
table above is that output.
forge testpasses 8/8 under the new settings.directions and observed.
foundry.toml(base) ->foundry.toml(branch),each built from an empty
out/cachewithforge build --force: artifactmetadata moves
optimizer {enabled: false, runs: 200}->{enabled: true, runs: 1000000}andbytecodeHash: ipfs->none;LibCtPopruntime86 B -> 32 B,
LibCtPopTestruntime 8429 B -> 7294 B; gas moves as tabulated(e.g.
testCtPopShuffled302,573 -> 144,925). Reverting the section moverestores every base value, so the change is load-bearing and nothing else in
the tree is producing the effect.
foundry.toml's own declared values, which are independent of whatforge was doing — the file states
0.8.25,cancun,optimizer = true,optimizer_runs = 1000000,bytecode_hash = "none",cbor_metadata = false,and
forge configmust report exactly those. The.gas-snapshotcommitted inJanuary, generated before 73a6669 broke the ordering, is a second independent
oracle: this branch reproduces its numbers,
maindoes not.[profile.default],(b)
forge configverified for all six named keys, (c) a sibling sweep.Covered a, b, c. The sweep is report-only per the issue's "worth sweeping"
framing;
rain.math.binarywas the only hit, so nothing was filed.