Skip to main content

Demo Project

A complete example project demonstrating how to use the Privacy Cash EVM SDK in a Next.js frontend: https://github.com/Privacy-Cash/base-sdk-demo-interface

Installation

npm install privacycash-evm wagmi viem @rainbow-me/rainbowkit @tanstack/react-query --save
Requires Node.js 20+. The SDK is written in TypeScript and includes type definitions.

Wallet Provider Setup

Wrap your app with Wagmi and RainbowKit providers configured for Base mainnet:
'use client'
import { RainbowKitProvider } from '@rainbow-me/rainbowkit'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider, createConfig, http } from 'wagmi'
import { base } from 'wagmi/chains'
import { walletConnect, coinbaseWallet } from 'wagmi/connectors'

const config = createConfig({
  ssr: true,
  chains: [base],
  connectors: [
    coinbaseWallet({ appName: 'Your App' }),
    walletConnect({ projectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID! }),
  ],
  transports: {
    [base.id]: http(process.env.NEXT_PUBLIC_BASE_RPC_URL),
  },
})

const queryClient = new QueryClient()

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>
      <WagmiProvider config={config}>
        <RainbowKitProvider initialChain={base}>
          {children}
        </RainbowKitProvider>
      </WagmiProvider>
    </QueryClientProvider>
  )
}

Deriving Encryption Key

Before a user can interact with Privacy Cash, they must sign an off-chain message. This signature is used to derive their private encryption key and UTXO keypair — neither key ever leaves the client.
import { useSignMessage } from 'wagmi'

const SIGN_MESSAGE = 'Privacy Money account sign in'
const LS_KEY_PREFIX = 'evm_sign_'

function saveSignature(address: string, signature: string) {
  localStorage.setItem(`${LS_KEY_PREFIX}${address}`, signature)
}

function getStoredSignature(address: string): string | null {
  return localStorage.getItem(`${LS_KEY_PREFIX}${address}`)
}

// In your component:
const { signMessage } = useSignMessage()
const { address } = useAccount()

function handleSignIn() {
  signMessage(
    { message: SIGN_MESSAGE },
    {
      onSuccess(signature) {
        saveSignature(address!, signature)
      },
    }
  )
}
Auto-prompt the user to sign when they connect their wallet:
useEffect(() => {
  if (!isConnected || !address) return
  const stored = getStoredSignature(address)
  if (!stored) handleSignIn()
}, [isConnected, address])

Circuit Key File

Place the circuit2.zkey file in your Next.js public/ folder. Pass the base path (without extension) to each SDK function:
public/
  circuit2.zkey    ← download from the SDK repo
keyBasePath: '/circuit'  // resolves to /circuit2.zkey at runtime

Common Issues

  1. Signature re-prompt on every page refresh — Store the signature in localStorage keyed by address as shown above.
  2. walletClient temporarily undefined — Use connector.getProvider() as a fallback when useWalletClient() is unavailable during initial mount.