|
| 1 | +--- |
| 2 | +title: 'Tutorial: Set Up a Substreams-Powered Subgraph on Solana' |
| 3 | +--- |
| 4 | + |
| 5 | +## Prerequisites |
| 6 | + |
| 7 | +Before starting, make sure to: |
| 8 | + |
| 9 | +- Complete the [Getting Started Guide](https://github.com/streamingfast/substreams-starter) to set up your development environment using a Dev Container. |
| 10 | +- Be familiar with The Graph and basic blockchain concepts such as transactions and Protobufs. |
| 11 | + |
| 12 | +## Step 1: Initialize Your Project |
| 13 | + |
| 14 | +1. Open your Dev Container and run the following command to initialize your project: |
| 15 | + |
| 16 | + ```bash |
| 17 | + substreams init |
| 18 | + ``` |
| 19 | + |
| 20 | +2. Select the "minimal" project option. |
| 21 | +3. 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: |
| 22 | + |
| 23 | +```yaml |
| 24 | +specVersion: v0.1.0 |
| 25 | +package: |
| 26 | + name: my_project_sol |
| 27 | + version: v0.1.0 |
| 28 | + |
| 29 | +imports: # Pass your spkg of interest |
| 30 | + solana: https://github.com/streamingfast/substreams-solana-spl-token/raw/master/tokens/solana-spl-token-v0.1.0.spkg |
| 31 | + |
| 32 | +modules: |
| 33 | + - name: map_spl_transfers |
| 34 | + use: solana:map_block # Select corresponding modules available within your spkg |
| 35 | + initialBlock: 260000082 |
| 36 | + |
| 37 | + - name: map_transactions_by_programid |
| 38 | + use: solana:solana:transactions_by_programid_without_votes |
| 39 | + |
| 40 | +network: solana-mainnet-beta |
| 41 | + |
| 42 | +params: # Modify the param fields to meet your needs |
| 43 | + # For program_id: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA |
| 44 | + map_spl_transfers: token_contract:orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE |
| 45 | +``` |
| 46 | +
|
| 47 | +## Step 2: Generate the Subgraph Manifest |
| 48 | +
|
| 49 | +Once the project is initialized, generate a subgraph manifest by running the following command in the Dev Container: |
| 50 | +
|
| 51 | +```bash |
| 52 | +substreams codegen subgraph |
| 53 | +``` |
| 54 | + |
| 55 | +You will generate a`subgraph.yaml` manifest which imports the Substreams package as a data source: |
| 56 | + |
| 57 | +```yaml |
| 58 | +--- |
| 59 | +dataSources: |
| 60 | + - kind: substreams |
| 61 | + name: my_project_sol |
| 62 | + network: solana-mainnet-beta |
| 63 | + source: |
| 64 | + package: |
| 65 | + moduleName: map_spl_transfers # Module defined in the substreams.yaml |
| 66 | + file: ./my-project-sol-v0.1.0.spkg |
| 67 | + mapping: |
| 68 | + apiVersion: 0.0.7 |
| 69 | + kind: substreams/graph-entities |
| 70 | + file: ./src/mappings.ts |
| 71 | + handler: handleTriggers |
| 72 | +``` |
| 73 | +
|
| 74 | +## Step 3: Define Entities in `schema.graphql` |
| 75 | + |
| 76 | +Define the fields you want to save in your subgraph entities by updating the `schema.graphql` file. Here is an example: |
| 77 | + |
| 78 | +```graphql |
| 79 | +type MyTransfer @entity { |
| 80 | + id: ID! |
| 81 | + amount: String! |
| 82 | + source: String! |
| 83 | + designation: String! |
| 84 | + signers: [String!]! |
| 85 | +} |
| 86 | +``` |
| 87 | + |
| 88 | +This schema defines a `MyTransfer` entity with fields such as `id`, `amount`, `source`, `designation`, and `signers`. |
| 89 | + |
| 90 | +## Step 4: Generate Protobuf Files |
| 91 | + |
| 92 | +To generate Protobuf objects in AssemblyScript, run the following command: |
| 93 | + |
| 94 | +```bash |
| 95 | +npm run protogen |
| 96 | +``` |
| 97 | + |
| 98 | +This command converts the Protobuf definitions into AssemblyScript, allowing you to use them in the subgraph's handler. |
| 99 | + |
| 100 | +## Step 5: Handle Substreams Data in `mappings.ts` |
| 101 | + |
| 102 | +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: |
| 103 | + |
| 104 | +```ts |
| 105 | +import { Protobuf } from 'as-proto/assembly' |
| 106 | +import { Events as protoEvents } from './pb/sf/solana/spl/token/v1/Events' |
| 107 | +import { MyTransfer } from '../generated/schema' |
| 108 | +
|
| 109 | +export function handleTriggers(bytes: Uint8Array): void { |
| 110 | + const input: protoEvents = Protobuf.decode<protoEvents>(bytes, protoEvents.decode) |
| 111 | +
|
| 112 | + for (let i = 0; i < input.data.length; i++) { |
| 113 | + const event = input.data[i] |
| 114 | +
|
| 115 | + if (event.transfer != null) { |
| 116 | + let entity_id: string = `${event.txnId}-${i}` |
| 117 | + const entity = new MyTransfer(entity_id) |
| 118 | + entity.amount = event.transfer!.instruction!.amount.toString() |
| 119 | + entity.source = event.transfer!.accounts!.source |
| 120 | + entity.designation = event.transfer!.accounts!.destination |
| 121 | + |
| 122 | + if (event.transfer!.accounts!.signer!.single != null) { |
| 123 | + entity.signers = [event.transfer!.accounts!.signer!.single.signer] |
| 124 | + } else if (event.transfer!.accounts!.signer!.multisig != null) { |
| 125 | + entity.signers = event.transfer!.accounts!.signer!.multisig!.signers |
| 126 | + } |
| 127 | + entity.save() |
| 128 | + } |
| 129 | + } |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +## Conclusion |
| 134 | + |
| 135 | +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. |
| 136 | + |
| 137 | +For more advanced customization and optimizations, check out the official [Substreams documentation](https://substreams.streamingfast.io/tutorials/solana). |
0 commit comments