Skip to content
home/guides/quickstart

Your first shielded payout.

Five minutes, one npm package and a funded testnet key. By the end you will have moved a stablecoin balance out of Robinhood Chain and into a Zcash Orchard note that no block explorer can read.

Before you start
You need Node 18+, a wallet with testnet USDG on chain 46630, and a Zcash unified address (u1…) to receive into. Any modern Zcash wallet will generate one.

1 — Install

The SDK is the only dependency. ethers is a peer dependency you probably already have; viem works equally well.

terminal
npm install @zrelay/sdk ethers

2 — Configure

There is no API key. Z-Relay runs no backend, so the SDK talks directly to the public Robinhood Chain RPC and a public lightwalletd endpoint. The only secret in your environment is your own signing key.

.env.local
# .env.local — every value is public infrastructure
RPC_URL=https://rpc.robinhoodchain.com
LIGHTWALLETD=https://zec.rocks:443
PRIVATE_KEY=0x...            # a funded testnet key, never a mainnet one
No account, no key, no rate limit tier
If a “privacy” protocol asks you to authenticate before it will talk to you, it has a log of who used it and when. Z-Relay cannot produce that log because it never sees the request.

3 — Quote the route

A quote prices the DEX hop, the relayer fee and the expected Orchard output. Quotes are short-lived by design — an expired quote fails loudly rather than settling at a price you did not agree to.

quote.ts
1const quote = await client.quote({2  token: "0xUSDG_ADDRESS",3  amount: ethers.parseUnits("2500", 6),4  pool: "orchard",5});6 7console.log(quote.estimatedZec);   // "79.12840000"8console.log(quote.relayerFee);     // "0.0015"  (0.15%)9console.log(quote.expiresAt);      // unix seconds — quotes are short-lived

4 — Shield

One call performs the approval, the swap, the escrow deposit and the gas surcharge, then waits for the relayer ring to produce the Orchard output.

shield.ts
1import { ZRelayClient } from "@zrelay/sdk";2import { ethers } from "ethers";3 4const provider = new ethers.JsonRpcProvider("https://rpc.robinhoodchain.com");5const signer = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);6 7const client = new ZRelayClient({8  chainId: 4663,            // Robinhood Chain mainnet9  signer,10});11 12// One call: swap, escrow, threshold-sign, mint into Orchard.13const settlement = await client.shield({14  token: "0xUSDG_ADDRESS",15  amount: ethers.parseUnits("2500", 6),16  recipientZAddress: "u1xyz...orchard_unified_address",17  memo: "Quarterly stock-token yield",18});19 20console.log(settlement.zcashTxId);   // 9f2a...c41d21console.log(settlement.status);      // "SETTLED"

When the promise resolves, the value exists as a shielded note. The recipient can spend it from any standard Zcash wallet — Z-Relay is not in the custody path once settlement completes.

5 — Track (optional)

For UI work, track() returns an async iterator over the cross-chain stages so you can render progress instead of a spinner.

track.ts
1const stream = client.track(settlement.trackingId);2 3for await (const update of stream) {4  console.log(update.stage, update.at);5  // EVM_SEQUENCED   → the escrow accepted the deposit6  // FROST_SIGNED    → the ring met its threshold7  // ORCHARD_INCLUDED→ the note is in a finalised Zcash block8}

Running against testnet

Point the client at chain 46630 and a testnet lightwalletd. Everything else is identical, which means the code you test is the code you ship.

testnet.ts
const client = new ZRelayClient({
  chainId: 46630,                    // Robinhood Chain Testnet
  signer,
  lightwalletd: "https://testnet.lightwalletd.com:9067",
});

Common failures

  • InsufficientGasCoverage — you sent less than the flat surcharge as msg.value. The SDK attaches it automatically; this usually means a hand-rolled transaction.
  • TransparentReceiverOnly — the unified address you supplied has no Orchard receiver. Settling it would produce a transparent payment, so the SDK refuses rather than silently de-shielding.
  • QuoteExpired — more than the quote window elapsed between quoting and executing. Re-quote; do not retry.
  • Stuck at FROST_SIGNED — the ring signed but the Zcash block has not finalised yet. This resolves on its own; the escrow timeout is the backstop.

Where to go next