For the complete documentation index, see llms.txt. This page is also available as Markdown.

First confidential dApp

End-to-end tutorial building a token dashboard with React, wagmi, and the Zama React SDK.

We'll build a token dashboard that shows a confidential balance, lets users shield tokens, transfer privately, and unshield. The finished app uses React, wagmi, and the Zama React SDK.

What you'll build

A single-page dashboard where a connected wallet can manage confidential ERC-20 tokens -- shield, view balance, transfer, and unshield -- all from one screen.

Prerequisites

  • Node.js 18+

  • A wallet browser extension (MetaMask or similar)

  • Testnet ETH on Sepolia

  • An encrypted ERC-20 token address deployed on Sepolia

1. Create the project

Scaffold a new Vite project with React and TypeScript:

pnpm create vite@latest my-confidential-dapp -- --template react-ts
cd my-confidential-dapp

2. Install dependencies

pnpm add @zama-fhe/sdk @zama-fhe/react-sdk @tanstack/react-query wagmi viem

@zama-fhe/react-sdk provides React hooks. Core SDK symbols (classes, types, chain presets, relayer factories) are imported from @zama-fhe/sdk directly.

3. Configure wagmi and the SDK

Create src/config.ts. This file sets up wagmi, the signer, and the relayer -- the three pieces every Zama app needs.

Replace YOUR_KEY with your Infura (or Alchemy) project ID, and update the relayer URL to point at your backend proxy. See the Authentication guide for proxy setup details.

4. Create the App layout with providers

Replace the contents of src/App.tsx. We wrap the app in three providers: wagmi for wallet state, React Query for async caching, and ZamaProvider for FHE operations. The Zama config is built by createConfig from @zama-fhe/react-sdk/wagmi, which derives the signer from your wagmi config so it tracks connection state automatically.

5. Build the balance display

Create src/BalanceDisplay.tsx. The useConfidentialBalance hook decrypts the on-chain balance. It polls the encrypted value cheaply and only triggers full decryption when the balance changes.

The first call prompts the wallet for a signature to generate FHE decrypt permits. Subsequent calls reuse cached permits silently.

6. Add shielding

Create src/ShieldForm.tsx. Shielding converts public ERC-20 tokens into their encrypted form. The SDK handles the ERC-20 approval automatically.

After a successful shield, the balance display updates automatically -- mutation hooks invalidate the relevant caches.

7. Add confidential transfers

Create src/TransferForm.tsx. The transfer amount is encrypted before it reaches the chain. Nobody can see how much was sent.

8. Add unshielding

Create src/UnshieldForm.tsx. Unshielding withdraws confidential tokens back to public ERC-20. This is a two-step on-chain process (unwrap + finalize), but the hook orchestrates it in a single call. We use progress callbacks to update the UI.

See Hooks > useUnshield for the full callback reference.

9. Add error handling

Create src/ErrorMessage.tsx. The matchZamaError utility maps SDK error codes to user-friendly messages without long instanceof chains. See Error Handling for the full list of error codes.

Use this component alongside any mutation hook. Pass the hook's error property:

10. Wire it up

Create src/Dashboard.tsx to bring all components together.

Start the dev server:

Open the app in your browser, connect your wallet, and try the full flow: shield some tokens, check the balance, send a confidential transfer, then unshield.

Next steps

Last updated