Transaction History
This guide covers querying and filtering transaction history in the Privacy Boost Android SDK.Basic Usage
val transactions = withContext(Dispatchers.IO) {
sdk.getTransactionHistory(
txType = null,
tokenAddress = null,
limit = null
)
}
for (tx in transactions) {
println("${tx.txType}: ${tx.amount} - ${tx.txHash}")
}
Transaction Type
data class Transaction(
val txHash: String, // Transaction hash
val txType: String, // "deposit", "withdraw", or "transfer"
val tokenAddress: String, // Token contract address
val amount: String, // Amount in wei
val direction: String, // "incoming" or "outgoing"
val senderPubKey: String, // Sender's public key
val receiverPubKeys: List<String>, // Receiver public keys
val createdAt: ULong // Unix timestamp
)
Filtering History
By Transaction Type
// Only deposits
val deposits = withContext(Dispatchers.IO) {
sdk.getTransactionHistory(txType = "deposit", tokenAddress = null, limit = null)
}
// Only withdrawals
val withdrawals = withContext(Dispatchers.IO) {
sdk.getTransactionHistory(txType = "withdraw", tokenAddress = null, limit = null)
}
// Only transfers
val transfers = withContext(Dispatchers.IO) {
sdk.getTransactionHistory(txType = "transfer", tokenAddress = null, limit = null)
}
By Token
val usdcHistory = withContext(Dispatchers.IO) {
sdk.getTransactionHistory(
txType = null,
tokenAddress = "0x...usdc-address",
limit = null
)
}
With Limit
// Get last 10 transactions
val recent = withContext(Dispatchers.IO) {
sdk.getTransactionHistory(txType = null, tokenAddress = null, limit = 10u)
}
Combined Filters
// Last 5 USDC deposits
val recentUsdcDeposits = withContext(Dispatchers.IO) {
sdk.getTransactionHistory(
txType = "deposit",
tokenAddress = "0x...usdc-address",
limit = 5u
)
}
Filter Parameters
| Parameter | Type | Description |
|---|---|---|
txType | String? | Filter by type: "deposit", "withdraw", "transfer" |
tokenAddress | String? | Filter by token contract address |
limit | UInt? | Maximum number of results |
ViewModel Integration
class TransactionViewModel(private val sdk: PrivacyBoost) : ViewModel() {
private val _transactions = MutableStateFlow<List<Transaction>>(emptyList())
val transactions: StateFlow<List<Transaction>> = _transactions.asStateFlow()
private val _isLoading = MutableStateFlow(false)
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
private val _filter = MutableStateFlow("all")
val filter: StateFlow<String> = _filter.asStateFlow()
fun setFilter(type: String) {
_filter.value = type
loadTransactions()
}
fun loadTransactions() {
viewModelScope.launch {
_isLoading.value = true
try {
val typeFilter = if (_filter.value == "all") null else _filter.value
val result = withContext(Dispatchers.IO) {
sdk.getTransactionHistory(
txType = typeFilter,
tokenAddress = null,
limit = 50u
)
}
_transactions.value = result
} catch (e: SDKError) {
println("Failed to load transactions: $e")
}
_isLoading.value = false
}
}
}
Displaying Transactions in Compose
@Composable
fun TransactionHistory(viewModel: TransactionViewModel) {
val transactions by viewModel.transactions.collectAsState()
val isLoading by viewModel.isLoading.collectAsState()
val filter by viewModel.filter.collectAsState()
val filters = listOf("all", "deposit", "withdraw", "transfer")
LaunchedEffect(Unit) {
viewModel.loadTransactions()
}
Column {
// Filter tabs
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
filters.forEach { type ->
FilterChip(
selected = filter == type,
onClick = { viewModel.setFilter(type) },
label = { Text(type.replaceFirstChar { it.uppercase() }) }
)
}
}
// Transaction list
if (isLoading) {
CircularProgressIndicator(modifier = Modifier.align(Alignment.CenterHorizontally))
} else if (transactions.isEmpty()) {
Text("No transactions found", color = Color.Gray)
} else {
LazyColumn {
items(transactions) { tx ->
TransactionRow(transaction = tx)
}
}
}
}
}
@Composable
fun TransactionRow(transaction: Transaction) {
val icon = when (transaction.txType) {
"deposit" -> Icons.Default.ArrowDownward
"withdraw" -> Icons.Default.ArrowUpward
"transfer" -> Icons.Default.SwapHoriz
else -> Icons.Default.Circle
}
val dateFormatter = SimpleDateFormat("MMM d, yyyy HH:mm", Locale.getDefault())
val formattedDate = dateFormatter.format(Date(transaction.createdAt.toLong() * 1000))
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(imageVector = icon, contentDescription = transaction.txType)
Spacer(modifier = Modifier.width(12.dp))
Column(modifier = Modifier.weight(1f)) {
Text(
text = transaction.txType.replaceFirstChar { it.uppercase() },
style = MaterialTheme.typography.titleSmall
)
Text(
text = formattedDate,
style = MaterialTheme.typography.bodySmall,
color = Color.Gray
)
}
Text(
text = transaction.amount,
style = MaterialTheme.typography.bodyMedium
)
}
}
Error Handling
try {
val transactions = withContext(Dispatchers.IO) {
sdk.getTransactionHistory(txType = null, tokenAddress = null, limit = null)
}
} catch (e: SDKError) {
when (e) {
is SDKError.NotAuthenticated ->
println("Please log in first")
is SDKError.NetworkError ->
println("Network error: ${e.message}")
else ->
println("Failed to get history: $e")
}
}
Best Practices
1. Paginate Results
For apps with many transactions, use thelimit parameter:
suspend fun loadPage(pageSize: UInt = 20u): List<Transaction> {
return withContext(Dispatchers.IO) {
sdk.getTransactionHistory(txType = null, tokenAddress = null, limit = pageSize)
}
}
2. Refresh After Operations
Fetch updated history after deposits, withdrawals, or transfers:val shieldResult = withContext(Dispatchers.IO) {
sdk.shield(tokenAddress = tokenAddress, amount = amount)
}
// Refresh transaction list
val updatedHistory = withContext(Dispatchers.IO) {
sdk.getTransactionHistory(txType = null, tokenAddress = null, limit = 20u)
}