> ## 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 paginating transaction history in the Privacy
Boost React Native SDK.

## Basic Usage

`getTransactionHistory` is async and returns a paginated result, not a raw
array. Iterate over `result.data`:

```typescript theme={null}
import { PrivacyBoost } from '@sunnyside-io/privacy-boost-react-native';

const result = await sdk.getTransactionHistory();
for (const tx of result.data) {
  console.log(`${tx.txType}: ${tx.value} - ${tx.txHash}`);
}
```

## Transaction Type

Each `Transaction` groups the on-chain event with zero or more shielded notes
it produced or consumed. Money movement lives in `value`/`tokenId`/`notes` —
not in the pre-0.2 `amount`/`tokenAddress`/`receivers` shape.

```typescript theme={null}
interface Transaction {
  txHash: string;                     // Transaction hash
  txType: string;                     // "shield" | "unshield" | "transfer"
  direction: string;                  // "incoming" | "outgoing"
  value: string;                      // Net value in wei
  tokenId: bigint;                    // Registered token ID
  createdAt: bigint;                  // Unix timestamp
  counterparty?: string;              // Other party's address or pubkey
  counterpartyType?: string;          // "wallet" | "privacy"
  notes: TransactionNote[];           // Shielded notes affected
}

interface TransactionNote {
  value: string;                      // Note value in wei
  direction: string;                  // "incoming" | "outgoing"
  isChange: boolean;                  // True if this is a change note
  leafIndex?: bigint;                 // Merkle leaf index
  nullifier?: string;                 // Spent-note nullifier
  counterparty?: string;
  counterpartyType?: string;
}

interface TransactionsResult {
  data: Transaction[];
  limit: number;
  next?: string;                      // Cursor for next page (undefined = end)
}
```

To resolve a `tokenId` to a token address/symbol, call
`sdk.getRegisteredTokens()` once and cache the lookup.

## Filtering History

### By Transaction Type

```typescript theme={null}
// Only shields (deposits)
const shields = await sdk.getTransactionHistory('shield');

// Only unshields (withdrawals)
const unshields = await sdk.getTransactionHistory('unshield');

// Only transfers
const transfers = await sdk.getTransactionHistory('transfer');
```

### With Limit

```typescript theme={null}
// First 10 transactions
const result = await sdk.getTransactionHistory(undefined, 10);
```

### Pagination

The previous page's `next` cursor is the third argument:

```typescript theme={null}
const first = await sdk.getTransactionHistory(undefined, 25);

if (first.next) {
  const second = await sdk.getTransactionHistory(undefined, 25, first.next);
}
```

## Parameters

| Parameter | Type      | Description                                            |
| --------- | --------- | ------------------------------------------------------ |
| `txType`  | `string?` | Filter by type: `"shield"`, `"unshield"`, `"transfer"` |
| `limit`   | `number?` | Page size                                              |
| `cursor`  | `string?` | Opaque continuation token from previous `result.next`  |

> Token filtering is not a parameter on this method — fetch all types and
> filter client-side by `tx.tokenId`, or use `sdk.getUnspentNotes(tokenAddress)`
> for balance-level queries.

## Complete Example

```tsx theme={null}
import React, { useState, useEffect, useCallback } from 'react';
import { View, Text, FlatList, ActivityIndicator } from 'react-native';
import type {
  PrivacyBoost,
  Transaction,
} from '@sunnyside-io/privacy-boost-react-native';

function TransactionHistoryScreen({ sdk }: { sdk: PrivacyBoost }) {
  const [transactions, setTransactions] = useState<Transaction[]>([]);
  const [cursor, setCursor] = useState<string | undefined>(undefined);
  const [filter, setFilter] = useState<string | undefined>(undefined);
  const [loading, setLoading] = useState(true);

  const loadMore = useCallback(async () => {
    setLoading(true);
    try {
      const page = await sdk.getTransactionHistory(filter, 25, cursor);
      setTransactions((prev) => (cursor ? [...prev, ...page.data] : page.data));
      setCursor(page.next);
    } catch (error) {
      console.log('Failed to load transactions:', error);
    }
    setLoading(false);
  }, [sdk, filter, cursor]);

  // Reset when filter changes
  useEffect(() => {
    setCursor(undefined);
    setTransactions([]);
    loadMore();
  }, [filter]);

  const formatDate = (timestamp: bigint) =>
    new Date(Number(timestamp) * 1000).toLocaleDateString();

  return (
    <View style={{ padding: 16 }}>
      <FlatList
        data={transactions}
        keyExtractor={(item) => item.txHash}
        renderItem={({ item }) => (
          <View style={{ paddingVertical: 8 }}>
            <Text style={{ fontWeight: 'bold' }}>
              {item.txType} · {item.direction}
            </Text>
            <Text>Value: {sdk.formatAmount(item.value, 18)}</Text>
            <Text style={{ color: 'gray' }}>{formatDate(item.createdAt)}</Text>
          </View>
        )}
        onEndReached={() => cursor && loadMore()}
        onEndReachedThreshold={0.5}
        ListFooterComponent={loading ? <ActivityIndicator /> : null}
        ListEmptyComponent={!loading ? <Text>No transactions</Text> : null}
      />
    </View>
  );
}
```

## Error Handling

```typescript theme={null}
import { SdkError } from '@sunnyside-io/privacy-boost-react-native';

try {
  const result = await sdk.getTransactionHistory();
} catch (error) {
  if (SdkError.NotAuthenticated.instanceOf(error)) {
    console.log('Please log in first');
  } else if (SdkError.NetworkError.instanceOf(error)) {
    console.log('Network error');
  } else {
    console.log('Failed to get history:', error);
  }
}
```

## Best Practices

### 1. Page through results

Always pass a `limit` and follow the `next` cursor. Unbounded history fetches
get expensive fast for active accounts.

### 2. Cache token metadata

`Transaction.tokenId` is a numeric ID. Resolve to display symbol/decimals via
`sdk.getRegisteredTokens()` and cache the result — the registered-token list
changes rarely.

### 3. Refresh after operations

Call `getTransactionHistory` (with no cursor) after a successful shield /
unshield / transfer so the UI reflects the new state.

## Next Steps

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