rainlanguage/rain.math.float#198 introduced a generic pattern for keeping rust crates compilable from a checkout when their alloy::sol! macro depends on forge artifacts:
script/CopyArtifacts.sol: forge script that uses vm.ffi + jq to extract a stable subset of the forge JSON (abi, bytecode.object, deployedBytecode.object) and write to a committed location.
script/lib/LibCopyArtifacts.sol: shared library carrying contract list, paths, and the jq extraction logic.
test/script/CopyArtifacts.t.sol: forge test asserting committed copies match the live build (runs in rainix-sol-test).
.github/workflows/copy-artifacts.yaml: CI workflow doing forge soldeer install + forge build + forge script script/CopyArtifacts.sol + git diff --exit-code (mirror of build-pointers).
- Committed artifacts under (in float's case)
crates/float/abi/.
Why it matters: lets the rust crate compile via rust-shell without the foundry toolchain entering the rs-static / rs-test / rs-wasm cache. Concrete CI win measured in rainlanguage/rain.math.float#199 — ~5–6m → ~3m20s on the rs-static gate, plus zero foundry/solc bytes carried in the rust-shell nix cache.
The workflow shape and the jq filter are generic; the contract list and committed path are consumer-specific. Possible upstreaming approaches:
- Reusable workflow
rainix-copy-artifacts.yaml hardcoded to ./script/CopyArtifacts.sol — symmetric with rainix-build-pointers.yaml. Consumer ships script/CopyArtifacts.sol and script/lib/LibCopyArtifacts.sol.
- Generalize
rainix-build-pointers.yaml to run any script/Build*.sol or script/Copy*.sol it finds. Avoids two near-identical reusables but couples them.
- Keep workflow per-consumer; upstream
LibCopyArtifacts.sol to a shared rain.* soldeer package. Consumers import it and write a thin wrapper script with their contract list.
(1) is the most consistent with existing rainix shape. (3) is the most reusable but adds a soldeer-dep on rainix-side library code.
Currently only rain.math.float needs this. If/when a second consumer surfaces, the upstream design becomes worth doing.
rainlanguage/rain.math.float#198 introduced a generic pattern for keeping rust crates compilable from a checkout when their
alloy::sol!macro depends on forge artifacts:script/CopyArtifacts.sol: forge script that usesvm.ffi+jqto extract a stable subset of the forge JSON (abi,bytecode.object,deployedBytecode.object) and write to a committed location.script/lib/LibCopyArtifacts.sol: shared library carrying contract list, paths, and the jq extraction logic.test/script/CopyArtifacts.t.sol: forge test asserting committed copies match the live build (runs inrainix-sol-test)..github/workflows/copy-artifacts.yaml: CI workflow doingforge soldeer install+forge build+forge script script/CopyArtifacts.sol+git diff --exit-code(mirror of build-pointers).crates/float/abi/.Why it matters: lets the rust crate compile via
rust-shellwithout the foundry toolchain entering the rs-static / rs-test / rs-wasm cache. Concrete CI win measured in rainlanguage/rain.math.float#199 — ~5–6m → ~3m20s on the rs-static gate, plus zero foundry/solc bytes carried in the rust-shell nix cache.The workflow shape and the jq filter are generic; the contract list and committed path are consumer-specific. Possible upstreaming approaches:
rainix-copy-artifacts.yamlhardcoded to./script/CopyArtifacts.sol— symmetric withrainix-build-pointers.yaml. Consumer shipsscript/CopyArtifacts.solandscript/lib/LibCopyArtifacts.sol.rainix-build-pointers.yamlto run anyscript/Build*.solorscript/Copy*.solit finds. Avoids two near-identical reusables but couples them.LibCopyArtifacts.solto a shared rain.* soldeer package. Consumers import it and write a thin wrapper script with their contract list.(1) is the most consistent with existing rainix shape. (3) is the most reusable but adds a soldeer-dep on rainix-side library code.
Currently only rain.math.float needs this. If/when a second consumer surfaces, the upstream design becomes worth doing.