Skip to main content
Learn how to analyze token activity and distribution on Spark. This guide covers querying transaction history and understanding token metrics.
Token Analytics

Query Token Transactions

Retrieve detailed transaction history for your token with flexible filtering options. queryTokenTransactions(params) Retrieves token transactions from the network with flexible filtering options.
const transactions = await wallet.queryTokenTransactions({
  ownerPublicKeys: ["spark1..."],
  issuerPublicKeys: ["spark1..."],
  tokenIdentifiers: ["btkn1..."]
});
console.log("Token transactions:", transactions);

Transaction Status Values

StatusMeaning
TOKEN_TRANSACTION_STARTEDTransaction created but not yet signed
TOKEN_TRANSACTION_SIGNEDTransaction signed by all required parties
TOKEN_TRANSACTION_REVEALEDTransaction revealed on-chain, awaiting finalization
TOKEN_TRANSACTION_FINALIZEDTransaction confirmed and finalized
TOKEN_TRANSACTION_STARTED_CANCELLEDTransaction cancelled before signing
TOKEN_TRANSACTION_SIGNED_CANCELLEDTransaction cancelled after signing
TOKEN_TRANSACTION_UNKNOWNUnknown or unexpected state

Query Examples

All Token Transactions

// Get all transactions for your token
const tokenIdentifier = await wallet.getIssuerTokenIdentifier();
const allTransactions = await wallet.queryTokenTransactions({
  tokenIdentifiers: [tokenIdentifier]
});

console.log(`Found ${allTransactions.length} transactions for your token`);

Transactions by Specific Owner

// Get transactions involving a specific address
const ownerAddress = "spark1...";
const ownerTransactions = await wallet.queryTokenTransactions({
  ownerPublicKeys: [ownerAddress],
  tokenIdentifiers: [tokenIdentifier]
});

console.log(`Found ${ownerTransactions.length} transactions for address ${ownerAddress}`);

Issuer-Initiated Transactions

// Get transactions created by the issuer
const metadata = await wallet.getIssuerTokenMetadata();
const issuerPublicKey = metadata.tokenPublicKey;
const issuerTransactions = await wallet.queryTokenTransactions({
  issuerPublicKeys: [issuerPublicKey]
});

console.log(`Found ${issuerTransactions.length} issuer-initiated transactions`);

Filter by Transaction Status

// Get only finalized transactions
const allTransactions = await wallet.queryTokenTransactions({
  tokenIdentifiers: [tokenIdentifier]
});

const finalizedTransactions = allTransactions.filter(
  tx => tx.status === "TOKEN_TRANSACTION_FINALIZED"
);

console.log(`Found ${finalizedTransactions.length} finalized transactions`);

Get Token Distribution

Get insights into how your token is distributed across the network. getIssuerTokenDistribution() Gets the token distribution information for the token associated with this issuer wallet.
This feature is currently under development and will be available in a future release of Spark.
const distribution = await wallet.getIssuerTokenDistribution();
console.log("Token distribution:", distribution);

Distribution Analysis Examples

const distribution = await wallet.getIssuerTokenDistribution();

console.log("=== Token Distribution Analysis ===");
console.log("Circulating Supply:", distribution.totalCirculatingSupply.toString());
console.log("Total Issued:", distribution.totalIssued.toString());
console.log("Total Burned:", distribution.totalBurned.toString());
console.log("Unique Holders:", distribution.numHoldingAddress);
console.log("Confirmed Transactions:", distribution.numConfirmedTransactions);

// Calculate burn rate
const burnRate = (Number(distribution.totalBurned) / Number(distribution.totalIssued)) * 100;
console.log(`Burn Rate: ${burnRate.toFixed(2)}%`);

// Calculate average holdings per address
const avgHoldings = Number(distribution.totalCirculatingSupply) / distribution.numHoldingAddress;
console.log(`Average Holdings per Address: ${avgHoldings.toFixed(2)} base units`);

Transaction Analysis

Analyze transaction patterns and trends for your token.

Transaction Volume Analysis

// Get all transactions for analysis
const transactions = await wallet.queryTokenTransactions({
  tokenIdentifiers: [tokenIdentifier]
});

// Group by status
const statusCounts = {};
transactions.forEach(tx => {
  const status = tx.status;
  statusCounts[status] = (statusCounts[status] || 0) + 1;
});

console.log("Transaction status breakdown:", statusCounts);

// Calculate success rate
const totalTransactions = transactions.length;
const successfulTransactions = statusCounts["TOKEN_TRANSACTION_FINALIZED"] || 0;
const successRate = (successfulTransactions / totalTransactions) * 100;

console.log(`Success rate: ${successRate.toFixed(2)}%`);

Recent Activity Analysis

// Analyze recent transaction activity
const recentTransactions = await wallet.queryTokenTransactions({
  tokenIdentifiers: [tokenIdentifier]
});

// Sort by timestamp (if available) and get recent ones
const sortedTransactions = recentTransactions.sort((a, b) => {
  // Sort by transaction timestamp if available
  return new Date(b.tokenTransaction.timestamp) - new Date(a.tokenTransaction.timestamp);
});

const last24Hours = sortedTransactions.filter(tx => {
  const txTime = new Date(tx.tokenTransaction.timestamp);
  const now = new Date();
  const hoursDiff = (now - txTime) / (1000 * 60 * 60);
  return hoursDiff <= 24;
});

console.log(`Transactions in last 24 hours: ${last24Hours.length}`);

Holder Analysis

// Analyze token holders
const transactions = await wallet.queryTokenTransactions({
  tokenIdentifiers: [tokenIdentifier]
});

// Extract unique addresses from transactions
const uniqueAddresses = new Set();
transactions.forEach(tx => {
  // Add addresses from transaction inputs and outputs
  tx.tokenTransaction.inputs?.forEach(input => {
    if (input.ownerPublicKey) {
      uniqueAddresses.add(input.ownerPublicKey);
    }
  });
  tx.tokenTransaction.outputs?.forEach(output => {
    if (output.ownerPublicKey) {
      uniqueAddresses.add(output.ownerPublicKey);
    }
  });
});

console.log(`Unique addresses involved: ${uniqueAddresses.size}`);

Best Practices

Query Optimization

  • Use Specific Filters: Apply relevant filters to reduce query response times
  • Paginate Results: For large datasets, implement pagination to manage memory usage
  • Cache Results: Store frequently accessed transaction data locally

Analysis Techniques

  • Batch Processing: Process large transaction sets in batches to avoid memory issues
  • Data Validation: Validate transaction data before analysis
  • Error Handling: Handle missing or malformed transaction data gracefully

Performance Considerations

  • Limit Query Scope: Use specific filters to limit the number of transactions returned
  • Async Processing: Use async/await for better performance with large datasets
  • Memory Management: Monitor memory usage when processing large transaction sets

Complete Example

import { IssuerSparkWallet } from "@buildonspark/issuer-sdk";

async function demonstrateTokenAnalytics() {
  try {
    // 1. Initialize issuer wallet
    const { wallet } = await IssuerSparkWallet.initialize({
      options: { network: "REGTEST" }
    });

    console.log("Issuer wallet initialized for analytics");

    // 2. Get token metadata
    const metadata = await wallet.getIssuerTokenMetadata();
    const tokenIdentifier = metadata.bech32mTokenIdentifier;
    console.log("Analyzing token:", metadata.tokenName, "(", metadata.tokenSymbol, ")");

    // 3. Query all transactions
    const allTransactions = await wallet.queryTokenTransactions({
      tokenIdentifiers: [tokenIdentifier]
    });
    console.log(`Found ${allTransactions.length} total transactions`);

    // 4. Analyze transaction statuses
    const statusCounts = {};
    allTransactions.forEach(tx => {
      const status = tx.status;
      statusCounts[status] = (statusCounts[status] || 0) + 1;
    });
    console.log("Transaction status breakdown:", statusCounts);

    // 5. Calculate success rate
    const totalTransactions = allTransactions.length;
    const successfulTransactions = statusCounts["TOKEN_TRANSACTION_FINALIZED"] || 0;
    const successRate = totalTransactions > 0 ? (successfulTransactions / totalTransactions) * 100 : 0;
    console.log(`Success rate: ${successRate.toFixed(2)}%`);

    // 6. Get issuer-specific transactions
    const issuerTransactions = await wallet.queryTokenTransactions({
      issuerPublicKeys: [metadata.tokenPublicKey]
    });
    console.log(`Issuer-initiated transactions: ${issuerTransactions.length}`);

    // 7. Try to get distribution data (when available)
    try {
      const distribution = await wallet.getIssuerTokenDistribution();
      console.log("=== Token Distribution ===");
      console.log("Circulating Supply:", distribution.totalCirculatingSupply.toString());
      console.log("Total Issued:", distribution.totalIssued.toString());
      console.log("Total Burned:", distribution.totalBurned.toString());
      console.log("Unique Holders:", distribution.numHoldingAddress);
      console.log("Confirmed Transactions:", distribution.numConfirmedTransactions);

      // Calculate metrics
      const burnRate = Number(distribution.totalBurned) / Number(distribution.totalIssued) * 100;
      const avgHoldings = Number(distribution.totalCirculatingSupply) / distribution.numHoldingAddress;
      console.log(`Burn Rate: ${burnRate.toFixed(2)}%`);
      console.log(`Average Holdings: ${avgHoldings.toFixed(2)} base units`);
    } catch (error) {
      console.log("Token distribution not yet available:", error.message);
    }

  } catch (error) {
    console.error("Token analytics error:", error);
  }
}

demonstrateTokenAnalytics().catch(console.error);