2021-07-02 10:56:32 +00:00
|
|
|
import assert from 'assert';
|
|
|
|
import debug from 'debug';
|
2021-07-06 11:25:11 +00:00
|
|
|
import { Client as UniClient } from '@vulcanize/uni-watcher';
|
|
|
|
import { Client as ERC20Client } from '@vulcanize/erc20-watcher';
|
2021-07-07 05:40:10 +00:00
|
|
|
import { BigNumber } from 'ethers';
|
2021-07-02 10:56:32 +00:00
|
|
|
|
2021-07-06 11:25:11 +00:00
|
|
|
import { Database } from './database';
|
2021-07-02 10:56:32 +00:00
|
|
|
|
|
|
|
const log = debug('vulcanize:events');
|
|
|
|
|
2021-07-06 11:25:11 +00:00
|
|
|
interface PoolCreatedEvent {
|
|
|
|
token0: string;
|
|
|
|
token1: string;
|
|
|
|
fee: bigint;
|
|
|
|
tickSpacing: bigint;
|
|
|
|
pool: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface ResultEvent {
|
|
|
|
proof: {
|
|
|
|
data: string
|
|
|
|
}
|
|
|
|
event: {
|
|
|
|
__typename: string;
|
|
|
|
[key: string]: any;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-02 10:56:32 +00:00
|
|
|
export class EventWatcher {
|
2021-07-06 11:25:11 +00:00
|
|
|
_db: Database
|
|
|
|
_subscription?: ZenObservable.Subscription
|
|
|
|
_uniClient: UniClient
|
|
|
|
_erc20Client: ERC20Client
|
2021-07-02 10:56:32 +00:00
|
|
|
|
2021-07-06 11:25:11 +00:00
|
|
|
constructor (db: Database, uniClient: UniClient, erc20Client: ERC20Client) {
|
|
|
|
assert(db);
|
2021-07-02 10:56:32 +00:00
|
|
|
|
2021-07-06 11:25:11 +00:00
|
|
|
this._db = db;
|
|
|
|
this._uniClient = uniClient;
|
|
|
|
this._erc20Client = erc20Client;
|
2021-07-02 10:56:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async start (): Promise<void> {
|
|
|
|
assert(!this._subscription, 'subscription already started');
|
2021-07-06 11:25:11 +00:00
|
|
|
log('Started watching upstream events...');
|
|
|
|
this._subscription = await this._uniClient.watchEvents(this._handleEvents.bind(this));
|
2021-07-02 10:56:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async stop (): Promise<void> {
|
|
|
|
if (this._subscription) {
|
2021-07-06 11:25:11 +00:00
|
|
|
log('Stopped watching upstream events');
|
2021-07-02 10:56:32 +00:00
|
|
|
this._subscription.unsubscribe();
|
|
|
|
}
|
|
|
|
}
|
2021-07-06 11:25:11 +00:00
|
|
|
|
|
|
|
async _handleEvents ({ blockHash, blockNumber, contract, event }: { blockHash: string, blockNumber: number, contract: string, event: ResultEvent}): Promise<void> {
|
|
|
|
// TODO: Process proof (proof.data) in event.
|
|
|
|
const { event: { __typename: eventType, ...eventValues } } = event;
|
|
|
|
|
|
|
|
switch (eventType) {
|
|
|
|
case 'PoolCreatedEvent':
|
2021-07-07 05:40:10 +00:00
|
|
|
log('PoolCreated event', contract);
|
2021-07-06 11:25:11 +00:00
|
|
|
this._handlePoolCreated(blockHash, blockNumber, contract, eventValues as PoolCreatedEvent);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async _handlePoolCreated (blockHash: string, blockNumber: number, contractAddress: string, poolCreatedEvent: PoolCreatedEvent): Promise<void> {
|
2021-07-07 05:40:10 +00:00
|
|
|
const { token0: token0Address, token1: token1Address, fee, pool: poolAddress } = poolCreatedEvent;
|
2021-07-06 11:25:11 +00:00
|
|
|
|
|
|
|
// Load factory.
|
|
|
|
const factory = await this._db.loadFactory({ blockNumber, id: contractAddress });
|
|
|
|
|
2021-07-07 05:40:10 +00:00
|
|
|
// Update Factory.
|
|
|
|
let factoryPoolCount = BigNumber.from(factory.poolCount);
|
|
|
|
factoryPoolCount = factoryPoolCount.add(1);
|
|
|
|
factory.poolCount = BigInt(factoryPoolCount.toHexString());
|
|
|
|
|
|
|
|
// Get Tokens.
|
|
|
|
let [token0, token1] = await Promise.all([
|
|
|
|
this._db.getToken({ blockNumber, id: token0Address }),
|
|
|
|
this._db.getToken({ blockNumber, id: token1Address })
|
|
|
|
]);
|
2021-07-06 11:25:11 +00:00
|
|
|
|
2021-07-07 05:40:10 +00:00
|
|
|
// Create Token.
|
|
|
|
const createToken = async (tokenAddress: string) => {
|
2021-07-06 11:25:11 +00:00
|
|
|
const { value: symbol } = await this._erc20Client.getSymbol(blockHash, tokenAddress);
|
2021-07-07 05:40:10 +00:00
|
|
|
const { value: name } = await this._erc20Client.getName(blockHash, tokenAddress);
|
|
|
|
const { value: totalSupply } = await this._erc20Client.getTotalSupply(blockHash, tokenAddress);
|
|
|
|
|
|
|
|
// TODO: decimals not implemented by erc20-watcher.
|
|
|
|
// const { value: decimals } = await this._erc20Client.getDecimals(blockHash, tokenAddress);
|
|
|
|
|
|
|
|
return this._db.loadToken({
|
|
|
|
blockNumber,
|
|
|
|
id: token1Address,
|
|
|
|
symbol,
|
|
|
|
name,
|
|
|
|
totalSupply
|
|
|
|
});
|
2021-07-06 11:25:11 +00:00
|
|
|
};
|
|
|
|
|
2021-07-07 05:40:10 +00:00
|
|
|
// Create Tokens if not present.
|
|
|
|
if (!token0) {
|
|
|
|
token0 = await createToken(token0Address);
|
|
|
|
}
|
2021-07-06 11:25:11 +00:00
|
|
|
|
2021-07-07 05:40:10 +00:00
|
|
|
if (!token1) {
|
|
|
|
token1 = await createToken(token1Address);
|
|
|
|
}
|
2021-07-06 11:25:11 +00:00
|
|
|
|
2021-07-07 05:40:10 +00:00
|
|
|
// Create new Pool entity.
|
|
|
|
// Skipping adding createdAtTimestamp field as it is not queried in frontend subgraph.
|
|
|
|
await this._db.loadPool({
|
|
|
|
blockNumber,
|
|
|
|
id: poolAddress,
|
|
|
|
token0: token0,
|
|
|
|
token1: token1,
|
|
|
|
feeTier: BigInt(fee)
|
|
|
|
});
|
|
|
|
|
|
|
|
// Skipping updating token whitelistPools field as it is not queried in frontend subgraph.
|
|
|
|
|
|
|
|
// Save entities to DB.
|
|
|
|
await this._db.saveFactory(factory, blockNumber);
|
2021-07-06 11:25:11 +00:00
|
|
|
}
|
2021-07-02 10:56:32 +00:00
|
|
|
}
|