LogoLogo
Package RegistryThe Graph
  • Introduction
  • Getting Started
  • Tutorials
    • Develop Your First Substreams
      • on EVM
      • on Solana
        • Transactions & Instructions
        • Account Changes
      • on Cosmos
        • Injective
        • MANTRA
      • on Starknet
      • on Stellar
    • Publishing a Substreams Package
  • How-To Guides
    • Developing Substreams
      • on EVM
        • Exploring Ethereum
          • Mapping Blocks
          • Filter Transactions
          • Retrieve Events of a Smart Contract
      • on Solana
        • Explore Solana
          • Filter Instructions
          • Filter Transactions
        • SPL Token Tracker
        • NFT Trades
        • DEX Trades
      • on Cosmos
        • Injective
          • Simple Substreams Example
          • Foundational Modules
          • Dojo DEX USDT Volume Subgraph Example
    • Using a Substreams Sink
      • Substreams:SQL
      • Substreams:Subgraph
        • Triggers
        • Graph Out
      • Substreams:Stream
        • JavaScript
        • Go
      • Substreams:PubSub
      • Community Sinks
        • MongoDB
        • Files
        • Key-Value Store
        • Prometheus
    • EVM Extensions
      • Making eth_calls
    • Getting Started Using Rust and Protobuf
      • Rust
        • Option struct
        • Result struct
      • Protobuf Schemas
    • From Yellowstone to Substreams
  • Reference Material
    • Chains and endpoints
      • Ethereum Data Model
    • Never Miss Data
    • Development Container Reference
    • Substreams CLI
      • Install the CLI
      • Authentication
      • Substreams CLI reference
    • Substreams Components
      • Packages
      • Modules
        • Module types
        • Inputs
        • Output
        • Module handlers
        • Module handler creation
        • Indexes
        • Keys in stores
        • Dynamic data sources
        • Aggregation Windows
        • Parameterized Modules
      • Manifests Reference
    • Substreams Architecture
    • Graph-Node
      • Local Development
      • Publish to The Graph Network
    • Indexer Reference
      • Test Substreams Locally
    • Logging, Debugging & Testing
    • Change log
    • FAQ
  • Decentralized Indexing
    • What is The Graph?
Powered by GitBook
On this page
  • Module handlers overview
  • Cargo.toml configuration file breakdown
  • Rust toolchain
  • Rust build target
  • ABI generation
  • Rust build script

Was this helpful?

Edit on GitHub
  1. Reference Material
  2. Substreams Components
  3. Modules

Module handlers

StreamingFast Substreams module handlers

PreviousOutputNextIndexes

Last updated 5 months ago

Was this helpful?

Module handlers overview

To begin creating the custom module handlers initialize a new Rust project by using the cargo init command.

# Creates a empty Rust project suitable for WASM compilation
cargo init --lib

Update the generated file by using:

Cargo.toml
[package]
name = "substreams-template"
version = "0.1.0"
description = "Substreams template demo project"
edition = "2021"
repository = "https://github.com/streamingfast/substreams-template"

[lib]
name = "substreams"
crate-type = ["cdylib"]

[dependencies]
ethabi = "17"
hex-literal = "0.3.4"
prost = "0.11"
# Use latest from https://crates.io/crates/substreams
substreams = "0.5"
# Use latest from https://crates.io/crates/substreams-ethereum
substreams-ethereum = "0.9"

# Required so ethabi > ethereum-types build correctly under wasm32-unknown-unknown
[target.wasm32-unknown-unknown.dependencies]
getrandom = { version = "0.2", features = ["custom"] }

[build-dependencies]
anyhow = "1"
substreams-ethereum = "0.8"

[profile.release]
lto = true
opt-level = 's'
strip = "debuginfo"

Cargo.toml configuration file breakdown

Build the Rust dynamic system library after the package by using:

Cargo.toml excerpt
...

[lib]
crate-type = ["cdylib"]

Note: Module handlers compile down to a WASM module. Explicitly specify the targetasm32-unknown-unknown by using [target.wasm32-unknown-unknown.dependencies].

ethabi

hex-literal

substreams

substreams-ethereum

Rust toolchain

rust-toolchain.toml
[toolchain]
channel = "1.65"
components = [ "rustfmt" ]
targets = [ "wasm32-unknown-unknown" ]

Build the code by using:

cargo build --target wasm32-unknown-unknown --release

Rust build target

When running cargo build the target is set to wasm32-unknown-unknown, which is important because it specifies the goal is to generate compiled WASM code.

To avoid having to specify the target wasm32-unknown-unknown for every cargo command, create a config.toml configuration file in the .cargo directory at the root of the Substreams project. The config.toml configuration file allows the target to be set automatically for all cargo commands.

The content for the config.toml configuration file is:

.cargo/config.toml
[build]
target = "wasm32-unknown-unknown"

The config.toml configuration file updates the default cargo build command to cargo build --target wasm32-unknown-unknown eliminating the need to specify the target manually every time you build.

ABI generation

Rust build script

Before building a package, Cargo compiles a build script into an executable if it has not already been built. The build script runs as part of the build process responsible for performing a variety of tasks.

To cause Cargo to compile and run a script before building a package, place a file called build.rs in the root of the package.

build.rs
use anyhow::{Ok, Result};
use substreams_ethereum::Abigen;

fn main() -> Result<(), anyhow::Error> {
    Abigen::new("ERC721", "abi/erc721.json")?
        .generate()?
        .write_to_file("src/abi/erc721.rs")?;

    Ok(())
}

Run the build script to generate the ABI directory and files.

cargo build --target wasm32-unknown-unknown --release
src/abi/mod.rs
pub mod erc721;

View the file in the repository.

You compile the Rust code into , a binary instruction format that runs in a virtual machine. The compilation process generates a .so file.

The next definition in the configuration file is for dependencies.

The is used to decode events from the application binary interface (ABI) and is required for substreams-ethereum ABI capabilities.

The is used to define bytes from hexadecimal string literals at compile time.

The offers all the basic building blocks for the module handlers.

The offers all the Ethereum constructs including blocks, transactions, eth, and useful ABI decoding capabilities.

Because code is being built by WASM output it's necessary to configure Rust to match the correct architecture. Create and add a configuration file at the root of your Substreams directory.

View the file in the repository.

The offers an API to generate Rust types from a smart contract's ABI.

Place the contract's in the Substreams project in the abi directory.

Create a build script file in the root of the Substreams project by using:

View the file in the repository.

Create a export file in the ABI directory, which is created by the Rust build process. The export file is responsible for exporting the generated Rust code.

View the file in the repository.

You're now ready to .

Cargo.toml
Cargo.toml
WebAssembly (WASM)
Cargo.toml
ethabi crate
hex-literal crate
substreams crate
substreams-ethereum crate
rust-toolchain.toml
rust-toolchain.toml
substreams-ethereum crate
Abigen
ABI JSON file
build.rs
build.rs
mod.rs
mod.rs
mod.rs
write the module handlers