@wraith-protocol/sdk/chains/stellar.
Most developers should use the Agent Client instead. These primitives are for power users building custom stealth address integrations on Stellar.
Installation
Import
Types
Key Differences from EVM
| Aspect | EVM | Stellar |
|---|---|---|
| Curve | secp256k1 | ed25519 |
| Key format | HexString (0x-prefixed) | Uint8Array (raw bytes) |
| ECDH | secp256k1.getSharedSecret | X25519 (Montgomery form) |
| Address format | 0x... (20 bytes) | G... (56 chars) |
| Pub key size | 33 bytes (compressed) | 32 bytes |
| Meta-address | st:eth:0x{66}{66} | st:xlm:{64}{64} |
| Hash function | keccak256 | SHA-256 (domain-separated) |
| Private key output | hex string | bigint scalar |
| Signing | secp256k1 ECDSA | ed25519 with raw scalar |
Constants
Functions
deriveStealthKeys(signature)
Derive spending and viewing key pairs from a 64-byte ed25519 signature.
spendingKey = SHA-256("wraith:spending:" || signature)— 32-byte seedviewingKey = SHA-256("wraith:viewing:" || signature)— 32-byte seed- Each seed is expanded via
seedToScalar()(SHA-512 + clamping) - Public keys derived via
ed25519.getPublicKey(seed)
r/s components, because ed25519 signature components don’t have the same independence.
seedToScalar(seed)
Convert a 32-byte ed25519 seed to its clamped scalar. Mirrors standard ed25519 private key expansion.
h = SHA-512(seed)— 64 bytesa = h[0:32]— lower half- Clamp:
a[0] &= 248; a[31] &= 127; a[31] |= 64 - Interpret as little-endian bigint
computeSharedSecret(privateKey, publicKey)
Compute an ECDH shared secret using X25519 (Montgomery form conversion).
privX = edwardsToMontgomeryPriv(privateKey)pubX = edwardsToMontgomeryPub(publicKey)shared = x25519.getSharedSecret(privX, pubX)
computeViewTag(sharedSecret)
Compute the view tag from a shared secret.
SHA-256("wraith:tag:" || sharedSecret)[0]
hashToScalar(sharedSecret)
Hash a shared secret to a scalar value for stealth address derivation.
SHA-256("wraith:scalar:" || sharedSecret) interpreted as little-endian bigint, reduced mod L.
generateStealthAddress(spendingPubKey, viewingPubKey, ephemeralSeed?)
Generate a one-time stealth address for a Stellar recipient.
- Generate random ephemeral ed25519 seed
- Compute shared secret via X25519 ECDH
viewTag = computeViewTag(sharedSecret)hScalar = hashToScalar(sharedSecret)stealthPoint = spendingPubKey + hScalar * G(ed25519 point addition)- Encode as Stellar
G...address viaStrKey.encodeEd25519PublicKey
checkStealthAddress(ephemeralPubKey, viewingKey, spendingPubKey, viewTag)
Check if an announcement belongs to you.
scanAnnouncements(announcements, viewingKey, spendingPubKey, spendingScalar)
Scan announcements and return matches with their private scalars.
spendingScalar (bigint), not spendingKey like in the EVM module.
deriveStealthPrivateScalar(spendingScalar, viewingKey, ephemeralPubKey)
Derive the private scalar for a specific stealth address.
signWithScalar(message, scalar, publicKey)
Sign a message using a raw scalar instead of a seed. Required because stealth private keys are derived scalars that can’t be used with Keypair.fromRawEd25519Seed().
(spendingScalar + hashScalar) % L is not necessarily clamped, so standard Stellar signing functions don’t work.
signStellarTransaction(txHash, stealthScalar, stealthPubKey)
Sign a Stellar transaction hash with a stealth private scalar.
encodeStealthMetaAddress(spendingPubKey, viewingPubKey)
Encode two 32-byte public keys into a Stellar stealth meta-address.
decodeStealthMetaAddress(metaAddress)
Decode a Stellar meta-address back into its component keys.
deriveStealthPubKey(spendingPubKey, hashScalar)
Derive a stealth public key from a spending public key and hash scalar.
pubKeyToStellarAddress(publicKey)
Convert a 32-byte ed25519 public key to a Stellar G... address.
bytesToHex(bytes) / hexToBytes(hex)
Utility functions for converting between Uint8Array and hex strings.
End-to-End Flow
Stellar-Specific Considerations
- Account creation: Stellar requires accounts to exist with a minimum balance (1 XLM). Sending to a new stealth address uses
Operation.createAccount, notOperation.payment. - Announcements: Come from Soroban contract events via
sorobanServer.getEvents(), not a subgraph. UsefetchAnnouncements("stellar")to handle this automatically. - Signing: Must use
signWithScalar()/signStellarTransaction()because stealth scalars aren’t valid seeds forKeypair.fromRawEd25519Seed().
Chain Deployments
The SDK ships with deployed contract addresses and RPC URLs for supported Stellar networks.getDeployment(chain)
Supported Stellar Networks
| Network | Status |
|---|---|
| Stellar Testnet | Live |
Fetching Announcements
fetchAnnouncements(chain?, sorobanUrl?)
Fetches all stealth address announcements from the Soroban RPC for the specified network. Handles ledger range detection and pagination automatically.
sorobanServer.getEvents() and parse XDR-encoded event data.
