Skip to main content

Multi-Chain

This guide covers using the useChain hook and ChainClient to build React applications that operate across multiple blockchains.
For an overview of multi-chain concepts, see Multi-Chain Concepts.

The useChain Hook

useChain returns a ChainClient for a specific chain, memoized to prevent unnecessary re-renders:
import { useChain } from '@testinprod-io/privacy-boost-react';

function MyComponent() {
  const arbitrum = useChain({ indexerUrl: 'https://arb.example.com' });

  if (!arbitrum) return <div>Loading SDK...</div>;

  return <div>Chain ID: {arbitrum.chainId}</div>;
}
useChain returns null if the parent SDK is not yet initialized. Chain clients are cached by indexerUrl, so calling useChain with the same URL in multiple components returns the same instance.

Setup

Wrap your app with PrivacyBoostProvider as usual. The provider initializes the parent SDK, and useChain creates chain clients from it:
import { PrivacyBoostProvider } from '@testinprod-io/privacy-boost-react';

function App() {
  return (
    <PrivacyBoostProvider config={{
      indexerUrl: 'https://op.example.com',
      appId: 'my-app',
    }}>
      <MultiChainApp />
    </PrivacyBoostProvider>
  );
}

Authentication

Each chain client must be authenticated independently. Use the wallet adapter from useAuth or create one manually:
import { useChain, useAuth } from '@testinprod-io/privacy-boost-react';
import { useState } from 'react';

function ChainConnect({ indexerUrl, name }: { indexerUrl: string; name: string }) {
  const chain = useChain({ indexerUrl });
  const [authenticated, setAuthenticated] = useState(false);

  const connect = async () => {
    if (!chain) return;
    await chain.authenticate(walletAdapter);
    setAuthenticated(true);
  };

  if (!chain) return <div>Loading...</div>;

  if (!authenticated) {
    return <button onClick={connect}>Connect to {name}</button>;
  }

  return (
    <div>
      <p>Connected to {name} (chain {chain.chainId})</p>
      <ChainOperations chain={chain} />
    </div>
  );
}

Multi-Chain Dashboard

Here’s a pattern for building a multi-chain dashboard:
import { useChain } from '@testinprod-io/privacy-boost-react';

const CHAINS = [
  { name: 'Arbitrum', indexerUrl: 'https://arb.example.com' },
  { name: 'Base', indexerUrl: 'https://base.example.com' },
  { name: 'Optimism', indexerUrl: 'https://op.example.com' },
];

function MultiChainDashboard() {
  return (
    <div>
      {CHAINS.map((chain) => (
        <ChainPanel key={chain.indexerUrl} {...chain} />
      ))}
    </div>
  );
}

function ChainPanel({ name, indexerUrl }: { name: string; indexerUrl: string }) {
  const chain = useChain({ indexerUrl });

  if (!chain) return <div>{name}: Loading...</div>;
  if (!chain.isAuthenticated) return <div>{name}: Not connected</div>;

  return (
    <div>
      <h3>{name}</h3>
      <ChainBalances chain={chain} />
      <ChainDeposit chain={chain} />
    </div>
  );
}

Chain-Scoped Components

Build reusable components that accept a ChainClient:

Balance Display

import type { ChainClient } from '@testinprod-io/privacy-boost-react';
import { useState, useEffect } from 'react';

function ChainBalances({ chain }: { chain: ChainClient }) {
  const [balance, setBalance] = useState<bigint>(0n);

  useEffect(() => {
    chain.vault.getBalance('0x...token').then(setBalance);
  }, [chain]);

  return <p>Shielded: {balance.toString()}</p>;
}

Deposit Form

import type { ChainClient } from '@testinprod-io/privacy-boost-react';
import { useState } from 'react';

function ChainDeposit({ chain }: { chain: ChainClient }) {
  const [amount, setAmount] = useState('');
  const [loading, setLoading] = useState(false);

  const handleShield = async () => {
    setLoading(true);
    try {
      await chain.vault.shield({
        tokenAddress: '0x...',
        amount: BigInt(amount),
      });
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      <input value={amount} onChange={(e) => setAmount(e.target.value)} />
      <button onClick={handleShield} disabled={loading}>
        {loading ? 'Depositing...' : 'Deposit'}
      </button>
    </div>
  );
}

Transfer Form

function ChainTransfer({ chain }: { chain: ChainClient }) {
  const [to, setTo] = useState('');
  const [amount, setAmount] = useState('');

  const handleSend = async () => {
    await chain.vault.send({
      to,
      tokenAddress: '0x...',
      amount: BigInt(amount),
    });
  };

  return (
    <div>
      <input value={to} onChange={(e) => setTo(e.target.value)} placeholder="Privacy address" />
      <input value={amount} onChange={(e) => setAmount(e.target.value)} placeholder="Amount" />
      <button onClick={handleSend}>Send</button>
    </div>
  );
}

Chain Switching

Build a chain selector that lets users switch between chains:
import { useChain } from '@testinprod-io/privacy-boost-react';
import { useState } from 'react';

const CHAINS = {
  arbitrum: { name: 'Arbitrum', indexerUrl: 'https://arb.example.com' },
  base: { name: 'Base', indexerUrl: 'https://base.example.com' },
};

function ChainSwitcher() {
  const [selected, setSelected] = useState<keyof typeof CHAINS>('arbitrum');
  const chain = useChain(CHAINS[selected]);

  return (
    <div>
      <select value={selected} onChange={(e) => setSelected(e.target.value as keyof typeof CHAINS)}>
        {Object.entries(CHAINS).map(([key, { name }]) => (
          <option key={key} value={key}>{name}</option>
        ))}
      </select>

      {chain && <ChainOperations chain={chain} />}
    </div>
  );
}

Available Hooks

HookPurpose
useChain(config)Get a ChainClient for a specific chain
useAuth()Wallet connection and authentication (primary chain)
useVault()Vault operations (primary chain)
useBalances()Reactive balances (primary chain)
useTransactions()Transaction history (primary chain)
usePrivacyBoost()Direct SDK access
useAuth, useVault, useBalances, and useTransactions operate on the primary chain configured in the provider. For other chains, use useChain and access resources directly via the ChainClient (e.g., chain.vault, chain.transactions).

Next Steps