Package Logo
solana-m0-orderbook
solana-m0-orderbook@v0.2.0
Total Downloads
33
Published
5 hours ago
Publisher
User Avatar jonalvarezz

Readme

Solana Substreams — M0 OrderBook

A Substreams module that indexes the M0 OrderBook program on Solana and sinks its events into the shared Postgres database (the solana schema). The EVM chains are indexed separately by Envio (see ../evm); the unified cross-chain views live in ../sql/views.sql.

Program ID (devnet + mainnet): MzLoYnJ6sF6eeejs4vV95TNmXqS3W4cAtLGKkjT4ZrK

What it indexes

map_svm_events (in src/lib.rs) scans each block's transactions for the program's Anchor CPI events, decodes them, and emits one row per event. The proto schema (proto/program.proto) maps each event to a table:

Event Table
OrderOpened events_order_opened
OrderFilled events_order_filled
OrderCompleted events_order_completed
OrderCancelled events_order_cancelled
FillReported events_fill_reported
CancelReported events_cancel_reported
RefundClaimed events_refund_claimed

OrderOpened has two on-chain layouts that share an Anchor discriminator: the legacy (V1, 188-byte) event and the current (V2, 228-byte) event that adds funder and fill_deadline. The handler dispatches on payload length — V1 events synthesize funder = sender and derive fill_deadline from the amount, V2 events read both fields directly. This mirrors the EVM indexer's V1/V2 handling.

Networks

Each network has its own manifest. They share the same Rust/proto code and differ only in package name, start block, network, and the chain_id written to rows.

Network Manifest Package initialBlock chain_id
Solana mainnet substreams-solana.yaml solana-m0-orderbook 399833693 1399811149
Solana devnet substreams-solana-devnet.yaml solana-devnet-m0-orderbook 436247835 1399811150

Build & test locally

# Compile the WASM module (output: target/wasm32-unknown-unknown/release/substreams.wasm)
just cargo-build

# Stream 10 blocks from a start block through the GUI to inspect decoded events
just debug-gui solana-devnet <start_block>
just debug-gui solana <start_block>

Pick a <start_block> at or just before a known order to see events in the output. The GUI requires a Substreams API token (see below).

Packages

Published packages live in the Substreams registry under their package names (solana-m0-orderbook, solana-devnet-m0-orderbook). The deployed sink references a package by its .spkg (via the PACKAGE env var), e.g. solana-devnet-m0-orderbook-v0.2.0.spkg.

Publishing a new version

  1. Authenticate to the registry (sets SUBSTREAMS_API_TOKEN):

    substreams auth
    
  2. Bump package.version in the target manifest and keep version in the justfile in sync — substreams pack names the file from the manifest while the publish step uses the justfile var, so they must match. (Or override per run: just version=v0.3.0 build-and-publish solana-devnet.)

  3. Build, pack, and publish:

    just build-and-publish solana-devnet   # or: solana (mainnet)
    

Deployment

The indexer runs as a containerized substreams-sink-sql sink. The image entrypoint is substreams-sink-sql from-proto "$DSN" "$PACKAGE", which creates the tables from the proto schema on first run and streams events into Postgres.

# Build & push the runtime image (ghcr.io/m0-foundation/liquidity-delivery:orderbook-substreams)
just build-docker-image

Run the container (in our AWS/ECS infra) with:

Env Value
DSN Postgres connection string (writes to the solana schema)
SUBSTREAMS_API_TOKEN registry token from substreams auth
PACKAGE published spkg, e.g. solana-m0-orderbook-v0.2.0.spkg

After the sink creates/updates the tables, (re)apply ../sql/views.sql so the unified public.* views expose any new columns.

Schema changes & reindexing

substreams-sink-sql resumes from a stored cursor and does not auto-migrate existing tables when the proto changes. To pick up new columns across history, either drop the solana schema and let the sink recreate + backfill from initialBlock, or ALTER TABLE to add the columns and accept NULLs on rows that predate the change (they are not reprocessed).

Documentation

Modules

Maps icon
Maps

map
map_svm_events

8a0fbd4f7d466a400f4b87a7d71ffee899e539ba
map map_svm_events (
paramsstring
solana:blocks_without_votessf.solana.type.v1.Block
)  -> substreams.v1.program.Data
Default param : 1399811149
substreams gui solana-m0-orderbook@v0.2.0 map_svm_events

map
solana:blocks_without_votes

0be93a73c65aa8ec2de4b1a47209edeea493ff29
map solana:blocks_without_votes (
)  -> sf.solana.type.v1.Block
substreams gui solana-m0-orderbook@v0.2.0 solana:blocks_without_votes

map
solana:v020:blocks_without_votes

0be93a73c65aa8ec2de4b1a47209edeea493ff29
map solana:v020:blocks_without_votes (
)  -> sf.solana.type.v1.Block

blocks_without_votes allows you to consume a full Solana Block without Vote instructions (Vote111111111111111111111111111111111111111). If you consume it on HISTORICAL data (+1000 blocks from HEAD), you will be reading from the StreamingFast cache, thus saving costs on the amount of TB read.

substreams gui solana-m0-orderbook@v0.2.0 solana:v020:blocks_without_votes
Block Indexes icon
Block Indexes

blockIndex
solana:program_ids_without_votes

811466d12743a8b02be8ba6649cfa9a24aa1af62
substreams gui solana-m0-orderbook@v0.2.0 solana:program_ids_without_votes
Protobuf

Protobuf Docs Explorer

sol.transactions.v1
schema
substreams.v1.program
sf.solana.type.v1
sol.instructions.v1