├── .github └── workflows │ └── build-schema.yml ├── .gitignore ├── Dockerfile ├── README.md ├── docker-compose.yml ├── docker ├── load-extensions.sh └── pg-Dockerfile ├── package.json ├── project.yaml ├── schema.graphql ├── src ├── chaintypes.ts ├── handlers │ └── allocation.ts ├── helpers │ ├── extrinsic.ts │ ├── index.ts │ └── verifyUnique.ts ├── index.ts └── mappings │ ├── mappingAllocationHandler.ts │ ├── mappingBalancesHandlers.ts │ └── mappingUniquesHandlers.ts ├── tsconfig.json └── yarn.lock /.github/workflows/build-schema.yml: -------------------------------------------------------------------------------- 1 | name: Check PR 2 | on: 3 | pull_request: 4 | paths-ignore: 5 | - ".github/workflows/**" 6 | jobs: 7 | pr: 8 | name: Codegen & Build 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Setup Node.js environment 13 | uses: actions/setup-node@v2 14 | with: 15 | node-version: 18 16 | - run: yarn 17 | - name: Codegen 18 | run: yarn codegen 19 | - name: Build 20 | run: yarn build 21 | # - name: Install subql-node 22 | # run: yarn global add @subql/node 23 | # - name: Run tests with Subquery Node 24 | # run: subql-node test -f ${{ github.workspace }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.data 4 | 5 | dist/ 6 | src/types 7 | 8 | .project-cid -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM onfinality/subql-node:latest 2 | 3 | COPY ./ /app 4 | 5 | RUN apk add --no-cache python3 py3-pip make g++\ 6 | && rm -rf /var/cache/apk/* 7 | RUN cd app\ 8 | && yarn install\ 9 | && yarn codegen && yarn build 10 | 11 | CMD ["-f=/app", "--db-schema=app", "--log-level=info", "--disable-historical=false", "--workers=5", "--batch-size=50"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # subquery-nodle 2 | https://github.com/stayforward09/graphql-subquery 3 | ## How to use query on Subquery server. 4 | Subquery is a [gaphql](https://graphql.org) based API server. As it's the case with graphql you can either use HTTP to deliver your queries to the server using either of the two GET or POST methods explained [here](https://graphql.org/learn/serving-over-http/), or depending on the language of your client applications you use [a graphql library](https://graphql.org/code) and query the server in a way that's more idiomatic in your own coding language. The direct HTTP requests could be useful for the tests created in Postman or Insomnia, while the latter approach could be preferred inside your applications. Below you see the list of the queries that this project is supporting at the moment: 5 | 6 | ### Query transaction history 7 | ``` 8 | query TransactionHistoryByAddress ($address: String!){ 9 | systemTokenTransfers (filter: { 10 | or: [ 11 | { 12 | fromId: { 13 | equalTo: $address 14 | } 15 | }, 16 | { 17 | toId: { 18 | equalTo: $address 19 | } 20 | } 21 | ] 22 | }) { 23 | nodes { 24 | id 25 | fromId 26 | toId 27 | amount 28 | extrinsicId 29 | timestamp 30 | } 31 | } 32 | } 33 | ``` 34 | ### Query vesting schedules for an address 35 | ``` 36 | query VestingSchedulesByAddress($address: String!){ 37 | vestingSchedules (filter: { 38 | signer: { 39 | equalTo: $address 40 | } 41 | }) { 42 | nodes { 43 | id 44 | signer 45 | to 46 | data 47 | } 48 | } 49 | } 50 | ``` 51 | 52 | ### How to get transfer lists by specific address & timestamp 53 | 54 | ```graphql 55 | query transfersByFields($from: String! $to: String!) { 56 | systemTokenTransfers(filter: { 57 | and: [ 58 | { 59 | fromId: { 60 | equalTo: $from 61 | } 62 | } 63 | { 64 | toId: { 65 | equalTo: $to 66 | } 67 | } 68 | ] 69 | }) { 70 | nodes { 71 | id 72 | fromId 73 | toId 74 | timestamp 75 | } 76 | } 77 | } 78 | ``` 79 | 80 | ```graphql 81 | query transfersByFields($from: String! $to: String! $start: Date! $end: Date!) { 82 | systemTokenTransfers(filter: { 83 | and: [ 84 | { 85 | fromId: { 86 | equalTo: $from 87 | } 88 | } 89 | { 90 | toId: { 91 | equalTo: $to 92 | } 93 | } 94 | { 95 | timestamp: { 96 | greaterThanOrEqualTo: $start 97 | } 98 | } 99 | { 100 | timestamp: { 101 | lessThanOrEqualTo: $end 102 | } 103 | } 104 | ] 105 | }) { 106 | nodes { 107 | id 108 | fromId 109 | toId 110 | timestamp 111 | } 112 | } 113 | } 114 | ``` -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | postgres: 5 | build: 6 | context: . 7 | dockerfile: ./docker/pg-Dockerfile 8 | ports: 9 | - 5432:5432 10 | volumes: 11 | - .data/postgres:/var/lib/postgresql/data 12 | environment: 13 | POSTGRES_PASSWORD: postgres 14 | healthcheck: 15 | test: ["CMD-SHELL", "pg_isready -U postgres"] 16 | interval: 5s 17 | timeout: 5s 18 | retries: 5 19 | 20 | subquery-node: 21 | image: onfinality/subql-node:v1.13.3 22 | depends_on: 23 | "postgres": 24 | condition: service_healthy 25 | restart: always 26 | environment: 27 | DB_USER: postgres 28 | DB_PASS: postgres 29 | DB_DATABASE: postgres 30 | DB_HOST: postgres 31 | DB_PORT: 5432 32 | volumes: 33 | - ./:/app 34 | command: 35 | - -f=/app 36 | - --db-schema=app 37 | - --log-level=debug 38 | - --disable-historical=false 39 | healthcheck: 40 | test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"] 41 | interval: 3s 42 | timeout: 5s 43 | retries: 10 44 | 45 | graphql-engine: 46 | image: onfinality/subql-query:latest 47 | ports: 48 | - 3000:3000 49 | depends_on: 50 | "postgres": 51 | condition: service_healthy 52 | "subquery-node": 53 | condition: service_healthy 54 | restart: always 55 | environment: 56 | DB_USER: postgres 57 | DB_PASS: postgres 58 | DB_DATABASE: postgres 59 | DB_HOST: postgres 60 | DB_PORT: 5432 61 | command: 62 | - --name=app 63 | - --playground 64 | - --indexer=http://subquery-node:3000 65 | -------------------------------------------------------------------------------- /docker/load-extensions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <', 18 | challenger_deposit: 'Option', 19 | created_block: 'BlockNumber', 20 | metadata: 'Vec', 21 | voters_against: 'Vec<(AccountId, Balance)>', 22 | voters_for: 'Vec<(AccountId, Balance)>', 23 | votes_against: 'Option', 24 | votes_for: 'Option' 25 | }, 26 | CertificateId: 'AccountId', 27 | RootCertificate: { 28 | child_revocations: 'Vec', 29 | created: 'BlockNumber', 30 | key: 'CertificateId', 31 | owner: 'AccountId', 32 | renewed: 'BlockNumber', 33 | revoked: 'bool', 34 | validity: 'BlockNumber' 35 | }, 36 | VestingSchedule: { 37 | start: 'BlockNumber', 38 | period: 'BlockNumber', 39 | period_count: 'u32', 40 | per_period: 'Balance' 41 | }, 42 | VestingScheduleOf: 'VestingSchedule' 43 | } 44 | } 45 | ] 46 | }; 47 | 48 | export default { typesBundle: {spec: {"nodle-parachain": definitions}}}; 49 | -------------------------------------------------------------------------------- /src/handlers/allocation.ts: -------------------------------------------------------------------------------- 1 | import { SubstrateExtrinsic } from '@subql/types' 2 | import { AllocationEvent } from '../types' 3 | import { Allocations } from '../types/models' 4 | 5 | export class AllocationHandler { 6 | private extrinsic: SubstrateExtrinsic 7 | 8 | constructor(extrinsic: SubstrateExtrinsic) { 9 | this.extrinsic = extrinsic 10 | } 11 | 12 | get blockNumber () { 13 | return this.extrinsic.block.block.header.number.toNumber() 14 | } 15 | 16 | get idx () { 17 | return this.extrinsic.idx 18 | } 19 | 20 | get hash () { 21 | return this.extrinsic.extrinsic.hash.toString() 22 | } 23 | 24 | get data () { 25 | return this.extrinsic.events.map((event) => event.event.toHuman()) 26 | } 27 | 28 | public async save () { 29 | logger.info(`AllocationHandler event 0' data: ${JSON.stringify(this.data[0])}`) 30 | const allocation = new Allocations(`${this.blockNumber}-${this.idx}`) 31 | 32 | allocation.data = this.data as AllocationEvent[] 33 | allocation.txHash = this.hash 34 | allocation.block = this.blockNumber 35 | allocation.success = this.extrinsic.success 36 | 37 | await allocation.save() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/helpers/extrinsic.ts: -------------------------------------------------------------------------------- 1 | import { SubstrateExtrinsic } from '@subql/types'; 2 | 3 | export const checkIfExtrinsicExecuteSuccess = (extrinsic: SubstrateExtrinsic): boolean => { 4 | const { events } = extrinsic 5 | 6 | return !events.find((item) => { 7 | const { event: { method, section }} = item 8 | 9 | return method === 'ExtrinsicFailed' && section === 'system' 10 | }) 11 | } -------------------------------------------------------------------------------- /src/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './extrinsic' -------------------------------------------------------------------------------- /src/helpers/verifyUnique.ts: -------------------------------------------------------------------------------- 1 | import { Collection, Item } from "../types"; 2 | import { Codec } from '@polkadot/types/types'; 3 | 4 | type EnsureCollection = { 5 | idx: number; 6 | blockNumber: number; 7 | collectionId: Codec; 8 | timestamp: Date; 9 | } 10 | 11 | type EnsureItem = EnsureCollection & { 12 | itemId: Codec; 13 | collectionFkey: string; 14 | } 15 | 16 | export const ensureCollection = async ({ 17 | collectionId, blockNumber, idx, timestamp 18 | }: EnsureCollection) => { 19 | const collectionIdString = collectionId.toString(); 20 | const collections = await Collection.getByCollectionId(collectionIdString); 21 | let collection = collections.find((c) => !c.isDestroyed); 22 | if (!collection) { 23 | const id = `${collectionIdString}-${blockNumber}-${idx}`; 24 | logger.warn('Collection not found, creating new collection', collectionIdString); 25 | collection = new Collection(id, collectionIdString, '', '', '', false); 26 | collection.createdAt = new Date( 27 | timestamp 28 | ).getTime(); 29 | } 30 | collection.createdAt = new Date( 31 | timestamp 32 | ).getTime(); 33 | return collection; 34 | } 35 | 36 | export const ensureItem = async ({ 37 | collectionId, itemId, blockNumber, idx, collectionFkey, timestamp 38 | }: EnsureItem) => { 39 | const itemIdString = itemId.toString(); 40 | const items = await Item.getByCollectionItemKey(`${collectionId}-${itemIdString}`); 41 | let item = items.find((c) => !c.isBurned); 42 | if (!item) { 43 | const id = `${collectionId}-${itemIdString}-${blockNumber}-${idx}`; 44 | logger.warn('Item not found, creating new item', itemIdString); 45 | item = new Item(id, itemIdString, `${collectionId}-${itemIdString}`, collectionFkey, false); 46 | item.createdAt = new Date( 47 | timestamp 48 | ).getTime(); 49 | } 50 | item.updatedAt = new Date( 51 | timestamp 52 | ).getTime(); 53 | return item; 54 | } -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import '@polkadot/types-augment'; 2 | import "@polkadot/api-augment"; 3 | 4 | export * from './mappings/mappingAllocationHandler' 5 | export * from './mappings/mappingUniquesHandlers' 6 | export * from './mappings/mappingBalancesHandlers' 7 | -------------------------------------------------------------------------------- /src/mappings/mappingAllocationHandler.ts: -------------------------------------------------------------------------------- 1 | import { SubstrateExtrinsic } from '@subql/types' 2 | import { AllocationHandler } from '../handlers/allocation' 3 | 4 | export async function handleAllocationBatchCall(extrinsic: SubstrateExtrinsic) { 5 | const handler = new AllocationHandler(extrinsic) 6 | 7 | return handler.save(); 8 | } -------------------------------------------------------------------------------- /src/mappings/mappingBalancesHandlers.ts: -------------------------------------------------------------------------------- 1 | import { SubstrateEvent } from "@subql/types"; 2 | import { Balance } from '@polkadot/types/interfaces/runtime'; 3 | import { checkIfExtrinsicExecuteSuccess } from "../helpers"; 4 | import { BalanceTransfer } from "../types/models"; 5 | 6 | export async function handleBalancesTransferEvent(event: SubstrateEvent) { 7 | const from = event.event.data[0]; 8 | const to = event.event.data[1]; 9 | if(!from || !to) { 10 | logger.error('Some of the from or to address is null', JSON.stringify(event.toHuman())); 11 | return; 12 | } 13 | 14 | const amount = event.event.data[2]; 15 | let record = new BalanceTransfer(`${event.block.block.header.number.toNumber()}-${event.idx}`, '', ''); 16 | record.blockNumber = event.block.block.header.number.toBigInt(); 17 | record.from = from.toString(); 18 | record.to = to.toString(); 19 | record.amount = (amount as Balance).toBigInt(); 20 | if (event.extrinsic) { 21 | record.txHash = event.extrinsic.extrinsic.hash.toString(); 22 | record.timestamp = new Date(event.extrinsic.block.timestamp).getTime(); 23 | record.success = checkIfExtrinsicExecuteSuccess(event.extrinsic) 24 | } 25 | 26 | return record.save(); 27 | } 28 | -------------------------------------------------------------------------------- /src/mappings/mappingUniquesHandlers.ts: -------------------------------------------------------------------------------- 1 | import { Item } from './../types/models/Item'; 2 | import { Balance } from '@polkadot/types/interfaces/runtime'; 3 | import { ensureCollection, ensureItem } from './../helpers/verifyUnique'; 4 | import { SubstrateEvent } from "@subql/types"; 5 | import { UniquesTransfer } from "../types/models"; 6 | 7 | export async function handleUniquesTransferEvent( 8 | event: SubstrateEvent 9 | ) { 10 | logger.debug("uniqueTransferEvent added: " + JSON.stringify(event.toHuman())); 11 | const from = event.event.data[2]; 12 | const to = event.event.data[3]; 13 | const collectionId = event.event.data[0]; 14 | const itemId = event.event.data[1]; 15 | const blockNumber = event.block.block.header.number.toNumber(); 16 | const id = `${blockNumber}-${event.idx}` 17 | 18 | if (!from || !to || !collectionId || !itemId) { 19 | logger.error( 20 | "Some arguments is null", 21 | JSON.stringify(event.toHuman()) 22 | ); 23 | return; 24 | } 25 | 26 | const uniqueTransfer = new UniquesTransfer(id, '', ''); 27 | 28 | uniqueTransfer.block = blockNumber; 29 | uniqueTransfer.from = from.toString(); 30 | uniqueTransfer.to = to.toString(); 31 | if (event.extrinsic) { 32 | event.extrinsic.events.forEach((eventItem) => { 33 | if (eventItem.event.method === "Withdraw") { 34 | const fee = eventItem.event.data[1]; 35 | uniqueTransfer.fee = (fee as Balance).toBigInt(); 36 | } 37 | }); 38 | uniqueTransfer.txHash = event.extrinsic.extrinsic.hash.toString(); 39 | uniqueTransfer.timestamp = new Date( 40 | event.extrinsic.block.timestamp 41 | ).getTime(); 42 | } 43 | 44 | const collection = await ensureCollection({ 45 | collectionId, 46 | blockNumber, 47 | idx: event.idx, 48 | timestamp: event.extrinsic.block.timestamp, 49 | }); 50 | 51 | const item = await ensureItem({ 52 | collectionId, 53 | collectionFkey: collection.id, 54 | itemId, 55 | blockNumber, 56 | idx: event.idx, 57 | timestamp: event.extrinsic.block.timestamp, 58 | }); 59 | item.owner = to.toString(); 60 | uniqueTransfer.itemId = item.id; 61 | uniqueTransfer.collectionId = collection.id; 62 | 63 | await collection.save(); 64 | await item.save() 65 | return uniqueTransfer.save(); 66 | } 67 | 68 | export const handleUniquesMetadataSetEvent = async ( 69 | event: SubstrateEvent 70 | ) => { 71 | logger.debug("uniqueMetadataSetEvent added: " + JSON.stringify(event.toHuman())); 72 | const collectionId = event.event.data[0]; 73 | const itemId = event.event.data[1]; 74 | const data = event.event.data[2]; 75 | const blockNumber = event.block.block.header.number.toNumber(); 76 | 77 | //small check 78 | let items = await Item.getByCollectionItemKey(`${collectionId.toString()}-${itemId.toString()}`); 79 | 80 | if (items.length <= 0) { 81 | logger.error( 82 | "Item not found while handling uniqueMetadataSetEvent", 83 | JSON.stringify(event.toHuman()) 84 | ); 85 | return; 86 | } 87 | const item = await ensureItem({ 88 | collectionId, 89 | collectionFkey: items[0].collectionId, 90 | itemId, 91 | blockNumber, 92 | idx: event.idx, 93 | timestamp: event.extrinsic.block.timestamp, 94 | }); 95 | item.metadataCid = data.toHuman().toString(); 96 | return item.save(); 97 | } 98 | 99 | export const handleUniquesCollectionMetadataSetEvent = async ( 100 | event: SubstrateEvent 101 | ) => { 102 | logger.debug( 103 | "uniqueCollectionMetadataSetEvent added: " + JSON.stringify(event.toHuman()) 104 | ); 105 | const collectionId = event.event.data[0]; 106 | const data = event.event.data[1]; 107 | const blockNumber = event.block.block.header.number.toNumber(); 108 | 109 | const collection = await ensureCollection({ 110 | collectionId, 111 | blockNumber, 112 | idx: event.idx, 113 | timestamp: event.extrinsic.block.timestamp 114 | }); 115 | collection.metadataCid = data.toHuman().toString(); 116 | 117 | return collection.save(); 118 | } 119 | 120 | export const handleUniquesDestroyedEvent = async ( 121 | event: SubstrateEvent 122 | ) => { 123 | logger.debug( 124 | "handleUniquesDestroyedEvent added: " + JSON.stringify(event.toHuman()) 125 | ); 126 | const collectionId = event.event.data[0]; 127 | const blockNumber = event.block.block.header.number.toNumber(); 128 | 129 | const collection = await ensureCollection({ 130 | collectionId, 131 | blockNumber, 132 | idx: event.idx, 133 | timestamp: event.extrinsic.block.timestamp 134 | }); 135 | collection.isDestroyed = true; 136 | return collection.save() 137 | } 138 | 139 | export const handleUniquesBurnedEvent = async ( 140 | event: SubstrateEvent 141 | ) => { 142 | logger.debug( 143 | "handleUniquesBurnedEvent added: " + JSON.stringify(event.toHuman()) 144 | ); 145 | const itemId = event.event.data[1]; 146 | const collectionId = event.event.data[0]; 147 | const blockNumber = event.block.block.header.number.toNumber(); 148 | 149 | const collection = await ensureCollection({ 150 | collectionId, 151 | blockNumber, 152 | idx: event.idx, 153 | timestamp: event.extrinsic.block.timestamp, 154 | }); 155 | 156 | const item = await ensureItem({ 157 | collectionId, 158 | collectionFkey: collection.id, 159 | itemId, 160 | blockNumber, 161 | idx: event.idx, 162 | timestamp: event.extrinsic.block.timestamp 163 | }); 164 | 165 | item.isBurned = true; 166 | return item.save(); 167 | } 168 | 169 | export const handleUniquesIssuedEvent = async ( 170 | event: SubstrateEvent 171 | ) => { 172 | logger.debug( 173 | "handleUniquesIssuedEvent added: " + JSON.stringify(event.toHuman()) 174 | ); 175 | const collectionId = event.event.data[0]; 176 | const itemId = event.event.data[1]; 177 | const owner = event.event.data[2]; 178 | const blockNumber = event.block.block.header.number.toNumber(); 179 | 180 | const collection = await ensureCollection({ 181 | collectionId, 182 | blockNumber, 183 | idx: event.idx, 184 | timestamp: event.extrinsic.block.timestamp 185 | }); 186 | const item = await ensureItem({ 187 | collectionId, 188 | collectionFkey: collection.id, 189 | itemId, 190 | blockNumber, 191 | idx: event.idx, 192 | timestamp: event.extrinsic.block.timestamp 193 | }); 194 | 195 | item.owner = owner.toString(); 196 | item.collectionId = collection.id; 197 | 198 | await collection.save() 199 | return item.save(); 200 | } 201 | 202 | export const handleUniquesCreatedEvent = async ( 203 | event: SubstrateEvent 204 | ) => { 205 | logger.debug( 206 | "handleUniquesCreatedEvent added: " + JSON.stringify(event.toHuman()) 207 | ); 208 | const collectionId = event.event.data[0]; 209 | const creator = event.event.data[1]; 210 | const owner = event.event.data[2]; 211 | const blockNumber = event.block.block.header.number.toNumber(); 212 | 213 | const collection = await ensureCollection({ 214 | collectionId, 215 | blockNumber, 216 | idx: event.idx, 217 | timestamp: event.extrinsic.block.timestamp 218 | }); 219 | 220 | collection.issuer = creator.toString(); 221 | collection.owner = owner.toString(); 222 | collection.admin = creator.toString(); 223 | 224 | return collection.save() 225 | } 226 | 227 | export const handleUniquesOwnershipAcceptanceChangedEvent = async ( 228 | event: SubstrateEvent 229 | ) => { 230 | logger.debug( 231 | "handleUniquesOwnershipAcceptanceChangedEvent added: " + JSON.stringify(event.toHuman()) 232 | ); 233 | const who = event.event.data[0]; 234 | const collectionId = event.event.data[1]; 235 | const blockNumber = event.block.block.header.number.toNumber(); 236 | 237 | if(!collectionId?.toString()) { 238 | return 239 | } 240 | 241 | const collection = await ensureCollection({ 242 | collectionId, 243 | blockNumber, 244 | idx: event.idx, 245 | timestamp: event.extrinsic.block.timestamp 246 | }); 247 | 248 | collection.owner = who.toString(); 249 | 250 | return collection.save() 251 | } 252 | 253 | export const handleUniquesTeamChangedEvent = async ( 254 | event: SubstrateEvent 255 | ) => { 256 | logger.debug( 257 | "handleUniquesTeamChangedEvent added: " + JSON.stringify(event.toHuman()) 258 | ); 259 | const collectionId = event.event.data[0]; 260 | const issuer = event.event.data[1]; 261 | const admin = event.event.data[2]; 262 | const freezer = event.event.data[3]; 263 | const blockNumber = event.block.block.header.number.toNumber(); 264 | 265 | const collection = await ensureCollection({ 266 | collectionId, 267 | blockNumber, 268 | idx: event.idx, 269 | timestamp: event.extrinsic.block.timestamp 270 | }); 271 | 272 | collection.issuer = issuer.toString(); 273 | collection.admin = admin.toString(); 274 | collection.freezer = freezer.toString(); 275 | 276 | return collection.save() 277 | } 278 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "emitDecoratorMetadata": true, 4 | "experimentalDecorators": true, 5 | "esModuleInterop": true, 6 | "declaration": true, 7 | "importHelpers": true, 8 | "resolveJsonModule": true, 9 | "module": "commonjs", 10 | "outDir": "dist", 11 | "rootDir": "src", 12 | "target": "es2017" 13 | }, 14 | "include": [ 15 | "src/**/*", 16 | "node_modules/@subql/types/dist/global.d.ts" 17 | ] 18 | } 19 | --------------------------------------------------------------------------------