mirror of
https://github.com/cerc-io/watcher-ts
synced 2024-11-19 20:36:19 +00:00
Handle swap event (#138)
* Create Swap entity. * Update day and hour interval data in Swap event handler. Co-authored-by: nabarun <nabarun@deepstacksoft.com>
This commit is contained in:
parent
03ceb95a1b
commit
ecfa3ed386
@ -17,6 +17,7 @@ import { Tick } from './entity/Tick';
|
||||
import { TokenDayData } from './entity/TokenDayData';
|
||||
import { TokenHourData } from './entity/TokenHourData';
|
||||
import { Burn } from './entity/Burn';
|
||||
import { Swap } from './entity/Swap';
|
||||
|
||||
export class Database {
|
||||
_config: ConnectionOptions
|
||||
@ -322,6 +323,29 @@ export class Database {
|
||||
});
|
||||
}
|
||||
|
||||
async loadSwap ({ id, blockNumber, ...values }:DeepPartial<Swap>): Promise<Swap> {
|
||||
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<Tick>): Promise<Tick> {
|
||||
return this._conn.transaction(async (tx) => {
|
||||
const repo = tx.getRepository(Tick);
|
||||
|
@ -22,5 +22,20 @@ export class Factory {
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
totalValueLockedUSD!: Decimal;
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
totalVolumeUSD!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
totalVolumeETH!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
totalFeesUSD!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
totalFeesETH!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
untrackedVolumeUSD!: Decimal
|
||||
|
||||
// TODO: Add remaining fields when they are used.
|
||||
}
|
||||
|
@ -57,5 +57,20 @@ export class Pool {
|
||||
@Column('bigint', { default: BigInt(0) })
|
||||
txCount!: bigint;
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volumeToken0!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volumeToken1!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volumeUSD!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
untrackedVolumeUSD!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
feesUSD!: Decimal
|
||||
|
||||
// TODO: Add remaining fields when they are used.
|
||||
}
|
||||
|
@ -57,5 +57,17 @@ export class PoolDayData {
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
txCount!: bigint
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volumeToken0!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volumeToken1!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volumeUSD!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
feesUSD!: Decimal
|
||||
|
||||
// TODO: Add remaining fields when they are used.
|
||||
}
|
||||
|
@ -57,5 +57,17 @@ export class PoolHourData {
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
txCount!: bigint
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volumeToken0!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volumeToken1!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volumeUSD!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
feesUSD!: Decimal
|
||||
|
||||
// TODO: Add remaining fields when they are used.
|
||||
}
|
||||
|
56
packages/uni-info-watcher/src/entity/Swap.ts
Normal file
56
packages/uni-info-watcher/src/entity/Swap.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import Decimal from 'decimal.js';
|
||||
import { decimalTransformer } from '@vulcanize/util';
|
||||
|
||||
import { Transaction } from './Transaction';
|
||||
import { Pool } from './Pool';
|
||||
import { Token } from './Token';
|
||||
|
||||
@Entity()
|
||||
export class Swap {
|
||||
@PrimaryColumn('varchar')
|
||||
id!: string;
|
||||
|
||||
@PrimaryColumn('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@ManyToOne(() => Transaction, transaction => transaction.mints)
|
||||
transaction!: Transaction
|
||||
|
||||
@Column('bigint')
|
||||
timestamp!: BigInt;
|
||||
|
||||
@ManyToOne(() => Pool)
|
||||
pool!: Pool
|
||||
|
||||
@ManyToOne(() => Token)
|
||||
token0!: Token
|
||||
|
||||
@ManyToOne(() => Token)
|
||||
token1!: Token
|
||||
|
||||
@Column('varchar', { length: 42 })
|
||||
sender!: string
|
||||
|
||||
// TODO: Assign origin with Transaction from address.
|
||||
// @Column('varchar', { length: 42 })
|
||||
// origin!: string
|
||||
|
||||
@Column('varchar', { length: 42 })
|
||||
recipient!: string
|
||||
|
||||
@Column('numeric', { transformer: decimalTransformer })
|
||||
amount0!: Decimal
|
||||
|
||||
@Column('numeric', { transformer: decimalTransformer })
|
||||
amount1!: Decimal
|
||||
|
||||
@Column('numeric', { transformer: decimalTransformer })
|
||||
amountUSD!: Decimal
|
||||
|
||||
@Column('bigint')
|
||||
tick!: bigint
|
||||
|
||||
@Column('bigint')
|
||||
sqrtPriceX96!: bigint
|
||||
}
|
@ -37,6 +37,18 @@ export class Token {
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
totalValueLockedUSD!: Decimal;
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volume!: Decimal;
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volumeUSD!: Decimal;
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
untrackedVolumeUSD!: Decimal;
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
feesUSD!: Decimal;
|
||||
|
||||
@ManyToMany(() => Pool)
|
||||
@JoinTable()
|
||||
whitelistPools!: Pool[];
|
||||
|
@ -41,4 +41,13 @@ export class TokenDayData {
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volumeUSD!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volume!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
untrackedVolumeUSD!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
feesUSD!: Decimal
|
||||
}
|
||||
|
@ -38,4 +38,16 @@ export class TokenHourData {
|
||||
|
||||
@Column('numeric', { transformer: decimalTransformer })
|
||||
totalValueLockedUSD!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volumeUSD!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
volume!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
untrackedVolumeUSD!: Decimal
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
feesUSD!: Decimal
|
||||
}
|
||||
|
@ -21,4 +21,10 @@ export class UniswapDayData {
|
||||
|
||||
@Column('bigint')
|
||||
txCount!: bigint;
|
||||
|
||||
@Column('numeric', { transformer: decimalTransformer, default: 0 })
|
||||
volumeETH!: Decimal
|
||||
|
||||
@Column('numeric', { transformer: decimalTransformer, default: 0 })
|
||||
feesUSD!: Decimal
|
||||
}
|
||||
|
@ -5,11 +5,12 @@ import { Client as ERC20Client } from '@vulcanize/erc20-watcher';
|
||||
import { BigNumber } from 'ethers';
|
||||
|
||||
import { Database } from './database';
|
||||
import { findEthPerToken, getEthPriceInUSD, WHITELIST_TOKENS } from './utils/pricing';
|
||||
import { findEthPerToken, getEthPriceInUSD, getTrackedAmountUSD, sqrtPriceX96ToTokenPrices, WHITELIST_TOKENS } from './utils/pricing';
|
||||
import { updatePoolDayData, updatePoolHourData, updateTokenDayData, updateTokenHourData, updateUniswapDayData } from './utils/interval-updates';
|
||||
import { Token } from './entity/Token';
|
||||
import { convertTokenToDecimal, loadTransaction } from './utils';
|
||||
import { convertTokenToDecimal, loadTransaction, safeDiv } from './utils';
|
||||
import { loadTick } from './utils/tick';
|
||||
import Decimal from 'decimal.js';
|
||||
|
||||
const log = debug('vulcanize:events');
|
||||
|
||||
@ -49,6 +50,17 @@ interface BurnEvent {
|
||||
amount1: bigint;
|
||||
}
|
||||
|
||||
interface SwapEvent {
|
||||
__typename: 'SwapEvent';
|
||||
sender: string;
|
||||
recipient: string;
|
||||
amount0: bigint;
|
||||
amount1: bigint;
|
||||
sqrtPriceX96: bigint;
|
||||
liquidity: bigint;
|
||||
tick: bigint;
|
||||
}
|
||||
|
||||
interface Block {
|
||||
number: number;
|
||||
hash: string;
|
||||
@ -64,7 +76,7 @@ interface ResultEvent {
|
||||
block: Block;
|
||||
tx: Transaction;
|
||||
contract: string;
|
||||
event: PoolCreatedEvent | InitializeEvent | MintEvent | BurnEvent;
|
||||
event: PoolCreatedEvent | InitializeEvent | MintEvent | BurnEvent | SwapEvent;
|
||||
proof: {
|
||||
data: string;
|
||||
}
|
||||
@ -122,6 +134,11 @@ export class EventWatcher {
|
||||
this._handleBurn(block, contract, tx, event as BurnEvent);
|
||||
break;
|
||||
|
||||
case 'SwapEvent':
|
||||
log('Pool Swap event', contract);
|
||||
this._handleSwap(block, contract, tx, event as SwapEvent);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -485,4 +502,209 @@ export class EventWatcher {
|
||||
await this._db.savePool(pool, blockNumber);
|
||||
await this._db.saveFactory(factory, blockNumber);
|
||||
}
|
||||
|
||||
async _handleSwap (block: Block, contractAddress: string, tx: Transaction, swapEvent: SwapEvent): Promise<void> {
|
||||
const { number: blockNumber, timestamp: blockTimestamp } = block;
|
||||
const { hash: txHash } = tx;
|
||||
const bundle = await this._db.loadBundle({ id: '1', blockNumber });
|
||||
|
||||
// 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 });
|
||||
|
||||
// Hot fix for bad pricing.
|
||||
if (pool.id === '0x9663f2ca0454accad3e094448ea6f77443880454') {
|
||||
return;
|
||||
}
|
||||
|
||||
const [token0, token1] = await Promise.all([
|
||||
this._db.getToken({ id: pool.token0.id, blockNumber }),
|
||||
this._db.getToken({ id: pool.token1.id, blockNumber })
|
||||
]);
|
||||
|
||||
assert(token0 && token1, 'Pool tokens not found.');
|
||||
|
||||
// Amounts - 0/1 are token deltas. Can be positive or negative.
|
||||
const amount0 = convertTokenToDecimal(swapEvent.amount0, token0.decimals);
|
||||
const amount1 = convertTokenToDecimal(swapEvent.amount1, token1.decimals);
|
||||
|
||||
// Need absolute amounts for volume.
|
||||
let amount0Abs = amount0;
|
||||
let amount1Abs = amount1;
|
||||
|
||||
if (amount0.lt(new Decimal(0))) {
|
||||
amount0Abs = amount0.times(new Decimal('-1'));
|
||||
}
|
||||
|
||||
if (amount1.lt(new Decimal(0))) {
|
||||
amount1Abs = amount1.times(new Decimal('-1'));
|
||||
}
|
||||
|
||||
const amount0ETH = amount0Abs.times(token0.derivedETH);
|
||||
const amount1ETH = amount1Abs.times(token1.derivedETH);
|
||||
const amount0USD = amount0ETH.times(bundle.ethPriceUSD);
|
||||
const amount1USD = amount1ETH.times(bundle.ethPriceUSD);
|
||||
|
||||
// Get amount that should be tracked only - div 2 because cant count both input and output as volume.
|
||||
const trackedAmountUSD = await getTrackedAmountUSD(this._db, amount0Abs, token0, amount1Abs, token1);
|
||||
const amountTotalUSDTracked = trackedAmountUSD.div(new Decimal('2'));
|
||||
const amountTotalETHTracked = safeDiv(amountTotalUSDTracked, bundle.ethPriceUSD);
|
||||
const amountTotalUSDUntracked = amount0USD.plus(amount1USD).div(new Decimal('2'));
|
||||
|
||||
const feesETH = amountTotalETHTracked.times(pool.feeTier.toString()).div(new Decimal('1000000'));
|
||||
const feesUSD = amountTotalUSDTracked.times(pool.feeTier.toString()).div(new Decimal('1000000'));
|
||||
|
||||
// Global updates.
|
||||
factory.txCount = factory.txCount + BigInt(1);
|
||||
factory.totalVolumeETH = factory.totalVolumeETH.plus(amountTotalETHTracked);
|
||||
factory.totalVolumeUSD = factory.totalVolumeUSD.plus(amountTotalUSDTracked);
|
||||
factory.untrackedVolumeUSD = factory.untrackedVolumeUSD.plus(amountTotalUSDUntracked);
|
||||
factory.totalFeesETH = factory.totalFeesETH.plus(feesETH);
|
||||
factory.totalFeesUSD = factory.totalFeesUSD.plus(feesUSD);
|
||||
|
||||
// Reset aggregate tvl before individual pool tvl updates.
|
||||
const currentPoolTvlETH = pool.totalValueLockedETH;
|
||||
factory.totalValueLockedETH = factory.totalValueLockedETH.minus(currentPoolTvlETH);
|
||||
|
||||
// pool volume
|
||||
pool.volumeToken0 = pool.volumeToken0.plus(amount0Abs);
|
||||
pool.volumeToken1 = pool.volumeToken1.plus(amount1Abs);
|
||||
pool.volumeUSD = pool.volumeUSD.plus(amountTotalUSDTracked);
|
||||
pool.untrackedVolumeUSD = pool.untrackedVolumeUSD.plus(amountTotalUSDUntracked);
|
||||
pool.feesUSD = pool.feesUSD.plus(feesUSD);
|
||||
pool.txCount = pool.txCount + BigInt(1);
|
||||
|
||||
// Update the pool with the new active liquidity, price, and tick.
|
||||
pool.liquidity = swapEvent.liquidity;
|
||||
pool.tick = BigInt(swapEvent.tick);
|
||||
pool.sqrtPrice = swapEvent.sqrtPriceX96;
|
||||
pool.totalValueLockedToken0 = pool.totalValueLockedToken0.plus(amount0);
|
||||
pool.totalValueLockedToken1 = pool.totalValueLockedToken1.plus(amount1);
|
||||
|
||||
// Update token0 data.
|
||||
token0.volume = token0.volume.plus(amount0Abs);
|
||||
token0.totalValueLocked = token0.totalValueLocked.plus(amount0);
|
||||
token0.volumeUSD = token0.volumeUSD.plus(amountTotalUSDTracked);
|
||||
token0.untrackedVolumeUSD = token0.untrackedVolumeUSD.plus(amountTotalUSDUntracked);
|
||||
token0.feesUSD = token0.feesUSD.plus(feesUSD);
|
||||
token0.txCount = token0.txCount + BigInt(1);
|
||||
|
||||
// Update token1 data.
|
||||
token1.volume = token1.volume.plus(amount1Abs);
|
||||
token1.totalValueLocked = token1.totalValueLocked.plus(amount1);
|
||||
token1.volumeUSD = token1.volumeUSD.plus(amountTotalUSDTracked);
|
||||
token1.untrackedVolumeUSD = token1.untrackedVolumeUSD.plus(amountTotalUSDUntracked);
|
||||
token1.feesUSD = token1.feesUSD.plus(feesUSD);
|
||||
token1.txCount = token1.txCount + BigInt(1);
|
||||
|
||||
// Updated pool rates.
|
||||
const prices = sqrtPriceX96ToTokenPrices(pool.sqrtPrice, token0 as Token, token1 as Token);
|
||||
pool.token0Price = prices[0];
|
||||
pool.token1Price = prices[1];
|
||||
this._db.savePool(pool, blockNumber);
|
||||
|
||||
// Update USD pricing.
|
||||
bundle.ethPriceUSD = await getEthPriceInUSD(this._db);
|
||||
this._db.saveBundle(bundle, blockNumber);
|
||||
token0.derivedETH = await findEthPerToken(token0);
|
||||
token1.derivedETH = await findEthPerToken(token1);
|
||||
|
||||
/**
|
||||
* Things afffected by new USD rates.
|
||||
*/
|
||||
pool.totalValueLockedETH = pool.totalValueLockedToken0
|
||||
.times(token0.derivedETH)
|
||||
.plus(pool.totalValueLockedToken1.times(token1.derivedETH));
|
||||
|
||||
pool.totalValueLockedUSD = pool.totalValueLockedETH.times(bundle.ethPriceUSD);
|
||||
|
||||
factory.totalValueLockedETH = factory.totalValueLockedETH.plus(pool.totalValueLockedETH);
|
||||
factory.totalValueLockedUSD = factory.totalValueLockedETH.times(bundle.ethPriceUSD);
|
||||
|
||||
token0.totalValueLockedUSD = token0.totalValueLocked.times(token0.derivedETH).times(bundle.ethPriceUSD);
|
||||
token1.totalValueLockedUSD = token1.totalValueLocked.times(token1.derivedETH).times(bundle.ethPriceUSD);
|
||||
|
||||
// Create Swap event
|
||||
const transaction = await loadTransaction(this._db, { txHash, blockNumber, blockTimestamp });
|
||||
|
||||
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,
|
||||
|
||||
// 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
|
||||
});
|
||||
|
||||
// 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 });
|
||||
|
||||
// Update volume metrics.
|
||||
uniswapDayData.volumeETH = uniswapDayData.volumeETH.plus(amountTotalETHTracked);
|
||||
uniswapDayData.volumeUSD = uniswapDayData.volumeUSD.plus(amountTotalUSDTracked);
|
||||
uniswapDayData.feesUSD = uniswapDayData.feesUSD.plus(feesUSD);
|
||||
|
||||
poolDayData.volumeUSD = poolDayData.volumeUSD.plus(amountTotalUSDTracked);
|
||||
poolDayData.volumeToken0 = poolDayData.volumeToken0.plus(amount0Abs);
|
||||
poolDayData.volumeToken1 = poolDayData.volumeToken1.plus(amount1Abs);
|
||||
poolDayData.feesUSD = poolDayData.feesUSD.plus(feesUSD);
|
||||
|
||||
poolHourData.volumeUSD = poolHourData.volumeUSD.plus(amountTotalUSDTracked);
|
||||
poolHourData.volumeToken0 = poolHourData.volumeToken0.plus(amount0Abs);
|
||||
poolHourData.volumeToken1 = poolHourData.volumeToken1.plus(amount1Abs);
|
||||
poolHourData.feesUSD = poolHourData.feesUSD.plus(feesUSD);
|
||||
|
||||
token0DayData.volume = token0DayData.volume.plus(amount0Abs);
|
||||
token0DayData.volumeUSD = token0DayData.volumeUSD.plus(amountTotalUSDTracked);
|
||||
token0DayData.untrackedVolumeUSD = token0DayData.untrackedVolumeUSD.plus(amountTotalUSDTracked);
|
||||
token0DayData.feesUSD = token0DayData.feesUSD.plus(feesUSD);
|
||||
|
||||
token0HourData.volume = token0HourData.volume.plus(amount0Abs);
|
||||
token0HourData.volumeUSD = token0HourData.volumeUSD.plus(amountTotalUSDTracked);
|
||||
token0HourData.untrackedVolumeUSD = token0HourData.untrackedVolumeUSD.plus(amountTotalUSDTracked);
|
||||
token0HourData.feesUSD = token0HourData.feesUSD.plus(feesUSD);
|
||||
|
||||
token1DayData.volume = token1DayData.volume.plus(amount1Abs);
|
||||
token1DayData.volumeUSD = token1DayData.volumeUSD.plus(amountTotalUSDTracked);
|
||||
token1DayData.untrackedVolumeUSD = token1DayData.untrackedVolumeUSD.plus(amountTotalUSDTracked);
|
||||
token1DayData.feesUSD = token1DayData.feesUSD.plus(feesUSD);
|
||||
|
||||
token1HourData.volume = token1HourData.volume.plus(amount1Abs);
|
||||
token1HourData.volumeUSD = token1HourData.volumeUSD.plus(amountTotalUSDTracked);
|
||||
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);
|
||||
|
||||
// Skipping update of inner vars of current or crossed ticks as they are not queried.
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Decimal from 'decimal.js';
|
||||
import { BigNumber } from 'ethers';
|
||||
|
||||
import { exponentToBigDecimal, safeDiv } from '.';
|
||||
import { Database } from '../database';
|
||||
import { Token } from '../entity/Token';
|
||||
|
||||
@ -36,6 +37,21 @@ export const WHITELIST_TOKENS: string[] = [
|
||||
];
|
||||
|
||||
const MINIMUM_ETH_LOCKED = new Decimal(52);
|
||||
const Q192 = 2 ** 192;
|
||||
|
||||
export const sqrtPriceX96ToTokenPrices = (sqrtPriceX96: bigint, token0: Token, token1: Token): Decimal[] => {
|
||||
const num = new Decimal((sqrtPriceX96 * sqrtPriceX96).toString());
|
||||
const denom = new Decimal(Q192.toString());
|
||||
|
||||
const price1 = num
|
||||
.div(denom)
|
||||
.times(exponentToBigDecimal(token0.decimals))
|
||||
.div(exponentToBigDecimal(token1.decimals));
|
||||
|
||||
const price0 = safeDiv(new Decimal('1'), price1);
|
||||
|
||||
return [price0, price1];
|
||||
};
|
||||
|
||||
export const getEthPriceInUSD = async (db: Database): Promise<Decimal> => {
|
||||
// Fetch eth prices for each stablecoin.
|
||||
@ -95,3 +111,39 @@ export const findEthPerToken = async (token: Token): Promise<Decimal> => {
|
||||
|
||||
return priceSoFar; // If nothing was found return 0.
|
||||
};
|
||||
|
||||
/**
|
||||
* Accepts tokens and amounts, return tracked amount based on token whitelist.
|
||||
* If one token on whitelist, return amount in that token converted to USD * 2.
|
||||
* If both are, return sum of two amounts.
|
||||
* If neither is, return 0.
|
||||
*/
|
||||
export const getTrackedAmountUSD = async (
|
||||
db: Database,
|
||||
tokenAmount0: Decimal,
|
||||
token0: Token,
|
||||
tokenAmount1: Decimal,
|
||||
token1: Token
|
||||
): Promise<Decimal> => {
|
||||
const bundle = await db.loadBundle({ id: '1' });
|
||||
const price0USD = token0.derivedETH.times(bundle.ethPriceUSD);
|
||||
const price1USD = token1.derivedETH.times(bundle.ethPriceUSD);
|
||||
|
||||
// Both are whitelist tokens, return sum of both amounts.
|
||||
if (WHITELIST_TOKENS.includes(token0.id) && WHITELIST_TOKENS.includes(token1.id)) {
|
||||
return tokenAmount0.times(price0USD).plus(tokenAmount1.times(price1USD));
|
||||
}
|
||||
|
||||
// Take double value of the whitelisted token amount.
|
||||
if (WHITELIST_TOKENS.includes(token0.id) && !WHITELIST_TOKENS.includes(token1.id)) {
|
||||
return tokenAmount0.times(price0USD).times(new Decimal('2'));
|
||||
}
|
||||
|
||||
// Take double value of the whitelisted token amount.
|
||||
if (!WHITELIST_TOKENS.includes(token0.id) && WHITELIST_TOKENS.includes(token1.id)) {
|
||||
return tokenAmount1.times(price1USD).times(new Decimal('2'));
|
||||
}
|
||||
|
||||
// Neither token is on white list, tracked amount is 0.
|
||||
return new Decimal(0);
|
||||
};
|
||||
|
@ -62,6 +62,16 @@ export class Client {
|
||||
amount0
|
||||
amount1
|
||||
}
|
||||
|
||||
... on SwapEvent {
|
||||
sender
|
||||
recipient
|
||||
amount0
|
||||
amount1
|
||||
sqrtPriceX96
|
||||
liquidity
|
||||
tick
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user