mirror of
https://github.com/cerc-io/watcher-ts
synced 2024-11-19 20:36:19 +00:00
Handle pool initialize event (#127)
* Move getConfig to util package. * Handle Pool initialize event. * Update Bundle entity ethPriceUSD. * Update Pool day and hour data. * Update token derivedETH and complete handleInitialize. Co-authored-by: nabarun <nabarun@deepstacksoft.com>
This commit is contained in:
parent
7f5229bf2f
commit
61f211f2d5
@ -28,6 +28,7 @@
|
||||
"@vulcanize/ipld-eth-client": "^0.1.0",
|
||||
"@vulcanize/solidity-mapper": "^0.1.0",
|
||||
"@vulcanize/tracing-client": "^0.1.0",
|
||||
"@vulcanize/util": "^0.1.0",
|
||||
"apollo-server-express": "^2.25.0",
|
||||
"apollo-type-bigint": "^0.1.3",
|
||||
"debug": "^4.3.1",
|
||||
|
@ -1,40 +0,0 @@
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import toml from 'toml';
|
||||
import debug from 'debug';
|
||||
import { ConnectionOptions } from 'typeorm';
|
||||
|
||||
import { Config as CacheConfig } from '@vulcanize/cache';
|
||||
|
||||
const log = debug('vulcanize:config');
|
||||
|
||||
export interface Config {
|
||||
server: {
|
||||
host: string;
|
||||
port: number;
|
||||
};
|
||||
database: ConnectionOptions;
|
||||
upstream: {
|
||||
gqlEndpoint: string;
|
||||
gqlSubscriptionEndpoint: string;
|
||||
traceProviderEndpoint: string;
|
||||
cache: CacheConfig
|
||||
}
|
||||
jobQueue: {
|
||||
dbConnectionString: string;
|
||||
maxCompletionLag: number;
|
||||
}
|
||||
}
|
||||
|
||||
export const getConfig = async (configFile: string): Promise<Config> => {
|
||||
const configFilePath = path.resolve(configFile);
|
||||
const fileExists = await fs.pathExists(configFilePath);
|
||||
if (!fileExists) {
|
||||
throw new Error(`Config file not found: ${configFilePath}`);
|
||||
}
|
||||
|
||||
const config = toml.parse(await fs.readFile(configFilePath, 'utf8'));
|
||||
log('config', JSON.stringify(config, null, 2));
|
||||
|
||||
return config;
|
||||
};
|
@ -10,13 +10,13 @@ import { createServer } from 'http';
|
||||
import { getCache } from '@vulcanize/cache';
|
||||
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||
import { TracingClient } from '@vulcanize/tracing-client';
|
||||
import { getConfig } from '@vulcanize/util';
|
||||
|
||||
import typeDefs from './schema';
|
||||
|
||||
import { createResolvers } from './resolvers';
|
||||
import { Indexer } from './indexer';
|
||||
import { Database } from './database';
|
||||
import { getConfig } from './config';
|
||||
import { TxWatcher } from './tx-watcher';
|
||||
import { JobQueue } from './job-queue';
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
"@vulcanize/cache": "^0.1.0",
|
||||
"@vulcanize/ipld-eth-client": "^0.1.0",
|
||||
"@vulcanize/solidity-mapper": "^0.1.0",
|
||||
"@vulcanize/util": "^0.1.0",
|
||||
"apollo-server-express": "^2.25.0",
|
||||
"apollo-type-bigint": "^0.1.3",
|
||||
"debug": "^4.3.1",
|
||||
|
@ -1,35 +0,0 @@
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import toml from 'toml';
|
||||
import debug from 'debug';
|
||||
import { ConnectionOptions } from 'typeorm';
|
||||
|
||||
import { Config as CacheConfig } from '@vulcanize/cache';
|
||||
|
||||
const log = debug('vulcanize:config');
|
||||
|
||||
export interface Config {
|
||||
server: {
|
||||
host: string;
|
||||
port: number;
|
||||
};
|
||||
database: ConnectionOptions;
|
||||
upstream: {
|
||||
gqlEndpoint: string;
|
||||
gqlSubscriptionEndpoint: string;
|
||||
cache: CacheConfig
|
||||
}
|
||||
}
|
||||
|
||||
export const getConfig = async (configFile: string): Promise<Config> => {
|
||||
const configFilePath = path.resolve(configFile);
|
||||
const fileExists = await fs.pathExists(configFilePath);
|
||||
if (!fileExists) {
|
||||
throw new Error(`Config file not found: ${configFilePath}`);
|
||||
}
|
||||
|
||||
const config = toml.parse(await fs.readFile(configFilePath, 'utf8'));
|
||||
log('config', JSON.stringify(config, null, 2));
|
||||
|
||||
return config;
|
||||
};
|
@ -10,6 +10,7 @@ import { createServer } from 'http';
|
||||
|
||||
import { getCache } from '@vulcanize/cache';
|
||||
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||
import { getConfig } from '@vulcanize/util';
|
||||
|
||||
import artifacts from './artifacts/ERC20.json';
|
||||
import typeDefs from './schema';
|
||||
@ -19,7 +20,6 @@ import { createResolvers } from './resolvers';
|
||||
import { Indexer } from './indexer';
|
||||
import { Database } from './database';
|
||||
import { EventWatcher } from './events';
|
||||
import { getConfig } from './config';
|
||||
|
||||
const log = debug('vulcanize:server');
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
"@vulcanize/cache": "^0.1.0",
|
||||
"@vulcanize/erc20-watcher": "^0.1.0",
|
||||
"@vulcanize/ipld-eth-client": "^0.1.0",
|
||||
"@vulcanize/util": "^0.1.0",
|
||||
"apollo-server-express": "^2.25.0",
|
||||
"apollo-type-bigint": "^0.1.3",
|
||||
"typeorm": "^0.2.32"
|
||||
|
@ -1,12 +1,15 @@
|
||||
import assert from 'assert';
|
||||
import { Connection, ConnectionOptions, createConnection, DeepPartial } from 'typeorm';
|
||||
import { Connection, ConnectionOptions, createConnection, DeepPartial, FindConditions, FindOneOptions, LessThanOrEqual } from 'typeorm';
|
||||
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
|
||||
|
||||
import { EventSyncProgress } from './entity/EventProgress';
|
||||
import { Factory } from './entity/Factory';
|
||||
import { Pool } from './entity/Pool';
|
||||
import { Event } from './entity/Event';
|
||||
import { Token } from './entity/Token';
|
||||
import { EventSyncProgress } from './entity/EventProgress';
|
||||
import { Bundle } from './entity/Bundle';
|
||||
import { PoolDayData } from './entity/PoolDayData';
|
||||
import { PoolHourData } from './entity/PoolHourData';
|
||||
|
||||
export class Database {
|
||||
_config: ConnectionOptions
|
||||
@ -33,25 +36,54 @@ export class Database {
|
||||
async getToken ({ id, blockNumber }: DeepPartial<Token>): Promise<Token | undefined> {
|
||||
const repo = this._conn.getRepository(Token);
|
||||
|
||||
return repo.createQueryBuilder('token')
|
||||
.where('id = :id AND block_number <= :blockNumber', {
|
||||
id,
|
||||
blockNumber
|
||||
})
|
||||
.orderBy('token.block_number', 'DESC')
|
||||
.getOne();
|
||||
const whereOptions: FindConditions<Token> = { id };
|
||||
|
||||
if (blockNumber) {
|
||||
whereOptions.blockNumber = LessThanOrEqual(blockNumber);
|
||||
}
|
||||
|
||||
const findOptions: FindOneOptions<Token> = {
|
||||
where: whereOptions,
|
||||
relations: ['whitelistPools', 'whitelistPools.token0', 'whitelistPools.token1'],
|
||||
order: {
|
||||
blockNumber: 'DESC'
|
||||
}
|
||||
};
|
||||
|
||||
return repo.findOne(findOptions);
|
||||
}
|
||||
|
||||
async getPool ({ id, blockNumber }: DeepPartial<Pool>): Promise<Pool | undefined> {
|
||||
const repo = this._conn.getRepository(Pool);
|
||||
const whereOptions: FindConditions<Pool> = { id };
|
||||
|
||||
if (blockNumber) {
|
||||
whereOptions.blockNumber = LessThanOrEqual(blockNumber);
|
||||
}
|
||||
|
||||
const findOptions: FindOneOptions<Pool> = {
|
||||
where: whereOptions,
|
||||
relations: ['token0', 'token1'],
|
||||
order: {
|
||||
blockNumber: 'DESC'
|
||||
}
|
||||
};
|
||||
|
||||
return repo.findOne(findOptions);
|
||||
}
|
||||
|
||||
async loadFactory ({ id, blockNumber, ...values }: DeepPartial<Factory>): Promise<Factory> {
|
||||
return this._conn.transaction(async (tx) => {
|
||||
const repo = tx.getRepository(Factory);
|
||||
|
||||
let entity = await repo.createQueryBuilder('factory')
|
||||
.where('id = :id AND block_number <= :blockNumber', {
|
||||
id,
|
||||
blockNumber
|
||||
})
|
||||
.orderBy('factory.block_number', 'DESC')
|
||||
let selectQueryBuilder = repo.createQueryBuilder('factory')
|
||||
.where('id = :id', { id });
|
||||
|
||||
if (blockNumber) {
|
||||
selectQueryBuilder = selectQueryBuilder.andWhere('block_number <= :blockNumber', { blockNumber });
|
||||
}
|
||||
|
||||
let entity = await selectQueryBuilder.orderBy('factory.block_number', 'DESC')
|
||||
.getOne();
|
||||
|
||||
if (!entity) {
|
||||
@ -67,13 +99,21 @@ export class Database {
|
||||
return this._conn.transaction(async (tx) => {
|
||||
const repo = tx.getRepository(Pool);
|
||||
|
||||
let entity = await repo.createQueryBuilder('pool')
|
||||
.where('id = :id AND block_number <= :blockNumber', {
|
||||
id,
|
||||
blockNumber
|
||||
})
|
||||
.orderBy('pool.block_number', 'DESC')
|
||||
.getOne();
|
||||
const whereOptions: FindConditions<Pool> = { id };
|
||||
|
||||
if (blockNumber) {
|
||||
whereOptions.blockNumber = LessThanOrEqual(blockNumber);
|
||||
}
|
||||
|
||||
const findOptions: FindOneOptions<Pool> = {
|
||||
where: whereOptions,
|
||||
relations: ['token0', 'token1'],
|
||||
order: {
|
||||
blockNumber: 'DESC'
|
||||
}
|
||||
};
|
||||
|
||||
let entity = await repo.findOne(findOptions);
|
||||
|
||||
if (!entity) {
|
||||
entity = repo.create({ blockNumber, id, ...values });
|
||||
@ -88,12 +128,92 @@ export class Database {
|
||||
return this._conn.transaction(async (tx) => {
|
||||
const repo = tx.getRepository(Token);
|
||||
|
||||
let entity = await repo.createQueryBuilder('token')
|
||||
.where('id = :id AND block_number <= :blockNumber', {
|
||||
id,
|
||||
blockNumber
|
||||
})
|
||||
.orderBy('token.block_number', 'DESC')
|
||||
const whereOptions: FindConditions<Token> = { id };
|
||||
|
||||
if (blockNumber) {
|
||||
whereOptions.blockNumber = LessThanOrEqual(blockNumber);
|
||||
}
|
||||
|
||||
const findOptions: FindOneOptions<Token> = {
|
||||
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<Bundle>): Promise<Bundle> {
|
||||
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('bundle.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<PoolDayData>): Promise<PoolDayData> {
|
||||
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('pool_day_data.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<PoolHourData>): Promise<PoolHourData> {
|
||||
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('pool_hour_data.block_number', 'DESC')
|
||||
.getOne();
|
||||
|
||||
if (!entity) {
|
||||
@ -113,6 +233,46 @@ export class Database {
|
||||
});
|
||||
}
|
||||
|
||||
async saveBundle (bundle: Bundle, blockNumber: number): Promise<Bundle> {
|
||||
return this._conn.transaction(async (tx) => {
|
||||
const repo = tx.getRepository(Bundle);
|
||||
bundle.blockNumber = blockNumber;
|
||||
return repo.save(bundle);
|
||||
});
|
||||
}
|
||||
|
||||
async savePool (pool: Pool, blockNumber: number): Promise<Pool> {
|
||||
return this._conn.transaction(async (tx) => {
|
||||
const repo = tx.getRepository(Pool);
|
||||
pool.blockNumber = blockNumber;
|
||||
return repo.save(pool);
|
||||
});
|
||||
}
|
||||
|
||||
async savePoolDayData (poolDayData: PoolDayData, blockNumber: number): Promise<PoolDayData> {
|
||||
return this._conn.transaction(async (tx) => {
|
||||
const repo = tx.getRepository(PoolDayData);
|
||||
poolDayData.blockNumber = blockNumber;
|
||||
return repo.save(poolDayData);
|
||||
});
|
||||
}
|
||||
|
||||
async savePoolHourData (poolHourData: PoolHourData, blockNumber: number): Promise<PoolHourData> {
|
||||
return this._conn.transaction(async (tx) => {
|
||||
const repo = tx.getRepository(PoolHourData);
|
||||
poolHourData.blockNumber = blockNumber;
|
||||
return repo.save(poolHourData);
|
||||
});
|
||||
}
|
||||
|
||||
async saveToken (token: Token, blockNumber: number): Promise<Token> {
|
||||
return this._conn.transaction(async (tx) => {
|
||||
const repo = tx.getRepository(Token);
|
||||
token.blockNumber = blockNumber;
|
||||
return repo.save(token);
|
||||
});
|
||||
}
|
||||
|
||||
// Returns true if events have already been synced for the (block, token) combination.
|
||||
async didSyncEvents ({ blockHash, token }: { blockHash: string, token: string }): Promise<boolean> {
|
||||
const numRows = await this._conn.getRepository(EventSyncProgress)
|
||||
|
13
packages/uni-info-watcher/src/entity/Bundle.ts
Normal file
13
packages/uni-info-watcher/src/entity/Bundle.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
export class Bundle {
|
||||
@PrimaryColumn('varchar', { length: 1 })
|
||||
id!: string;
|
||||
|
||||
@PrimaryColumn('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
ethPriceUSD!: number
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
import { Entity, Column, Index, PrimaryColumn } from 'typeorm';
|
||||
import { Entity, Column, PrimaryColumn } from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
@Index(['blockNumber', 'id'], { unique: true })
|
||||
export class Factory {
|
||||
@PrimaryColumn('varchar', { length: 42 })
|
||||
id!: string;
|
||||
|
||||
@PrimaryColumn('numeric')
|
||||
@PrimaryColumn('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
|
@ -1,14 +1,13 @@
|
||||
import { Entity, PrimaryColumn, Column, Index, ManyToOne } from 'typeorm';
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
|
||||
import { Token } from './Token';
|
||||
|
||||
@Entity()
|
||||
@Index(['blockNumber', 'id'])
|
||||
export class Pool {
|
||||
@PrimaryColumn('varchar', { length: 42 })
|
||||
id!: string;
|
||||
|
||||
@PrimaryColumn('numeric')
|
||||
@PrimaryColumn('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@ManyToOne(() => Token)
|
||||
@ -17,8 +16,38 @@ export class Pool {
|
||||
@ManyToOne(() => Token)
|
||||
token1!: Token;
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
token0Price!: number
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
token1Price!: number
|
||||
|
||||
@Column('numeric')
|
||||
feeTier!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
sqrtPrice!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
tick!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
liquidity!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
feeGrowthGlobal0X128!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
feeGrowthGlobal1X128!: bigint
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
totalValueLockedUSD!: number
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
totalValueLockedToken0!: number
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
totalValueLockedToken1!: number
|
||||
|
||||
// TODO: Add remaining fields when they are used.
|
||||
}
|
||||
|
58
packages/uni-info-watcher/src/entity/PoolDayData.ts
Normal file
58
packages/uni-info-watcher/src/entity/PoolDayData.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { Pool } from './Pool';
|
||||
|
||||
@Entity()
|
||||
export class PoolDayData {
|
||||
@PrimaryColumn('varchar')
|
||||
id!: string;
|
||||
|
||||
@PrimaryColumn('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@Column('integer')
|
||||
date!: number;
|
||||
|
||||
@ManyToOne(() => Pool)
|
||||
pool!: Pool;
|
||||
|
||||
@Column('numeric')
|
||||
high!: number;
|
||||
|
||||
@Column('numeric')
|
||||
low!: number;
|
||||
|
||||
@Column('numeric')
|
||||
open!: number;
|
||||
|
||||
@Column('numeric')
|
||||
close!: number;
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
sqrtPrice!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
tick!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
liquidity!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
feeGrowthGlobal0X128!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
feeGrowthGlobal1X128!: bigint
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
token0Price!: number
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
token1Price!: number
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
tvlUSD!: number
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
txCount!: bigint
|
||||
|
||||
// TODO: Add remaining fields when they are used.
|
||||
}
|
58
packages/uni-info-watcher/src/entity/PoolHourData.ts
Normal file
58
packages/uni-info-watcher/src/entity/PoolHourData.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { Pool } from './Pool';
|
||||
|
||||
@Entity()
|
||||
export class PoolHourData {
|
||||
@PrimaryColumn('varchar')
|
||||
id!: string;
|
||||
|
||||
@PrimaryColumn('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@Column('integer')
|
||||
periodStartUnix!: number;
|
||||
|
||||
@ManyToOne(() => Pool)
|
||||
pool!: Pool;
|
||||
|
||||
@Column('numeric')
|
||||
high!: number;
|
||||
|
||||
@Column('numeric')
|
||||
low!: number;
|
||||
|
||||
@Column('numeric')
|
||||
open!: number;
|
||||
|
||||
@Column('numeric')
|
||||
close!: number;
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
sqrtPrice!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
tick!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
liquidity!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
feeGrowthGlobal0X128!: bigint
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
feeGrowthGlobal1X128!: bigint
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
token0Price!: number
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
token1Price!: number
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
tvlUSD!: number
|
||||
|
||||
@Column('numeric', { default: BigInt(0) })
|
||||
txCount!: bigint
|
||||
|
||||
// TODO: Add remaining fields when they are used.
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
|
||||
import { Entity, PrimaryColumn, Column, ManyToMany, JoinTable } from 'typeorm';
|
||||
import { Pool } from './Pool';
|
||||
|
||||
@Entity()
|
||||
@Index(['blockNumber', 'id'])
|
||||
export class Token {
|
||||
@PrimaryColumn('varchar', { length: 42 })
|
||||
id!: string;
|
||||
|
||||
@PrimaryColumn('numeric')
|
||||
@PrimaryColumn('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@Column('varchar')
|
||||
@ -18,5 +18,12 @@ export class Token {
|
||||
@Column('numeric')
|
||||
totalSupply!: number;
|
||||
|
||||
@Column('numeric', { default: 0 })
|
||||
derivedETH!: number;
|
||||
|
||||
@ManyToMany(() => Pool)
|
||||
@JoinTable()
|
||||
whitelistPools!: Pool[];
|
||||
|
||||
// TODO: Add remaining fields when they are used.
|
||||
}
|
||||
|
@ -5,6 +5,9 @@ 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 { updatePoolDayData, updatePoolHourData } from './utils/intervalUpdates';
|
||||
import { Token } from './entity/Token';
|
||||
|
||||
const log = debug('vulcanize:events');
|
||||
|
||||
@ -16,6 +19,11 @@ interface PoolCreatedEvent {
|
||||
pool: string;
|
||||
}
|
||||
|
||||
interface InitializeEvent {
|
||||
sqrtPriceX96: bigint;
|
||||
tick: bigint;
|
||||
}
|
||||
|
||||
interface ResultEvent {
|
||||
proof: {
|
||||
data: string
|
||||
@ -59,10 +67,15 @@ export class EventWatcher {
|
||||
|
||||
switch (eventType) {
|
||||
case 'PoolCreatedEvent':
|
||||
log('PoolCreated event', contract);
|
||||
log('Factory PoolCreated event', contract);
|
||||
this._handlePoolCreated(blockHash, blockNumber, contract, eventValues as PoolCreatedEvent);
|
||||
break;
|
||||
|
||||
case 'InitializeEvent':
|
||||
log('Pool Initialize event', contract);
|
||||
this._handleInitialize(blockHash, blockNumber, contract, eventValues as InitializeEvent);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -85,36 +98,18 @@ export class EventWatcher {
|
||||
this._db.getToken({ blockNumber, id: token1Address })
|
||||
]);
|
||||
|
||||
// Create Token.
|
||||
const createToken = async (tokenAddress: string) => {
|
||||
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);
|
||||
|
||||
// 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
|
||||
});
|
||||
};
|
||||
|
||||
// Create Tokens if not present.
|
||||
if (!token0) {
|
||||
token0 = await createToken(token0Address);
|
||||
token0 = await this._createToken(blockHash, blockNumber, token0Address);
|
||||
}
|
||||
|
||||
if (!token1) {
|
||||
token1 = await createToken(token1Address);
|
||||
token1 = await this._createToken(blockHash, blockNumber, token1Address);
|
||||
}
|
||||
|
||||
// Create new Pool entity.
|
||||
// Skipping adding createdAtTimestamp field as it is not queried in frontend subgraph.
|
||||
await this._db.loadPool({
|
||||
const pool = await this._db.loadPool({
|
||||
blockNumber,
|
||||
id: poolAddress,
|
||||
token0: token0,
|
||||
@ -122,9 +117,74 @@ export class EventWatcher {
|
||||
feeTier: BigInt(fee)
|
||||
});
|
||||
|
||||
// Skipping updating token whitelistPools field as it is not queried in frontend subgraph.
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Save entities to DB.
|
||||
await this._db.saveFactory(factory, blockNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new Token.
|
||||
* @param tokenAddress
|
||||
*/
|
||||
async _createToken (blockHash: string, blockNumber: number, tokenAddress: string): Promise<Token> {
|
||||
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);
|
||||
|
||||
// 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
|
||||
});
|
||||
}
|
||||
|
||||
async _handleInitialize (blockHash: string, blockNumber: number, contractAddress: string, initializeEvent: InitializeEvent): Promise<void> {
|
||||
const { sqrtPriceX96, tick } = initializeEvent;
|
||||
const pool = await this._db.getPool({ id: contractAddress, blockNumber });
|
||||
assert(pool, `Pool ${contractAddress} not found.`);
|
||||
|
||||
// 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 });
|
||||
await updatePoolHourData(this._db, { contractAddress, blockNumber });
|
||||
|
||||
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.');
|
||||
|
||||
// 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)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import { getCache } from '@vulcanize/cache';
|
||||
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||
import { Client as ERC20Client } from '@vulcanize/erc20-watcher';
|
||||
import { Client as UniClient } from '@vulcanize/uni-watcher';
|
||||
import { getConfig } from '@vulcanize/util';
|
||||
|
||||
import typeDefs from './schema';
|
||||
|
||||
@ -20,7 +21,6 @@ import { createResolvers } from './resolvers';
|
||||
import { Indexer } from './indexer';
|
||||
import { Database } from './database';
|
||||
import { EventWatcher } from './events';
|
||||
import { getConfig } from './config';
|
||||
|
||||
const log = debug('vulcanize:server');
|
||||
|
||||
|
103
packages/uni-info-watcher/src/utils/intervalUpdates.ts
Normal file
103
packages/uni-info-watcher/src/utils/intervalUpdates.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import { BigNumber } from 'ethers';
|
||||
|
||||
import { Database } from '../database';
|
||||
import { PoolDayData } from '../entity/PoolDayData';
|
||||
import { PoolHourData } from '../entity/PoolHourData';
|
||||
|
||||
export const updatePoolDayData = async (db: Database, event: { contractAddress: string, blockNumber: number }): Promise<PoolDayData> => {
|
||||
const { contractAddress, blockNumber } = event;
|
||||
|
||||
// TODO: Get block timestamp from event.
|
||||
// let timestamp = event.block.timestamp.toI32()
|
||||
const timestamp = Math.floor(Date.now() / 1000); // Unix timestamp.
|
||||
|
||||
const dayID = Math.floor(timestamp / 86400);
|
||||
const dayStartTimestamp = dayID * 86400;
|
||||
|
||||
const dayPoolID = contractAddress
|
||||
.concat('-')
|
||||
.concat(dayID.toString());
|
||||
|
||||
const pool = await db.loadPool({ id: contractAddress, blockNumber });
|
||||
|
||||
let poolDayData = await db.loadPoolDayData({
|
||||
id: dayPoolID,
|
||||
blockNumber,
|
||||
date: dayStartTimestamp,
|
||||
pool: pool,
|
||||
open: pool.token0Price,
|
||||
high: pool.token0Price,
|
||||
low: pool.token0Price,
|
||||
close: pool.token0Price
|
||||
});
|
||||
|
||||
if (Number(pool.token0Price) > Number(poolDayData.high)) {
|
||||
poolDayData.high = pool.token0Price;
|
||||
}
|
||||
|
||||
if (Number(pool.token0Price) < Number(poolDayData.low)) {
|
||||
poolDayData.low = pool.token0Price;
|
||||
}
|
||||
|
||||
poolDayData.liquidity = pool.liquidity;
|
||||
poolDayData.sqrtPrice = pool.sqrtPrice;
|
||||
poolDayData.feeGrowthGlobal0X128 = pool.feeGrowthGlobal0X128;
|
||||
poolDayData.feeGrowthGlobal1X128 = pool.feeGrowthGlobal1X128;
|
||||
poolDayData.token0Price = pool.token0Price;
|
||||
poolDayData.token1Price = pool.token1Price;
|
||||
poolDayData.tick = pool.tick;
|
||||
poolDayData.tvlUSD = pool.totalValueLockedUSD;
|
||||
poolDayData.txCount = BigInt(BigNumber.from(poolDayData.txCount).add(1).toHexString());
|
||||
poolDayData = await db.savePoolDayData(poolDayData, blockNumber);
|
||||
|
||||
return poolDayData;
|
||||
};
|
||||
|
||||
export const updatePoolHourData = async (db: Database, event: { contractAddress: string, blockNumber: number }): Promise<PoolHourData> => {
|
||||
const { contractAddress, blockNumber } = event;
|
||||
|
||||
// TODO: Get block timestamp from event.
|
||||
// let timestamp = event.block.timestamp.toI32()
|
||||
const timestamp = Math.floor(Date.now() / 1000); // Unix timestamp.
|
||||
|
||||
const hourIndex = Math.floor(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 });
|
||||
|
||||
let poolHourData = await db.loadPoolHourData({
|
||||
id: hourPoolID,
|
||||
blockNumber,
|
||||
periodStartUnix: hourStartUnix,
|
||||
pool: pool,
|
||||
open: pool.token0Price,
|
||||
high: pool.token0Price,
|
||||
low: pool.token0Price,
|
||||
close: pool.token0Price
|
||||
});
|
||||
|
||||
if (Number(pool.token0Price) > Number(poolHourData.high)) {
|
||||
poolHourData.high = pool.token0Price;
|
||||
}
|
||||
if (Number(pool.token0Price) < Number(poolHourData.low)) {
|
||||
poolHourData.low = pool.token0Price;
|
||||
}
|
||||
|
||||
poolHourData.liquidity = pool.liquidity;
|
||||
poolHourData.sqrtPrice = pool.sqrtPrice;
|
||||
poolHourData.token0Price = pool.token0Price;
|
||||
poolHourData.token1Price = pool.token1Price;
|
||||
poolHourData.feeGrowthGlobal0X128 = pool.feeGrowthGlobal0X128;
|
||||
poolHourData.feeGrowthGlobal1X128 = pool.feeGrowthGlobal1X128;
|
||||
poolHourData.close = pool.token0Price;
|
||||
poolHourData.tick = pool.tick;
|
||||
poolHourData.tvlUSD = pool.totalValueLockedUSD;
|
||||
poolHourData.txCount = BigInt(BigNumber.from(poolHourData.txCount).add(1).toHexString());
|
||||
poolHourData = await db.savePoolHourData(poolHourData, blockNumber);
|
||||
|
||||
return poolHourData;
|
||||
};
|
96
packages/uni-info-watcher/src/utils/pricing.ts
Normal file
96
packages/uni-info-watcher/src/utils/pricing.ts
Normal file
@ -0,0 +1,96 @@
|
||||
import { BigNumber } from 'ethers';
|
||||
|
||||
import { Database } from '../database';
|
||||
import { Token } from '../entity/Token';
|
||||
|
||||
// TODO: Move constants to config.
|
||||
const WETH_ADDRESS = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';
|
||||
|
||||
const USDC_WETH_03_POOL = '0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8';
|
||||
|
||||
// Token where amounts should contribute to tracked volume and liquidity.
|
||||
// Usually tokens that many tokens are paired with.
|
||||
// TODO: Load whitelisted tokens from config.
|
||||
export const WHITELIST_TOKENS: string[] = [
|
||||
WETH_ADDRESS, // WETH
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f', // DAI
|
||||
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC
|
||||
'0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT
|
||||
'0x0000000000085d4780b73119b644ae5ecd22b376', // TUSD
|
||||
'0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', // WBTC
|
||||
'0x5d3a536e4d6dbd6114cc1ead35777bab948e3643', // cDAI
|
||||
'0x39aa39c021dfbae8fac545936693ac917d5e7563', // cUSDC
|
||||
'0x86fadb80d8d2cff3c3680819e4da99c10232ba0f', // EBASE
|
||||
'0x57ab1ec28d129707052df4df418d58a2d46d5f51', // sUSD
|
||||
'0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2', // MKR
|
||||
'0xc00e94cb662c3520282e6f5717214004a7f26888', // COMP
|
||||
'0x514910771af9ca656af840dff83e8264ecf986ca', // LINK
|
||||
'0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f', // SNX
|
||||
'0x0bc529c00c6401aef6d220be8c6ea1667f6ad93e', // YFI
|
||||
'0x111111111117dc0aa78b770fa6a738034120c302', // 1INCH
|
||||
'0xdf5e0e81dff6faf3a7e52ba697820c5e32d806a8', // yCurv
|
||||
'0x956f47f50a910163d8bf957cf5846d573e7f87ca', // FEI
|
||||
'0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0', // MATIC
|
||||
'0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9' // AAVE
|
||||
];
|
||||
|
||||
const MINIMUM_ETH_LOCKED = 52;
|
||||
|
||||
export const getEthPriceInUSD = async (db: Database): Promise<number> => {
|
||||
// Fetch eth prices for each stablecoin.
|
||||
const usdcPool = await db.getPool({ id: USDC_WETH_03_POOL }); // DAI is token0.
|
||||
|
||||
if (usdcPool) {
|
||||
return usdcPool.token0Price;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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<number> => {
|
||||
if (token.id === WETH_ADDRESS) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const whiteList = token.whitelistPools;
|
||||
// For now just take USD from pool with greatest TVL.
|
||||
// Need to update this to actually detect best rate based on liquidity distribution.
|
||||
let largestLiquidityETH = 0;
|
||||
let priceSoFar = 0;
|
||||
|
||||
for (let i = 0; i < whiteList.length; ++i) {
|
||||
const pool = whiteList[i];
|
||||
|
||||
if (BigNumber.from(pool.liquidity).gt(0)) {
|
||||
if (pool.token0.id === token.id) {
|
||||
// Whitelist token is token1.
|
||||
const token1 = pool.token1;
|
||||
// Get the derived ETH in pool.
|
||||
const ethLocked = Number(pool.totalValueLockedToken1) * Number(token1.derivedETH);
|
||||
|
||||
if (ethLocked > largestLiquidityETH && ethLocked > MINIMUM_ETH_LOCKED) {
|
||||
largestLiquidityETH = ethLocked;
|
||||
// token1 per our token * Eth per token1
|
||||
priceSoFar = Number(pool.token1Price) * Number(token1.derivedETH);
|
||||
}
|
||||
}
|
||||
if (pool.token1.id === token.id) {
|
||||
const token0 = pool.token0;
|
||||
// Get the derived ETH in pool.
|
||||
const ethLocked = Number(pool.totalValueLockedToken0) * Number(token0.derivedETH);
|
||||
|
||||
if (ethLocked > largestLiquidityETH && ethLocked > MINIMUM_ETH_LOCKED) {
|
||||
largestLiquidityETH = ethLocked;
|
||||
// token0 per our token * ETH per token0
|
||||
priceSoFar = Number(pool.token0Price) * Number(token0.derivedETH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return priceSoFar; // If nothing was found return 0.
|
||||
};
|
@ -28,6 +28,7 @@
|
||||
"@vulcanize/cache": "^0.1.0",
|
||||
"@vulcanize/ipld-eth-client": "^0.1.0",
|
||||
"@vulcanize/solidity-mapper": "^0.1.0",
|
||||
"@vulcanize/util": "^0.1.0",
|
||||
"apollo-server-express": "^2.25.0",
|
||||
"apollo-type-bigint": "^0.1.3",
|
||||
"debug": "^4.3.1",
|
||||
|
@ -3,7 +3,7 @@ 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 () => {
|
||||
|
@ -25,6 +25,7 @@ export class Client {
|
||||
}
|
||||
event {
|
||||
__typename
|
||||
|
||||
... on PoolCreatedEvent {
|
||||
token0
|
||||
token1
|
||||
@ -32,6 +33,11 @@ export class Client {
|
||||
tickSpacing
|
||||
pool
|
||||
}
|
||||
|
||||
... on InitializeEvent {
|
||||
sqrtPriceX96
|
||||
tick
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import toml from 'toml';
|
||||
import debug from 'debug';
|
||||
import { ConnectionOptions } from 'typeorm';
|
||||
|
||||
import { Config as CacheConfig } from '@vulcanize/cache';
|
||||
|
||||
const log = debug('vulcanize:config');
|
||||
|
||||
export interface Config {
|
||||
server: {
|
||||
host: string;
|
||||
port: number;
|
||||
};
|
||||
database: ConnectionOptions;
|
||||
upstream: {
|
||||
gqlEndpoint: string;
|
||||
gqlSubscriptionEndpoint: string;
|
||||
cache: CacheConfig
|
||||
}
|
||||
}
|
||||
|
||||
export const getConfig = async (configFile: string): Promise<Config> => {
|
||||
const configFilePath = path.resolve(configFile);
|
||||
const fileExists = await fs.pathExists(configFilePath);
|
||||
if (!fileExists) {
|
||||
throw new Error(`Config file not found: ${configFilePath}`);
|
||||
}
|
||||
|
||||
const config = toml.parse(await fs.readFile(configFilePath, 'utf8'));
|
||||
log('config', JSON.stringify(config, null, 2));
|
||||
|
||||
return config;
|
||||
};
|
@ -8,11 +8,11 @@ import { PubSub } from 'apollo-server-express';
|
||||
|
||||
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||
import { GetStorageAt } from '@vulcanize/solidity-mapper';
|
||||
import { Config } from '@vulcanize/util';
|
||||
|
||||
import { Database } from './database';
|
||||
import { Event } from './entity/Event';
|
||||
import { Contract, KIND_FACTORY, KIND_POOL } from './entity/Contract';
|
||||
import { Config } from './config';
|
||||
|
||||
import factoryABI from './artifacts/factory.json';
|
||||
import poolABI from './artifacts/pool.json';
|
||||
|
@ -10,6 +10,7 @@ import { createServer } from 'http';
|
||||
|
||||
import { getCache } from '@vulcanize/cache';
|
||||
import { EthClient } from '@vulcanize/ipld-eth-client';
|
||||
import { getConfig } from '@vulcanize/util';
|
||||
|
||||
import typeDefs from './schema';
|
||||
|
||||
@ -18,7 +19,6 @@ import { createResolvers } from './resolvers';
|
||||
import { Indexer } from './indexer';
|
||||
import { Database } from './database';
|
||||
import { EventWatcher } from './events';
|
||||
import { getConfig } from './config';
|
||||
|
||||
const log = debug('vulcanize:server');
|
||||
|
||||
|
5
packages/util/.eslintignore
Normal file
5
packages/util/.eslintignore
Normal file
@ -0,0 +1,5 @@
|
||||
# Don't lint node_modules.
|
||||
node_modules
|
||||
|
||||
# Don't lint build output.
|
||||
dist
|
18
packages/util/.eslintrc.json
Normal file
18
packages/util/.eslintrc.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": [
|
||||
"semistandard",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 12,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
]
|
||||
}
|
1
packages/util/index.ts
Normal file
1
packages/util/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './src/config';
|
32
packages/util/package.json
Normal file
32
packages/util/package.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "@vulcanize/util",
|
||||
"version": "0.1.0",
|
||||
"main": "index.js",
|
||||
"license": "UNLICENSED",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.1",
|
||||
"ethers": "^5.2.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"toml": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vulcanize/cache": "^0.1.0",
|
||||
"@types/fs-extra": "^9.0.11",
|
||||
"@typescript-eslint/eslint-plugin": "^4.25.0",
|
||||
"@typescript-eslint/parser": "^4.25.0",
|
||||
"chai": "^4.3.4",
|
||||
"eslint": "^7.27.0",
|
||||
"eslint-config-semistandard": "^15.0.1",
|
||||
"eslint-config-standard": "^16.0.3",
|
||||
"eslint-plugin-import": "^2.23.3",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
"eslint-plugin-standard": "^5.0.0",
|
||||
"mocha": "^8.4.0",
|
||||
"typeorm": "^0.2.32"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"build": "tsc"
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ export interface Config {
|
||||
gqlEndpoint: string;
|
||||
gqlSubscriptionEndpoint: string;
|
||||
traceProviderEndpoint: string;
|
||||
cache: CacheConfig;
|
||||
cache: CacheConfig,
|
||||
uniWatcher: {
|
||||
gqlEndpoint: string;
|
||||
gqlSubscriptionEndpoint: string;
|
||||
@ -27,7 +27,7 @@ export interface Config {
|
||||
gqlEndpoint: string;
|
||||
gqlSubscriptionEndpoint: string;
|
||||
}
|
||||
}
|
||||
},
|
||||
jobQueue: {
|
||||
dbConnectionString: string;
|
||||
maxCompletionLag: number;
|
77
packages/util/tsconfig.json
Normal file
77
packages/util/tsconfig.json
Normal file
@ -0,0 +1,77 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
"lib": [ "ES5", "ES6", "ES2020" ], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
"outDir": "dist", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
"typeRoots": [
|
||||
"./src/types"
|
||||
], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
|
||||
"resolveJsonModule": true /* Enabling the option allows importing JSON, and validating the types in that JSON file. */
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["dist"]
|
||||
}
|
Loading…
Reference in New Issue
Block a user