Stealth address smart contracts for the Wraith Protocol multichain privacy platform. EVM contracts in Solidity (Hardhat), Stellar contracts in Soroban/Rust, Solana programs in Anchor/Rust, CKB scripts in Rust (RISC-V).
Every payment generates a fresh one-time stealth address so on-chain observers cannot link sender, recipient, or transaction history.
| Contract | Description |
|---|---|
| ERC5564Announcer | Minimal singleton that emits Announcement events per ERC-5564. No storage, no access control. |
| ERC6538Registry | Stealth meta-address registry per ERC-6538. Supports direct registration and delegated registration via EIP-712 signatures with replay-protected nonces. |
| WraithSender | Atomically transfers ETH or ERC-20 tokens to a stealth address and publishes an announcement in a single transaction. Supports batch sends and optional ETH gas tips. |
| WraithNames | Privacy-preserving .wraith name registry. Maps human-readable names to stealth meta-addresses with ownership proven via secp256k1 spending key signatures. |
| WraithWithdrawer | EIP-7702 delegation target for gas-sponsored stealth address withdrawals. A sponsor pays gas on behalf of the stealth address holder. |
| Contract | Description |
|---|---|
| stealth-announcer | Emits stealth address announcement events. No storage. |
| stealth-registry | Maps addresses to 64-byte stealth meta-addresses with auth-gated registration. |
| stealth-sender | Atomic token transfer + announcement via the announcer contract. Supports batch sends. |
| wraith-names | Name registry with SHA-256 hashed storage keys, reverse lookup, and lowercase alphanumeric validation (3-32 chars per label). Supports one level of hierarchical subdomains (sub.parent), where only the current owner of the parent name may register, update, or release subdomains under it. |
A name is either a flat label (alice) or a subdomain (payments.alice). Each
dot-separated label is validated independently (3-32 chars, lowercase
alphanumeric); at most one level of nesting is allowed (a.b.c is rejected with
NameTooDeep).
- Delegation — A subdomain can only be registered when its parent name already exists, and only the current owner of the parent may register, update, or release subdomains under it. The owner address is re-read from the parent on every management call, so a change of parent ownership transfers control of its subdomains.
- Resolution —
resolve("payments.alice")returns the subdomain's own meta-address, but walks to the parent first: ifalicehas been released the subdomain no longer resolves (NameNotFound). - Migration-safe — Existing flat names are unaffected; they register with no parent linkage and behave exactly as before.
SDK follow-up: the off-chain resolver needs to split
sub.parent.wraithinto labels and callresolvewithsub.parent. Tracked as a separate SDK issue.
Stellar design notes:
stellar/EVENT_TOPIC_DESIGN.mddocuments the proposed indexed-topic strategy forstealth-announcer.
| Program | Description |
|---|---|
| wraith-announcer | Stateless event emitter for stealth address announcements via Anchor emit!(). |
| wraith-sender | Atomic SOL transfer + announcement in one instruction. Also supports SPL token sends. |
| wraith-names | PDA-based name registry. Names are 3-32 chars (lowercase alphanumeric/hyphens), stored as PDA seeds. |
| Script | Description |
|---|---|
| wraith-stealth-lock | Lock script that verifies secp256k1 signatures against blake160(stealth_pubkey) in args[33:53]. Embeds the ephemeral public key in args[0:33] — the Cell itself is the announcement. Delegates to on-chain ckb-auth via exec_cell. |
| wraith-names-type | Type script for .wraith name registration cells. Validates 66-byte cell data (spending + viewing public keys). Ownership proven by the cell's lock script. Supports create, update, and release (destroy). |
Before deploying, validate the target network is reachable and configured correctly:
``` ./scripts/check-network.sh testnet ```
Checks passphrase config, RPC reachability, friendbot (testnet/futurenet), and that
the deploying identity exists. deploy.sh runs this automatically as its first step.
- Node.js 22+
- Rust toolchain with
cargo - Anchor CLI and Solana CLI (for Solana programs)
riscv64-elf-gcccross-compiler (for CKB scripts)
cd evm
npm install
npx hardhat compile
npx hardhat testcd stellar
cargo test --workspaceThe Stellar Soroban crates include proptest integration tests in each crate's tests/properties.rs. They cover event emission, register/lookup round-trips, invalid input rejection, batch-send invariants, and name lifecycle behavior.
cd stellar
cargo test --workspace --test properties
WRAITH_PROPTEST_CASES=16384 cargo test --workspace --test propertiesBy default each property runs at least 1,024 generated cases. The scheduled stellar-nightly CI job raises that to 16,384 cases through WRAITH_PROPTEST_CASES. Add new properties beside the contract they cover so failures point directly at the affected crate.
TypeScript bindings for the Stellar/Soroban contracts are automatically generated under stellar/bindings/typescript/ and checked into the repository. These provide type-safe, compiled TS clients that the SDK can import directly.
To regenerate the bindings locally (offline using compiled .wasm files):
- Install Node.js dependencies at the repository root:
pnpm install
- Compile the contracts to WASM (this is also done automatically by the script if WASM files are missing):
cd stellar && cargo build --target wasm32-unknown-unknown --release && cd ..
- Run the bindings generator script from the root:
pnpm bindings:stellar
To generate the bindings against live deployed contract IDs on testnet:
- Specify the contract IDs in
stellar/contract-ids.jsonor as environment variables (e.g.,STEALTH_REGISTRY_CONTRACT_ID=...). - Run the generation script from the root:
pnpm bindings:stellar
When to Regenerate: You must regenerate and commit the updated bindings whenever:
- You modify any Soroban contract function signatures, events, or custom types in Rust.
- A new contract deployment is made on testnet and you want to update the bindings' target client references.
cd solana
anchor build
anchor testcd ckb
make buildevm/
contracts/ # Solidity sources
test/ # Hardhat + Chai tests
scripts/deploy.ts # Deployment script
stellar/
stealth-announcer/ # Soroban contract
stealth-registry/ # Soroban contract
stealth-sender/ # Soroban contract
wraith-names/ # Soroban contract
solana/
programs/
wraith-announcer/ # Anchor program
wraith-sender/ # Anchor program
wraith-names/ # Anchor program
tests/ # TypeScript tests
ckb/
contracts/
wraith-stealth-lock/ # CKB lock script (RISC-V)
wraith-names-type/ # CKB type script (RISC-V)
testnet.toml # Deployed code hash and cell deps
| Contract | Address |
|---|---|
| ERC5564Announcer | TBD |
| ERC6538Registry | TBD |
| WraithSender | TBD |
| WraithNames | TBD |
| WraithWithdrawer | TBD |
| Contract | Contract ID |
|---|---|
| stealth-announcer | TBD |
| stealth-registry | TBD |
| stealth-sender | TBD |
| wraith-names | TBD |
| Contract | Pausable | Admin |
|---|---|---|
| stealth-announcer | No | N/A |
| stealth-registry | Yes | upgrade admin |
| stealth-sender | Yes | upgrade admin |
| wraith-names | Yes | upgrade admin |
See stellar/PAUSE.md for full pattern docs.
| Program | Program ID |
|---|---|
| wraith-announcer | 9Ko7TuXHpLUH1ZsZWQEpeA9Tv7hX325ooWk5SD7Y9nuq |
| wraith-sender | E6J7GBSTjKbYANWjfTo5HfnXZ4Tg3LAasN7NrvCwn5Dq |
| wraith-names | 4JrrQh5aK7iLvx6MgtEQk7K7X3SsWfTLxVJu1jXEwNjD |
| Script | Code Hash | Cell Dep |
|---|---|---|
| wraith-stealth-lock | 0x31f6ab9c7e7a26ecba980b838ac3b5bd6c3a2f1b945e75b7cf7e6a46cb19cb87 |
0xde1e8e4bed2d1d7102b9ad3d7a74925ace007800ae49498f9c374cb4968dd32b:0 |
| wraith-names-type | 0xc133817d433f72ea16a2404adaf961524e9572c8378829a21968710d6182e20d |
0x9acd640d35eadd893b358dddd415f4061fe81cb249e8ace51a866fee314141b8:0 |
| ckb-auth (dependency) | 0x0915983bb31584df4566e0946fd00ef1e9a75ad37a39ce70fec9b5cbf3b87021 |
0xa0e99b29fd154385815142b76668d5f4ecf30ae85bc2942bd21e9e51b9066f97:0 |
MIT