Skip to content

Commit

Permalink
Implement custom update of transfer counter in state diff
Browse files Browse the repository at this point in the history
  • Loading branch information
nikugogoi committed Jun 13, 2022
1 parent 83a1b03 commit c633d27
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 11 deletions.
8 changes: 7 additions & 1 deletion packages/erc721-watcher/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
}
```

* Run the following GQL query (`storage`) in generated watcher graphql endpoint http://127.0.0.1:3006/graphql
* Run the following GQL query (`storage`) in generated watcher GraphQL endpoint http://127.0.0.1:3006/graphql

```graphql
query {
Expand Down Expand Up @@ -214,6 +214,8 @@

* An auto-generated diff_staged IPLDBlock should be added with parent cid pointing to the initial checkpoint IPLDBlock.

* Custom property `transferCount` should be 1 initially.

* Run the getState query at the endpoint to get the latest IPLDBlock for NFT_ADDRESS:

```graphql
Expand Down Expand Up @@ -290,6 +292,8 @@

* 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.

* 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.
Expand All @@ -310,6 +314,8 @@

* Open IPFS WebUI http://127.0.0.1:5001/webui and search for IPLDBlocks using their CIDs.

* The state should have auto indexed data and also custom property `transferCount` according to code in hooks file handleEvent method.

## Customize

* Indexing on an event:
Expand Down
32 changes: 31 additions & 1 deletion packages/erc721-watcher/src/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//

import assert from 'assert';
import { Connection, ConnectionOptions, DeepPartial, FindConditions, QueryRunner, FindManyOptions } from 'typeorm';
import { Connection, ConnectionOptions, DeepPartial, FindConditions, QueryRunner, FindManyOptions, FindOneOptions } from 'typeorm';
import path from 'path';

import { IPLDDatabase as BaseDatabase, IPLDDatabaseInterface, QueryOptions, StateKind, Where } from '@vulcanize/util';
Expand All @@ -28,6 +28,7 @@ import { _Owners } from './entity/_Owners';
import { _Balances } from './entity/_Balances';
import { _TokenApprovals } from './entity/_TokenApprovals';
import { _OperatorApprovals } from './entity/_OperatorApprovals';
import { TransferCount } from './entity/TransferCount';

export class Database implements IPLDDatabaseInterface {
_config: ConnectionOptions;
Expand Down Expand Up @@ -128,6 +129,35 @@ export class Database implements IPLDDatabaseInterface {
});
}

async getTransferCount (queryRunner: QueryRunner, { id, blockHash }: DeepPartial<TransferCount>): Promise<TransferCount | undefined> {
const repo = queryRunner.manager.getRepository(TransferCount);
const whereOptions: FindConditions<TransferCount> = { id };

if (blockHash) {
whereOptions.blockHash = blockHash;
}

const findOptions = {
where: whereOptions,
order: {
blockNumber: 'DESC'
}
};

let entity = await repo.findOne(findOptions as FindOneOptions<TransferCount>);

if (!entity && findOptions.where.blockHash) {
entity = await this._baseDatabase.getPrevEntityVersion(queryRunner, repo, findOptions);
}

return entity;
}

async saveTransferCount (queryRunner: QueryRunner, transferCount: TransferCount): Promise<TransferCount> {
const repo = queryRunner.manager.getRepository(TransferCount);
return repo.save(transferCount);
}

async _getName ({ blockHash, contractAddress }: { blockHash: string, contractAddress: string }): Promise<_Name | undefined> {
return this._conn.getRepository(_Name)
.findOne({
Expand Down
20 changes: 20 additions & 0 deletions packages/erc721-watcher/src/entity/TransferCount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Copyright 2022 Vulcanize, Inc.
//

import { Entity, PrimaryColumn, Column, Index } from 'typeorm';

@Entity()
export class TransferCount {
@PrimaryColumn('varchar')
id!: string;

@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;

@Column('integer')
blockNumber!: number;

@Column('integer')
count!: number;
}
26 changes: 17 additions & 9 deletions packages/erc721-watcher/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import assert from 'assert';
import { updateStateForMappingType, updateStateForElementaryType } from '@vulcanize/util';

import { Indexer, ResultEvent } from './indexer';
import { TransferCount } from './entity/TransferCount';

/**
* Hook function to store an initial state.
Expand Down Expand Up @@ -94,18 +95,25 @@ export async function handleEvent (indexer: Indexer, eventData: ResultEvent): Pr
// Update owner for the tokenId in database.
await indexer._owners(eventData.block.hash, eventData.contract, tokenId, true);

// Update custom state diffs with properties name and symbol.
// Update custom state diffs with transferCount.
// {
// "name": "TestNFT",
// "symbol": "TNFT"
// "transferCount": "1"
// }
const { value: name } = await indexer.name(eventData.block.hash, eventData.contract);
const nameUpdate = updateStateForElementaryType({}, 'name', name);
await indexer.createDiffStaged(eventData.contract, eventData.block.hash, nameUpdate);
let transferCount = await indexer.transferCount(eventData.block.hash, eventData.contract);

if (!transferCount) {
transferCount = new TransferCount();
transferCount.blockHash = eventData.block.hash;
transferCount.blockNumber = eventData.block.number;
transferCount.id = eventData.contract;
transferCount.count = 0;
}

transferCount.count++;

const { value: symbol } = await indexer.symbol(eventData.block.hash, eventData.contract);
const symbolUpdate = updateStateForElementaryType({}, 'symbol', symbol);
await indexer.createDiffStaged(eventData.contract, eventData.block.hash, symbolUpdate);
const stateUpdate = updateStateForElementaryType({}, 'transferCount', String(transferCount.count));
await indexer.createDiffStaged(eventData.contract, eventData.block.hash, stateUpdate);
await indexer.saveOrUpdateTransferCount(transferCount);

break;
}
Expand Down
34 changes: 34 additions & 0 deletions packages/erc721-watcher/src/indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { SyncStatus } from './entity/SyncStatus';
import { IpldStatus } from './entity/IpldStatus';
import { BlockProgress } from './entity/BlockProgress';
import { IPLDBlock } from './entity/IPLDBlock';
import { TransferCount } from './entity/TransferCount';

const log = debug('vulcanize:indexer');

Expand Down Expand Up @@ -430,6 +431,39 @@ export class Indexer implements IPLDIndexerInterface {
return result;
}

async transferCount (blockHash: string, contractAddress: string): Promise<TransferCount | undefined> {
const dbTx = await this._db.createTransactionRunner();
let res;

try {
res = await this._db.getTransferCount(dbTx, { id: contractAddress, blockHash });
await dbTx.commitTransaction();
} catch (error) {
await dbTx.rollbackTransaction();
throw error;
} finally {
await dbTx.release();
}

return res;
}

async saveOrUpdateTransferCount (transferCount: TransferCount) {
const dbTx = await this._db.createTransactionRunner();
let res;

try {
await this._db.saveTransferCount(dbTx, transferCount);
} catch (error) {
await dbTx.rollbackTransaction();
throw error;
} finally {
await dbTx.release();
}

return res;
}

async _name (blockHash: string, contractAddress: string, diff = false): Promise<ValueResult> {
const entity = await this._db._getName({ blockHash, contractAddress });
if (entity) {
Expand Down

0 comments on commit c633d27

Please sign in to comment.