diff --git a/packages/erc721-watcher/demo.md b/packages/erc721-watcher/demo.md index 335b08807..709343462 100644 --- a/packages/erc721-watcher/demo.md +++ b/packages/erc721-watcher/demo.md @@ -161,7 +161,7 @@ * Custom property `transferCount` should be 1 initially. -* Run the getState query at the endpoint to get the latest IPLDBlock for NFT_ADDRESS: +* Run the `getState` query at the endpoint to get the latest IPLDBlock for NFT_ADDRESS: ```graphql query { @@ -190,7 +190,25 @@ * `data` contains the default state and also the custom state property `transferCount` that is indexed in [hooks.ts](./src/hooks.ts) file. -* Get the latest blockHash and run the following query for `balanceOf` and `ownerOf` (`eth_call`): +* Get the latest blockHash and run the following query for `transferCount` entity: + + ```graphql + query { + transferCount( + block: { + hash: "LATEST_BLOCK_HASH" + } + id: "NFT_ADDRESS" + ) { + id + count + } + } + ``` + + *Note: Contract address is assigned to the Entity ID.* + +* With the latest blockHash, run the following query for `balanceOf` and `ownerOf` (`eth_call`): ```graphql query { @@ -239,11 +257,13 @@ * An auto-generated `diff_staged` IPLDBlock should be added with parent CID pointing to the previous IPLDBlock. - * Custom property `transferCount` should be incremented after transfer. This can be checked in the getState query and in IPFS webUI mentioned in the later steps. + * Custom property `transferCount` should be incremented after transfer. This can be checked in the `getState` query and in IPFS webUI mentioned in the later steps. + +* Get the latest blockHash and replace the blockHash in the above `eth_call` query. The result should be different and the token should be transferred to the recipient. -* Get the latest blockHash and replace the blockHash in the above query. The result should be different and the token should be transferred to the recipient. +* Run the `getState` query again at the endpoint with the event blockHash. -* Run the getState query again at the endpoint with the event blockHash. +* Run the `transferCount` entity query again with the latest blockHash. The updated count should be returned. * After the `diff` block has been created (can check if event block number pruned in yarn server log), create a checkpoint using CLI in `packages/erc721-watcher`: @@ -251,7 +271,7 @@ yarn checkpoint --address $NFT_ADDRESS ``` - * Run the getState query again with the output blockHash and kind checkpoint at the endpoint. + * Run the `getState` query again with the output blockHash and kind checkpoint at the endpoint. * The latest checkpoint should have the aggregate of state diffs since the last checkpoint. diff --git a/packages/erc721-watcher/src/database.ts b/packages/erc721-watcher/src/database.ts index b63511271..463f5b324 100644 --- a/packages/erc721-watcher/src/database.ts +++ b/packages/erc721-watcher/src/database.ts @@ -3,7 +3,7 @@ // import assert from 'assert'; -import { Connection, ConnectionOptions, DeepPartial, FindConditions, QueryRunner, FindManyOptions, FindOneOptions } from 'typeorm'; +import { Connection, ConnectionOptions, DeepPartial, FindConditions, QueryRunner, FindManyOptions, FindOneOptions, LessThanOrEqual } from 'typeorm'; import path from 'path'; import { IPLDDatabase as BaseDatabase, IPLDDatabaseInterface, QueryOptions, StateKind, Where } from '@vulcanize/util'; @@ -129,7 +129,7 @@ export class Database implements IPLDDatabaseInterface { }); } - async getTransferCount (queryRunner: QueryRunner, { id, blockHash }: DeepPartial): Promise { + async getTransferCount (queryRunner: QueryRunner, { id, blockHash, blockNumber }: DeepPartial): Promise { const repo = queryRunner.manager.getRepository(TransferCount); const whereOptions: FindConditions = { id }; @@ -137,6 +137,10 @@ export class Database implements IPLDDatabaseInterface { whereOptions.blockHash = blockHash; } + if (blockNumber) { + whereOptions.blockNumber = LessThanOrEqual(blockNumber); + } + const findOptions = { where: whereOptions, order: { diff --git a/packages/erc721-watcher/src/hooks.ts b/packages/erc721-watcher/src/hooks.ts index 22e6382e2..6567696b3 100644 --- a/packages/erc721-watcher/src/hooks.ts +++ b/packages/erc721-watcher/src/hooks.ts @@ -100,16 +100,17 @@ export async function handleEvent (indexer: Indexer, eventData: ResultEvent): Pr // "transferCount": "1" // } // Fetch transferCount entity from database. - let transferCount = await indexer.transferCount(eventData.block.hash, eventData.contract); + let transferCount = await indexer.getTransferCount(eventData.contract, eventData.block); if (!transferCount) { transferCount = new TransferCount(); - transferCount.blockHash = eventData.block.hash; - transferCount.blockNumber = eventData.block.number; transferCount.id = eventData.contract; transferCount.count = 0; } + transferCount.blockHash = eventData.block.hash; + transferCount.blockNumber = eventData.block.number; + // Increment count on transfer event. transferCount.count++; diff --git a/packages/erc721-watcher/src/indexer.ts b/packages/erc721-watcher/src/indexer.ts index 14b07499a..8aa6a3f6f 100644 --- a/packages/erc721-watcher/src/indexer.ts +++ b/packages/erc721-watcher/src/indexer.ts @@ -431,12 +431,12 @@ export class Indexer implements IPLDIndexerInterface { return result; } - async transferCount (blockHash: string, contractAddress: string): Promise { + async getTransferCount (id: string, block: BlockHeight): Promise { const dbTx = await this._db.createTransactionRunner(); let res; try { - res = await this._db.getTransferCount(dbTx, { id: contractAddress, blockHash }); + res = await this._db.getTransferCount(dbTx, { id, blockHash: block.hash, blockNumber: block.number }); await dbTx.commitTransaction(); } catch (error) { await dbTx.rollbackTransaction(); diff --git a/packages/erc721-watcher/src/resolvers.ts b/packages/erc721-watcher/src/resolvers.ts index 5d662ad7f..8f72a2ade 100644 --- a/packages/erc721-watcher/src/resolvers.ts +++ b/packages/erc721-watcher/src/resolvers.ts @@ -12,6 +12,7 @@ import { ValueResult, BlockHeight, StateKind } from '@vulcanize/util'; import { Indexer } from './indexer'; import { EventWatcher } from './events'; +import { TransferCount } from './entity/TransferCount'; const log = debug('vulcanize:resolver'); @@ -128,6 +129,12 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch return indexer._operatorApprovals(blockHash, contractAddress, key0, key1); }, + transferCount: async (_: any, { id, block = {} }: { id: string, block: BlockHeight }) => { + log('transferCount', id, block); + + return indexer.getTransferCount(id, block); + }, + events: async (_: any, { blockHash, contractAddress, name }: { blockHash: string, contractAddress: string, name?: string }) => { log('events', blockHash, contractAddress, name); diff --git a/packages/erc721-watcher/src/schema.gql b/packages/erc721-watcher/src/schema.gql index b345f2b3e..6be95a117 100644 --- a/packages/erc721-watcher/src/schema.gql +++ b/packages/erc721-watcher/src/schema.gql @@ -4,6 +4,11 @@ scalar BigDecimal scalar Bytes +input Block_height { + hash: Bytes + number: Int +} + type Proof { data: String! } @@ -99,6 +104,12 @@ type Query { _operatorApprovals(blockHash: String!, contractAddress: String!, key0: String!, key1: String!): ResultBoolean! getStateByCID(cid: String!): ResultIPLDBlock getState(blockHash: String!, contractAddress: String!, kind: String): ResultIPLDBlock + transferCount(id: String!, block: Block_height): TransferCount! +} + +type TransferCount { + id: ID! + count: Int! } type Mutation {