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
11 changes: 10 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
This is a repo of onchain operational tasks. Each network has its own directory with each individual task as a sub-directory.
This is a repo of onchain operational tasks. Active EVM tasks live under `active/evm/tasks/`; one task directory may contain configurations for multiple networks under `config/<network>/`.

Active EVM task lifecycle:

- A task directory represents one logical operation and carries its shared Makefile, scripts, and facilitator guide across network rollouts. Add another `config/<network>/` to the existing task instead of creating a duplicate task solely to change networks.
- A task with multiple network configurations must require `TASK_NETWORK` on each `make` command line. Do not set a mutable default or rely on an exported environment value; use `make TASK_NETWORK=<network> <target>` so the selected network is visible at every invocation.
- Keep the task-root `FACILITATOR.md` authoritative and network-agnostic, using explicit placeholders such as `TASK_NETWORK=<network>` and paths under `config/<network>/`. Per-network facilitator files are discouraged because they duplicate configuration and drift from the shared procedure. Only consider one as a last resort when a network has a materially different procedure that cannot be expressed in the root guide, `.env`, or signer README. If unavoidable, place only the procedural delta in `config/<network>/FACILITATOR.md` and link to it from the root guide.
- Keep a task under `active/evm/tasks/` while any currently intended network rollout remains pending. Do not run `make archive-task` between network rollouts; archive only after every intended network configuration is executed or canceled and its final artifacts are committed.
- Treat `archive/evm/` as historical. Do not edit or execute an archived task in place. If the same operation later needs another network rollout, restore the entire task directory to `active/evm/tasks/` before adding that network.
- Store network-specific deployment address artifacts such as `addresses.json` under `config/<network>/`. Keep Forge broadcast records at task scope under `records/`; Foundry separates them by script and chain ID.

Task writing:

Expand Down
45 changes: 17 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,47 +105,36 @@ All address variables are prefixed with `export` so they are available to child

## Directory structure

Active EVM tasks live under `active/evm/`, which is a single shared Foundry
project rather than a standalone project per task. A single `active/evm/Makefile`
selects the active task via `TASK_ID` / `TASK_NETWORK`, reusable operation
scripts are shared across tasks under `script/common/<category>/`, and each task
directory holds only its own config, docs, and (per-network) validations and
signatures:
Active EVM tasks share the Foundry project under `active/evm/`, while each task owns its Makefile, facilitator guide, network configurations, signatures, and execution records. Reusable operation scripts live under `script/common/<category>/`; one-off scripts stay with their task.

```text
active/evm/
├── Makefile # shared; selects the task via TASK_ID / TASK_NETWORK
├── foundry.toml # shared Foundry config (base-contracts v8.2.1)
├── foundry.toml # shared Foundry configuration
├── script/
│ └── common/ # reusable scripts, shared across tasks
│ └── <category>/ # bridge, funding, gas, ownership, safe, superchain, verifier-update
└── tasks/
└── <YYYY-MM-DD-task-name>/
├── FACILITATOR.md
├── Makefile # task dependencies, validation, approvals, and execution
├── FACILITATOR.md # network-agnostic facilitator procedure
├── script/ # optional one-off task scripts
├── config/
│ └── <network>/
│ ├── .env # task inputs + BASE_CONTRACTS_COMMIT + RECORD_STATE_DIFF
│ ├── network.env # RPC, chain ids, Safe/contract addresses
│ ├── README.md # status + description (parsed by the signer tool)
│ ├── .env # network-specific task inputs + BASE_CONTRACTS_COMMIT
│ ├── addresses.json # generated network-specific deployment addresses
│ ├── README.md # status + description parsed by the signer tool
│ └── validations/ # generated per-signer validation JSON
└── signatures/
└── <network>/ # task-origin signatures (when required)
├── signatures/
│ └── <network>/ # task-origin signatures when required
└── records/
└── <script>/<chain-id>/ # Forge broadcast records
```

Task commands run from `active/evm`, selecting the task by `TASK_ID` /
`TASK_NETWORK` (both default to the current task in the shared `Makefile`), e.g.
`TASK_ID=<task> TASK_NETWORK=<network> make gen-validation-cb`. The shared
Makefile runs Forge from `active/evm` using the shared `foundry.toml` and `lib/`,
while task-specific files are read from `tasks/<task-id>/config/<network>/`.
Reusable scripts are documented in [`active/evm/script/common/README.md`](active/evm/script/common/README.md);
put a script under `script/common/<category>/` when it will be reused across
tasks, and keep one-off task glue out of `common/`.

The shared `active/evm/Makefile` selects a task (via `TASK_ID` / `TASK_NETWORK`)
and sources that task's `.env` for `BASE_CONTRACTS_COMMIT`. To install
dependencies for the shared project without selecting a task (e.g. to build the
common scripts locally), invoke the root Makefile directly with a `PROJECT_DIR`
override and an explicit `BASE_CONTRACTS_COMMIT`:
Run task commands from `active/evm/tasks/<task-id>/`. A task with multiple network configurations must require `TASK_NETWORK` on each Make command line, for example `make TASK_NETWORK=sepolia gen-validation-cb`; it must not rely on a mutable default or exported environment value. Keep the root `FACILITATOR.md` authoritative and network-agnostic, and make the need to replace `TASK_NETWORK=<network>` explicit. Per-network facilitator files are discouraged; if one is unavoidable for a materially different procedure, put only that procedural delta in `config/<network>/FACILITATOR.md` and link to it from the root guide.

One task directory represents one logical operation across its intended network rollouts. Add sibling `config/<network>/` directories and keep the task active until all intended networks are executed or canceled and their final artifacts are committed. Do not run `make archive-task` between network rollouts.

Reusable scripts are documented in [`active/evm/script/common/README.md`](active/evm/script/common/README.md). To install dependencies for the shared project without selecting a task, invoke the root Makefile with a project directory and explicit contracts commit:

```bash
make deps PROJECT_DIR="$PWD/active/evm" BASE_CONTRACTS_COMMIT=<commit>
Expand Down
11 changes: 7 additions & 4 deletions active/evm/script/common/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ Reusable EVM operation scripts live here. A script belongs in this directory whe
Reference common scripts by explicit Forge target path from `active/evm`:

```bash
mise exec -- forge script --rpc-url "$L1_RPC_URL" script/common/verifier-update/UpdateVerifierHashes.s.sol:UpdateVerifierHashes
ADDRESSES_JSON="tasks/<task-id>/config/<network>/addresses.json" \
mise exec -- forge script --rpc-url "$L1_RPC_URL" script/common/verifier-update/UpdateVerifierHashes.s.sol:UpdateVerifierHashes
```

In Makefiles, prefer the same explicit path:
Expand All @@ -22,8 +23,8 @@ This keeps validation JSON portable and avoids ambiguity when different files de

| Folder | Script | Purpose | Required task files |
| --- | --- | --- | --- |
| `verifier-update/` | `DeployAggregateVerifier.s.sol` | Deploys a replacement `AggregateVerifier` by copying immutable constructor inputs from the live implementation and replacing verifier hashes. | `tasks/<task-id>/config/<network>/.env`, `tasks/<task-id>/config/<network>/network.env`, `ADDRESSES_JSON` output path |
| `verifier-update/` | `UpdateVerifierHashes.s.sol` | Multisig script that updates `DisputeGameFactory.gameImpls(gameType)` to a deployed `AggregateVerifier`. | `ADDRESSES_JSON` pointing at a JSON file with `aggregateVerifier` |
| `verifier-update/` | `DeployAggregateVerifier.s.sol` | Deploys a replacement `AggregateVerifier` by copying immutable constructor inputs from the live implementation and replacing verifier hashes. | `tasks/<task-id>/config/<network>/.env`, `ADDRESSES_JSON=tasks/<task-id>/config/<network>/addresses.json` |
| `verifier-update/` | `UpdateVerifierHashes.s.sol` | Multisig script that updates `DisputeGameFactory.gameImpls(gameType)` to a deployed `AggregateVerifier`. | `ADDRESSES_JSON=tasks/<task-id>/config/<network>/addresses.json` containing `aggregateVerifier` |
| `funding/` | `Fund.s.sol` | Sends native token from a Safe to recipients listed in `funding.json`. | `funding.json` |
| `gas/` | `IncreaseEip1559ElasticityAndIncreaseGasLimit.s.sol` | Updates gas limit, EIP-1559 elasticity, and DA footprint gas scalar on `SystemConfig`. | config env values |
| `bridge/` | `PauseBridge.s.sol` | Deposits an L2 transaction through the portal to pause or unpause the L2 bridge. | config env values |
Expand All @@ -34,6 +35,8 @@ This keeps validation JSON portable and avoids ambiguity when different files de

## Adding Scripts

Use exact Solidity pragmas based on the contracts the script imports; preserve a script's original exact pragma when moving it here. Load config from environment variables into immutable variables where possible. Keep task-specific values in `tasks/<task-id>/config/<network>/.env`, `tasks/<task-id>/config/<network>/network.env`, or task-local JSON files rather than hardcoding them in common scripts.
Use exact Solidity pragmas based on the contracts they import; preserve a script's original exact pragma when moving it here. Load config from environment variables into immutable variables where possible. Keep scalar task-specific values in `tasks/<task-id>/config/<network>/.env`, or use the script-documented JSON input when structured data is required, rather than hardcoding values in common scripts.

Network-specific deployment address artifacts belong under `tasks/<task-id>/config/<network>/addresses.json`. Common verifier scripts must require `ADDRESSES_JSON` explicitly instead of defaulting to the shared project or task root. Forge broadcast records remain at task scope because Foundry separates them by script and chain ID.

If a script needs task-specific behavior, prefer a small task-local wrapper or Makefile target that passes environment variables into a common script. Move the underlying Solidity into this directory only when the operation itself is reusable.
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ contract DeployAggregateVerifier is Script {
string memory root = "root";
string memory json =
vm.serializeAddress({objectKey: root, valueKey: "aggregateVerifier", value: aggregateVerifier});
string memory path = vm.envOr("ADDRESSES_JSON", string("addresses.json"));
string memory path = vm.envString("ADDRESSES_JSON");
vm.writeJson({json: json, path: path});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ contract UpdateVerifierHashes is MultisigScript {

currentAggregateVerifier = IDisputeGameFactoryAdmin(disputeGameFactoryProxyEnv).gameImpls(gameTypeEnv);

string memory path = vm.envOr("ADDRESSES_JSON", string("addresses.json"));
string memory path = vm.envString("ADDRESSES_JSON");
string memory json = vm.readFile(path);
nextAggregateVerifier = vm.parseJsonAddress({json: json, key: ".aggregateVerifier"});

Expand Down
Loading