Balance Management
This guide covers querying and managing token balances in the Privacy Boost iOS SDK.Understanding Balances
Privacy Boost tracks two types of balances:| Balance Type | Description |
|---|---|
| Shielded | Private balance in the privacy pool — only you can see it |
| Wallet | Public balance in your connected wallet on-chain |
Get Single Token Balance
do {
let balance = try await sdk.getBalance(tokenAddress: "0x...")
print("Token: \(balance.tokenAddress)")
print("Shielded: \(balance.shieldedBalance)")
print("Wallet: \(balance.walletBalance)")
print("Symbol: \(balance.symbol ?? "Unknown")")
print("Decimals: \(balance.decimals)")
} catch {
print("Failed to get balance: \(error)")
}
Get All Balances
do {
let balances = try await sdk.getAllBalances()
for balance in balances {
print("\(balance.symbol ?? balance.tokenAddress):")
print(" Shielded: \(balance.shieldedBalance)")
print(" Wallet: \(balance.walletBalance)")
}
} catch {
print("Failed to get balances: \(error)")
}
Balance Type
struct TokenBalance {
let tokenAddress: String // Token contract address
let shieldedBalance: String // Private balance in wei
let walletBalance: String // Public balance in wei
let symbol: String? // Token symbol (e.g., "USDC")
let decimals: UInt8 // Token decimals (e.g., 18)
}
Formatting Amounts
Convert between wei strings and human-readable format:// Parse human-readable to wei
let weiAmount = try sdk.parseAmount("1.5", decimals: 18)
// Returns: "1500000000000000000"
// Format wei to human-readable
let humanAmount = try sdk.formatAmount("1500000000000000000", decimals: 18)
// Returns: "1.5"
// Format a balance for display
let balance = try await sdk.getBalance(tokenAddress: tokenAddress)
let formatted = try sdk.formatAmount(balance.shieldedBalance, decimals: balance.decimals)
print("Shielded: \(formatted) \(balance.symbol ?? "")")
Checking Sufficient Balance
Before performing operations, verify the user has enough balance:func hasSufficientBalance(
tokenAddress: String,
requiredAmount: String
) async throws -> Bool {
let balance = try await sdk.getBalance(tokenAddress: tokenAddress)
guard let shielded = UInt64(balance.shieldedBalance),
let required = UInt64(requiredAmount) else {
return false
}
return shielded >= required
}
// Usage
if try await hasSufficientBalance(tokenAddress: token, requiredAmount: amount) {
let result = try await sdk.unshield(
tokenAddress: token,
amount: amount,
recipient: recipient
)
}
Displaying Balances in SwiftUI
struct BalanceListView: View {
@State private var balances: [TokenBalance] = []
@State private var isLoading = true
var body: some View {
List {
if isLoading {
ProgressView("Loading balances...")
} else if balances.isEmpty {
Text("No balances found")
.foregroundColor(.secondary)
} else {
ForEach(balances, id: \.tokenAddress) { balance in
BalanceRow(balance: balance)
}
}
}
.task {
await loadBalances()
}
.refreshable {
await loadBalances()
}
}
private func loadBalances() async {
isLoading = true
do {
balances = try await sdk.getAllBalances()
} catch {
print("Failed to load balances: \(error)")
}
isLoading = false
}
}
struct BalanceRow: View {
let balance: TokenBalance
var formattedShielded: String {
(try? sdk.formatAmount(balance.shieldedBalance, decimals: balance.decimals)) ?? "0"
}
var formattedWallet: String {
(try? sdk.formatAmount(balance.walletBalance, decimals: balance.decimals)) ?? "0"
}
var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text(balance.symbol ?? balance.tokenAddress)
.font(.headline)
HStack {
Label("Shielded: \(formattedShielded)", systemImage: "lock.shield")
Spacer()
Label("Wallet: \(formattedWallet)", systemImage: "wallet.pass")
}
.font(.subheadline)
.foregroundColor(.secondary)
}
.padding(.vertical, 4)
}
}
Error Handling
do {
let balance = try await sdk.getBalance(tokenAddress: tokenAddress)
} catch SDKError.notAuthenticated {
print("Please log in first")
} catch SDKError.networkError(let message) {
print("Network error: \(message)")
} catch {
print("Balance error: \(error)")
}
Best Practices
1. Refresh After Operations
// Refresh balance after a deposit
let shieldResult = try await sdk.shield(
tokenAddress: tokenAddress,
amount: amount
)
let updatedBalance = try await sdk.getBalance(tokenAddress: tokenAddress)
2. Handle Zero Balances
func displayBalance(_ balance: TokenBalance) -> String {
if balance.shieldedBalance == "0" && balance.walletBalance == "0" {
return "0"
}
return (try? sdk.formatAmount(
balance.shieldedBalance,
decimals: balance.decimals
)) ?? "0"
}
3. Filter Non-Zero Balances
let allBalances = try await sdk.getAllBalances()
let nonZero = allBalances.filter { balance in
balance.shieldedBalance != "0" || balance.walletBalance != "0"
}