Skip to main content
The TypeScript SDK is WIP. Today, this flow is wired through three relayer endpoints: GET /recipient/addresses, POST /recipient/derive-stealth-key, and POST /recipient/relay-proxy (gasless sweep via the deployed Safe). Funds at a stealth address are owned by a Safe; the recipient signs a Safe tx hash with the stealth key and the relayer broadcasts.
When an intent settles, funds land at a fresh stealth address on the destination chain (and a Safe at that address holds them). The recipient detects it, derives the stealth key, signs a Safe tx, and the relayer broadcasts gas-paid. This page covers how to wire that into your app.

Detect incoming intents

Using the recipient’s viewing key, list intents addressed to them:
const incoming = await tachyon.recipient.listIncoming();
// [{ intentId, sourceAsset, destAsset, amount, settledAt, stealthAddress, ... }, ...]
The result includes both intents that have been swept and those that haven’t. Filter as needed:
const unswept = incoming.filter((i) => i.swept === false);

Sweep a single intent (gasless)

const txHash = await tachyon.recipient.sweep(intentId);
Under the hood this calls POST /recipient/relay-proxy, the recipient signs a Safe transaction with their derived stealth key, and the relayer broadcasts and pays gas. The recipient does not need native gas on the destination chain to sweep.

Auto-sweep on detection

Most integrators want to sweep on detection. The SDK exposes a long-lived listener:
tachyon.recipient.subscribe(async (intent) => {
  await tachyon.recipient.sweep(intent.intentId);
  ui.notify(`Received ${formatAmount(intent.amount, intent.destAsset)}`);
});
This runs as long as your app is open. For server-side persistence, use a polling job:
setInterval(async () => {
  const incoming = await tachyon.recipient.listIncoming({ unsweptOnly: true });
  for (const intent of incoming) {
    await tachyon.recipient.sweep(intent.intentId);
  }
}, 30_000);

Sweep behavior

  • Sweep target: wherever the recipient’s Safe transaction sends, typically their main wallet on the destination chain.
  • Asset: the destination asset of the intent (tokenOut).
  • Privacy on the sweep: the sweep transaction is a normal on-chain transfer. Observers see it. The link from sender to recipient is still hidden, they only see the stealth-address Safe sending to the recipient’s destination.
  • Gas: paid by the relayer when you use POST /recipient/relay-proxy. The recipient does not need native gas on the destination chain for a relay-proxy sweep.

What if the recipient isn’t using a Tachyon-aware app?

The funds are still under the recipient’s control, the stealth key is derived from their viewing/spending keys, and the Safe at that stealth address holds the funds. Without an SDK-aware app, they won’t auto-sweep, but they can: There is no separate hosted “claim” URL, the recipient dashboard at testnet.app.tachyon.pe surfaces incoming stealth balances and offers a one-click sweep.

Handling failed sweeps

If a sweep transaction reverts (e.g., out of gas), the funds stay at the stealth address. Retry with more gas:
try {
  await tachyon.recipient.sweep(intentId);
} catch (err) {
  // Relay-proxy sweeps can fail if the Safe tx reverts on destination chain.
  // The funds stay safe at the stealth Safe, retry or investigate the target call.
  console.error("sweep failed:", err.code, err.message);
}

Error reference

Full list of SDK error codes.