Package Logo
solana-spl-token
solana-spl-token@v0.1.4
Total Downloads
339
Published
2 weeks ago
Network
solana solana
Publisher
StreamingFast

Readme

Solana SPL Token

This Substreams module extracts SPL token instructions from Solana transactions, resolving account ownership through the SPL Initialized Account Foundational Store to provide complete transfer information.

If you are a Substreams developer, jump to Using SPL Token Module for details about how to consume SPL token instruction data with resolved ownership information.

Using SPL Token Module

This module processes SPL token instructions and enriches them with account ownership data to create complete transfer records. The ownership resolution is critical since SPL transfer instructions only contain account addresses, not the actual wallet owners.

[!NOTE] Ensure your Cargo substreams and substreams-solana dependencies are up to date cargo update substreams substreams-solana.

First, add the SPL Token import to your substreams.yaml manifest:

...

imports:
  ...
  spl_token: solana-spl-token@v0.1.4

modules:
  ...

  - name: <your-module>
    kind: map
    inputs:
      ...
      - map: spl_token:map_spl_instructions
    output:
      ...

Then in your code, use the module output:

...
use sf::solana::spl::v1::type::SplInstructions;

#[substreams::handlers::map]
fn process_spl_data(spl_instructions: SplInstructions) -> Result<YourOutputType, Error> {
    ...

    // Process transfers with resolved ownership
    for transfer in spl_instructions.transfers {
        substreams::log::info!("Transfer from {} to {}",
            Address(&transfer.from_owner).to_string(),
            Address(&transfer.to_owner).to_string()
        );
    }

    // Process mints
    for mint in spl_instructions.mints {
        substreams::log::info!("Mint to owner {}",
            Address(&mint.to_owner).to_string()
        );
    }

    // Process burns
    for burn in spl_instructions.burns {
        substreams::log::info!("Burn from owner {}",
            Address(&burn.from_owner).to_string()
        );
    }
}

See https://github.com/streamingfast/substreams-foundational-modules/tree/main/solana/spl-initialized-account for the foundational store that resolves account ownership.

Data Source

The module processes SPL token instructions and extracts information from these instruction types:

  • Transfer - Token transfers between accounts (with resolved sender/receiver ownership)
  • Mint - New token creation (with destination owner)
  • Burn - Token destruction (with source owner)
  • InitializeAccount* - Account initialization events

For each instruction, it resolves account ownership using the SPL Initialized Account Foundational Store to provide:

  • Account address - The token account involved in the operation
  • Owner - The actual wallet/program that controls the account
  • Amount - The token amount for transfers, mints, and burns
  • Mint - The SPL token mint address

Configuration

Configure the module to track a specific SPL token by editing the parameters in substreams.yaml:

params:
  map_spl_instructions: "spl_token_address=YOUR_TOKEN_ADDRESS|spl_token_decimal=DECIMALS"
  solana_common:transactions_by_programid_and_account_without_votes: "program:TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA && account:YOUR_TOKEN_ADDRESS"

The module supports both SPL Token programs:

  • TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA (original)
  • TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb (Token-2022)

Quick Start with ClickHouse

This project includes a complete data pipeline from Solana blockchain to ClickHouse database with pre-built materialized views for analytics.

Prerequisites

1. Clone and Setup

git clone https://github.com/streamingfast/substreams-spl-token.git
cd substreams-spl-token

2. Start Local ClickHouse Database

# Start ClickHouse database
make db-up

This will:

  • Start a ClickHouse instance on localhost:8123 (HTTP) and localhost:9000 (native)
  • Create the spl2 database

3. Build and Package

substreams build

4. Run the Data Pipeline

# Consume a subset of the chain just for demonstration purposes
substreams-sink-sql from-proto clickhouse://default:@localhost:9000/spl2 ./solana-spl-token-v0.1.0.spkg -s 356312000 -t +10000

5. Apply Materialized Views

# Apply views using the db-query command
docker exec -i spl-token-clickhouse clickhouse-client --database spl2 --multiquery < views.sql

6. Query Your Data

# Open ClickHouse client and enter query there (SELECT count() FROM mints)
make db-shell

# Or run example queries
make db-query QUERY="SELECT count() FROM mints"

Database Schema

The pipeline creates the following tables in ClickHouse:

Core Tables

  • mints: Token mint operations
  • burns: Token burn operations
  • transfers: Token transfer operations
  • initialized_accounts: Account initialization events
  • instructions: Instruction metadata
  • _blocks_: Block information

Materialized Views

  • mv_all_mints: Enhanced mint data with account owner information
  • mv_all_burns: Enhanced burn data with account owner information
  • mv_mint_per_month: Monthly mint aggregations
  • mv_burn_per_month: Monthly burn aggregations
  • mv_supply: Current total supply calculation

Example Queries

See example-queries.md for comprehensive query examples. Here are a few quick ones:

Current Token Supply

SELECT * FROM spl2.mv_supply;

Recent Mint Transactions

SELECT
    block_time,
    to_derive_address,
    amount / 1000000000 as tokens_minted
FROM spl2.mv_all_mints
ORDER BY block_number DESC
LIMIT 10;

Monthly Supply Changes

SELECT
    m.month,
    m.total / 1000000000 as tokens_minted,
    COALESCE(b.total, 0) / 1000000000 as tokens_burned,
    (m.total - COALESCE(b.total, 0)) / 1000000000 as net_change
FROM spl2.mv_mint_per_month m
LEFT JOIN spl2.mv_burn_per_month b ON m.month = b.month
ORDER BY m.month DESC;

Development Commands

# Database management
make db-up          # Start ClickHouse
make db-down        # Stop ClickHouse
make db-setup       # Initialize database
make db-shell       # Open database shell
make db-reset       # Reset database (removes all data)

Installing substreams-sink-sql

The substreams-sink-sql tool is required to stream data from Substreams to ClickHouse.

Installation Options

Option 1: Download Pre-built Binary

# Download from GitHub releases
curl -L https://github.com/streamingfast/substreams-sink-sql/releases/latest/download/substreams-sink-sql-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m).tar.gz | tar -xz
sudo mv substreams-sink-sql /usr/local/bin/

Option 2: Build from Source

git clone https://github.com/streamingfast/substreams-sink-sql.git
cd substreams-sink-sql
go build -o substreams-sink-sql ./cmd/substreams-sink-sql

For detailed installation instructions, see the official documentation.

Documentation

Modules

Maps icon
Maps

map
map_spl_instructions

4f582b8c10829ebd1707e2cde13ca1ac3bc9412a
map map_spl_instructions (
paramsstring
solana_common:transactions_by_programid_and_account_without_votessf.substreams.solana.v1.Transactions
)  -> sf.solana.spl.v1.type.SplInstructions
Default param : spl_token_address=4vMsoUT2BWatFweudnQM1xedRLfJgJ7hswhcpz4xgBTy|spl_token_decimal=9
substreams gui solana-spl-token@v0.1.4 map_spl_instructions

map
solana_common:blocks_without_votes

0be93a73c65aa8ec2de4b1a47209edeea493ff29
map solana_common:blocks_without_votes (
)  -> sf.solana.type.v1.Block
substreams gui solana-spl-token@v0.1.4 solana_common:blocks_without_votes

map
solana_common:transactions_by_programid_and_account_without_votes

aeb30436c354bb7c5c1ede1112cc42932fbaab8a
map solana_common:transactions_by_programid_and_account_without_votes (
paramsstring
)  -> sf.substreams.solana.v1.Transactions
Default param : program:TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA && account:4vMsoUT2BWatFweudnQM1xedRLfJgJ7hswhcpz4xgBTy
substreams gui solana-spl-token@v0.1.4 solana_common:transactions_by_programid_and_account_without_votes
Block Indexes icon
Block Indexes

blockIndex
solana_common:program_ids_and_accounts_without_votes

ec0d2eb5ebfb384b6befa8aa19f6178b853672fe
blockIndex solana_common:program_ids_and_accounts_without_votes (
)  -> sf.substreams.index.v1.Keys
substreams gui solana-spl-token@v0.1.4 solana_common:program_ids_and_accounts_without_votes
Protobuf

Protobuf Docs Explorer

sf.solana.type.v1
sol.instructions.v1
sf.solana.spl.v1.type
schema
sol.transactions.v1