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.

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

// 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

// First 10 transactions
const result = await sdk.getTransactionHistory(undefined, 10);

Pagination

The previous page’s next cursor is the third argument:
const first = await sdk.getTransactionHistory(undefined, 25);

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

Parameters

ParameterTypeDescription
txTypestring?Filter by type: "shield", "unshield", "transfer"
limitnumber?Page size
cursorstring?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

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

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