diff --git a/audit-prep/06-deployment-manifest.md b/audit-prep/06-deployment-manifest.md index 6678f96..a688543 100644 --- a/audit-prep/06-deployment-manifest.md +++ b/audit-prep/06-deployment-manifest.md @@ -31,6 +31,8 @@ The machine-readable record of every deployment, on all chains, is [`deployments | `stealth-registry` | Frozen/no upgrade path. | Verify user mappings cannot be changed by maintainers. | | `stealth-sender` | 3-of-5 multisig, 7-day timelock for upgrades, pause mechanism for emergencies. | Verify pause and upgrade powers are scoped and observable. | | `wraith-names` | 3-of-5 multisig, 7-day timelock, eventually renounceable. | Verify state migration and replay storage safety under upgrades. | +| `stealth-splitter` | Frozen/no upgrade path. | Verify no admin role, no pause, no upgrade interface; `init` only stores the announcer once. | +| `stealth-batch-sender` | No upgrade path. Pause admin set once by `init`; signer-rotation multisig set once by `init_multisig`, 7-day timelock. | Verify the multisig can only rotate its own signers and the pause admin can only pause and unpause `batch_send`. | Planned guardians from `stellar/GOVERNANCE.md`: diff --git a/audit-prep/DEPLOYMENT_MANIFEST.md b/audit-prep/DEPLOYMENT_MANIFEST.md index 2eab6a9..44c597a 100644 --- a/audit-prep/DEPLOYMENT_MANIFEST.md +++ b/audit-prep/DEPLOYMENT_MANIFEST.md @@ -163,7 +163,7 @@ soroban contract invoke \ **Purpose:** Batch operations **Dependencies:** stealth-announcer **Init Required:** Yes -**Configuration:** Announcer address +**Configuration:** Pause admin address, announcer address, optional asset policy ```bash soroban contract deploy \ @@ -173,12 +173,26 @@ soroban contract deploy \ # Returns: CONTRACT_ID_BATCH_SENDER +# Neither `init` nor `init_multisig` checks the caller (see AUTHORIZATION_MATRIX.md): +# the first call sets the value for good, so run both right after deploy. + +# `admin` is the pause admin. It cannot be changed later. soroban contract invoke \ --id CONTRACT_ID_BATCH_SENDER \ --network mainnet \ --source [DEPLOYER_SECRET_KEY] \ -- init \ + --admin [PAUSE_ADMIN_ADDRESS] \ --announcer CONTRACT_ID_ANNOUNCER + +# Signer set for signer rotation only (see Governance Configuration). +soroban contract invoke \ + --id CONTRACT_ID_BATCH_SENDER \ + --network mainnet \ + --source [DEPLOYER_SECRET_KEY] \ + -- init_multisig \ + --signers '[SIGNER_ADDRESSES]' \ + --threshold [THRESHOLD] ``` --- @@ -197,6 +211,19 @@ soroban contract invoke \ - No upgrade mechanism - Immutable forever +**stealth-splitter:** +- No admin role +- No pause +- No upgrade mechanism +- `init` stores the announcer address once; a second call returns `AlreadyInitialized` + +### Non-Upgradeable Contracts (Pause Admin) + +**stealth-batch-sender:** +- No upgrade mechanism +- **Pause admin:** one address, set once by `init`. `pause` and `unpause` stop or resume `batch_send` and nothing else. No function changes the admin after `init`. +- **Governance multisig:** the signer set and threshold are set once by `init_multisig`. The multisig only rotates its own signer set: a current signer proposes, a quorum of current signers approves, and after a 7-day timelock (`ROTATION_TIMELOCK_SECS`, ledger timestamp) a signer executes; any signer can cancel a pending rotation. It cannot pause the contract, change the pause admin, or upgrade the code. + ### Upgradeable Contracts (Multisig + Timelock) **stealth-sender:** @@ -366,7 +393,7 @@ A keeper bot will monitor and extend storage rent: ### Emergency Procedures **Scenario 1: Critical Vulnerability Discovered** -1. Pause affected contracts (if upgradeable) +1. Pause affected contracts that have a pause function 2. Notify community via status page 3. Develop and test fix 4. Deploy fix via upgrade process @@ -379,7 +406,7 @@ A keeper bot will monitor and extend storage rent: 4. Ensure adequate treasury funding **Scenario 3: Admin Key Compromise** -1. Emergency multisig rotation +1. Emergency multisig rotation. The stealth-batch-sender pause admin cannot be replaced: if that key is compromised, deploy a new batch sender and move integrations to it. 2. Audit all recent admin actions 3. Notify community 4. Investigate compromise vector @@ -436,7 +463,7 @@ sha256sum deployed.wasm If critical issues are discovered post-deployment: -### For Frozen Contracts (announcer, registry) +### For Frozen and Non-Upgradeable Contracts (announcer, registry, splitter, batch sender) **No rollback possible.** Must deploy new version with different address. **Mitigation:** diff --git a/audit-prep/README.md b/audit-prep/README.md index 2a65352..2fd8999 100644 --- a/audit-prep/README.md +++ b/audit-prep/README.md @@ -96,12 +96,12 @@ contracts/ 5. **stealth-splitter** (~300 LOC) - Payment splitting across multiple recipients - - **Status:** Upgradeable + - **Status:** Frozen (no upgrade path, no admin) - **Blast Radius:** High (handles user assets) 6. **stealth-batch-sender** (~150 LOC) - Optimized batch operations - - **Status:** Upgradeable + - **Status:** Non-upgradeable (pause admin and a signer-rotation multisig, see DEPLOYMENT_MANIFEST.md) - **Blast Radius:** High (handles user assets) ## Audit Timeline diff --git a/stellar/MIGRATION_V0_TO_V1.md b/stellar/MIGRATION_V0_TO_V1.md index 8631894..2ab6e94 100644 --- a/stellar/MIGRATION_V0_TO_V1.md +++ b/stellar/MIGRATION_V0_TO_V1.md @@ -20,8 +20,8 @@ Wraith Protocol contract architecture separates immutable core components (froze | `stealth-announcer` | **Frozen (Immutable)** | None | No | Stateless (Events Only) | | `stealth-registry` | **Frozen (Immutable)** | None | No | `persistent()` with TTL auto-extension | | `stealth-sender` | **Timelocked + Multisig** | 3-of-5 Multisig | **Yes** (`DataKey::Paused`) | `instance()` for config; token transfers | -| `stealth-batch-sender` | **Timelocked + Multisig** | 3-of-5 Multisig | **Yes** (`DataKey::Paused`) | `instance()` for config | -| `stealth-splitter` | **Timelocked + Multisig** | 3-of-5 Multisig | **Yes** (`DataKey::Paused`) | `persistent()` for split definitions | +| `stealth-batch-sender` | **Non-upgradeable (Pause Admin)** | None | **Yes** (`DataKey::Paused`, pause admin) | `instance()` for config | +| `stealth-splitter` | **Frozen (Immutable)** | None | No | `instance()` for split definitions | | `stealth-vault` | **Timelocked + Multisig** | 3-of-5 Multisig | **Yes** (`DataKey::Paused`) | `persistent()` for time-locked deposits | | `wraith-names` | **Timelocked + Multisig** | 3-of-5 Multisig | **Yes** (`DataKey::Paused`) | `persistent()` for name & reverse records | | `wraith-asset-policy` | **Admin Managed** | Admin Address | No | `instance()` admin, `persistent()` allowlist |