Skip to content

useWallet

The useWallet hook generates and manages facilitator wallets from user authentication entropy. These wallets are used for private transaction routing in Silent Swap.

Import

import { useWallet, useAuth } from '@silentswap/react';
import { useAccount, useWalletClient } from 'wagmi';

Basic Usage

import { useWallet, useAuth, useSilentClient } from '@silentswap/react';
import { useAccount, useWalletClient } from 'wagmi';
import { ENVIRONMENT } from '@silentswap/sdk';
 
function WalletComponent() {
  const { address } = useAccount();
  const { data: walletClient } = useWalletClient();
  const { connector } = useAccount();
  
  const { client } = useSilentClient({
    config: {
      environment: ENVIRONMENT.MAINNET,
    },
  });
 
  const { auth } = useAuth({
    client,
    address: address!,
    walletClient: walletClient as any,
    autoAuthenticate: true,
  });
 
  const {
    wallet,
    generateWallet,
    isLoading,
    error,
  } = useWallet({
    address: address!,
    auth: auth || undefined,
    walletClient: walletClient as any,
    connector,
  });
 
  // Auto-generate wallet when authenticated
  useEffect(() => {
    if (auth && walletClient && !wallet && !isLoading) {
      generateWallet();
    }
  }, [auth, walletClient, wallet, isLoading, generateWallet]);
 
  if (isLoading) {
    return <div>Generating wallet...</div>;
  }
 
  if (error) {
    return <div>Error: {error.message}</div>;
  }
 
  if (wallet) {
    return (
      <div>
        <p>Wallet ready with {wallet.accounts.length} accounts</p>
      </div>
    );
  }
 
  return <div>Waiting for authentication...</div>;
}

API Reference

Options

interface useWalletOptions {
  /** The user's EVM address */
  address: `0x${string}`;
  /** Authentication response from SIWE */
  auth?: AuthResponse;
  /** Wallet client for signing operations */
  walletClient?: WalletClient;
  /** Wagmi connector */
  connector?: Connector;
  /** Whether to generate all deposit accounts or just the latest */
  allDeposits?: boolean;
}

Return Value

interface useWalletReturn {
  // State
  wallet: SilentSwapWallet | null;
  isLoading: boolean;
  error: Error | null;
 
  // Methods
  generateWallet: () => Promise<void>;
  getCachedWallet: () => SilentSwapWallet | null;
  clearWallet: () => void;
  refreshWallet: () => Promise<void>;
}
 
interface SilentSwapWallet {
  entropy: Uint8Array;
  accounts: FacilitatorAccount[];
}
 
interface FacilitatorAccount {
  group: () => Promise<HdFacilitatorGroup>;
  nonce: number;
}

Wallet Generation Flow

  1. Check Cache - Look for cached wallet in sessionStorage
  2. Query Deposit Count - Get current deposit count from blockchain
  3. Generate Entropy - Sign EIP-712 document to generate entropy
  4. Create Accounts - Generate facilitator accounts based on deposit count
  5. Cache Wallet - Store wallet data in sessionStorage

Generating Entropy

The wallet entropy is generated by signing an EIP-712 document:

// This happens automatically in generateWallet()
// The hook:
// 1. Ensures we're on Ethereum mainnet
// 2. Creates EIP-712 document for wallet generation
// 3. Signs the document with walletClient
// 4. Uses signature bytes as entropy

Account Generation

Accounts are generated based on deposit count:

// If allDeposits is false (default):
// - Only generates accounts for current deposit count
// - More efficient for most use cases
 
// If allDeposits is true:
// - Generates accounts for all deposits (0 to depositCount)
// - Useful for historical deposit access

Using Facilitator Groups

Once the wallet is generated, you can access facilitator groups:

const { wallet } = useWallet({
  address: address!,
  auth,
  walletClient,
});
 
// Get facilitator group for first account
const facilitatorGroup = await wallet?.accounts[0]?.group();
 
// Export public keys for quote
const viewer = await facilitatorGroup.viewer();
const { publicKeyBytes: viewerPk } = viewer.exportPublicKey(
  '*',
  FacilitatorKeyType.SECP256K1
);
 
const groupPks = await facilitatorGroup.exportPublicKeys(
  outputs.length,
  PublicKeyArgGroups.GENERIC
);

Caching

The wallet is cached in sessionStorage:

  • Key: Based on user address
  • TTL: Session-based (cleared on browser close)
  • Format: Base93-encoded entropy + account nonces

Manual Wallet Management

const {
  generateWallet,
  getCachedWallet,
  clearWallet,
  refreshWallet,
} = useWallet({
  address: address!,
  auth,
  walletClient,
});
 
// Get cached wallet without generating
const cached = getCachedWallet();
 
// Clear wallet cache
clearWallet();
 
// Refresh wallet (clear + regenerate)
await refreshWallet();

Error Handling

const { wallet, generateWallet, error } = useWallet({
  address: address!,
  auth,
  walletClient,
});
 
const handleGenerate = async () => {
  try {
    await generateWallet();
  } catch (err) {
    console.error('Wallet generation failed:', err);
    // Handle error (show user message, retry, etc.)
  }
};
 
// Display errors
{error && (
  <div className="error">
    Wallet generation failed: {error.message}
  </div>
)}

Chain Requirements

Wallet generation requires being on Ethereum mainnet:

// The hook automatically switches to Ethereum mainnet
// if needed before generating entropy
// This is required by the protocol

Best Practices

  1. Auto-Generate - Generate wallet automatically after authentication
  2. Cache Management - Let the hook handle caching automatically
  3. Error Recovery - Provide retry mechanisms for failed generation
  4. Loading States - Show loading indicators during generation
  5. Account Selection - Use the appropriate account nonce for your use case

Next Steps