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
54 changes: 7 additions & 47 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ pnpm workspaces (no nx/turbo/lerna). All packages under `packages/`:
|---------|---------|
| `cluster-tool` (`@wireio/cluster-tool`) | THE core library: orchestration engine (PhaseGroup → Phase → Step → Report), process managers, chain clients, config/bind resolution, Steps palette, flow substrate (`FlowCLI`/`FlowScenario`), CLI |
| `cluster-tool-shared` (`@wireio/cluster-tool-shared`) | Zod schema-first persisted shapes (`ClusterConfig`, `BindConfig`, `ClusterState`, `SignatureProviderConfig`, `ExternalOutpostConfig`, `ExternalClusterConfig`, `ChainTokenAmount`, `QueryEngineConfig`) behind the generic `SchemaCodec` (validate-both-ends serialize/deserialize) |
| `flow-*` (21 packages; 13 enabled, 8 disabled at launch) | One scenario each — standalone executables built on `FlowCLI.create(<Name>Scenario).run()`; batch-operator lifecycle (slashing/termination), collateral, reserves, emissions soak, node-owner NFT, yield distribution, liq syndication, liq yield, and the six swap variants |
| `flow-*` (13 enabled packages) | One scenario each — standalone executables built on `FlowCLI.create(<Name>Scenario).run()`; batch-operator lifecycle, depot collateral, emissions, node-owner NFT, yield, LIQ syndication and underwriting, and emergency stop |
| `debugging-shared` / `debugging-server` / `debugging-client-shared` / `debugging-client-tool` / `debugging-client-tool-tui` | OPP debugging surface: shared types + storage paths, ingest server, RPC client, CLI, TUI |
| `test-app-server` | Fixture app server used by debugging tests |

Expand Down Expand Up @@ -300,13 +300,7 @@ secret-id pattern), plus `--external-outpost-config <file>` (bootstrap the depot
against already-deployed REMOTE ETH+SOL outposts — no local anvil/validator),
`--bind-config <file>` (a complete `BindConfig` used verbatim, or a partial
override merged over the resolved defaults; a remote anvil/solana address
requires `--external-outpost-config`), `--enable-mock-reserves` (default off —
seed the 8 mock (chain, token) PRIMARY reserves at bootstrap; a real / external
depot leaves these unseeded), `--enable-launch-withheld-operations` (default
off — run the Solana outpost bootstrap calls the launch build of the program
withholds with `OperationDisabled`: `init_reserve`, `create_reserve_native` and the
mock SPL reserve provisioning that writes `sol-mock-mints.json`; a default cluster
skips them), `--enable-mock-liq-pools` (default off — seed the
requires `--external-outpost-config`), `--enable-mock-liq-pools` (default off — seed the
2 mock shadow-liq yield pools on `sysio.swap` and back the shadow in outpost
custody), `--enable-mock-syndication-import` (default off — import the mock
bonder's LIQSOL/LIQETH positions during epoch zero and back all mock shadow), `--api-count <N>` (default 0 — plan N API nodes:
Expand Down Expand Up @@ -357,14 +351,8 @@ inline signing key (the GHA workflow is SSM-only, so published archives do not).
the SAME `applyClusterBuildOptionsArgs` surface every flow uses (env vars
`WIRE_*` seed the path flags). Exit code mirrors the bootstrap Report.

**Flow authoring — mock reserves, liq pools and syndication import.** A flow that reads the mock
(chain, token) PRIMARY reserves sets `enableMockReserves: true` in its
`Scenario.defaults` (the same mechanism it uses for `operatorsPerEpoch` /
collateral) — never in `plan()`. The bootstrap seeds them during epoch 0; a
flow's `plan()` phases always run AFTER `EpochBootstrap` advances epoch 0→1, and
the depot gates `regreserve` to epoch 0, so `regreserve` can never be called from
a flow phase. The mock shadow-liq yield pools (`enableMockLiqPools: true`,
`sysio.liq::regliqpool`) follow the same rule for the same reason. The shadow
**Flow authoring — mock LIQ pools and syndication import.** The mock shadow-liq yield pools (`enableMockLiqPools: true`,
`sysio.liq::regliqpool`) must be seeded during epoch zero through scenario defaults, before flow phases run. The shadow
symbols themselves (`sysio.liq::create`, one per registered liq token), the swap's
`setconfig` and the kicker are registry setup a real depot performs too, so the
bootstrap does those unconditionally. A flow needing the first bonder sets
Expand Down Expand Up @@ -401,37 +389,9 @@ are `SolanaLiqSyndicationTool` (`planSetFrozen`, `planDonateToPool`,
PDA) and `EthereumSyndicationTool` (`planSyndicate`, `planDonateToPool`,
`planSetPaused`, `planPayPendingDesyndication`).

**Flow authoring — launch-withheld operations.** `enableLaunchWithheldOperations:
true` makes the bootstrap RUN the Solana outpost calls the launch build of the
program withholds (`init_reserve`, `create_reserve_native`, the mock SPL reserve
provisioning), so a flow that sets it requires a Solana program build without the
launch restrictions; against the launch build those calls return
`OperationDisabled` (6086). A flow sets it in its `Scenario.defaults` — never in
`plan()` — when its scenario needs the bootstrap-seeded Solana reserves or the mock
SPL mints. The flag does not decide which flows the launch program can run: the
eight that set it are **disabled at launch** (`flow-reserve-lifecycle`, `flow-swap-from-wire`,
`flow-swap-non-native-tokens`, `flow-swap-private-reserves`, `flow-swap-to-wire`,
`flow-swap-variance-revert`, `flow-swap-with-underwriting`,
`flow-underwriter-slashing`) need Solana operations the launch build withholds, and
`flow-yield-distribution` injects attestations through the withheld
`add_attestation` instruction — it does not set the flag, which governs only
bootstrap calls. The collateral, producer-registration and batch-operator-termination
flows bond on the depot, do not set the flag, and run against the launch program.

Each of the eight disabled flows opts into `enableLaunchWithheldOperations: true`
and exercises
reserves/swaps, which the launch Solana program refuses: wire-solana `89565920`
("Disable unaudited reserve and swap operations") returns `OperationDisabled`
6086 at `InitReserve` during bootstrap. There is no launch replacement for these
operations; they return when reserves/swaps are enabled after audit.

Their `package.json` live-flow script is named `test:disabled` instead of `test`.
Both local `scripts/run-flow.mjs` discovery (including exact names, short names,
regex and the picker) and CI's `run-flows.mjs` require a `test` script, so these
packages are skipped. To re-enable a flow after audit, rename `test:disabled`
back to `test` in its `package.json` (one line per flow). All packages remain in
`pnpm build`; root `pnpm test` still runs Jest and every `test:unit` script.
These eight packages currently have no unit tests.
**Removed functionality.** The eight reserve/swap flow packages and their bootstrap
flags have been deleted. Only batch operators run OPP daemons. Syndication bond
providers act through `sysio.bond`; they do not run swap-underwriter daemons.

**Flow authoring — API nodes.** A flow that needs an API node sets `apiCount`
(and, if needed, `queryEngine`) in its `Scenario.defaults`; the nodes start in
Expand Down
49 changes: 13 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ that OPP envelopes circulate and that on-chain state stays consistent end to end
The OPP message flow spans three chains:

- **WIRE depot** (`nodeop` + `kiod`) — system contracts `sysio.epoch`, `sysio.msgch`,
`sysio.opreg`, `sysio.uwrit`, `sysio.reserv`, `sysio.chalg`, …
- **Ethereum outpost** (`anvil`) — `OPP.sol`, `OPPInbound.sol`, `OperatorRegistry.sol`,
`ReserveManager.sol`, `StakingManager.sol` (+ `liqEth`).
`sysio.opreg`, `sysio.chalg`, `sysio.synd`, `sysio.bond`, `sysio.liq`, `sysio.swap`
(a depot-local AMM with no outpost participation), `sysio.andon`, `sysio.dclaim`, …
- **Ethereum outpost** (`anvil`) — `OPP.sol`, `OPPInbound.sol`, `OutpostManager.sol`,
`SyndicationPool.sol`, `BAR.sol`, `StakingManager.sol` (an inert placeholder) (+ `liqEth`).
- **Solana outpost** (`solana-test-validator`) — all four wire-solana Anchor programs
loaded at genesis (`liqsol_core`, which hosts the OPP outpost interface, plus
`liqsol_token` / `transfer_hook` / `validator_leaderboard`), with the liqsol
Expand Down Expand Up @@ -131,19 +132,11 @@ pnpm workspace (no nx/turbo/lerna); everything lives under `packages/`.
|---|---|---|
| `cluster-tool` | `@wireio/cluster-tool` | Core harness: process managers, chain clients, bootstrap, **`wire-cluster-tool` CLI** |
| `flow-operator-collateral-deposit` | `@wireio/test-flow-operator-collateral-deposit` | Node-operator collateral deposit + withdraw remit |
| `flow-swap-with-underwriting` | `@wireio/test-flow-swap-with-underwriting` | **Disabled at launch (reserves/swaps withheld)** — Bidirectional SWAP (ETH ↔ SOL) with underwriting |
| `flow-swap-non-native-tokens` | `@wireio/test-flow-swap-non-native-tokens` | **Disabled at launch (reserves/swaps withheld)** — SWAP of non-native tokens (USDC / USDT / LIQ) |
| `flow-swap-variance-revert` | `@wireio/test-flow-swap-variance-revert` | **Disabled at launch (reserves/swaps withheld)** — Swap variance-tolerance revert |
| `flow-batch-operator-termination` | `@wireio/test-flow-batch-operator-termination` | Batch-operator termination via delivery underperformance |
| `flow-yield-distribution` | `@wireio/test-flow-yield-distribution` | `STAKING_REWARD` (Ethereum) → `sysio.dclaim::onreward` → `fundclaim` |
| `flow-liq-syndication` | `@wireio/test-flow-liq-syndication` | Real syndication reaches the destination wallet; reported yield is fully released |
| `flow-liq-yield` | `@wireio/test-flow-liq-yield` | Syndicated liqSOL parked → linked → credited; reported yield minted, sold through `sysio.swap`, claimed as WIRE; `DESYNDICATE_LIQ` paid on the outpost |
| `flow-emissions-soak` | `@wireio/test-flow-emissions-soak` | Multi-hour emissions + `sysio.dclaim` payout soak |
| `flow-reserve-lifecycle` | `@wireio/test-flow-reserve-lifecycle` | **Disabled at launch (reserves/swaps withheld)** |
| `flow-swap-from-wire` | `@wireio/test-flow-swap-from-wire` | **Disabled at launch (reserves/swaps withheld)** |
| `flow-swap-to-wire` | `@wireio/test-flow-swap-to-wire` | **Disabled at launch (reserves/swaps withheld)** |
| `flow-swap-private-reserves` | `@wireio/test-flow-swap-private-reserves` | **Disabled at launch (reserves/swaps withheld)** |
| `flow-underwriter-slashing` | `@wireio/test-flow-underwriter-slashing` | **Disabled at launch (reserves/swaps withheld)** |
| `debugging-*` / `test-app-server` | `@wireio/debugging-*` | OPP debugging server, client tooling, TUI, shared types |

Flow packages depend on the harness via `workspace:*`.
Expand All @@ -169,7 +162,7 @@ The other seven enabled flows (`flow-batch-operator-slashing`,
`flow-operator-collateral-deposit`, `flow-producer-registration`,
`flow-yield-distribution`) submit no user LIQ syndication/desyndication. Imported
bootstrap collateral and reward funding have their own assertions. The eight
disabled swap/reserve flows remain disabled and have no direct LIQ syndication call.
former disabled swap/reserve flows have been removed.

`WireSyndicationTool.planResolveEnvelope` is an explicit `sysio.bond::rslvvalid`
shortcut for an unbonded OPEN request. It refuses provider-funded, challenged or
Expand Down Expand Up @@ -197,22 +190,11 @@ payout after the existing queued-redemption assertions. TypeScript compilation,
stopped at the bootstrap toolchain check because the shell selected Solana 4.0.3;
the successful runs above selected the installed pinned 4.2.0 toolchain explicitly.

### Disabled reserve and swap flows
### Removed reserve and swap flows

Each of the eight disabled flows opts into `enableLaunchWithheldOperations: true`
and exercises
reserves/swaps, which the launch Solana program refuses: wire-solana `89565920`
("Disable unaudited reserve and swap operations") returns `OperationDisabled`
6086 at `InitReserve` during bootstrap. There is no launch replacement for these
operations; they return when reserves/swaps are enabled after audit.

Their `package.json` live-flow script is named `test:disabled` instead of `test`.
Both local `scripts/run-flow.mjs` discovery (including exact names, short names,
regex and the picker) and CI's `run-flows.mjs` require a `test` script, so these
packages are skipped. To re-enable a flow after audit, rename `test:disabled`
back to `test` in its `package.json` (one line per flow). All packages remain in
`pnpm build`; root `pnpm test` still runs Jest and every `test:unit` script.
These eight packages currently have no unit tests.
The eight former reserve/swap flow packages, their dedicated helpers and bootstrap
flags have been deleted. The 13 remaining flows exercise supported functionality.
Syndication underwriting uses depot bond providers, without swap-underwriter daemons.

## Running flows

Expand Down Expand Up @@ -418,7 +400,7 @@ wire-cluster-tool create \
--producer-count=5 \
--node-count=1 \
--batch-operator-count=3 \
--underwriter-count=1 \
--underwriter-count=0 \
--epoch-duration-sec=60 \
--ethereum-path=/data/shared/code/wire-platform/wire-ethereum \
--solana-path=/data/shared/code/wire-platform/wire-solana \
Expand Down Expand Up @@ -486,7 +468,7 @@ command comes first).
| `--node-count` | `-n` | `1` | producer node **processes** to launch |
| `--producer-count` | `-p` | `1` | producer **accounts** to register on-chain |
| `--batch-operator-count` | `-b` | `3` | batch operators |
| `--underwriter-count` | `-u` | `1` | underwriters |
| `--underwriter-count` | `-u` | `0` | compatibility option; nonzero values are rejected |
| `--epoch-duration-sec` | | `60` | minimum epoch duration in seconds (the depot floor — `sysio.epoch::setconfig` rejects lower) |
| `--warmup-epochs` | | `1` | epochs before an operator goes `WARMUP` → `ACTIVE` |
| `--cooldown-epochs` | | `1` | epochs before an operator can deregister after `COOLDOWN` |
Expand All @@ -495,8 +477,6 @@ command comes first).
| `--terminate-max-percent-misses24h` | | — | 24h missed-delivery percentage termination threshold |
| `--terminate-window-ms` | | — | termination evaluation window in ms |
| `--bind-all` | | `false` | bind every daemon to `0.0.0.0` instead of loopback |
| `--enable-mock-reserves` | | `false` | seed the 8 mock (chain, token) PRIMARY reserves at bootstrap |
| `--enable-launch-withheld-operations` | | `false` | run the Solana outpost bootstrap calls the launch build withholds (`init_reserve`, `create_reserve_native`, mock SPL reserves); a flow that sets it (in its scenario defaults, when it needs the bootstrap-seeded Solana reserves or the mock SPL mints) requires a Solana program build without the launch restrictions, which answer these calls with `OperationDisabled` (6086). The flag does not decide which flows the launch program can run: the eight opted-in flows need withheld Solana operations, and `flow-yield-distribution` needs the withheld `add_attestation` instruction without opting in (see CLAUDE.md, "Flow authoring — launch-withheld operations") |
| `--enable-mock-liq-pools` | | `false` | seed the mock LIQETH/LIQSOL yield pools during epoch zero and fund outpost custody to back all outstanding shadow |
| `--enable-mock-syndication-import` | | `false` | import the mock bonder's LIQSOL and LIQETH positions during epoch zero, seal import, and back all mock shadow in outpost custody |
| `--api-count` | | `0` | API nodes — non-producing nodeops meshed with bios + producers, serving `/v1/chain/*` and the query engine's `POST /v1/query/execute`; never `producer_api_plugin` |
Expand Down Expand Up @@ -575,11 +555,8 @@ config; the Solana program id is parsed from the IDL):
}
```

External mode ALSO requires an EXPLICIT `--underwriter-count 0`. The flag
defaults to `1`, so omitting it asks for one underwriter — and an external
cluster has no local outpost for an underwriter to bond collateral on, so
`create` fails fast naming whichever cause applies ("you asked for N" vs "you
omitted it and got the default").
Swap-underwriter daemon counts default to zero in all deployment modes. Nonzero
values are rejected; syndication bond providers do not need a daemon.

At `create` the harness verifies the external endpoints are reachable
(`eth_chainId` matches the configured `chainId`; Solana `getVersion` responds)
Expand Down
8 changes: 4 additions & 4 deletions STYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,8 @@ const {

Notes: async defaults are fine (`const { port = await BindConfigProvider.findAvailable(…) } = options`);
a fallback to ANOTHER member destructures both then coalesces the locals
(`const { batchOperatorAccount, underwriterAccount } = node` →
`batchOperatorAccount ?? underwriterAccount`); optional chains and computed
(`const { primary, fallback } = options` →
`primary ?? fallback`); optional chains and computed
members (`arr[0] ?? x`) stay accessor-form.

### Module-level joined declarations
Expand Down Expand Up @@ -966,8 +966,8 @@ define protocol latency):
|---|---|---|
| `EpochExtensionMaxSec` (30s) | via `effectiveEpochSec()` | every N-epoch deadline: `N × (epochDurationSec + 30) × MsPerSecond` |
| `CollateralVerifyBudgetMs` (6 min) | deposit → depot verification gates |
| `SingleHopBudgetMs` (7 min) | act on an outpost, verify on the depot — or the reverse (uwreq appears, race confirms, reserve relay/READY, attestation propagation) |
| `DoubleHopBudgetMs` (14 min) | outpost → depot → outpost tails (remit/payout, SWAP_REVERT round-trips) |
| `SingleHopBudgetMs` (7 min) | act on an outpost, verify on the depot — or the reverse (a `SYNDICATE_LIQ` envelope reaches `REQUESTED`, a `DESYNDICATE_LIQ` payout reaches the outpost wallet, attestation propagation) |
| `DoubleHopBudgetMs` (14 min) | outpost → depot → outpost tails (an outpost syndication bonded and released on the depot, then redeemed back to the outpost wallet via `DESYNDICATE_LIQ`) |

Principles:

Expand Down
Loading
Loading