Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.privacyboost.io/llms.txt

Use this file to discover all available pages before exploring further.

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 TypeDescription
ShieldedPrivate balance in the privacy pool — only you can see it
WalletPublic 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"
}

Next Steps