> ## 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.

# Transactions

# Transaction History

This guide covers querying and filtering transaction history in the Privacy Boost Android SDK.

## Basic Usage

```kotlin theme={null}
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

```kotlin theme={null}
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

```kotlin theme={null}
// 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

```kotlin theme={null}
val usdcHistory = withContext(Dispatchers.IO) {
    sdk.getTransactionHistory(
        txType = null,
        tokenAddress = "0x...usdc-address",
        limit = null
    )
}
```

### With Limit

```kotlin theme={null}
// Get last 10 transactions
val recent = withContext(Dispatchers.IO) {
    sdk.getTransactionHistory(txType = null, tokenAddress = null, limit = 10u)
}
```

### Combined Filters

```kotlin theme={null}
// 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

```kotlin theme={null}
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

```kotlin theme={null}
@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

```kotlin theme={null}
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 the `limit` parameter:

```kotlin theme={null}
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:

```kotlin theme={null}
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)
}
```

## Next Steps

* [Balances Guide](./balances)
* [Deposits Guide](./deposits)
* [Error Handling](./error-handling)
* [API Reference](/sdk/android/api-reference)
