diff --git a/README.md b/README.md index c93b4838..f62cd116 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ Create the databases for the job queues and enable the `pgcrypto` extension on t ``` createdb address-watcher-job-queue createdb uni-watcher-job-queue +createdb uni-info-watcher-job-queue ``` ``` @@ -74,6 +75,18 @@ CREATE EXTENSION uni-watcher-job-queue=# exit ``` +``` +postgres@tesla:~$ psql -U postgres -h localhost uni-info-watcher-job-queue +Password for user postgres: +psql (12.7 (Ubuntu 12.7-1.pgdg18.04+1)) +SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off) +Type "help" for help. + +uni-info-watcher-job-queue=# CREATE EXTENSION pgcrypto; +CREATE EXTENSION +uni-info-watcher-job-queue=# exit +``` + #### Reset Reset the databases used by the watchers: diff --git a/packages/address-watcher/src/cli/watch-address.ts b/packages/address-watcher/src/cli/watch-address.ts index 6851dcf4..ab1839a1 100644 --- a/packages/address-watcher/src/cli/watch-address.ts +++ b/packages/address-watcher/src/cli/watch-address.ts @@ -7,7 +7,8 @@ import yargs from 'yargs'; import 'reflect-metadata'; import { ethers } from 'ethers'; -import { Config, getConfig } from '../config'; +import { Config, getConfig } from '@vulcanize/util'; + import { Database } from '../database'; (async () => { diff --git a/packages/uni-info-watcher/src/indexer.ts b/packages/uni-info-watcher/src/indexer.ts index 9d390f4f..2ad02512 100644 --- a/packages/uni-info-watcher/src/indexer.ts +++ b/packages/uni-info-watcher/src/indexer.ts @@ -463,8 +463,11 @@ export class Indexer implements IndexerInterface { token0.whitelistPools.push(pool); } - await this._db.saveToken(dbTx, token0, block); - await this._db.saveToken(dbTx, token1, block); + token0 = await this._db.saveToken(dbTx, token0, block); + token1 = await this._db.saveToken(dbTx, token1, block); + pool.token0 = token0; + pool.token1 = token1; + await this._db.savePool(dbTx, pool, block); await this._db.saveFactory(dbTx, factory, block); await dbTx.commitTransaction(); } catch (error) { @@ -511,7 +514,7 @@ export class Indexer implements IndexerInterface { // Update ETH price now that prices could have changed. const bundle = await this._db.getBundle(dbTx, { id: '1', blockHash: block.hash }); assert(bundle); - bundle.ethPriceUSD = await getEthPriceInUSD(this._db, dbTx, block); + bundle.ethPriceUSD = await getEthPriceInUSD(this._db, dbTx, block, this._isDemo); // Update token prices. const [token0, token1] = await Promise.all([ @@ -521,11 +524,13 @@ export class Indexer implements IndexerInterface { assert(token0 && token1, 'Pool tokens not found.'); - token0.derivedETH = await findEthPerToken(token0); - token1.derivedETH = await findEthPerToken(token1); + token0.derivedETH = await findEthPerToken(this._db, dbTx, token0, this._isDemo); + token1.derivedETH = await findEthPerToken(this._db, dbTx, token1, this._isDemo); - this._db.savePool(dbTx, pool, block); - this._db.saveBundle(dbTx, bundle, block); + pool.token0 = token0; + pool.token1 = token1; + await this._db.savePool(dbTx, pool, block); + await this._db.saveBundle(dbTx, bundle, block); await updatePoolDayData(this._db, dbTx, { contractAddress, block }); await updatePoolHourData(this._db, dbTx, { contractAddress, block }); @@ -551,15 +556,17 @@ export class Indexer implements IndexerInterface { const bundle = await this._db.getBundle(dbTx, { id: '1', blockHash: block.hash }); assert(bundle); const poolAddress = contractAddress; - const pool = await this._db.getPool(dbTx, { id: poolAddress, blockHash: block.hash }); + let pool = await this._db.getPool(dbTx, { id: poolAddress, blockHash: block.hash }); assert(pool); // 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.getModelEntities(dbTx, Factory, { hash: block.hash }, {}, { limit: 1 }); - const token0 = pool.token0; - const token1 = pool.token1; + let token0 = await this._db.getToken(dbTx, pool.token0); + let token1 = await this._db.getToken(dbTx, pool.token1); + assert(token0); + assert(token1); const amount0 = convertTokenToDecimal(BigInt(mintEvent.amount0), BigInt(token0.decimals)); const amount1 = convertTokenToDecimal(BigInt(mintEvent.amount1), BigInt(token1.decimals)); @@ -664,16 +671,24 @@ export class Indexer implements IndexerInterface { await updatePoolDayData(this._db, dbTx, { block, contractAddress }); await updatePoolHourData(this._db, dbTx, { block, contractAddress }); - await Promise.all([ + [token0, token1] = await Promise.all([ this._db.saveToken(dbTx, token0, block), this._db.saveToken(dbTx, token1, block) ]); - await this._db.savePool(dbTx, pool, block); + pool.token0 = token0; + pool.token1 = token1; + + pool = await this._db.savePool(dbTx, pool, block); await this._db.saveFactory(dbTx, factory, block); + mint.pool = pool; + mint.token0 = token0; + mint.token1 = token1; await this._db.saveMint(dbTx, mint, block); + lowerTick.pool = pool; + upperTick.pool = pool; await Promise.all([ await this._db.saveTick(dbTx, lowerTick, block), await this._db.saveTick(dbTx, upperTick, block) @@ -696,15 +711,17 @@ export class Indexer implements IndexerInterface { const bundle = await this._db.getBundle(dbTx, { id: '1', blockHash: block.hash }); assert(bundle); const poolAddress = contractAddress; - const pool = await this._db.getPool(dbTx, { id: poolAddress, blockHash: block.hash }); + let pool = await this._db.getPool(dbTx, { id: poolAddress, blockHash: block.hash }); assert(pool); // 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.getModelEntities(dbTx, Factory, { hash: block.hash }, {}, { limit: 1 }); - const token0 = pool.token0; - const token1 = pool.token1; + let token0 = await this._db.getToken(dbTx, pool.token0); + let token1 = await this._db.getToken(dbTx, pool.token1); + assert(token0); + assert(token1); const amount0 = convertTokenToDecimal(BigInt(burnEvent.amount0), BigInt(token0.decimals)); const amount1 = convertTokenToDecimal(BigInt(burnEvent.amount1), BigInt(token1.decimals)); @@ -794,21 +811,28 @@ export class Indexer implements IndexerInterface { await updatePoolDayData(this._db, dbTx, { block, contractAddress }); await updatePoolHourData(this._db, dbTx, { block, contractAddress }); - await Promise.all([ + [token0, token1] = await Promise.all([ this._db.saveToken(dbTx, token0, block), this._db.saveToken(dbTx, token1, block) ]); - await this._db.savePool(dbTx, pool, block); + pool.token0 = token0; + pool.token1 = token1; + pool = await this._db.savePool(dbTx, pool, block); await this._db.saveFactory(dbTx, factory, block); // Skipping update Tick fee and Tick day data as they are not queried. + lowerTick.pool = pool; + upperTick.pool = pool; await Promise.all([ await this._db.saveTick(dbTx, lowerTick, block), await this._db.saveTick(dbTx, upperTick, block) ]); + burn.pool = pool; + burn.token0 = token0; + burn.token1 = token1; await this._db.saveBurn(dbTx, burn, block); await dbTx.commitTransaction(); } catch (error) { @@ -823,14 +847,14 @@ export class Indexer implements IndexerInterface { const dbTx = await this._db.createTransactionRunner(); try { - const bundle = await this._db.getBundle(dbTx, { id: '1', blockHash: block.hash }); + let bundle = await this._db.getBundle(dbTx, { id: '1', blockHash: block.hash }); 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.getModelEntities(dbTx, Factory, { hash: block.hash }, {}, { limit: 1 }); - const pool = await this._db.getPool(dbTx, { id: contractAddress, blockHash: block.hash }); + let pool = await this._db.getPool(dbTx, { id: contractAddress, blockHash: block.hash }); assert(pool); // Hot fix for bad pricing. @@ -838,7 +862,7 @@ export class Indexer implements IndexerInterface { return; } - const [token0, token1] = await Promise.all([ + let [token0, token1] = await Promise.all([ this._db.getToken(dbTx, { id: pool.token0.id, blockHash: block.hash }), this._db.getToken(dbTx, { id: pool.token1.id, blockHash: block.hash }) ]); @@ -924,9 +948,10 @@ export class Indexer implements IndexerInterface { pool.token1Price = prices[1]; // Update USD pricing. - bundle.ethPriceUSD = await getEthPriceInUSD(this._db, dbTx, block); - token0.derivedETH = await findEthPerToken(token0); - token1.derivedETH = await findEthPerToken(token1); + bundle.ethPriceUSD = await getEthPriceInUSD(this._db, dbTx, block, this._isDemo); + bundle = await this._db.saveBundle(dbTx, bundle, block); + token0.derivedETH = await findEthPerToken(this._db, dbTx, token0, this._isDemo); + token1.derivedETH = await findEthPerToken(this._db, dbTx, token1, this._isDemo); /** * Things afffected by new USD rates. @@ -1008,16 +1033,31 @@ export class Indexer implements IndexerInterface { token1HourData.untrackedVolumeUSD = token1HourData.untrackedVolumeUSD.plus(amountTotalUSDTracked); token1HourData.feesUSD = token1HourData.feesUSD.plus(feesUSD); - await this._db.saveBundle(dbTx, bundle, block); + await this._db.saveFactory(dbTx, factory, block); + + [token0, token1] = await Promise.all([ + this._db.saveToken(dbTx, token0, block), + this._db.saveToken(dbTx, token1, block) + ]); + + pool.token0 = token0; + pool.token1 = token1; + pool = await this._db.savePool(dbTx, pool, block); + + swap.token0 = token0; + swap.token1 = token1; + swap.pool = pool; await this._db.saveSwap(dbTx, swap, block); + + token0DayData.token = token0; + token1DayData.token = token1; await this._db.saveTokenDayData(dbTx, token0DayData, block); await this._db.saveTokenDayData(dbTx, token1DayData, block); + await this._db.saveUniswapDayData(dbTx, uniswapDayData, block); + + poolDayData.pool = pool; await this._db.savePoolDayData(dbTx, poolDayData, block); - await this._db.saveFactory(dbTx, factory, block); - await this._db.savePool(dbTx, pool, block); - await this._db.saveToken(dbTx, token0, block); - await this._db.saveToken(dbTx, token1, block); // Skipping update of inner vars of current or crossed ticks as they are not queried. await dbTx.commitTransaction(); diff --git a/packages/uni-info-watcher/src/resolvers.ts b/packages/uni-info-watcher/src/resolvers.ts index cc138fcb..88621a4a 100644 --- a/packages/uni-info-watcher/src/resolvers.ts +++ b/packages/uni-info-watcher/src/resolvers.ts @@ -117,7 +117,7 @@ export const createResolvers = async (indexer: Indexer, eventWatcher: EventWatch tokens: async (_: any, { block = {}, first, orderBy, orderDirection, where }: { block: BlockHeight, first: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => { log('tokens', orderBy, orderDirection, where); - return indexer.getEntities(Token, block, where, { limit: first, orderBy, orderDirection }); + return indexer.getEntities(Token, block, where, { limit: first, orderBy, orderDirection }, ['token.whitelistPools']); }, tokenDayDatas: async (_: any, { first, skip, orderBy, orderDirection, where }: { first: number, skip: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => { diff --git a/packages/uni-info-watcher/src/schema.ts b/packages/uni-info-watcher/src/schema.ts index c8cce5d8..62ef2be7 100644 --- a/packages/uni-info-watcher/src/schema.ts +++ b/packages/uni-info-watcher/src/schema.ts @@ -120,6 +120,7 @@ type Token { txCount: BigInt! volume: BigDecimal! volumeUSD: BigDecimal! + whitelistPools: [Pool] } type TokenDayData { diff --git a/packages/uni-info-watcher/src/utils/pricing.ts b/packages/uni-info-watcher/src/utils/pricing.ts index 055ddbf1..6a77419e 100644 --- a/packages/uni-info-watcher/src/utils/pricing.ts +++ b/packages/uni-info-watcher/src/utils/pricing.ts @@ -46,6 +46,9 @@ export const WHITELIST_TOKENS: string[] = [ const MINIMUM_ETH_LOCKED = new Decimal(52); const Q192 = 2 ** 192; +// Constants used in demo. +const ETH_PRICE_IN_USD = '3200.00'; + export const sqrtPriceX96ToTokenPrices = (sqrtPriceX96: bigint, token0: Token, token1: Token): Decimal[] => { const num = new Decimal((sqrtPriceX96 * sqrtPriceX96).toString()); const denom = new Decimal(Q192.toString()); @@ -60,7 +63,13 @@ export const sqrtPriceX96ToTokenPrices = (sqrtPriceX96: bigint, token0: Token, t return [price0, price1]; }; -export const getEthPriceInUSD = async (db: Database, dbTx: QueryRunner, block: Block): Promise => { +export const getEthPriceInUSD = async (db: Database, dbTx: QueryRunner, block: Block, isDemo: boolean): Promise => { + if (isDemo) { + // For demo purpose in local development. + const ethPriceInUSD = new Decimal(ETH_PRICE_IN_USD); + return ethPriceInUSD; + } + // Fetch eth prices for each stablecoin. const usdcPool = await db.getPool(dbTx, { id: USDC_WETH_03_POOL, blockHash: block.hash }); // DAI is token0. @@ -75,8 +84,8 @@ export const getEthPriceInUSD = async (db: Database, dbTx: QueryRunner, block: B * Search through graph to find derived Eth per token. * @todo update to be derived ETH (add stablecoin estimates) **/ -export const findEthPerToken = async (token: Token): Promise => { - if (token.id === WETH_ADDRESS) { +export const findEthPerToken = async (db: Database, dbTx: QueryRunner, token: Token, isDemo: boolean): Promise => { + if (token.id === WETH_ADDRESS || isDemo) { return new Decimal(1); } @@ -87,7 +96,9 @@ export const findEthPerToken = async (token: Token): Promise => { let priceSoFar = new Decimal(0); for (let i = 0; i < whiteList.length; ++i) { - const pool = whiteList[i]; + const poolAddress = whiteList[i].id; + const pool = await db.getPool(dbTx, { id: poolAddress }); + assert(pool); if (BigNumber.from(pool.liquidity).gt(0)) { if (pool.token0.id === token.id) {