From 7596eecdb62ec0bfde47beff032a45ecffd3baee Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:04:06 +0800 Subject: [PATCH 01/31] Featuring zkSync Sepolia (#287) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> --- .github/scripts/ci.package.json | 3 +- .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../zksync-sepolia-testnet-starter/.gitignore | 60 +++++ .../zksync-sepolia-testnet-starter/LICENSE | 21 ++ .../zksync-sepolia-testnet-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../package.json | 34 +++ .../zksync-sepolia-testnet-starter/project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 759 insertions(+), 1 deletion(-) create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/.github/workflows/pr.yml create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/.gitignore create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/LICENSE create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/README.md create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/abis/erc20.abi.json create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/docker-compose.yml create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/docker/load-extensions.sh create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/docker/pg-Dockerfile create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/package.json create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/project.ts create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/schema.graphql create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/src/index.ts create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 zkSync Sepolia/zksync-sepolia-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 816e8041..2f9c3e3f 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -88,7 +88,8 @@ "Torus", "Now Chain", "Kakarot Starknet", - "0G Newton Testnet" + "0G Newton Testnet", + "zkSync Sepolia" ], "scripts": { "codegen": "yarn workspaces run codegen", diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/.github/workflows/cli-deploy.yml b/zkSync Sepolia/zksync-sepolia-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/.github/workflows/pr.yml b/zkSync Sepolia/zksync-sepolia-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/zkSync Sepolia/zksync-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/.gitignore b/zkSync Sepolia/zksync-sepolia-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/LICENSE b/zkSync Sepolia/zksync-sepolia-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/README.md b/zkSync Sepolia/zksync-sepolia-testnet-starter/README.md new file mode 100644 index 00000000..5400c23d --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for zkSync Sepolia Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Bonsai (`0xB0588f9A9cADe7CD5f194a5fe77AcD6A58250f82`) on zkSync Sepolia Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/abis/erc20.abi.json b/zkSync Sepolia/zksync-sepolia-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/docker-compose.yml b/zkSync Sepolia/zksync-sepolia-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/docker/load-extensions.sh b/zkSync Sepolia/zksync-sepolia-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for zkSync Sepolia this is 300 + * https://chainlist.org/chain/300 + */ + chainId: "300", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://zksync-era-sepolia.blockpi.network/v1/rpc/public,https://sepolia.era.zksync.dev"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 3680793, + options: { + abi: "erc20", + // This is the contract address for Bonsai + address: "0xB0588f9A9cADe7CD5f194a5fe77AcD6A58250f82", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since zkSync Sepolia Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/schema.graphql b/zkSync Sepolia/zksync-sepolia-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/src/index.ts b/zkSync Sepolia/zksync-sepolia-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/src/mappings/mappingHandlers.ts b/zkSync Sepolia/zksync-sepolia-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/src/test/mappingHandlers.test.ts b/zkSync Sepolia/zksync-sepolia-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/zkSync Sepolia/zksync-sepolia-testnet-starter/tsconfig.json b/zkSync Sepolia/zksync-sepolia-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/zkSync Sepolia/zksync-sepolia-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From dc6fda62758a62aa5756eaf575d38a77e11fc678 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:04:50 +0800 Subject: [PATCH 02/31] Featuring zkLink Nova (#285) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ zkLink Nova/zklink-nova-starter/.gitignore | 60 +++++ zkLink Nova/zklink-nova-starter/LICENSE | 21 ++ zkLink Nova/zklink-nova-starter/README.md | 90 +++++++ .../zklink-nova-starter/abis/erc20.abi.json | 222 ++++++++++++++++++ .../zklink-nova-starter/docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../zklink-nova-starter/docker/pg-Dockerfile | 9 + zkLink Nova/zklink-nova-starter/package.json | 34 +++ zkLink Nova/zklink-nova-starter/project.ts | 89 +++++++ .../zklink-nova-starter/schema.graphql | 21 ++ zkLink Nova/zklink-nova-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + zkLink Nova/zklink-nova-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 zkLink Nova/zklink-nova-starter/.github/workflows/cli-deploy.yml create mode 100644 zkLink Nova/zklink-nova-starter/.github/workflows/pr.yml create mode 100644 zkLink Nova/zklink-nova-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 zkLink Nova/zklink-nova-starter/.gitignore create mode 100644 zkLink Nova/zklink-nova-starter/LICENSE create mode 100644 zkLink Nova/zklink-nova-starter/README.md create mode 100644 zkLink Nova/zklink-nova-starter/abis/erc20.abi.json create mode 100644 zkLink Nova/zklink-nova-starter/docker-compose.yml create mode 100644 zkLink Nova/zklink-nova-starter/docker/load-extensions.sh create mode 100644 zkLink Nova/zklink-nova-starter/docker/pg-Dockerfile create mode 100644 zkLink Nova/zklink-nova-starter/package.json create mode 100644 zkLink Nova/zklink-nova-starter/project.ts create mode 100644 zkLink Nova/zklink-nova-starter/schema.graphql create mode 100644 zkLink Nova/zklink-nova-starter/src/index.ts create mode 100644 zkLink Nova/zklink-nova-starter/src/mappings/mappingHandlers.ts create mode 100644 zkLink Nova/zklink-nova-starter/src/test/mappingHandlers.test.ts create mode 100644 zkLink Nova/zklink-nova-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 2f9c3e3f..ac579be0 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "zkLink Nova", "zkSync Sepolia" ], "scripts": { diff --git a/zkLink Nova/zklink-nova-starter/.github/workflows/cli-deploy.yml b/zkLink Nova/zklink-nova-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/zkLink Nova/zklink-nova-starter/.github/workflows/pr.yml b/zkLink Nova/zklink-nova-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/zkLink Nova/zklink-nova-starter/.github/workflows/scripts/publish-deploy.sh b/zkLink Nova/zklink-nova-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/zkLink Nova/zklink-nova-starter/.gitignore b/zkLink Nova/zklink-nova-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/zkLink Nova/zklink-nova-starter/LICENSE b/zkLink Nova/zklink-nova-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/zkLink Nova/zklink-nova-starter/README.md b/zkLink Nova/zklink-nova-starter/README.md new file mode 100644 index 00000000..9c6c8327 --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for zkLink Nova + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Wrapped BTC (`0xDa4AaEd3A53962c83B35697Cd138cc6df43aF71f`) on zkLink Nova** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/zkLink Nova/zklink-nova-starter/abis/erc20.abi.json b/zkLink Nova/zklink-nova-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/zkLink Nova/zklink-nova-starter/docker-compose.yml b/zkLink Nova/zklink-nova-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/zkLink Nova/zklink-nova-starter/docker/load-extensions.sh b/zkLink Nova/zklink-nova-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for zkLink Nova this is 810180 + * https://chainlist.org/chain/810180 + */ + chainId: "810180", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["wss://rpc.zklink.io,https://rpc.zklink.io"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 137410, + options: { + abi: "erc20", + // This is the contract address for Wrapped BTC + address: "0xDa4AaEd3A53962c83B35697Cd138cc6df43aF71f", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since zkLink Nova is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/zkLink Nova/zklink-nova-starter/schema.graphql b/zkLink Nova/zklink-nova-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/zkLink Nova/zklink-nova-starter/src/index.ts b/zkLink Nova/zklink-nova-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/zkLink Nova/zklink-nova-starter/src/mappings/mappingHandlers.ts b/zkLink Nova/zklink-nova-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/zkLink Nova/zklink-nova-starter/src/test/mappingHandlers.test.ts b/zkLink Nova/zklink-nova-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/zkLink Nova/zklink-nova-starter/tsconfig.json b/zkLink Nova/zklink-nova-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/zkLink Nova/zklink-nova-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 59d613df20088582a7a6a53d47134ecc056ae29a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:05:36 +0800 Subject: [PATCH 03/31] Featuring Zora Sepolia (#289) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../zora-sepolia-testnet-starter/.gitignore | 60 +++++ .../zora-sepolia-testnet-starter/LICENSE | 21 ++ .../zora-sepolia-testnet-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../zora-sepolia-testnet-starter/package.json | 34 +++ .../zora-sepolia-testnet-starter/project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../zora-sepolia-testnet-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/.github/workflows/pr.yml create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/.gitignore create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/LICENSE create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/README.md create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/abis/erc20.abi.json create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/docker-compose.yml create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/docker/load-extensions.sh create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/docker/pg-Dockerfile create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/package.json create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/project.ts create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/schema.graphql create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/src/index.ts create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Zora Sepolia/zora-sepolia-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index ac579be0..aec02f8c 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Zora Sepolia", "zkLink Nova", "zkSync Sepolia" ], diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/.github/workflows/cli-deploy.yml b/Zora Sepolia/zora-sepolia-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/.github/workflows/pr.yml b/Zora Sepolia/zora-sepolia-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Zora Sepolia/zora-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/.gitignore b/Zora Sepolia/zora-sepolia-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/LICENSE b/Zora Sepolia/zora-sepolia-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/README.md b/Zora Sepolia/zora-sepolia-testnet-starter/README.md new file mode 100644 index 00000000..81a40c71 --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Zora Sepolia Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Atlantis (`0xb9E09063BF9C3a9dbFC78Cb294DD9a65273d60e9`) on Zora Sepolia Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/abis/erc20.abi.json b/Zora Sepolia/zora-sepolia-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/docker-compose.yml b/Zora Sepolia/zora-sepolia-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/docker/load-extensions.sh b/Zora Sepolia/zora-sepolia-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Zora Sepolia this is 999999999 + * https://chainlist.org/chain/999999999 + */ + chainId: "999999999", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://sepolia.rpc.zora.energy"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 7721755, + options: { + abi: "erc20", + // This is the contract address for Atlantis + address: "0xb9E09063BF9C3a9dbFC78Cb294DD9a65273d60e9", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Zora Sepolia Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/schema.graphql b/Zora Sepolia/zora-sepolia-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/src/index.ts b/Zora Sepolia/zora-sepolia-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/src/mappings/mappingHandlers.ts b/Zora Sepolia/zora-sepolia-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/src/test/mappingHandlers.test.ts b/Zora Sepolia/zora-sepolia-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Zora Sepolia/zora-sepolia-testnet-starter/tsconfig.json b/Zora Sepolia/zora-sepolia-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Zora Sepolia/zora-sepolia-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 9d848d955625287de610521e2e83e4b727c9ee7b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:06:10 +0800 Subject: [PATCH 04/31] Featuring Taiko (#283) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ Taiko/taiko-starter/.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ Taiko/taiko-starter/.gitignore | 60 +++++ Taiko/taiko-starter/LICENSE | 21 ++ Taiko/taiko-starter/README.md | 90 +++++++ Taiko/taiko-starter/abis/erc20.abi.json | 222 ++++++++++++++++++ Taiko/taiko-starter/docker-compose.yml | 67 ++++++ Taiko/taiko-starter/docker/load-extensions.sh | 6 + Taiko/taiko-starter/docker/pg-Dockerfile | 9 + Taiko/taiko-starter/package.json | 34 +++ Taiko/taiko-starter/project.ts | 89 +++++++ Taiko/taiko-starter/schema.graphql | 21 ++ Taiko/taiko-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + Taiko/taiko-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Taiko/taiko-starter/.github/workflows/cli-deploy.yml create mode 100644 Taiko/taiko-starter/.github/workflows/pr.yml create mode 100644 Taiko/taiko-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Taiko/taiko-starter/.gitignore create mode 100644 Taiko/taiko-starter/LICENSE create mode 100644 Taiko/taiko-starter/README.md create mode 100644 Taiko/taiko-starter/abis/erc20.abi.json create mode 100644 Taiko/taiko-starter/docker-compose.yml create mode 100644 Taiko/taiko-starter/docker/load-extensions.sh create mode 100644 Taiko/taiko-starter/docker/pg-Dockerfile create mode 100644 Taiko/taiko-starter/package.json create mode 100644 Taiko/taiko-starter/project.ts create mode 100644 Taiko/taiko-starter/schema.graphql create mode 100644 Taiko/taiko-starter/src/index.ts create mode 100644 Taiko/taiko-starter/src/mappings/mappingHandlers.ts create mode 100644 Taiko/taiko-starter/src/test/mappingHandlers.test.ts create mode 100644 Taiko/taiko-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index aec02f8c..7463a09e 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Taiko", "Zora Sepolia", "zkLink Nova", "zkSync Sepolia" diff --git a/Taiko/taiko-starter/.github/workflows/cli-deploy.yml b/Taiko/taiko-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Taiko/taiko-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Taiko/taiko-starter/.github/workflows/pr.yml b/Taiko/taiko-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Taiko/taiko-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Taiko/taiko-starter/.github/workflows/scripts/publish-deploy.sh b/Taiko/taiko-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Taiko/taiko-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Taiko/taiko-starter/.gitignore b/Taiko/taiko-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Taiko/taiko-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Taiko/taiko-starter/LICENSE b/Taiko/taiko-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Taiko/taiko-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Taiko/taiko-starter/README.md b/Taiko/taiko-starter/README.md new file mode 100644 index 00000000..fb993566 --- /dev/null +++ b/Taiko/taiko-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Taiko + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Wrapped Ether (`0xA51894664A773981C6C112C43ce576f315d5b1B6`) on Taiko** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Taiko/taiko-starter/abis/erc20.abi.json b/Taiko/taiko-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Taiko/taiko-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Taiko/taiko-starter/docker-compose.yml b/Taiko/taiko-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Taiko/taiko-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Taiko/taiko-starter/docker/load-extensions.sh b/Taiko/taiko-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Taiko/taiko-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Taiko this is 167000 + * https://chainlist.org/chain/167000 + */ + chainId: "167000", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://taiko-json-rpc.stakely.io,https://taiko-rpc.publicnode.com"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 85, + options: { + abi: "erc20", + // This is the contract address for Wrapped Ether + address: "0xA51894664A773981C6C112C43ce576f315d5b1B6", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Taiko is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Taiko/taiko-starter/schema.graphql b/Taiko/taiko-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Taiko/taiko-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Taiko/taiko-starter/src/index.ts b/Taiko/taiko-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Taiko/taiko-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Taiko/taiko-starter/src/mappings/mappingHandlers.ts b/Taiko/taiko-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Taiko/taiko-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Taiko/taiko-starter/src/test/mappingHandlers.test.ts b/Taiko/taiko-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Taiko/taiko-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Taiko/taiko-starter/tsconfig.json b/Taiko/taiko-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Taiko/taiko-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From ff9ff78d11aca227f017df2540b9edd1c38fdcd5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:06:42 +0800 Subject: [PATCH 05/31] Featuring Superseed Sepolia (#281) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../.gitignore | 60 +++++ .../superseed-sepolia-testnet-starter/LICENSE | 21 ++ .../README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../package.json | 34 +++ .../project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/.github/workflows/pr.yml create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/.gitignore create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/LICENSE create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/README.md create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/abis/erc20.abi.json create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/docker-compose.yml create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/docker/load-extensions.sh create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/docker/pg-Dockerfile create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/package.json create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/project.ts create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/schema.graphql create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/src/index.ts create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Superseed Sepolia/superseed-sepolia-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 7463a09e..a21ce341 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Superseed Sepolia", "Taiko", "Zora Sepolia", "zkLink Nova", diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/.github/workflows/cli-deploy.yml b/Superseed Sepolia/superseed-sepolia-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/.github/workflows/pr.yml b/Superseed Sepolia/superseed-sepolia-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Superseed Sepolia/superseed-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/.gitignore b/Superseed Sepolia/superseed-sepolia-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/LICENSE b/Superseed Sepolia/superseed-sepolia-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/README.md b/Superseed Sepolia/superseed-sepolia-testnet-starter/README.md new file mode 100644 index 00000000..bb8f0b75 --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Superseed Sepolia Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the USDC (`0x85773169ee07022AA2b4785A5e69803540E9106A`) on Superseed Sepolia Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/abis/erc20.abi.json b/Superseed Sepolia/superseed-sepolia-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/docker-compose.yml b/Superseed Sepolia/superseed-sepolia-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/docker/load-extensions.sh b/Superseed Sepolia/superseed-sepolia-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Superseed Sepolia this is 53302 + * https://chainlist.org/chain/53302 + */ + chainId: "53302", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["wss://sepolia.superseed.xyz,https://sepolia.superseed.xyz"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 5132022, + options: { + abi: "erc20", + // This is the contract address for USDC + address: "0x85773169ee07022AA2b4785A5e69803540E9106A", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Superseed Sepolia Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/schema.graphql b/Superseed Sepolia/superseed-sepolia-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/src/index.ts b/Superseed Sepolia/superseed-sepolia-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/src/mappings/mappingHandlers.ts b/Superseed Sepolia/superseed-sepolia-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/src/test/mappingHandlers.test.ts b/Superseed Sepolia/superseed-sepolia-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Superseed Sepolia/superseed-sepolia-testnet-starter/tsconfig.json b/Superseed Sepolia/superseed-sepolia-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Superseed Sepolia/superseed-sepolia-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From f6b6c5735ce97525f1e943b8984fcf0656866229 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:07:19 +0800 Subject: [PATCH 06/31] Featuring StratoVM Testnet (#279) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../.gitignore | 60 +++++ .../stratovm-testnet-testnet-starter/LICENSE | 21 ++ .../README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../package.json | 34 +++ .../project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/.github/workflows/pr.yml create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/.gitignore create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/LICENSE create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/README.md create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/abis/erc20.abi.json create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/docker-compose.yml create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/docker/load-extensions.sh create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/docker/pg-Dockerfile create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/package.json create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/project.ts create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/schema.graphql create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/src/index.ts create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 StratoVM Testnet/stratovm-testnet-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index a21ce341..25b0ed27 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "StratoVM Testnet", "Superseed Sepolia", "Taiko", "Zora Sepolia", diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/.github/workflows/cli-deploy.yml b/StratoVM Testnet/stratovm-testnet-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/.github/workflows/pr.yml b/StratoVM Testnet/stratovm-testnet-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/StratoVM Testnet/stratovm-testnet-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/.gitignore b/StratoVM Testnet/stratovm-testnet-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/LICENSE b/StratoVM Testnet/stratovm-testnet-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/README.md b/StratoVM Testnet/stratovm-testnet-testnet-starter/README.md new file mode 100644 index 00000000..193aac32 --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for StratoVM Testnet Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the IceCream (`0xcc82bD85a3CaAdE271756FB24C831456Ff7c053F`) on StratoVM Testnet Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/abis/erc20.abi.json b/StratoVM Testnet/stratovm-testnet-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/docker-compose.yml b/StratoVM Testnet/stratovm-testnet-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/docker/load-extensions.sh b/StratoVM Testnet/stratovm-testnet-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for StratoVM Testnet this is 93747 + * https://chainlist.org/chain/93747 + */ + chainId: "93747", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://rpc.stratovm.io"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 698172, + options: { + abi: "erc20", + // This is the contract address for IceCream + address: "0xcc82bD85a3CaAdE271756FB24C831456Ff7c053F", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since StratoVM Testnet Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/schema.graphql b/StratoVM Testnet/stratovm-testnet-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/src/index.ts b/StratoVM Testnet/stratovm-testnet-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/src/mappings/mappingHandlers.ts b/StratoVM Testnet/stratovm-testnet-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/src/test/mappingHandlers.test.ts b/StratoVM Testnet/stratovm-testnet-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/StratoVM Testnet/stratovm-testnet-testnet-starter/tsconfig.json b/StratoVM Testnet/stratovm-testnet-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/StratoVM Testnet/stratovm-testnet-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 6e12a8035929ccb2299665e09a41680a084d40a0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:07:49 +0800 Subject: [PATCH 07/31] Featuring Shibarium (#277) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ Shibarium/shibarium-starter/.gitignore | 60 +++++ Shibarium/shibarium-starter/LICENSE | 21 ++ Shibarium/shibarium-starter/README.md | 90 +++++++ .../shibarium-starter/abis/erc20.abi.json | 222 ++++++++++++++++++ .../shibarium-starter/docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../shibarium-starter/docker/pg-Dockerfile | 9 + Shibarium/shibarium-starter/package.json | 34 +++ Shibarium/shibarium-starter/project.ts | 89 +++++++ Shibarium/shibarium-starter/schema.graphql | 21 ++ Shibarium/shibarium-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + Shibarium/shibarium-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Shibarium/shibarium-starter/.github/workflows/cli-deploy.yml create mode 100644 Shibarium/shibarium-starter/.github/workflows/pr.yml create mode 100644 Shibarium/shibarium-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Shibarium/shibarium-starter/.gitignore create mode 100644 Shibarium/shibarium-starter/LICENSE create mode 100644 Shibarium/shibarium-starter/README.md create mode 100644 Shibarium/shibarium-starter/abis/erc20.abi.json create mode 100644 Shibarium/shibarium-starter/docker-compose.yml create mode 100644 Shibarium/shibarium-starter/docker/load-extensions.sh create mode 100644 Shibarium/shibarium-starter/docker/pg-Dockerfile create mode 100644 Shibarium/shibarium-starter/package.json create mode 100644 Shibarium/shibarium-starter/project.ts create mode 100644 Shibarium/shibarium-starter/schema.graphql create mode 100644 Shibarium/shibarium-starter/src/index.ts create mode 100644 Shibarium/shibarium-starter/src/mappings/mappingHandlers.ts create mode 100644 Shibarium/shibarium-starter/src/test/mappingHandlers.test.ts create mode 100644 Shibarium/shibarium-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 25b0ed27..5381c816 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Shibarium", "StratoVM Testnet", "Superseed Sepolia", "Taiko", diff --git a/Shibarium/shibarium-starter/.github/workflows/cli-deploy.yml b/Shibarium/shibarium-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Shibarium/shibarium-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Shibarium/shibarium-starter/.github/workflows/pr.yml b/Shibarium/shibarium-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Shibarium/shibarium-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Shibarium/shibarium-starter/.github/workflows/scripts/publish-deploy.sh b/Shibarium/shibarium-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Shibarium/shibarium-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Shibarium/shibarium-starter/.gitignore b/Shibarium/shibarium-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Shibarium/shibarium-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Shibarium/shibarium-starter/LICENSE b/Shibarium/shibarium-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Shibarium/shibarium-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Shibarium/shibarium-starter/README.md b/Shibarium/shibarium-starter/README.md new file mode 100644 index 00000000..dbb2ce5a --- /dev/null +++ b/Shibarium/shibarium-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Shibarium + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the BAD IDEA AI (`0xef99cd3e619C058658043F8775ED9077105D8581`) on Shibarium** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Shibarium/shibarium-starter/abis/erc20.abi.json b/Shibarium/shibarium-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Shibarium/shibarium-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Shibarium/shibarium-starter/docker-compose.yml b/Shibarium/shibarium-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Shibarium/shibarium-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Shibarium/shibarium-starter/docker/load-extensions.sh b/Shibarium/shibarium-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Shibarium/shibarium-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Shibarium this is 109 + * https://chainlist.org/chain/109 + */ + chainId: "109", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://www.shibrpc.com"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 5917814, + options: { + abi: "erc20", + // This is the contract address for BAD IDEA AI + address: "0xef99cd3e619C058658043F8775ED9077105D8581", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Shibarium is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Shibarium/shibarium-starter/schema.graphql b/Shibarium/shibarium-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Shibarium/shibarium-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Shibarium/shibarium-starter/src/index.ts b/Shibarium/shibarium-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Shibarium/shibarium-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Shibarium/shibarium-starter/src/mappings/mappingHandlers.ts b/Shibarium/shibarium-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Shibarium/shibarium-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Shibarium/shibarium-starter/src/test/mappingHandlers.test.ts b/Shibarium/shibarium-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Shibarium/shibarium-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Shibarium/shibarium-starter/tsconfig.json b/Shibarium/shibarium-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Shibarium/shibarium-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 8a0bae6c9d35f7386a116471ebf9416ee48276c0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:08:21 +0800 Subject: [PATCH 08/31] Featuring Puppynet Shibarium (#275) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../puppynet-shibarium-starter/.gitignore | 60 +++++ .../puppynet-shibarium-starter/LICENSE | 21 ++ .../puppynet-shibarium-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../puppynet-shibarium-starter/package.json | 34 +++ .../puppynet-shibarium-starter/project.ts | 89 +++++++ .../puppynet-shibarium-starter/schema.graphql | 21 ++ .../puppynet-shibarium-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../puppynet-shibarium-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/.github/workflows/cli-deploy.yml create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/.github/workflows/pr.yml create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/.gitignore create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/LICENSE create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/README.md create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/abis/erc20.abi.json create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/docker-compose.yml create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/docker/load-extensions.sh create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/docker/pg-Dockerfile create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/package.json create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/project.ts create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/schema.graphql create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/src/index.ts create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/src/mappings/mappingHandlers.ts create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/src/test/mappingHandlers.test.ts create mode 100644 Puppynet Shibarium/puppynet-shibarium-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 5381c816..77b995d6 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Puppynet Shibarium", "Shibarium", "StratoVM Testnet", "Superseed Sepolia", diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/.github/workflows/cli-deploy.yml b/Puppynet Shibarium/puppynet-shibarium-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/.github/workflows/pr.yml b/Puppynet Shibarium/puppynet-shibarium-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/.github/workflows/scripts/publish-deploy.sh b/Puppynet Shibarium/puppynet-shibarium-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/.gitignore b/Puppynet Shibarium/puppynet-shibarium-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/LICENSE b/Puppynet Shibarium/puppynet-shibarium-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/README.md b/Puppynet Shibarium/puppynet-shibarium-starter/README.md new file mode 100644 index 00000000..33c642cc --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Puppynet Shibarium + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the App Shib Club (`0x165BD68cB3027Ca8fc0F5302cA427192121049aB`) on Puppynet Shibarium** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/abis/erc20.abi.json b/Puppynet Shibarium/puppynet-shibarium-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/docker-compose.yml b/Puppynet Shibarium/puppynet-shibarium-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/docker/load-extensions.sh b/Puppynet Shibarium/puppynet-shibarium-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Puppynet Shibarium this is 157 + * https://chainlist.org/chain/157 + */ + chainId: "157", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://puppynet.shibrpc.com"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 4555957, + options: { + abi: "erc20", + // This is the contract address for App Shib Club + address: "0x165BD68cB3027Ca8fc0F5302cA427192121049aB", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Puppynet Shibarium is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/schema.graphql b/Puppynet Shibarium/puppynet-shibarium-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/src/index.ts b/Puppynet Shibarium/puppynet-shibarium-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/src/mappings/mappingHandlers.ts b/Puppynet Shibarium/puppynet-shibarium-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/src/test/mappingHandlers.test.ts b/Puppynet Shibarium/puppynet-shibarium-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Puppynet Shibarium/puppynet-shibarium-starter/tsconfig.json b/Puppynet Shibarium/puppynet-shibarium-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Puppynet Shibarium/puppynet-shibarium-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 9d17c477c96456ff5ed2f2f60009bbfa71155510 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:10:57 +0800 Subject: [PATCH 09/31] Featuring Polygon zkEVM Cardona (#273) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../.gitignore | 60 +++++ .../LICENSE | 21 ++ .../README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../package.json | 34 +++ .../project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.github/workflows/pr.yml create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.gitignore create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/LICENSE create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/README.md create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/abis/erc20.abi.json create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/docker-compose.yml create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/docker/load-extensions.sh create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/docker/pg-Dockerfile create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/package.json create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/project.ts create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/schema.graphql create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/src/index.ts create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 77b995d6..e19622fb 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Polygon zkEVM Cardona", "Puppynet Shibarium", "Shibarium", "StratoVM Testnet", diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.github/workflows/cli-deploy.yml b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.github/workflows/pr.yml b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.gitignore b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/LICENSE b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/README.md b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/README.md new file mode 100644 index 00000000..40a813fe --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Polygon zkEVM Cardona Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the LINK (`0x5576815a38A3706f37bf815b261cCc7cCA77e975`) on Polygon zkEVM Cardona Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/abis/erc20.abi.json b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/docker-compose.yml b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/docker/load-extensions.sh b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Polygon zkEVM Cardona this is 2442 + * https://chainlist.org/chain/2442 + */ + chainId: "2442", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://rpc.cardona.zkevm-rpc.com,https://polygon-zkevm-cardona.blockpi.network/v1/rpc/public"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 1337982, + options: { + abi: "erc20", + // This is the contract address for LINK + address: "0x5576815a38A3706f37bf815b261cCc7cCA77e975", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Polygon zkEVM Cardona Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/schema.graphql b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/src/index.ts b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/src/mappings/mappingHandlers.ts b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/src/test/mappingHandlers.test.ts b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/tsconfig.json b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Polygon zkEVM Cardona/polygon-zkevm-cardona-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 1b5cc855d99a445cc4623f7ba158fb346cedd622 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:11:27 +0800 Subject: [PATCH 10/31] Featuring Polygon Amoy (#271) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../polygon-amoy-testnet-starter/.gitignore | 60 +++++ .../polygon-amoy-testnet-starter/LICENSE | 21 ++ .../polygon-amoy-testnet-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../polygon-amoy-testnet-starter/package.json | 34 +++ .../polygon-amoy-testnet-starter/project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../polygon-amoy-testnet-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/.github/workflows/pr.yml create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/.gitignore create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/LICENSE create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/README.md create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/abis/erc20.abi.json create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/docker-compose.yml create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/docker/load-extensions.sh create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/docker/pg-Dockerfile create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/package.json create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/project.ts create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/schema.graphql create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/src/index.ts create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Polygon Amoy/polygon-amoy-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index e19622fb..b3be73af 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Polygon Amoy", "Polygon zkEVM Cardona", "Puppynet Shibarium", "Shibarium", diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/.github/workflows/cli-deploy.yml b/Polygon Amoy/polygon-amoy-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/.github/workflows/pr.yml b/Polygon Amoy/polygon-amoy-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Polygon Amoy/polygon-amoy-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/.gitignore b/Polygon Amoy/polygon-amoy-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/LICENSE b/Polygon Amoy/polygon-amoy-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/README.md b/Polygon Amoy/polygon-amoy-testnet-starter/README.md new file mode 100644 index 00000000..a0063a7d --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Polygon Amoy Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the ADIX (`0xC9d291858a0F86A499835783093b643D812b3711`) on Polygon Amoy Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/abis/erc20.abi.json b/Polygon Amoy/polygon-amoy-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/docker-compose.yml b/Polygon Amoy/polygon-amoy-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/docker/load-extensions.sh b/Polygon Amoy/polygon-amoy-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Polygon Amoy this is 80002 + * https://chainlist.org/chain/80002 + */ + chainId: "80002", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["wss://polygon-amoy-bor-rpc.publicnode.com,https://polygon-amoy.drpc.org"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 12851017, + options: { + abi: "erc20", + // This is the contract address for ADIX + address: "0xC9d291858a0F86A499835783093b643D812b3711", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Polygon Amoy Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/schema.graphql b/Polygon Amoy/polygon-amoy-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/src/index.ts b/Polygon Amoy/polygon-amoy-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/src/mappings/mappingHandlers.ts b/Polygon Amoy/polygon-amoy-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/src/test/mappingHandlers.test.ts b/Polygon Amoy/polygon-amoy-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Polygon Amoy/polygon-amoy-testnet-starter/tsconfig.json b/Polygon Amoy/polygon-amoy-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Polygon Amoy/polygon-amoy-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 0959e5af8657533d814a3984f2810acc002973a0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:12:15 +0800 Subject: [PATCH 11/31] Featuring Peaq (#269) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ Peaq/peaq-starter/.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ Peaq/peaq-starter/.gitignore | 60 +++++ Peaq/peaq-starter/LICENSE | 21 ++ Peaq/peaq-starter/README.md | 90 +++++++ Peaq/peaq-starter/abis/erc20.abi.json | 222 ++++++++++++++++++ Peaq/peaq-starter/docker-compose.yml | 67 ++++++ Peaq/peaq-starter/docker/load-extensions.sh | 6 + Peaq/peaq-starter/docker/pg-Dockerfile | 9 + Peaq/peaq-starter/package.json | 34 +++ Peaq/peaq-starter/project.ts | 89 +++++++ Peaq/peaq-starter/schema.graphql | 21 ++ Peaq/peaq-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + Peaq/peaq-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Peaq/peaq-starter/.github/workflows/cli-deploy.yml create mode 100644 Peaq/peaq-starter/.github/workflows/pr.yml create mode 100644 Peaq/peaq-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Peaq/peaq-starter/.gitignore create mode 100644 Peaq/peaq-starter/LICENSE create mode 100644 Peaq/peaq-starter/README.md create mode 100644 Peaq/peaq-starter/abis/erc20.abi.json create mode 100644 Peaq/peaq-starter/docker-compose.yml create mode 100644 Peaq/peaq-starter/docker/load-extensions.sh create mode 100644 Peaq/peaq-starter/docker/pg-Dockerfile create mode 100644 Peaq/peaq-starter/package.json create mode 100644 Peaq/peaq-starter/project.ts create mode 100644 Peaq/peaq-starter/schema.graphql create mode 100644 Peaq/peaq-starter/src/index.ts create mode 100644 Peaq/peaq-starter/src/mappings/mappingHandlers.ts create mode 100644 Peaq/peaq-starter/src/test/mappingHandlers.test.ts create mode 100644 Peaq/peaq-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index b3be73af..c536dc56 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Peaq", "Polygon Amoy", "Polygon zkEVM Cardona", "Puppynet Shibarium", diff --git a/Peaq/peaq-starter/.github/workflows/cli-deploy.yml b/Peaq/peaq-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Peaq/peaq-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Peaq/peaq-starter/.github/workflows/pr.yml b/Peaq/peaq-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Peaq/peaq-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Peaq/peaq-starter/.github/workflows/scripts/publish-deploy.sh b/Peaq/peaq-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Peaq/peaq-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Peaq/peaq-starter/.gitignore b/Peaq/peaq-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Peaq/peaq-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Peaq/peaq-starter/LICENSE b/Peaq/peaq-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Peaq/peaq-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Peaq/peaq-starter/README.md b/Peaq/peaq-starter/README.md new file mode 100644 index 00000000..421221ba --- /dev/null +++ b/Peaq/peaq-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Peaq + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the PEAQ (`0x0000000000000000000000000000000000000809`) on Peaq** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Peaq/peaq-starter/abis/erc20.abi.json b/Peaq/peaq-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Peaq/peaq-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Peaq/peaq-starter/docker-compose.yml b/Peaq/peaq-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Peaq/peaq-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Peaq/peaq-starter/docker/load-extensions.sh b/Peaq/peaq-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Peaq/peaq-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Peaq this is 3338 + * https://chainlist.org/chain/3338 + */ + chainId: "3338", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://peaq.api.onfinality.io/public,https://peaq-rpc.publicnode.com"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 0, + options: { + abi: "erc20", + // This is the contract address for PEAQ + address: "0x0000000000000000000000000000000000000809", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Peaq is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Peaq/peaq-starter/schema.graphql b/Peaq/peaq-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Peaq/peaq-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Peaq/peaq-starter/src/index.ts b/Peaq/peaq-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Peaq/peaq-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Peaq/peaq-starter/src/mappings/mappingHandlers.ts b/Peaq/peaq-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Peaq/peaq-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Peaq/peaq-starter/src/test/mappingHandlers.test.ts b/Peaq/peaq-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Peaq/peaq-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Peaq/peaq-starter/tsconfig.json b/Peaq/peaq-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Peaq/peaq-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 6cfbae324f91e726d7de07133b39e17a41173a2e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:12:48 +0800 Subject: [PATCH 12/31] Featuring OP Sepolia (#267) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../op-sepolia-testnet-starter/.gitignore | 60 +++++ OP Sepolia/op-sepolia-testnet-starter/LICENSE | 21 ++ .../op-sepolia-testnet-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../op-sepolia-testnet-starter/package.json | 34 +++ .../op-sepolia-testnet-starter/project.ts | 89 +++++++ .../op-sepolia-testnet-starter/schema.graphql | 21 ++ .../op-sepolia-testnet-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../op-sepolia-testnet-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 OP Sepolia/op-sepolia-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 OP Sepolia/op-sepolia-testnet-starter/.github/workflows/pr.yml create mode 100644 OP Sepolia/op-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 OP Sepolia/op-sepolia-testnet-starter/.gitignore create mode 100644 OP Sepolia/op-sepolia-testnet-starter/LICENSE create mode 100644 OP Sepolia/op-sepolia-testnet-starter/README.md create mode 100644 OP Sepolia/op-sepolia-testnet-starter/abis/erc20.abi.json create mode 100644 OP Sepolia/op-sepolia-testnet-starter/docker-compose.yml create mode 100644 OP Sepolia/op-sepolia-testnet-starter/docker/load-extensions.sh create mode 100644 OP Sepolia/op-sepolia-testnet-starter/docker/pg-Dockerfile create mode 100644 OP Sepolia/op-sepolia-testnet-starter/package.json create mode 100644 OP Sepolia/op-sepolia-testnet-starter/project.ts create mode 100644 OP Sepolia/op-sepolia-testnet-starter/schema.graphql create mode 100644 OP Sepolia/op-sepolia-testnet-starter/src/index.ts create mode 100644 OP Sepolia/op-sepolia-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 OP Sepolia/op-sepolia-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 OP Sepolia/op-sepolia-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index c536dc56..87408b3f 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "OP Sepolia", "Peaq", "Polygon Amoy", "Polygon zkEVM Cardona", diff --git a/OP Sepolia/op-sepolia-testnet-starter/.github/workflows/cli-deploy.yml b/OP Sepolia/op-sepolia-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/OP Sepolia/op-sepolia-testnet-starter/.github/workflows/pr.yml b/OP Sepolia/op-sepolia-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/OP Sepolia/op-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/OP Sepolia/op-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/OP Sepolia/op-sepolia-testnet-starter/.gitignore b/OP Sepolia/op-sepolia-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/OP Sepolia/op-sepolia-testnet-starter/LICENSE b/OP Sepolia/op-sepolia-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/OP Sepolia/op-sepolia-testnet-starter/README.md b/OP Sepolia/op-sepolia-testnet-starter/README.md new file mode 100644 index 00000000..58e41132 --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for OP Sepolia Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the USDC (`0x5fd84259d66Cd46123540766Be93DFE6D43130D7`) on OP Sepolia Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/OP Sepolia/op-sepolia-testnet-starter/abis/erc20.abi.json b/OP Sepolia/op-sepolia-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/OP Sepolia/op-sepolia-testnet-starter/docker-compose.yml b/OP Sepolia/op-sepolia-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/OP Sepolia/op-sepolia-testnet-starter/docker/load-extensions.sh b/OP Sepolia/op-sepolia-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for OP Sepolia this is 11155420 + * https://chainlist.org/chain/11155420 + */ + chainId: "11155420", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://optimism-sepolia.blockpi.network/v1/rpc/public,https://optimism-sepolia.drpc.org"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 5133798, + options: { + abi: "erc20", + // This is the contract address for USDC + address: "0x5fd84259d66Cd46123540766Be93DFE6D43130D7", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since OP Sepolia Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/OP Sepolia/op-sepolia-testnet-starter/schema.graphql b/OP Sepolia/op-sepolia-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/OP Sepolia/op-sepolia-testnet-starter/src/index.ts b/OP Sepolia/op-sepolia-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/OP Sepolia/op-sepolia-testnet-starter/src/mappings/mappingHandlers.ts b/OP Sepolia/op-sepolia-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/OP Sepolia/op-sepolia-testnet-starter/src/test/mappingHandlers.test.ts b/OP Sepolia/op-sepolia-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/OP Sepolia/op-sepolia-testnet-starter/tsconfig.json b/OP Sepolia/op-sepolia-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/OP Sepolia/op-sepolia-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From af4531141fb424b040f731756ff2f4bfc603d313 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:13:23 +0800 Subject: [PATCH 13/31] Featuring opBNB Testnet (#265) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../opbnb-testnet-testnet-starter/.gitignore | 60 +++++ .../opbnb-testnet-testnet-starter/LICENSE | 21 ++ .../opbnb-testnet-testnet-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../package.json | 34 +++ .../opbnb-testnet-testnet-starter/project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/.github/workflows/pr.yml create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/.gitignore create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/LICENSE create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/README.md create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/abis/erc20.abi.json create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/docker-compose.yml create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/docker/load-extensions.sh create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/docker/pg-Dockerfile create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/package.json create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/project.ts create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/schema.graphql create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/src/index.ts create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 opBNB Testnet/opbnb-testnet-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 87408b3f..64c59813 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "opBNB Testnet", "OP Sepolia", "Peaq", "Polygon Amoy", diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/.github/workflows/cli-deploy.yml b/opBNB Testnet/opbnb-testnet-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/.github/workflows/pr.yml b/opBNB Testnet/opbnb-testnet-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/opBNB Testnet/opbnb-testnet-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/.gitignore b/opBNB Testnet/opbnb-testnet-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/LICENSE b/opBNB Testnet/opbnb-testnet-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/README.md b/opBNB Testnet/opbnb-testnet-testnet-starter/README.md new file mode 100644 index 00000000..4eed355a --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for opBNB Testnet Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Runix (`0x9A069098f3508F4b4F937CCF5abFfDE8980914eF`) on opBNB Testnet Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/abis/erc20.abi.json b/opBNB Testnet/opbnb-testnet-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/docker-compose.yml b/opBNB Testnet/opbnb-testnet-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/docker/load-extensions.sh b/opBNB Testnet/opbnb-testnet-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for opBNB Testnet this is 5611 + * https://chainlist.org/chain/5611 + */ + chainId: "5611", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["wss://opbnb-testnet-rpc.publicnode.com,https://opbnb-testnet-rpc.bnbchain.org"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 171251, + options: { + abi: "erc20", + // This is the contract address for Runix + address: "0x9A069098f3508F4b4F937CCF5abFfDE8980914eF", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since opBNB Testnet Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/schema.graphql b/opBNB Testnet/opbnb-testnet-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/src/index.ts b/opBNB Testnet/opbnb-testnet-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/src/mappings/mappingHandlers.ts b/opBNB Testnet/opbnb-testnet-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/src/test/mappingHandlers.test.ts b/opBNB Testnet/opbnb-testnet-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/opBNB Testnet/opbnb-testnet-testnet-starter/tsconfig.json b/opBNB Testnet/opbnb-testnet-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/opBNB Testnet/opbnb-testnet-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 5c25e05bcfd85c66a1292081444fa4da2ebb5fac Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:13:53 +0800 Subject: [PATCH 14/31] Featuring Neon EVM (#263) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../neon-evm-starter/.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ Neon EVM/neon-evm-starter/.gitignore | 60 +++++ Neon EVM/neon-evm-starter/LICENSE | 21 ++ Neon EVM/neon-evm-starter/README.md | 90 +++++++ Neon EVM/neon-evm-starter/abis/erc20.abi.json | 222 ++++++++++++++++++ Neon EVM/neon-evm-starter/docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../neon-evm-starter/docker/pg-Dockerfile | 9 + Neon EVM/neon-evm-starter/package.json | 34 +++ Neon EVM/neon-evm-starter/project.ts | 89 +++++++ Neon EVM/neon-evm-starter/schema.graphql | 21 ++ Neon EVM/neon-evm-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + Neon EVM/neon-evm-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Neon EVM/neon-evm-starter/.github/workflows/cli-deploy.yml create mode 100644 Neon EVM/neon-evm-starter/.github/workflows/pr.yml create mode 100644 Neon EVM/neon-evm-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Neon EVM/neon-evm-starter/.gitignore create mode 100644 Neon EVM/neon-evm-starter/LICENSE create mode 100644 Neon EVM/neon-evm-starter/README.md create mode 100644 Neon EVM/neon-evm-starter/abis/erc20.abi.json create mode 100644 Neon EVM/neon-evm-starter/docker-compose.yml create mode 100644 Neon EVM/neon-evm-starter/docker/load-extensions.sh create mode 100644 Neon EVM/neon-evm-starter/docker/pg-Dockerfile create mode 100644 Neon EVM/neon-evm-starter/package.json create mode 100644 Neon EVM/neon-evm-starter/project.ts create mode 100644 Neon EVM/neon-evm-starter/schema.graphql create mode 100644 Neon EVM/neon-evm-starter/src/index.ts create mode 100644 Neon EVM/neon-evm-starter/src/mappings/mappingHandlers.ts create mode 100644 Neon EVM/neon-evm-starter/src/test/mappingHandlers.test.ts create mode 100644 Neon EVM/neon-evm-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 64c59813..1f5db0f7 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Neon EVM", "opBNB Testnet", "OP Sepolia", "Peaq", diff --git a/Neon EVM/neon-evm-starter/.github/workflows/cli-deploy.yml b/Neon EVM/neon-evm-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Neon EVM/neon-evm-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Neon EVM/neon-evm-starter/.github/workflows/pr.yml b/Neon EVM/neon-evm-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Neon EVM/neon-evm-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Neon EVM/neon-evm-starter/.github/workflows/scripts/publish-deploy.sh b/Neon EVM/neon-evm-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Neon EVM/neon-evm-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Neon EVM/neon-evm-starter/.gitignore b/Neon EVM/neon-evm-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Neon EVM/neon-evm-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Neon EVM/neon-evm-starter/LICENSE b/Neon EVM/neon-evm-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Neon EVM/neon-evm-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Neon EVM/neon-evm-starter/README.md b/Neon EVM/neon-evm-starter/README.md new file mode 100644 index 00000000..69ec4de7 --- /dev/null +++ b/Neon EVM/neon-evm-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Neon EVM + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Mora (`0x2043191e10a2A4b4601F5123D6C94E000b5d915F`) on Neon EVM** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Neon EVM/neon-evm-starter/abis/erc20.abi.json b/Neon EVM/neon-evm-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Neon EVM/neon-evm-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Neon EVM/neon-evm-starter/docker-compose.yml b/Neon EVM/neon-evm-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Neon EVM/neon-evm-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Neon EVM/neon-evm-starter/docker/load-extensions.sh b/Neon EVM/neon-evm-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Neon EVM/neon-evm-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Neon EVM this is 245022934 + * https://chainlist.org/chain/245022934 + */ + chainId: "245022934", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://neon-proxy-mainnet.solana.p2p.org,wss://neon-evm.drpc.org"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 207988165, + options: { + abi: "erc20", + // This is the contract address for Mora + address: "0x2043191e10a2A4b4601F5123D6C94E000b5d915F", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Neon EVM is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Neon EVM/neon-evm-starter/schema.graphql b/Neon EVM/neon-evm-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Neon EVM/neon-evm-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Neon EVM/neon-evm-starter/src/index.ts b/Neon EVM/neon-evm-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Neon EVM/neon-evm-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Neon EVM/neon-evm-starter/src/mappings/mappingHandlers.ts b/Neon EVM/neon-evm-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Neon EVM/neon-evm-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Neon EVM/neon-evm-starter/src/test/mappingHandlers.test.ts b/Neon EVM/neon-evm-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Neon EVM/neon-evm-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Neon EVM/neon-evm-starter/tsconfig.json b/Neon EVM/neon-evm-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Neon EVM/neon-evm-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 8b6ac7ef93f365f5b8dc167f6e5b2e318f138d41 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:14:33 +0800 Subject: [PATCH 15/31] Featuring Manta Pacific Sepolia (#261) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../.gitignore | 60 +++++ .../LICENSE | 21 ++ .../README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../package.json | 34 +++ .../project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.github/workflows/pr.yml create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.gitignore create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/LICENSE create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/README.md create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/abis/erc20.abi.json create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/docker-compose.yml create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/docker/load-extensions.sh create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/docker/pg-Dockerfile create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/package.json create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/project.ts create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/schema.graphql create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/src/index.ts create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 1f5db0f7..f9ee3b98 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Manta Pacific Sepolia", "Neon EVM", "opBNB Testnet", "OP Sepolia", diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.github/workflows/cli-deploy.yml b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.github/workflows/pr.yml b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.gitignore b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/LICENSE b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/README.md b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/README.md new file mode 100644 index 00000000..0ad8badf --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Manta Pacific Sepolia Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the testUSDC (`0x9c76c6304885661CdB97F3984b13114B6D4b5248`) on Manta Pacific Sepolia Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/abis/erc20.abi.json b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/docker-compose.yml b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/docker/load-extensions.sh b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Manta Pacific Sepolia this is 3441006 + * https://chainlist.org/chain/3441006 + */ + chainId: "3441006", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://endpoints.omniatech.io/v1/manta-pacific/sepolia/public,https://endpoints.omniatech.io/v1/manta-pacific/sepolia/public"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 220462, + options: { + abi: "erc20", + // This is the contract address for testUSDC + address: "0x9c76c6304885661CdB97F3984b13114B6D4b5248", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Manta Pacific Sepolia Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/schema.graphql b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/src/index.ts b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/src/mappings/mappingHandlers.ts b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/src/test/mappingHandlers.test.ts b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/tsconfig.json b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Manta Pacific Sepolia/manta-pacific-sepolia-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 8ed493fe9db18f01c7c1eb1ed88c662e1e1a293a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:15:06 +0800 Subject: [PATCH 16/31] Featuring Immutable zkEVM (#259) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../.gitignore | 60 +++++ .../immutable-zkevm-testnet-starter/LICENSE | 21 ++ .../immutable-zkevm-testnet-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../package.json | 34 +++ .../project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/.github/workflows/pr.yml create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/.gitignore create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/LICENSE create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/README.md create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/abis/erc20.abi.json create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/docker-compose.yml create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/docker/load-extensions.sh create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/docker/pg-Dockerfile create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/package.json create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/project.ts create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/schema.graphql create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/src/index.ts create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Immutable zkEVM/immutable-zkevm-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index f9ee3b98..658d98cf 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Immutable zkEVM", "Manta Pacific Sepolia", "Neon EVM", "opBNB Testnet", diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/.github/workflows/cli-deploy.yml b/Immutable zkEVM/immutable-zkevm-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/.github/workflows/pr.yml b/Immutable zkEVM/immutable-zkevm-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Immutable zkEVM/immutable-zkevm-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/.gitignore b/Immutable zkEVM/immutable-zkevm-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/LICENSE b/Immutable zkEVM/immutable-zkevm-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/README.md b/Immutable zkEVM/immutable-zkevm-testnet-starter/README.md new file mode 100644 index 00000000..3a66ca73 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Immutable zkEVM Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Best Game Token (`0x1303F139FEac224ff877e6071C782A41C30F3255`) on Immutable zkEVM Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/abis/erc20.abi.json b/Immutable zkEVM/immutable-zkevm-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/docker-compose.yml b/Immutable zkEVM/immutable-zkevm-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/docker/load-extensions.sh b/Immutable zkEVM/immutable-zkevm-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Immutable zkEVM this is 13473 + * https://chainlist.org/chain/13473 + */ + chainId: "13473", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://rpc.testnet.immutable.com,wss://immutable-zkevm-testnet.drpc.org"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 6934244, + options: { + abi: "erc20", + // This is the contract address for Best Game Token + address: "0x1303F139FEac224ff877e6071C782A41C30F3255", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Immutable zkEVM Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/schema.graphql b/Immutable zkEVM/immutable-zkevm-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/src/index.ts b/Immutable zkEVM/immutable-zkevm-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/src/mappings/mappingHandlers.ts b/Immutable zkEVM/immutable-zkevm-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/src/test/mappingHandlers.test.ts b/Immutable zkEVM/immutable-zkevm-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Immutable zkEVM/immutable-zkevm-testnet-starter/tsconfig.json b/Immutable zkEVM/immutable-zkevm-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 97fa1bcc352bc4d36d54eea67dc5b9631ea3e62f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:15:40 +0800 Subject: [PATCH 17/31] Featuring Immutable zkEVM (#257) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../immutable-zkevm-starter/.gitignore | 60 +++++ .../immutable-zkevm-starter/LICENSE | 21 ++ .../immutable-zkevm-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../immutable-zkevm-starter/package.json | 34 +++ .../immutable-zkevm-starter/project.ts | 89 +++++++ .../immutable-zkevm-starter/schema.graphql | 21 ++ .../immutable-zkevm-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../immutable-zkevm-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Immutable zkEVM/immutable-zkevm-starter/.github/workflows/cli-deploy.yml create mode 100644 Immutable zkEVM/immutable-zkevm-starter/.github/workflows/pr.yml create mode 100644 Immutable zkEVM/immutable-zkevm-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Immutable zkEVM/immutable-zkevm-starter/.gitignore create mode 100644 Immutable zkEVM/immutable-zkevm-starter/LICENSE create mode 100644 Immutable zkEVM/immutable-zkevm-starter/README.md create mode 100644 Immutable zkEVM/immutable-zkevm-starter/abis/erc20.abi.json create mode 100644 Immutable zkEVM/immutable-zkevm-starter/docker-compose.yml create mode 100644 Immutable zkEVM/immutable-zkevm-starter/docker/load-extensions.sh create mode 100644 Immutable zkEVM/immutable-zkevm-starter/docker/pg-Dockerfile create mode 100644 Immutable zkEVM/immutable-zkevm-starter/package.json create mode 100644 Immutable zkEVM/immutable-zkevm-starter/project.ts create mode 100644 Immutable zkEVM/immutable-zkevm-starter/schema.graphql create mode 100644 Immutable zkEVM/immutable-zkevm-starter/src/index.ts create mode 100644 Immutable zkEVM/immutable-zkevm-starter/src/mappings/mappingHandlers.ts create mode 100644 Immutable zkEVM/immutable-zkevm-starter/src/test/mappingHandlers.test.ts create mode 100644 Immutable zkEVM/immutable-zkevm-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 658d98cf..7df27929 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -90,6 +90,7 @@ "Kakarot Starknet", "0G Newton Testnet", "Immutable zkEVM", + "Immutable zkEVM", "Manta Pacific Sepolia", "Neon EVM", "opBNB Testnet", diff --git a/Immutable zkEVM/immutable-zkevm-starter/.github/workflows/cli-deploy.yml b/Immutable zkEVM/immutable-zkevm-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Immutable zkEVM/immutable-zkevm-starter/.github/workflows/pr.yml b/Immutable zkEVM/immutable-zkevm-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Immutable zkEVM/immutable-zkevm-starter/.github/workflows/scripts/publish-deploy.sh b/Immutable zkEVM/immutable-zkevm-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Immutable zkEVM/immutable-zkevm-starter/.gitignore b/Immutable zkEVM/immutable-zkevm-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Immutable zkEVM/immutable-zkevm-starter/LICENSE b/Immutable zkEVM/immutable-zkevm-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Immutable zkEVM/immutable-zkevm-starter/README.md b/Immutable zkEVM/immutable-zkevm-starter/README.md new file mode 100644 index 00000000..0be7418a --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Immutable zkEVM + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the BitGem (`0xd82bbD600c5Ee9fAF1647d39f25F2aF356B2c565`) on Immutable zkEVM** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Immutable zkEVM/immutable-zkevm-starter/abis/erc20.abi.json b/Immutable zkEVM/immutable-zkevm-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Immutable zkEVM/immutable-zkevm-starter/docker-compose.yml b/Immutable zkEVM/immutable-zkevm-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Immutable zkEVM/immutable-zkevm-starter/docker/load-extensions.sh b/Immutable zkEVM/immutable-zkevm-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Immutable zkEVM this is 13371 + * https://chainlist.org/chain/13371 + */ + chainId: "13371", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://rpc.immutable.com,wss://immutable-zkevm.drpc.org"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 3168018, + options: { + abi: "erc20", + // This is the contract address for BitGem + address: "0xd82bbD600c5Ee9fAF1647d39f25F2aF356B2c565", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Immutable zkEVM is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Immutable zkEVM/immutable-zkevm-starter/schema.graphql b/Immutable zkEVM/immutable-zkevm-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Immutable zkEVM/immutable-zkevm-starter/src/index.ts b/Immutable zkEVM/immutable-zkevm-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Immutable zkEVM/immutable-zkevm-starter/src/mappings/mappingHandlers.ts b/Immutable zkEVM/immutable-zkevm-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Immutable zkEVM/immutable-zkevm-starter/src/test/mappingHandlers.test.ts b/Immutable zkEVM/immutable-zkevm-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Immutable zkEVM/immutable-zkevm-starter/tsconfig.json b/Immutable zkEVM/immutable-zkevm-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Immutable zkEVM/immutable-zkevm-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 6b91ca871547dc8559928d85bc1452b2ab325f83 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:16:13 +0800 Subject: [PATCH 18/31] Featuring Optimism Celestia Raspberry (#255) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../.gitignore | 60 +++++ .../LICENSE | 21 ++ .../README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../package.json | 34 +++ .../project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.github/workflows/pr.yml create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.gitignore create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/LICENSE create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/README.md create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/abis/erc20.abi.json create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/docker-compose.yml create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/docker/load-extensions.sh create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/docker/pg-Dockerfile create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/package.json create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/project.ts create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/schema.graphql create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/src/index.ts create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 7df27929..78a2daba 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Optimism Celestia Raspberry", "Immutable zkEVM", "Immutable zkEVM", "Manta Pacific Sepolia", diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.github/workflows/cli-deploy.yml b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.github/workflows/pr.yml b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.gitignore b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/LICENSE b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/README.md b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/README.md new file mode 100644 index 00000000..3779ad84 --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Optimism Celestia Raspberry Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the TEST (`0x39008557c498c7B620Ec9F882e556faD8ADBdCd5`) on Optimism Celestia Raspberry Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/abis/erc20.abi.json b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/docker-compose.yml b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/docker/load-extensions.sh b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Optimism Celestia Raspberry this is 123420111 + * https://chainlist.org/chain/123420111 + */ + chainId: "123420111", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["wss://ws.opcelestia-raspberry.gelato.digital,https://rpc.opcelestia-raspberry.gelato.digital"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 4783457, + options: { + abi: "erc20", + // This is the contract address for TEST + address: "0x39008557c498c7B620Ec9F882e556faD8ADBdCd5", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Optimism Celestia Raspberry Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/schema.graphql b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/src/index.ts b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/src/mappings/mappingHandlers.ts b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/src/test/mappingHandlers.test.ts b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/tsconfig.json b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Optimism Celestia Raspberry/optimism-celestia-raspberry-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 5a31e7c23e6f2ac23eb50b9697fd00e75ac4688d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:16:41 +0800 Subject: [PATCH 19/31] Featuring Arbitrum Blueberry (#253) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../.gitignore | 60 +++++ .../LICENSE | 21 ++ .../README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../package.json | 34 +++ .../project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.github/workflows/pr.yml create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.gitignore create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/LICENSE create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/README.md create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/abis/erc20.abi.json create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/docker-compose.yml create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/docker/load-extensions.sh create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/docker/pg-Dockerfile create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/package.json create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/project.ts create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/schema.graphql create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/src/index.ts create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 78a2daba..9e79e457 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Arbitrum Blueberry", "Optimism Celestia Raspberry", "Immutable zkEVM", "Immutable zkEVM", diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.github/workflows/cli-deploy.yml b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.github/workflows/pr.yml b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.gitignore b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/LICENSE b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/README.md b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/README.md new file mode 100644 index 00000000..cec8b2f2 --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Arbitrum Blueberry Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Playnance (`0x73C3cDd1418c3F17D54A81148387d93122802E72`) on Arbitrum Blueberry Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/abis/erc20.abi.json b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/docker-compose.yml b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/docker/load-extensions.sh b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Arbitrum Blueberry this is 88153591557 + * https://chainlist.org/chain/88153591557 + */ + chainId: "88153591557", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["wss://ws.arb-blueberry.gelato.digital,https://rpc.arb-blueberry.gelato.digital"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 51217, + options: { + abi: "erc20", + // This is the contract address for Playnance + address: "0x73C3cDd1418c3F17D54A81148387d93122802E72", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Arbitrum Blueberry Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/schema.graphql b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/src/index.ts b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/src/mappings/mappingHandlers.ts b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/src/test/mappingHandlers.test.ts b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/tsconfig.json b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Arbitrum Blueberry/arbitrum-blueberry-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From bae21f2f27cebaa44c61a1cf50abc3291ad0bb84 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:17:09 +0800 Subject: [PATCH 20/31] Featuring Fantom (#251) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ Fantom/fantom-testnet-starter/.gitignore | 60 +++++ Fantom/fantom-testnet-starter/LICENSE | 21 ++ Fantom/fantom-testnet-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../fantom-testnet-starter/docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + Fantom/fantom-testnet-starter/package.json | 34 +++ Fantom/fantom-testnet-starter/project.ts | 89 +++++++ Fantom/fantom-testnet-starter/schema.graphql | 21 ++ Fantom/fantom-testnet-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + Fantom/fantom-testnet-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Fantom/fantom-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Fantom/fantom-testnet-starter/.github/workflows/pr.yml create mode 100644 Fantom/fantom-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Fantom/fantom-testnet-starter/.gitignore create mode 100644 Fantom/fantom-testnet-starter/LICENSE create mode 100644 Fantom/fantom-testnet-starter/README.md create mode 100644 Fantom/fantom-testnet-starter/abis/erc20.abi.json create mode 100644 Fantom/fantom-testnet-starter/docker-compose.yml create mode 100644 Fantom/fantom-testnet-starter/docker/load-extensions.sh create mode 100644 Fantom/fantom-testnet-starter/docker/pg-Dockerfile create mode 100644 Fantom/fantom-testnet-starter/package.json create mode 100644 Fantom/fantom-testnet-starter/project.ts create mode 100644 Fantom/fantom-testnet-starter/schema.graphql create mode 100644 Fantom/fantom-testnet-starter/src/index.ts create mode 100644 Fantom/fantom-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Fantom/fantom-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Fantom/fantom-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 9e79e457..3ec01999 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Fantom", "Arbitrum Blueberry", "Optimism Celestia Raspberry", "Immutable zkEVM", diff --git a/Fantom/fantom-testnet-starter/.github/workflows/cli-deploy.yml b/Fantom/fantom-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Fantom/fantom-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Fantom/fantom-testnet-starter/.github/workflows/pr.yml b/Fantom/fantom-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Fantom/fantom-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Fantom/fantom-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Fantom/fantom-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Fantom/fantom-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Fantom/fantom-testnet-starter/.gitignore b/Fantom/fantom-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Fantom/fantom-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Fantom/fantom-testnet-starter/LICENSE b/Fantom/fantom-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Fantom/fantom-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Fantom/fantom-testnet-starter/README.md b/Fantom/fantom-testnet-starter/README.md new file mode 100644 index 00000000..36c07dc5 --- /dev/null +++ b/Fantom/fantom-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Fantom Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the WFTM (`0xE8175A3C1Dd1337aD276a8105ae6375367bf620B`) on Fantom Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Fantom/fantom-testnet-starter/abis/erc20.abi.json b/Fantom/fantom-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Fantom/fantom-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Fantom/fantom-testnet-starter/docker-compose.yml b/Fantom/fantom-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Fantom/fantom-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Fantom/fantom-testnet-starter/docker/load-extensions.sh b/Fantom/fantom-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Fantom/fantom-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Fantom this is 4002 + * https://chainlist.org/chain/4002 + */ + chainId: "4002", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://rpc.testnet.fantom.network,https://fantom-testnet.public.blastapi.io,wss://fantom-testnet-rpc.publicnode.com"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 26060817, + options: { + abi: "erc20", + // This is the contract address for WFTM + address: "0xE8175A3C1Dd1337aD276a8105ae6375367bf620B", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Fantom Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Fantom/fantom-testnet-starter/schema.graphql b/Fantom/fantom-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Fantom/fantom-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Fantom/fantom-testnet-starter/src/index.ts b/Fantom/fantom-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Fantom/fantom-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Fantom/fantom-testnet-starter/src/mappings/mappingHandlers.ts b/Fantom/fantom-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Fantom/fantom-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Fantom/fantom-testnet-starter/src/test/mappingHandlers.test.ts b/Fantom/fantom-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Fantom/fantom-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Fantom/fantom-testnet-starter/tsconfig.json b/Fantom/fantom-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Fantom/fantom-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From a91b7d3f314eb04f6f0ab83e616ac9ea2f0121d4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:17:43 +0800 Subject: [PATCH 21/31] Featuring Exosama Network (#249) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../exosama-network-starter/.gitignore | 60 +++++ .../exosama-network-starter/LICENSE | 21 ++ .../exosama-network-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../exosama-network-starter/package.json | 34 +++ .../exosama-network-starter/project.ts | 89 +++++++ .../exosama-network-starter/schema.graphql | 21 ++ .../exosama-network-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../exosama-network-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Exosama Network/exosama-network-starter/.github/workflows/cli-deploy.yml create mode 100644 Exosama Network/exosama-network-starter/.github/workflows/pr.yml create mode 100644 Exosama Network/exosama-network-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Exosama Network/exosama-network-starter/.gitignore create mode 100644 Exosama Network/exosama-network-starter/LICENSE create mode 100644 Exosama Network/exosama-network-starter/README.md create mode 100644 Exosama Network/exosama-network-starter/abis/erc20.abi.json create mode 100644 Exosama Network/exosama-network-starter/docker-compose.yml create mode 100644 Exosama Network/exosama-network-starter/docker/load-extensions.sh create mode 100644 Exosama Network/exosama-network-starter/docker/pg-Dockerfile create mode 100644 Exosama Network/exosama-network-starter/package.json create mode 100644 Exosama Network/exosama-network-starter/project.ts create mode 100644 Exosama Network/exosama-network-starter/schema.graphql create mode 100644 Exosama Network/exosama-network-starter/src/index.ts create mode 100644 Exosama Network/exosama-network-starter/src/mappings/mappingHandlers.ts create mode 100644 Exosama Network/exosama-network-starter/src/test/mappingHandlers.test.ts create mode 100644 Exosama Network/exosama-network-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 3ec01999..46b86948 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Exosama Network", "Fantom", "Arbitrum Blueberry", "Optimism Celestia Raspberry", diff --git a/Exosama Network/exosama-network-starter/.github/workflows/cli-deploy.yml b/Exosama Network/exosama-network-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Exosama Network/exosama-network-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Exosama Network/exosama-network-starter/.github/workflows/pr.yml b/Exosama Network/exosama-network-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Exosama Network/exosama-network-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Exosama Network/exosama-network-starter/.github/workflows/scripts/publish-deploy.sh b/Exosama Network/exosama-network-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Exosama Network/exosama-network-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Exosama Network/exosama-network-starter/.gitignore b/Exosama Network/exosama-network-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Exosama Network/exosama-network-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Exosama Network/exosama-network-starter/LICENSE b/Exosama Network/exosama-network-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Exosama Network/exosama-network-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Exosama Network/exosama-network-starter/README.md b/Exosama Network/exosama-network-starter/README.md new file mode 100644 index 00000000..9f2516f6 --- /dev/null +++ b/Exosama Network/exosama-network-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Exosama Network + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Stone (`0x122EBE2B679cF54Bc8a6e89c1009714b354e2d10`) on Exosama Network** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Exosama Network/exosama-network-starter/abis/erc20.abi.json b/Exosama Network/exosama-network-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Exosama Network/exosama-network-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Exosama Network/exosama-network-starter/docker-compose.yml b/Exosama Network/exosama-network-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Exosama Network/exosama-network-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Exosama Network/exosama-network-starter/docker/load-extensions.sh b/Exosama Network/exosama-network-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Exosama Network/exosama-network-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Exosama Network this is 2109 + * https://chainlist.org/chain/2109 + */ + chainId: "2109", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["wss://rpc.exosama.com,https://rpc.exosama.com"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 472169, + options: { + abi: "erc20", + // This is the contract address for Stone + address: "0x122EBE2B679cF54Bc8a6e89c1009714b354e2d10", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Exosama Network is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Exosama Network/exosama-network-starter/schema.graphql b/Exosama Network/exosama-network-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Exosama Network/exosama-network-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Exosama Network/exosama-network-starter/src/index.ts b/Exosama Network/exosama-network-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Exosama Network/exosama-network-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Exosama Network/exosama-network-starter/src/mappings/mappingHandlers.ts b/Exosama Network/exosama-network-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Exosama Network/exosama-network-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Exosama Network/exosama-network-starter/src/test/mappingHandlers.test.ts b/Exosama Network/exosama-network-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Exosama Network/exosama-network-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Exosama Network/exosama-network-starter/tsconfig.json b/Exosama Network/exosama-network-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Exosama Network/exosama-network-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From cab7cdbd10165b0075894b523679b60b131c933c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:18:27 +0800 Subject: [PATCH 22/31] Featuring Etherlink (#247) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../etherlink-testnet-starter/.gitignore | 60 +++++ Etherlink/etherlink-testnet-starter/LICENSE | 21 ++ Etherlink/etherlink-testnet-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../etherlink-testnet-starter/package.json | 34 +++ .../etherlink-testnet-starter/project.ts | 89 +++++++ .../etherlink-testnet-starter/schema.graphql | 21 ++ .../etherlink-testnet-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../etherlink-testnet-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Etherlink/etherlink-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Etherlink/etherlink-testnet-starter/.github/workflows/pr.yml create mode 100644 Etherlink/etherlink-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Etherlink/etherlink-testnet-starter/.gitignore create mode 100644 Etherlink/etherlink-testnet-starter/LICENSE create mode 100644 Etherlink/etherlink-testnet-starter/README.md create mode 100644 Etherlink/etherlink-testnet-starter/abis/erc20.abi.json create mode 100644 Etherlink/etherlink-testnet-starter/docker-compose.yml create mode 100644 Etherlink/etherlink-testnet-starter/docker/load-extensions.sh create mode 100644 Etherlink/etherlink-testnet-starter/docker/pg-Dockerfile create mode 100644 Etherlink/etherlink-testnet-starter/package.json create mode 100644 Etherlink/etherlink-testnet-starter/project.ts create mode 100644 Etherlink/etherlink-testnet-starter/schema.graphql create mode 100644 Etherlink/etherlink-testnet-starter/src/index.ts create mode 100644 Etherlink/etherlink-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Etherlink/etherlink-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Etherlink/etherlink-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 46b86948..13051e4a 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Etherlink", "Exosama Network", "Fantom", "Arbitrum Blueberry", diff --git a/Etherlink/etherlink-testnet-starter/.github/workflows/cli-deploy.yml b/Etherlink/etherlink-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Etherlink/etherlink-testnet-starter/.github/workflows/pr.yml b/Etherlink/etherlink-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Etherlink/etherlink-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Etherlink/etherlink-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Etherlink/etherlink-testnet-starter/.gitignore b/Etherlink/etherlink-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Etherlink/etherlink-testnet-starter/LICENSE b/Etherlink/etherlink-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Etherlink/etherlink-testnet-starter/README.md b/Etherlink/etherlink-testnet-starter/README.md new file mode 100644 index 00000000..68ac1f09 --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Etherlink Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Wrapped XTZ (`0xB1Ea698633d57705e93b0E40c1077d46CD6A51d8`) on Etherlink Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Etherlink/etherlink-testnet-starter/abis/erc20.abi.json b/Etherlink/etherlink-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Etherlink/etherlink-testnet-starter/docker-compose.yml b/Etherlink/etherlink-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Etherlink/etherlink-testnet-starter/docker/load-extensions.sh b/Etherlink/etherlink-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Etherlink this is 128123 + * https://chainlist.org/chain/128123 + */ + chainId: "128123", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://node.ghostnet.etherlink.com"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 1033039, + options: { + abi: "erc20", + // This is the contract address for Wrapped XTZ + address: "0xB1Ea698633d57705e93b0E40c1077d46CD6A51d8", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Etherlink Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Etherlink/etherlink-testnet-starter/schema.graphql b/Etherlink/etherlink-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Etherlink/etherlink-testnet-starter/src/index.ts b/Etherlink/etherlink-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Etherlink/etherlink-testnet-starter/src/mappings/mappingHandlers.ts b/Etherlink/etherlink-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Etherlink/etherlink-testnet-starter/src/test/mappingHandlers.test.ts b/Etherlink/etherlink-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Etherlink/etherlink-testnet-starter/tsconfig.json b/Etherlink/etherlink-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Etherlink/etherlink-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 2f4c2ac8d59498af60ce61226cc6f50e39152958 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:18:56 +0800 Subject: [PATCH 23/31] Featuring Etherlink Mainnet (#245) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../.gitignore | 60 +++++ .../LICENSE | 21 ++ .../README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../package.json | 34 +++ .../project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.github/workflows/cli-deploy.yml create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.github/workflows/pr.yml create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.gitignore create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/LICENSE create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/README.md create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/abis/erc20.abi.json create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/docker-compose.yml create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/docker/load-extensions.sh create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/docker/pg-Dockerfile create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/package.json create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/project.ts create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/schema.graphql create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/src/index.ts create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/src/mappings/mappingHandlers.ts create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/src/test/mappingHandlers.test.ts create mode 100644 Etherlink Mainnet/etherlink-mainnet-etherlink-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 13051e4a..6a67eb5f 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Etherlink Mainnet", "Etherlink", "Exosama Network", "Fantom", diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.github/workflows/cli-deploy.yml b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.github/workflows/pr.yml b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.github/workflows/scripts/publish-deploy.sh b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.gitignore b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/LICENSE b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/README.md b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/README.md new file mode 100644 index 00000000..e5a3c626 --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Etherlink Mainnet Etherlink + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Wrapped Ether (`0xfc24f770F94edBca6D6f885E12d4317320BcB401`) on Etherlink Mainnet Etherlink** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/abis/erc20.abi.json b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/docker-compose.yml b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/docker/load-extensions.sh b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Etherlink Mainnet this is 42793 + * https://chainlist.org/chain/42793 + */ + chainId: "42793", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://node.mainnet.etherlink.com"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 1062136, + options: { + abi: "erc20", + // This is the contract address for Wrapped Ether + address: "0xfc24f770F94edBca6D6f885E12d4317320BcB401", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Etherlink Mainnet Etherlink is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/schema.graphql b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/src/index.ts b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/src/mappings/mappingHandlers.ts b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/src/test/mappingHandlers.test.ts b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/tsconfig.json b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Etherlink Mainnet/etherlink-mainnet-etherlink-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 38ed8b3e8fcf633f03eb471b41f645963de6169a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:19:32 +0800 Subject: [PATCH 24/31] Featuring Ethereum Holesky (#243) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../.gitignore | 60 +++++ .../ethereum-holesky-testnet-starter/LICENSE | 21 ++ .../README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../package.json | 34 +++ .../project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/.github/workflows/pr.yml create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/.gitignore create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/LICENSE create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/README.md create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/abis/erc20.abi.json create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/docker-compose.yml create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/docker/load-extensions.sh create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/docker/pg-Dockerfile create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/package.json create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/project.ts create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/schema.graphql create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/src/index.ts create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Ethereum Holesky/ethereum-holesky-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 6a67eb5f..fdaff632 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Ethereum Holesky", "Etherlink Mainnet", "Etherlink", "Exosama Network", diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/.github/workflows/cli-deploy.yml b/Ethereum Holesky/ethereum-holesky-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/.github/workflows/pr.yml b/Ethereum Holesky/ethereum-holesky-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Ethereum Holesky/ethereum-holesky-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/.gitignore b/Ethereum Holesky/ethereum-holesky-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/LICENSE b/Ethereum Holesky/ethereum-holesky-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/README.md b/Ethereum Holesky/ethereum-holesky-testnet-starter/README.md new file mode 100644 index 00000000..321f853f --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Ethereum Holesky Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the GaspV2 (`0x5620cDb94BaAaD10c20483bd8705DA711b2Bc0a3`) on Ethereum Holesky Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/abis/erc20.abi.json b/Ethereum Holesky/ethereum-holesky-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/docker-compose.yml b/Ethereum Holesky/ethereum-holesky-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/docker/load-extensions.sh b/Ethereum Holesky/ethereum-holesky-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Ethereum Holesky this is 17000 + * https://chainlist.org/chain/17000 + */ + chainId: "17000", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["wss://ethereum-holesky-rpc.publicnode.com,wss://holesky.drpc.org"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 1817049, + options: { + abi: "erc20", + // This is the contract address for GaspV2 + address: "0x5620cDb94BaAaD10c20483bd8705DA711b2Bc0a3", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Ethereum Holesky Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/schema.graphql b/Ethereum Holesky/ethereum-holesky-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/src/index.ts b/Ethereum Holesky/ethereum-holesky-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/src/mappings/mappingHandlers.ts b/Ethereum Holesky/ethereum-holesky-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/src/test/mappingHandlers.test.ts b/Ethereum Holesky/ethereum-holesky-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Ethereum Holesky/ethereum-holesky-testnet-starter/tsconfig.json b/Ethereum Holesky/ethereum-holesky-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Ethereum Holesky/ethereum-holesky-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 4ef0cb19a49594963a2877e5e89f247e4e51a185 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:20:06 +0800 Subject: [PATCH 25/31] Featuring Dogechain (#241) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../dogechain-testnet-starter/.gitignore | 60 +++++ Dogechain/dogechain-testnet-starter/LICENSE | 21 ++ Dogechain/dogechain-testnet-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../dogechain-testnet-starter/package.json | 34 +++ .../dogechain-testnet-starter/project.ts | 89 +++++++ .../dogechain-testnet-starter/schema.graphql | 21 ++ .../dogechain-testnet-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../dogechain-testnet-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Dogechain/dogechain-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Dogechain/dogechain-testnet-starter/.github/workflows/pr.yml create mode 100644 Dogechain/dogechain-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Dogechain/dogechain-testnet-starter/.gitignore create mode 100644 Dogechain/dogechain-testnet-starter/LICENSE create mode 100644 Dogechain/dogechain-testnet-starter/README.md create mode 100644 Dogechain/dogechain-testnet-starter/abis/erc20.abi.json create mode 100644 Dogechain/dogechain-testnet-starter/docker-compose.yml create mode 100644 Dogechain/dogechain-testnet-starter/docker/load-extensions.sh create mode 100644 Dogechain/dogechain-testnet-starter/docker/pg-Dockerfile create mode 100644 Dogechain/dogechain-testnet-starter/package.json create mode 100644 Dogechain/dogechain-testnet-starter/project.ts create mode 100644 Dogechain/dogechain-testnet-starter/schema.graphql create mode 100644 Dogechain/dogechain-testnet-starter/src/index.ts create mode 100644 Dogechain/dogechain-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Dogechain/dogechain-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Dogechain/dogechain-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index fdaff632..5215cefe 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Dogechain", "Ethereum Holesky", "Etherlink Mainnet", "Etherlink", diff --git a/Dogechain/dogechain-testnet-starter/.github/workflows/cli-deploy.yml b/Dogechain/dogechain-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Dogechain/dogechain-testnet-starter/.github/workflows/pr.yml b/Dogechain/dogechain-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Dogechain/dogechain-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Dogechain/dogechain-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Dogechain/dogechain-testnet-starter/.gitignore b/Dogechain/dogechain-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Dogechain/dogechain-testnet-starter/LICENSE b/Dogechain/dogechain-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Dogechain/dogechain-testnet-starter/README.md b/Dogechain/dogechain-testnet-starter/README.md new file mode 100644 index 00000000..9aefd89c --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Dogechain Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the uREKT Token (`0x6F301941acF13997eF81E2F9e676f263d938b82D`) on Dogechain Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Dogechain/dogechain-testnet-starter/abis/erc20.abi.json b/Dogechain/dogechain-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Dogechain/dogechain-testnet-starter/docker-compose.yml b/Dogechain/dogechain-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Dogechain/dogechain-testnet-starter/docker/load-extensions.sh b/Dogechain/dogechain-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Dogechain this is 568 + * https://chainlist.org/chain/568 + */ + chainId: "568", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://rpc-testnet.dogechain.dog"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 7670482, + options: { + abi: "erc20", + // This is the contract address for uREKT Token + address: "0x6F301941acF13997eF81E2F9e676f263d938b82D", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Dogechain Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Dogechain/dogechain-testnet-starter/schema.graphql b/Dogechain/dogechain-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Dogechain/dogechain-testnet-starter/src/index.ts b/Dogechain/dogechain-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Dogechain/dogechain-testnet-starter/src/mappings/mappingHandlers.ts b/Dogechain/dogechain-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Dogechain/dogechain-testnet-starter/src/test/mappingHandlers.test.ts b/Dogechain/dogechain-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Dogechain/dogechain-testnet-starter/tsconfig.json b/Dogechain/dogechain-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Dogechain/dogechain-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From b661d7288babff4c17f1cd4089d194dba29e1b83 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:20:41 +0800 Subject: [PATCH 26/31] Featuring Dogechain (#239) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ Dogechain/dogechain-starter/.gitignore | 60 +++++ Dogechain/dogechain-starter/LICENSE | 21 ++ Dogechain/dogechain-starter/README.md | 90 +++++++ .../dogechain-starter/abis/erc20.abi.json | 222 ++++++++++++++++++ .../dogechain-starter/docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../dogechain-starter/docker/pg-Dockerfile | 9 + Dogechain/dogechain-starter/package.json | 34 +++ Dogechain/dogechain-starter/project.ts | 89 +++++++ Dogechain/dogechain-starter/schema.graphql | 21 ++ Dogechain/dogechain-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + Dogechain/dogechain-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Dogechain/dogechain-starter/.github/workflows/cli-deploy.yml create mode 100644 Dogechain/dogechain-starter/.github/workflows/pr.yml create mode 100644 Dogechain/dogechain-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Dogechain/dogechain-starter/.gitignore create mode 100644 Dogechain/dogechain-starter/LICENSE create mode 100644 Dogechain/dogechain-starter/README.md create mode 100644 Dogechain/dogechain-starter/abis/erc20.abi.json create mode 100644 Dogechain/dogechain-starter/docker-compose.yml create mode 100644 Dogechain/dogechain-starter/docker/load-extensions.sh create mode 100644 Dogechain/dogechain-starter/docker/pg-Dockerfile create mode 100644 Dogechain/dogechain-starter/package.json create mode 100644 Dogechain/dogechain-starter/project.ts create mode 100644 Dogechain/dogechain-starter/schema.graphql create mode 100644 Dogechain/dogechain-starter/src/index.ts create mode 100644 Dogechain/dogechain-starter/src/mappings/mappingHandlers.ts create mode 100644 Dogechain/dogechain-starter/src/test/mappingHandlers.test.ts create mode 100644 Dogechain/dogechain-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 5215cefe..f9967c2b 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -90,6 +90,7 @@ "Kakarot Starknet", "0G Newton Testnet", "Dogechain", + "Dogechain", "Ethereum Holesky", "Etherlink Mainnet", "Etherlink", diff --git a/Dogechain/dogechain-starter/.github/workflows/cli-deploy.yml b/Dogechain/dogechain-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Dogechain/dogechain-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Dogechain/dogechain-starter/.github/workflows/pr.yml b/Dogechain/dogechain-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Dogechain/dogechain-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Dogechain/dogechain-starter/.github/workflows/scripts/publish-deploy.sh b/Dogechain/dogechain-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Dogechain/dogechain-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Dogechain/dogechain-starter/.gitignore b/Dogechain/dogechain-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Dogechain/dogechain-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Dogechain/dogechain-starter/LICENSE b/Dogechain/dogechain-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Dogechain/dogechain-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Dogechain/dogechain-starter/README.md b/Dogechain/dogechain-starter/README.md new file mode 100644 index 00000000..d3ef53cc --- /dev/null +++ b/Dogechain/dogechain-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Dogechain + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the XEN Crypto (`0x948eed4490833D526688fD1E5Ba0b9B35CD2c32e`) on Dogechain** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Dogechain/dogechain-starter/abis/erc20.abi.json b/Dogechain/dogechain-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Dogechain/dogechain-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Dogechain/dogechain-starter/docker-compose.yml b/Dogechain/dogechain-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Dogechain/dogechain-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Dogechain/dogechain-starter/docker/load-extensions.sh b/Dogechain/dogechain-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Dogechain/dogechain-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Dogechain this is 2000 + * https://chainlist.org/chain/2000 + */ + chainId: "2000", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://rpc.dogechain.dog,https://rpc-us.dogechain.dog,https://rpc-sg.dogechain.dog"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 4100944, + options: { + abi: "erc20", + // This is the contract address for XEN Crypto + address: "0x948eed4490833D526688fD1E5Ba0b9B35CD2c32e", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Dogechain is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Dogechain/dogechain-starter/schema.graphql b/Dogechain/dogechain-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Dogechain/dogechain-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Dogechain/dogechain-starter/src/index.ts b/Dogechain/dogechain-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Dogechain/dogechain-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Dogechain/dogechain-starter/src/mappings/mappingHandlers.ts b/Dogechain/dogechain-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Dogechain/dogechain-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Dogechain/dogechain-starter/src/test/mappingHandlers.test.ts b/Dogechain/dogechain-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Dogechain/dogechain-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Dogechain/dogechain-starter/tsconfig.json b/Dogechain/dogechain-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Dogechain/dogechain-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 6509b990c6c32bff9d4342c06c56752dce1b23d6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:21:21 +0800 Subject: [PATCH 27/31] Featuring DFK Chain (#237) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ DFK Chain/dfk-chain-starter/.gitignore | 60 +++++ DFK Chain/dfk-chain-starter/LICENSE | 21 ++ DFK Chain/dfk-chain-starter/README.md | 90 +++++++ .../dfk-chain-starter/abis/erc20.abi.json | 222 ++++++++++++++++++ .../dfk-chain-starter/docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../dfk-chain-starter/docker/pg-Dockerfile | 9 + DFK Chain/dfk-chain-starter/package.json | 34 +++ DFK Chain/dfk-chain-starter/project.ts | 89 +++++++ DFK Chain/dfk-chain-starter/schema.graphql | 21 ++ DFK Chain/dfk-chain-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + DFK Chain/dfk-chain-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 DFK Chain/dfk-chain-starter/.github/workflows/cli-deploy.yml create mode 100644 DFK Chain/dfk-chain-starter/.github/workflows/pr.yml create mode 100644 DFK Chain/dfk-chain-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 DFK Chain/dfk-chain-starter/.gitignore create mode 100644 DFK Chain/dfk-chain-starter/LICENSE create mode 100644 DFK Chain/dfk-chain-starter/README.md create mode 100644 DFK Chain/dfk-chain-starter/abis/erc20.abi.json create mode 100644 DFK Chain/dfk-chain-starter/docker-compose.yml create mode 100644 DFK Chain/dfk-chain-starter/docker/load-extensions.sh create mode 100644 DFK Chain/dfk-chain-starter/docker/pg-Dockerfile create mode 100644 DFK Chain/dfk-chain-starter/package.json create mode 100644 DFK Chain/dfk-chain-starter/project.ts create mode 100644 DFK Chain/dfk-chain-starter/schema.graphql create mode 100644 DFK Chain/dfk-chain-starter/src/index.ts create mode 100644 DFK Chain/dfk-chain-starter/src/mappings/mappingHandlers.ts create mode 100644 DFK Chain/dfk-chain-starter/src/test/mappingHandlers.test.ts create mode 100644 DFK Chain/dfk-chain-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index f9967c2b..3dce7a2c 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "DFK Chain", "Dogechain", "Dogechain", "Ethereum Holesky", diff --git a/DFK Chain/dfk-chain-starter/.github/workflows/cli-deploy.yml b/DFK Chain/dfk-chain-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/DFK Chain/dfk-chain-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/DFK Chain/dfk-chain-starter/.github/workflows/pr.yml b/DFK Chain/dfk-chain-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/DFK Chain/dfk-chain-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/DFK Chain/dfk-chain-starter/.github/workflows/scripts/publish-deploy.sh b/DFK Chain/dfk-chain-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/DFK Chain/dfk-chain-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/DFK Chain/dfk-chain-starter/.gitignore b/DFK Chain/dfk-chain-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/DFK Chain/dfk-chain-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/DFK Chain/dfk-chain-starter/LICENSE b/DFK Chain/dfk-chain-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/DFK Chain/dfk-chain-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/DFK Chain/dfk-chain-starter/README.md b/DFK Chain/dfk-chain-starter/README.md new file mode 100644 index 00000000..98bbcef1 --- /dev/null +++ b/DFK Chain/dfk-chain-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for DFK Chain + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the WJEWEL Token (`0xCCb93dABD71c8Dad03Fc4CE5559dC3D89F67a260`) on DFK Chain** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/DFK Chain/dfk-chain-starter/abis/erc20.abi.json b/DFK Chain/dfk-chain-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/DFK Chain/dfk-chain-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/DFK Chain/dfk-chain-starter/docker-compose.yml b/DFK Chain/dfk-chain-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/DFK Chain/dfk-chain-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/DFK Chain/dfk-chain-starter/docker/load-extensions.sh b/DFK Chain/dfk-chain-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/DFK Chain/dfk-chain-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for DFK Chain this is 53935 + * https://chainlist.org/chain/53935 + */ + chainId: "53935", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://subnets.avax.network/defi-kingdoms/dfk-chain/rpc"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 44, + options: { + abi: "erc20", + // This is the contract address for WJEWEL Token + address: "0xCCb93dABD71c8Dad03Fc4CE5559dC3D89F67a260", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since DFK Chain is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/DFK Chain/dfk-chain-starter/schema.graphql b/DFK Chain/dfk-chain-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/DFK Chain/dfk-chain-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/DFK Chain/dfk-chain-starter/src/index.ts b/DFK Chain/dfk-chain-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/DFK Chain/dfk-chain-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/DFK Chain/dfk-chain-starter/src/mappings/mappingHandlers.ts b/DFK Chain/dfk-chain-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/DFK Chain/dfk-chain-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/DFK Chain/dfk-chain-starter/src/test/mappingHandlers.test.ts b/DFK Chain/dfk-chain-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/DFK Chain/dfk-chain-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/DFK Chain/dfk-chain-starter/tsconfig.json b/DFK Chain/dfk-chain-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/DFK Chain/dfk-chain-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From b536d149a3bf8927e5e713dc2e06a6a8bae0db9a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:21:54 +0800 Subject: [PATCH 28/31] Featuring Cyber (#235) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ Cyber/cyber-testnet-starter/.gitignore | 60 +++++ Cyber/cyber-testnet-starter/LICENSE | 21 ++ Cyber/cyber-testnet-starter/README.md | 90 +++++++ .../cyber-testnet-starter/abis/erc20.abi.json | 222 ++++++++++++++++++ .../cyber-testnet-starter/docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + Cyber/cyber-testnet-starter/package.json | 34 +++ Cyber/cyber-testnet-starter/project.ts | 89 +++++++ Cyber/cyber-testnet-starter/schema.graphql | 21 ++ Cyber/cyber-testnet-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + Cyber/cyber-testnet-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Cyber/cyber-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Cyber/cyber-testnet-starter/.github/workflows/pr.yml create mode 100644 Cyber/cyber-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Cyber/cyber-testnet-starter/.gitignore create mode 100644 Cyber/cyber-testnet-starter/LICENSE create mode 100644 Cyber/cyber-testnet-starter/README.md create mode 100644 Cyber/cyber-testnet-starter/abis/erc20.abi.json create mode 100644 Cyber/cyber-testnet-starter/docker-compose.yml create mode 100644 Cyber/cyber-testnet-starter/docker/load-extensions.sh create mode 100644 Cyber/cyber-testnet-starter/docker/pg-Dockerfile create mode 100644 Cyber/cyber-testnet-starter/package.json create mode 100644 Cyber/cyber-testnet-starter/project.ts create mode 100644 Cyber/cyber-testnet-starter/schema.graphql create mode 100644 Cyber/cyber-testnet-starter/src/index.ts create mode 100644 Cyber/cyber-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Cyber/cyber-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Cyber/cyber-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index 3dce7a2c..e152538c 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Cyber", "DFK Chain", "Dogechain", "Dogechain", diff --git a/Cyber/cyber-testnet-starter/.github/workflows/cli-deploy.yml b/Cyber/cyber-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Cyber/cyber-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Cyber/cyber-testnet-starter/.github/workflows/pr.yml b/Cyber/cyber-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Cyber/cyber-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Cyber/cyber-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Cyber/cyber-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Cyber/cyber-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Cyber/cyber-testnet-starter/.gitignore b/Cyber/cyber-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Cyber/cyber-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Cyber/cyber-testnet-starter/LICENSE b/Cyber/cyber-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Cyber/cyber-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Cyber/cyber-testnet-starter/README.md b/Cyber/cyber-testnet-starter/README.md new file mode 100644 index 00000000..136c2390 --- /dev/null +++ b/Cyber/cyber-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Cyber Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Compound CYBER (`0x580278859b01bfdc303ca80b36be364b438105d6`) on Cyber Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Cyber/cyber-testnet-starter/abis/erc20.abi.json b/Cyber/cyber-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Cyber/cyber-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Cyber/cyber-testnet-starter/docker-compose.yml b/Cyber/cyber-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Cyber/cyber-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Cyber/cyber-testnet-starter/docker/load-extensions.sh b/Cyber/cyber-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Cyber/cyber-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Cyber this is 111557560 + * https://chainlist.org/chain/111557560 + */ + chainId: "111557560", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["wss://rpc.testnet.cyber.co,https://cyber-testnet.alt.technology"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 762850, + options: { + abi: "erc20", + // This is the contract address for Compound CYBER + address: "0x580278859b01bfdc303ca80b36be364b438105d6", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Cyber Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Cyber/cyber-testnet-starter/schema.graphql b/Cyber/cyber-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Cyber/cyber-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Cyber/cyber-testnet-starter/src/index.ts b/Cyber/cyber-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Cyber/cyber-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Cyber/cyber-testnet-starter/src/mappings/mappingHandlers.ts b/Cyber/cyber-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Cyber/cyber-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Cyber/cyber-testnet-starter/src/test/mappingHandlers.test.ts b/Cyber/cyber-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Cyber/cyber-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Cyber/cyber-testnet-starter/tsconfig.json b/Cyber/cyber-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Cyber/cyber-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From e45e307276b8aa72f9610d009cffe01bbab1cc46 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:22:44 +0800 Subject: [PATCH 29/31] Featuring Cyber (#233) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .../.github/workflows/cli-deploy.yml | 33 +++ Cyber/cyber-starter/.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ Cyber/cyber-starter/.gitignore | 60 +++++ Cyber/cyber-starter/LICENSE | 21 ++ Cyber/cyber-starter/README.md | 90 +++++++ Cyber/cyber-starter/abis/erc20.abi.json | 222 ++++++++++++++++++ Cyber/cyber-starter/docker-compose.yml | 67 ++++++ Cyber/cyber-starter/docker/load-extensions.sh | 6 + Cyber/cyber-starter/docker/pg-Dockerfile | 9 + Cyber/cyber-starter/package.json | 34 +++ Cyber/cyber-starter/project.ts | 89 +++++++ Cyber/cyber-starter/schema.graphql | 21 ++ Cyber/cyber-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + Cyber/cyber-starter/tsconfig.json | 16 ++ 17 files changed, 757 insertions(+) create mode 100644 Cyber/cyber-starter/.github/workflows/cli-deploy.yml create mode 100644 Cyber/cyber-starter/.github/workflows/pr.yml create mode 100644 Cyber/cyber-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Cyber/cyber-starter/.gitignore create mode 100644 Cyber/cyber-starter/LICENSE create mode 100644 Cyber/cyber-starter/README.md create mode 100644 Cyber/cyber-starter/abis/erc20.abi.json create mode 100644 Cyber/cyber-starter/docker-compose.yml create mode 100644 Cyber/cyber-starter/docker/load-extensions.sh create mode 100644 Cyber/cyber-starter/docker/pg-Dockerfile create mode 100644 Cyber/cyber-starter/package.json create mode 100644 Cyber/cyber-starter/project.ts create mode 100644 Cyber/cyber-starter/schema.graphql create mode 100644 Cyber/cyber-starter/src/index.ts create mode 100644 Cyber/cyber-starter/src/mappings/mappingHandlers.ts create mode 100644 Cyber/cyber-starter/src/test/mappingHandlers.test.ts create mode 100644 Cyber/cyber-starter/tsconfig.json diff --git a/Cyber/cyber-starter/.github/workflows/cli-deploy.yml b/Cyber/cyber-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Cyber/cyber-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Cyber/cyber-starter/.github/workflows/pr.yml b/Cyber/cyber-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Cyber/cyber-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Cyber/cyber-starter/.github/workflows/scripts/publish-deploy.sh b/Cyber/cyber-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Cyber/cyber-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Cyber/cyber-starter/.gitignore b/Cyber/cyber-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Cyber/cyber-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Cyber/cyber-starter/LICENSE b/Cyber/cyber-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Cyber/cyber-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Cyber/cyber-starter/README.md b/Cyber/cyber-starter/README.md new file mode 100644 index 00000000..aac13208 --- /dev/null +++ b/Cyber/cyber-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Cyber + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the CyberConnect (`0x14778860e937f509e651192a90589de711fb88a9`) on Cyber** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Cyber/cyber-starter/abis/erc20.abi.json b/Cyber/cyber-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Cyber/cyber-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Cyber/cyber-starter/docker-compose.yml b/Cyber/cyber-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Cyber/cyber-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Cyber/cyber-starter/docker/load-extensions.sh b/Cyber/cyber-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Cyber/cyber-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Cyber this is 7560 + * https://chainlist.org/chain/7560 + */ + chainId: "7560", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://cyber.alt.technology,https://rpc.cyber.co,wss://cyber-ws.alt.technology"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 1236112, + options: { + abi: "erc20", + // This is the contract address for CyberConnect + address: "0x14778860e937f509e651192a90589de711fb88a9", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Cyber is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Cyber/cyber-starter/schema.graphql b/Cyber/cyber-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Cyber/cyber-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Cyber/cyber-starter/src/index.ts b/Cyber/cyber-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Cyber/cyber-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Cyber/cyber-starter/src/mappings/mappingHandlers.ts b/Cyber/cyber-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Cyber/cyber-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Cyber/cyber-starter/src/test/mappingHandlers.test.ts b/Cyber/cyber-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Cyber/cyber-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Cyber/cyber-starter/tsconfig.json b/Cyber/cyber-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Cyber/cyber-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 968994e0250244594c07c993499b5a47eb000085 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:23:15 +0800 Subject: [PATCH 30/31] Featuring Celo Alfajores (#231) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ .../celo-alfajores-testnet-starter/.gitignore | 60 +++++ .../celo-alfajores-testnet-starter/LICENSE | 21 ++ .../celo-alfajores-testnet-starter/README.md | 90 +++++++ .../abis/erc20.abi.json | 222 ++++++++++++++++++ .../docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + .../package.json | 34 +++ .../celo-alfajores-testnet-starter/project.ts | 89 +++++++ .../schema.graphql | 21 ++ .../src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + .../tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/.github/workflows/pr.yml create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/.gitignore create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/LICENSE create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/README.md create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/abis/erc20.abi.json create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/docker-compose.yml create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/docker/load-extensions.sh create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/docker/pg-Dockerfile create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/package.json create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/project.ts create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/schema.graphql create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/src/index.ts create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Celo Alfajores/celo-alfajores-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index e152538c..ed2289be 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Celo Alfajores", "Cyber", "DFK Chain", "Dogechain", diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/.github/workflows/cli-deploy.yml b/Celo Alfajores/celo-alfajores-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/.github/workflows/pr.yml b/Celo Alfajores/celo-alfajores-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Celo Alfajores/celo-alfajores-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/.gitignore b/Celo Alfajores/celo-alfajores-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/LICENSE b/Celo Alfajores/celo-alfajores-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/README.md b/Celo Alfajores/celo-alfajores-testnet-starter/README.md new file mode 100644 index 00000000..7fbdc251 --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Celo Alfajores Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the MyTether USD (`0x5C68B64d52B651916796f195fb776cB49bAa12d8`) on Celo Alfajores Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/abis/erc20.abi.json b/Celo Alfajores/celo-alfajores-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/docker-compose.yml b/Celo Alfajores/celo-alfajores-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/docker/load-extensions.sh b/Celo Alfajores/celo-alfajores-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Celo Alfajores this is 44787 + * https://chainlist.org/chain/44787 + */ + chainId: "44787", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://alfajores-forno.celo-testnet.org,wss://alfajores-forno.celo-testnet.org/ws"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 26160957, + options: { + abi: "erc20", + // This is the contract address for MyTether USD + address: "0x5C68B64d52B651916796f195fb776cB49bAa12d8", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Celo Alfajores Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/schema.graphql b/Celo Alfajores/celo-alfajores-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/src/index.ts b/Celo Alfajores/celo-alfajores-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/src/mappings/mappingHandlers.ts b/Celo Alfajores/celo-alfajores-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/src/test/mappingHandlers.test.ts b/Celo Alfajores/celo-alfajores-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Celo Alfajores/celo-alfajores-testnet-starter/tsconfig.json b/Celo Alfajores/celo-alfajores-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Celo Alfajores/celo-alfajores-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +} From 636ee29a0f578d5bb803fbf6b02df097f50198b0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:23:46 +0800 Subject: [PATCH 31/31] Featuring Canto (#229) Co-authored-by: jamesbayly <46693720+jamesbayly@users.noreply.github.com> Co-authored-by: James Bayly --- .github/scripts/ci.package.json | 1 + .../.github/workflows/cli-deploy.yml | 33 +++ .../.github/workflows/pr.yml | 24 ++ .../workflows/scripts/publish-deploy.sh | 14 ++ Canto/canto-testnet-starter/.gitignore | 60 +++++ Canto/canto-testnet-starter/LICENSE | 21 ++ Canto/canto-testnet-starter/README.md | 90 +++++++ .../canto-testnet-starter/abis/erc20.abi.json | 222 ++++++++++++++++++ .../canto-testnet-starter/docker-compose.yml | 67 ++++++ .../docker/load-extensions.sh | 6 + .../docker/pg-Dockerfile | 9 + Canto/canto-testnet-starter/package.json | 34 +++ Canto/canto-testnet-starter/project.ts | 89 +++++++ Canto/canto-testnet-starter/schema.graphql | 21 ++ Canto/canto-testnet-starter/src/index.ts | 2 + .../src/mappings/mappingHandlers.ts | 37 +++ .../src/test/mappingHandlers.test.ts | 12 + Canto/canto-testnet-starter/tsconfig.json | 16 ++ 18 files changed, 758 insertions(+) create mode 100644 Canto/canto-testnet-starter/.github/workflows/cli-deploy.yml create mode 100644 Canto/canto-testnet-starter/.github/workflows/pr.yml create mode 100644 Canto/canto-testnet-starter/.github/workflows/scripts/publish-deploy.sh create mode 100644 Canto/canto-testnet-starter/.gitignore create mode 100644 Canto/canto-testnet-starter/LICENSE create mode 100644 Canto/canto-testnet-starter/README.md create mode 100644 Canto/canto-testnet-starter/abis/erc20.abi.json create mode 100644 Canto/canto-testnet-starter/docker-compose.yml create mode 100644 Canto/canto-testnet-starter/docker/load-extensions.sh create mode 100644 Canto/canto-testnet-starter/docker/pg-Dockerfile create mode 100644 Canto/canto-testnet-starter/package.json create mode 100644 Canto/canto-testnet-starter/project.ts create mode 100644 Canto/canto-testnet-starter/schema.graphql create mode 100644 Canto/canto-testnet-starter/src/index.ts create mode 100644 Canto/canto-testnet-starter/src/mappings/mappingHandlers.ts create mode 100644 Canto/canto-testnet-starter/src/test/mappingHandlers.test.ts create mode 100644 Canto/canto-testnet-starter/tsconfig.json diff --git a/.github/scripts/ci.package.json b/.github/scripts/ci.package.json index ed2289be..4ae59ad6 100644 --- a/.github/scripts/ci.package.json +++ b/.github/scripts/ci.package.json @@ -89,6 +89,7 @@ "Now Chain", "Kakarot Starknet", "0G Newton Testnet", + "Canto", "Celo Alfajores", "Cyber", "DFK Chain", diff --git a/Canto/canto-testnet-starter/.github/workflows/cli-deploy.yml b/Canto/canto-testnet-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..5edba7c0 --- /dev/null +++ b/Canto/canto-testnet-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,33 @@ +name: "CLI deploy" + +on: + workflow_dispatch: + inputs: + projectName: + description: "Project name" + required: true + type: string +jobs: + deploy: + name: CLI Deploy + runs-on: ubuntu-latest + environment: + name: DEPLOYMENT + env: + SUBQL_ACCESS_TOKEN: ${{ secrets.SUBQL_ACCESS_TOKEN }} + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Version + run: npx subql --version + - name: repo + run: echo ${{github.repository}} + - name: Publish and Deploy + run: | + sh .github/workflows/scripts/publish-deploy.sh -o ${{github.repository}} -p ${{github.event.inputs.projectName}} diff --git a/Canto/canto-testnet-starter/.github/workflows/pr.yml b/Canto/canto-testnet-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..7a3166c7 --- /dev/null +++ b/Canto/canto-testnet-starter/.github/workflows/pr.yml @@ -0,0 +1,24 @@ +name: PR +on: + pull_request: + paths-ignore: + - ".github/workflows/**" +jobs: + pr: + name: pr + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + - run: yarn + - name: Codegen + run: yarn codegen + - name: Build + run: yarn build + - name: Install subql-node-ethereum + run: yarn global add @subql/node-ethereum + - name: Run tests with Subquery Node + run: subql-node-ethereum test -f ${{ github.workspace }} diff --git a/Canto/canto-testnet-starter/.github/workflows/scripts/publish-deploy.sh b/Canto/canto-testnet-starter/.github/workflows/scripts/publish-deploy.sh new file mode 100644 index 00000000..adae267d --- /dev/null +++ b/Canto/canto-testnet-starter/.github/workflows/scripts/publish-deploy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +while getopts p:o: flag +do + case "${flag}" in + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" \ No newline at end of file diff --git a/Canto/canto-testnet-starter/.gitignore b/Canto/canto-testnet-starter/.gitignore new file mode 100644 index 00000000..53b19635 --- /dev/null +++ b/Canto/canto-testnet-starter/.gitignore @@ -0,0 +1,60 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Generated files +target/ +dist/ +src/types +project.yaml + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv + +.data +.yarn + +.DS_Store diff --git a/Canto/canto-testnet-starter/LICENSE b/Canto/canto-testnet-starter/LICENSE new file mode 100644 index 00000000..f168fbe1 --- /dev/null +++ b/Canto/canto-testnet-starter/LICENSE @@ -0,0 +1,21 @@ +MIT LICENSE + +Copyright 2020-2024 SubQuery Pte Ltd authors & contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Canto/canto-testnet-starter/README.md b/Canto/canto-testnet-starter/README.md new file mode 100644 index 00000000..b43d1839 --- /dev/null +++ b/Canto/canto-testnet-starter/README.md @@ -0,0 +1,90 @@ +# SubQuery - Example Project for Canto Testnet + +[SubQuery](https://subquery.network) is a fast, flexible, and reliable open-source data indexer that provides you with custom APIs for your web3 project across all of our supported networks. To learn about how to get started with SubQuery, [visit our docs](https://academy.subquery.network). + +**This SubQuery project indexes all transfers and approval events for the Note (`0x03F734Bd9847575fDbE9bEaDDf9C166F880B5E5f`) on Canto Testnet** + +## Start + +First, install SubQuery CLI globally on your terminal by using NPM `npm install -g @subql/cli` + +You can either clone this GitHub repo, or use the `subql` CLI to bootstrap a clean project in the network of your choosing by running `subql init` and following the prompts. + +Don't forget to install dependencies with `npm install` or `yarn install`! + +## Editing your SubQuery project + +Although this is a working example SubQuery project, you can edit the SubQuery project by changing the following files: + +- The project manifest in `project.yaml` defines the key project configuration and mapping handler filters +- The GraphQL Schema (`schema.graphql`) defines the shape of the resulting data that you are using SubQuery to index +- The Mapping functions in `src/mappings/` directory are typescript functions that handle transformation logic + +SubQuery supports various layer-1 blockchain networks and provides [dedicated quick start guides](https://academy.subquery.network/quickstart/quickstart.html) as well as [detailed technical documentation](https://academy.subquery.network/build/introduction.html) for each of them. + +## Run your project + +_If you get stuck, find out how to get help below._ + +The simplest way to run your project is by running `yarn dev` or `npm run-script dev`. This does all of the following: + +1. `yarn codegen` - Generates types from the GraphQL schema definition and contract ABIs and saves them in the `/src/types` directory. This must be done after each change to the `schema.graphql` file or the contract ABIs +2. `yarn build` - Builds and packages the SubQuery project into the `/dist` directory +3. `docker-compose pull && docker-compose up` - Runs a Docker container with an indexer, PostgeSQL DB, and a query service. This requires [Docker to be installed](https://docs.docker.com/engine/install) and running locally. The configuration for this container is set from your `docker-compose.yml` + +You can observe the three services start, and once all are running (it may take a few minutes on your first start), please open your browser and head to [http://localhost:3000](http://localhost:3000) - you should see a GraphQL playground showing with the schemas ready to query. [Read the docs for more information](https://academy.subquery.network/run_publish/run.html) or [explore the possible service configuration for running SubQuery](https://academy.subquery.network/run_publish/references.html). + +## Query your project + +For this project, you can try to query with the following GraphQL code to get a taste of how it works. + +```graphql +{ + query { + transfers(first: 5, orderBy: VALUE_DESC) { + totalCount + nodes { + id + blockHeight + from + to + value + contractAddress + } + } + } + approvals(first: 5, orderBy: BLOCK_HEIGHT_DESC) { + nodes { + id + blockHeight + owner + spender + value + contractAddress + } + } +} +``` + +You can explore the different possible queries and entities to help you with GraphQL using the documentation draw on the right. + +## Publish your project + +SubQuery is open-source, meaning you have the freedom to run it in the following three ways: + +- Locally on your own computer (or a cloud provider of your choosing), [view the instructions on how to run SubQuery Locally](https://academy.subquery.network/run_publish/run.html) +- By publishing it to our enterprise-level [Managed Service](https://managedservice.subquery.network), where we'll host your SubQuery project in production ready services for mission critical data with zero-downtime blue/green deployments. We even have a generous free tier. [Find out how](https://academy.subquery.network/run_publish/publish.html) +- By publishing it to the decentralised [SubQuery Network](https://app.subquery.network), the most open, performant, reliable, and scalable data service for dApp developers. The SubQuery Network indexes and services data to the global community in an incentivised and verifiable way + +## What Next? + +Take a look at some of our advanced features to take your project to the next level! + +- [**Multi-chain indexing support**](https://academy.subquery.network/build/multi-chain.html) - SubQuery allows you to index data from across different layer-1 networks into the same database, this allows you to query a single endpoint to get data for all supported networks. +- [**Dynamic Data Sources**](https://academy.subquery.network/build/dynamicdatasources.html) - When you want to index factory contracts, for example on a DEX or generative NFT project. +- [**Project Optimisation Advice**](https://academy.subquery.network/build/optimisation.html) - Some common tips on how to tweak your project to maximise performance. +- [**GraphQL Subscriptions**](https://academy.subquery.network/run_publish/subscription.html) - Build more reactive front end applications that subscribe to changes in your SubQuery project. + +## Need Help? + +The fastest way to get support is by [searching our documentation](https://academy.subquery.network), or by [joining our discord](https://discord.com/invite/subquery) and messaging us in the `#technical-support` channel. diff --git a/Canto/canto-testnet-starter/abis/erc20.abi.json b/Canto/canto-testnet-starter/abis/erc20.abi.json new file mode 100644 index 00000000..405d6b36 --- /dev/null +++ b/Canto/canto-testnet-starter/abis/erc20.abi.json @@ -0,0 +1,222 @@ +[ + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_spender", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_from", + "type": "address" + }, + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [ + { + "name": "", + "type": "uint8" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "name": "balance", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [ + { + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "_to", + "type": "address" + }, + { + "name": "_value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "_owner", + "type": "address" + }, + { + "name": "_spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "payable": true, + "stateMutability": "payable", + "type": "fallback" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "from", + "type": "address" + }, + { + "indexed": true, + "name": "to", + "type": "address" + }, + { + "indexed": false, + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } +] diff --git a/Canto/canto-testnet-starter/docker-compose.yml b/Canto/canto-testnet-starter/docker-compose.yml new file mode 100644 index 00000000..4ddd9bc3 --- /dev/null +++ b/Canto/canto-testnet-starter/docker-compose.yml @@ -0,0 +1,67 @@ +version: "3" + +services: + postgres: + build: + context: . + dockerfile: ./docker/pg-Dockerfile + ports: + - 5432:5432 + volumes: + - .data/postgres:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: postgres + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + subquery-node: + image: subquerynetwork/subql-node-ethereum:latest + depends_on: + "postgres": + condition: service_healthy + restart: unless-stopped + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + - ${SUB_COMMAND} # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + - --workers=4 + - --batch-size=30 + - --unfinalized-blocks=true + + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: subquerynetwork/subql-query:latest + ports: + - 3000:3000 + depends_on: + "postgres": + condition: service_healthy + "subquery-node": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + command: + - --name=app + - --playground + - --indexer=http://subquery-node:3000 diff --git a/Canto/canto-testnet-starter/docker/load-extensions.sh b/Canto/canto-testnet-starter/docker/load-extensions.sh new file mode 100644 index 00000000..7f5d0206 --- /dev/null +++ b/Canto/canto-testnet-starter/docker/load-extensions.sh @@ -0,0 +1,6 @@ + +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <=3.0.0", + }, + query: { + name: "@subql/query", + version: "*", + }, + }, + schema: { + file: "./schema.graphql", + }, + network: { + /** + * chainId is the EVM Chain ID, for Canto this is 7701 + * https://chainlist.org/chain/7701 + */ + chainId: "7701", + /** + * These endpoint(s) should be public non-pruned archive node + * We recommend providing more than one endpoint for improved reliability, performance, and uptime + * Public nodes may be rate limited, which can affect indexing speed + * When developing your project we suggest getting a private API key + * If you use a rate limited endpoint, adjust the --batch-size and --workers parameters + * These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited + */ + endpoint: ["https://testnet-archive.plexnode.wtf"], + }, + dataSources: [ + { + kind: EthereumDatasourceKind.Runtime, + startBlock: 149606, + options: { + abi: "erc20", + // This is the contract address for Note + address: "0x03F734Bd9847575fDbE9bEaDDf9C166F880B5E5f", + }, + assets: new Map([["erc20", { file: "./abis/erc20.abi.json" }]]), + mapping: { + file: "./dist/index.js", + handlers: [ + { + kind: EthereumHandlerKind.Call, // We use ethereum handlers since Canto Testnet is EVM-compatible + handler: "handleTransaction", + filter: { + /** + * The function can either be the function fragment or signature + * function: '0x095ea7b3' + * function: '0x7ff36ab500000000000000000000000000000000000000000000000000000000' + */ + function: "approve(address spender, uint256 amount)", + }, + }, + { + kind: EthereumHandlerKind.Event, + handler: "handleLog", + filter: { + /** + * Follows standard log filters https://docs.ethers.io/v5/concepts/events/ + * address: "0x60781C2586D68229fde47564546784ab3fACA982" + */ + topics: [ + "Transfer(address indexed from, address indexed to, uint256 amount)", + ], + }, + }, + ], + }, + }, + ], + repository: "https://github.com/subquery/ethereum-subql-starter", +}; + +// Must set default to the project instance +export default project; diff --git a/Canto/canto-testnet-starter/schema.graphql b/Canto/canto-testnet-starter/schema.graphql new file mode 100644 index 00000000..dc4b318c --- /dev/null +++ b/Canto/canto-testnet-starter/schema.graphql @@ -0,0 +1,21 @@ +# To improve query performance, we strongly suggest adding indexes to any field that you plan to filter or sort by +# Add the `@index` or `@index(unique: true)` annotation after any non-key field +# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field + +type Transfer @entity { + id: ID! # Transaction hash + blockHeight: BigInt + to: String! + from: String! + value: BigInt! + contractAddress: String! +} + +type Approval @entity { + id: ID! # Transaction hash + blockHeight: BigInt + owner: String! + spender: String! + value: BigInt! + contractAddress: String! +} diff --git a/Canto/canto-testnet-starter/src/index.ts b/Canto/canto-testnet-starter/src/index.ts new file mode 100644 index 00000000..fb59776f --- /dev/null +++ b/Canto/canto-testnet-starter/src/index.ts @@ -0,0 +1,2 @@ +//Exports all handler functions +export * from "./mappings/mappingHandlers"; diff --git a/Canto/canto-testnet-starter/src/mappings/mappingHandlers.ts b/Canto/canto-testnet-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..d5a6ade6 --- /dev/null +++ b/Canto/canto-testnet-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,37 @@ +import { Approval, Transfer } from "../types"; +import { + ApproveTransaction, + TransferLog, +} from "../types/abi-interfaces/Erc20Abi"; +import assert from "assert"; + +export async function handleLog(log: TransferLog): Promise { + logger.info(`New transfer transaction log at block ${log.blockNumber}`); + assert(log.args, "No log.args"); + + const transaction = Transfer.create({ + id: log.transactionHash, + blockHeight: BigInt(log.blockNumber), + to: log.args.to, + from: log.args.from, + value: log.args.value.toBigInt(), + contractAddress: log.address, + }); + + await transaction.save(); +} + +export async function handleTransaction(tx: ApproveTransaction): Promise { + logger.info(`New Approval transaction at block ${tx.blockNumber}`); + assert(tx.args, "No tx.args"); + + const approval = Approval.create({ + id: tx.hash, + owner: tx.from, + spender: await tx.args[0], + value: BigInt(await tx.args[1].toString()), + contractAddress: tx.to || "", + }); + + await approval.save(); +} diff --git a/Canto/canto-testnet-starter/src/test/mappingHandlers.test.ts b/Canto/canto-testnet-starter/src/test/mappingHandlers.test.ts new file mode 100644 index 00000000..42f41c3f --- /dev/null +++ b/Canto/canto-testnet-starter/src/test/mappingHandlers.test.ts @@ -0,0 +1,12 @@ +import { subqlTest } from "@subql/testing"; + +/* +// https://academy.subquery.network/build/testing.html +subqlTest( + "testName", // test name + 1000003, // block height to process + [], // dependent entities + [], // expected entities + "handleEvent" //handler name +); +*/ diff --git a/Canto/canto-testnet-starter/tsconfig.json b/Canto/canto-testnet-starter/tsconfig.json new file mode 100644 index 00000000..5dee9796 --- /dev/null +++ b/Canto/canto-testnet-starter/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2018", + "strict": true, + }, + "include": ["src/**/*", "node_modules/@subql/types-core/dist/global.d.ts"], +}