Skip to content

Commit 4658f1b

Browse files
authored
Feat/add agents.md (#171)
* added agents-md * updated agents.md * updated
1 parent d4b531c commit 4658f1b

4 files changed

Lines changed: 101 additions & 2 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
out/
33
cache/
44
broadcast/
5+
lcov.info
56

67
# Dependencies (we explicitly do NOT vendor third-party libs;
78
# this is here only for any future Foundry-managed installs).

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "lib/forge-std"]
22
path = lib/forge-std
33
url = https://github.com/foundry-rs/forge-std
4+
[submodule "lib/base-std"]
5+
path = lib/base-std
6+
url = https://github.com/base/base-std

AGENTS.md

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,100 @@
11
# AGENTS.md
22

3-
## Branching
3+
Solidity interfaces, libraries, and reference mocks for Base's precompiles: **B20** (ERC-20 superset
4+
with roles, policies, pausing, permits, memos), **PolicyRegistry** (allowlist/blocklist singleton),
5+
and **ActivationRegistry** (feature flags). The Solidity mocks must mirror the Rust implementations
6+
in base/base **slot-for-slot** — storage layout parity is the core invariant of this repo.
7+
8+
## Commands
9+
10+
```bash
11+
forge build # compile (solc 0.8.30)
12+
forge test -v # unit tests against mocked precompiles (fast; run first)
13+
forge test -v --match-test <name> # one test; --match-contract <name> for one suite
14+
forge fmt # format Solidity (CI gates on `forge fmt --check`)
15+
python3 script/check-coverage.py # every interface function has a test (CI gate)
16+
make coverage # lcov + HTML report (needs genhtml)
17+
18+
base-forge test # same suite vs the real Rust precompiles, in-process (no node); auto-detects
19+
make smoke-setup # one-time venv setup — requires Python 3.13 exactly
20+
make smoke-all # live-RPC smoke journeys (needs .env; see below)
21+
make fork-tests # same suite vs a real base-anvil node (CI harness; patched anvil/forge)
22+
```
23+
24+
Test tiers, in the order to reach for them: **unit** (mocks, no network) → **live precompile**
25+
(real Rust precompiles — in-process via `base-forge test`, or vs a node via `make fork-tests`;
26+
cross-validates layout/behavior) → **smoke** (real txs against a live chain).
27+
28+
## Testing
29+
30+
- Unit tests live in `test/unit/{Feature}/{Name}.t.sol`; names follow
31+
`test_{function}_{outcome}_{variant}`, e.g. `test_allowance_success_zeroByDefault`.
32+
- Tests assert precompile storage directly via `vm.load` against the slot constants in
33+
`test/lib/mocks/MockB20Storage.sol`. **A live-precompile failure with passing unit tests means the
34+
Solidity reference and the Rust impl have diverged** — see `LIVE_PRECOMPILE_TESTING.md`, don't just
35+
patch the test.
36+
- Live-precompile tests need the patched binaries from
37+
[base/base-anvil](https://github.com/base/base-anvil); **stock forge/anvil will not work**. Install
38+
them alongside stock Foundry with `base-foundryup` (it never touches your `forge`/`anvil`). Common
39+
path — in-process, no node: `base-forge test`; `BaseTest` auto-detects and `setUp` logs **LIVE
40+
PRECOMPILE mode** vs **REFERENCE mode**. CI/node path: `make fork-tests` boots `anvil --base` and
41+
activates the gated features for you (override the binaries with `ANVIL_BIN` / `FORGE_BIN`). Pass
42+
forge args via `make fork-tests ARGS="-vvvv --match-test <name>"`. Details:
43+
`LIVE_PRECOMPILE_TESTING.md`, `script/fork/README.md`.
44+
- Smoke tests need `.env` (copy `.env.template`): `RPC_URL`, `DEPLOYER_PK`, `USER2_PK`
45+
**testnet keys only**, both accounts funded. Journeys **skip (not fail)** when the target chain
46+
hasn't activated the feature — a skip is not a pass. Run one journey with
47+
`make smoke-{factory,asset,stablecoin,policy,invariants}`; audit mode:
48+
`make smoke-all KEEP_GOING=1`.
49+
- Fuzz runs: 256 default, 10 under `FOUNDRY_PROFILE=fork` (RPC round-trips are slow).
50+
51+
## Project structure
52+
53+
```
54+
src/StdPrecompiles.sol # canonical precompile addresses + typed handles
55+
src/interfaces/ # IB20, IB20Asset, IB20Stablecoin, IB20Factory, IPolicyRegistry, IActivationRegistry
56+
src/lib/ # B20Constants (role/policy ids), B20FactoryLib (createB20 encoders)
57+
src/impls/ # reserved for reference impls (currently empty; mocks fill that role)
58+
test/unit/ # one directory per feature; slot-level assertions
59+
test/regression/ # interface renames/removals guard (B20Renames.t.sol, B20Removals.t.sol)
60+
test/lib/ # BaseTest.sol, B20Test.sol, mocks/ (reference behavior + storage layout)
61+
script/smoke/ # Python 3.13 live-node smoketest (web3.py); see script/smoke/README.md
62+
script/fork/ # node-based live-precompile runner (anvil + patched forge); see script/fork/README.md
63+
docs/ # specs: docs/B20/README.md, docs/PolicyRegistry/, docs/ActivationRegistry/
64+
```
65+
66+
Deeper reading: `LIVE_PRECOMPILE_TESTING.md` (cross-validation architecture), `docs/B20/README.md` (B20 spec).
67+
68+
## Code style
69+
70+
- Solidity formatting comes from `foundry.toml`: 120-char lines, 4-space tabs, double quotes,
71+
long int types (`uint256`, never `uint`). Run `forge fmt` before committing.
72+
- Interfaces use pragma `>=0.8.20 <0.9.0` (consumer compatibility); test/mock code uses `^0.8.20`,
73+
compiled with the pinned solc 0.8.30 from `foundry.toml`.
74+
- Errors are custom types with parameters, e.g. `error InvalidSupplyCap(uint256 currentSupply,
75+
uint256 proposedCap)` — never `require` strings.
76+
- Import via the public remappings `base-std/=src/` and `base-std-test/=test/`.
77+
- Mock state uses ERC-7201 namespaced storage; new state must follow the same pattern.
78+
- Python (`script/`): 3.13, PEP 8, snake_case functions, frozen dataclasses for config.
79+
`web3>=7.6,<8` is the only dependency; both runners share `script/smoke/.venv`.
80+
81+
## Git workflow
482

583
- **`main` is the default branch.** Branch from `main` and open PRs against `main`.
6-
- Ignore `master` — it is stale. Do not branch from it, target it in PRs, or use it as a base reference.
84+
- Conventional Commits with optional scope: `feat(b20): ...`, `fix(smoke): ...`, `test:`, `docs:`,
85+
`chore:`. Put the rationale in the body, not just the what.
86+
- CI on every PR: `forge build`, `forge test`, `forge fmt --check`,
87+
`python3 script/check-coverage.py`, coverage comment. Live-precompile tests run in a separate workflow.
88+
89+
## Boundaries
90+
91+
- **Don't change the precompile addresses** in `src/StdPrecompiles.sol` or the feature IDs in
92+
`script/smoke/config.py` / `test/lib/mocks/ActivationRegistryFeatureList.sol` — they are
93+
canonical constants shared with base/base; coordinate changes there first.
94+
- **Don't reshape mock storage layout unilaterally** — match `MockB20Storage.sol` slot constants
95+
and cross-validate with `make fork-tests` before merging.
96+
- **Don't commit `.env` or real private keys**`.env` is gitignored; use funded testnet keys.
97+
- **Don't hand-edit ABIs for the smoke tests**`script/smoke/abis.py` loads them from `out/`;
98+
run `forge build` instead.
99+
- **Don't weaken a slot-assertion test to make live-precompile tests pass** — investigate the divergence via
100+
`LIVE_PRECOMPILE_TESTING.md` and fix the side that's wrong.

lib/base-std

Submodule base-std added at d4b531c

0 commit comments

Comments
 (0)