diff --git a/Moonbeam/moonbeam-substrate-evm-starter/.github/scripts/publish-deploy.sh b/Moonbeam/moonbeam-substrate-evm-starter/.github/scripts/publish-deploy.sh new file mode 100644 index 00000000..3c9dc04b --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/.github/scripts/publish-deploy.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +while getopts p:o:e: flag +do + case "${flag}" in + e) ENDPOINT=${OPTARG};; + p) PROJECTNAME=${OPTARG};; + o) ORG=${OPTARG};; + *) echo "Usage: $0 [-p projectname] [-o org] [-e endpoint]" && exit 1;; + esac +done + +IPFSCID=$(npx subql publish -o -f .) + +npx subql deployment:deploy -d --ipfsCID="$IPFSCID" --projectName="${PROJECTNAME}" --org="${ORG%/*}" --endpoint="${ENDPOINT}" diff --git a/Moonbeam/moonbeam-substrate-evm-starter/.github/workflows/cli-deploy.yml b/Moonbeam/moonbeam-substrate-evm-starter/.github/workflows/cli-deploy.yml new file mode 100644 index 00000000..658d2c6c --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/.github/workflows/cli-deploy.yml @@ -0,0 +1,34 @@ +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 }} + ENDPOINT: ${{ secrets.ENDPOINT }} + 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}} -e ${{secrets.ENDPOINT}} diff --git a/Moonbeam/moonbeam-substrate-evm-starter/.github/workflows/pr.yml b/Moonbeam/moonbeam-substrate-evm-starter/.github/workflows/pr.yml new file mode 100644 index 00000000..b428f2d8 --- /dev/null +++ b/Moonbeam/moonbeam-substrate-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 + run: yarn global add @subql/node + - name: Run tests with Subquery Node + run: subql-node test -f ${{ github.workspace }} diff --git a/Moonbeam/moonbeam-substrate-evm-starter/.gitignore b/Moonbeam/moonbeam-substrate-evm-starter/.gitignore new file mode 100644 index 00000000..1b334008 --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/.gitignore @@ -0,0 +1,57 @@ +# 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/ +.data/ + +# lock files +yarn.lock +package-lock.json + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Maven +target/ +dist/ +src/types + +# 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/* \ No newline at end of file diff --git a/Moonbeam/moonbeam-substrate-evm-starter/.project-cid b/Moonbeam/moonbeam-substrate-evm-starter/.project-cid new file mode 100644 index 00000000..0fac55f4 --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/.project-cid @@ -0,0 +1 @@ +QmcL3wVRtwgNYpgyfUfDJX3ZVUAe5j3qAmma9NN5DmCYtd \ No newline at end of file diff --git a/Moonbeam/moonbeam-substrate-evm-starter/README.md b/Moonbeam/moonbeam-substrate-evm-starter/README.md new file mode 100644 index 00000000..5edee07f --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/README.md @@ -0,0 +1,104 @@ +# SubQuery - Starter Package + +A basic Frontier EVM + Substrate example project with an event handler for the FrontierEVM and call handler for Substrate calls. Read more about this at https://academy.subquery.network/quickstart/quickstart_chains/polkadot-moonbeam.html. This project can be used as a starting point for developing your SubQuery project + +The Starter Package is an example that you can use as a starting point for developing your SubQuery project. +A SubQuery package defines which data The SubQuery will index from the Substrate blockchain, and how it will store it. + +## Preparation + +#### Environment + +- [Typescript](https://www.typescriptlang.org/) are required to compile project and define types. + +- Both SubQuery CLI and generated Project have dependencies and require [Node](https://nodejs.org/en/). + +#### Install the SubQuery CLI + +Install SubQuery CLI globally on your terminal by using NPM: + +``` +npm install -g @subql/cli +``` + +Run help to see available commands and usage provide by CLI + +``` +subql help +``` + +## Initialize the starter package + +Inside the directory in which you want to create the SubQuery project, simply replace `project-name` with your project name and run the command: + +``` +subql init project-name +``` + +Then you should see a folder with your project name has been created inside the directory, you can use this as the start point of your project. And the files should be identical as in the [Directory Structure](https://doc.subquery.network/directory_structure.html). + +Last, under the project directory, run following command to install all the dependency. + +``` +yarn install +``` + +## Configure your project + +In the starter package, we have provided a simple example of project configuration. You will be mainly working on the following files: + +- The Manifest in `project.yaml` +- The GraphQL Schema in `schema.graphql` +- The Mapping functions in `src/mappings/` directory + +For more information on how to write the SubQuery, +check out our doc section on [Define the SubQuery](https://doc.subquery.network/define_a_subquery.html) + +#### Code generation + +In order to index your SubQuery project, it is mandatory to build your project first. +Run this command under the project directory. + +``` +yarn codegen +``` + +## Build the project + +In order to deploy your SubQuery project to our hosted service, it is mandatory to pack your configuration before upload. +Run pack command from root directory of your project will automatically generate a `your-project-name.tgz` file. + +``` +yarn build +``` + +## Indexing and Query + +#### Run required systems in docker + +Under the project directory run following command: + +``` +docker-compose pull && docker-compose up +``` + +#### Query the project + +Open your browser and head to `http://localhost:3000`. + +Finally, you should see a GraphQL playground is showing in the explorer and the schemas that ready to query. + +For the `subql-starter` project, you can try to query with the following code to get a taste of how it works. + +```graphql +query { + erc20transfers (first: 10, orderBy: AMOUNT_DESC) { + nodes { + id + value + from + to + } + } +} +``` diff --git a/Moonbeam/moonbeam-substrate-evm-starter/docker-compose.yml b/Moonbeam/moonbeam-substrate-evm-starter/docker-compose.yml new file mode 100644 index 00000000..8b3df5ed --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/docker-compose.yml @@ -0,0 +1,63 @@ +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: onfinality/subql-node:latest + depends_on: + "postgres": + condition: service_healthy + restart: always + environment: + DB_USER: postgres + DB_PASS: postgres + DB_DATABASE: postgres + DB_HOST: postgres + DB_PORT: 5432 + volumes: + - ./:/app + command: + #- test # set SUB_COMMAND env variable to "test" to run tests + - -f=/app + - --db-schema=app + healthcheck: + test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] + interval: 3s + timeout: 5s + retries: 10 + + graphql-engine: + image: onfinality/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/Moonbeam/moonbeam-substrate-evm-starter/docker/load-extensions.sh b/Moonbeam/moonbeam-substrate-evm-starter/docker/load-extensions.sh new file mode 100644 index 00000000..6d33f863 --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/docker/load-extensions.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <- + A basic Substrate EVM example project with an event and call handler. Read more + about this at https://academy.subquery.network/build/substrate-evm.html. This + project can be use as a starting point for developing your SubQuery project +repository: "https://github.com/subquery/subql-starter.git" +schema: + file: ./schema.graphql +network: + # The genesis hash of the network (hash of block 0) + chainId: "0xfe58ea77779b7abda7da4ec526d14db9b1e9cd40a217c34892af80a9b332b76d" + # This endpoint must be a public non-pruned archive node + # Public nodes may be rate limited, which can affect indexing speed + # When developing your project we suggest getting a private API key + # You can get them from OnFinality for free https://app.onfinality.io + # https://documentation.onfinality.io/support/the-enhanced-api-service + endpoint: + - wss://moonbeam.api.onfinality.io/public-ws + - wss://wss.api.moonbeam.network + dictionary: "https://api.subquery.network/sq/subquery/moonbeam-dictionary" + chaintypes: + file: ./dist/chaintypes.js +dataSources: + - kind: substrate/Runtime + # This is the datasource for Moonbeam's Native Substrate processor + startBlock: 1 + mapping: + file: ./dist/index.js + handlers: + - handler: handleCollatorJoined + kind: substrate/CallHandler + filter: + module: staking + method: joinCandidates + - handler: handleCollatorLeft + kind: substrate/CallHandler + filter: + module: staking + method: executeLeaveCandidates + + - kind: substrate/FrontierEvm + startBlock: 189831 + processor: + file: "./node_modules/@subql/frontier-evm-processor/dist/bundle.js" + options: + # Must be a key of assets + abi: erc20 + # Contract address of $FRAX + address: "0x322E86852e492a7Ee17f28a78c663da38FB33bfb" + assets: + erc20: + file: ./erc20.abi.json + mapping: + file: ./dist/index.js + handlers: + - handler: handleErc20Transfer + kind: substrate/FrontierEvmEvent + filter: + topics: + - "Transfer(address indexed from,address indexed to,uint256 indexed tokenId)" \ No newline at end of file diff --git a/Moonbeam/moonbeam-substrate-evm-starter/schema.graphql b/Moonbeam/moonbeam-substrate-evm-starter/schema.graphql new file mode 100644 index 00000000..6f8badbf --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/schema.graphql @@ -0,0 +1,20 @@ +# 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 Erc20Transfer @entity { + + id: ID! #id is a required field + from: String! + to: String! + contractAddress: String! + amount: BigInt! + +} + +type Collator @entity { + + id: ID! #collator address + joinedDate: Date! + +} \ No newline at end of file diff --git a/Moonbeam/moonbeam-substrate-evm-starter/src/chaintypes.ts b/Moonbeam/moonbeam-substrate-evm-starter/src/chaintypes.ts new file mode 100644 index 00000000..d90fbf8e --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/src/chaintypes.ts @@ -0,0 +1,3 @@ +import { typesBundleDeprecated } from "moonbeam-types-bundle"; + +export default { typesBundle: typesBundleDeprecated }; diff --git a/Moonbeam/moonbeam-substrate-evm-starter/src/index.ts b/Moonbeam/moonbeam-substrate-evm-starter/src/index.ts new file mode 100644 index 00000000..89dc0c5f --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/src/index.ts @@ -0,0 +1,3 @@ +//Exports all handler functions +import "@polkadot/api-augment"; +export * from "./mappings/mappingHandlers"; diff --git a/Moonbeam/moonbeam-substrate-evm-starter/src/mappings/mappingHandlers.ts b/Moonbeam/moonbeam-substrate-evm-starter/src/mappings/mappingHandlers.ts new file mode 100644 index 00000000..1ca03d74 --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/src/mappings/mappingHandlers.ts @@ -0,0 +1,52 @@ +import { + Erc20Transfer, Collator +} from "../types"; +import { + FrontierEvmEvent +} from "@subql/frontier-evm-processor"; + +import { + SubstrateExtrinsic, + SubstrateEvent, +} from "@subql/types"; + +global.atob = require("atob"); +global.Blob = require('node-blob'); +import { BigNumber } from "ethers"; + +export async function handleCollatorJoined(call: SubstrateExtrinsic): Promise { + //We added a logger to the top of this function, in order to see the block number of the event we are processing. + logger.info(`Processing SubstrateEvent at ${call.block.block.header.number}`); + + const address = call.extrinsic.signer.toString(); + + const collator = Collator.create({ + id: address, + joinedDate: call.block.timestamp + }); + + await collator.save(); + +} + +export async function handleCollatorLeft(call: SubstrateExtrinsic): Promise { + //We added a logger to the top of this function, in order to see the block number of the event we are processing. + logger.info(`Processing SubstrateCall at ${call.block.block.header.number}`); + + const address = call.extrinsic.signer.toString(); + await Collator.remove(address); +} + +export async function handleErc20Transfer(event: FrontierEvmEvent<[string, string, BigNumber] & { from: string, to: string, value: BigNumber, }>): Promise { + //We added a logger to the top of this function, in order to see the block number of the event we are processing. + logger.info(`Processing MoonbeamEvent at ${event.blockNumber.toString()}`); + const transfer = Erc20Transfer.create({ + id: event.transactionHash, + from: event.args.from, + to: event.args.to, + amount: event.args.value.toBigInt(), + contractAddress: event.address, + }); + + await transfer.save(); +} \ No newline at end of file diff --git a/Moonbeam/moonbeam-substrate-evm-starter/src/tests/mappingHandlers.test.ts b/Moonbeam/moonbeam-substrate-evm-starter/src/tests/mappingHandlers.test.ts new file mode 100644 index 00000000..e6d350e8 --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/src/tests/mappingHandlers.test.ts @@ -0,0 +1,21 @@ +import {subqlTest} from "@subql/testing"; +import {Collator, Erc20Transfer} from "../types"; + + +subqlTest( + "newCollator test", // test name + 1, // block height to process + [ + Collator.create({ + id: "1", + joinedDate: new Date(1000), + }), + ], // dependent entities + [ + Collator.create({ + id: "1", + joinedDate: new Date(1000), + }) + ], // expected entities + "handleCollatorJoined" //handler name +); \ No newline at end of file diff --git a/Moonbeam/moonbeam-substrate-evm-starter/tsconfig.json b/Moonbeam/moonbeam-substrate-evm-starter/tsconfig.json new file mode 100644 index 00000000..4be11b62 --- /dev/null +++ b/Moonbeam/moonbeam-substrate-evm-starter/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "declaration": true, + "importHelpers": true, + "resolveJsonModule": true, + "module": "commonjs", + "outDir": "dist", + "rootDir": "src", + "target": "es2017" + }, + "include": ["src/**/*", "node_modules/@subql/types/dist/global.d.ts"] +}