All packages

x402_solana_pulse

PaulieB14
v1.2.0/11 downloads/Repository

Package ref

x402-solana-pulse@v1.2.0

Run package

CLI

Run db_out from the command line.

substreams run x402-solana-pulse@v1.2.0 db_out -e solana
Authenticate by running substreams auth or directly on thegraph.market (see docs).

README

x402 Solana Pulse

Real-time payment protocol analytics for Coinbase x402 on Solana

Track every x402 payment settlement on Solana — both schemes. This Substreams detects facilitator-sponsored settlements for HTTP 402 payments and extracts payer, recipient, mint, amount, facilitator and memo from each one.

SchemeShape on chainCovered
exactSPL Token TransferChecked at top levelsince v1.0
uptopayment-channels program, transfer as a CPInew in v1.2

Every row carries scheme, so you can filter to one or trust the total. That matters more than it sounds: upto settlements have no top-level TransferChecked at all, so any Solana x402 indexer that only walks top-level instructions silently undercounts them and looks complete while doing it.

Companion to x402-base-pulse — same model, Solana native.


How It Works

The x402 protocol enables internet-native payments using the HTTP 402 status code. The Solana settlement path is defined by the SVM exact scheme:

  1. Server responds with HTTP 402 + payment requirements (mint, payTo, amount, feePayer)
  2. Client constructs a transaction containing a TransferChecked to the resource server's ATA, signs it, and returns the partially-signed tx
  3. Facilitator verifies the transaction, provides the final feePayer signature, and submits it to Solana
  4. Solana executes an SPL Token (or Token-2022) TransferChecked + SPL Memo instruction
  5. This Substreams captures those transactions by looking for the x402 SVM settlement shape

The upto scheme is shaped differently

upto settles through the payment-channels program (CHNLxYvVA28MJP9PrFuDXccuoGXAx7jBacfLEkahyGsX) rather than a direct transfer. Observed on mainnet, the transaction looks like:

top-level : [ComputeBudget, ComputeBudget, PAYMENT_CHANNELS, Memo]
inner CPI : SPL TransferChecked     <- the actual token movement

Two consequences worth knowing before you query:

  • The transfer is a CPI, so it never appears among top-level instructions. A detector that only walks those will report zero upto volume rather than an error.
  • The inner transfer's authority is the channel PDA, not the end payer. Those rows set scheme='upto' and carry the PDA in both payer and channel, so you always know which one you are holding instead of mistaking a channel for a wallet.

Detection: strict spec match + known-facilitator fallback

Solana has no on-chain FacilitatorRegistry. This substreams uses a two-layer approach:

1. Strict spec match (any facilitator, known or new): Matches the SVM exact scheme layout verbatim — 3–6 top-level instructions consisting of ComputeBudget SetLimit, ComputeBudget SetPrice, TransferChecked, then optional Memo / Lighthouse. Fee payer must differ from the TransferChecked authority. This captures any spec-compliant facilitator automatically, including new ones that haven't been added to the allowlist.

2. Relaxed match for known facilitators: For the 21 facilitator pubkeys mirrored from x402scan's registry, we accept looser layouts (TransferChecked + Memo anywhere in top-level instructions) so non-spec variants still get indexed. Known facilitators include: Coinbase, PayAI, Dexter, Daydreams, OpenX402, AnySpend, CodeNut, Corbits, Aurracloud, Bitrefill, Cascade, OpenFacilitator, Relai, UltravioletaDAO, X402Jobs.

Splitting volume by scheme

SELECT scheme, COUNT(*) AS settlements, SUM(amount::numeric) AS volume
FROM settlements
GROUP BY scheme;

Channel activity, for upto only:

SELECT channel, COUNT(*) AS settlements, SUM(amount::numeric) AS volume
FROM settlements
WHERE scheme = 'upto'
GROUP BY channel
ORDER BY volume DESC;

Discovering new facilitators

Every settlement has facilitator_name (empty if unknown) and facilitator_known (boolean). To find new facilitators to add to the allowlist:

SELECT facilitator, COUNT(*) AS tx_count, SUM(amount) AS volume
FROM settlements
WHERE facilitator_known = false
GROUP BY facilitator
ORDER BY tx_count DESC
LIMIT 20;

High-volume unknown fee-payers are candidates. Verify on Solscan, then add to KNOWN_FACILITATORS in src/lib.rs and publish a new version.

Modules

ModuleKindDescription
map_x402_settlementsMapDetects x402 settlements in each Solana block and extracts payer / recipient / mint / amount / facilitator / memo
store_payer_volumeStoreAccumulates total amount spent per payer pubkey
store_payer_countStoreCounts payments per payer
store_recipient_volumeStoreAccumulates total received per resource server (ATA owner)
store_recipient_countStoreCounts payments per recipient
store_facilitator_volumeStoreAccumulates volume settled per facilitator
store_facilitator_countStoreCounts settlements per facilitator
store_facilitator_feesStoreAccumulates tx fees (lamports) paid per facilitator
store_first_seenStoreRecords first-seen block timestamp per payer / recipient / facilitator
map_payer_statsMapComputes payer leaderboards and averages
map_recipient_statsMapComputes resource server revenue stats
map_facilitator_statsMapComputes facilitator economics (volume, fees, counts)
db_outMapOutputs DatabaseChanges for the PostgreSQL sink

Programs Indexed

ProgramPubkey
SPL TokenTokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
SPL Token-2022TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
SPL Memo v2MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr
SPL Memo v1Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo

Quick Start

# Stream settlements
substreams run x402-solana-pulse map_x402_settlements \
  -e mainnet.sol.streamingfast.io:443 \
  -s 280000000 -t +1000

# GUI mode
substreams gui x402-solana-pulse map_x402_settlements \
  -e mainnet.sol.streamingfast.io:443 \
  -s 280000000

# Sink to PostgreSQL
substreams-sink-sql run "psql://localhost/x402" \
  x402-solana-pulse-v1.0.0.spkg \
  -e mainnet.sol.streamingfast.io:443

SQL Output

Tables

TableKeyDescription
settlementssignature-instruction_indexEvery settlement with payer, recipient, mint, amount, facilitator, fee, memo
payerspayer_addressAggregated spend and payment count per payer pubkey
recipientsrecipient_addressRevenue and payment count per resource server
facilitatorsfacilitator_addressVolume settled, settlement count, lamport fees per facilitator

Views

ViewDescription
daily_statsDaily protocol-wide volume, unique participants, fees
top_payersRanked by total spend
top_recipientsRanked by total revenue
facilitator_economicsVolume settled vs fee cost per facilitator
whale_paymentsPayments ≥ 100 USDC (atomic units)
recent_settlementsLatest 100 settlements

Build

cargo build --target wasm32-unknown-unknown --release
substreams pack substreams.yaml

References

Network

  • Chain: Solana mainnet
  • Endpoint: mainnet.sol.streamingfast.io:443
  • Initial block: 280,000,000 (adjustable)

Modules

Execution graph

13 modules
map

map_x402_settlements

Extracts x402 payment settlements on Solana by detecting the SVM `exact` scheme settlement shape: a transaction that contains an SPL Token (or Token-2022) TransferChecked instruction paired with an SPL Memo instruction, where the transaction fee payer is distinct from the TransferChecked authority (the facilitator sponsors, the payer signs). Per the x402 SVM exact scheme: https://github.com/coinbase/x402/blob/main/specs/schemes/exact/scheme_exact_svm.md

from #280000000
store

store_facilitator_count

Counts total settlements per facilitator. Key: {facilitator_pubkey}

from #280000000

Store value

int64

Update policy

add

store

store_facilitator_fees

Accumulates total tx fees (lamports) spent per facilitator. Key: {facilitator_pubkey}

from #280000000

Store value

bigint

Update policy

add

store

store_facilitator_volume

Accumulates total volume settled per facilitator. Key: {facilitator_pubkey}

from #280000000

Store value

bigint

Update policy

add

store

store_first_seen

Records first-seen block timestamp per entity. Key: payer:{p}, recipient:{r}, facilitator:{f}

from #280000000

Store value

int64

Update policy

set_if_not_exists

store

store_payer_count

Counts total payments per payer. Key: {payer_pubkey}

from #280000000

Store value

int64

Update policy

add

store

store_payer_volume

Accumulates total payment volume per payer. Key: {payer_pubkey}

from #280000000

Store value

bigint

Update policy

add

store

store_recipient_count

Counts total payments per recipient. Key: {recipient_pubkey}

from #280000000

Store value

int64

Update policy

add

store

store_recipient_volume

Accumulates total revenue per recipient. Key: {recipient_pubkey}

from #280000000

Store value

bigint

Update policy

add