Module handlers
StreamingFast Substreams module handlers
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 --libUpdate the generated Cargo.toml file by using:
[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"View the Cargo.toml file in the repository.
You compile the Rust code into WebAssembly (WASM), a binary instruction format that runs in a virtual machine. The compilation process generates a .so file.
Cargo.toml configuration file breakdown
Cargo.toml configuration file breakdownBuild the Rust dynamic system library after the package by using:
...
[lib]
crate-type = ["cdylib"]The next definition in the Cargo.toml configuration file is for dependencies.
ethabi
ethabiThe ethabi crate is used to decode events from the application binary interface (ABI) and is required for substreams-ethereum ABI capabilities.
hex-literal
hex-literalThe hex-literal crate is used to define bytes from hexadecimal string literals at compile time.
substreams
substreamsThe substreams crate offers all the basic building blocks for the module handlers.
substreams-ethereum
substreams-ethereumThe substreams-ethereum crate 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 rust-toolchain.toml configuration file at the root of your Substreams directory.
Rust toolchain
[toolchain]
channel = "1.65"
components = [ "rustfmt" ]
targets = [ "wasm32-unknown-unknown" ]View the rust-toolchain.toml file in the repository.
Build the code by using:
cargo build --target wasm32-unknown-unknown --releaseRust 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:
[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
The substreams-ethereum crate offers an Abigen API to generate Rust types from a smart contract's ABI.
Place the contract's ABI JSON file in the Substreams project in the abi directory.
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.
Create a build.rs build script file in the root of the Substreams project by using:
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(())
}View the build.rs file in the repository.
Run the build script to generate the ABI directory and files.
cargo build --target wasm32-unknown-unknown --releaseCreate a mod.rs export file in the ABI directory, which is created by the Rust build process. The mod.rs export file is responsible for exporting the generated Rust code.
pub mod erc721;View the mod.rs file in the repository.
You're now ready to write the module handlers.
Last updated
Was this helpful?

