SQD Quickstart
This is a 5-10 minutes quickstart on how to build an indexer using Squid SDK.
What You Will Learn:
- How to fetch all transactions from the mint address
- Decode it
- Save it to a local Postgres database
- Start a GraphQL server with a rich API to query the transactions
What You Need Before Starting (Prerequisites):
- (On Windows) WSL
- Node.js v18+
- Git
- Docker (for running Postgres)
Step 1 - Install Squid CLI
Install Squid CLI:
pnpm i -g @subsquid/cli
Squid CLI is a command line tool for for creating and managing the indexers, both locally and in SQD Cloud.
Step 2 - Create the Indexer Project (Squid)
Create the indexer project (squid) from an example repo using Squid CLI:
sqd init arthera-squid -t https://github.com/bertux/arthera-squid && cd arthera-squid
The example is a starter template of a squid indexer for EVM networks (slightly modified to fit Arthera).
Step 3 - Explore the ./src Folder
Inspect the ./src
folder:
src/
├── abi
├── main.ts
├── processor.ts
└── model
├── generated
│ ├── mint.model.ts
│ ├── index.ts
│ └── marshal.ts
└── index.ts
src/abi
serves as a utility module created from the JSON ABI of the contracts you want to interact with. One module will be generated for each ABI file, and it will include constants useful for filtering and functions for decoding EVM events and functions defined in the ABI. We are not working with ABI in this tutorial.src/model
contains TypeORM model classes autogenerated fromschema.graphql
. Squids use them to populate Postgres.
processor.ts
is the main executable. In this example, it also contains all the data retrieval configuration.
Made minor changes to the official minimal EVM template to get real-time data about Arthera transactions from the zero address:
- Declare a variable for the mint address
const ARTHERA_MINT_ADDRESS = '0x0000000000000000000000000000000000000000'
- Change
.setGateway
to https://v2.archive.subsquid.io/network/arthera-mainnet - Provide an RPC endpoint to get real-time data and store it in
arthera-squid/.env
. E.g.RPC_ETH_HTTP
= https://rpc.arthera.net - Adjust
.setFields
to replacefrom: true
byto: true
- Adjust
.addTransaction
to use our constantARTHERA_MINT_ADDRESS
Optional changes:
rateLimit
(requests per second, default is no limit)setFinalityConfirmation
(sets the number of blocks after which the processor will consider the consensus data final)setBlockRange
(limits the range of blocks to be processed)
const ARTHERA_MINT_ADDRESS = '0x0000000000000000000000000000000000000000'
export const processor = new EvmBatchProcessor()
// Lookup archive by the network name in Subsquid registry
// See https://docs.subsquid.io/evm-indexing/supported-networks/
.setGateway('https://v2.archive.subsquid.io/network/arthera-mainnet')
// Chain RPC endpoint is required for
// - indexing unfinalized blocks https://docs.subsquid.io/basics/unfinalized-blocks/
// - querying the contract state https://docs.subsquid.io/evm-indexing/query-state/
.setRpcEndpoint({
// Set the URL via .env for local runs or via secrets when deploying to Subsquid Cloud
// https://docs.subsquid.io/deploy-squid/env-variables/
url: assertNotNull(process.env.RPC_ETH_HTTP, 'No RPC endpoint supplied'),
// More RPC connection options at https://docs.subsquid.io/evm-indexing/configuration/initialization/#set-data-source
rateLimit: 10
})
.setFinalityConfirmation(75)
.setFields({
transaction: {
to: true,
value: true,
hash: true,
},
})
.setBlockRange({
from: 0,
})
.addTransaction({
from: [ARTHERA_MINT_ADDRESS],
})
The main.ts
file is about data processing and storage (changed tx.from
by tx.to
):
processor.run(new TypeormDatabase({supportHotBlocks: true}), async (ctx) => {
const mints: Mint[] = []
for (let c of ctx.blocks) {
for (let tx of c.transactions) {
// decode and normalize the tx data
mints.push(
new Mint({
id: tx.id,
block: c.header.height,
address: tx.to,
value: tx.value,
txHash: tx.hash,
})
)
}
}
// apply vectorized transformations and aggregations
const minted = mints.length
const startBlock = ctx.blocks.at(0)?.header.height
const endBlock = ctx.blocks.at(-1)?.header.height
ctx.log.info(`Minted a total of ${minted} from ${startBlock} to ${endBlock}`)
// upsert batches of entities with batch-optimized ctx.store.save
await ctx.store.upsert(mints)
})
Step 4 - Install Dependencies and Build the Project
Install the dependencies and build.
npm ci
npm run build
Step 5 - Initialize Local Postgres Database
The processor is a background process that continously fetches the data, decodes it and stores it in a local Postgres. All the logic is defined in main.ts
and is fully customizable.
To run the processor, we first start a local Postgres where the decoded data is persisted (the template comes with a Docker compose file):
docker compose up -d
Step 6 - Apply Database Migrations
Processor will connect to Postgres using the connection parameters from .env
.
Apply database migrations with:
npx squid-typeorm-migration apply
Step 7 - Start the Processor
Then start the processor with:
node -r dotenv/config lib/main.js
The indexer is now running.
Step 8 - Launch the GraphQL Playground
Start the GraphQL API serving the mint transaction data from Postgres:
npx squid-graphql-server
The server comes with a GraphQL playground available at localhost:4350/graphql
in your browser.
Try the query below to get the last 10 transactions:
query MyQuery {
mints(limit: 10, orderBy: id_ASC) {
txHash
address
block
}
}
Example of the GraphQL playground:
The example above shows data that you can find on Arthera's explorer too:
Next steps
We hope you found this tutorial helpful and are eager to learn more! 😊
Here are three actions you can take next:
- Visit our Documentation for detailed guides and resources.
- Explore more EVM examples to enhance your skills.
- Join our Discord community to ask questions and connect with other builders.
Once you are ready to build your dApp with SQD, you can either self-host or use our SQD Cloud. We offer SQD Cloud credits worth $500 to support projects built on Arthera. If you're interested, please complete this form, and we'll be in touch shortly.