Unit
LibRainDeploy.supportedNetworks() and the [rpc_endpoints] / [etherscan]
sections of foundry.toml, in this repo and in every consumer that inherits
BuildScript.
Intent oracle
RainDeployVerifySnapshot's NatSpec: the config sections "MUST be EXACTLY
supportedNetworks(), which makes the three lists one". The roster is a claim
this dependency makes, and three things read it —
RainDeployBroadcast for which chains to deploy to, RainDeployVerifySnapshot
for the config to match, RainDeployVerifyChain for which chains to check.
Violated property
The lists are stated by hand in four places and derived from nothing:
supportedNetworks() in src/lib/LibRainDeploy.sol
[rpc_endpoints] in foundry.toml
[etherscan] in foundry.toml, which also carries the only statement of
each chain id
.env.example
Every consumer repo carries its own copy of the last three. Nothing generates
any of them, so agreement is maintained by a test that compares them, and the
prose describing them drifts silently — #198 found "seven networks" against a
roster of nine, and #192 found an [etherscan] entry that satisfies every
assertion while verifying nothing.
Proposed shape
The Solidity roster stays the single source. BuildScript gains a hook that
emits both config sections, and .env.example, from
LibRainDeploy.supportedNetworks() — delimited so hand-written config around
them survives. Consumers inherit the hook and regenerate from the dependency's
constant, so a bump is how a network arrives everywhere.
Git is clean then fails any tree, here or downstream, whose config has drifted
from the roster it pins. That is the enforcement mechanism already holding
src/generated/ and src/lib/.
The direction matters: deriving the roster FROM the config instead would let a
consumer delete an alias and silently deploy to and verify fewer chains, green,
because the thing that would notice is reading the same file.
What this removes
The membership assertions in RainDeployVerifySnapshotBase have nothing left to
compare once both sides come from one list.
What still needs asserting
What generation cannot settle: that each declared chain id is the one the bound
endpoint reports. That is a fork test against block.chainid, with a real
subject.
Requirements
fs_permissions on ./foundry.toml moves from read to read-write, here and
in each consumer.
- The hook runs in
run(), a script. foundry.toml is read at forge startup
and not re-read, so writing it mid-run is safe — but any test that reads it
concurrently races the write, the way the src/lib readers do. The test that
reads it is the one this removes.
BuildScript has never emitted anything but Solidity.
Unit
LibRainDeploy.supportedNetworks()and the[rpc_endpoints]/[etherscan]sections of
foundry.toml, in this repo and in every consumer that inheritsBuildScript.Intent oracle
RainDeployVerifySnapshot's NatSpec: the config sections "MUST be EXACTLYsupportedNetworks(), which makes the three lists one". The roster is a claimthis dependency makes, and three things read it —
RainDeployBroadcastfor which chains to deploy to,RainDeployVerifySnapshotfor the config to match,
RainDeployVerifyChainfor which chains to check.Violated property
The lists are stated by hand in four places and derived from nothing:
supportedNetworks()insrc/lib/LibRainDeploy.sol[rpc_endpoints]infoundry.toml[etherscan]infoundry.toml, which also carries the only statement ofeach chain id
.env.exampleEvery consumer repo carries its own copy of the last three. Nothing generates
any of them, so agreement is maintained by a test that compares them, and the
prose describing them drifts silently — #198 found "seven networks" against a
roster of nine, and #192 found an
[etherscan]entry that satisfies everyassertion while verifying nothing.
Proposed shape
The Solidity roster stays the single source.
BuildScriptgains a hook thatemits both config sections, and
.env.example, fromLibRainDeploy.supportedNetworks()— delimited so hand-written config aroundthem survives. Consumers inherit the hook and regenerate from the dependency's
constant, so a bump is how a network arrives everywhere.
Git is cleanthen fails any tree, here or downstream, whose config has driftedfrom the roster it pins. That is the enforcement mechanism already holding
src/generated/andsrc/lib/.The direction matters: deriving the roster FROM the config instead would let a
consumer delete an alias and silently deploy to and verify fewer chains, green,
because the thing that would notice is reading the same file.
What this removes
The membership assertions in
RainDeployVerifySnapshotBasehave nothing left tocompare once both sides come from one list.
What still needs asserting
What generation cannot settle: that each declared chain id is the one the bound
endpoint reports. That is a fork test against
block.chainid, with a realsubject.
Requirements
fs_permissionson./foundry.tomlmoves from read to read-write, here andin each consumer.
run(), a script.foundry.tomlis read at forge startupand not re-read, so writing it mid-run is safe — but any test that reads it
concurrently races the write, the way the
src/libreaders do. The test thatreads it is the one this removes.
BuildScripthas never emitted anything but Solidity.