├── .gitignore ├── evm-transactions-example ├── src │ ├── model │ │ ├── index.ts │ │ └── generated │ │ │ ├── index.ts │ │ │ ├── transaction.model.ts │ │ │ └── marshal.ts │ ├── processor.ts │ └── main.ts ├── .gitignore ├── .env ├── .DS_Store ├── schema.graphql ├── docker-compose.yml ├── squid.yaml ├── tsconfig.json ├── db │ └── migrations │ │ └── 1681397371690-Data.js ├── renovate.json ├── package.json ├── README.md ├── .gitpod.yml ├── commands.json └── abi │ └── erc20.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /evm-transactions-example/src/model/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./generated" 2 | -------------------------------------------------------------------------------- /evm-transactions-example/src/model/generated/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./transaction.model" 2 | -------------------------------------------------------------------------------- /evm-transactions-example/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /lib 3 | 4 | # IDE files 5 | /.idea 6 | pnpm-lock.yaml 7 | **/*.log -------------------------------------------------------------------------------- /evm-transactions-example/.env: -------------------------------------------------------------------------------- 1 | DB_NAME=squid 2 | DB_PASS=squid 3 | DB_PORT=23798 4 | PROCESSOR_PROMETHEUS_PORT=3000 5 | GQL_PORT=4350 6 | -------------------------------------------------------------------------------- /evm-transactions-example/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/subsquid-quests/snapshot-subgraph-migration/HEAD/evm-transactions-example/.DS_Store -------------------------------------------------------------------------------- /evm-transactions-example/schema.graphql: -------------------------------------------------------------------------------- 1 | type Transaction @entity { 2 | id: ID! 3 | block: Int! 4 | timestamp: DateTime! 5 | hash: String! 6 | from: String! 7 | to: String! 8 | input: String! 9 | } -------------------------------------------------------------------------------- /evm-transactions-example/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | db: 5 | image: postgres:15 6 | environment: 7 | POSTGRES_DB: squid 8 | POSTGRES_PASSWORD: squid 9 | ports: 10 | - "${DB_PORT}:5432" 11 | # command: ["postgres", "-c", "log_statement=all"] 12 | -------------------------------------------------------------------------------- /evm-transactions-example/squid.yaml: -------------------------------------------------------------------------------- 1 | manifestVersion: subsquid.io/v0.1 2 | name: transactions-example 3 | version: 1 4 | description: |- 5 | Basic example of processing transactions 6 | build: 7 | 8 | deploy: 9 | addons: 10 | postgres: 11 | processor: 12 | cmd: [ "node", "lib/main" ] 13 | api: 14 | cmd: [ "npx", "squid-graphql-server", "--dumb-cache", "in-memory", "--dumb-cache-ttl", "1000", "--dumb-cache-size", "100", "--dumb-cache-max-age", "1000" ] -------------------------------------------------------------------------------- /evm-transactions-example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2020", 5 | "outDir": "lib", 6 | "rootDir": "src", 7 | "strict": true, 8 | "resolveJsonModule": true, 9 | "declaration": false, 10 | "sourceMap": true, 11 | "esModuleInterop": true, 12 | "experimentalDecorators": true, 13 | "emitDecoratorMetadata": true, 14 | "skipLibCheck": true 15 | }, 16 | "include": ["src"], 17 | "exclude": [ 18 | "node_modules" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /evm-transactions-example/db/migrations/1681397371690-Data.js: -------------------------------------------------------------------------------- 1 | module.exports = class Data1681397371690 { 2 | name = 'Data1681397371690' 3 | 4 | async up(db) { 5 | await db.query(`CREATE TABLE "transaction" ("id" character varying NOT NULL, "block" integer NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "hash" text NOT NULL, "from" text NOT NULL, "to" text NOT NULL, "input" text NOT NULL, CONSTRAINT "PK_89eadb93a89810556e1cbcd6ab9" PRIMARY KEY ("id"))`) 6 | } 7 | 8 | async down(db) { 9 | await db.query(`DROP TABLE "transaction"`) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /evm-transactions-example/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ], 6 | "packageRules": [ 7 | { 8 | "groupName": "@subsquid", 9 | "matchPackagePatterns": [ 10 | "^@subsquid/" 11 | ], 12 | "matchUpdateTypes": [ 13 | "minor", 14 | "patch", 15 | "pin", 16 | "digest" 17 | ] 18 | }, 19 | { 20 | "matchPackagePatterns": ["*"], 21 | "excludePackagePatterns": ["^@subsquid/"], 22 | "enabled": false 23 | } 24 | ], 25 | "automerge": true, 26 | "automergeType": "pr", 27 | "automergeStrategy": "squash", 28 | "ignoreTests": true 29 | } -------------------------------------------------------------------------------- /evm-transactions-example/src/model/generated/transaction.model.ts: -------------------------------------------------------------------------------- 1 | import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_} from "typeorm" 2 | 3 | @Entity_() 4 | export class Transaction { 5 | constructor(props?: Partial) { 6 | Object.assign(this, props) 7 | } 8 | 9 | @PrimaryColumn_() 10 | id!: string 11 | 12 | @Column_("int4", {nullable: false}) 13 | block!: number 14 | 15 | @Column_("timestamp with time zone", {nullable: false}) 16 | timestamp!: Date 17 | 18 | @Column_("text", {nullable: false}) 19 | hash!: string 20 | 21 | @Column_("text", {nullable: false}) 22 | from!: string 23 | 24 | @Column_("text", {nullable: false}) 25 | to!: string 26 | 27 | @Column_("text", {nullable: false}) 28 | input!: string 29 | } 30 | -------------------------------------------------------------------------------- /evm-transactions-example/src/processor.ts: -------------------------------------------------------------------------------- 1 | import {EvmBatchProcessor} from '@subsquid/evm-processor' 2 | import {lookupArchive} from '@subsquid/archive-registry' 3 | 4 | const ACCOUNT_ADDRESS = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' 5 | 6 | export const processor = new EvmBatchProcessor() 7 | .setDataSource({ 8 | archive: lookupArchive('eth-mainnet'), 9 | chain: 'https://rpc.ankr.com/eth', 10 | }) 11 | .setFinalityConfirmation(10) 12 | .setFields({ 13 | transaction: { 14 | from: true, 15 | value: true, 16 | hash: true, 17 | input: true, 18 | }, 19 | }) 20 | // Txs sent to vitalik.eth 21 | .addTransaction({ 22 | to: [ACCOUNT_ADDRESS], 23 | }) 24 | // Txs sent from vitalik.eth 25 | .addTransaction({ 26 | from: [ACCOUNT_ADDRESS], 27 | }) 28 | -------------------------------------------------------------------------------- /evm-transactions-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "squid", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "rm -rf lib && tsc", 7 | "update": "npx npm-check-updates --filter /subsquid/ --upgrade && npm i -f" 8 | }, 9 | "dependencies": { 10 | "@subsquid/archive-registry": "^3.0.0", 11 | "@subsquid/evm-processor": "^1.4.0", 12 | "@subsquid/evm-typegen": "^3.2.0", 13 | "@subsquid/graphql-server": "^4.2.0", 14 | "@subsquid/typeorm-migration": "^1.2.0", 15 | "@subsquid/typeorm-store": "^1.2.0", 16 | "dotenv": "^16.0.3", 17 | "ethers": "^6.3.0", 18 | "pg": "^8.8.0", 19 | "typeorm": "^0.3.11" 20 | }, 21 | "devDependencies": { 22 | "@subsquid/evm-typegen": "^3.2.0", 23 | "@subsquid/typeorm-codegen": "^1.2.0", 24 | "@types/node": "^18.11.18", 25 | "typescript": "^4.9.4" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /evm-transactions-example/src/main.ts: -------------------------------------------------------------------------------- 1 | import {TypeormDatabase} from '@subsquid/typeorm-store' 2 | import {processor} from './processor' 3 | import {Transaction} from './model' 4 | 5 | processor.run(new TypeormDatabase({supportHotBlocks: true}), async (ctx) => { 6 | let transactions: Transaction[] = [] 7 | 8 | for (let block of ctx.blocks) { 9 | for (let transaction of block.transactions) { 10 | transactions.push( 11 | new Transaction({ 12 | id: transaction.id, 13 | block: block.header.height, 14 | timestamp: new Date(block.header.timestamp), 15 | from: transaction.from || '0x', 16 | to: transaction.to || '0x', 17 | hash: transaction.hash, 18 | input: transaction.input, 19 | }) 20 | ) 21 | } 22 | } 23 | 24 | await ctx.store.insert(transactions) 25 | }) 26 | -------------------------------------------------------------------------------- /evm-transactions-example/README.md: -------------------------------------------------------------------------------- 1 | [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/subsquid-labs/transactions-example) 2 | 3 | 4 | # Tracking transactions 5 | 6 | This sample squid tracks transactions to and from `vitalik.eth` address on Ethereum Mainnet. 7 | One can use this example as a template for scaffolding a new squid project with [`sqd init`](https://docs.subsquid.io/squid-cli/): 8 | 9 | ```bash 10 | sqd init my-new-squid --template https://github.com/subsquid-labs/transactions-example 11 | ``` 12 | 13 | For a full reference, check the [docs](https://docs.subsquid.io). 14 | 15 | ## Prerequisites 16 | 17 | - Node v16.x 18 | - Docker 19 | - [Squid CLI](https://docs.subsquid.io/squid-cli/) 20 | 21 | ## Running 22 | 23 | Clone the repo and navigate to the root folder. 24 | 25 | ```bash 26 | npm ci 27 | sqd build 28 | # start the database 29 | sqd up 30 | # starts a long-running ETL and blocks the terminal 31 | sqd process 32 | 33 | # starts the GraphQL API server at localhost:4350/graphql 34 | sqd serve 35 | ``` 36 | -------------------------------------------------------------------------------- /evm-transactions-example/.gitpod.yml: -------------------------------------------------------------------------------- 1 | # This configuration file was automatically generated by Gitpod. 2 | # Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml) 3 | # and commit this file to your remote git repository to share the goodness with others. 4 | 5 | # Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart 6 | github: 7 | prebuilds: 8 | # enable for the master/default branch (defaults to true) 9 | master: true 10 | # enable for all branches in this repo (defaults to false) 11 | branches: false 12 | # enable for pull requests coming from this repo (defaults to true) 13 | pullRequests: true 14 | # add a check to pull requests (defaults to true) 15 | addCheck: true 16 | # add a "Review in Gitpod" button as a comment to pull requests (defaults to false) 17 | addComment: false 18 | 19 | tasks: 20 | - init: | 21 | npm i 22 | npm i -g @subsquid/cli 23 | docker compose pull 24 | gp sync-done setup 25 | - name: DB 26 | command: | 27 | make up 28 | - name: GraphQL API 29 | command: | 30 | gp sync-await setup 31 | sqd serve 32 | - command: | 33 | gp sync-await setup 34 | gp ports await 4350 35 | gp preview $(gp url 4350)/graphql 36 | - name: Squid procesor 37 | command: | 38 | gp open src/processor.ts 39 | gp sync-await setup 40 | npm run build 41 | gp ports await 23798 42 | npx sqd process 43 | -------------------------------------------------------------------------------- /evm-transactions-example/commands.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://cdn.subsquid.io/schemas/commands.json", 3 | "commands": { 4 | "clean": { 5 | "description": "delete all build artifacts", 6 | "cmd": ["npx", "--yes", "rimraf", "lib"] 7 | }, 8 | "build": { 9 | "description": "Build the squid project", 10 | "deps": ["clean"], 11 | "cmd": ["tsc"] 12 | }, 13 | "up": { 14 | "description": "Start a PG database", 15 | "cmd": ["docker", "compose", "up", "-d"] 16 | }, 17 | "down": { 18 | "description": "Drop a PG database", 19 | "cmd": ["docker", "compose", "down"] 20 | }, 21 | "migration:apply": { 22 | "description": "Apply the DB migrations", 23 | "cmd": ["squid-typeorm-migration", "apply"] 24 | }, 25 | "migration:generate": { 26 | "description": "Generate a DB migration matching the TypeORM entities", 27 | "deps": ["migration:clean"], 28 | "cmd": ["squid-typeorm-migration", "generate"], 29 | }, 30 | "migration:clean": { 31 | "description": "Clean the migrations folder", 32 | "cmd": ["npx", "--yes", "rimraf", "./db/migrations/*.js"], 33 | }, 34 | "migration": { 35 | "cmd": ["squid-typeorm-migration", "generate"], 36 | "hidden": true 37 | }, 38 | "codegen": { 39 | "description": "Generate TypeORM entities from the schema file", 40 | "cmd": ["squid-typeorm-codegen"] 41 | }, 42 | "typegen": { 43 | "description": "Generate data access classes for an ABI file(s) in the ./abi folder", 44 | "cmd": ["squid-evm-typegen", "./src/abi", {"glob": "./abi/*.json"}, "--multicall"] 45 | }, 46 | "process": { 47 | "description": "Load .env and start the squid processor", 48 | "deps": ["migration:apply"], 49 | "cmd": ["node", "--require=dotenv/config", "lib/main.js"] 50 | }, 51 | "process:prod": { 52 | "description": "Start the squid processor", 53 | "cmd": ["node", "lib/main.js"], 54 | "hidden": true 55 | }, 56 | "serve": { 57 | "description": "Start the GraphQL API server", 58 | "cmd": ["squid-graphql-server"] 59 | }, 60 | "serve:prod": { 61 | "description": "Start the GraphQL API server with caching and limits", 62 | "cmd": ["squid-graphql-server", 63 | "--dumb-cache", "in-memory", 64 | "--dumb-cache-ttl", "1000", 65 | "--dumb-cache-size", "100", 66 | "--dumb-cache-max-age", "1000" ] 67 | }, 68 | "check-updates": { 69 | "cmd": ["npx", "--yes", "npm-check-updates", "--filter=/subsquid/", "--upgrade"], 70 | "hidden": true 71 | }, 72 | "bump": { 73 | "description": "Bump @subsquid packages to the latest versions", 74 | "deps": ["check-updates"], 75 | "cmd": ["npm", "i", "-f"] 76 | }, 77 | "open": { 78 | "description": "Open a local browser window", 79 | "cmd": ["npx", "--yes", "opener"] 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /evm-transactions-example/src/model/generated/marshal.ts: -------------------------------------------------------------------------------- 1 | import assert from 'assert' 2 | 3 | 4 | export interface Marshal { 5 | fromJSON(value: unknown): T 6 | toJSON(value: T): S 7 | } 8 | 9 | 10 | export const string: Marshal = { 11 | fromJSON(value: unknown): string { 12 | assert(typeof value === 'string', 'invalid String') 13 | return value 14 | }, 15 | toJSON(value) { 16 | return value 17 | } 18 | } 19 | 20 | 21 | export const id = string 22 | 23 | 24 | export const int: Marshal = { 25 | fromJSON(value: unknown): number { 26 | assert(Number.isInteger(value), 'invalid Int') 27 | return value as number 28 | }, 29 | toJSON(value) { 30 | return value 31 | } 32 | } 33 | 34 | 35 | export const float: Marshal = { 36 | fromJSON(value: unknown): number { 37 | assert(typeof value === 'number', 'invalid Float') 38 | return value as number 39 | }, 40 | toJSON(value) { 41 | return value 42 | } 43 | } 44 | 45 | 46 | export const boolean: Marshal = { 47 | fromJSON(value: unknown): boolean { 48 | assert(typeof value === 'boolean', 'invalid Boolean') 49 | return value 50 | }, 51 | toJSON(value: boolean): boolean { 52 | return value 53 | } 54 | } 55 | 56 | 57 | export const bigint: Marshal = { 58 | fromJSON(value: unknown): bigint { 59 | assert(typeof value === 'string', 'invalid BigInt') 60 | return BigInt(value) 61 | }, 62 | toJSON(value: bigint): string { 63 | return value.toString() 64 | } 65 | } 66 | 67 | 68 | export const bigdecimal: Marshal = { 69 | fromJSON(value: unknown): bigint { 70 | assert(typeof value === 'string', 'invalid BigDecimal') 71 | return decimal.BigDecimal(value) 72 | }, 73 | toJSON(value: any): string { 74 | return value.toString() 75 | } 76 | } 77 | 78 | 79 | // credit - https://github.com/Urigo/graphql-scalars/blob/91b4ea8df891be8af7904cf84751930cc0c6613d/src/scalars/iso-date/validator.ts#L122 80 | const RFC_3339_REGEX = 81 | /^(\d{4}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60))(\.\d{1,})?([Z])$/ 82 | 83 | 84 | function isIsoDateTimeString(s: string): boolean { 85 | return RFC_3339_REGEX.test(s) 86 | } 87 | 88 | 89 | export const datetime: Marshal = { 90 | fromJSON(value: unknown): Date { 91 | assert(typeof value === 'string', 'invalid DateTime') 92 | assert(isIsoDateTimeString(value), 'invalid DateTime') 93 | return new Date(value) 94 | }, 95 | toJSON(value: Date): string { 96 | return value.toISOString() 97 | } 98 | } 99 | 100 | 101 | export const bytes: Marshal = { 102 | fromJSON(value: unknown): Buffer { 103 | assert(typeof value === 'string', 'invalid Bytes') 104 | assert(value.length % 2 === 0, 'invalid Bytes') 105 | assert(/^0x[0-9a-f]+$/i.test(value), 'invalid Bytes') 106 | return Buffer.from(value.slice(2), 'hex') 107 | }, 108 | toJSON(value: Uint8Array): string { 109 | if (Buffer.isBuffer(value)) { 110 | return '0x' + value.toString('hex') 111 | } else { 112 | return '0x' + Buffer.from(value.buffer, value.byteOffset, value.byteLength).toString('hex') 113 | } 114 | } 115 | } 116 | 117 | 118 | export function fromList(list: unknown, f: (val: unknown) => T): T[] { 119 | assert(Array.isArray(list)) 120 | return list.map((val) => f(val)) 121 | } 122 | 123 | 124 | export function nonNull(val: T | undefined | null): T { 125 | assert(val != null, 'non-nullable value is null') 126 | return val 127 | } 128 | 129 | 130 | export const bigintTransformer = { 131 | to(x?: bigint) { 132 | return x?.toString() 133 | }, 134 | from(s?: string): bigint | undefined { 135 | return s == null ? undefined : BigInt(s) 136 | } 137 | } 138 | 139 | 140 | export const floatTransformer = { 141 | to(x?: number) { 142 | return x?.toString() 143 | }, 144 | from(s?: string): number | undefined { 145 | return s == null ? undefined : Number(s) 146 | } 147 | } 148 | 149 | 150 | export const bigdecimalTransformer = { 151 | to(x?: any) { 152 | return x?.toString() 153 | }, 154 | from(s?: any): any | undefined { 155 | return s == null ? undefined : decimal.BigDecimal(s) 156 | } 157 | } 158 | 159 | 160 | export function enumFromJson(json: unknown, enumObject: E): E[keyof E] { 161 | assert(typeof json == 'string', 'invalid enum value') 162 | let val = (enumObject as any)[json] 163 | assert(typeof val == 'string', `invalid enum value`) 164 | return val as any 165 | } 166 | 167 | 168 | const decimal = { 169 | get BigDecimal(): any { 170 | throw new Error('Package `@subsquid/big-decimal` is not installed') 171 | } 172 | } 173 | 174 | 175 | try { 176 | Object.defineProperty(decimal, "BigDecimal", { 177 | value: require('@subsquid/big-decimal').BigDecimal 178 | }) 179 | } catch (e) {} 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | Subsquid Logo 5 | 6 |

7 | 8 | [![docs.rs](https://docs.rs/leptos/badge.svg)](https://docs.subsquid.io/) 9 | [![Discord](https://img.shields.io/discord/1031524867910148188?color=%237289DA&label=discord)](https://discord.gg/subsquid) 10 | 11 | [Website](https://subsquid.io) | [Docs](https://docs.subsquid.io/) | [Discord](https://discord.gg/subsquid) 12 | 13 | # Winners 14 | - [@Showyilu](https://github.com/Showyilu/Snapshot-Squid) 15 | - [@0xNomind](https://github.com/0xNomind/snapshot-squid) 16 | - [@davaymne](https://github.com/davaymne/snapshot-subgraph-migration) 17 | - [@script-money](https://github.com/script-money/snapshot-migration-task) 18 | - [@arnobase](https://github.com/arnobase/snapshot-squid) 19 | - [@RicqCodes](https://github.com/RicqCodes/snapshot-subgraph-migration-submission) 20 | 21 | # Snapshot Subgraph migration 22 | 23 | **Submissions for this quest are closed** 24 | 25 | This quest is to migrate the [Snapshot Subgraph](https://thegraph.com/hosted-service/subgraph/snapshot-labs/snapshot) to Squid SDK. The resulting squid should match the GraphQL API of the subgraph as close as possible, by migrating `schema.graphql`. The judges reserve the right to request improvements afther the initial review of the submission. Reach out to the [Discord Channel]( https://discord.com/channels/857105545135390731/1155812879770058783) for any tech questions regarding this quest. 26 | 27 | # Quest Info 28 | 29 | | Category | Skill Level | Time required (hours) | Max Participants | Reward | Status | 30 | | ---------------- | ------------------------------------ | --------------------- | ---------------- | ---------------------------------- | ------ | 31 | | Squid Deployment | $\textcolor{green}{\textsf{Intermediate}}$ | ~10 | 5 | $\textcolor{red}{\textsf{1500tSQD}}$ | closed | 32 | 33 | # Acceptance critera 34 | 35 | Each quest should be submitted as a private repo and will be reviewed manually. To submit, create an issue with url to your repo and invite the following github accounts: [@dariaag](https://github.com/dariaag), [@belopash](https://github.com/belopash), [@abernatskiy](https://github.com/abernatskiy) and [@dzhelezov](https://github.com/dzhelezov). The repo should contain `README.MD` with 36 | 37 | - Insturctions how to run the squid locally 38 | - Sample Squid queries and the corresponding Subgraph queries 39 | 40 | The code should be well documented. The judges will access: 41 | 42 | - In-line commends where necessary 43 | - Clarity of the code 44 | - Performance and optimization (if [batching](https://docs.subsquid.io/basics/batch-processing/) and [Multicall queries](https://docs.subsquid.io/tutorials/bayc/step-four-optimizations/#using-multicall-for-aggregating-state-queries) are used whenever appropriate) 45 | 46 | # Useful links 47 | 48 | - [Quickstart](https://docs.subsquid.io/deploy-squid/quickstart/) 49 | - [TheGraph Migration guide](https://docs.subsquid.io/migrate/migrate-subgraph/) 50 | - [Snapshot Subgraph source code](https://github.com/snapshot-labs/snapshot-subgraph) 51 | 52 | # Setup and Common errors 53 | 54 | 1. Install Node v16.x or newer [https://nodejs.org/en/download](https://nodejs.org/en/download) 55 | 2. Install Docker [https://docs.docker.com/engine/install/](https://docs.docker.com/engine/install/) 56 | 3. Install git [https://git-scm.com/book/en/v2/Getting-Started-Installing-Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) 57 | 4. Install Squid CLI 58 | 59 | ```bash 60 | npm i -g @subsquid/cli@latest 61 | ``` 62 | 63 | ## How to run a squid: 64 | 65 | 1. Install dependecies: 66 | 67 | ```bash 68 | npm ci 69 | ``` 70 | 71 | 2. Generate model 72 | 73 | ```bash 74 | sqd codegen 75 | ``` 76 | 77 | 3. Generate types 78 | 79 | ```bash 80 | sqd typegen 81 | ``` 82 | 83 | 4. Open docker and run: 84 | 85 | ```bash 86 | sqd up 87 | ``` 88 | 89 | 5. Generate migrations: 90 | 91 | ```bash 92 | sqd migration:generate 93 | ``` 94 | 95 | 6. Start processing: 96 | 97 | ```bash 98 | sqd process 99 | ``` 100 | 101 | ## Possible Errors: 102 | 103 | 1. Docker not installed 104 | 105 | ```bash 106 | X db Error × query-gateway Error 107 | Error response from daemon: Get "https://registry-1.docker.jo/v2/": uri ting to 127.0.0.1:8888: dial cp 127.0.0.1:8888: connectex: No connection 108 | ``` 109 | 110 | 2. Git not installed 111 | 112 | ```bash 113 | Error: Error: spawn git ENOENT 114 | at ChildProcess._handle.onexit (node: internal/child_process: 284:19) 115 | at onErrorNT (node: internal/child_process:477:16) 116 | at process.processTicksAndRejections (node: internal/process/task_queues:82:21) 117 | ``` 118 | 119 | 3. Dependencies not installed. Run `npm ci` 120 | 121 | ```bash 122 | sqd typegen 123 | TYPEGEN 124 | Error: spawn squid-evm-typegen ENOENT 125 | Code: ENOENT 126 | ``` 127 | 128 | 4. Rate-limiting. Change the `rpcUrl` in `processor.ts` 129 | 130 | ```bash 131 | will pause new requests for 20000ms {"rpcUrl":"https://rpc.ankr.com/eth", 132 | "reason" : "HttpError: got 429 from https://rpc.ankr.com/eth"} 133 | ``` 134 | 135 | 136 | -------------------------------------------------------------------------------- /evm-transactions-example/abi/erc20.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "name", 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "string" 10 | } 11 | ], 12 | "payable": false, 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | { 17 | "constant": false, 18 | "inputs": [ 19 | { 20 | "name": "_spender", 21 | "type": "address" 22 | }, 23 | { 24 | "name": "_value", 25 | "type": "uint256" 26 | } 27 | ], 28 | "name": "approve", 29 | "outputs": [ 30 | { 31 | "name": "", 32 | "type": "bool" 33 | } 34 | ], 35 | "payable": false, 36 | "stateMutability": "nonpayable", 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [], 42 | "name": "totalSupply", 43 | "outputs": [ 44 | { 45 | "name": "", 46 | "type": "uint256" 47 | } 48 | ], 49 | "payable": false, 50 | "stateMutability": "view", 51 | "type": "function" 52 | }, 53 | { 54 | "constant": false, 55 | "inputs": [ 56 | { 57 | "name": "_from", 58 | "type": "address" 59 | }, 60 | { 61 | "name": "_to", 62 | "type": "address" 63 | }, 64 | { 65 | "name": "_value", 66 | "type": "uint256" 67 | } 68 | ], 69 | "name": "transferFrom", 70 | "outputs": [ 71 | { 72 | "name": "", 73 | "type": "bool" 74 | } 75 | ], 76 | "payable": false, 77 | "stateMutability": "nonpayable", 78 | "type": "function" 79 | }, 80 | { 81 | "constant": true, 82 | "inputs": [], 83 | "name": "decimals", 84 | "outputs": [ 85 | { 86 | "name": "", 87 | "type": "uint8" 88 | } 89 | ], 90 | "payable": false, 91 | "stateMutability": "view", 92 | "type": "function" 93 | }, 94 | { 95 | "constant": true, 96 | "inputs": [ 97 | { 98 | "name": "_owner", 99 | "type": "address" 100 | } 101 | ], 102 | "name": "balanceOf", 103 | "outputs": [ 104 | { 105 | "name": "balance", 106 | "type": "uint256" 107 | } 108 | ], 109 | "payable": false, 110 | "stateMutability": "view", 111 | "type": "function" 112 | }, 113 | { 114 | "constant": true, 115 | "inputs": [], 116 | "name": "symbol", 117 | "outputs": [ 118 | { 119 | "name": "", 120 | "type": "string" 121 | } 122 | ], 123 | "payable": false, 124 | "stateMutability": "view", 125 | "type": "function" 126 | }, 127 | { 128 | "constant": false, 129 | "inputs": [ 130 | { 131 | "name": "_to", 132 | "type": "address" 133 | }, 134 | { 135 | "name": "_value", 136 | "type": "uint256" 137 | } 138 | ], 139 | "name": "transfer", 140 | "outputs": [ 141 | { 142 | "name": "", 143 | "type": "bool" 144 | } 145 | ], 146 | "payable": false, 147 | "stateMutability": "nonpayable", 148 | "type": "function" 149 | }, 150 | { 151 | "constant": true, 152 | "inputs": [ 153 | { 154 | "name": "_owner", 155 | "type": "address" 156 | }, 157 | { 158 | "name": "_spender", 159 | "type": "address" 160 | } 161 | ], 162 | "name": "allowance", 163 | "outputs": [ 164 | { 165 | "name": "", 166 | "type": "uint256" 167 | } 168 | ], 169 | "payable": false, 170 | "stateMutability": "view", 171 | "type": "function" 172 | }, 173 | { 174 | "payable": true, 175 | "stateMutability": "payable", 176 | "type": "fallback" 177 | }, 178 | { 179 | "anonymous": false, 180 | "inputs": [ 181 | { 182 | "indexed": true, 183 | "name": "owner", 184 | "type": "address" 185 | }, 186 | { 187 | "indexed": true, 188 | "name": "spender", 189 | "type": "address" 190 | }, 191 | { 192 | "indexed": false, 193 | "name": "value", 194 | "type": "uint256" 195 | } 196 | ], 197 | "name": "Approval", 198 | "type": "event" 199 | }, 200 | { 201 | "anonymous": false, 202 | "inputs": [ 203 | { 204 | "indexed": true, 205 | "name": "from", 206 | "type": "address" 207 | }, 208 | { 209 | "indexed": true, 210 | "name": "to", 211 | "type": "address" 212 | }, 213 | { 214 | "indexed": false, 215 | "name": "value", 216 | "type": "uint256" 217 | } 218 | ], 219 | "name": "Transfer", 220 | "type": "event" 221 | } 222 | ] --------------------------------------------------------------------------------