Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d4b8a1a
docs: Add PEN-to-Base migration PRD, ADR-001 and token standards deci…
ebma Jul 7, 2026
ee69f72
pallets: Add token-migration pallet for one-way PEN migration to Base
ebma Jul 7, 2026
6b5863a
contracts: Add PEN token and MigrationVault for Base
ebma Jul 7, 2026
f772c31
runtime: Wire token-migration pallet into the Pendulum runtime
ebma Jul 7, 2026
d25ce9a
contracts: Add governance stack and deployment scripts
ebma Jul 7, 2026
9b27a99
attestor: Add attestor daemon for the PEN migration
ebma Jul 7, 2026
db66f0d
monitor: Add independent invariant monitor for the PEN migration
ebma Jul 7, 2026
da0fb79
docs: Add PEN migration operational runbooks (key compromise, outage,…
ebma Jul 7, 2026
f2dcea6
pallets: Add benchmarks for the token-migration pallet
ebma Jul 7, 2026
74b0cc6
security: Fix internal-review findings across vault, attestor and mon…
ebma Jul 7, 2026
087d094
contracts: Add .env.example documenting deployment parameters
ebma Jul 7, 2026
1f61407
docs: Add implementation overview of the PEN migration work across bo…
ebma Jul 7, 2026
5e7e322
security: Fix round-2 audit findings (zero-address DoS, rotation bypass)
ebma Jul 7, 2026
420b024
security: Fix round-3 audit findings (sweep vs in-flight migrations)
ebma Jul 7, 2026
c4f0a2d
docs: Update overview with round-3 review and current test counts
ebma Jul 7, 2026
9d8299e
security: Fix round-4 audit findings (threshold-cut strand, cap window)
ebma Jul 8, 2026
06b16c6
docs: Add holder-facing governance guide with two worked examples
ebma Jul 9, 2026
6194b5c
pallets: Add governance-gated migrate_treasury to token-migration
ebma Jul 9, 2026
e573063
docs: Record migrate_treasury and the treasury governance structure
ebma Jul 9, 2026
4e1df12
security: Fix round-5 audit findings (monitor surplus DoS, liveness b…
ebma Jul 9, 2026
a2de8d9
security: Fix round-6 audit findings (attestor vault-recipient DoS, m…
ebma Jul 9, 2026
7052c09
docs: Add migration-window analysis (6 months is sufficient)
ebma Jul 10, 2026
cad0027
docs: Adopt the 3-month migration window (D5 decided)
ebma Jul 10, 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
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
3 changes: 3 additions & 0 deletions attestor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
dist/
checkpoint.json
76 changes: 76 additions & 0 deletions attestor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# PEN Migration Attestor

Daemon run by each of the five independent attestor operators (PRD §6.4).
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