Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
reviews:
path_filters:
- "!audit/**"
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
cache
out
out
.fixes
76 changes: 76 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Solidity interfaces for the Rainlang interpreter and utility libraries for implementing them. Part of the Rain Protocol ecosystem for onchain interpreted compute.

License: DecentraLicense 1.0 (DCL-1.0). REUSE 3.2 compliant — all files need SPDX headers and copyright notices.

## Build & Development

Requires the Nix package manager. **Only use the nix version of Foundry**, not a system-installed one.

```bash
nix develop # Enter dev shell
rainix-sol-prelude # Setup (run before first build/test)
rainix-sol-test # Run all tests
rainix-sol-static # Static analysis (Slither)
rainix-sol-legal # License/REUSE compliance check
```

Compiler: Solidity 0.8.25, EVM target: cancun, optimizer enabled (1M runs). Fuzz tests run 2048 iterations.

All reverts use custom errors — no `revert("string")` or `require()` with string messages.

Interfaces use `pragma solidity ^0.8.18` for downstream compatibility; libraries and errors use `^0.8.25`.

## Architecture

### Core Interfaces (`src/interface/`)

The current interface set (all in `src/interface/`):

- **IInterpreterV4** — Evaluates Rainlang bytecode. Stateless: returns stack results and state writes without persisting anything itself.
- **IInterpreterStoreV3** — Key-value state storage with namespace isolation per caller. `set()` for bulk writes, `get()` for reads.
- **IInterpreterCallerV4** — Defines `EvaluableV4` struct (interpreter + store + bytecode). Contracts that call the interpreter implement this.
- **IParserV2** — Converts Rainlang source text to bytecode (`parse2()`).
- **ISubParserV4** — Extension point for custom literals and words in parsers.
- **IInterpreterExternV4** — External function dispatch with integrity checking.
- **IParserPragmaV1** — Pragma support (e.g. `usingWordsFrom`).

Deprecated v1/v2 interfaces live in `src/interface/deprecated/`. Deprecated interfaces should not be modified unless undeprecating (moving back to `src/interface/`).

### Libraries (`src/lib/`)

- **LibBytecode** (`bytecode/`) — Parse and validate Rainlang bytecode structure (source counts, offsets, stack allocation, OOB checks).
- **LibContext** (`caller/`) — Build execution context arrays with signature verification (uses OZ SignatureChecker). Base context = `[msg.sender, calling_contract]`.
- **LibEvaluable** (`caller/`) — Hash utility for `EvaluableV4` structs.
- **LibNamespace** (`ns/`) — Qualifies state namespaces by hashing with sender address for caller isolation.
- **LibParseMeta** (`parse/`) — Bloom filter + fingerprint-based word lookup for parser metadata.
- **LibGenParseMeta** (`codegen/`) — Code generation for optimized parse metadata constants.

### Key Types

- `StackItem` — `bytes32`, the interpreter's stack value type
- `OperandV2` — `bytes32`, opcode operands
- `StateNamespace` / `FullyQualifiedNamespace` — `bytes32`, state isolation
- `SourceIndexV2` — `bytes32`, index into bytecode sources
- `EvaluableV4` — struct containing interpreter address, store address, and bytecode

### Security Model

Interpreters must be resilient to malicious expressions. Eval is read-only; state changes go through a separate `set()` call. Namespace qualification ensures caller isolation. If eval reverts, no state changes persist.

## Tests

Tests are in `test/src/lib/` mirroring the `src/lib/` structure. Test files use `.t.sol` suffix. Some test helpers use `.Slow.sol` suffix for reference implementations used in differential testing.

## Dependencies

Git submodules in `lib/`: forge-std, openzeppelin-contracts, and Rain Protocol libraries (rain.sol.codegen, rain.solmem, rain.lib.hash, rain.lib.typecast, rain.math.binary, rain.math.float, rain.intorastring). The `rain.sol.codegen` submodule has a remapping configured in `foundry.toml`.

## Branch Naming

Feature branches follow `YYYY-MM-DD-description` convention.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interfaces.

Uses nixos.

Install `nix develop` - https://nixos.org/download.html.
Install Nix - https://nixos.org/download.html.

Run `nix develop` in this repo to drop into the shell. Please ONLY use the nix
version of `foundry` for development, to ensure versions are all compatible.
Expand Down
3 changes: 3 additions & 0 deletions REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ version = 1

[[annotations]]
path = [
".coderabbit.yaml",
".gas-snapshot",
".github/workflows/**/",
".gitignore",
".gitmodules",
"CLAUDE.md",
"README.md",
"audit/**/",
"flake.lock",
"flake.nix",
"foundry.toml",
Expand Down
52 changes: 52 additions & 0 deletions audit/2026-03-01-01/pass0/process.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Pass 0: Process Review

Audit date: 2026-03-01
Documents reviewed: CLAUDE.md, README.md, foundry.toml, flake.nix, slither.config.json, .github/workflows/rainix.yaml

## Evidence of Thorough Reading

### CLAUDE.md (73 lines)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix markdownlint MD022 heading-spacing violations.

At Line 8, Line 14, Line 17, Line 20, Line 24, and Line 28, add a blank line after each ### heading to satisfy the configured markdownlint rule.

Also applies to: 14-14, 17-17, 20-20, 24-24, 28-28

🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 8-8: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@audit/2026-03-01-01/pass0/process.md` at line 8, The MD022 violations are due
to missing blank lines immediately after level-3 headings; open CLAUDE.md and
after every line that starts with "###" (specifically the headings at lines
cited in the review) insert a single blank line following the heading so there
is an empty line between the "### ..." header and the following paragraph or
content, then save and re-run markdownlint to confirm the MD022 heading-spacing
errors are resolved.

- Sections: Project Overview, Build & Development, Architecture (Core Interfaces, Libraries, Key Types, Security Model), Tests, Dependencies, Branch Naming
- Commands listed: nix develop, rainix-sol-prelude, rainix-sol-test, rainix-sol-static, rainix-sol-legal
- Interfaces listed: IInterpreterV4, IInterpreterStoreV3, IInterpreterCallerV4, IParserV2, ISubParserV4, IInterpreterExternV4, IParserPragmaV1
- Libraries listed: LibBytecode, LibContext, LibEvaluable, LibNamespace, LibParseMeta, LibGenParseMeta

### README.md (50 lines)
- Sections: High level, Dev stuff (Local environment & CI), Legal stuff, Contributions

### foundry.toml (28 lines)
- Settings: solc 0.8.25, optimizer true, optimizer_runs 1000000, evm_version cancun, bytecode_hash none, cbor_metadata false, fuzz runs 2048, one remapping

### flake.nix (17 lines)
- Inputs: flake-utils, rainix
- Outputs: packages and devShells from rainix

### slither.config.json (4 lines)
- Excluded detectors: assembly-usage, solc-version, unused-imports, pragma
- Filter paths: forge-std, openzeppelin

### rainix.yaml (43 lines)
- Jobs: rainix-sol-test, rainix-sol-static, rainix-sol-legal
- Steps: checkout with submodules, nix install, cache, prelude, task

## Findings

### A00-1 [LOW] CLAUDE.md says "Requires NixOS" but NixOS is the Linux distribution — what's required is the Nix package manager

CLAUDE.md line 13: "Requires NixOS." The README.md correctly says "Uses nixos" and directs to nix installation. The actual requirement is the Nix package manager (`nix develop`), which runs on macOS and any Linux distro, not just NixOS. A future session on macOS could be confused about whether the tooling works on their platform.

### A00-2 [LOW] CLAUDE.md does not mention `revert("...")` prohibition or other Solidity-specific coding conventions

The project's security model section in CLAUDE.md mentions stateless eval and namespace isolation but does not document Solidity coding conventions that a future session should follow — most importantly, whether string reverts or custom errors are expected. This information exists in the codebase (all errors use custom errors) but is not captured in process docs.

### A00-3 [INFO] README.md says "Install `nix develop`" which is misleading

README.md line 14: "Install `nix develop` - https://nixos.org/download.html" — `nix develop` is a command, not something you install. The instruction should say to install Nix and then run `nix develop`. This is a README issue, not CLAUDE.md, but it's the canonical human-facing setup doc.

### A00-4 [INFO] CLAUDE.md mentions deprecated interfaces but doesn't state policy on modifying them

Line 39: "Deprecated v1/v2 interfaces live in `src/interface/deprecated/`." A future session doesn't know whether these should be left untouched, whether they can be deleted, or whether they might still need updates. Recent git history shows `IParserPragmaV1` was undeprecated (commit 8bb60bc), suggesting the deprecation status is not always final.

### A00-5 [INFO] No instruction on Solidity version policy for new vs. existing files

foundry.toml sets solc 0.8.25, but some interface files use `pragma solidity ^0.8.18` while libraries use `>=0.8.25`. CLAUDE.md doesn't explain when to use which pragma. A future session adding a new file wouldn't know which pragma to use.
Loading