Skip to content

Switch from Nix-derivation ABI to committed JSON artifacts for rust crate #199

@thedavidmeister

Description

@thedavidmeister

Context

The rust crate (crates/float) reads forge ABI JSON via alloy::sol! to generate types. Two designs exist:

  1. Nix-derivation / env-var (introduced in 816a579 by @0xgleb, "feat: provide json abi as flake output"). alloy::sol! reads env!("RAIN_MATH_FLOAT_DECIMAL_FLOAT_ABI"). The default devShell shellHook exports the env var pointing at $PWD/out/.... A decimal-float-abi Nix derivation is exposed as a flake output that runs forge build and copies JSONs to $out/.
  2. Committed JSONs. alloy::sol! reads from $CARGO_MANIFEST_DIR/abi/<Contract>.json. JSONs are committed under crates/float/abi/. A forge script script/CopyArtifacts.sol regenerates them from out/. CI workflow runs the script + git diff --exit-code to detect drift (build-pointers pattern).

Switching from (1) to (2) in #198. Rationale below.

Why switch

CI cost. The new rainix-rs-static reusable runs through rainix's rust-shell (rust toolchain only — no foundry/solc). Approach (1) requires foundry+solc in the runner — either to live-build artifacts (no cache hit) or to be present in the nix store cache for decimal-float-abi's store-path restoration (cache hit). Either way the rs-static job's nix cache carries the sol toolchain, eating into the 1G gc-max-store-size-linux budget and slowing every job's cache restore. Approach (2) lets rs-static carry only rust-toolchain paths in its cache. Smaller cache, faster restore, less eviction churn. Same applies to rs-test.

Standalone cargo build. Approach (2): bare checkout + cargo build works. No env vars, no Nix, no orchestration. Approach (1): cargo build errors at env!() lookup if you're not inside the dev shell, and inside the shell you must have run forge build first. Useful if the crate ever ships to crates.io or is consumed outside Nix.

Staleness enforcement. Approach (2) has explicit CI staleness check (copy-artifacts.yaml runs the forge script + git diff --exit-code). Approach (1) has no commit-and-diff to enforce, so there's no CI signal that local dev was working with a stale out/. Both still rely on the developer running regen on Solidity edits — Nix doesn't structurally enforce freshness in a cargo / forge workflow.

Trade-off accepted

PR diffs surface JSON churn on Solidity edits. Mitigated by bytecode_hash = "none" and cbor_metadata = false already set in foundry.toml — only deployed-bytecode and ABI structure diffs surface, not metadata-hash noise. Reviewers can use the diff as a sanity check on ABI changes.

What changes

  • script/CopyArtifacts.sol: forge script copying out/<Contract>.sol/<Contract>.jsoncrates/float/abi/<Contract>.json.
  • crates/float/src/lib.rs: alloy::sol! reads from concat!(env!("CARGO_MANIFEST_DIR"), "/abi/<Contract>.json").
  • flake.nix: drop env-var exports + decimal-float-abi derivation.
  • foundry.toml: extend fs_permissions for ./out (read) and ./crates/float/abi (read-write).
  • .github/workflows/copy-artifacts.yaml: regen-and-diff CI step.
  • crates/float/abi/{DecimalFloat,TestDecimalFloat}.json: seed committed.

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions