useBalances Hook
TheuseBalances hook provides reactive balance data with automatic formatting.
Basic Usage
Copy
import { useBalances } from '@testinprod-io/privacy-boost-react';
function BalanceDisplay() {
const { balances, loading, lastSynced } = useBalances();
if (loading) return <div>Loading...</div>;
return (
<ul>
{balances.map((balance) => (
<li key={balance.tokenAddress}>
{balance.symbol}: {balance.formattedShielded}
</li>
))}
</ul>
);
}
Return Value
Copy
interface UseBalancesResult {
// Reactive balance data
balances: FormattedBalance[];
loading: boolean;
lastSynced: number | null;
// Query functions
getBalance(tokenAddress: string): FormattedBalance | undefined;
getShieldedBalance(tokenAddress: string): bigint;
getWalletBalance(tokenAddress: string): bigint;
// Computed values
totalShielded: bigint;
tokenCount: number;
}
FormattedBalance Type
Copy
interface FormattedBalance extends TokenBalance {
tokenAddress: Hex;
shielded: bigint;
wallet: bigint;
symbol?: string;
decimals?: number;
// Pre-formatted strings
formattedShielded: string; // e.g., "1.5"
formattedWallet: string; // e.g., "2.3"
}
State Properties
| Property | Type | Description |
|---|---|---|
balances | FormattedBalance[] | All token balances |
loading | boolean | Currently syncing |
lastSynced | number | null | Last sync timestamp |
totalShielded | bigint | Sum of all shielded balances |
tokenCount | number | Non-zero token count |
Query Functions
getBalance(tokenAddress)
Get formatted balance for a specific token:
Copy
const { getBalance } = useBalances();
const usdcBalance = getBalance('0x...usdc');
if (usdcBalance) {
console.log(`USDC: ${usdcBalance.formattedShielded}`);
}
getShieldedBalance(tokenAddress)
Get raw shielded balance:
Copy
const { getShieldedBalance } = useBalances();
const shielded = getShieldedBalance('0x...usdc');
// Returns: bigint (e.g., 1500000n for 1.5 USDC)
getWalletBalance(tokenAddress)
Get raw wallet balance:
Copy
const { getWalletBalance } = useBalances();
const wallet = getWalletBalance('0x...usdc');
Examples
Balance List
Copy
function BalanceList() {
const { balances, loading, totalShielded, tokenCount } = useBalances();
if (loading) {
return <div>Loading balances...</div>;
}
if (balances.length === 0) {
return <div>No tokens found</div>;
}
return (
<div>
<h3>{tokenCount} tokens</h3>
<table>
<thead>
<tr>
<th>Token</th>
<th>Shielded</th>
<th>Wallet</th>
</tr>
</thead>
<tbody>
{balances.map((b) => (
<tr key={b.tokenAddress}>
<td>{b.symbol}</td>
<td>{b.formattedShielded}</td>
<td>{b.formattedWallet}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
Single Token Balance
Copy
function TokenBalance({ tokenAddress }: { tokenAddress: string }) {
const { getBalance } = useBalances();
const balance = getBalance(tokenAddress);
if (!balance) {
return <span>-</span>;
}
return (
<span>
{balance.formattedShielded} {balance.symbol}
</span>
);
}
Balance Summary Card
Copy
function BalanceSummary() {
const { balances, totalShielded, loading } = useBalances();
// Filter non-zero balances
const nonZeroBalances = balances.filter(
(b) => b.shielded > 0n || b.wallet > 0n
);
return (
<div className="balance-summary">
{loading && <span className="syncing">Syncing...</span>}
<h4>Your Privacy Balance</h4>
{nonZeroBalances.length === 0 ? (
<p>No tokens. Deposit to get started.</p>
) : (
nonZeroBalances.map((b) => (
<div key={b.tokenAddress} className="balance-item">
<span className="symbol">{b.symbol}</span>
<span className="amount">{b.formattedShielded}</span>
</div>
))
)}
</div>
);
}
Balance with Refresh
Copy
function RefreshableBalance() {
const { balances, loading, lastSynced } = useBalances();
const { syncAllBalances } = useVault();
const [refreshing, setRefreshing] = useState(false);
const handleRefresh = async () => {
setRefreshing(true);
await syncAllBalances();
setRefreshing(false);
};
return (
<div>
<div className="header">
<h3>Balances</h3>
<button onClick={handleRefresh} disabled={refreshing || loading}>
{refreshing ? 'Syncing...' : 'Refresh'}
</button>
</div>
{lastSynced && (
<small>
Last updated: {new Date(lastSynced).toLocaleTimeString()}
</small>
)}
<ul>
{balances.map((b) => (
<li key={b.tokenAddress}>
{b.symbol}: {b.formattedShielded}
</li>
))}
</ul>
</div>
);
}
Conditional Rendering
Copy
function DepositPrompt({ tokenAddress }: { tokenAddress: string }) {
const { getShieldedBalance } = useBalances();
const balance = getShieldedBalance(tokenAddress);
if (balance > 0n) {
return null;
}
return (
<div className="deposit-prompt">
<p>You have no shielded tokens.</p>
<button>Make your first deposit</button>
</div>
);
}
Polling for Updates
Copy
function AutoRefreshBalances() {
const { syncAllBalances } = useVault();
useEffect(() => {
// Refresh every 30 seconds
const interval = setInterval(() => {
syncAllBalances();
}, 30000);
return () => clearInterval(interval);
}, [syncAllBalances]);
return <BalanceList />;
}