Skip to content

Commit

Permalink
Implement changes at graft block height (#6)
Browse files Browse the repository at this point in the history
* Implement changes at graft block

* Implement workarounds to fix mismatches

* Add unique query for transaction table

* Apply where condition for id in inner subquery
  • Loading branch information
nikugogoi authored and prathamesh0 committed Nov 3, 2022
1 parent ca75248 commit d8e9327
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 47 deletions.
6 changes: 3 additions & 3 deletions packages/uni-info-watcher/src/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ export interface CachedEntities {
const ENTITY_QUERY_TYPE_MAP = new Map<new() => any, ENTITY_QUERY_TYPE>([
[Bundle, ENTITY_QUERY_TYPE.SINGULAR],
[Factory, ENTITY_QUERY_TYPE.SINGULAR],
[Pool, ENTITY_QUERY_TYPE.DISTINCT_ON],
[Token, ENTITY_QUERY_TYPE.DISTINCT_ON],
[Pool, ENTITY_QUERY_TYPE.GROUP_BY],
[Token, ENTITY_QUERY_TYPE.GROUP_BY],
[Burn, ENTITY_QUERY_TYPE.DISTINCT_ON],
[Mint, ENTITY_QUERY_TYPE.DISTINCT_ON],
[Swap, ENTITY_QUERY_TYPE.DISTINCT_ON],
[Transaction, ENTITY_QUERY_TYPE.DISTINCT_ON],
[Transaction, ENTITY_QUERY_TYPE.UNIQUE],
[TokenDayData, ENTITY_QUERY_TYPE.DISTINCT_ON],
[TokenHourData, ENTITY_QUERY_TYPE.DISTINCT_ON],
[PoolDayData, ENTITY_QUERY_TYPE.DISTINCT_ON],
Expand Down
37 changes: 24 additions & 13 deletions packages/uni-info-watcher/src/indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { findEthPerToken, getEthPriceInUSD, getTrackedAmountUSD, sqrtPriceX96ToT
import { updatePoolDayData, updatePoolHourData, updateTickDayData, updateTokenDayData, updateTokenHourData, updateUniswapDayData } from './utils/interval-updates';
import { convertTokenToDecimal, loadFactory, loadTransaction, safeDiv, Block } from './utils';
import { createTick, feeTierToTickSpacing } from './utils/tick';
import { ADDRESS_ZERO, FACTORY_ADDRESS, WATCHED_CONTRACTS } from './utils/constants';
import { ADDRESS_ZERO, FACTORY_ADDRESS, FIRST_GRAFT_BLOCK, WATCHED_CONTRACTS } from './utils/constants';
import { Database, DEFAULT_LIMIT } from './database';
import { Event } from './entity/Event';
import { ResultEvent, Transaction, PoolCreatedEvent, InitializeEvent, MintEvent, BurnEvent, SwapEvent, IncreaseLiquidityEvent, DecreaseLiquidityEvent, CollectEvent, TransferEvent, FlashEvent } from './events';
Expand Down Expand Up @@ -828,6 +828,13 @@ export class Indexer implements IndexerInterface {
pool.createdAtBlockNumber = BigInt(block.number);
pool = await this._db.savePool(dbTx, pool, block);

if (block.number >= 13450924) {
// Temp workaround to fix mismatch of Factory totalVolumeUSD and totalFeesUSD values with hosted subgraph endpoint
if (!WHITELIST_TOKENS.includes('0x4dd28568d05f09b02220b09c2cb307bfd837cb95')) {
WHITELIST_TOKENS.push('0x4dd28568d05f09b02220b09c2cb307bfd837cb95');
}
}

// Update white listed pools.
if (WHITELIST_TOKENS.includes(token0.id) || this._isDemo) {
token1.whitelistPools.push(pool.id);
Expand Down Expand Up @@ -1477,12 +1484,16 @@ export class Indexer implements IndexerInterface {
poolDayData.pool = pool.id;
await this._db.savePoolDayData(dbTx, poolDayData, block);

if (block.number > FIRST_GRAFT_BLOCK) {
await this._db.savePoolHourData(dbTx, poolHourData, block);
}

// Update inner vars of current or crossed ticks.
const newTick = pool.tick;
// Check that the tick value is not null (can be zero).
assert(newTick !== null);

const tickSpacing = feeTierToTickSpacing(pool.feeTier);
const tickSpacing = feeTierToTickSpacing(pool.feeTier, block);
const modulo = newTick % tickSpacing;

if (modulo === BigInt(0)) {
Expand Down Expand Up @@ -1640,7 +1651,6 @@ export class Indexer implements IndexerInterface {
position.withdrawnToken1 = position.withdrawnToken1.plus(amount1);

await this._db.savePosition(dbTx, position, block);

await this._savePositionSnapshot(dbTx, position, block, tx);
await dbTx.commitTransaction();
} catch (error) {
Expand Down Expand Up @@ -1668,21 +1678,22 @@ export class Indexer implements IndexerInterface {
const dbTx = await this._db.createTransactionRunner();

try {
const [token0, token1] = await Promise.all([
this._db.getToken(dbTx, { id: position.token0, blockHash: block.hash }),
this._db.getToken(dbTx, { id: position.token1, blockHash: block.hash })
]);
if (block.number <= FIRST_GRAFT_BLOCK) {
const [token0, token1] = await Promise.all([
this._db.getToken(dbTx, { id: position.token0, blockHash: block.hash }),
this._db.getToken(dbTx, { id: position.token1, blockHash: block.hash })
]);

assert(token0 && token1);
assert(token0 && token1);

const amount0 = convertTokenToDecimal(BigInt(event.amount0), BigInt(token0.decimals));
const amount1 = convertTokenToDecimal(BigInt(event.amount1), BigInt(token1.decimals));
const amount0 = convertTokenToDecimal(BigInt(event.amount0), BigInt(token0.decimals));
const amount1 = convertTokenToDecimal(BigInt(event.amount1), BigInt(token1.decimals));

position.collectedFeesToken0 = position.collectedFeesToken0.plus(amount0);
position.collectedFeesToken1 = position.collectedFeesToken1.plus(amount1);
position.collectedFeesToken0 = position.collectedFeesToken0.plus(amount0);
position.collectedFeesToken1 = position.collectedFeesToken1.plus(amount1);
}

await this._db.savePosition(dbTx, position, block);

await this._savePositionSnapshot(dbTx, position, block, tx);
await dbTx.commitTransaction();
} catch (error) {
Expand Down
2 changes: 2 additions & 0 deletions packages/uni-info-watcher/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export const FACTORY_ADDRESS = '0x1F98431c8aD98523631AE4a59f267346ea31F984';
export const NFPM_ADDRESS = '0xC36442b4a4522E871399CD717aBDD847Ab11FE88';
export const BUNDLE_ID = '1';

export const FIRST_GRAFT_BLOCK = 13591197;

export const WATCHED_CONTRACTS = [
{
kind: KIND_FACTORY,
Expand Down
101 changes: 71 additions & 30 deletions packages/uni-info-watcher/src/utils/pricing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { exponentToBigDecimal, safeDiv } from '.';
import { Database } from '../database';
import { Token } from '../entity/Token';
import { Block } from '../events';
import { FIRST_GRAFT_BLOCK } from './constants';

// TODO: Move constants to config.
const WETH_ADDRESS = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
Expand Down Expand Up @@ -44,7 +45,17 @@ export const WHITELIST_TOKENS: string[] = [
'0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9' // AAVE
];

const STABLE_COINS: string[] = [
'0x6b175474e89094c44da98b954eedeac495271d0f',
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
'0xdac17f958d2ee523a2206206994597c13d831ec7',
'0x0000000000085d4780b73119b644ae5ecd22b376',
'0x956f47f50a910163d8bf957cf5846d573e7f87ca',
'0x4dd28568d05f09b02220b09c2cb307bfd837cb95'
];

const MINIMUM_ETH_LOCKED = new GraphDecimal(52);
const HOT_FIX_MIN_ETH_LOCKED = new GraphDecimal(30);
const Q192 = 2 ** 192;

// Constants used in demo.
Expand Down Expand Up @@ -96,37 +107,60 @@ export const findEthPerToken = async (db: Database, dbTx: QueryRunner, token: To
let largestLiquidityETH = new GraphDecimal(0);
let priceSoFar = new GraphDecimal(0);

for (let i = 0; i < whiteList.length; ++i) {
const poolAddress = whiteList[i];
const pool = await db.getPool(dbTx, { id: poolAddress, blockHash: block.hash });
assert(pool);

if (BigNumber.from(pool.liquidity).gt(0)) {
if (pool.token0 === token.id) {
// whitelist token is token1
const token1 = await db.getToken(dbTx, { id: pool.token1, blockHash: block.hash });
assert(token1);

// get the derived ETH in pool
const ethLocked = pool.totalValueLockedToken1.times(token1.derivedETH);

if (ethLocked.gt(largestLiquidityETH) && ethLocked.gt(MINIMUM_ETH_LOCKED)) {
largestLiquidityETH = ethLocked;
// token1 per our token * Eth per token1
priceSoFar = pool.token1Price.times(token1.derivedETH);
// hardcoded fix for incorrect rates
// if whitelist includes token - get the safe price
if (block.number > FIRST_GRAFT_BLOCK && STABLE_COINS.includes(token.id)) {
const bundle = await db.getBundle(dbTx, { id: '1', blockHash: block.hash });
assert(bundle);
priceSoFar = safeDiv(new GraphDecimal(1), bundle.ethPriceUSD);
} else {
for (let i = 0; i < whiteList.length; ++i) {
const poolAddress = whiteList[i];
const pool = await db.getPool(dbTx, { id: poolAddress, blockHash: block.hash });
assert(pool);

if (BigNumber.from(pool.liquidity).gt(0)) {
if (pool.token0 === token.id) {
// whitelist token is token1
const token1 = await db.getToken(dbTx, { id: pool.token1, blockHash: block.hash });
assert(token1);

// get the derived ETH in pool
const ethLocked = pool.totalValueLockedToken1.times(token1.derivedETH);

if (
ethLocked.gt(largestLiquidityETH) &&
// Temp workaround to fix mismatch of Token derivedEth value with hosted subgraph endpoint
(
(block.number >= 13450893 && ethLocked.gt(HOT_FIX_MIN_ETH_LOCKED)) ||
(block.number >= 13450924 && token.id === '0x4dd28568d05f09b02220b09c2cb307bfd837cb95') ||
ethLocked.gt(MINIMUM_ETH_LOCKED)
)
) {
largestLiquidityETH = ethLocked;
// token1 per our token * Eth per token1
priceSoFar = pool.token1Price.times(token1.derivedETH);
}
}
}
if (pool.token1 === token.id) {
const token0 = await db.getToken(dbTx, { id: pool.token0, blockHash: block.hash });
assert(token0);

// get the derived ETH in pool
const ethLocked = pool.totalValueLockedToken0.times(token0.derivedETH);

if (ethLocked.gt(largestLiquidityETH) && ethLocked.gt(MINIMUM_ETH_LOCKED)) {
largestLiquidityETH = ethLocked;
// token0 per our token * ETH per token0
priceSoFar = pool.token0Price.times(token0.derivedETH);
if (pool.token1 === token.id) {
const token0 = await db.getToken(dbTx, { id: pool.token0, blockHash: block.hash });
assert(token0);

// get the derived ETH in pool
const ethLocked = pool.totalValueLockedToken0.times(token0.derivedETH);

if (
ethLocked.gt(largestLiquidityETH) &&
// Temp workaround to fix mismatch of Token derivedEth value with hosted subgraph endpoint
(
(block.number >= 13450893 && ethLocked.gt(HOT_FIX_MIN_ETH_LOCKED)) ||
ethLocked.gt(MINIMUM_ETH_LOCKED)
)
) {
largestLiquidityETH = ethLocked;
// token0 per our token * ETH per token0
priceSoFar = pool.token0Price.times(token0.derivedETH);
}
}
}
}
Expand Down Expand Up @@ -156,6 +190,13 @@ export const getTrackedAmountUSD = async (
const price0USD = token0.derivedETH.times(bundle.ethPriceUSD);
const price1USD = token1.derivedETH.times(bundle.ethPriceUSD);

if (block.number >= 13450924) {
// Temp workaround to fix mismatch of Factory totalVolumeUSD and totalFeesUSD values with hosted subgraph endpoint
if (!WHITELIST_TOKENS.includes('0x4dd28568d05f09b02220b09c2cb307bfd837cb95')) {
WHITELIST_TOKENS.push('0x4dd28568d05f09b02220b09c2cb307bfd837cb95');
}
}

// Both are whitelist tokens, return sum of both amounts.
// Use demo mode
if ((WHITELIST_TOKENS.includes(token0.id) && WHITELIST_TOKENS.includes(token1.id)) || isDemo) {
Expand Down
6 changes: 5 additions & 1 deletion packages/uni-info-watcher/src/utils/tick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Database } from '../database';
import { bigDecimalExponated, safeDiv } from '.';
import { Tick } from '../entity/Tick';
import { Block } from '../events';
import { FIRST_GRAFT_BLOCK } from './constants';

export const createTick = async (db: Database, dbTx: QueryRunner, tickId: string, tickIdx: bigint, pool: Pool, block: Block): Promise<Tick> => {
const tick = new Tick();
Expand All @@ -30,7 +31,7 @@ export const createTick = async (db: Database, dbTx: QueryRunner, tickId: string
return db.saveTick(dbTx, tick, block);
};

export const feeTierToTickSpacing = (feeTier: bigint): bigint => {
export const feeTierToTickSpacing = (feeTier: bigint, block: Block): bigint => {
if (feeTier === BigInt(10000)) {
return BigInt(200);
}
Expand All @@ -40,6 +41,9 @@ export const feeTierToTickSpacing = (feeTier: bigint): bigint => {
if (feeTier === BigInt(500)) {
return BigInt(10);
}
if (block.number > FIRST_GRAFT_BLOCK && feeTier === BigInt(100)) {
return BigInt(1);
}

throw Error('Unexpected fee tier');
};

0 comments on commit d8e9327

Please sign in to comment.