> ## Documentation Index
> Fetch the complete documentation index at: https://docs.opaque.cash/llms.txt
> Use this file to discover all available pages before exploring further.

# Send a stealth payment

> End-to-end flow to pay someone privately on Ethereum, Solana, or Starknet.

## Prerequisites

* Sender wallet funded with native asset (ETH or SOL)
* Recipient registered on the target chain (or pass their meta-address directly)
* `ethereumWalletClient` / `ethereumProvider` (EVM) or `solanaWallet` (Solana)

## High-level: one method

```ts theme={"dark"}
import { parseEther } from "viem";

const result = await client.sendStealthPayment({
  chain: "ethereum",
  recipient: "0xRecipientEoa...",   // or meta-address hex, or Solana base58
  amount: parseEther("0.01"),
  announce: true,                   // default
  relay: false,                     // set true for cross-chain UAB
});

console.log({
  stealthAddress: result.stealthAddress,
  txHash: result.txHash,
  announceTxHash: result.announceTxHash,  // Ethereum only (separate tx)
  metaAddressHex: result.metaAddressHex,
});
```

Solana bundles transfer + announce in **one** transaction (unless the announcement is
delayed, see below). Ethereum submits the transfer first, then the announce (two tx hashes).

### Delayed announcement (anonymity set)

Set `delayAnnouncement` (ms) to decouple the transfer from the announcement and break
the timing correlation between the two on-chain events:

```ts theme={"dark"}
const result = await client.sendStealthPayment({
  chain: "ethereum",
  recipient,
  amount: parseEther("0.01"),
  delayAnnouncement: 5 * 60_000,   // announce 5 minutes later
});
const announceTx = await result.announcePromise;  // keep the process alive until this resolves
```

See [Anonymity utilities](/sdk/stealth-api#anonymity-utilities) for dummy-announcement
noise as well.

### Cross-chain send

```ts theme={"dark"}
await client.sendStealthPayment({
  chain: "solana",
  recipient: recipientMetaOrPubkey,
  amount: 1_000_000n,  // lamports
  relay: true,
  batchId: 42,         // optional Wormhole nonce
});
```

## Starknet sends

Starknet is supported at **testnet-preview** maturity. `sendStealthPayment` handles
Ethereum and Solana only — Starknet sends go through a dedicated builder that returns
**unsigned** transfer + announce calls for the app's Starknet wallet to broadcast:

```ts theme={"dark"}
// buildStarknetStealthSend returns unsigned transfer + announce calls
const starknetSend = await client.buildStarknetStealthSend({
  recipient,                      // meta-address, or a Starknet registry lookup
  amount: 1_000000000000000000n,  // 1 STRK (18 decimals)
});

// The app's Starknet wallet broadcasts them (starknet.js account.execute)
await starknetAccount.execute(starknetSend.calls);
```

Enable Starknet with the `starknet: {}` client option. See [Starknet](/concepts/starknet)
for the full send flow, custody model, and preview caveats.

## Low-level: prepare + submit yourself

Use this when you need custom gas, batching, or UI control.

```ts theme={"dark"}
// 1. Resolve recipient
const { metaAddressHex } = await client.resolveRecipientMetaAddress(recipientEoa);
if (!metaAddressHex) throw new Error("Not registered");

// 2. Derive stealth material
const send = client.prepareStealthSend(metaAddressHex);
/*
  send.stealthAddress      -> fund this address
  send.ephemeralPublicKey  -> goes in announce
  send.ephemeralPrivateKey -> store if you need ghost/relay later
  send.metadata            -> view tag byte (+ PSR extension if applicable)
*/

// 3. Transfer
await walletClient.sendTransaction({
  to: send.stealthAddress,
  value: parseEther("0.01"),
  chain: sepolia,
});

// 4. Announce
const announce = client.buildAnnounceTransactionRequest(send);
await walletClient.sendTransaction({
  to: announce.to,
  data: announce.data,
  chain: sepolia,
});
```

## Cross-chain relay (manual)

```ts theme={"dark"}
const relay = await client.buildAnnounceWithRelay("ethereum", send);
await walletClient.sendTransaction({
  to: relay.to,
  data: relay.data,
  value: relay.value,
  chain: sepolia,
});
```

On Solana, `buildAnnounceWithRelay` returns instructions + extra signers (Wormhole message keypair):

```ts theme={"dark"}
const relay = await client.buildAnnounceWithRelay("solana", send);
// relay.instructions, relay.signers: co-sign with solanaWallet
```

## Sending tokens (ERC-20 / SPL)

Set `token` to send an ERC-20 (Ethereum) or SPL mint (Solana) instead of the native asset.
`amount` is the token's smallest unit (decimals-aware). The announcement is identical to a
native send, so the recipient discovers it the same way.

```ts theme={"dark"}
// USDC on Ethereum (6 decimals)
await client.sendStealthPayment({
  chain: "ethereum",
  recipient,
  token: "0xUSDC...",
  amount: 25_000000n,   // 25 USDC
});

// SPL mint on Solana (sender pays the ~0.002 SOL ATA rent for the recipient)
await client.sendStealthPayment({
  chain: "solana",
  recipient,
  token: "EPjF...USDCmint",
  amount: 25_000000n,
});
```

<Note>
  A fresh stealth address holds the token but no native gas, so the recipient cannot move it
  without help. Either set `gasDrop` to also send a little native asset to the stealth address,
  or have the recipient withdraw via a [gasless sweep](/guides/scan-and-sweep#gasless-token-sweep).
</Note>

```ts theme={"dark"}
await client.sendStealthPayment({
  chain: "ethereum",
  recipient,
  token: "0xUSDC...",
  amount: 25_000000n,
  gasDrop: parseEther("0.0005"),  // recipient can self-sweep later
});
```

## Recipient resolution

`recipient` accepts every identity form `client.resolveRecipient` understands:

| `recipient` value                                                            | Behavior                                                          |
| ---------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| meta-address, 66- or 98-byte (`0x` + 132/196 hex, `st:opq:` prefix accepted) | Validated and used directly                                       |
| Ethereum `0x` address                                                        | Registry lookup on Ethereum                                       |
| Solana base58 pubkey                                                         | Registry lookup on Solana                                         |
| `ipfs://CID`                                                                 | DID document fetch (configure `ipfs` on the client)               |
| `*.eth` name                                                                 | ENS `com.opaque.meta` text record (configure `ens` on the client) |

See [resolveRecipient](/sdk/stealth-api#resolverecipientinput) for setup details.
