Tutorial: Set Up a Substreams-Powered Subgraph on Solana
Reading time: 3 min
Before starting, make sure to:
- Complete the to set up your development environment using a Dev Container.
- Be familiar with The Graph and basic blockchain concepts such as transactions and Protobufs.
Open your Dev Container and run the following command to initialize your project:
substreams initSelect the "minimal" project option.
Replace the contents of the generated
substreams.yaml
file with the following configuration, which filters transactions for the Orca account on the SPL token program ID:
specVersion: v0.1.0package:name: my_project_solversion: v0.1.0imports: # Pass your spkg of interestsolana: https://github.com/streamingfast/substreams-solana-spl-token/raw/master/tokens/solana-spl-token-v0.1.0.spkgmodules:- name: map_spl_transfersuse: solana:map_block # Select corresponding modules available within your spkginitialBlock: 260000082- name: map_transactions_by_programiduse: solana:solana:transactions_by_programid_without_votesnetwork: solana-mainnet-betaparams: # Modify the param fields to meet your needs# For program_id: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DAmap_spl_transfers: token_contract:orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE
Once the project is initialized, generate a subgraph manifest by running the following command in the Dev Container:
substreams codegen subgraph
You will generate asubgraph.yaml
manifest which imports the Substreams package as a data source:
---dataSources:- kind: substreamsname: my_project_solnetwork: solana-mainnet-betasource:package:moduleName: map_spl_transfers # Module defined in the substreams.yamlfile: ./my-project-sol-v0.1.0.spkgmapping:apiVersion: 0.0.7kind: substreams/graph-entitiesfile: ./src/mappings.tshandler: handleTriggers
Define the fields you want to save in your subgraph entities by updating the schema.graphql
file. Here is an example:
type MyTransfer @entity {id: ID!amount: String!source: String!designation: String!signers: [String!]!}
This schema defines a MyTransfer
entity with fields such as id
, amount
, source
, designation
, and signers
.
With the Protobuf objects generated, you can now handle the decoded Substreams data in your mappings.ts
file found in the ./src
directory. The example below demonstrates how to extract to subgraph entities the non-derived transfers associated to the Orca account id:
import { Protobuf } from 'as-proto/assembly'import { Events as protoEvents } from './pb/sf/solana/spl/token/v1/Events'import { MyTransfer } from '../generated/schema'export function handleTriggers(bytes: Uint8Array): void {const input: protoEvents = Protobuf.decode<protoEvents>(bytes, protoEvents.decode)for (let i = 0; i < input.data.length; i++) {const event = input.data[i]if (event.transfer != null) {let entity_id: string = `${event.txnId}-${i}`const entity = new MyTransfer(entity_id)entity.amount = event.transfer!.instruction!.amount.toString()entity.source = event.transfer!.accounts!.sourceentity.designation = event.transfer!.accounts!.destinationif (event.transfer!.accounts!.signer!.single != null) {entity.signers = [event.transfer!.accounts!.signer!.single!.signer]} else if (event.transfer!.accounts!.signer!.multisig != null) {entity.signers = event.transfer!.accounts!.signer!.multisig!.signers}entity.save()}}}
To generate Protobuf objects in AssemblyScript, run the following command:
npm run protogen
This command converts the Protobuf definitions into AssemblyScript, allowing you to use them in the subgraph's handler.
You’ve successfully set up a trigger-based Substreams-powered subgraph for a Solana SPL token. You can now further customize your schema, mappings, and modules to suit your specific use case.
For more advanced customization and optimizations, check out the official .