Skip to content

Commit

Permalink
Add EVM indexing using subsquid
Browse files Browse the repository at this point in the history
  • Loading branch information
mj52951 committed Jul 4, 2024
1 parent 7a1cf7a commit 82e4b6f
Show file tree
Hide file tree
Showing 38 changed files with 12,332 additions and 1 deletion.
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
DB_NAME=squid
DB_PASS=squid
DB_PORT=23798
DB_USERNAME=postgres
DB_HOST=localhost

SHARED_CONFIG_URL=
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/node_modules
/lib

# IDE files
/.idea
pnpm-lock.yaml
**/*.log
7 changes: 7 additions & 0 deletions .squidignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
builds
lib
Dockerfile
.git
.github
.idea
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
# squid-indexer
# Sygma Squid Indexer

### Running locally

Starting docker container:

`docker-compose up`

Generating a database migration:

`sqd migration:generate`

Filling the database with data from `shared-config`:

`sqd start-init`

Starting indexing on the desired network:

`sqd start-<network-name>`

Checking stored data using GraphQL:

`sqd serve`

For additional commands see `commands.json`

120 changes: 120 additions & 0 deletions commands.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
{
"$schema": "https://cdn.subsquid.io/schemas/commands.json",
"commands": {
"clean": {
"description": "delete all build artifacts",
"cmd": ["npx", "--yes", "rimraf", "lib"]
},
"build": {
"description": "Build the squid project",
"deps": ["clean"],
"cmd": ["tsc"]
},
"up": {
"description": "Start a PG database",
"cmd": [
"docker",
"compose",
"up",
"-d"
]
},
"down": {
"description": "Drop a PG database",
"cmd": [
"docker",
"compose",
"down"
]
},
"migration:apply": {
"description": "Apply the DB migrations",
"cmd": ["squid-typeorm-migration", "apply"]
},
"migration:generate": {
"description": "Generate a DB migration matching the TypeORM entities",
"deps": ["migration:clean"],
"cmd": ["squid-typeorm-migration", "generate"]
},
"migration:clean": {
"description": "Clean the migrations folder",
"cmd": ["npx", "--yes", "rimraf", "./db/migrations/*.js"]
},
"migration": {
"cmd": ["squid-typeorm-migration", "generate"],
"hidden": true
},
"codegen": {
"description": "Generate TypeORM entities from the schema file",
"cmd": ["squid-typeorm-codegen"]
},
"evm-typegen": {
"description": "Generate data access classes for an ABI file(s) in the ./abi folder",
"cmd": ["squid-evm-typegen", "./src/abi", {"glob": "./src/abi/*.json"}, "--multicall"]
},
"substrate-typegen": {
"description": "Generate data access classes for an substrate metadata",
"cmd": ["squid-substrate-typegen", "./typegen.json"]
},
"start-sepolia":{
"description": "Start Sepolia indexer",
"deps": ["build", "migration:apply"],
"cmd": ["node", "--require=dotenv/config", "lib/main.js", "dotenv_config_path=envs/.env.sepolia"]
},
"start-holesky":{
"description": "Start Holesky indexer",
"deps": ["build", "migration:apply"],
"cmd": ["node", "--require=dotenv/config", "lib/main.js", "dotenv_config_path=envs/.env.holesky"]
},
"start-arbitrum-sepolia":{
"description": "Start Arbitrum Sepolia indexer",
"deps": ["build", "migration:apply"],
"cmd": ["node", "--require=dotenv/config", "lib/main.js", "dotenv_config_path=envs/.env.arbitrum-sepolia"]
},
"start-base-sepolia":{
"description": "Start Base Sepolia indexer",
"deps": ["build", "migration:apply"],
"cmd": ["node", "--require=dotenv/config", "lib/main.js", "dotenv_config_path=envs/.env.base-sepolia"]
},
"process": {
"description": "Load .env and start the squid processor",
"deps": ["build", "migration:apply"],
"cmd": ["node", "--require=dotenv/config", "lib/main.js"]
},
"start-init": {
"description": "Initialize the database and load config data",
"deps": ["build", "migration:apply"],
"cmd": ["node", "--require=dotenv/config", "lib/main_init.js"]
},
"process:prod": {
"description": "Start the squid processor",
"cmd": ["node", "lib/main.js"],
"hidden": true
},
"serve": {
"description": "Start the GraphQL API server",
"cmd": ["squid-graphql-server"]
},
"serve:prod": {
"description": "Start the GraphQL API server with caching and limits",
"cmd": ["squid-graphql-server",
"--dumb-cache", "in-memory",
"--dumb-cache-ttl", "1000",
"--dumb-cache-size", "100",
"--dumb-cache-max-age", "1000" ]
},
"check-updates": {
"cmd": ["npx", "--yes", "npm-check-updates", "--filter=/subsquid/", "--upgrade"],
"hidden": true
},
"bump": {
"description": "Bump @subsquid packages to the latest versions",
"deps": ["check-updates"],
"cmd": ["npm", "i", "-f"]
},
"open": {
"description": "Open a local browser window",
"cmd": ["npx", "--yes", "opener"]
}
}
}
11 changes: 11 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: "3"

services:
db:
image: postgres:15
environment:
POSTGRES_DB: squid
POSTGRES_PASSWORD: squid
ports:
- "${DB_PORT}:5432"
# command: ["postgres", "-c", "log_statement=all"]
16 changes: 16 additions & 0 deletions envs/.env.sepolia.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
DB_NAME=squid
DB_PASS=squid
DB_PORT=23798
DB_USERNAME=postgres
DB_HOST=localhost

PROCESSOR_PROMETHEUS_PORT=3000
GQL_PORT=4350

SHARED_CONFIG_URL=

DOMAIN_ID=2
DOMAIN_GATEWAY=
DOMAIN_BRIDGE_ADDRESS=
START_BLOCK=
RPC_URL=
90 changes: 90 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"name": "squid",
"version": "0.0.0",
"private": true,
"scripts": {
"build": "rm -rf lib && tsc",
"update": "npx npm-check-updates --filter /subsquid/ --upgrade && npm i -f"
},
"dependencies": {
"@aws-sdk/client-ssm": "^3.145.0",
"@buildwithsygma/sygma-contracts": "^2.5.1",
"@ethersproject/bignumber": "^5.7.0",
"@ethersproject/providers": "^5.7.2",
"@fastify/compress": "6.2.1",
"@fastify/cors": "^8.2.1",
"@fastify/swagger": "^8.14.0",
"@fastify/swagger-ui": "^3.0.0",
"@openzeppelin/contracts": "^4.8.3",
"@polkadot/api": "^12.0.1",
"@polkadot/typegen": "^12.0.1",
"@polkadot/util": "^12.6.2",
"@subsquid/archive-registry": "^3.3.2",
"@subsquid/evm-processor": "^1.17.1",
"@subsquid/evm-typegen": "^4.0.0",
"@subsquid/graphql-server": "^4.5.1",
"@subsquid/ss58": "^2.0.2",
"@subsquid/substrate-processor": "^8.4.1",
"@subsquid/substrate-runtime": "^2.0.0",
"@subsquid/typeorm-migration": "^1.3.0",
"@subsquid/typeorm-store": "^1.3.0",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"ethers": "^6.11.1",
"fastify": "4.17.0",
"fastify-healthcheck": "^4.4.0",
"license-check-and-add": "^4.0.5",
"morgan": "^1.10.0",
"node-cache": "^5.1.2",
"node-cleanup": "^2.1.2",
"pg": "^8.11.5",
"typeorm": "^0.3.20",
"winston": "^3.3.3",
"winston-transport": "^4.5.0"
},
"devDependencies": {
"@aws-sdk/client-sns": "^3.418.0",
"@buildwithsygma/sygma-sdk-core": "^2.1.0",
"@chainsafe/eslint-config": "^1.1.0",
"@polkadot/types": "10.9.1",
"@rushstack/eslint-patch": "^1.2.0",
"@subsquid/evm-typegen": "^4.0.0",
"@subsquid/substrate-metadata-explorer": "^3.1.2",
"@subsquid/substrate-typegen": "^8.1.0",
"@subsquid/typeorm-codegen": "^1.3.3",
"@types/chai": "^4.3.5",
"@types/cors": "^2.8.12",
"@types/cron": "^2.4.0",
"@types/ejs": "^3.1.3",
"@types/eslint": "^8",
"@types/mocha": "^10.0.1",
"@types/mongodb": "^4.0.7",
"@types/morgan": "^1.9.3",
"@types/node": "^16.7.10",
"@types/node-cleanup": "^2.1.2",
"@types/sinon": "^10.0.16",
"@types/supertest": "^2.0.11",
"axios": "^1.4.0",
"bignumber.js": "^9.1.2",
"cache-manager": "^5.2.4",
"chai": "^4.3.7",
"cron": "^2.4.3",
"cross-fetch": "3.1.5",
"docker-secret": "^1.2.4",
"dotenv": "^10.0.0",
"dotenv-cli": "^4.0.0",
"dotenv-flow": "^3.2.0",
"ejs": "^3.1.9",
"eslint": "^8.21.0",
"luxon": "^3.4.3",
"mocha": "^10.2.0",
"nodemon": "^2.0.12",
"nyc": "^15.1.0",
"prettier": "^2.7.1",
"sinon": "^15.2.0",
"supertest": "^6.1.6",
"ts-node": "^10.2.1",
"typeorm-naming-strategies": "^4.1.0",
"typescript": "^5.4.4"
}
}
74 changes: 74 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
type Transfer @entity {
id: ID!
depositNonce: BigInt!
resource: Resource
resourceID: String
fromDomain: Domain!
fromDomainID: Int!
toDomain: Domain
toDomainID: Int
destination: String
amount: String
status: TransferStatus!
deposit: Deposit @unique
execution: Execution @unique
fee: Fee @unique
account: Account
message: String
usdValue: Float
}

type Deposit @entity {
id: ID!
transfer: Transfer @derivedFrom(field: "deposit")
type: String!
txHash: String!
blockNumber: String!
depositData: String!
timestamp: DateTime
handlerResponse: String!
}

type Execution @entity {
id: ID!
transfer: Transfer @derivedFrom(field: "execution")
txHash: String!
timestamp: DateTime
blockNumber: String!
}

enum TransferStatus {
pending
executed
failed
}

type Account @entity {
id: ID!
addressStatus: String
transfers: [Transfer!] @derivedFrom(field: "account")
}

type Resource @entity {
id: ID!
type: String!
decimals: Int
transfers: [Transfer!] @derivedFrom(field: "resource")
}

type Domain @entity {
id: ID!
name: String!
lastIndexedBlock: String!
transfersFrom: [Transfer!] @derivedFrom(field: "fromDomain")
transfersTo: [Transfer!] @derivedFrom(field: "toDomain")
}

type Fee @entity {
id: ID!
amount: String!
tokenAddress: String!
tokenSymbol: String!
decimals: Int
transfer: Transfer @derivedFrom(field: "fee")
}
21 changes: 21 additions & 0 deletions squid.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
manifestVersion: subsquid.io/v0.1
name: evm-logs-example
version: 1
description: |-
Basic example of processing evm logs
build:

deploy:
addons:
postgres:
processor:
- name: sepolia-processor
cmd: ["sqd", "start-sepolia"]
- name: arbitrum-sepolia-processor
cmd: ["sqd", "start-arbitrum-sepolia"]
- name: base-sepolia-processor
cmd: ["sqd", "start-base-sepolia"]
- name: holesky-processor
cmd: ["sqd", "start-holesky"]
api:
cmd: [ "npx", "squid-graphql-server", "--dumb-cache", "in-memory", "--dumb-cache-ttl", "1000", "--dumb-cache-size", "100", "--dumb-cache-max-age", "1000" ]
1 change: 1 addition & 0 deletions src/abi/FeeHandlerRouter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"abi":[{"inputs":[{"internalType":"address","name":"bridgeAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"IncorrectFeeSupplied","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint8","name":"fromDomainID","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"destinationDomainID","type":"uint8"},{"indexed":false,"internalType":"bytes32","name":"resourceID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"FeeCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeeDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"whitelistAddress","type":"address"},{"indexed":false,"internalType":"bool","name":"isWhitelisted","type":"bool"}],"name":"WhitelistChanged","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_bridgeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"_domainResourceIDToFeeHandlerAddress","outputs":[{"internalType":"contract IFeeHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_whitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"destinationDomainID","type":"uint8"},{"internalType":"bytes32","name":"resourceID","type":"bytes32"},{"internalType":"contract IFeeHandler","name":"handlerAddress","type":"address"}],"name":"adminSetResourceHandler","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"whitelistAddress","type":"address"},{"internalType":"bool","name":"isWhitelisted","type":"bool"}],"name":"adminSetWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint8","name":"fromDomainID","type":"uint8"},{"internalType":"uint8","name":"destinationDomainID","type":"uint8"},{"internalType":"bytes32","name":"resourceID","type":"bytes32"},{"internalType":"bytes","name":"depositData","type":"bytes"},{"internalType":"bytes","name":"feeData","type":"bytes"}],"name":"calculateFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint8","name":"fromDomainID","type":"uint8"},{"internalType":"uint8","name":"destinationDomainID","type":"uint8"},{"internalType":"bytes32","name":"resourceID","type":"bytes32"},{"internalType":"bytes","name":"depositData","type":"bytes"},{"internalType":"bytes","name":"feeData","type":"bytes"}],"name":"collectFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"getRoleMemberIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}]}
Loading

0 comments on commit 82e4b6f

Please sign in to comment.