Labels: Stellar Wave, stellar, feature, security, drips, help-wanted
Tier: L (1–2 weeks)
Type: feature
Context
stealth-sender::send is supposed to be atomic: either the transfer + announcement both succeed, or both fail. But Soroban's auth/CPI model is rich enough that we can construct edge cases where funds might be transferred but the announcement panics — leaving funds at a stealth address with no on-chain announcement, making them effectively unrecoverable.
The audit (#03) will tell us if any such path exists. Regardless, we should have a rescue mechanism for the worst case.
Scope
This issue has two parts: a defensive contract change and a rescue tool.
Part 1: defensive contract change
Audit stealth-sender::send to confirm atomicity holds today. If it does — and we expect it does — keep this as a documented invariant via MAINNET_READINESS.md and skip Part 2 implementation.
If atomicity does NOT hold (the audit finds a gap), close it. Document the gap and the fix in contracts/stellar/POSTMORTEMS.md.
Part 2: rescue tool
For the hypothetical case where funds land at a stealth address without a matching announcement (operator error, partial chain reorg, future bug), build:
- A CLI tool
scripts/rescue-stealth-funds.ts:
- Input: sender's wallet, expected recipient meta-address, ephemeral pubkey, amount, asset.
- Recomputes the stealth address using the SDK.
- Queries the stealth address's balance.
- If the balance matches, generates a post-hoc announcement signed by the sender and broadcasts it via the standard announcer contract.
- The recipient can then scan normally and recover.
- Documentation explaining when to use this and the trust assumptions:
- Sender must still have the ephemeral private key (or be able to regenerate it via deterministic derivation if available).
- The "rescue" only restores findability, not the original tx hash.
- Make the tool refuse to operate if the stealth address has already moved funds (it would be a no-op anyway).
Constraints
- The rescue tool must NEVER request the sender's spending key. It only needs the ephemeral key and the recipient meta-address.
- The tool must clearly disclose: "This is a recovery mechanism. The original payment is final, but the recipient can now find it."
Acceptance criteria
Why this matters
No one wants to be the team that says "your funds are lost, here's a sympathy email." Building the rescue path before we need it costs us a few days. Needing it without building it first costs us a user.
Labels:
Stellar Wave,stellar,feature,security,drips,help-wantedTier: L (1–2 weeks)
Type: feature
Context
stealth-sender::sendis supposed to be atomic: either the transfer + announcement both succeed, or both fail. But Soroban's auth/CPI model is rich enough that we can construct edge cases where funds might be transferred but the announcement panics — leaving funds at a stealth address with no on-chain announcement, making them effectively unrecoverable.The audit (#03) will tell us if any such path exists. Regardless, we should have a rescue mechanism for the worst case.
Scope
This issue has two parts: a defensive contract change and a rescue tool.
Part 1: defensive contract change
Audit
stealth-sender::sendto confirm atomicity holds today. If it does — and we expect it does — keep this as a documented invariant viaMAINNET_READINESS.mdand skip Part 2 implementation.If atomicity does NOT hold (the audit finds a gap), close it. Document the gap and the fix in
contracts/stellar/POSTMORTEMS.md.Part 2: rescue tool
For the hypothetical case where funds land at a stealth address without a matching announcement (operator error, partial chain reorg, future bug), build:
scripts/rescue-stealth-funds.ts:Constraints
Acceptance criteria
Why this matters
No one wants to be the team that says "your funds are lost, here's a sympathy email." Building the rescue path before we need it costs us a few days. Needing it without building it first costs us a user.