From f8335aad039802835b4b8854719907e889ed765c Mon Sep 17 00:00:00 2001 From: Ashwin Phatak Date: Fri, 23 Jul 2021 11:00:40 +0530 Subject: [PATCH] Add block hash to entities, split get and set methods (#161) * Split get and set entity for PoolCreated and Initialize events. * Split get/set entity for Mint, Burn and Swap events. * Split get/set entity for IncreaseLiquidity and DecreaseLiquidity events. * Split get/set for NFPM Transfer and Collect events. * Add blockHash to entities. Co-authored-by: nabarun --- packages/uni-info-watcher/src/database.ts | 625 ++++++------------ .../uni-info-watcher/src/entity/Bundle.ts | 5 +- packages/uni-info-watcher/src/entity/Burn.ts | 5 +- .../uni-info-watcher/src/entity/Factory.ts | 5 +- packages/uni-info-watcher/src/entity/Mint.ts | 5 +- packages/uni-info-watcher/src/entity/Pool.ts | 5 +- .../src/entity/PoolDayData.ts | 5 +- .../src/entity/PoolHourData.ts | 5 +- .../uni-info-watcher/src/entity/Position.ts | 5 +- .../src/entity/PositionSnapshot.ts | 5 +- packages/uni-info-watcher/src/entity/Swap.ts | 5 +- packages/uni-info-watcher/src/entity/Tick.ts | 5 +- packages/uni-info-watcher/src/entity/Token.ts | 5 +- .../src/entity/TokenDayData.ts | 5 +- .../src/entity/TokenHourData.ts | 5 +- .../src/entity/Transaction.ts | 5 +- .../src/entity/UniswapDayData.ts | 5 +- packages/uni-info-watcher/src/indexer.ts | 444 +++++++------ packages/uni-info-watcher/src/utils/index.ts | 23 +- .../src/utils/interval-updates.ts | 174 ++--- .../uni-info-watcher/src/utils/pricing.ts | 4 +- packages/uni-info-watcher/src/utils/tick.ts | 22 +- 22 files changed, 643 insertions(+), 729 deletions(-) diff --git a/packages/uni-info-watcher/src/database.ts b/packages/uni-info-watcher/src/database.ts index e78fd405..3d0ba3d9 100644 --- a/packages/uni-info-watcher/src/database.ts +++ b/packages/uni-info-watcher/src/database.ts @@ -45,6 +45,44 @@ export class Database { return this._conn.close(); } + async getFactory ({ id, blockNumber }: DeepPartial): Promise { + const repo = this._conn.getRepository(Factory); + + const whereOptions: FindConditions = { id }; + + if (blockNumber) { + whereOptions.blockNumber = LessThanOrEqual(blockNumber); + } + + const findOptions: FindOneOptions = { + where: whereOptions, + order: { + blockNumber: 'DESC' + } + }; + + return repo.findOne(findOptions); + } + + async getBundle ({ id, blockNumber }: DeepPartial): Promise { + const repo = this._conn.getRepository(Bundle); + + const whereOptions: FindConditions = { id }; + + if (blockNumber) { + whereOptions.blockNumber = LessThanOrEqual(blockNumber); + } + + const findOptions: FindOneOptions = { + where: whereOptions, + order: { + blockNumber: 'DESC' + } + }; + + return repo.findOne(findOptions); + } + async getToken ({ id, blockNumber }: DeepPartial): Promise { const repo = this._conn.getRepository(Token); @@ -122,6 +160,114 @@ export class Database { return repo.findOne(findOptions); } + async getPoolDayData ({ id, blockNumber }: DeepPartial): Promise { + const repo = this._conn.getRepository(PoolDayData); + const whereOptions: FindConditions = { id }; + + if (blockNumber) { + whereOptions.blockNumber = LessThanOrEqual(blockNumber); + } + + const findOptions: FindOneOptions = { + where: whereOptions, + order: { + blockNumber: 'DESC' + } + }; + + return repo.findOne(findOptions); + } + + async getPoolHourData ({ id, blockNumber }: DeepPartial): Promise { + const repo = this._conn.getRepository(PoolHourData); + const whereOptions: FindConditions = { id }; + + if (blockNumber) { + whereOptions.blockNumber = LessThanOrEqual(blockNumber); + } + + const findOptions: FindOneOptions = { + where: whereOptions, + order: { + blockNumber: 'DESC' + } + }; + + return repo.findOne(findOptions); + } + + async getUniswapDayData ({ id, blockNumber }: DeepPartial): Promise { + const repo = this._conn.getRepository(UniswapDayData); + const whereOptions: FindConditions = { id }; + + if (blockNumber) { + whereOptions.blockNumber = LessThanOrEqual(blockNumber); + } + + const findOptions: FindOneOptions = { + where: whereOptions, + order: { + blockNumber: 'DESC' + } + }; + + return repo.findOne(findOptions); + } + + async getTokenDayData ({ id, blockNumber }: DeepPartial): Promise { + const repo = this._conn.getRepository(TokenDayData); + const whereOptions: FindConditions = { id }; + + if (blockNumber) { + whereOptions.blockNumber = LessThanOrEqual(blockNumber); + } + + const findOptions: FindOneOptions = { + where: whereOptions, + order: { + blockNumber: 'DESC' + } + }; + + return repo.findOne(findOptions); + } + + async getTokenHourData ({ id, blockNumber }: DeepPartial): Promise { + const repo = this._conn.getRepository(TokenHourData); + const whereOptions: FindConditions = { id }; + + if (blockNumber) { + whereOptions.blockNumber = LessThanOrEqual(blockNumber); + } + + const findOptions: FindOneOptions = { + where: whereOptions, + order: { + blockNumber: 'DESC' + } + }; + + return repo.findOne(findOptions); + } + + async getTransaction ({ id, blockNumber }: DeepPartial): Promise { + const repo = this._conn.getRepository(Transaction); + const whereOptions: FindConditions = { id }; + + if (blockNumber) { + whereOptions.blockNumber = LessThanOrEqual(blockNumber); + } + + const findOptions: FindOneOptions = { + where: whereOptions, + order: { + blockNumber: 'DESC' + } + }; + + return repo.findOne(findOptions); + } + async getFactories ({ blockNumber }: DeepPartial, queryOptions: { [key: string]: any }): Promise> { const repo = this._conn.getRepository(Factory); @@ -143,485 +289,150 @@ export class Database { return selectQueryBuilder.getMany(); } - async loadFactory ({ id, blockNumber, ...values }: DeepPartial): Promise { + async saveFactory (factory: Factory, block: Block): Promise { return this._conn.transaction(async (tx) => { const repo = tx.getRepository(Factory); - - let selectQueryBuilder = repo.createQueryBuilder('factory') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadPool ({ id, blockNumber, ...values }: DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(Pool); - - const whereOptions: FindConditions = { id }; - - if (blockNumber) { - whereOptions.blockNumber = LessThanOrEqual(blockNumber); - } - - const findOptions: FindOneOptions = { - where: whereOptions, - relations: ['token0', 'token1'], - order: { - blockNumber: 'DESC' - } - }; - - let entity = await repo.findOne(findOptions); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadToken ({ id, blockNumber, ...values }: DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(Token); - - const whereOptions: FindConditions = { id }; - - if (blockNumber) { - whereOptions.blockNumber = LessThanOrEqual(blockNumber); - } - - const findOptions: FindOneOptions = { - where: whereOptions, - relations: ['whitelistPools', 'whitelistPools.token0', 'whitelistPools.token1'], - order: { - blockNumber: 'DESC' - } - }; - - let entity = await repo.findOne(findOptions); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - - // TODO: Find way to preload relations during create. - entity.whitelistPools = []; - } - - return entity; - }); - } - - async loadBundle ({ id, blockNumber, ...values }: DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(Bundle); - - let selectQueryBuilder = repo.createQueryBuilder('bundle') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadPoolDayData ({ id, blockNumber, ...values }: DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(PoolDayData); - - let selectQueryBuilder = repo.createQueryBuilder('pool_day_data') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadPoolHourData ({ id, blockNumber, ...values }: DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(PoolHourData); - - let selectQueryBuilder = repo.createQueryBuilder('pool_hour_data') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadTransaction ({ id, blockNumber, ...values }: DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(Transaction); - - let selectQueryBuilder = repo.createQueryBuilder('transaction') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadMint ({ id, blockNumber, ...values }:DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(Mint); - - let selectQueryBuilder = repo.createQueryBuilder('mint') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadBurn ({ id, blockNumber, ...values }:DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(Burn); - - let selectQueryBuilder = repo.createQueryBuilder('burn') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadSwap ({ id, blockNumber, ...values }:DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(Swap); - - let selectQueryBuilder = repo.createQueryBuilder('swap') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadTick ({ id, blockNumber, ...values }: DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(Tick); - - let selectQueryBuilder = repo.createQueryBuilder('tick') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadUniswapDayData ({ id, blockNumber, ...values }: DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(UniswapDayData); - - let selectQueryBuilder = repo.createQueryBuilder('uniswap_day_data') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadTokenDayData ({ id, blockNumber, ...values }: DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(TokenDayData); - - let selectQueryBuilder = repo.createQueryBuilder('token_day_data') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadTokenHourData ({ id, blockNumber, ...values }: DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(TokenHourData); - - let selectQueryBuilder = repo.createQueryBuilder('token_hour_data') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadPosition ({ id, blockNumber, ...values }: DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(Position); - - let selectQueryBuilder = repo.createQueryBuilder('position') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async loadPositionSnapshot ({ id, blockNumber, ...values }: DeepPartial): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(PositionSnapshot); - - let selectQueryBuilder = repo.createQueryBuilder('positionSnapshot') - .where('id = :id', { id }); - - if (blockNumber) { - selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber }); - } - - let entity = await selectQueryBuilder.orderBy('block_number', 'DESC') - .getOne(); - - if (!entity) { - entity = repo.create({ blockNumber, id, ...values }); - entity = await repo.save(entity); - } - - return entity; - }); - } - - async saveFactory (factory: Factory, blockNumber: number): Promise { - return this._conn.transaction(async (tx) => { - const repo = tx.getRepository(Factory); - factory.blockNumber = blockNumber; + factory.blockNumber = block.number; + factory.blockHash = block.hash; return repo.save(factory); }); } - async saveBundle (bundle: Bundle, blockNumber: number): Promise { + async saveBundle (bundle: Bundle, block: Block): Promise { return this._conn.transaction(async (tx) => { const repo = tx.getRepository(Bundle); - bundle.blockNumber = blockNumber; + bundle.blockNumber = block.number; + bundle.blockHash = block.hash; return repo.save(bundle); }); } - async savePool (pool: Pool, blockNumber: number): Promise { + async savePool (pool: Pool, block: Block): Promise { return this._conn.transaction(async (tx) => { const repo = tx.getRepository(Pool); - pool.blockNumber = blockNumber; + pool.blockNumber = block.number; + pool.blockHash = block.hash; return repo.save(pool); }); } - async savePoolDayData (poolDayData: PoolDayData, blockNumber: number): Promise { + async savePoolDayData (poolDayData: PoolDayData, block: Block): Promise { return this._conn.transaction(async (tx) => { const repo = tx.getRepository(PoolDayData); - poolDayData.blockNumber = blockNumber; + poolDayData.blockNumber = block.number; + poolDayData.blockHash = block.hash; return repo.save(poolDayData); }); } - async savePoolHourData (poolHourData: PoolHourData, blockNumber: number): Promise { + async savePoolHourData (poolHourData: PoolHourData, block: Block): Promise { return this._conn.transaction(async (tx) => { const repo = tx.getRepository(PoolHourData); - poolHourData.blockNumber = blockNumber; + poolHourData.blockNumber = block.number; + poolHourData.blockHash = block.hash; return repo.save(poolHourData); }); } - async saveToken (token: Token, blockNumber: number): Promise { + async saveToken (token: Token, block: Block): Promise { return this._conn.transaction(async (tx) => { const repo = tx.getRepository(Token); - token.blockNumber = blockNumber; + token.blockNumber = block.number; + token.blockHash = block.hash; return repo.save(token); }); } - async saveTransaction (transaction: Transaction, blockNumber: number): Promise { + async saveTransaction (transaction: Transaction, block: Block): Promise { return this._conn.transaction(async (tx) => { const repo = tx.getRepository(Transaction); - transaction.blockNumber = blockNumber; + transaction.blockNumber = block.number; + transaction.blockHash = block.hash; return repo.save(transaction); }); } - async saveUniswapDayData (uniswapDayData: UniswapDayData, blockNumber: number): Promise { + async saveUniswapDayData (uniswapDayData: UniswapDayData, block: Block): Promise { return this._conn.transaction(async (tx) => { const repo = tx.getRepository(UniswapDayData); - uniswapDayData.blockNumber = blockNumber; + uniswapDayData.blockNumber = block.number; + uniswapDayData.blockHash = block.hash; return repo.save(uniswapDayData); }); } - async saveTokenDayData (tokenDayData: TokenDayData, blockNumber: number): Promise { + async saveTokenDayData (tokenDayData: TokenDayData, block: Block): Promise { return this._conn.transaction(async (tx) => { const repo = tx.getRepository(TokenDayData); - tokenDayData.blockNumber = blockNumber; + tokenDayData.blockNumber = block.number; + tokenDayData.blockHash = block.hash; return repo.save(tokenDayData); }); } - async saveTokenHourData (tokenHourData: TokenHourData, blockNumber: number): Promise { + async saveTokenHourData (tokenHourData: TokenHourData, block: Block): Promise { return this._conn.transaction(async (tx) => { const repo = tx.getRepository(TokenHourData); - tokenHourData.blockNumber = blockNumber; + tokenHourData.blockNumber = block.number; + tokenHourData.blockHash = block.hash; return repo.save(tokenHourData); }); } - async saveTick (tick: Tick, blockNumber: number): Promise { + async saveTick (tick: Tick, block: Block): Promise { return this._conn.transaction(async (tx) => { const repo = tx.getRepository(Tick); - tick.blockNumber = blockNumber; + tick.blockNumber = block.number; + tick.blockHash = block.hash; return repo.save(tick); }); } - async savePosition (position: Position, blockNumber: number): Promise { + async savePosition (position: Position, block: Block): Promise { return this._conn.transaction(async (tx) => { const repo = tx.getRepository(Position); - position.blockNumber = blockNumber; + position.blockNumber = block.number; + position.blockHash = block.hash; return repo.save(position); }); } + async savePositionSnapshot (positionSnapshot: PositionSnapshot, block: Block): Promise { + return this._conn.transaction(async (tx) => { + const repo = tx.getRepository(PositionSnapshot); + positionSnapshot.blockNumber = block.number; + positionSnapshot.blockHash = block.hash; + return repo.save(positionSnapshot); + }); + } + + async saveMint (mint: Mint, block: Block): Promise { + return this._conn.transaction(async (tx) => { + const repo = tx.getRepository(Mint); + mint.blockNumber = block.number; + mint.blockHash = block.hash; + return repo.save(mint); + }); + } + + async saveBurn (burn: Burn, block: Block): Promise { + return this._conn.transaction(async (tx) => { + const repo = tx.getRepository(Burn); + burn.blockNumber = block.number; + burn.blockHash = block.hash; + return repo.save(burn); + }); + } + + async saveSwap (swap: Swap, block: Block): Promise { + return this._conn.transaction(async (tx) => { + const repo = tx.getRepository(Swap); + swap.blockNumber = block.number; + swap.blockHash = block.hash; + return repo.save(swap); + }); + } + // Returns true if events have already been synced for the (block, token) combination. async didSyncEvents ({ blockHash, token }: { blockHash: string, token: string }): Promise { const numRows = await this._conn.getRepository(EventSyncProgress) diff --git a/packages/uni-info-watcher/src/entity/Bundle.ts b/packages/uni-info-watcher/src/entity/Bundle.ts index 705538bc..63f42b1c 100644 --- a/packages/uni-info-watcher/src/entity/Bundle.ts +++ b/packages/uni-info-watcher/src/entity/Bundle.ts @@ -7,7 +7,10 @@ export class Bundle { @PrimaryColumn('varchar', { length: 1 }) id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @Column('numeric', { default: 0, transformer: decimalTransformer }) diff --git a/packages/uni-info-watcher/src/entity/Burn.ts b/packages/uni-info-watcher/src/entity/Burn.ts index a2a49460..d9b68359 100644 --- a/packages/uni-info-watcher/src/entity/Burn.ts +++ b/packages/uni-info-watcher/src/entity/Burn.ts @@ -11,7 +11,10 @@ export class Burn { @PrimaryColumn('varchar') id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @ManyToOne(() => Transaction, transaction => transaction.burns) diff --git a/packages/uni-info-watcher/src/entity/Factory.ts b/packages/uni-info-watcher/src/entity/Factory.ts index c0e6ca7d..b751e143 100644 --- a/packages/uni-info-watcher/src/entity/Factory.ts +++ b/packages/uni-info-watcher/src/entity/Factory.ts @@ -7,7 +7,10 @@ export class Factory { @PrimaryColumn('varchar', { length: 42 }) id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @Column('bigint', { default: BigInt(0) }) diff --git a/packages/uni-info-watcher/src/entity/Mint.ts b/packages/uni-info-watcher/src/entity/Mint.ts index b7d06ee7..e7060032 100644 --- a/packages/uni-info-watcher/src/entity/Mint.ts +++ b/packages/uni-info-watcher/src/entity/Mint.ts @@ -11,7 +11,10 @@ export class Mint { @PrimaryColumn('varchar') id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @ManyToOne(() => Transaction, transaction => transaction.mints) diff --git a/packages/uni-info-watcher/src/entity/Pool.ts b/packages/uni-info-watcher/src/entity/Pool.ts index 666c21dc..a60dace6 100644 --- a/packages/uni-info-watcher/src/entity/Pool.ts +++ b/packages/uni-info-watcher/src/entity/Pool.ts @@ -9,7 +9,10 @@ export class Pool { @PrimaryColumn('varchar', { length: 42 }) id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @ManyToOne(() => Token) diff --git a/packages/uni-info-watcher/src/entity/PoolDayData.ts b/packages/uni-info-watcher/src/entity/PoolDayData.ts index 79ad79bf..32a4f353 100644 --- a/packages/uni-info-watcher/src/entity/PoolDayData.ts +++ b/packages/uni-info-watcher/src/entity/PoolDayData.ts @@ -9,7 +9,10 @@ export class PoolDayData { @PrimaryColumn('varchar') id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @Column('integer') diff --git a/packages/uni-info-watcher/src/entity/PoolHourData.ts b/packages/uni-info-watcher/src/entity/PoolHourData.ts index 6bb1f576..b5d4d02d 100644 --- a/packages/uni-info-watcher/src/entity/PoolHourData.ts +++ b/packages/uni-info-watcher/src/entity/PoolHourData.ts @@ -9,7 +9,10 @@ export class PoolHourData { @PrimaryColumn('varchar') id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @Column('integer') diff --git a/packages/uni-info-watcher/src/entity/Position.ts b/packages/uni-info-watcher/src/entity/Position.ts index a7f13f12..ba8c026f 100644 --- a/packages/uni-info-watcher/src/entity/Position.ts +++ b/packages/uni-info-watcher/src/entity/Position.ts @@ -13,7 +13,10 @@ export class Position { @PrimaryColumn('varchar') id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @Column('bigint') diff --git a/packages/uni-info-watcher/src/entity/PositionSnapshot.ts b/packages/uni-info-watcher/src/entity/PositionSnapshot.ts index 0f387a3b..6e3e24cc 100644 --- a/packages/uni-info-watcher/src/entity/PositionSnapshot.ts +++ b/packages/uni-info-watcher/src/entity/PositionSnapshot.ts @@ -12,7 +12,10 @@ export class PositionSnapshot { @PrimaryColumn('varchar') id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @Column('bigint') diff --git a/packages/uni-info-watcher/src/entity/Swap.ts b/packages/uni-info-watcher/src/entity/Swap.ts index bff8e6af..51ac9909 100644 --- a/packages/uni-info-watcher/src/entity/Swap.ts +++ b/packages/uni-info-watcher/src/entity/Swap.ts @@ -11,7 +11,10 @@ export class Swap { @PrimaryColumn('varchar') id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @ManyToOne(() => Transaction, transaction => transaction.swaps) diff --git a/packages/uni-info-watcher/src/entity/Tick.ts b/packages/uni-info-watcher/src/entity/Tick.ts index dd96e4ef..88ad6265 100644 --- a/packages/uni-info-watcher/src/entity/Tick.ts +++ b/packages/uni-info-watcher/src/entity/Tick.ts @@ -9,7 +9,10 @@ export class Tick { @PrimaryColumn('varchar') id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @Column('bigint') diff --git a/packages/uni-info-watcher/src/entity/Token.ts b/packages/uni-info-watcher/src/entity/Token.ts index a6490d4c..c0437e45 100644 --- a/packages/uni-info-watcher/src/entity/Token.ts +++ b/packages/uni-info-watcher/src/entity/Token.ts @@ -9,7 +9,10 @@ export class Token { @PrimaryColumn('varchar', { length: 42 }) id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @Column('varchar') diff --git a/packages/uni-info-watcher/src/entity/TokenDayData.ts b/packages/uni-info-watcher/src/entity/TokenDayData.ts index 921e1b72..812c14ad 100644 --- a/packages/uni-info-watcher/src/entity/TokenDayData.ts +++ b/packages/uni-info-watcher/src/entity/TokenDayData.ts @@ -9,7 +9,10 @@ export class TokenDayData { @PrimaryColumn('varchar') id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @Column('integer') diff --git a/packages/uni-info-watcher/src/entity/TokenHourData.ts b/packages/uni-info-watcher/src/entity/TokenHourData.ts index 5090b6df..35edb0f6 100644 --- a/packages/uni-info-watcher/src/entity/TokenHourData.ts +++ b/packages/uni-info-watcher/src/entity/TokenHourData.ts @@ -9,7 +9,10 @@ export class TokenHourData { @PrimaryColumn('varchar') id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @Column('integer') diff --git a/packages/uni-info-watcher/src/entity/Transaction.ts b/packages/uni-info-watcher/src/entity/Transaction.ts index 4bb9c1ae..1320bdc8 100644 --- a/packages/uni-info-watcher/src/entity/Transaction.ts +++ b/packages/uni-info-watcher/src/entity/Transaction.ts @@ -11,7 +11,10 @@ export class Transaction { @PrimaryColumn('varchar') id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @Column('numeric', { default: 0, transformer: decimalTransformer }) diff --git a/packages/uni-info-watcher/src/entity/UniswapDayData.ts b/packages/uni-info-watcher/src/entity/UniswapDayData.ts index 80509d30..8fe1bf33 100644 --- a/packages/uni-info-watcher/src/entity/UniswapDayData.ts +++ b/packages/uni-info-watcher/src/entity/UniswapDayData.ts @@ -7,7 +7,10 @@ export class UniswapDayData { @PrimaryColumn('varchar') id!: string; - @PrimaryColumn('integer') + @PrimaryColumn('varchar', { length: 66 }) + blockHash!: string + + @Column('integer') blockNumber!: number; @Column('integer') diff --git a/packages/uni-info-watcher/src/indexer.ts b/packages/uni-info-watcher/src/indexer.ts index e1da862a..a70ede00 100644 --- a/packages/uni-info-watcher/src/indexer.ts +++ b/packages/uni-info-watcher/src/indexer.ts @@ -2,7 +2,7 @@ import assert from 'assert'; import debug from 'debug'; import { DeepPartial } from 'typeorm'; import JSONbig from 'json-bigint'; -import { BigNumber, utils } from 'ethers'; +import { utils } from 'ethers'; import { Client as UniClient } from '@vulcanize/uni-watcher'; import { Client as ERC20Client } from '@vulcanize/erc20-watcher'; @@ -10,12 +10,19 @@ import { findEthPerToken, getEthPriceInUSD, getTrackedAmountUSD, sqrtPriceX96ToT import { updatePoolDayData, updatePoolHourData, updateTokenDayData, updateTokenHourData, updateUniswapDayData } from './utils/interval-updates'; import { Token } from './entity/Token'; import { convertTokenToDecimal, loadTransaction, safeDiv } from './utils'; -import { loadTick } from './utils/tick'; +import { createTick } from './utils/tick'; import Decimal from 'decimal.js'; import { Position } from './entity/Position'; import { Database } from './database'; import { Event } from './entity/Event'; import { ResultEvent, Block, Transaction, PoolCreatedEvent, InitializeEvent, MintEvent, BurnEvent, SwapEvent, IncreaseLiquidityEvent, DecreaseLiquidityEvent, CollectEvent, TransferEvent } from './events'; +import { Factory } from './entity/Factory'; +import { Bundle } from './entity/Bundle'; +import { Pool } from './entity/Pool'; +import { Mint } from './entity/Mint'; +import { Burn } from './entity/Burn'; +import { Swap } from './entity/Swap'; +import { PositionSnapshot } from './entity/PositionSnapshot'; const log = debug('vulcanize:indexer'); @@ -88,7 +95,7 @@ export class Indexer { const resultEvent = this.getResultEvent(dbEvent); // TODO: Process proof (proof.data) in event. - const { contract, block, tx, event } = resultEvent; + const { contract, tx, block, event } = resultEvent; const { __typename: eventType } = event; switch (eventType) { @@ -179,16 +186,33 @@ export class Indexer { } async _handlePoolCreated (block: Block, contractAddress: string, tx: Transaction, poolCreatedEvent: PoolCreatedEvent): Promise { - const { number: blockNumber, hash: blockHash } = block; + const { number: blockNumber } = block; const { token0: token0Address, token1: token1Address, fee, pool: poolAddress } = poolCreatedEvent; + // Temp fix from Subgraph mapping code. + if (utils.getAddress(poolAddress) === utils.getAddress('0x8fe8d9bb8eeba3ed688069c3d6b556c9ca258248')) { + return; + } + // Load factory. - const factory = await this._db.loadFactory({ blockNumber, id: contractAddress }); + let factory = await this._db.getFactory({ blockNumber, id: contractAddress }); + + if (!factory) { + factory = new Factory(); + factory.id = contractAddress; + factory = await this._db.saveFactory(factory, block); + + // Create new bundle for tracking eth price. + const bundle = new Bundle(); + bundle.id = '1'; + await this._db.saveBundle(bundle, block); + } // Update Factory. - let factoryPoolCount = BigNumber.from(factory.poolCount); - factoryPoolCount = factoryPoolCount.add(1); - factory.poolCount = BigInt(factoryPoolCount.toHexString()); + factory.poolCount = BigInt(factory.poolCount) + BigInt(1); + + let pool = new Pool(); + pool.id = poolAddress; // Get Tokens. let [token0, token1] = await Promise.all([ @@ -198,61 +222,59 @@ export class Indexer { // Create Tokens if not present. if (!token0) { - token0 = await this._createToken(blockHash, blockNumber, token0Address); + token0 = await this._createToken(block, token0Address); } if (!token1) { - token1 = await this._createToken(blockHash, blockNumber, token1Address); + token1 = await this._createToken(block, token1Address); } - // Create new Pool entity. - // Skipping adding createdAtTimestamp field as it is not queried in frontend subgraph. - const pool = await this._db.loadPool({ - blockNumber, - id: poolAddress, - token0: token0, - token1: token1, - feeTier: BigInt(fee) - }); + pool.token0 = token0; + pool.token1 = token1; + pool.feeTier = BigInt(fee); + pool = await this._db.savePool(pool, block); // Update white listed pools. if (WHITELIST_TOKENS.includes(token0.id)) { token1.whitelistPools.push(pool); - await this._db.saveToken(token1, blockNumber); } if (WHITELIST_TOKENS.includes(token1.id)) { token0.whitelistPools.push(pool); - await this._db.saveToken(token0, blockNumber); } + // Skipping adding createdAtTimestamp field as it is not queried in frontend subgraph. + // Save entities to DB. - await this._db.saveFactory(factory, blockNumber); + await this._db.saveToken(token0, block); + await this._db.saveToken(token1, block); + await this._db.saveFactory(factory, block); } /** * Create new Token. * @param tokenAddress */ - async _createToken (blockHash: string, blockNumber: number, tokenAddress: string): Promise { - const { value: symbol } = await this._erc20Client.getSymbol(blockHash, tokenAddress); - const { value: name } = await this._erc20Client.getName(blockHash, tokenAddress); - const { value: totalSupply } = await this._erc20Client.getTotalSupply(blockHash, tokenAddress); + async _createToken (block: Block, tokenAddress: string): Promise { + const token = new Token(); + token.id = tokenAddress; + + const { value: symbol } = await this._erc20Client.getSymbol(block.hash, tokenAddress); + const { value: name } = await this._erc20Client.getName(block.hash, tokenAddress); + const { value: totalSupply } = await this._erc20Client.getTotalSupply(block.hash, tokenAddress); // TODO: Decimals not implemented by erc20-watcher. // const { value: decimals } = await this._erc20Client.getDecimals(blockHash, tokenAddress); - return this._db.loadToken({ - blockNumber, - id: tokenAddress, - symbol, - name, - totalSupply - }); + token.symbol = symbol; + token.name = name; + token.totalSupply = totalSupply; + + return this._db.saveToken(token, block); } async _handleInitialize (block: Block, contractAddress: string, tx: Transaction, initializeEvent: InitializeEvent): Promise { - const { number: blockNumber, timestamp: blockTimestamp } = block; + const { number: blockNumber } = block; const { sqrtPriceX96, tick } = initializeEvent; const pool = await this._db.getPool({ id: contractAddress, blockNumber }); assert(pool, `Pool ${contractAddress} not found.`); @@ -260,39 +282,41 @@ export class Indexer { // Update Pool. pool.sqrtPrice = BigInt(sqrtPriceX96); pool.tick = BigInt(tick); - this._db.savePool(pool, blockNumber); - - // Update ETH price now that prices could have changed. - const bundle = await this._db.loadBundle({ id: '1', blockNumber }); - bundle.ethPriceUSD = await getEthPriceInUSD(this._db); - this._db.saveBundle(bundle, blockNumber); - - await updatePoolDayData(this._db, { contractAddress, blockNumber, blockTimestamp }); - await updatePoolHourData(this._db, { contractAddress, blockNumber, blockTimestamp }); + this._db.savePool(pool, block); + // Update token prices. const [token0, token1] = await Promise.all([ this._db.getToken({ id: pool.token0.id, blockNumber }), this._db.getToken({ id: pool.token1.id, blockNumber }) ]); + // Update ETH price now that prices could have changed. + const bundle = await this._db.getBundle({ id: '1', blockNumber }); + assert(bundle); + bundle.ethPriceUSD = await getEthPriceInUSD(this._db); + this._db.saveBundle(bundle, block); + + await updatePoolDayData(this._db, { contractAddress, block }); + await updatePoolHourData(this._db, { contractAddress, block }); + assert(token0 && token1, 'Pool tokens not found.'); - // Update token prices. token0.derivedETH = await findEthPerToken(token0); token1.derivedETH = await findEthPerToken(token1); await Promise.all([ - this._db.saveToken(token0, blockNumber), - this._db.saveToken(token1, blockNumber) + this._db.saveToken(token0, block), + this._db.saveToken(token1, block) ]); } async _handleMint (block: Block, contractAddress: string, tx: Transaction, mintEvent: MintEvent): Promise { - const { number: blockNumber, timestamp: blockTimestamp } = block; - const { hash: txHash } = tx; - const bundle = await this._db.loadBundle({ id: '1', blockNumber }); + const { number: blockNumber } = block; + const bundle = await this._db.getBundle({ id: '1', blockNumber }); + assert(bundle); const poolAddress = contractAddress; - const pool = await this._db.loadPool({ id: poolAddress, blockNumber }); + const pool = await this._db.getPool({ id: poolAddress, blockNumber }); + assert(pool); // TODO: In subgraph factory is fetched by hardcoded factory address. // Currently fetching first factory in database as only one exists. @@ -349,29 +373,27 @@ export class Indexer { factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH); factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD); - const transaction = await loadTransaction(this._db, { txHash, blockNumber, blockTimestamp }); + const transaction = await loadTransaction(this._db, { block, tx }); - await this._db.loadMint({ - id: transaction.id + '#' + pool.txCount.toString(), - blockNumber, - transaction, - timestamp: transaction.timestamp, - pool, - token0: pool.token0, - token1: pool.token1, - owner: mintEvent.owner, - sender: mintEvent.sender, + const mint = new Mint(); + mint.id = transaction.id + '#' + pool.txCount.toString(); + mint.transaction = transaction; + mint.timestamp = transaction.timestamp; + mint.pool = pool; + mint.token0 = pool.token0; + mint.token1 = pool.token1; + mint.owner = mintEvent.owner; + mint.sender = mintEvent.sender; - // TODO: Assign origin with Transaction from address. - // origin: event.transaction.from + // TODO: Assign origin with Transaction from address. + // origin: event.transaction.from - amount: mintEvent.amount, - amount0: amount0, - amount1: amount1, - amountUSD: amountUSD, - tickLower: mintEvent.tickLower, - tickUpper: mintEvent.tickUpper - }); + mint.amount = mintEvent.amount; + mint.amount0 = amount0; + mint.amount1 = amount1; + mint.amountUSD = amountUSD; + mint.tickLower = mintEvent.tickLower; + mint.tickUpper = mintEvent.tickUpper; // Tick entities. const lowerTickIdx = mintEvent.tickLower; @@ -380,8 +402,16 @@ export class Indexer { const lowerTickId = poolAddress + '#' + mintEvent.tickLower.toString(); const upperTickId = poolAddress + '#' + mintEvent.tickUpper.toString(); - const lowerTick = await loadTick(this._db, lowerTickId, BigInt(lowerTickIdx), pool, blockNumber); - const upperTick = await loadTick(this._db, upperTickId, BigInt(upperTickIdx), pool, blockNumber); + let lowerTick = await this._db.getTick({ id: lowerTickId, blockNumber }); + let upperTick = await this._db.getTick({ id: upperTickId, blockNumber }); + + if (!lowerTick) { + lowerTick = await createTick(this._db, lowerTickId, BigInt(lowerTickIdx), pool, block); + } + + if (!upperTick) { + upperTick = await createTick(this._db, upperTickId, BigInt(upperTickIdx), pool, block); + } const amount = BigInt(mintEvent.amount); lowerTick.liquidityGross = BigInt(lowerTick.liquidityGross) + amount; @@ -392,36 +422,38 @@ export class Indexer { // TODO: Update Tick's volume, fees, and liquidity provider count. // Computing these on the tick level requires reimplementing some of the swapping code from v3-core. - await updateUniswapDayData(this._db, { blockNumber, contractAddress, blockTimestamp }); - await updatePoolDayData(this._db, { blockNumber, contractAddress, blockTimestamp }); - await updatePoolHourData(this._db, { blockNumber, contractAddress, blockTimestamp }); - await updateTokenDayData(this._db, token0, { blockNumber, blockTimestamp }); - await updateTokenDayData(this._db, token1, { blockNumber, blockTimestamp }); - await updateTokenHourData(this._db, token0, { blockNumber, blockTimestamp }); - await updateTokenHourData(this._db, token1, { blockNumber, blockTimestamp }); + await updateUniswapDayData(this._db, { block, contractAddress }); + await updatePoolDayData(this._db, { block, contractAddress }); + await updatePoolHourData(this._db, { block, contractAddress }); + await updateTokenDayData(this._db, token0, { block }); + await updateTokenDayData(this._db, token1, { block }); + await updateTokenHourData(this._db, token0, { block }); + await updateTokenHourData(this._db, token1, { block }); await Promise.all([ - this._db.saveToken(token0, blockNumber), - this._db.saveToken(token1, blockNumber) + this._db.saveToken(token0, block), + this._db.saveToken(token1, block) ]); - await this._db.savePool(pool, blockNumber); - await this._db.saveFactory(factory, blockNumber); + await this._db.savePool(pool, block); + await this._db.saveFactory(factory, block); + await this._db.saveMint(mint, block); await Promise.all([ - await this._db.saveTick(lowerTick, blockNumber), - await this._db.saveTick(upperTick, blockNumber) + await this._db.saveTick(lowerTick, block), + await this._db.saveTick(upperTick, block) ]); // Skipping update inner tick vars and tick day data as they are not queried. } async _handleBurn (block: Block, contractAddress: string, tx: Transaction, burnEvent: BurnEvent): Promise { - const { number: blockNumber, timestamp: blockTimestamp } = block; - const { hash: txHash } = tx; - const bundle = await this._db.loadBundle({ id: '1', blockNumber }); + const { number: blockNumber } = block; + const bundle = await this._db.getBundle({ id: '1', blockNumber }); + assert(bundle); const poolAddress = contractAddress; - const pool = await this._db.loadPool({ id: poolAddress, blockNumber }); + const pool = await this._db.getPool({ id: poolAddress, blockNumber }); + assert(pool); // TODO: In subgraph factory is fetched by hardcoded factory address. // Currently fetching first factory in database as only one exists. @@ -479,74 +511,75 @@ export class Indexer { factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD); // Burn entity. - const transaction = await loadTransaction(this._db, { txHash, blockNumber, blockTimestamp }); + const transaction = await loadTransaction(this._db, { block, tx }); - await this._db.loadBurn({ - id: transaction.id + '#' + pool.txCount.toString(), - blockNumber, - transaction, - timestamp: transaction.timestamp, - pool, - token0: pool.token0, - token1: pool.token1, - owner: burnEvent.owner, + const burn = new Burn(); + burn.id = transaction.id + '#' + pool.txCount.toString(); + burn.transaction = transaction; + burn.timestamp = transaction.timestamp; + burn.pool = pool; + burn.token0 = pool.token0; + burn.token1 = pool.token1; + burn.owner = burnEvent.owner; - // TODO: Assign origin with Transaction from address. - // origin: event.transaction.from + // TODO: Assign origin with Transaction from address. + // origin: event.transaction.from - amount: burnEvent.amount, - amount0, - amount1, - amountUSD, - tickLower: burnEvent.tickLower, - tickUpper: burnEvent.tickUpper - }); + burn.amount = burnEvent.amount; + burn.amount0 = amount0; + burn.amount1 = amount1; + burn.amountUSD = amountUSD; + burn.tickLower = burnEvent.tickLower; + burn.tickUpper = burnEvent.tickUpper; // Tick entities. const lowerTickId = poolAddress + '#' + (burnEvent.tickLower).toString(); const upperTickId = poolAddress + '#' + (burnEvent.tickUpper).toString(); - const lowerTick = await this._db.loadTick({ id: lowerTickId, blockNumber }); - const upperTick = await this._db.loadTick({ id: upperTickId, blockNumber }); + const lowerTick = await this._db.getTick({ id: lowerTickId, blockNumber }); + const upperTick = await this._db.getTick({ id: upperTickId, blockNumber }); + assert(lowerTick && upperTick); const amount = BigInt(burnEvent.amount); lowerTick.liquidityGross = BigInt(lowerTick.liquidityGross) - amount; lowerTick.liquidityNet = BigInt(lowerTick.liquidityNet) - amount; upperTick.liquidityGross = BigInt(upperTick.liquidityGross) - amount; upperTick.liquidityNet = BigInt(upperTick.liquidityNet) + amount; - await updateUniswapDayData(this._db, { blockNumber, contractAddress, blockTimestamp }); - await updatePoolDayData(this._db, { blockNumber, contractAddress, blockTimestamp }); - await updatePoolHourData(this._db, { blockNumber, contractAddress, blockTimestamp }); - await updateTokenDayData(this._db, token0, { blockNumber, blockTimestamp }); - await updateTokenDayData(this._db, token0, { blockNumber, blockTimestamp }); - await updateTokenHourData(this._db, token0, { blockNumber, blockTimestamp }); - await updateTokenHourData(this._db, token0, { blockNumber, blockTimestamp }); + await updateUniswapDayData(this._db, { block, contractAddress }); + await updatePoolDayData(this._db, { block, contractAddress }); + await updatePoolHourData(this._db, { block, contractAddress }); + await updateTokenDayData(this._db, token0, { block }); + await updateTokenDayData(this._db, token0, { block }); + await updateTokenHourData(this._db, token0, { block }); + await updateTokenHourData(this._db, token0, { block }); // Skipping update Tick fee and Tick day data as they are not queried. await Promise.all([ - await this._db.saveTick(lowerTick, blockNumber), - await this._db.saveTick(upperTick, blockNumber) + await this._db.saveTick(lowerTick, block), + await this._db.saveTick(upperTick, block) ]); await Promise.all([ - this._db.saveToken(token0, blockNumber), - this._db.saveToken(token1, blockNumber) + this._db.saveToken(token0, block), + this._db.saveToken(token1, block) ]); - await this._db.savePool(pool, blockNumber); - await this._db.saveFactory(factory, blockNumber); + await this._db.savePool(pool, block); + await this._db.saveFactory(factory, block); + await this._db.saveBurn(burn, block); } async _handleSwap (block: Block, contractAddress: string, tx: Transaction, swapEvent: SwapEvent): Promise { - const { number: blockNumber, timestamp: blockTimestamp } = block; - const { hash: txHash } = tx; - const bundle = await this._db.loadBundle({ id: '1', blockNumber }); + const { number: blockNumber } = block; + const bundle = await this._db.getBundle({ id: '1', blockNumber }); + assert(bundle); // TODO: In subgraph factory is fetched by hardcoded factory address. // Currently fetching first factory in database as only one exists. const [factory] = await this._db.getFactories({ blockNumber }, { limit: 1 }); - const pool = await this._db.loadPool({ id: contractAddress, blockNumber }); + const pool = await this._db.getPool({ id: contractAddress, blockNumber }); + assert(pool); // Hot fix for bad pricing. if (pool.id === '0x9663f2ca0454accad3e094448ea6f77443880454') { @@ -637,11 +670,11 @@ export class Indexer { const prices = sqrtPriceX96ToTokenPrices(pool.sqrtPrice, token0 as Token, token1 as Token); pool.token0Price = prices[0]; pool.token1Price = prices[1]; - this._db.savePool(pool, blockNumber); + this._db.savePool(pool, block); // Update USD pricing. bundle.ethPriceUSD = await getEthPriceInUSD(this._db); - this._db.saveBundle(bundle, blockNumber); + this._db.saveBundle(bundle, block); token0.derivedETH = await findEthPerToken(token0); token1.derivedETH = await findEthPerToken(token1); @@ -661,39 +694,37 @@ export class Indexer { token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH).times(bundle.ethPriceUSD); // Create Swap event - const transaction = await loadTransaction(this._db, { txHash, blockNumber, blockTimestamp }); + const transaction = await loadTransaction(this._db, { block, tx }); - await this._db.loadSwap({ - id: transaction.id + '#' + pool.txCount.toString(), - blockNumber, - transaction, - timestamp: transaction.timestamp, - pool, - token0: pool.token0, - token1: pool.token1, - sender: swapEvent.sender, + const swap = new Swap(); + swap.id = transaction.id + '#' + pool.txCount.toString(); + swap.transaction = transaction; + swap.timestamp = transaction.timestamp; + swap.pool = pool; + swap.token0 = pool.token0; + swap.token1 = pool.token1; + swap.sender = swapEvent.sender; - // TODO: Assign origin with Transaction from address. - // origin: event.transaction.from + // TODO: Assign origin with Transaction from address. + // origin: event.transaction.from - recipient: swapEvent.recipient, - amount0: amount0, - amount1: amount1, - amountUSD: amountTotalUSDTracked, - tick: BigInt(swapEvent.tick), - sqrtPriceX96: swapEvent.sqrtPriceX96 - }); + swap.recipient = swapEvent.recipient; + swap.amount0 = amount0; + swap.amount1 = amount1; + swap.amountUSD = amountTotalUSDTracked; + swap.tick = BigInt(swapEvent.tick); + swap.sqrtPriceX96 = swapEvent.sqrtPriceX96; // Skipping update pool fee growth as they are not queried. // Interval data. - const uniswapDayData = await updateUniswapDayData(this._db, { blockNumber, contractAddress, blockTimestamp }); - const poolDayData = await updatePoolDayData(this._db, { blockNumber, contractAddress, blockTimestamp }); - const poolHourData = await updatePoolHourData(this._db, { blockNumber, contractAddress, blockTimestamp }); - const token0DayData = await updateTokenDayData(this._db, token0, { blockNumber, blockTimestamp }); - const token1DayData = await updateTokenDayData(this._db, token0, { blockNumber, blockTimestamp }); - const token0HourData = await updateTokenHourData(this._db, token0, { blockNumber, blockTimestamp }); - const token1HourData = await updateTokenHourData(this._db, token0, { blockNumber, blockTimestamp }); + const uniswapDayData = await updateUniswapDayData(this._db, { block, contractAddress }); + const poolDayData = await updatePoolDayData(this._db, { block, contractAddress }); + const poolHourData = await updatePoolHourData(this._db, { block, contractAddress }); + const token0DayData = await updateTokenDayData(this._db, token0, { block }); + const token1DayData = await updateTokenDayData(this._db, token0, { block }); + const token0HourData = await updateTokenHourData(this._db, token0, { block }); + const token1HourData = await updateTokenHourData(this._db, token0, { block }); // Update volume metrics. uniswapDayData.volumeETH = uniswapDayData.volumeETH.plus(amountTotalETHTracked); @@ -730,20 +761,20 @@ export class Indexer { token1HourData.untrackedVolumeUSD = token1HourData.untrackedVolumeUSD.plus(amountTotalUSDTracked); token1HourData.feesUSD = token1HourData.feesUSD.plus(feesUSD); - this._db.saveTokenDayData(token0DayData, blockNumber); - this._db.saveTokenDayData(token1DayData, blockNumber); - this._db.saveUniswapDayData(uniswapDayData, blockNumber); - this._db.savePoolDayData(poolDayData, blockNumber); - this._db.saveFactory(factory, blockNumber); - this._db.savePool(pool, blockNumber); - this._db.saveToken(token0, blockNumber); - this._db.saveToken(token1, blockNumber); + await this._db.saveSwap(swap, block); + await this._db.saveTokenDayData(token0DayData, block); + await this._db.saveTokenDayData(token1DayData, block); + await this._db.saveUniswapDayData(uniswapDayData, block); + await this._db.savePoolDayData(poolDayData, block); + await this._db.saveFactory(factory, block); + await this._db.savePool(pool, block); + await this._db.saveToken(token0, block); + await this._db.saveToken(token1, block); // Skipping update of inner vars of current or crossed ticks as they are not queried. } async _handleIncreaseLiquidity (block: Block, contractAddress: string, tx: Transaction, event: IncreaseLiquidityEvent): Promise { - const { number: blockNumber } = block; const position = await this._getPosition(block, contractAddress, tx, BigInt(event.tokenId)); // position was not able to be fetched. @@ -768,14 +799,13 @@ export class Indexer { await this._updateFeeVars(position, block, contractAddress, BigInt(event.tokenId)); - await this._db.savePosition(position, blockNumber); + await this._db.savePosition(position, block); await this._savePositionSnapshot(position, block, tx); } async _handleDecreaseLiquidity (block: Block, contractAddress: string, tx: Transaction, event: DecreaseLiquidityEvent): Promise { - const { number: blockNumber } = block; - const position = await this._getPosition(block, contractAddress, tx, BigInt(event.tokenId)); + let position = await this._getPosition(block, contractAddress, tx, BigInt(event.tokenId)); // Position was not able to be fetched. if (position == null) { @@ -796,15 +826,14 @@ export class Indexer { position.depositedToken0 = position.depositedToken0.plus(amount0); position.depositedToken1 = position.depositedToken1.plus(amount1); - await this._updateFeeVars(position, block, contractAddress, BigInt(event.tokenId)); + position = await this._updateFeeVars(position, block, contractAddress, BigInt(event.tokenId)); - await this._db.savePosition(position, blockNumber); + await this._db.savePosition(position, block); await this._savePositionSnapshot(position, block, tx); } async _handleCollect (block: Block, contractAddress: string, tx: Transaction, event: CollectEvent): Promise { - const { number: blockNumber } = block; let position = await this._getPosition(block, contractAddress, tx, BigInt(event.tokenId)); // Position was not able to be fetched. @@ -826,7 +855,7 @@ export class Indexer { position = await this._updateFeeVars(position, block, contractAddress, BigInt(event.tokenId)); - await this._db.savePosition(position, blockNumber); + await this._db.savePosition(position, block); await this._savePositionSnapshot(position, block, tx); } @@ -839,14 +868,13 @@ export class Indexer { } position.owner = event.to; - await this._db.savePosition(position, block.number); + await this._db.savePosition(position, block); await this._savePositionSnapshot(position, block, tx); } async _getPosition (block: Block, contractAddress: string, tx: Transaction, tokenId: bigint): Promise { - const { number: blockNumber, hash: blockHash, timestamp: blockTimestamp } = block; - const { hash: txHash } = tx; + const { number: blockNumber, hash: blockHash } = block; let position = await this._db.getPosition({ id: tokenId.toString(), blockNumber }); if (!position) { @@ -861,31 +889,36 @@ export class Indexer { const { pool: poolAddress } = await this._uniClient.getPool(blockHash, token0Address, token1Address, fee); - const transaction = await loadTransaction(this._db, { txHash, blockNumber, blockTimestamp }); + position = new Position(); + position.id = tokenId.toString(); + const pool = await this._db.getPool({ id: poolAddress, blockNumber }); + assert(pool); + position.pool = pool; const [token0, token1] = await Promise.all([ this._db.getToken({ id: token0Address, blockNumber }), this._db.getToken({ id: token0Address, blockNumber }) ]); + assert(token0 && token1); + position.token0 = token0; + position.token1 = token1; const [tickLower, tickUpper] = await Promise.all([ this._db.getTick({ id: poolAddress.concat('#').concat(nfpmPosition.tickLower.toString()), blockNumber }), this._db.getTick({ id: poolAddress.concat('#').concat(nfpmPosition.tickUpper.toString()), blockNumber }) ]); + assert(tickLower && tickUpper); + position.tickLower = tickLower; + position.tickUpper = tickUpper; - position = await this._db.loadPosition({ - id: tokenId.toString(), - blockNumber, - pool, - token0, - token1, - tickLower, - tickUpper, - transaction, - feeGrowthInside0LastX128: BigInt(nfpmPosition.feeGrowthInside0LastX128.toString()), - feeGrowthInside1LastX128: BigInt(nfpmPosition.feeGrowthInside1LastX128.toString()) - }); + const transaction = await loadTransaction(this._db, { block, tx }); + position.transaction = transaction; + + position.feeGrowthInside0LastX128 = BigInt(nfpmPosition.feeGrowthInside0LastX128.toString()); + position.feeGrowthInside1LastX128 = BigInt(nfpmPosition.feeGrowthInside1LastX128.toString()); + + position = await this._db.savePosition(position, block); } } @@ -904,25 +937,24 @@ export class Indexer { } async _savePositionSnapshot (position: Position, block: Block, tx: Transaction): Promise { - const transaction = await loadTransaction(this._db, { txHash: tx.hash, blockNumber: block.number, blockTimestamp: block.timestamp }); + const positionSnapshot = new PositionSnapshot(); + positionSnapshot.id = position.id.concat('#').concat(block.number.toString()); + positionSnapshot.blockNumber = block.number; + positionSnapshot.owner = position.owner; + positionSnapshot.pool = position.pool; + positionSnapshot.position = position; + positionSnapshot.timestamp = BigInt(block.timestamp); + positionSnapshot.liquidity = position.liquidity; + positionSnapshot.depositedToken0 = position.depositedToken0; + positionSnapshot.depositedToken1 = position.depositedToken1; + positionSnapshot.withdrawnToken0 = position.withdrawnToken0; + positionSnapshot.withdrawnToken1 = position.withdrawnToken1; + positionSnapshot.collectedFeesToken0 = position.collectedFeesToken0; + positionSnapshot.collectedFeesToken1 = position.collectedFeesToken1; + positionSnapshot.transaction = await loadTransaction(this._db, { block, tx }); + positionSnapshot.feeGrowthInside0LastX128 = position.feeGrowthInside0LastX128; + positionSnapshot.feeGrowthInside1LastX128 = position.feeGrowthInside1LastX128; - await this._db.loadPositionSnapshot({ - id: position.id.concat('#').concat(block.number.toString()), - blockNumber: block.number, - owner: position.owner, - pool: position.pool, - position: position, - timestamp: block.timestamp, - liquidity: position.liquidity, - depositedToken0: position.depositedToken0, - depositedToken1: position.depositedToken1, - withdrawnToken0: position.withdrawnToken0, - withdrawnToken1: position.withdrawnToken1, - collectedFeesToken0: position.collectedFeesToken0, - collectedFeesToken1: position.collectedFeesToken1, - transaction, - feeGrowthInside0LastX128: position.feeGrowthInside0LastX128, - feeGrowthInside1LastX128: position.feeGrowthInside1LastX128 - }); + await this._db.savePositionSnapshot(positionSnapshot, block); } } diff --git a/packages/uni-info-watcher/src/utils/index.ts b/packages/uni-info-watcher/src/utils/index.ts index 1b0d49db..8b48ef93 100644 --- a/packages/uni-info-watcher/src/utils/index.ts +++ b/packages/uni-info-watcher/src/utils/index.ts @@ -1,8 +1,9 @@ import Decimal from 'decimal.js'; import { BigNumber } from 'ethers'; -import { Transaction } from '../entity/Transaction'; +import { Transaction as TransactionEntity } from '../entity/Transaction'; import { Database } from '../database'; +import { Block, Transaction } from '../events'; export const exponentToBigDecimal = (decimals: bigint): Decimal => { let bd = new Decimal(1); @@ -22,19 +23,19 @@ export const convertTokenToDecimal = (tokenAmount: bigint, exchangeDecimals: big return (new Decimal(tokenAmount.toString())).div(exponentToBigDecimal(exchangeDecimals)); }; -export const loadTransaction = async (db: Database, event: { txHash: string, blockNumber: number, blockTimestamp: number }): Promise => { - const { txHash, blockNumber, blockTimestamp } = event; +export const loadTransaction = async (db: Database, event: { block: Block, tx: Transaction }): Promise => { + const { tx, block } = event; + let transaction = await db.getTransaction({ id: tx.hash, blockNumber: block.number }); - const transaction = await db.loadTransaction({ - id: txHash, - blockNumber, - timestamp: BigInt(blockTimestamp) - }); + if (!transaction) { + transaction = new TransactionEntity(); + transaction.id = tx.hash; + } - transaction.blockNumber = blockNumber; - transaction.timestamp = BigInt(blockTimestamp); + transaction.blockNumber = block.number; + transaction.timestamp = BigInt(block.timestamp); - return db.saveTransaction(transaction, blockNumber); + return db.saveTransaction(transaction, block); }; // Return 0 if denominator is 0 in division. diff --git a/packages/uni-info-watcher/src/utils/interval-updates.ts b/packages/uni-info-watcher/src/utils/interval-updates.ts index f2eb1f43..6ccc0768 100644 --- a/packages/uni-info-watcher/src/utils/interval-updates.ts +++ b/packages/uni-info-watcher/src/utils/interval-updates.ts @@ -1,3 +1,4 @@ +import assert from 'assert'; import { BigNumber } from 'ethers'; import { Database } from '../database'; @@ -7,56 +8,63 @@ import { Token } from '../entity/Token'; import { TokenDayData } from '../entity/TokenDayData'; import { TokenHourData } from '../entity/TokenHourData'; import { UniswapDayData } from '../entity/UniswapDayData'; +import { Block } from '../events'; /** * Tracks global aggregate data over daily windows. * @param db * @param event */ -export const updateUniswapDayData = async (db: Database, event: { contractAddress: string, blockNumber: number, blockTimestamp: number }): Promise => { - const { blockNumber, blockTimestamp } = event; +export const updateUniswapDayData = async (db: Database, event: { contractAddress: string, block: Block }): Promise => { + const { block } = event; // TODO: In subgraph factory is fetched by hardcoded factory address. // Currently fetching first factory in database as only one exists. - const [factory] = await db.getFactories({ blockNumber }, { limit: 1 }); + const [factory] = await db.getFactories({ blockNumber: block.number }, { limit: 1 }); - const dayID = Math.floor(blockTimestamp / 86400); // Rounded. + const dayID = Math.floor(block.timestamp / 86400); // Rounded. const dayStartTimestamp = dayID * 86400; - const uniswapDayData = await db.loadUniswapDayData({ - id: dayID.toString(), - blockNumber, - date: dayStartTimestamp, - tvlUSD: factory.totalValueLockedUSD, - txCount: factory.txCount - }); + let uniswapDayData = await db.getUniswapDayData({ id: dayID.toString(), blockNumber: block.number }); + + if (!uniswapDayData) { + uniswapDayData = new UniswapDayData(); + uniswapDayData.id = dayID.toString(); + uniswapDayData.date = dayStartTimestamp; + uniswapDayData.tvlUSD = factory.totalValueLockedUSD; + uniswapDayData.txCount = factory.txCount; + } uniswapDayData.tvlUSD = factory.totalValueLockedUSD; uniswapDayData.txCount = factory.txCount; - return db.saveUniswapDayData(uniswapDayData, blockNumber); + return db.saveUniswapDayData(uniswapDayData, block); }; -export const updatePoolDayData = async (db: Database, event: { contractAddress: string, blockNumber: number, blockTimestamp: number }): Promise => { - const { contractAddress, blockNumber, blockTimestamp } = event; - const dayID = Math.floor(blockTimestamp / 86400); +export const updatePoolDayData = async (db: Database, event: { contractAddress: string, block: Block }): Promise => { + const { contractAddress, block } = event; + const dayID = Math.floor(block.timestamp / 86400); const dayStartTimestamp = dayID * 86400; const dayPoolID = contractAddress .concat('-') .concat(dayID.toString()); - const pool = await db.loadPool({ id: contractAddress, blockNumber }); + const pool = await db.getPool({ id: contractAddress, blockNumber: block.number }); + assert(pool); - let poolDayData = await db.loadPoolDayData({ - id: dayPoolID, - blockNumber, - date: dayStartTimestamp, - pool: pool, - open: pool.token0Price, - high: pool.token0Price, - low: pool.token0Price, - close: pool.token0Price - }); + let poolDayData = await db.getPoolDayData({ id: dayPoolID, blockNumber: block.number }); + + if (!poolDayData) { + poolDayData = new PoolDayData(); + poolDayData.id = dayPoolID; + poolDayData.date = dayStartTimestamp; + poolDayData.pool = pool; + poolDayData.open = pool.token0Price; + poolDayData.high = pool.token0Price; + poolDayData.low = pool.token0Price; + poolDayData.close = pool.token0Price; + poolDayData = await db.savePoolDayData(poolDayData, block); + } if (Number(pool.token0Price) > Number(poolDayData.high)) { poolDayData.high = pool.token0Price; @@ -75,32 +83,36 @@ export const updatePoolDayData = async (db: Database, event: { contractAddress: poolDayData.tick = pool.tick; poolDayData.tvlUSD = pool.totalValueLockedUSD; poolDayData.txCount = BigInt(BigNumber.from(poolDayData.txCount).add(1).toHexString()); - poolDayData = await db.savePoolDayData(poolDayData, blockNumber); + poolDayData = await db.savePoolDayData(poolDayData, block); return poolDayData; }; -export const updatePoolHourData = async (db: Database, event: { contractAddress: string, blockNumber: number, blockTimestamp: number }): Promise => { - const { contractAddress, blockNumber, blockTimestamp } = event; - const hourIndex = Math.floor(blockTimestamp / 3600); // Get unique hour within unix history. +export const updatePoolHourData = async (db: Database, event: { contractAddress: string, block: Block }): Promise => { + const { contractAddress, block } = event; + const hourIndex = Math.floor(block.timestamp / 3600); // Get unique hour within unix history. const hourStartUnix = hourIndex * 3600; // Want the rounded effect. const hourPoolID = contractAddress .concat('-') .concat(hourIndex.toString()); - const pool = await db.loadPool({ id: contractAddress, blockNumber }); + const pool = await db.getPool({ id: contractAddress, blockNumber: block.number }); + assert(pool); - let poolHourData = await db.loadPoolHourData({ - id: hourPoolID, - blockNumber, - periodStartUnix: hourStartUnix, - pool: pool, - open: pool.token0Price, - high: pool.token0Price, - low: pool.token0Price, - close: pool.token0Price - }); + let poolHourData = await db.getPoolHourData({ id: hourPoolID, blockNumber: block.number }); + + if (!poolHourData) { + poolHourData = new PoolHourData(); + poolHourData.id = hourPoolID; + poolHourData.periodStartUnix = hourStartUnix; + poolHourData.pool = pool; + poolHourData.open = pool.token0Price; + poolHourData.high = pool.token0Price; + poolHourData.low = pool.token0Price; + poolHourData.close = pool.token0Price; + poolHourData = await db.savePoolHourData(poolHourData, block); + } if (Number(pool.token0Price) > Number(poolHourData.high)) { poolHourData.high = pool.token0Price; @@ -119,15 +131,16 @@ export const updatePoolHourData = async (db: Database, event: { contractAddress: poolHourData.tick = pool.tick; poolHourData.tvlUSD = pool.totalValueLockedUSD; poolHourData.txCount = BigInt(BigNumber.from(poolHourData.txCount).add(1).toHexString()); - poolHourData = await db.savePoolHourData(poolHourData, blockNumber); + poolHourData = await db.savePoolHourData(poolHourData, block); return poolHourData; }; -export const updateTokenDayData = async (db: Database, token: Token, event: { blockNumber: number, blockTimestamp: number }): Promise => { - const { blockNumber, blockTimestamp } = event; - const bundle = await db.loadBundle({ id: '1', blockNumber }); - const dayID = Math.floor(blockTimestamp / 86400); +export const updateTokenDayData = async (db: Database, token: Token, event: { block: Block }): Promise => { + const { block } = event; + const bundle = await db.getBundle({ id: '1', blockNumber: block.number }); + assert(bundle); + const dayID = Math.floor(block.timestamp / 86400); const dayStartTimestamp = dayID * 86400; const tokenDayID = token.id @@ -136,19 +149,21 @@ export const updateTokenDayData = async (db: Database, token: Token, event: { bl const tokenPrice = token.derivedETH.times(bundle.ethPriceUSD); - const tokenDayData = await db.loadTokenDayData({ - id: tokenDayID, - blockNumber, - date: dayStartTimestamp, - token, - open: tokenPrice, - high: tokenPrice, - low: tokenPrice, - close: tokenPrice, - priceUSD: token.derivedETH.times(bundle.ethPriceUSD), - totalValueLocked: token.totalValueLocked, - totalValueLockedUSD: token.totalValueLockedUSD - }); + let tokenDayData = await db.getTokenDayData({ id: tokenDayID, blockNumber: block.number }); + + if (!tokenDayData) { + tokenDayData = new TokenDayData(); + tokenDayData.id = tokenDayID; + tokenDayData.date = dayStartTimestamp; + tokenDayData.token = token; + tokenDayData.open = tokenPrice; + tokenDayData.high = tokenPrice; + tokenDayData.low = tokenPrice; + tokenDayData.close = tokenPrice; + tokenDayData.priceUSD = token.derivedETH.times(bundle.ethPriceUSD); + tokenDayData.totalValueLocked = token.totalValueLocked; + tokenDayData.totalValueLockedUSD = token.totalValueLockedUSD; + } if (tokenPrice.gt(tokenDayData.high)) { tokenDayData.high = tokenPrice; @@ -162,13 +177,14 @@ export const updateTokenDayData = async (db: Database, token: Token, event: { bl tokenDayData.priceUSD = token.derivedETH.times(bundle.ethPriceUSD); tokenDayData.totalValueLocked = token.totalValueLocked; tokenDayData.totalValueLockedUSD = token.totalValueLockedUSD; - return db.saveTokenDayData(tokenDayData, blockNumber); + return db.saveTokenDayData(tokenDayData, block); }; -export const updateTokenHourData = async (db: Database, token: Token, event: { blockNumber: number, blockTimestamp: number }): Promise => { - const { blockNumber, blockTimestamp } = event; - const bundle = await db.loadBundle({ id: '1', blockNumber }); - const hourIndex = Math.floor(blockTimestamp / 3600); // Get unique hour within unix history. +export const updateTokenHourData = async (db: Database, token: Token, event: { block: Block }): Promise => { + const { block } = event; + const bundle = await db.getBundle({ id: '1', blockNumber: block.number }); + assert(bundle); + const hourIndex = Math.floor(block.timestamp / 3600); // Get unique hour within unix history. const hourStartUnix = hourIndex * 3600; // Want the rounded effect. const tokenHourID = token.id @@ -177,19 +193,21 @@ export const updateTokenHourData = async (db: Database, token: Token, event: { b const tokenPrice = token.derivedETH.times(bundle.ethPriceUSD); - const tokenHourData = await db.loadTokenHourData({ - id: tokenHourID, - blockNumber, - periodStartUnix: hourStartUnix, - token: token, - open: tokenPrice, - high: tokenPrice, - low: tokenPrice, - close: tokenPrice, - priceUSD: tokenPrice, - totalValueLocked: token.totalValueLocked, - totalValueLockedUSD: token.totalValueLockedUSD - }); + let tokenHourData = await db.getTokenHourData({ id: tokenHourID, blockNumber: block.number }); + + if (!tokenHourData) { + tokenHourData = new TokenHourData(); + tokenHourData.id = tokenHourID; + tokenHourData.periodStartUnix = hourStartUnix; + tokenHourData.token = token; + tokenHourData.open = tokenPrice; + tokenHourData.high = tokenPrice; + tokenHourData.low = tokenPrice; + tokenHourData.close = tokenPrice; + tokenHourData.priceUSD = tokenPrice; + tokenHourData.totalValueLocked = token.totalValueLocked; + tokenHourData.totalValueLockedUSD = token.totalValueLockedUSD; + } if (tokenPrice.gt(tokenHourData.high)) { tokenHourData.high = tokenPrice; @@ -203,5 +221,5 @@ export const updateTokenHourData = async (db: Database, token: Token, event: { b tokenHourData.priceUSD = tokenPrice; tokenHourData.totalValueLocked = token.totalValueLocked; tokenHourData.totalValueLockedUSD = token.totalValueLockedUSD; - return db.saveTokenHourData(tokenHourData, blockNumber); + return db.saveTokenHourData(tokenHourData, block); }; diff --git a/packages/uni-info-watcher/src/utils/pricing.ts b/packages/uni-info-watcher/src/utils/pricing.ts index 1f325dcb..9ac7950a 100644 --- a/packages/uni-info-watcher/src/utils/pricing.ts +++ b/packages/uni-info-watcher/src/utils/pricing.ts @@ -1,3 +1,4 @@ +import assert from 'assert'; import Decimal from 'decimal.js'; import { BigNumber } from 'ethers'; @@ -125,7 +126,8 @@ export const getTrackedAmountUSD = async ( tokenAmount1: Decimal, token1: Token ): Promise => { - const bundle = await db.loadBundle({ id: '1' }); + const bundle = await db.getBundle({ id: '1' }); + assert(bundle); const price0USD = token0.derivedETH.times(bundle.ethPriceUSD); const price1USD = token1.derivedETH.times(bundle.ethPriceUSD); diff --git a/packages/uni-info-watcher/src/utils/tick.ts b/packages/uni-info-watcher/src/utils/tick.ts index b435349f..cbadea5b 100644 --- a/packages/uni-info-watcher/src/utils/tick.ts +++ b/packages/uni-info-watcher/src/utils/tick.ts @@ -4,18 +4,20 @@ import { Pool } from '../entity/Pool'; import { Database } from '../database'; import { bigDecimalExponated, safeDiv } from '.'; import { Tick } from '../entity/Tick'; +import { Block } from '../events'; + +export const createTick = async (db: Database, tickId: string, tickIdx: bigint, pool: Pool, block: Block): Promise => { + const tick = new Tick(); + tick.id = tickId; + tick.tickIdx = tickIdx; + tick.pool = pool; + tick.poolAddress = pool.id; -export const loadTick = async (db: Database, tickId: string, tickIdx: bigint, pool: Pool, blockNumber: number): Promise => { // 1.0001^tick is token1/token0. const price0 = bigDecimalExponated(new Decimal('1.0001'), tickIdx); - return db.loadTick({ - id: tickId, - blockNumber, - tickIdx: tickIdx, - pool, - poolAddress: pool.id, - price0, - price1: safeDiv(new Decimal(1), price0) - }); + tick.price0 = price0; + tick.price1 = safeDiv(new Decimal(1), price0); + + return db.saveTick(tick, block); };