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 Android 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
val balance = withContext(Dispatchers.IO) {
sdk.getBalance(tokenAddress = "0x...")
}
println("Token: ${balance.tokenAddress}")
println("Shielded: ${balance.shieldedBalance}")
println("Wallet: ${balance.walletBalance}")
println("Symbol: ${balance.symbol}")
println("Decimals: ${balance.decimals}")
Get All Balances
val balances = withContext(Dispatchers.IO) {
sdk.getAllBalances()
}
for (balance in balances) {
println("${balance.symbol ?: balance.tokenAddress}:")
println(" Shielded: ${balance.shieldedBalance}")
println(" Wallet: ${balance.walletBalance}")
}
Balance Type
data class TokenBalance(
val tokenAddress: String, // Token contract address
val shieldedBalance: String, // Private balance in wei
val walletBalance: String, // Public balance in wei
val symbol: String?, // Token symbol (e.g., "USDC")
val decimals: UByte // Token decimals (e.g., 18)
)
Convert between wei strings and human-readable format:
// Parse human-readable to wei
val weiAmount = sdk.parseAmount("1.5", decimals = 18u)
// Returns: "1500000000000000000"
// Format wei to human-readable
val humanAmount = sdk.formatAmount("1500000000000000000", decimals = 18u)
// Returns: "1.5"
// Format a balance for display
val balance = withContext(Dispatchers.IO) {
sdk.getBalance(tokenAddress = tokenAddress)
}
val formatted = sdk.formatAmount(balance.shieldedBalance, decimals = balance.decimals)
println("Shielded: $formatted ${balance.symbol ?: ""}")
Checking Sufficient Balance
Before performing operations, verify the user has enough balance:
suspend fun hasSufficientBalance(
tokenAddress: String,
requiredAmount: String
): Boolean {
val balance = withContext(Dispatchers.IO) {
sdk.getBalance(tokenAddress = tokenAddress)
}
val shielded = balance.shieldedBalance.toBigIntegerOrNull() ?: return false
val required = requiredAmount.toBigIntegerOrNull() ?: return false
return shielded >= required
}
// Usage
if (hasSufficientBalance(token, amount)) {
val result = withContext(Dispatchers.IO) {
sdk.unshield(
tokenAddress = token,
amount = amount,
recipient = recipient
)
}
}
ViewModel Integration
class BalanceViewModel(private val sdk: PrivacyBoost) : ViewModel() {
private val _balances = MutableStateFlow<List<TokenBalance>>(emptyList())
val balances: StateFlow<List<TokenBalance>> = _balances.asStateFlow()
private val _isLoading = MutableStateFlow(true)
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
fun loadBalances() {
viewModelScope.launch {
_isLoading.value = true
try {
val result = withContext(Dispatchers.IO) {
sdk.getAllBalances()
}
_balances.value = result
} catch (e: SDKError) {
println("Failed to load balances: $e")
}
_isLoading.value = false
}
}
fun formatBalance(balance: TokenBalance): String {
return try {
sdk.formatAmount(balance.shieldedBalance, decimals = balance.decimals)
} catch (e: Exception) {
"0"
}
}
}
Displaying Balances in Compose
@Composable
fun BalanceList(viewModel: BalanceViewModel) {
val balances by viewModel.balances.collectAsState()
val isLoading by viewModel.isLoading.collectAsState()
LaunchedEffect(Unit) {
viewModel.loadBalances()
}
if (isLoading) {
CircularProgressIndicator()
} else if (balances.isEmpty()) {
Text("No balances found", color = Color.Gray)
} else {
LazyColumn {
items(balances) { balance ->
BalanceRow(balance = balance, viewModel = viewModel)
}
}
}
}
@Composable
fun BalanceRow(balance: TokenBalance, viewModel: BalanceViewModel) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = balance.symbol ?: balance.tokenAddress.take(10),
style = MaterialTheme.typography.titleMedium
)
Column(horizontalAlignment = Alignment.End) {
Text("Shielded: ${viewModel.formatBalance(balance)}")
Text(
text = "Wallet: ${sdk.formatAmount(balance.walletBalance, balance.decimals)}",
color = Color.Gray
)
}
}
}
Error Handling
try {
val balance = withContext(Dispatchers.IO) {
sdk.getBalance(tokenAddress = tokenAddress)
}
} catch (e: SDKError) {
when (e) {
is SDKError.NotAuthenticated ->
println("Please log in first")
is SDKError.NetworkError ->
println("Network error: ${e.message}")
else ->
println("Balance error: $e")
}
}
Best Practices
1. Refresh After Operations
// Refresh balance after a deposit
val shieldResult = withContext(Dispatchers.IO) {
sdk.shield(tokenAddress = tokenAddress, amount = amount)
}
val updatedBalance = withContext(Dispatchers.IO) {
sdk.getBalance(tokenAddress = tokenAddress)
}
2. Handle Zero Balances
fun displayBalance(balance: TokenBalance): String {
if (balance.shieldedBalance == "0" && balance.walletBalance == "0") {
return "0"
}
return try {
sdk.formatAmount(balance.shieldedBalance, decimals = balance.decimals)
} catch (e: Exception) {
"0"
}
}
3. Filter Non-Zero Balances
val allBalances = withContext(Dispatchers.IO) { sdk.getAllBalances() }
val nonZero = allBalances.filter { balance ->
balance.shieldedBalance != "0" || balance.walletBalance != "0"
}
Next Steps