Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
a27e4a6
docs: Add design documents for the PEN migration to Base
ebma Aug 24, 2026
9cf7d89
pallets: Add the token-migration pallet
ebma Aug 24, 2026
e1f168a
runtime: Wire the token-migration pallet into Pendulum
ebma Aug 24, 2026
2aec0e8
contracts: Add the PEN token, migration vault and governance for Base
ebma Aug 24, 2026
eb8ba1b
attestor: Add the attestor daemon
ebma Aug 24, 2026
bb1966c
monitor: Add the independent invariant monitor
ebma Aug 24, 2026
9b6a7c8
releaser: Add the deferred-release service
ebma Aug 24, 2026
2fb8c1c
docs: Add operational runbooks, local test plan and review log
ebma Aug 24, 2026
3c47488
contracts: Fill in the decided deployment parameters
ebma Aug 24, 2026
a6f8100
testing: Add a local validation harness for the migration
ebma Aug 27, 2026
b3e31fe
docs: Refresh the implementation overview and settle the testnet plan
ebma Aug 27, 2026
298a54b
pallets: Replace estimated weights with benchmarked ones
ebma Aug 27, 2026
7c1b91c
attestor: Pad the gas limit when submitting an approval
ebma Aug 27, 2026
dcf5401
releaser: Declare Multicall3 and fall back to per-nonce reads
ebma Aug 27, 2026
58e48b2
testing: Add phase 1 and phase 3 to the validation harness
ebma Aug 27, 2026
1bb94df
attestor: Ignore local checkpoint files from test runs
ebma Aug 27, 2026
7027c81
docs: Point the test plan at the automated harness
ebma Aug 28, 2026
9aeb872
testing: Repair chain specs so the node can read back its own output
ebma Aug 28, 2026
e7ca41b
testing: Add a Zombienet network for relay-finality validation
ebma Aug 28, 2026
df0b9a8
testing: Add phase 4, relay-chain finality under Zombienet
ebma Aug 28, 2026
9c2add8
docs: Record relay-finality validation in the test plan
ebma Aug 28, 2026
ec4100d
testing: Add rehearsal environment with testnet guardrails
ebma Aug 28, 2026
e0eda12
testing: Extract Zombienet control into a shared module
ebma Aug 28, 2026
c1b2654
testing: Add phase 5, full-stack rehearsal on Base Sepolia
ebma Aug 28, 2026
53acc1e
docs: Document the full-stack rehearsal phase
ebma Aug 28, 2026
b4f13aa
testing: Fan rehearsal gas out from the deployer
ebma Aug 28, 2026
0a05626
testing: Share the collator discovery helper with phase 4
ebma Aug 28, 2026
844f731
attestor: Survive a lost race when the RPC has not caught up
ebma Aug 28, 2026
c7f4f0c
attestor: Actually route the race recheck through the backoff
ebma Aug 28, 2026
7037f6f
attestor: Survive transient RPC failures instead of exiting
ebma Aug 28, 2026
faf7939
testing: Ride out endpoint throttling in the rehearsal's own reads
ebma Aug 28, 2026
299601f
docs: Record the two defects the Base Sepolia rehearsal found
ebma Aug 28, 2026
8b86094
testing: Automate the phase 6 failure drills
ebma Aug 31, 2026
c0ba4f1
docs: Point the failure-drill table at the automated drills
ebma Aug 31, 2026
e975577
testing: Drill the real runtime upgrade under a live fleet
ebma Aug 31, 2026
f0f64e4
attestor: Cover bare 429 codes; record the post-drills review pass
ebma Aug 31, 2026
d952d5e
testing: Add phase 5b, the governance rehearsal on Base Sepolia
ebma Aug 31, 2026
16ee8bf
docs: Document the governance rehearsal and its manual walkthrough
ebma Aug 31, 2026
ac1e77b
docs: Add the review handover briefing for the next review round
ebma Aug 31, 2026
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
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,10 @@

.DS_Store
.idea
.vscode
.vscode
# Locally generated Zombienet chain spec (13MB, rebuilt by make-zombienet-spec.mjs)
testing/.zombienet-pendulum-raw.json*

# Rehearsal secrets and run artifacts (throwaway keys, but never commit them)
testing/.env.rehearsal
testing/.rehearsal/
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "contracts/lib/openzeppelin-contracts"]
path = contracts/lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
[submodule "contracts/lib/forge-std"]
path = contracts/lib/forge-std
url = https://github.com/foundry-rs/forge-std
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ members = [
"pallets/vesting-manager",
"pallets/orml-currencies-allowance-extension",
"pallets/orml-tokens-management-extension",
"pallets/token-migration",
"pallets/treasury-buyout-extension",
"pallets/xcm-teleport",
"runtime/common",
Expand Down
4 changes: 4 additions & 0 deletions attestor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
dist/
checkpoint.json
cp*.json
77 changes: 77 additions & 0 deletions attestor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# PEN Migration Attestor

Daemon run by each of the four attestor operators (3-of-4, initially
team-operated — PRD §6.4 / D4).
Watches **relay-finalized** blocks on the operator's **own** Pendulum node for
`tokenMigration.MigrationInitiated` events and submits the matching
`approve(nonce, recipient, palletAmount)` transaction to the MigrationVault on
Base. The vault releases the tokens on the 3rd matching approval; attestors
never communicate with each other — the contract is the only coordination
point.

## Non-negotiable operational rules (PRD A1–A5)

1. **Run your own Pendulum full node** and point `PENDULUM_WS` at it. Using a
public RPC means trusting that RPC with release authority.
2. **Key isolation:** the attestor key signs only vault `approve` calls. Keep
it in an HSM/KMS signer where possible; never reuse it elsewhere. The same
address pays gas — keep it funded with Base ETH (the daemon alerts below
`MIN_GAS_BALANCE_WEI`).
3. **Separate infrastructure per operator** — different hosting, different
credentials, nothing shared with other attestors or with the monitor.
4. The daemon **exits on any decode or processing error** instead of skipping
events. Run it under a process manager (systemd example below) and page a
human when it restart-loops: a stuck attestor on a runtime upgrade usually
means the metadata changed and the daemon needs updating.

## Configuration (environment)

| Variable | Meaning |
|---|---|
| `PENDULUM_WS` | WebSocket of your own Pendulum node, e.g. `ws://127.0.0.1:9944` |
| `BASE_RPC_URL` | Base JSON-RPC endpoint |
| `VAULT_ADDRESS` | MigrationVault address on Base |
| `ATTESTOR_PRIVATE_KEY` | This attestor's signing key (0x-prefixed) |
| `CHECKPOINT_FILE` | Path persisting the last processed block (default `./checkpoint.json`) |
| `START_BLOCK` | First Pendulum block to scan on the very first run |
| `MIN_GAS_BALANCE_WEI` | Low-gas alert threshold (default 0.01 ETH) |
| `ALERT_WEBHOOK_URL` | Optional webhook receiving JSON alerts |
| `BASE_CHAIN_ID` | Default 8453 (Base mainnet) |

## Run

```sh
npm install
npm run build
npm start
```

### systemd example

```ini
[Unit]
Description=PEN migration attestor
After=network-online.target

[Service]
EnvironmentFile=/etc/pen-attestor/env
WorkingDirectory=/opt/pen-attestor
ExecStart=/usr/bin/node dist/main.js
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
```

## Behavior details

- Blocks are processed strictly in order; the checkpoint advances only after
every event in a block is handled. A crash re-processes at most one block —
safe, because approvals are idempotent (`nonceConsumed`/`hasApproved` are
checked first, and duplicate submissions revert harmlessly).
- The daemon verifies at startup that its address is in the vault's attestor
set and refuses to run otherwise.
- After a Pendulum **runtime upgrade**, verify event decoding against the new
metadata on a staging node before letting the fleet advance past the
upgrade block (see docs/pen-migration-runbooks.md).
Loading
Loading