diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..e77954bd08a70176f66c6368d0623c307830d3a6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +/.git +/node_modules +/lib +/*Versions.json diff --git a/.env b/.env index f949bbf033bfec9b24ec2c2d24b00ad563758ddd..e45a883191fc10f4f12215605f1a8e23cc4fdc72 100644 --- a/.env +++ b/.env @@ -1,2 +1,3 @@ +DB_NAME=squid DB_PORT=23798 GQL_PORT=4350 diff --git a/.gitignore b/.gitignore index 61781f019f65d762e8685fbc7e748ca3ea5bddf6..86f413753fa4984dba00a1b1dc235fb40898515e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ /node_modules /lib -/chainVersions.json +/duniterVersions.json # IDE files /.idea diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..3866c3c9a6a0d7e1b8d40b14797fddb51669aac2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +FROM node:16-alpine AS node + +FROM node AS node-with-gyp +RUN apk add g++ make python3 + +FROM node-with-gyp AS builder +WORKDIR /squid +ADD package.json . +ADD package-lock.json . +RUN npm ci +ADD tsconfig.json . +ADD src src +RUN npm run build + +FROM node-with-gyp AS deps +WORKDIR /squid +ADD package.json . +ADD package-lock.json . +RUN npm ci --production + +FROM node AS squid +WORKDIR /squid +COPY --from=deps /squid/package.json . +COPY --from=deps /squid/package-lock.json . +COPY --from=deps /squid/node_modules node_modules +COPY --from=builder /squid/lib lib +ADD db db +ADD schema.graphql . +# TODO: use shorter PROMETHEUS_PORT +ENV PROCESSOR_PROMETHEUS_PORT 3000 +EXPOSE 3000 +EXPOSE 4000 + + +FROM squid AS processor +CMD ["npm", "run", "processor:start"] + + +FROM squid AS query-node +CMD ["npm", "run", "query-node:start"] diff --git a/FAQ.md b/FAQ.md new file mode 100644 index 0000000000000000000000000000000000000000..9305ac82ead0383d8d918f4de4c931b6a24d0e04 --- /dev/null +++ b/FAQ.md @@ -0,0 +1,166 @@ +# How-to cheat sheet + +## How to run a processor against a different chain? + +You will need to have WebSocket endpoint to connect to the chain node and a Squid Archive. For a registry of Squid Archives, check this community-owned [Archive Registry](https://github.com/subsquid/archive-registry) + +If you don't find a suitable Squid Archive in the registry, set up your own Squid archive. There are multiple examples in this [repo](https://github.com/subsquid/squid-archive-setup) + +Once set up, we encourage to contribute to the Squid community and make a PR to the [Archive Registry](https://github.com/subsquid/archive-registry). + + +## Where do I get a type bundle for my chain? + +Most chains publish their type bundles as an npm package. One of the best places to check for the latest version is the [polkadot-js/app repo](https://github.com/polkadot-js/apps/tree/master/packages/apps-config). Note, however, that a types bundle is only needed for pre-Metadata v14 blocks, so for recently deployed chains it may be not needed. + +Note that the type bundle format for typegen is slightly different from `OverrideBundleDefinition` of `polkadot.js`. The structure is as follows, all the fields are optional. + +```javascript +{ + types: {}, // top-level type definitions, as `.types` option of `ApiPromise` + typesAlias: {}, // top-level type alieases, as `.typesAlias` option of `ApiPromise` + versions: [ // spec version specific overrides, same as `OverrideBundleDefinition.types` of `polkadot.js` + { + minmax: [0, 1010] // spec range + types: {}, // type overrides for the spec range + typesAlias: {}, // type alias overrides for the spec range + } + ] +} +``` + + +## How do I write the schema? + +The schema file defines the shape of the final GraphQL API and has very few limitations. Designing the schema file is very similar to the design of the database schema. As a rule of thumb, the schema should represent high level domain specific entities and relations between them, to make data fetching and filtering easy for the API consumers. + +Typically, the API is consumed by the frontend and mobile apps, so it's a good idea to design the schema even before you go on with implementing the processor mappings. In fact, the processor is completely indpendent from the GraphQL server serving the API, so you can experiment how the API looks like. + +## How do I update my schema? + +TL;DR: If you're ok dropping the database, simply update `schema.graphql` and run: + +```sh +bash reset-schema.sh +``` + +OBS! The database will be wiped out, so if it's not an option, read below. + + +Here's a step-by-step instruction. First, generated the model files: + +```sh +npx sqd codegen +npm run build +``` + +Now you have to options: either create a migration for an incremental schema update or recreate the whole schema from scratch. + +During the development process, recreating the schema is often more convenient. However, if you already have a running API in production and don't want to resync it, having an incremental update is preferrable (but requires data backfilling). + +### Option 1: Recreate schema from scratch + +Run + +```sh +bash reset-db.sh +``` + +### Option 2: Make an incremental update to the schema + +Generate a migration for the incremental changes and apply it + +```sh +npx sqd db create-migration AddMyAwesomeNewField +npx sqd db migrate +``` + +You can find the newly generated and applied migration in `db/migrations`. + + +## How do I run and test the GraphQL API? + +Once the migrations are applied, simply run + +``` +npx squid-graphql-server +``` + +Observe the port (4350 by default) and navigate to `localhost:4350/graphql` to explore your API. However, you need to run the processor to start populating the database. + + +## How do I start the processor? + +First, make sure you have compiled your project with +``` +npm run build +``` + +Then simply run +``` +node -r dotenv/config lib/processor.js +``` + +Note that `-r dotenv/config` ensures that the database settings are picked up from `.env`. If you the environment variables them elsewhere, skip it. + +## How do I deploy my API to the Subsquid Hosted service? + +Login to the [Subsquid Hosted Service](https://app.subsquid.io) with your github handle to obtain a deployment key. Then create a Squid (that is, your deployment) and follow the instructions. + +## How do I know which events and extrinsics I need for the handlers? + +This part depends on the runtime business-logic of the chain. The primary and the most reliable source of information is thus the Rust sources for the pallets used by the chain. +For a quick lookup of the documentation and the data format it is often useful to check `Runtime` section of Subscan, e.g. for [Statemine](https://statemine.subscan.io/runtime). One can see the deployed pallets and drill down to events and extrinsics from there. One can also choose the spec version on the drop down. + +## How do I decode the event data? And how to deal with runtime upgrades? + +Runtime upgrades may change the event data and even the event logic altogether, but Squid gets you covered with a first-class support for runtime upgrades. + +Subsquid SDK comes with a tool called metadata explorer which makes it easy to keep track of all runtime upgrades happen so far. + +The basic usage of the explorer is as follows (check README for details): + +```sh +npx squid-substrate-metadata-explorer \ + --chain <chain endpoint here> \ + --archive <archive endpoint here> \ + --out metadataVersions.json +``` + +Once the exploration is done, you should define all events and calls of interest in `typegen.json`, then adjust the bundle and metadata history references and run: + +```sh +npx squid-substrate-typegen typegen.json +``` + +A type-safe definition for each and every version of the event will be generated. Most of the times, one should be able to infer a normalized interface together with some glue code to make it fit the runtime specific versions. For example, for Kusama `balances.Transfer` event, `squid-substrate-typegen` generated three slightly different versions that can be reconciled as follows: + +```typescript +/** + * Normalized `balances.Transfer` event data + */ +interface TransferEvent { + from: Uint8Array + to: Uint8Array + amount: bigint +} + +function getTransferEvent(ctx: EventHandlerContext): TransferEvent { + // instanciate type-safe facade around event data + let event = new BalancesTransferEvent(ctx) + // initial version, with runtime spec 1020 + if (event.isV1020) { + let [from, to, amount, fee] = event.asV1020 + return {from, to, amount} + // first upgrade at runtime spec version 1050 + } else if (event.isV1050) { + let [from, to, amount] = event.asV1050 + return {from, to, amount} + } else { // current version + // This cast will assert, + // that the type of a given event matches + // the type of generated facade. + return event.asLatest + } +} +``` diff --git a/Makefile b/Makefile index 62754b5b9545768b4d381ac286e097ff0f00d59c..20c00f15883eeee1a204412111c91287a08007b7 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -process: +process: migrate @node -r dotenv/config lib/processor.js @@ -22,15 +22,19 @@ codegen: @npx sqd codegen -typegen: +typegen: duniterVersions.json @npx squid-substrate-typegen typegen.json +duniterVersions.json: + @make explore + + explore: @npx squid-substrate-metadata-explorer \ - --chain wss://kusama-rpc.polkadot.io \ - --archive https://kusama.indexer.gc.subsquid.io/v4/graphql \ - --out kusamaVersions.json + --chain ws://127.0.0.1:9944 \ + --archive http://localhost:4010/v1/graphql \ + --out duniterVersions.json up: diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1cc4f9d48c9deee263133d768d85512949c4b750 --- /dev/null +++ b/README.md @@ -0,0 +1,196 @@ +# squid-template + +Duniter [squid](https://subsquid.io) project. +It accumulates [ğdev] account balances and serves them via graphql API. For more info consult [FAQ](./FAQ.md). + +## Prerequisites + +* node 16.x +* docker + +## Quickly running the sample + +```bash +# 1. Install dependencies +npm ci + +# 2. Compile typescript files +npm run build + +# 3. Start target Postgres database +docker compose up -d + +# 4. Apply database migrations from db/migrations +npx sqd db migrate + +# 5. Now start the processor +node -r dotenv/config lib/processor.js + +# 6. The above command will block the terminal +# being busy with fetching the chain data, +# transforming and storing it in the target database. +# +# To start the graphql server open the separate terminal +# and run +npx squid-graphql-server +``` + +## Dev flow + +### 1. Define database schema + +Start development by defining the schema of the target database via `schema.graphql`. +Schema definition consists of regular graphql type declarations annotated with custom directives. +Full description of `schema.graphql` dialect is available [here](https://docs.subsquid.io/schema-spec). + +### 2. Generate TypeORM classes + +Mapping developers use TypeORM [EntityManager](https://typeorm.io/#/working-with-entity-manager) +to interact with target database during data processing. All necessary entity classes are +generated by the squid framework from `schema.graphql`. This is done by running `npx sqd codegen` +command. + +### 3. Generate database migration + +All database changes are applied through migration files located at `db/migrations`. +`sqd(1)` tool provides several commands to drive the process. +It is all [TypeORM](https://typeorm.io/#/migrations) under the hood. + +```bash +# Connect to database, analyze its state and generate migration to match the target schema. +# The target schema is derived from entity classes generated earlier. +npx sqd db create-migration + +# Create template file for custom database changes +npx sqd db new-migration + +# Apply database migrations from `db/migrations` +npx sqd db migrate + +# Revert the last performed migration +npx sqd db revert + +# DROP DATABASE +npx sqd db drop + +# CREATE DATABASE +npx sqd db create +``` + +### 4. Generate TypeScript definitions for substrate events and calls + +This is an optional part, but it is very advisable. + +Event and call data comes to mapping handlers as a raw untyped json. +Not only it is unclear what the exact structure of a particular event or call is, but +it can also rather frequently change over time. + +Squid framework provides tools for generation of type-safe, spec version aware wrappers around +events and calls. + +The end result looks like this: + +```typescript +/** + * Normalized `balances.Transfer` event data + */ +interface TransferEvent { + from: Uint8Array + to: Uint8Array + amount: bigint +} + +function getTransferEvent(ctx: EventHandlerContext): TransferEvent { + // instanciate type-safe facade around event data + let event = new BalancesTransferEvent(ctx) + if (event.isV1020) { + let [from, to, amount, fee] = event.asV1020 + return {from, to, amount} + } else if (event.isV1050) { + let [from, to, amount] = event.asV1050 + return {from, to, amount} + } else { + // This cast will assert, + // that the type of a given event matches + // the type of generated facade. + return event.asLatest + } +} +``` + +Generation of type-safe wrappers for events and calls is currently a two-step process. + +First, you need to explore the chain to find blocks which introduce new spec version and +fetch corresponding metadata. + +```bash +npx squid-substrate-metadata-explorer \ + --chain ws://127.0.0.1:9944 \ + --archive http://localhost:4010/v1/graphql \ + --out duniterVersions.json +``` + +In the above command `--archive` parameter is optional, but it speeds up the process +significantly. From scratch exploration of duniter network without archive takes 20-30 minutes. + +You can pass the result of previous exploration to `--out` parameter. In that case exploration will +start from the last known block and thus will take much less time. + +After chain exploration is complete you can use `squid-substrate-typegen(1)` to generate +required wrappers. + +```bash +npx squid-substrate-typegen typegen.json +``` + +Where `typegen.json` config file has the following structure: + +```json5 +{ + "outDir": "src/types", + "chainVersions": "duniterVersions.json", // the result of chain exploration + "events": [ // list of events to generate + "balances.Transfer" + ], + "calls": [ // list of calls to generate + "timestamp.set" + ] +} +``` + +## Project conventions + +Squid tools assume a certain project layout. + +* All compiled js files must reside in `lib` and all TypeScript sources in `src`. +The layout of `lib` must reflect `src`. +* All TypeORM classes must be exported by `src/model/index.ts` (`lib/model` module). +* Database schema must be defined in `schema.graphql`. +* Database migrations must reside in `db/migrations` and must be plain js files. +* `sqd(1)` and `squid-*(1)` executables consult `.env` file for a number of environment variables. + +## Differences from polkadot.js + +Polkadot.js provides lots of [specialized classes](https://polkadot.js.org/docs/api/start/types.basics) for various types of data. +Even primitives like `u32` are exposed through special classes. +In contrast, squid framework works only with plain js primitives and objects. +This allows to decrease coupling and also simply dictated by the fact, that +there is not enough information in substrate metadata to distinguish between +interesting cases. + +Account addresses is one example where such difference shows up. +From substrate metadata (and squid framework) point of view account address is simply a fixed length +sequence of bytes. On other hand, polkadot.js creates special wrapper for account addresses which +aware not only of address value, but also of its +[ss58](https://docs.substrate.io/v3/advanced/ss58/) formatting rules. +Mapping developers should handle such cases themselves. + +## Graphql server extensions + +It is possible to extend `squid-graphql-server(1)` with custom +[type-graphql](https://typegraphql.com) resolvers and to add request validation. +More details will be added later. + +## Disclaimer + +This is alpha-quality software. Expect some bugs and incompatible changes in coming weeks. diff --git a/db/init.js b/db/init.js new file mode 100644 index 0000000000000000000000000000000000000000..c3d86c80e1582b399119869fa8dfa8860c04a89e --- /dev/null +++ b/db/init.js @@ -0,0 +1,31 @@ +require('dotenv/config') + +const ormconfig = { + type: 'postgres', + // entities: [require.resolve('../lib/model')], + entities: [], + migrations: [__dirname + '/migrations/*.js'], + synchronize: false, + migrationsRun: false, + dropSchema: false, + logging: ["query", "error", "schema"], + host: process.env.DB_HOST || 'localhost', + port: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 5432, + database: process.env.DB_NAME || 'postgres', + username: process.env.DB_USER || 'postgres', + password: process.env.DB_PASS || 'postgres' +} + +require('typeorm').createConnection(ormconfig).then(async con => { + try { + await con.runMigrations({transaction: 'all'}) + } finally { + await con.close().catch(err => null) + } +}).then( + () => process.exit(), + err => { + console.error(err) + process.exit(1) + } +) diff --git a/db/migrations/1641285739348-Data.js b/db/migrations/1643496058360-Init.js similarity index 93% rename from db/migrations/1641285739348-Data.js rename to db/migrations/1643496058360-Init.js index 14ae51debfedee53e15bded038da40e4a8927d3f..32c574635c848868414f3817a2c8397c5b7aa17f 100644 --- a/db/migrations/1641285739348-Data.js +++ b/db/migrations/1643496058360-Init.js @@ -1,5 +1,5 @@ -module.exports = class Data1641285739348 { - name = 'Data1641285739348' +module.exports = class Init1643496058360 { + name = 'Init1643496058360' async up(db) { await db.query(`CREATE TABLE "historical_balance" ("id" character varying NOT NULL, "balance" numeric NOT NULL, "date" TIMESTAMP WITH TIME ZONE NOT NULL, "account_id" character varying NOT NULL, CONSTRAINT "PK_74ac29ad0bdffb6d1281a1e17e8" PRIMARY KEY ("id"))`) diff --git a/package-lock.json b/package-lock.json index f9169588a2c9576dd043c597a296e94c902fceb9..71ab2557d6e24ca8c96f81566a75cd0ec4a09d09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,22 +1,22 @@ { - "name": "kusama-balances", + "name": "duniter-squid", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "kusama-balances", + "name": "duniter-squid", "dependencies": { - "@subsquid/graphql-server": "^0.0.2", - "@subsquid/substrate-metadata": "^0.0.1", - "@subsquid/substrate-processor": "^0.0.1", + "@subsquid/graphql-server": "^0.1.0", + "@subsquid/ss58": "^0.0.0", + "@subsquid/substrate-processor": "^0.2.1", "dotenv": "^10.0.0", "pg": "^8.7.1", "typeorm": "^0.2.41" }, "devDependencies": { - "@subsquid/cli": "^0.0.2", - "@subsquid/substrate-metadata-explorer": "^0.0.1", - "@subsquid/substrate-typegen": "^0.0.1", + "@subsquid/cli": "^0.0.4", + "@subsquid/substrate-metadata-explorer": "^0.0.4", + "@subsquid/substrate-typegen": "^0.0.4", "@types/node": "^16.11.17", "typescript": "~4.5.4" } @@ -1002,9 +1002,9 @@ "integrity": "sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg==" }, "node_modules/@subsquid/cli": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@subsquid/cli/-/cli-0.0.2.tgz", - "integrity": "sha512-5tMJUKKZLV0SBBo6Td8ZNvN8Kr61zCIDj3Ia3mvgtXJoppai5JTbFMruTjPudXs/G6QPKOTvEmbedPtJX7Mbsw==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@subsquid/cli/-/cli-0.0.4.tgz", + "integrity": "sha512-lWdubqSvmXheWu+ktuRVef1ulWjzmfnUJzPqF5QaRI+alYQ9mSdwh/vETHG58unnqbY68SwBQcpgAhKhmof3yQ==", "dev": true, "dependencies": { "@oclif/core": "^1.0.11", @@ -1035,9 +1035,9 @@ "integrity": "sha512-Wh2Oxi9JkK79Y728yDEeY7JelcY1cGiQTbzVIRMFLT2tjkkoQ69goAGXdh9QmM/ANAVrHQkBUNJOLd5oAg//oQ==" }, "node_modules/@subsquid/graphql-server": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@subsquid/graphql-server/-/graphql-server-0.0.2.tgz", - "integrity": "sha512-8imG+C9CNXAm+8szj+PBAPInYiY3M30lzrHaNkDm/rDyLFpYyIM1d5bOMCHlMnspou56MxCxRejddFZNEEnyfA==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@subsquid/graphql-server/-/graphql-server-0.1.0.tgz", + "integrity": "sha512-4hD0d9mSNqKuWlItF5M9a+t/cc/PTFHZFvieuOlz5Drg8QslaZgd4bsOxUbUCpR2lMCzhZLIE/KEp10tOTnjrw==", "dependencies": { "@graphql-tools/merge": "^8", "@graphql-tools/utils": "^8", @@ -1092,37 +1092,64 @@ } }, "node_modules/@subsquid/rpc-client": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@subsquid/rpc-client/-/rpc-client-0.0.1.tgz", - "integrity": "sha512-ISSB4OpPaE/6vEq7x7DR+6NJwh8E6IUUuJhEpQ9YmRfBEQONnWMGzubxnwwZivnL2o3GrFd/nNQdnScXnfvybA==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@subsquid/rpc-client/-/rpc-client-0.1.0.tgz", + "integrity": "sha512-msAGqkV6GSxcHxYD/tupCPYuz6PgsdAdf19dnhMw8llI7sFstjBIQykHTg4GVPd5Q70QjAZqPlzS4F08NbSEWQ==", "dependencies": { "websocket": "^1.0.34" } }, "node_modules/@subsquid/scale-codec": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@subsquid/scale-codec/-/scale-codec-0.0.1.tgz", - "integrity": "sha512-qfEjP0Ns/nMZiOG7w+wAG0uzJCzUI/7mQ8KyCuTMVnCJgVXsFN6bsmbVfN2vKylbrCjs4txVl13fbpUty+1dcA==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@subsquid/scale-codec/-/scale-codec-0.2.0.tgz", + "integrity": "sha512-0enF7Z/rF8y9TW711yc8T80/amEw6znfoJJQim2KsbWXqqHJbu4eGcyULe9A6ZjH14MxPzeObscNr56KEH+Jyg==", "dependencies": { - "base-x": "^3.0.9" + "@subsquid/ss58-codec": "^0.0.0" + } + }, + "node_modules/@subsquid/scale-codec-json": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@subsquid/scale-codec-json/-/scale-codec-json-0.0.3.tgz", + "integrity": "sha512-zE2F+HlDySSOQsbv4ohNVw5P1+vtIdRxve13PdPGZboaWHMqG5aJYGJ+1ZgKR6bvH1R038ciE8eIHKvOvhc43Q==", + "dependencies": { + "@subsquid/scale-codec": "^0.2.0", + "@subsquid/ss58-codec": "^0.0.0", + "@subsquid/util": "^0.0.1" + } + }, + "node_modules/@subsquid/ss58": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@subsquid/ss58/-/ss58-0.0.0.tgz", + "integrity": "sha512-axrHRsuI8BZnpNi6I3zGqg9rdi67tnf2wKjWTt9IdxZ7RJ6Akd5aQe3mLu0ez7ZaHfUm44BO2NQtSURgkRMeLA==", + "dependencies": { + "@subsquid/ss58-codec": "^0.0.0" + } + }, + "node_modules/@subsquid/ss58-codec": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@subsquid/ss58-codec/-/ss58-codec-0.0.0.tgz", + "integrity": "sha512-VjI0nqefOqSa2ZSxovtLsLJZDSP/jo3rW2fVyWZXGcX5UoPrgd+BNoqRTbg/OfVb1KgK6B3OmLfXXQAFVWKqvw==", + "dependencies": { + "base-x": "^3.0.9", + "blake2b": "^2.1.4" } }, "node_modules/@subsquid/substrate-metadata": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@subsquid/substrate-metadata/-/substrate-metadata-0.0.1.tgz", - "integrity": "sha512-9Pa/7J/ElemAuGvRyYJkht1zIoFQXI4qEdhaZxQk6ZDsUDPpcM05FpnVGFq4jqOMZMLVTDHPQO2CV+9NPUtGTg==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@subsquid/substrate-metadata/-/substrate-metadata-0.1.0.tgz", + "integrity": "sha512-pBYepA2muOAv1nt5ZYZv53W5ZBujOI3tK7EqK2u9tmsObfu/LJxEGGA1NGWULgsOc/cfRlUush5FdE6I29LYsA==", "dependencies": { - "@subsquid/scale-codec": "^0.0.1", + "@subsquid/scale-codec": "^0.2.0", "@subsquid/util": "^0.0.1" } }, "node_modules/@subsquid/substrate-metadata-explorer": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@subsquid/substrate-metadata-explorer/-/substrate-metadata-explorer-0.0.1.tgz", - "integrity": "sha512-DME7CIJSjmPHLTg3JL8JWZtyjFapk7C92s38OW3MmCOCJq2uSfIkI93GVl7HeEw6Gzq1ZmvjWQPWuSUj4jh/vQ==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@subsquid/substrate-metadata-explorer/-/substrate-metadata-explorer-0.0.4.tgz", + "integrity": "sha512-ALoYMwQvtn2KcvG1nKd6I7rZVk/dKLtf3yEJDtCkTBg+XYiHKjBd796P+X6yPQVqx2OeTgWJksS3yoy0+6JC3g==", "dev": true, "dependencies": { - "@subsquid/rpc-client": "^0.0.1", + "@subsquid/rpc-client": "^0.1.0", "commander": "^8.3.0", "node-fetch": "^2.6.6" }, @@ -1131,13 +1158,13 @@ } }, "node_modules/@subsquid/substrate-processor": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@subsquid/substrate-processor/-/substrate-processor-0.0.1.tgz", - "integrity": "sha512-y8xx8N6/uHqIT+aWgM8qoMd4QAxPp91Uoyf7HVx45VWhBvUtCkcUrQdywFyzzdO1NxF032Rse/xqjmOzmGKT9w==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@subsquid/substrate-processor/-/substrate-processor-0.2.1.tgz", + "integrity": "sha512-4+dR5zgDgjvonztaR+zgZ1egcHumtvpbYoDPy6gufcrUAnXF/HmWC3wfBwDssQ/zyE511yUjoe4fzOv5HLp3KQ==", "dependencies": { - "@subsquid/rpc-client": "^0.0.1", - "@subsquid/scale-codec": "^0.0.1", - "@subsquid/substrate-metadata": "^0.0.1", + "@subsquid/rpc-client": "^0.1.0", + "@subsquid/scale-codec-json": "^0.0.3", + "@subsquid/substrate-metadata": "^0.1.0", "@subsquid/typeorm-config": "^0.0.1", "@subsquid/util": "^0.0.1", "node-fetch": "^2.6.6", @@ -1149,12 +1176,12 @@ } }, "node_modules/@subsquid/substrate-typegen": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@subsquid/substrate-typegen/-/substrate-typegen-0.0.1.tgz", - "integrity": "sha512-D0Z+m/PLqBpBzNd7pDDFUgcESdr/qOvdQoyHOc2iZjdm1TVRfXduLl3ZdAweRI2Lzwz6uje/ICM+bAewCbzYDg==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@subsquid/substrate-typegen/-/substrate-typegen-0.0.4.tgz", + "integrity": "sha512-Sx/L5wthC4335RUvmLtCXqfeXAafFa9Bp3cMi66Z01AftVf+SkaiAiEBWwh8tXFsZulFqhTGtQZIImNJwkBFHg==", "dev": true, "dependencies": { - "@subsquid/substrate-metadata": "^0.0.1", + "@subsquid/substrate-metadata": "^0.1.0", "@subsquid/util": "^0.0.1", "ajv": "^8.8.2", "commander": "^8.3.0" @@ -1703,6 +1730,11 @@ "follow-redirects": "^1.14.0" } }, + "node_modules/b4a": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.3.1.tgz", + "integrity": "sha512-ULHjbJGjZcdA5bugDNAAcMA6GWXX/9N10I6AQc14TH+Sr7bMfT+NHuJnOFGPJWLtzYa6Tz+PnFD2D/1bISLLZQ==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1807,6 +1839,24 @@ "node": ">= 6" } }, + "node_modules/blake2b": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.4.tgz", + "integrity": "sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A==", + "dependencies": { + "blake2b-wasm": "^2.4.0", + "nanoassert": "^2.0.0" + } + }, + "node_modules/blake2b-wasm": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz", + "integrity": "sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==", + "dependencies": { + "b4a": "^1.0.1", + "nanoassert": "^2.0.0" + } + }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -5908,6 +5958,11 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nanoassert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz", + "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==" + }, "node_modules/nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -12280,9 +12335,9 @@ "integrity": "sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg==" }, "@subsquid/cli": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@subsquid/cli/-/cli-0.0.2.tgz", - "integrity": "sha512-5tMJUKKZLV0SBBo6Td8ZNvN8Kr61zCIDj3Ia3mvgtXJoppai5JTbFMruTjPudXs/G6QPKOTvEmbedPtJX7Mbsw==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@subsquid/cli/-/cli-0.0.4.tgz", + "integrity": "sha512-lWdubqSvmXheWu+ktuRVef1ulWjzmfnUJzPqF5QaRI+alYQ9mSdwh/vETHG58unnqbY68SwBQcpgAhKhmof3yQ==", "dev": true, "requires": { "@oclif/core": "^1.0.11", @@ -12310,9 +12365,9 @@ "integrity": "sha512-Wh2Oxi9JkK79Y728yDEeY7JelcY1cGiQTbzVIRMFLT2tjkkoQ69goAGXdh9QmM/ANAVrHQkBUNJOLd5oAg//oQ==" }, "@subsquid/graphql-server": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@subsquid/graphql-server/-/graphql-server-0.0.2.tgz", - "integrity": "sha512-8imG+C9CNXAm+8szj+PBAPInYiY3M30lzrHaNkDm/rDyLFpYyIM1d5bOMCHlMnspou56MxCxRejddFZNEEnyfA==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@subsquid/graphql-server/-/graphql-server-0.1.0.tgz", + "integrity": "sha512-4hD0d9mSNqKuWlItF5M9a+t/cc/PTFHZFvieuOlz5Drg8QslaZgd4bsOxUbUCpR2lMCzhZLIE/KEp10tOTnjrw==", "requires": { "@graphql-tools/merge": "^8", "@graphql-tools/utils": "^8", @@ -12345,49 +12400,76 @@ } }, "@subsquid/rpc-client": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@subsquid/rpc-client/-/rpc-client-0.0.1.tgz", - "integrity": "sha512-ISSB4OpPaE/6vEq7x7DR+6NJwh8E6IUUuJhEpQ9YmRfBEQONnWMGzubxnwwZivnL2o3GrFd/nNQdnScXnfvybA==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@subsquid/rpc-client/-/rpc-client-0.1.0.tgz", + "integrity": "sha512-msAGqkV6GSxcHxYD/tupCPYuz6PgsdAdf19dnhMw8llI7sFstjBIQykHTg4GVPd5Q70QjAZqPlzS4F08NbSEWQ==", "requires": { "websocket": "^1.0.34" } }, "@subsquid/scale-codec": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@subsquid/scale-codec/-/scale-codec-0.0.1.tgz", - "integrity": "sha512-qfEjP0Ns/nMZiOG7w+wAG0uzJCzUI/7mQ8KyCuTMVnCJgVXsFN6bsmbVfN2vKylbrCjs4txVl13fbpUty+1dcA==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@subsquid/scale-codec/-/scale-codec-0.2.0.tgz", + "integrity": "sha512-0enF7Z/rF8y9TW711yc8T80/amEw6znfoJJQim2KsbWXqqHJbu4eGcyULe9A6ZjH14MxPzeObscNr56KEH+Jyg==", "requires": { - "base-x": "^3.0.9" + "@subsquid/ss58-codec": "^0.0.0" + } + }, + "@subsquid/scale-codec-json": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@subsquid/scale-codec-json/-/scale-codec-json-0.0.3.tgz", + "integrity": "sha512-zE2F+HlDySSOQsbv4ohNVw5P1+vtIdRxve13PdPGZboaWHMqG5aJYGJ+1ZgKR6bvH1R038ciE8eIHKvOvhc43Q==", + "requires": { + "@subsquid/scale-codec": "^0.2.0", + "@subsquid/ss58-codec": "^0.0.0", + "@subsquid/util": "^0.0.1" + } + }, + "@subsquid/ss58": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@subsquid/ss58/-/ss58-0.0.0.tgz", + "integrity": "sha512-axrHRsuI8BZnpNi6I3zGqg9rdi67tnf2wKjWTt9IdxZ7RJ6Akd5aQe3mLu0ez7ZaHfUm44BO2NQtSURgkRMeLA==", + "requires": { + "@subsquid/ss58-codec": "^0.0.0" + } + }, + "@subsquid/ss58-codec": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/@subsquid/ss58-codec/-/ss58-codec-0.0.0.tgz", + "integrity": "sha512-VjI0nqefOqSa2ZSxovtLsLJZDSP/jo3rW2fVyWZXGcX5UoPrgd+BNoqRTbg/OfVb1KgK6B3OmLfXXQAFVWKqvw==", + "requires": { + "base-x": "^3.0.9", + "blake2b": "^2.1.4" } }, "@subsquid/substrate-metadata": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@subsquid/substrate-metadata/-/substrate-metadata-0.0.1.tgz", - "integrity": "sha512-9Pa/7J/ElemAuGvRyYJkht1zIoFQXI4qEdhaZxQk6ZDsUDPpcM05FpnVGFq4jqOMZMLVTDHPQO2CV+9NPUtGTg==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@subsquid/substrate-metadata/-/substrate-metadata-0.1.0.tgz", + "integrity": "sha512-pBYepA2muOAv1nt5ZYZv53W5ZBujOI3tK7EqK2u9tmsObfu/LJxEGGA1NGWULgsOc/cfRlUush5FdE6I29LYsA==", "requires": { - "@subsquid/scale-codec": "^0.0.1", + "@subsquid/scale-codec": "^0.2.0", "@subsquid/util": "^0.0.1" } }, "@subsquid/substrate-metadata-explorer": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@subsquid/substrate-metadata-explorer/-/substrate-metadata-explorer-0.0.1.tgz", - "integrity": "sha512-DME7CIJSjmPHLTg3JL8JWZtyjFapk7C92s38OW3MmCOCJq2uSfIkI93GVl7HeEw6Gzq1ZmvjWQPWuSUj4jh/vQ==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@subsquid/substrate-metadata-explorer/-/substrate-metadata-explorer-0.0.4.tgz", + "integrity": "sha512-ALoYMwQvtn2KcvG1nKd6I7rZVk/dKLtf3yEJDtCkTBg+XYiHKjBd796P+X6yPQVqx2OeTgWJksS3yoy0+6JC3g==", "dev": true, "requires": { - "@subsquid/rpc-client": "^0.0.1", + "@subsquid/rpc-client": "^0.1.0", "commander": "^8.3.0", "node-fetch": "^2.6.6" } }, "@subsquid/substrate-processor": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@subsquid/substrate-processor/-/substrate-processor-0.0.1.tgz", - "integrity": "sha512-y8xx8N6/uHqIT+aWgM8qoMd4QAxPp91Uoyf7HVx45VWhBvUtCkcUrQdywFyzzdO1NxF032Rse/xqjmOzmGKT9w==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@subsquid/substrate-processor/-/substrate-processor-0.2.1.tgz", + "integrity": "sha512-4+dR5zgDgjvonztaR+zgZ1egcHumtvpbYoDPy6gufcrUAnXF/HmWC3wfBwDssQ/zyE511yUjoe4fzOv5HLp3KQ==", "requires": { - "@subsquid/rpc-client": "^0.0.1", - "@subsquid/scale-codec": "^0.0.1", - "@subsquid/substrate-metadata": "^0.0.1", + "@subsquid/rpc-client": "^0.1.0", + "@subsquid/scale-codec-json": "^0.0.3", + "@subsquid/substrate-metadata": "^0.1.0", "@subsquid/typeorm-config": "^0.0.1", "@subsquid/util": "^0.0.1", "node-fetch": "^2.6.6", @@ -12396,12 +12478,12 @@ } }, "@subsquid/substrate-typegen": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@subsquid/substrate-typegen/-/substrate-typegen-0.0.1.tgz", - "integrity": "sha512-D0Z+m/PLqBpBzNd7pDDFUgcESdr/qOvdQoyHOc2iZjdm1TVRfXduLl3ZdAweRI2Lzwz6uje/ICM+bAewCbzYDg==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@subsquid/substrate-typegen/-/substrate-typegen-0.0.4.tgz", + "integrity": "sha512-Sx/L5wthC4335RUvmLtCXqfeXAafFa9Bp3cMi66Z01AftVf+SkaiAiEBWwh8tXFsZulFqhTGtQZIImNJwkBFHg==", "dev": true, "requires": { - "@subsquid/substrate-metadata": "^0.0.1", + "@subsquid/substrate-metadata": "^0.1.0", "@subsquid/util": "^0.0.1", "ajv": "^8.8.2", "commander": "^8.3.0" @@ -12831,6 +12913,11 @@ "follow-redirects": "^1.14.0" } }, + "b4a": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.3.1.tgz", + "integrity": "sha512-ULHjbJGjZcdA5bugDNAAcMA6GWXX/9N10I6AQc14TH+Sr7bMfT+NHuJnOFGPJWLtzYa6Tz+PnFD2D/1bISLLZQ==" + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -12910,6 +12997,24 @@ } } }, + "blake2b": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.4.tgz", + "integrity": "sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A==", + "requires": { + "blake2b-wasm": "^2.4.0", + "nanoassert": "^2.0.0" + } + }, + "blake2b-wasm": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz", + "integrity": "sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==", + "requires": { + "b4a": "^1.0.1", + "nanoassert": "^2.0.0" + } + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -16118,6 +16223,11 @@ "thenify-all": "^1.0.0" } }, + "nanoassert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz", + "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==" + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", diff --git a/package.json b/package.json index 56eedb0e1e4dba20c953d3dab120499eadf24043..23aa45fc2d9f19658a291a1215ef590b02023ab1 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,27 @@ { - "name": "kusama-balances", + "name": "duniter-squid", "private": true, "scripts": { - "build": "rm -rf lib && tsc" + "build": "rm -rf lib && tsc", + "init": "node db/init.js", + "db:migrate": "sqd db migrate", + "schema:reset": "", + "processor:migrate": "echo skip", + "processor:start": "node lib/processor.js", + "query-node:start": "squid-graphql-server" }, "dependencies": { - "@subsquid/graphql-server": "^0.0.2", - "@subsquid/substrate-metadata": "^0.0.1", - "@subsquid/substrate-processor": "^0.0.1", + "@subsquid/graphql-server": "^0.1.0", + "@subsquid/ss58": "^0.0.0", + "@subsquid/substrate-processor": "^0.2.1", "dotenv": "^10.0.0", "pg": "^8.7.1", "typeorm": "^0.2.41" }, "devDependencies": { - "@subsquid/cli": "^0.0.2", - "@subsquid/substrate-metadata-explorer": "^0.0.1", - "@subsquid/substrate-typegen": "^0.0.1", + "@subsquid/cli": "^0.0.4", + "@subsquid/substrate-metadata-explorer": "^0.0.4", + "@subsquid/substrate-typegen": "^0.0.4", "@types/node": "^16.11.17", "typescript": "~4.5.4" } diff --git a/reset-db.sh b/reset-db.sh new file mode 100755 index 0000000000000000000000000000000000000000..f0db908645fafc3e011dcb26cc2322b896a7e561 --- /dev/null +++ b/reset-db.sh @@ -0,0 +1,8 @@ +set -e +npx sqd codegen +npm run build +rm -rf db/migrations/*.js +npx sqd db drop +npx sqd db create +npx sqd db create-migration Init +npx sqd db migrate \ No newline at end of file diff --git a/reset-schema.sh b/reset-schema.sh new file mode 100644 index 0000000000000000000000000000000000000000..f34fcabeed4e4ffbe1c4a33b450322a54c708065 --- /dev/null +++ b/reset-schema.sh @@ -0,0 +1,4 @@ +set -e +npx sqd codegen +npm run build +./reset-db.sh \ No newline at end of file diff --git a/src/processor.ts b/src/processor.ts index 4ff3cadf16ec3342b009cd5de96eea8092048249..cafac9444ed7f471b4a9d33668dc54774e86f2f9 100644 --- a/src/processor.ts +++ b/src/processor.ts @@ -1,32 +1,50 @@ +import * as ss58 from "@subsquid/ss58" import {EventHandlerContext, Store, SubstrateProcessor} from "@subsquid/substrate-processor" import {Account, HistoricalBalance} from "./model" -import {BalancesTransferEvent} from "./types/events" +import {BalancesDepositEvent, BalancesTransferEvent} from "./types/events" -const processor = new SubstrateProcessor('kusama_balances') +const processor = new SubstrateProcessor('duniter-squid') -processor.setTypesBundle('kusama') processor.setBatchSize(500) processor.setDataSource({ - archive: 'https://kusama.indexer.gc.subsquid.io/v4/graphql', - chain: 'wss://kusama-rpc.polkadot.io' + archive: 'http://localhost:4010/v1/graphql', + chain: 'ws://127.0.0.1:9944' }) +processor.addEventHandler('balances.Deposit', async ctx => { + let deposit = getDepositEvent(ctx) + let who = ss58.codec(42).encode(deposit.who) + + let whoAcc = await getOrCreate(ctx.store, Account, who) + whoAcc.balance = whoAcc.balance || 0n + whoAcc.balance += deposit.amount + await ctx.store.save(whoAcc) + + await ctx.store.save(new HistoricalBalance({ + id: ctx.event.id + '-who', + account: whoAcc, + balance: whoAcc.balance, + date: new Date(ctx.block.timestamp) + })) +}) processor.addEventHandler('balances.Transfer', async ctx => { let transfer = getTransferEvent(ctx) let tip = ctx.extrinsic?.tip || 0n + let from = ss58.codec(42).encode(transfer.from) + let to = ss58.codec(42).encode(transfer.to) - let fromAcc = await getOrCreate(ctx.store, Account, toHex(transfer.from)) + let fromAcc = await getOrCreate(ctx.store, Account, from) fromAcc.balance = fromAcc.balance || 0n fromAcc.balance -= transfer.amount fromAcc.balance -= tip await ctx.store.save(fromAcc) - const toAcc = await getOrCreate(ctx.store, Account, toHex(transfer.to)) + const toAcc = await getOrCreate(ctx.store, Account, to) toAcc.balance = toAcc.balance || 0n toAcc.balance += transfer.amount await ctx.store.save(toAcc) @@ -49,6 +67,10 @@ processor.addEventHandler('balances.Transfer', async ctx => { processor.run() +interface DepositEvent { + who: Uint8Array + amount: bigint +} interface TransferEvent { from: Uint8Array @@ -56,23 +78,14 @@ interface TransferEvent { amount: bigint } +function getDepositEvent(ctx: EventHandlerContext): DepositEvent { + let event = new BalancesDepositEvent(ctx) + return event.asLatest +} function getTransferEvent(ctx: EventHandlerContext): TransferEvent { let event = new BalancesTransferEvent(ctx) - if (event.isV1020) { - let [from, to, amount] = event.asV1020 - return {from, to, amount} - } else if (event.isV1050) { - let [from, to, amount] = event.asV1050 - return {from, to, amount} - } else { - return event.asLatest - } -} - - -function toHex(data: Uint8Array): string { - return '0x' + Buffer.from(data).toString('hex') + return event.asLatest } diff --git a/src/types/events.ts b/src/types/events.ts index fc92704938313c0bb385a7c9407a24c7a7592868..d997a5b52b5ac9b324c1d52f0fe623ec55fd8e8c 100644 --- a/src/types/events.ts +++ b/src/types/events.ts @@ -1,55 +1,44 @@ import assert from 'assert' import {EventContext, Result} from './support' -import * as v9130 from './v9130' +import * as v100 from './v100' -export class BalancesTransferEvent { +export class BalancesDepositEvent { constructor(private ctx: EventContext) { - assert(this.ctx.event.name === 'balances.Transfer') + assert(this.ctx.event.name === 'balances.Deposit') } /** - * Transfer succeeded (from, to, value, fees). + * Some amount was deposited (e.g. for transaction fees). */ - get isV1020(): boolean { - let h = this.ctx.block.height - return h <= 1375086 + get isLatest(): boolean { + return this.ctx._chain.getEventHash('balances.Deposit') === '830a4a3779cfac8257383d9466fe630842d310aebadd8dcab7ccd67ee0a90207' } /** - * Transfer succeeded (from, to, value, fees). + * Some amount was deposited (e.g. for transaction fees). */ - get asV1020(): [Uint8Array, Uint8Array, bigint, bigint] { - assert(this.isV1020) + get asLatest(): {who: v100.AccountId32, amount: bigint} { + assert(this.isLatest) return this.ctx._chain.decodeEvent(this.ctx.event) } +} - /** - * Transfer succeeded (from, to, value). - */ - get isV1050(): boolean { - let h = this.ctx.block.height - return 1375086 < h && h <= 10403784 - } - - /** - * Transfer succeeded (from, to, value). - */ - get asV1050(): [Uint8Array, Uint8Array, bigint] { - assert(this.isV1050) - return this.ctx._chain.decodeEvent(this.ctx.event) +export class BalancesTransferEvent { + constructor(private ctx: EventContext) { + assert(this.ctx.event.name === 'balances.Transfer') } /** * Transfer succeeded. */ get isLatest(): boolean { - return this.ctx.block.height > 10403784 && this.ctx._chain.getEventHash('balances.Transfer') === '68dcb27fbf3d9279c1115ef6dd9d30a3852b23d8e91c1881acd12563a212512d' + return this.ctx._chain.getEventHash('balances.Transfer') === 'b99648076a88060fad61c93afcdcd9152c5e6093a329175feb02c7eccf1bc44f' } /** * Transfer succeeded. */ - get asLatest(): {from: v9130.AccountId32, to: v9130.AccountId32, amount: bigint} { + get asLatest(): {from: v100.AccountId32, to: v100.AccountId32, amount: bigint} { assert(this.isLatest) return this.ctx._chain.decodeEvent(this.ctx.event) } diff --git a/src/types/v9130.ts b/src/types/v100.ts similarity index 100% rename from src/types/v9130.ts rename to src/types/v100.ts diff --git a/typegen.json b/typegen.json index 0a11acc005ab4b104fa95251f75320411cd23e2b..547e790613eef65158f6438f89f8eae8df0c02a7 100644 --- a/typegen.json +++ b/typegen.json @@ -1,8 +1,8 @@ { "outDir": "src/types", - "chainVersions": "kusamaVersions.json", - "typesBundle": "kusama", + "chainVersions": "duniterVersions.json", "events": [ + "balances.Deposit", "balances.Transfer" ], "calls": []