Testnet guide

Privé runs on Robinhood Chain testnet (chain id 46630). This page walks you from an empty wallet to a private withdrawal: add the network, get gas, mint test USDG, deposit into the shielded pool, back up your notes, then withdraw to a fresh address with a proof generated in your browser. Everything here uses testnet assets only.

Testnet only. The USDG on chain 46630 is MockUSDG, a test token with an open mint function. It is play money with no value. The contracts are not audited and there is no mainnet deployment. The compliance layer (ASP, deposit screening, proof-of-innocence) is Planned and is not enforced by the withdraw circuit today. See Compliance model and Security and risk.

Network and contracts

FieldValue
Network nameRobinhood Chain Testnet
Chain id46630 (hex 0xB626)
Gas currencyETH (18 decimals)
RPChttps://rpc.testnet.chain.robinhood.com/rpc
Explorerexplorer.testnet.chain.robinhood.com
Gas faucetfaucet.testnet.chain.robinhood.com

The deployed contracts on chain 46630:

ContractAddress
PrivacyPool0xd62C837a70b9552637C8ee1681fb09b459648181
WithdrawVerifier (Groth16)0xBAFE6434C40e5582b11bA90cFd6cA1f5ebd904BF
MockUSDG (6 decimals)0xF47593cac046C3a4C15B495eDAd59DE5868B6BbB

1. Add the network to your wallet

You do not have to add it by hand. The app requests the connection directly on chain 46630, so most wallets (MetaMask, Coinbase Wallet, other injected wallets) will prompt you to add or switch to Robinhood Chain Testnet the moment you connect. If your wallet ends up on the wrong chain anyway, the console shows a Switch network button and also fires the switch request once automatically.

If you prefer to add it manually, create a custom network with the chain id, RPC and explorer from the table above. The currency symbol is ETH.

2. Get testnet ETH for gas

Every on-chain action (mint, approve, deposit, self-submitted withdraw) costs gas in Robinhood Chain testnet ETH. Request it from the official faucet. A small amount is enough for a full run through this guide. If you plan to use only the gasless relayer for withdrawals, you still need a little ETH for the mint, approve and deposit steps, which are signed by your own wallet.

3. Mint test USDG

Open the app and connect. The Test USDG faucet card calls MockUSDG.mint and sends 1,000 USDG to your connected address. USDG has 6 decimals, so 1,000 USDG is 1000000000 base units. The mint is open to anyone: this is exactly why the token is testnet only and never deployed to mainnet.

4. Deposit into the shielded pool

Go to Deposit, choose Add to my balance, and enter an amount. The app generates a fresh note locally (a random nullifier and secret), derives precommitment = Poseidon(nullifier, secret), and then asks your wallet to sign two transactions:

  1. approve: allow the pool to pull the USDG amount.
  2. deposit(value, precommitment): the pool assigns an on-chain label, inserts commitment = Poseidon(value, label, precommitment) into the LeanIMT Merkle tree, and emits Deposited.

Only after the deposit transaction confirms does the app read the label from the event, finalize the note and store it. The note lives in this browser’s localStorage, namespaced by chain id and pool address. It never touches a server. It is the only key to those funds.

5. Back up your notes immediately

Do this before anything else. Privé is non-custodial and there is no recovery path. If you clear site data, switch browsers, use a private window, or lose the device, the funds behind an unbacked note are gone permanently. No support team can restore them.

Two backups are available and you should take both:

  • The deposit screen offers Download note / Copy note JSON for the single note you just created.
  • The Back up your balance card exports your whole note set as an encrypted file, prive-backup-46630.prive. The passphrase is stretched with PBKDF2 (200,000 iterations, SHA-256) and the payload is sealed with AES-GCM-256. The passphrase is never stored and cannot be recovered: keep the file and the passphrase together, both are required to restore.

6. Withdraw to a fresh address

Under Send, enter an amount and a recipient. Use an address with no history tied to you: the unlinkability comes from the proof, but a recipient address you have already funded from your public wallet leaks the link anyway.

The app syncs the commitment tree from on-chain events, builds the inclusion proof, and generates a Groth16 proof with snarkjs inside your browser. Expect a few seconds. The on-chain WithdrawVerifier checks it, the pool spends the note’s nullifier hash (blocking any double spend), inserts a change note for the remainder, and pays out. Partial withdrawals are supported: the change note is saved back under Notes. Open the transaction hash in the explorer to see the payout land at the recipient with no on-chain link to your deposit.

7. Send with a claim link

Pick Create claim-link on the deposit screen to fund a private envelope for someone who has no wallet set up yet. The app produces a URL whose fragment carries the note secret, for example /claim#v=1&c=46630&p=0x...&n=...&s=.... The secret lives in the fragment, so it is never sent to a server or written to a web log.

Anyone holding that link can claim the funds, so share it over a private channel. The recipient opens it, connects a wallet, optionally picks a different fresh address, and claims: that is a full private withdraw of the note, proof included. Until it is claimed, the link stays under Send in Sent / unclaimed, where you can copy it again or reclaim the funds to your own wallet.

8. Gasless withdrawal via the relayer

Live A relayer (/api/relay) can submit the withdrawal for you, so the recipient never needs ETH. The fee is paid in USDG out of the withdrawn amount, with a floor of 0.05 USDG, and the recipient receives the remainder. The fee split is bound into the proof context, so the relayer cannot alter the fee or the recipient after the fact: any tampering reverts on-chain.

Use it when the recipient address is brand new, or when a claim-link recipient has no gas at all. The relayer simulates the call before broadcasting and rate-limits requests. If it is unavailable or rejects the request, the app quietly falls back to self-submit, which needs ETH in your connected wallet.

Troubleshooting

Wallet is on the wrong network

The console will not show your balance until the wallet is on chain 46630. If you dismissed the automatic switch prompt, use the Switch network button, or select Robinhood Chain Testnet manually in the wallet.

The official RPC hostname is blocked

Some ISPs and DNS resolvers do not resolve rpc.testnet.chain.robinhood.com. Symptoms: the wallet reports the network as unreachable, balances never load, or transactions never broadcast. The app reads chain state directly from that endpoint in your browser, so a block affects both the wallet and the app. Work around it by pointing your wallet’s network entry at any other RPC endpoint that serves chain 46630, and by changing DNS resolver or network if the block is at the DNS level. If you run the app yourself, set NEXT_PUBLIC_RPC_URL to the alternative endpoint.

Proof generation is slow the first time

The first withdrawal in a session downloads the circuit wasm and the proving key, then runs the prover on your CPU. The first run is the slowest. Subsequent proofs in the same session are faster. Keep the tab open and let it finish. On a low-powered phone this can take noticeably longer than on a laptop.

The note did not appear after depositing

A note is only finalized once the deposit transaction confirms, because the label comes from the on-chain Deposited event. If you close the tab while the deposit is still pending, the app has no confirmed label to store. Wait for the confirmation before navigating away.

The amount is larger than any single note

The circuit spends one note and produces one change note, so a single send cannot exceed the value of your largest unspent note. The app shows that ceiling as Available to send. Note consolidation is not implemented yet: for now, deposit in the sizes you expect to send.

What is not live yet

Be clear about the limits before you draw conclusions from testnet. The withdraw circuit today proves membership in the pool’s state tree and nothing else: there is no association-set constraint in it. Deposit screening, the approved-set root and proof-of-innocence membership are Planned and are targeted to land with the mainnet audit. The TypeScript SDK lives in the repository but is not published to npm. There is no mainnet deployment, and nothing here has been audited.