Components/Wallet
TokenBalance
Display token balances with icons and formatted values for BSV20, BSV21, and other token standards.
Display token balances with icons and formatted values for BSV20, BSV21, and other token standards. Features real-time price data, portfolio tracking, and interactive token management.
Installation
npm install bigblocksUsage
import { TokenBalance } from 'bigblocks';
export default function WalletTokens() {
const tokens = [
{
symbol: 'MNEE',
name: 'MNEE Token',
balance: { confirmed: '1000', unconfirmed: '0', total: '1000' },
icon: '🪙',
price: { bsv: 0.001, usd: 0.05 }
},
{
symbol: 'SHUA',
name: 'SHUA Token',
balance: { confirmed: '500', unconfirmed: '0', total: '500' },
icon: '💎',
price: { bsv: 0.002, usd: 0.10 }
}
];
return (
<TokenBalance
tokens={tokens}
onViewDetails={(token) => {
router.push(`/tokens/${token.symbol}`);
}}
onSendToken={(token) => {
setShowSendModal(token);
}}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
tokens | TokenBalanceType[] | [] | Array of token balances |
showValues | boolean | true | Show token values |
onToggleValues | () => void | - | Toggle value visibility |
onViewDetails | (token: TokenBalanceType) => void | - | View token details callback |
onSendToken | (token: TokenBalanceType) => void | - | Send token callback |
currency | 'BSV' | 'USD' | 'BSV' | Display currency |
loading | boolean | false | Show loading state |
className | string | - | Additional CSS classes |
TokenBalanceType Interface
interface TokenBalanceType {
symbol: string; // Token symbol (e.g., "MNEE")
name: string; // Full token name
contractId?: string; // Token contract identifier
balance: {
confirmed: string; // Confirmed balance
unconfirmed: string; // Pending balance
total: string; // Total balance
};
decimals?: number; // Decimal places
icon?: string; // Icon URL or emoji
price?: {
bsv: number; // Price in BSV
usd: number; // Price in USD
change24h?: number; // 24h change percentage
};
value?: {
bsv: number; // Total value in BSV
usd: number; // Total value in USD
};
type?: 'BSV20' | 'BSV21' | 'BSV721' | 'custom';
}Features
- Multi-Standard Support: BSV20, BSV21, BSV721, and custom tokens
- Real-time Pricing: Live token prices in BSV and USD
- Portfolio Value: Calculate total portfolio worth
- Interactive Actions: Send, view details, and manage tokens
- Privacy Controls: Toggle value visibility
- Loading States: Skeleton loading for better UX
- Responsive Design: Mobile-optimized layout
Examples
Basic Token Display
<TokenBalance
tokens={[
{
symbol: 'MNEE',
name: 'MNEE Token',
balance: { confirmed: '1000000', unconfirmed: '0', total: '1000000' },
icon: '🪙',
decimals: 8
}
]}
/>With Price Data
<TokenBalance
tokens={[
{
symbol: 'PEPE',
name: 'PEPE Token',
balance: { confirmed: '420000', unconfirmed: '0', total: '420000' },
icon: '🐸',
price: { bsv: 0.000001, usd: 0.00005, change24h: 15.3 },
value: { bsv: 0.42, usd: 21.0 }
}
]}
currency="USD"
/>Interactive Token Management
<TokenBalance
tokens={userTokens}
onViewDetails={(token) => {
setSelectedToken(token);
setShowDetailsModal(true);
}}
onSendToken={(token) => {
setTokenToSend(token);
setShowSendModal(true);
}}
onToggleValues={() => {
setShowValues(!showValues);
}}
showValues={showValues}
/>Loading State
<TokenBalance
tokens={[]}
loading={true}
/>Simple Version
import { SimpleTokenBalance } from 'bigblocks';
<SimpleTokenBalance
tokens={tokens}
currency="BSV"
className="compact-tokens"
/>Portfolio Overview
function TokenPortfolio() {
const [tokens, setTokens] = useState([]);
const [totalValue, setTotalValue] = useState({ bsv: 0, usd: 0 });
const [showValues, setShowValues] = useState(true);
useEffect(() => {
const total = tokens.reduce((acc, token) => ({
bsv: acc.bsv + (token.value?.bsv || 0),
usd: acc.usd + (token.value?.usd || 0)
}), { bsv: 0, usd: 0 });
setTotalValue(total);
}, [tokens]);
return (
<div className="token-portfolio">
<div className="portfolio-header">
<h2>Token Portfolio</h2>
<div className="total-value">
<span className="value">
{showValues ? `${totalValue.bsv.toFixed(8)} BSV` : '••••••••'}
</span>
<span className="usd-value">
{showValues ? `$${totalValue.usd.toFixed(2)}` : '$••••'}
</span>
</div>
</div>
<TokenBalance
tokens={tokens}
showValues={showValues}
onToggleValues={() => setShowValues(!showValues)}
onViewDetails={(token) => {
router.push(`/portfolio/token/${token.symbol}`);
}}
onSendToken={(token) => {
router.push(`/send?token=${token.symbol}`);
}}
/>
</div>
);
}Token Watchlist
function TokenWatchlist() {
const [watchedTokens, setWatchedTokens] = useState([]);
const [priceAlerts, setPriceAlerts] = useState({});
return (
<div className="token-watchlist">
<h3>Watched Tokens</h3>
<TokenBalance
tokens={watchedTokens}
onViewDetails={(token) => {
// Show token details with price history
showTokenAnalytics(token);
}}
onSendToken={(token) => {
// Quick send for watched tokens
quickSendToken(token);
}}
/>
{Object.entries(priceAlerts).map(([symbol, alert]) => (
<div key={symbol} className="price-alert">
🚨 {symbol} price {alert.type}: {alert.price}
</div>
))}
</div>
);
}Multi-Wallet Token View
function MultiWalletTokens() {
const [wallets, setWallets] = useState([]);
const [selectedWallet, setSelectedWallet] = useState(0);
return (
<div className="multi-wallet-tokens">
<div className="wallet-selector">
{wallets.map((wallet, index) => (
<button
key={index}
onClick={() => setSelectedWallet(index)}
className={selectedWallet === index ? 'active' : ''}
>
{wallet.name}
</button>
))}
</div>
<TokenBalance
tokens={wallets[selectedWallet]?.tokens || []}
onViewDetails={(token) => {
// Show token details for selected wallet
showWalletTokenDetails(selectedWallet, token);
}}
onSendToken={(token) => {
// Send from selected wallet
sendFromWallet(selectedWallet, token);
}}
/>
</div>
);
}Token Trading Interface
function TokenTradingInterface() {
const [tokens, setTokens] = useState([]);
const [marketData, setMarketData] = useState({});
return (
<div className="token-trading">
<TokenBalance
tokens={tokens.map(token => ({
...token,
// Add market data
price: marketData[token.symbol]?.price,
value: {
bsv: parseFloat(token.balance.total) * (marketData[token.symbol]?.price?.bsv || 0),
usd: parseFloat(token.balance.total) * (marketData[token.symbol]?.price?.usd || 0)
}
}))}
onViewDetails={(token) => {
// Show trading view
router.push(`/trade/${token.symbol}`);
}}
onSendToken={(token) => {
// Quick sell option
setTokenToSell(token);
setShowSellModal(true);
}}
/>
</div>
);
}Required Context
The component requires the following providers:
import {
BitcoinAuthProvider,
BitcoinQueryProvider
} from 'bigblocks';
function App() {
return (
<BitcoinAuthProvider>
<BitcoinQueryProvider>
<TokenBalance
tokens={tokens}
onViewDetails={handleViewDetails}
onSendToken={handleSendToken}
/>
</BitcoinQueryProvider>
</BitcoinAuthProvider>
);
}API Integration
Required Backend Endpoints
The component expects these API endpoints:
1. Get Token Balances
GET /api/wallet/tokens?address=<address>
Response:
{
tokens: Array<{
symbol: string;
name: string;
contractId: string;
balance: {
confirmed: string;
unconfirmed: string;
total: string;
};
decimals: number;
icon?: string;
type: 'BSV20' | 'BSV21' | 'BSV721';
}>;
totalValue: {
bsv: number;
usd: number;
};
}2. Get Token Prices
GET /api/tokens/prices?symbols=<symbol1,symbol2>
Response:
{
prices: {
[symbol: string]: {
bsv: number;
usd: number;
change24h: number;
volume24h: number;
};
};
lastUpdated: number;
}3. Get Token Details
GET /api/tokens/{symbol}/details
Response:
{
token: {
symbol: string;
name: string;
description: string;
contractId: string;
type: string;
decimals: number;
totalSupply: string;
website?: string;
social?: object;
};
market: {
price: TokenPrice;
marketCap: number;
volume24h: number;
holders: number;
};
}Authentication Headers
For authenticated token operations:
headers: {
'X-Auth-Token': '<BSM signature>',
'Content-Type': 'application/json'
}Token Standards
BSV20 Tokens
Fungible tokens following the BSV20 standard:
{
type: 'BSV20',
symbol: 'MNEE',
name: 'MNEE Token',
decimals: 8,
totalSupply: '21000000'
}BSV21 Tokens
Enhanced tokens with metadata:
{
type: 'BSV21',
symbol: 'SHUA',
name: 'SHUA Token',
decimals: 8,
metadata: {
description: 'Community token',
image: 'https://example.com/icon.png',
website: 'https://shua.com'
}
}BSV721 NFTs
Non-fungible tokens:
{
type: 'BSV721',
contractId: 'collection-123',
tokenId: 'nft-456',
name: 'Rare Art #456',
metadata: {
image: 'https://example.com/nft-456.png',
attributes: [
{ trait_type: 'Color', value: 'Blue' },
{ trait_type: 'Rarity', value: 'Legendary' }
]
}
}Real-time Updates
WebSocket Integration
function LiveTokenBalance() {
const [tokens, setTokens] = useState([]);
useEffect(() => {
const ws = new WebSocket('/api/wallet/tokens/stream');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case 'balance_updated':
setTokens(prev =>
prev.map(token =>
token.symbol === data.symbol
? { ...token, balance: data.balance }
: token
)
);
break;
case 'price_updated':
setTokens(prev =>
prev.map(token =>
token.symbol === data.symbol
? { ...token, price: data.price }
: token
)
);
break;
}
};
return () => ws.close();
}, []);
return (
<TokenBalance
tokens={tokens}
onViewDetails={handleViewDetails}
onSendToken={handleSendToken}
/>
);
}Performance Considerations
- Lazy Loading: Load token prices on demand
- Caching: Cache token data and prices
- Debounced Updates: Prevent excessive re-renders
- Virtual Scrolling: Handle large token lists efficiently
Error Handling
Common Error Scenarios
function RobustTokenBalance() {
const [tokens, setTokens] = useState([]);
const [error, setError] = useState(null);
const [retrying, setRetrying] = useState(false);
const retryTokenLoad = async () => {
setRetrying(true);
try {
const tokenData = await fetchTokenBalances();
setTokens(tokenData);
setError(null);
} catch (err) {
setError(err.message);
} finally {
setRetrying(false);
}
};
if (error) {
return (
<div className="token-error">
<p>Failed to load tokens: {error}</p>
<button onClick={retryTokenLoad} disabled={retrying}>
{retrying ? 'Retrying...' : 'Retry'}
</button>
</div>
);
}
return (
<TokenBalance
tokens={tokens}
onViewDetails={handleViewDetails}
onSendToken={handleSendToken}
/>
);
}Related Components
- SimpleTokenBalance - Minimal token display
- WalletOverview - Complete wallet dashboard
- SendBSVButton - Send BSV transactions
- MarketTable - Token trading interface