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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ docs/*
!docs/deployed-addresses.md
!docs/pool-versions.md
!docs/enabling-existing-token.md
!docs/governance-modes.md

# Safe Transaction Builder batches (run artifacts, kept local); keep the example
batches/*
!batches/example.transfer-ownership.11155111.json

# Dotenv file
.env
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ endif
done
@echo "review the lane policy diff (lanes{} = owner policy), then: make doctor CHAIN=$(LOCAL)"

remove-lane: tools ## Remove a lanes{} policy entry LOCAL -> REMOTE from the declaration (LOCAL= REMOTE= required; BOTH=1 removes the reciprocal; on-chain removal via ApplyChainUpdates is a separate step)
remove-lane: tools ## Remove a lanes{} policy entry LOCAL -> REMOTE from the declaration (LOCAL= REMOTE= required; BOTH=1 removes the reciprocal; on-chain removal via RemoveChain, or RemoveRemotePool for a single pool, is a separate step)
$(if $(LOCAL),,$(error LOCAL is required: make remove-lane LOCAL=<name> REMOTE=<name> [BOTH=1]))
$(if $(REMOTE),,$(error REMOTE is required: make remove-lane LOCAL=<name> REMOTE=<name> [BOTH=1]))
FOUNDRY_PROFILE=sync forge script $(SYNC_SCRIPT) --sig "removeLane(string,string)" "$(LOCAL)" "$(REMOTE)"
Expand Down
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ make add-chain CHAIN=ethereum-testnet-sepolia-base-1 SELECTOR=103449712358744650
make doctor CHAIN=ethereum-testnet-sepolia-base-1 # 3. layered verification — re-run until green
```

`CHAIN` is the chain's **canonical CCIP selectorName** as shown by `make discover` (the API/registry name — e.g. `ethereum-testnet-sepolia-base-1`, not a bespoke `base-sepolia`); it becomes the file name `config/chains/<CHAIN>.json` and is validated against the API. `SELECTOR` is the **explicit identity key**, also from `make discover` — every fetch cross-checks both: a valid-but-wrong selector fails loudly as `SELECTOR MISMATCH`, and a non-canonical name as `SELECTOR NAME MISMATCH`, instead of silently writing another chain's contracts. New chains are **discovered automatically** from `config/chains/` — `HelperConfig` scans the directory, so no Solidity edit is needed anywhere. For a newly added chain the `chainNameIdentifier` (and hence the `rpcEnv` and the `<ID>_TOKEN`/`<ID>_TOKEN_POOL` override prefix) is **derived from the selectorName** as UPPER_SNAKE — so it may differ in style from the six bundled chains' curated short forms (e.g. `AVALANCHE_TESTNET_FUJI`, not `AVALANCHE_FUJI`); `add-chain` **prints the exact `chainNameIdentifier` and `rpcEnv` names it generated** so you never have to guess (or open the JSON) which env var to export. `add-chain` prints your next steps: add the chain's RPC env var to `.env`, then deploy your token and pool there ([Step 1](#step-1-deploy-token-on-both-chains) / [Step 2](#step-2-deploy-token-pools-on-both-chains)). Then declare the lane policy with `make add-lane LOCAL=<name> REMOTE=<remote> CAPACITY=<wei> RATE=<wei> BOTH=1`, apply it on-chain via [Step 5](#step-5-apply-chain-updates-configure-cross-chain-routes), and re-run `make doctor` — its lanes rung reconciles the declared policy against the pool. To retire a lane, `make remove-lane LOCAL=<name> REMOTE=<remote> [BOTH=1]` removes the declaration; that is a separate step from the on-chain removal (the pool's `applyChainUpdates` takes the selector in `remoteChainSelectorsToRemove`), and between the two `make doctor` WARNs that the on-chain lane is not declared.
`CHAIN` is the chain's **canonical CCIP selectorName** as shown by `make discover` (the API/registry name — e.g. `ethereum-testnet-sepolia-base-1`, not a bespoke `base-sepolia`); it becomes the file name `config/chains/<CHAIN>.json` and is validated against the API. `SELECTOR` is the **explicit identity key**, also from `make discover` — every fetch cross-checks both: a valid-but-wrong selector fails loudly as `SELECTOR MISMATCH`, and a non-canonical name as `SELECTOR NAME MISMATCH`, instead of silently writing another chain's contracts. New chains are **discovered automatically** from `config/chains/` — `HelperConfig` scans the directory, so no Solidity edit is needed anywhere. For a newly added chain the `chainNameIdentifier` (and hence the `rpcEnv` and the `<ID>_TOKEN`/`<ID>_TOKEN_POOL` override prefix) is **derived from the selectorName** as UPPER_SNAKE — so it may differ in style from the six bundled chains' curated short forms (e.g. `AVALANCHE_TESTNET_FUJI`, not `AVALANCHE_FUJI`); `add-chain` **prints the exact `chainNameIdentifier` and `rpcEnv` names it generated** so you never have to guess (or open the JSON) which env var to export. `add-chain` prints your next steps: add the chain's RPC env var to `.env`, then deploy your token and pool there ([Step 1](#step-1-deploy-token-on-both-chains) / [Step 2](#step-2-deploy-token-pools-on-both-chains)). Then declare the lane policy with `make add-lane LOCAL=<name> REMOTE=<remote> CAPACITY=<wei> RATE=<wei> BOTH=1`, apply it on-chain via [Step 5](#step-5-apply-chain-updates-configure-cross-chain-routes), and re-run `make doctor` — its lanes rung reconciles the declared policy against the pool. To retire a lane, `make remove-lane LOCAL=<name> REMOTE=<remote> [BOTH=1]` removes the declaration; that is a separate step from the on-chain removal, done with [`RemoveChain`](#remove-a-remote-chain) (whole-chain teardown, every version) or [`RemoveRemotePool`](#remove-a-remote-pool) (a single pool, 1.5.1+), and between the two `make doctor` WARNs that the on-chain lane is not declared.

Full details: [Configuration](#configuration) overview, the per-field [`docs/config-schema.md`](docs/config-schema.md), and the command + architecture reference [`docs/config-architecture.md`](docs/config-architecture.md).

Expand Down Expand Up @@ -1048,6 +1048,8 @@ DEST_CHAIN=MANTLE_SEPOLIA \

##### Remove a Remote Pool

Drops a single remote pool from a chain that stays supported. This is a 1.5.1+ operation; on a 1.5.0 pool it refuses and points at "Remove a Remote Chain" below, since 1.5.0 holds one remote pool per chain (there is no standalone pool removal).

> **Warning:** All inflight transactions from the removed pool will be rejected after removal. Ensure there are no inflight transactions before proceeding.

```bash
Expand All @@ -1062,6 +1064,23 @@ DEST_CHAIN=MANTLE_SEPOLIA \
--broadcast
```

##### Remove a Remote Chain

Tears down the whole lane: fully unsupports a remote chain on the source pool (removes the selector and deletes its remote-chain config), so neither direction accepts messages afterward. Use this to retire a lane, not to swap a pool. Works on every pool version (1.5.0 through 2.0.0) — the script dispatches on the pool's on-chain version.

> **Warning:** All inflight transactions on this lane will be rejected after removal. Ensure there are no inflight messages to or from this chain before proceeding. See [`docs/pool-versions.md`](docs/pool-versions.md#removing-a-lane-or-a-pool) for the live-lane drain sequence and the config that survives removal.

```bash
DEST_CHAIN=MANTLE_SEPOLIA \
forge script \
script/configure/remote-chains/RemoveChain.s.sol \
--rpc-url \
$ETHEREUM_SEPOLIA_RPC_URL \
--account \
$KEYSTORE_NAME \
--broadcast
```

### Deploy Advanced Pool Hooks

Use this script for enhanced security features like allowlists, CCV management, policy engine integration, and threshold-based validation.
Expand Down
1 change: 1 addition & 0 deletions batches/example.transfer-ownership.11155111.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":"1.0","chainId":"11155111","createdAt":0,"meta":{"name":"transfer-ownership","description":"CCT action-layer batch (docs-cct-foundry)","txBuilderVersion":"1.17.1","createdFromSafeAddress":"0x01ABb19a5c0e22F34a52cA590ddaC116533679BA","createdFromOwnerAddress":""},"transactions":[{"to":"0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496","value":"0","data":"0xf2fde38b00000000000000000000000001abb19a5c0e22f34a52ca590ddac116533679ba","contractMethod":null,"contractInputsValues":null}]}
7 changes: 4 additions & 3 deletions docs/config-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ that need it, never exported. Targets that touch the API need only `curl` + `jq`
| `discover` | List the CCIP API testnet catalog joined against local configs | `FILTER=<term>` (optional) | `bash script/config/sync-discover.sh` |
| `add-chain` | Generate `config/chains/<CHAIN>.json` from the live API, then sync | `CHAIN=` **+** `SELECTOR=` (both required) | `SyncCcipConfig.s.sol --sig "init(string,uint256)" <CHAIN> <SELECTOR>` → canonicalize |
| `add-lane` | Append a `lanes{}` policy entry LOCAL → REMOTE (writes **only** the `lanes` subtree; no API fetch) | `LOCAL=` `REMOTE=` `CAPACITY=` `RATE=` (all required); `INBOUND_CAPACITY=` + `INBOUND_RATE=` (paired, optional) add the `inbound{}` block; `BOTH=1` adds the reciprocal | `SyncCcipConfig.s.sol --sig "addLane(string,string,uint256,uint256)" <LOCAL> <REMOTE> <CAP> <RATE>` (6-arg overload with the inbound pair; twice with `BOTH=1`) → canonicalize both files |
| `remove-lane` | Remove a `lanes{}` policy entry LOCAL → REMOTE (undo of `add-lane`; writes **only** the `lanes` subtree, declaration only - an applied lane must also be removed on-chain via `ApplyChainUpdates`) | `LOCAL=` `REMOTE=` (both required); `BOTH=1` removes the reciprocal | `SyncCcipConfig.s.sol --sig "removeLane(string,string)" <LOCAL> <REMOTE>` (twice with `BOTH=1`) → canonicalize both files |
| `remove-lane` | Remove a `lanes{}` policy entry LOCAL → REMOTE (undo of `add-lane`; writes **only** the `lanes` subtree, declaration only - an applied lane must also be removed on-chain via `RemoveChain`, or `RemoveRemotePool` for a single pool) | `LOCAL=` `REMOTE=` (both required); `BOTH=1` removes the reciprocal | `SyncCcipConfig.s.sol --sig "removeLane(string,string)" <LOCAL> <REMOTE>` (twice with `BOTH=1`) → canonicalize both files |
| `adopt-token` | Adopt an externally deployed token (and optionally its pool) into the address registry after on-chain validation (needs the chain's `rpcEnv` RPC; see [`enabling-existing-token.md`](enabling-existing-token.md)) | `CHAIN=` **+** `TOKEN=` (both required); `TOKEN_POOL=` optional | `AdoptToken.s.sol --sig "run(string,address,address)" <CHAIN> <TOKEN> <TOKEN_POOL or 0x0>` |
| `sync` | Refresh one chain's API-served fields (`ccip{}` + identity/metadata) from the API | `CHAIN=` (required) | `SyncCcipConfig.s.sol --sig "run(string)" <CHAIN>` → canonicalize |
| `sync-preview` | Fetch + log a chain's `ccip{}` from the API **without writing** | `CHAIN=` (required) | `SyncCcipConfig.s.sol --sig "preview(string)" <CHAIN>` |
Expand Down Expand Up @@ -172,8 +172,9 @@ A lane is **directional policy**: `lanes.<remote>` in chain A's file declares "A
`<remote>`" with an outbound rate limit. A working transfer path needs the lane declared on **both** files
(each side's `applyChainUpdates` reads its own file), so the committed configs must form a **reciprocal
mesh**. `make add-lane ... BOTH=1` writes both sides in one command, and `make remove-lane` is its undo
(declaration only - a lane still applied on the pool must be removed separately via
`ApplyChainUpdates`, and until then the doctor's lanes rung WARNs about the undeclared on-chain
(declaration only - a lane still applied on the pool must be removed separately on-chain via
`RemoveChain` (whole-chain teardown, every version) or `RemoveRemotePool` (one pool, 1.5.1+), and
until then the doctor's lanes rung WARNs about the undeclared on-chain
lane); the doctor's **mesh rung** proves the property across the whole directory on every
`make doctor CHAIN=<name>`:

Expand Down
Loading
Loading