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
44 changes: 44 additions & 0 deletions MAINNET_READINESS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Mainnet Readiness Checklist — Stellar (Soroban)

> **Related issues:**
> - [#03](https://www.drips.network/wave/contributors/issues/03-audit-stealth-sender.md) — Stealth sender atomicity audit & rescue mechanism
> - [#20](https://www.drips.network/wave/contributors/issues/20-mainnet-readiness.md) — This document

## 1. Contract Audit Status

### stealth-sender Atomicity

| Item | Status | Reference |
|---|---|---|
| `send()` atomicity audit | ✅ Passed — no gap found | [POSTMORTEMS.md](./contracts/stellar/POSTMORTEMS.md#pm-001-atomicity-of-stealth-sendersend) |
| `batch_send()` atomicity audit | ✅ Passed — no gap found | [POSTMORTEMS.md](./contracts/stellar/POSTMORTEMS.md#pm-001-atomicity-of-stealth-sendersend) |
| Rescue tool available | ✅ Built | [scripts/rescue-stealth-funds.ts](./scripts/rescue-stealth-funds.ts) |

### Verified Invariants

1. `stealth-sender::send` is atomic under the Soroban execution model.
2. No code change to `stealth-sender` was required.
3. The rescue tool provides a safety net for non-contract failure modes (direct
external transfers, operator error, theoretical chain reorg).

## 2. Contract Deployment Checklist

- [ ] `stealth-announcer` deployed and address recorded
- [ ] `stealth-registry` deployed and address recorded
- [ ] `stealth-sender` deployed, `init()` called with announcer address
- [ ] `wraith-names` deployed and address recorded
- [ ] All contract addresses published in README

## 3. Pre-Mainnet Verification

- [ ] `cargo test --workspace` passes for all Stellar contracts
- [ ] Rescue tool tested against a fixture stealth address
- [ ] All four contracts compile with `soroban-sdk` 22.0.0

## 4. Monitoring & Incident Response

| Scenario | Response |
|---|---|
| Missing announcement detected | Run `scripts/rescue-stealth-funds.ts` with sender's ephemeral key |
| Suspected atomicity breach | Investigate immediately; escalate to protocol team |
| Announcement event indexer down | Announcements are on-chain events; indexer can catch up from genesis |
164 changes: 164 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# Wraith Rescue Tool — `rescue-stealth-funds.ts`

A recovery mechanism for the hypothetical case where funds land at a stealth
address without a matching on-chain announcement.

## When to Use This

| Scenario | Example | Use Rescue Tool? |
|---|---|---|
| **Operator error** | UI sends transfer but forgets to call `stealth-sender::send` | ✅ Yes |
| **Direct external send** | Someone sends tokens directly to a stealth address | ✅ Yes |
| **Chain reorg** | Stellar ledger reorg drops the announcement tx | ✅ Yes (theoretical) |
| **Normal operation** | `stealth-sender::send` works correctly | ❌ No — everything is fine |
| **Funds already moved** | Recipient already withdrew or forwarded funds | ❌ No — would be a no-op |

## Trust Assumptions

1. **The sender MUST still have the ephemeral private key.** Without it, the
rescue tool cannot prove the connection between the stealth address and the
intended recipient. If the ephemeral key is lost, the funds are unrecoverable
(this is by design — it's what makes stealth addresses secure).

2. **The tool NEVER requests the sender's long-term spending key.** Only the
ephemeral key material is needed. If you are asked for a spending key,
you are using a modified or malicious version of this tool.

3. **The "rescue" only restores findability, not the original tx hash.** The
announcement event lets the recipient discover the payment during scanning.
The original transfer transaction hash is different from the announcement
transaction hash.

## How It Works

```
Sender's ephemeral key + Recipient's meta-address
│ │
└──────────┬─────────────┘
Compute shared secret (ECDH)
Derive stealth address
Query balance at stealth address
If balance matches expected amount
Build & broadcast announcement
via StealthAnnouncer contract
Recipient can now scan & find payment
```

## Usage

### Prerequisites

- Node.js 20+
- Access to a Stellar RPC endpoint (Horizon or Soroban RPC)
- The ephemeral private key used in the original transfer
- The recipient's 64-byte stealth meta-address

### Installation

```bash
cd scripts
npm install
```

### Running

```bash
npx tsx rescue-stealth-funds.ts \
--ephemeral-key <32-byte-hex> \
--recipient-meta-address <64-byte-hex> \
--amount <number> \
--asset <asset-id> \
--announcer <contract-id> \
--rpc <rpc-url> \
--network-passphrase "<passphrase>" \
--yes
```

### Example

```bash
npx tsx rescue-stealth-funds.ts \
--ephemeral-key 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \
--recipient-meta-address aaaa...bbbb \
--amount 100 \
--asset XLM \
--announcer CDLZFC3SYJYDKTNBT7YIJ4HPN5XKKBYYY7QB7QY7PJY7PJY7PJY7PJY \
--rpc https://horizon-testnet.stellar.org \
--network-passphrase "Test SDF Network ; September 2025" \
--yes
```

### Options

| Option | Required | Description |
|---|---|---|
| `--ephemeral-key` | ✅ | Ephemeral private key (32 bytes hex) |
| `--recipient-meta-address` | ✅ | Recipient's stealth meta-address (64 bytes hex) |
| `--amount` | ✅ | Amount of tokens sent |
| `--asset` | ✅ | Asset identifier ("XLM" or "CODE:ISSUER") |
| `--announcer` | ✅ | StealthAnnouncer contract ID or account ID |
| `--rpc` | ❌ | RPC URL (defaults to testnet) |
| `--network-passphrase` | ❌ | Network passphrase (defaults to testnet) |
| `--yes` | ❌ | Skip confirmation prompt |

## Safety Features

1. **Balance verification:** The tool queries the stealth address balance and
compares it to the expected amount. If the balance doesn't match, it warns
the user.

2. **Moved-funds detection:** If the balance is significantly lower than
expected, the tool suspects funds have been moved and refuses to proceed.

3. **Refusal on empty addresses:** If the stealth address has no funds or the
balance is zero, the tool warns and asks for confirmation.

4. **Explicit confirmation:** The `--yes` flag is required to prevent
accidental announcements.

## Testing

```bash
cd scripts
npm install
npx vitest run
```

The test suite validates:
- Parsing of 64-byte meta-addresses
- Deterministic shared secret computation
- Stealth address derivation
- Edge cases (wrong-length keys, invalid hex)
- Balance matching logic
- Announcement payload construction

## Integration with Soroban

In a production deployment, the tool would use `@stellar/stellar-sdk` to:

1. Build a Soroban transaction that calls `announce()` on the announcer contract
2. Simulate the transaction to check validity
3. Sign with the sender's key (for fee payment — never the spending key)
4. Submit the transaction to the Soroban RPC

The current version outputs the announcement payload and prepares the
transaction structure. Full Soroban RPC integration requires:
- A funded Stellar account for fee payment
- The `@stellar/stellar-sdk` library

## Linking

This tool is linked from:
- [Mainnet Readiness Doc](../MAINNET_READINESS.md)
- [POSTMORTEMS.md — PM-001/R](../stellar/POSTMORTEMS.md#pm-001r-rescue-tool-design-rationale)
Loading