Skip to main content

Overview

useChipiWallet is a convenience hook that simplifies wallet management by combining multiple operations into one:
  • Wallet fetching (replaces useGetWallet)
  • Wallet creation (replaces useCreateWallet)
  • Balance checking (replaces useGetTokenBalance)
Use this hook when you want a streamlined API. Use the individual hooks (useGetWallet, useCreateWallet, useGetTokenBalance) when you need more granular control.

Quick Start

import { useAuth } from "@clerk/nextjs";
import { useChipiWallet } from "@chipi-stack/nextjs";

function WalletComponent() {
  const { userId, getToken } = useAuth();
  
  const {
    wallet,
    hasWallet,
    balance,
    formattedBalance,
    createWallet,
    isCreating,
    isLoadingWallet,
  } = useChipiWallet({
    externalUserId: userId,
    getBearerToken: getToken,
  });

  if (isLoadingWallet) return <div>Loading...</div>;

  if (!hasWallet) {
    return (
      <button 
        onClick={() => createWallet({ encryptKey: "1234", chain: "STARKNET" })}
        disabled={isCreating}
      >
        {isCreating ? "Creating..." : "Create Wallet"}
      </button>
    );
  }

  return (
    <div>
      <p>Address: {wallet?.shortAddress}</p>
      <p>Balance: ${formattedBalance} USDC</p>
    </div>
  );
}

Configuration Options

interface UseChipiWalletConfig {
  // Required
  externalUserId: string | null | undefined;
  getBearerToken: () => Promise<string | null | undefined>;
  
  // Optional
  defaultToken?: ChainToken;  // Default: "USDC"
  enabled?: boolean;          // Default: true
}
OptionTypeDefaultDescription
externalUserIdstring | nullRequiredUser ID from your auth provider (Clerk, Firebase, etc.)
getBearerToken() => Promise<string>RequiredFunction to get the auth token
defaultTokenChainToken"USDC"Token to fetch balance for
enabledbooleantrueWhether to fetch wallet on mount

Return Values

Wallet Data

PropertyTypeDescription
walletChipiWalletData | null | undefinedWallet data with computed properties
hasWalletbooleanWhether the user has a wallet
isLoadingWalletbooleanWallet fetch loading state
walletErrorError | nullAny error from fetching

Balance Data

PropertyTypeDescription
balanceGetTokenBalanceResponse | undefinedRaw balance data
formattedBalancestringFormatted balance (e.g., “1,234.56”)
isLoadingBalancebooleanBalance fetch loading state

Create Wallet

PropertyTypeDescription
createWallet(params) => Promise<CreateWalletResponse>Create a new wallet
isCreatingbooleanCreation loading state
createdWalletCreateWalletResponse | undefinedLast created wallet data

Actions

MethodDescription
refetchWallet()Refetch wallet data
refetchBalance()Refetch balance data
refetchAll()Refetch both wallet and balance

Computed Wallet Properties

The wallet object includes these computed properties:
interface ChipiWalletData extends GetWalletResponse {
  supportsSessionKeys: boolean;  // true for CHIPI wallets
  shortAddress: string;          // Truncated address for display
}

Example: Full Implementation with Clerk

"use client";

import { useState } from "react";
import { useAuth, SignInButton, SignedIn, SignedOut } from "@clerk/nextjs";
import { useChipiWallet } from "@chipi-stack/nextjs";

export function WalletDashboard() {
  const { userId, getToken } = useAuth();
  const [pin, setPin] = useState("");
  
  const {
    wallet,
    hasWallet,
    formattedBalance,
    createWallet,
    isCreating,
    isLoadingWallet,
    refetchAll,
  } = useChipiWallet({
    externalUserId: userId,
    getBearerToken: getToken,
  });

  const handleCreateWallet = async (walletType: "CHIPI" | "READY") => {
    if (!pin || pin.length < 4) {
      alert("Please enter a 4-digit PIN");
      return;
    }
    
    try {
      const result = await createWallet({ 
        encryptKey: pin,
        chain: "STARKNET",
        walletType,
      });
      alert(`Wallet created! TX: ${result.txHash}`);
    } catch (err) {
      console.error(err);
      alert("Failed to create wallet");
    }
  };

  return (
    <div className="p-6 space-y-6">
      <SignedOut>
        <SignInButton mode="modal">
          <button className="btn">Sign In</button>
        </SignInButton>
      </SignedOut>
      
      <SignedIn>
        {isLoadingWallet ? (
          <p>Loading wallet...</p>
        ) : hasWallet ? (
          <div className="space-y-4">
            <div>
              <p className="text-sm text-gray-500">Wallet Address</p>
              <p className="font-mono">{wallet?.shortAddress}</p>
            </div>
            
            <div>
              <p className="text-sm text-gray-500">Balance</p>
              <p className="text-3xl font-bold">${formattedBalance} USDC</p>
            </div>
            
            <div>
              <p className="text-sm text-gray-500">Session Keys</p>
              <p>{wallet?.supportsSessionKeys ? "Supported" : "Not Supported"}</p>
            </div>
            
            <button onClick={() => refetchAll()} className="btn-secondary">
              Refresh
            </button>
          </div>
        ) : (
          <div className="space-y-4">
            <input
              type="password"
              placeholder="Enter 4-digit PIN"
              value={pin}
              onChange={(e) => setPin(e.target.value)}
              maxLength={4}
              className="input"
            />
            
            <div className="flex gap-2">
              <button
                onClick={() => handleCreateWallet("CHIPI")}
                disabled={isCreating}
                className="btn-primary"
              >
                Create Chipi Wallet
              </button>
              
              <button
                onClick={() => handleCreateWallet("READY")}
                disabled={isCreating}
                className="btn-secondary"
              >
                Create Argent Wallet
              </button>
            </div>
          </div>
        )}
      </SignedIn>
    </div>
  );
}

Wallet Types

When creating a wallet, you can specify the type:
TypeSession KeysDescription
CHIPI✅ YesOpenZeppelin account with SNIP-9 session key support
READY❌ NoArgent X compatible wallet
// Create a CHIPI wallet (supports session keys)
await createWallet({ 
  encryptKey: pin,
  chain: "STARKNET",
  walletType: "CHIPI" 
});

// Create a READY wallet (no session keys)
await createWallet({ 
  encryptKey: pin,
  chain: "STARKNET",
  walletType: "READY" 
});

Migration from Individual Hooks

If you’re currently using separate hooks, here’s how to migrate:

Before

const { data: wallet, isLoading } = useGetWallet({
  params: { externalUserId: userId },
  getBearerToken: getToken,
  enabled: !!userId,
});

const { createWalletAsync } = useCreateWallet();

const { data: balance } = useGetTokenBalance({
  params: { walletPublicKey: wallet?.publicKey, ... },
  getBearerToken: getToken,
  enabled: !!wallet?.publicKey,
});

After

const {
  wallet,
  hasWallet,
  balance,
  formattedBalance,
  createWallet,
  isLoadingWallet,
} = useChipiWallet({
  externalUserId: userId,
  getBearerToken: getToken,
});
useChipiWallet automatically handles the dependency chain - it only fetches balance after the wallet is loaded.