Remove watchers after moving them out to their own repos (#365)

* Remove all watchers after moving them out

* Add missing dependencies
This commit is contained in:
Nabarun Gogoi 2023-04-14 17:22:44 +05:30 committed by GitHub
parent e841b6a7c3
commit 7f91fa7ed8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
429 changed files with 23 additions and 31044 deletions

View File

@ -1,5 +0,0 @@
# Don't lint node_modules.
node_modules
# Don't lint build output.
dist

View File

@ -1,28 +0,0 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"semistandard",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"indent": ["error", 2, { "SwitchCase": 1 }],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": [
"warn",
{
"allowArgumentsExplicitlyTypedAsAny": true
}
]
}
}

View File

@ -1,6 +0,0 @@
.idea/
.vscode/
node_modules/
build/
tmp/
temp/

View File

@ -1,33 +0,0 @@
# Address Watcher
## Setup
First try the [stack orchestrator](https://github.com/cerc-io/stack-orchestrator) to quickly get started. Advanced users can see [here](/docs/README.md) for instructions on setting up a local environment by hand.
Build files:
```bash
yarn && yarn build
```
## Run
Run the following commands in different terminals:
GraphQL server:
```bash
yarn server
```
Job runner for processing the tracing requests queue:
```bash
yarn job-runner
```
To fill a block range:
```bash
yarn fill --start-block 1 --end-block 1000
```

View File

@ -1,28 +0,0 @@
[server]
host = "127.0.0.1"
port = 3002
[database]
type = "postgres"
host = "localhost"
port = 5432
database = "address-watcher"
username = "postgres"
password = "postgres"
synchronize = true
logging = false
[upstream]
traceProviderEndpoint = "http://127.0.0.1:8545"
[upstream.ethServer]
gqlApiEndpoint = "http://127.0.0.1:8082/graphql"
[upstream.cache]
name = "requests"
enabled = false
deleteOnStart = false
[jobQueue]
dbConnectionString = "postgres://postgres:postgres@localhost/address-watcher-job-queue"
maxCompletionLagInSecs = 300

View File

@ -1,64 +0,0 @@
{
"name": "@cerc-io/address-watcher",
"version": "0.2.38",
"description": "Address Watcher",
"private": true,
"scripts": {
"lint": "eslint .",
"test": "mocha -r ts-node/register src/**/*.test.ts",
"build": "tsc",
"server": "DEBUG=vulcanize:* node --enable-source-maps dist/server.js",
"server:dev": "DEBUG=vulcanize:* nodemon --watch src src/server.ts",
"job-runner": "DEBUG=vulcanize:* node --enable-source-maps dist/job-runner.js",
"job-runner:dev": "DEBUG=vulcanize:* nodemon --watch src src/job-runner.ts",
"fill": "DEBUG=vulcanize:* node --enable-source-maps dist/fill.js",
"fill:dev": "DEBUG=vulcanize:* ts-node src/fill.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/cerc-io/watcher-ts.git"
},
"author": "",
"license": "AGPL-3.0",
"bugs": {
"url": "https://github.com/cerc-io/watcher-ts/issues"
},
"homepage": "https://github.com/cerc-io/watcher-ts#readme",
"dependencies": {
"@apollo/client": "^3.3.19",
"@cerc-io/cache": "^0.2.38",
"@cerc-io/ipld-eth-client": "^0.2.38",
"@cerc-io/solidity-mapper": "^0.2.38",
"@cerc-io/tracing-client": "^0.2.38",
"@cerc-io/util": "^0.2.38",
"@types/lodash": "^4.14.168",
"debug": "^4.3.1",
"ethers": "^5.4.4",
"express": "^4.18.2",
"graphql": "^15.5.0",
"lodash": "^4.17.21",
"reflect-metadata": "^0.1.13",
"typeorm": "^0.2.32",
"typeorm-naming-strategies": "^2.0.0",
"yargs": "^17.0.1"
},
"devDependencies": {
"@ethersproject/abi": "^5.3.0",
"@types/chai": "^4.2.19",
"@types/express": "^4.17.14",
"@types/mocha": "^8.2.2",
"@types/yargs": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"chai": "^4.3.4",
"eslint": "^8.35.0",
"eslint-config-semistandard": "^15.0.1",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-standard": "^5.0.0",
"mocha": "^8.4.0",
"nodemon": "^2.0.7"
}
}

View File

@ -1,51 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import assert from 'assert';
import yargs from 'yargs';
import 'reflect-metadata';
import { ethers } from 'ethers';
import { Config, DEFAULT_CONFIG_PATH, getConfig } from '@cerc-io/util';
import { Database } from '../database';
(async () => {
const argv = await yargs.parserConfiguration({
'parse-numbers': false
}).options({
configFile: {
type: 'string',
require: true,
demandOption: true,
describe: 'configuration file path (toml)',
default: DEFAULT_CONFIG_PATH
},
address: {
type: 'string',
require: true,
demandOption: true,
describe: 'Address to watch'
},
startingBlock: {
type: 'number',
default: 1,
describe: 'Starting block'
}
}).argv;
const config: Config = await getConfig(argv.configFile);
const { database: dbConfig } = config;
assert(dbConfig);
const db = new Database(dbConfig);
await db.init();
// Always use the checksum address (https://docs.ethers.io/v5/api/utils/address/#utils-getAddress).
const address = ethers.utils.getAddress(argv.address);
await db.saveAccount(address, argv.startingBlock);
await db.close();
})();

View File

@ -1,141 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import assert from 'assert';
import { Connection, ConnectionOptions, createConnection, DeepPartial } from 'typeorm';
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
import path from 'path';
import { Account } from './entity/Account';
import { BlockProgress } from './entity/BlockProgress';
import { Trace } from './entity/Trace';
export class Database {
_config: ConnectionOptions;
_conn!: Connection;
constructor (config: ConnectionOptions) {
assert(config);
this._config = {
...config,
entities: [path.join(__dirname, 'entity/*')]
};
}
async init (): Promise<void> {
assert(!this._conn);
this._conn = await createConnection({
...this._config,
namingStrategy: new SnakeNamingStrategy()
});
}
async close (): Promise<void> {
return this._conn.close();
}
async isWatchedAddress (address: string): Promise<boolean> {
const numRows = await this._conn.getRepository(Account)
.createQueryBuilder()
.where('address = :address', { address })
.getCount();
return numRows > 0;
}
async saveAccount (address: string, startingBlock: number): Promise<void> {
await this._conn.transaction(async (tx) => {
const repo = tx.getRepository(Account);
const numRows = await repo
.createQueryBuilder()
.where('address = :address', { address })
.getCount();
if (numRows === 0) {
const entity = repo.create({ address, startingBlock });
await repo.save(entity);
}
});
}
async getAccount (address: string): Promise<Account | undefined> {
return this._conn.getRepository(Account)
.createQueryBuilder()
.where('address = :address', { address })
.getOne();
}
async getTrace (txHash: string): Promise<Trace | undefined> {
const repo = this._conn.getRepository(Trace);
return repo.findOne({ where: { txHash } });
}
async saveTrace ({ txHash, blockNumber, blockHash, trace }: DeepPartial<Trace>): Promise<void> {
await this._conn.transaction(async (tx) => {
const repo = tx.getRepository(Trace);
const numRows = await repo
.createQueryBuilder()
.where('tx_hash = :txHash', { txHash })
.getCount();
if (numRows === 0) {
const entity = repo.create({ txHash, blockNumber, blockHash, trace });
await repo.save(entity);
}
});
}
async saveTraceEntity (trace: Trace): Promise<Trace> {
const repo = this._conn.getRepository(Trace);
return repo.save(trace);
}
async getAppearances (address: string, fromBlockNumber: number, toBlockNumber: number): Promise<Trace[]> {
return this._conn.getRepository(Trace)
.createQueryBuilder('trace')
.leftJoinAndSelect('trace.accounts', 'account')
.where('address = :address AND block_number >= :fromBlockNumber AND block_number <= :toBlockNumber', { address, fromBlockNumber, toBlockNumber })
.orderBy({ block_number: 'ASC' })
.getMany();
}
async getBlockProgress (blockHash: string): Promise<BlockProgress | undefined> {
const repo = this._conn.getRepository(BlockProgress);
return repo.findOne({ where: { blockHash } });
}
async initBlockProgress (blockHash: string, blockNumber: number, numTx: number): Promise<void> {
await this._conn.transaction(async (tx) => {
const repo = tx.getRepository(BlockProgress);
const numRows = await repo
.createQueryBuilder()
.where('block_hash = :blockHash', { blockHash })
.getCount();
if (numRows === 0) {
const entity = repo.create({ blockHash, blockNumber, numTx, numTracedTx: 0, isComplete: (numTx === 0) });
await repo.save(entity);
}
});
}
async updateBlockProgress (blockHash: string): Promise<void> {
await this._conn.transaction(async (tx) => {
const repo = tx.getRepository(BlockProgress);
const entity = await repo.findOne({ where: { blockHash } });
if (entity && !entity.isComplete) {
entity.numTracedTx++;
if (entity.numTracedTx >= entity.numTx) {
entity.isComplete = true;
}
await repo.save(entity);
}
});
}
}

View File

@ -1,19 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, ManyToMany, JoinTable } from 'typeorm';
import { Trace } from './Trace';
@Entity()
export class Account {
@PrimaryColumn('varchar', { length: 42 })
address!: string;
@Column('integer')
startingBlock!: number;
@ManyToMany(() => Trace, trace => trace.accounts)
@JoinTable()
appearances: Trace[];
}

View File

@ -1,24 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
@Entity()
@Index(['blockNumber'])
export class BlockProgress {
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('integer')
numTx!: number;
@Column('integer')
numTracedTx!: number;
@Column('boolean')
isComplete!: boolean;
}

View File

@ -1,27 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index, ManyToMany } from 'typeorm';
import { Account } from './Account';
@Entity()
@Index(['txHash'], { unique: true })
@Index(['blockNumber'])
export class Trace {
@PrimaryColumn('varchar', { length: 66 })
txHash!: string;
@Column('integer')
blockNumber!: number;
@Column('varchar', { length: 66 })
blockHash!: string;
@Column('text')
trace!: string;
@ManyToMany(() => Account, account => account.appearances, { eager: true, cascade: ['insert'] })
accounts: Account[];
}

View File

@ -1,108 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import assert from 'assert';
import 'reflect-metadata';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import debug from 'debug';
import { getCache } from '@cerc-io/cache';
import { EthClient } from '@cerc-io/ipld-eth-client';
import { Config, DEFAULT_CONFIG_PATH, getConfig, JobQueue } from '@cerc-io/util';
import { Database } from './database';
import { QUEUE_TX_TRACING } from './tx-watcher';
const log = debug('vulcanize:server');
export const main = async (): Promise<any> => {
const argv = await yargs(hideBin(process.argv)).parserConfiguration({
'parse-numbers': false
}).options({
configFile: {
alias: 'f',
type: 'string',
require: true,
demandOption: true,
describe: 'configuration file path (toml)',
default: DEFAULT_CONFIG_PATH
},
startBlock: {
type: 'number',
require: true,
demandOption: true,
describe: 'Block number to start processing at'
},
endBlock: {
type: 'number',
require: true,
demandOption: true,
describe: 'Block number to stop processing at'
}
}).argv;
const config = await getConfig<Config>(argv.configFile);
assert(config.server, 'Missing server config');
const { upstream, database: dbConfig, jobQueue: jobQueueConfig } = config;
assert(dbConfig, 'Missing database config');
const db = new Database(dbConfig);
await db.init();
assert(upstream, 'Missing upstream config');
const { ethServer: { gqlApiEndpoint }, traceProviderEndpoint, cache: cacheConfig } = upstream;
assert(gqlApiEndpoint, 'Missing upstream ethServer.gqlApiEndpoint');
assert(traceProviderEndpoint, 'Missing upstream traceProviderEndpoint');
const cache = await getCache(cacheConfig);
const ethClient = new EthClient({
gqlEndpoint: gqlApiEndpoint,
cache
});
assert(jobQueueConfig, 'Missing job queue config');
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
assert(dbConnectionString, 'Missing job queue db connection string');
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
await jobQueue.start();
for (let blockNumber = argv.startBlock; blockNumber <= argv.endBlock; blockNumber++) {
log(`Fill block ${blockNumber}`);
// TODO: Add pause between requests so as to not overwhelm the upsteam server.
const result = await ethClient.getBlockWithTransactions({ blockNumber });
const { allEthHeaderCids: { nodes: blockNodes } } = result;
for (let bi = 0; bi < blockNodes.length; bi++) {
const { blockHash, ethTransactionCidsByHeaderId: { nodes: txNodes } } = blockNodes[bi];
const blockProgress = await db.getBlockProgress(blockHash);
if (blockProgress) {
log(`Block number ${blockNumber}, block hash ${blockHash} already known, skip filling`);
} else {
await db.initBlockProgress(blockHash, blockNumber, txNodes.length);
for (let ti = 0; ti < txNodes.length; ti++) {
const { txHash } = txNodes[ti];
log(`Filling block number ${blockNumber}, block hash ${blockHash}, tx hash ${txHash}`);
// Never push appearances from fill jobs to GQL subscribers, as this command can be run multiple times
// for the same block range, and/or process the same block in multiple different runs spread over a
// period of time. Also, the tx's are probably too old anyway for publishing.
await jobQueue.pushJob(QUEUE_TX_TRACING, { txHash, blockHash, publish: false, publishBlockProgress: true });
}
}
}
}
};
main().then(() => {
process.exit();
}).catch(err => {
log(err);
});

View File

@ -1,111 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import assert from 'assert';
import debug from 'debug';
import { ethers } from 'ethers';
import { EthClient } from '@cerc-io/ipld-eth-client';
import { GetStorageAt } from '@cerc-io/solidity-mapper';
import { TracingClient } from '@cerc-io/tracing-client';
import { addressesInTrace } from './util';
import { Database } from './database';
import { Trace } from './entity/Trace';
import { Account } from './entity/Account';
import { BlockProgress } from './entity/BlockProgress';
const log = debug('vulcanize:indexer');
export class Indexer {
_db: Database;
_ethClient: EthClient;
_getStorageAt: GetStorageAt;
_tracingClient: TracingClient;
constructor (db: Database, ethClient: EthClient, tracingClient: TracingClient) {
assert(db);
assert(ethClient);
assert(tracingClient);
this._db = db;
this._ethClient = ethClient;
this._tracingClient = tracingClient;
this._getStorageAt = this._ethClient.getStorageAt.bind(this._ethClient);
}
async isWatchedAddress (address : string): Promise<boolean> {
assert(address);
return this._db.isWatchedAddress(ethers.utils.getAddress(address));
}
async watchAddress (address: string, startingBlock: number): Promise<boolean> {
// Always use the checksum address (https://docs.ethers.io/v5/api/utils/address/#utils-getAddress).
await this._db.saveAccount(ethers.utils.getAddress(address), startingBlock);
return true;
}
async getTrace (txHash: string): Promise<Trace | undefined> {
return this._db.getTrace(txHash);
}
async traceTxAndIndexAppearances (txHash: string): Promise<Trace> {
let entity = await this._db.getTrace(txHash);
if (entity) {
log(`traceTx: db hit ${txHash}`);
} else {
log(`traceTx: db miss, fetching from tracing API server ${txHash}`);
const tx = await this._tracingClient.getTx(txHash);
const trace = await this._tracingClient.getTxTrace(txHash, 'callTraceWithAddresses', '15s');
await this._db.saveTrace({
txHash,
blockNumber: tx.blockNumber,
blockHash: tx.blockHash,
trace: JSON.stringify(trace)
});
entity = await this._db.getTrace(txHash);
assert(entity);
await this._indexAppearances(entity);
}
return entity;
}
async getAppearances (address: string, fromBlockNumber: number, toBlockNumber: number): Promise<Trace[]> {
return this._db.getAppearances(address, fromBlockNumber, toBlockNumber);
}
async getBlockProgress (blockHash: string): Promise<BlockProgress | undefined> {
return this._db.getBlockProgress(blockHash);
}
async updateBlockProgress (blockHash: string): Promise<void> {
return this._db.updateBlockProgress(blockHash);
}
async _indexAppearances (trace: Trace): Promise<Trace> {
const traceObj = JSON.parse(trace.trace);
// TODO: Check if tx has failed?
const addresses = addressesInTrace(traceObj);
trace.accounts = addresses.map((address: string) => {
assert(address);
const account = new Account();
account.address = ethers.utils.getAddress(address);
account.startingBlock = trace.blockNumber;
return account;
});
return await this._db.saveTraceEntity(trace);
}
}

View File

@ -1,78 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import assert from 'assert';
import 'reflect-metadata';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import debug from 'debug';
import { getCache } from '@cerc-io/cache';
import { EthClient } from '@cerc-io/ipld-eth-client';
import { TracingClient } from '@cerc-io/tracing-client';
import { getConfig, JobQueue, DEFAULT_CONFIG_PATH, Config } from '@cerc-io/util';
import { Indexer } from './indexer';
import { Database } from './database';
import { QUEUE_TX_TRACING } from './tx-watcher';
const log = debug('vulcanize:server');
export const main = async (): Promise<any> => {
const argv = await yargs(hideBin(process.argv))
.option('f', {
alias: 'config-file',
demandOption: true,
describe: 'configuration file path (toml)',
type: 'string',
default: DEFAULT_CONFIG_PATH
})
.argv;
const config: Config = await getConfig(argv.f);
assert(config.server, 'Missing server config');
const { upstream, database: dbConfig, jobQueue: jobQueueConfig } = config;
assert(dbConfig, 'Missing database config');
const db = new Database(dbConfig);
await db.init();
assert(upstream, 'Missing upstream config');
const { ethServer: { gqlApiEndpoint }, traceProviderEndpoint, cache: cacheConfig } = upstream;
assert(gqlApiEndpoint, 'Missing upstream ethServer.gqlApiEndpoint');
assert(traceProviderEndpoint, 'Missing upstream traceProviderEndpoint');
const cache = await getCache(cacheConfig);
const ethClient = new EthClient({
gqlEndpoint: gqlApiEndpoint,
cache
});
const tracingClient = new TracingClient(traceProviderEndpoint);
const indexer = new Indexer(db, ethClient, tracingClient);
assert(jobQueueConfig, 'Missing job queue config');
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
assert(dbConnectionString, 'Missing job queue db connection string');
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
await jobQueue.start();
await jobQueue.subscribe(QUEUE_TX_TRACING, async (job) => {
const { data: { txHash } } = job;
await indexer.traceTxAndIndexAppearances(txHash);
await jobQueue.markComplete(job);
});
};
main().then(() => {
log('Starting job runner...');
}).catch(err => {
log(err);
});

View File

@ -1,73 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import debug from 'debug';
import { withFilter } from 'graphql-subscriptions';
import { ethers } from 'ethers';
import { Indexer } from './indexer';
import { TxWatcher } from './tx-watcher';
const log = debug('vulcanize:resolver');
interface WatchAddressParams {
address: string,
startingBlock: number
}
interface AppearanceParams {
address: string,
fromBlockNumber: number,
toBlockNumber: number
}
export const createResolvers = async (indexer: Indexer, txWatcher: TxWatcher): Promise<any> => {
return {
Subscription: {
onAddressEvent: {
subscribe: withFilter(
() => txWatcher.getAddressEventIterator(),
(payload: any, variables: any) => {
return payload.onAddressEvent.address === ethers.utils.getAddress(variables.address);
}
)
},
onBlockProgressEvent: {
subscribe: () => txWatcher.getBlockProgressEventIterator()
}
},
Mutation: {
watchAddress: (_: any, { address, startingBlock = 1 }: WatchAddressParams): Promise<boolean> => {
address = ethers.utils.getAddress(address);
log('watchAddress', address, startingBlock);
return indexer.watchAddress(address, startingBlock);
}
},
Query: {
appearances: async (_: any, { address, fromBlockNumber, toBlockNumber }: AppearanceParams): Promise<any> => {
address = ethers.utils.getAddress(address);
log('appearances', address, fromBlockNumber, toBlockNumber);
return indexer.getAppearances(address, fromBlockNumber, toBlockNumber);
},
traceTx: async (_: any, { txHash }: { txHash: string }): Promise<any> => {
log('traceTx', txHash);
const { blockHash, blockNumber, trace } = await indexer.traceTxAndIndexAppearances(txHash);
return {
txHash,
blockNumber,
blockHash,
trace
};
}
}
};
};

View File

@ -1,79 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { gql } from '@apollo/client/core';
export default gql`
# Types
type TxTrace {
txHash: String!
blockNumber: Int!
blockHash: String!
trace: String!
}
# Watched address event, include additional context over and above the event data.
type WatchedAddressEvent {
address: String!
txTrace: TxTrace!
}
type BlockProgressEvent {
blockNumber: Int!
blockHash: String!
numTx: Int!
numTracedTx: Int!
isComplete: Boolean!
}
#
# Queries
#
type Query {
#
# Developer API methods
#
appearances(
address: String!
fromBlockNumber: Int!
toBlockNumber: Int!
): [TxTrace!]
#
# Low level utility methods
#
traceTx(
txHash: String!
): TxTrace
}
#
# Subscriptions
#
type Subscription {
# Watch for address events (at head of chain).
onAddressEvent(address: String!): WatchedAddressEvent!
# Watch for block progress events from filler process.
onBlockProgressEvent: BlockProgressEvent!
}
#
# Mutations
#
type Mutation {
# Actively watch and index data for the address.
watchAddress(
address: String!
startingBlock: Int
): Boolean!
}
`;

View File

@ -1,92 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import assert from 'assert';
import 'reflect-metadata';
import express, { Application } from 'express';
import { PubSub } from 'graphql-subscriptions';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import debug from 'debug';
import { getCache } from '@cerc-io/cache';
import { EthClient } from '@cerc-io/ipld-eth-client';
import { TracingClient } from '@cerc-io/tracing-client';
import { getConfig, JobQueue, DEFAULT_CONFIG_PATH, createAndStartServer, Config } from '@cerc-io/util';
import typeDefs from './schema';
import { createResolvers } from './resolvers';
import { Indexer } from './indexer';
import { Database } from './database';
import { TxWatcher } from './tx-watcher';
const log = debug('vulcanize:server');
export const main = async (): Promise<any> => {
const argv = await yargs(hideBin(process.argv))
.option('f', {
alias: 'config-file',
demandOption: true,
describe: 'configuration file path (toml)',
type: 'string',
default: DEFAULT_CONFIG_PATH
})
.argv;
const config: Config = await getConfig(argv.f);
assert(config.server, 'Missing server config');
const { upstream, database: dbConfig, jobQueue: jobQueueConfig } = config;
assert(dbConfig, 'Missing database config');
const db = new Database(dbConfig);
await db.init();
assert(upstream, 'Missing upstream config');
const { ethServer: { gqlApiEndpoint }, traceProviderEndpoint, cache: cacheConfig } = upstream;
assert(gqlApiEndpoint, 'Missing upstream ethServer.gqlApiEndpoint');
assert(traceProviderEndpoint, 'Missing upstream traceProviderEndpoint');
const cache = await getCache(cacheConfig);
const ethClient = new EthClient({
gqlEndpoint: gqlApiEndpoint,
cache
});
const tracingClient = new TracingClient(traceProviderEndpoint);
const indexer = new Indexer(db, ethClient, tracingClient);
assert(jobQueueConfig, 'Missing job queue config');
const { dbConnectionString, maxCompletionLagInSecs } = jobQueueConfig;
assert(dbConnectionString, 'Missing job queue db connection string');
assert(dbConnectionString, 'Missing job queue max completion lag time (seconds)');
const jobQueue = new JobQueue({ dbConnectionString, maxCompletionLag: maxCompletionLagInSecs });
await jobQueue.start();
// Note: In-memory pubsub works fine for now, as each watcher is a single process anyway.
// Later: https://www.apollographql.com/docs/apollo-server/data/subscriptions/#production-pubsub-libraries
const pubsub = new PubSub();
const txWatcher = new TxWatcher(ethClient, indexer, pubsub, jobQueue);
await txWatcher.start();
const resolvers = await createResolvers(indexer, txWatcher);
// Create an Express app
const app: Application = express();
const server = createAndStartServer(app, typeDefs, resolvers, config.server);
return { app, server };
};
main().then(() => {
log('Starting server...');
}).catch(err => {
log(err);
});

View File

@ -1,126 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import assert from 'assert';
import debug from 'debug';
import { PubSub } from 'graphql-subscriptions';
import { EthClient } from '@cerc-io/ipld-eth-client';
import { JobQueue } from '@cerc-io/util';
import { Indexer } from './indexer';
import { BlockProgress } from './entity/BlockProgress';
const log = debug('vulcanize:tx-watcher');
export const AddressEvent = 'address-event';
export const BlockProgressEvent = 'block-progress-event';
export const QUEUE_TX_TRACING = 'tx-tracing';
export class TxWatcher {
_ethClient: EthClient;
_indexer: Indexer;
_pubsub: PubSub;
_watchTxSubscription: ZenObservable.Subscription | undefined;
_jobQueue: JobQueue;
constructor (ethClient: EthClient, indexer: Indexer, pubsub: PubSub, jobQueue: JobQueue) {
this._ethClient = ethClient;
this._indexer = indexer;
this._pubsub = pubsub;
this._jobQueue = jobQueue;
}
getAddressEventIterator (): AsyncIterator<any> {
return this._pubsub.asyncIterator([AddressEvent]);
}
getBlockProgressEventIterator (): AsyncIterator<any> {
return this._pubsub.asyncIterator([BlockProgressEvent]);
}
async start (): Promise<void> {
assert(!this._watchTxSubscription, 'subscription already started');
log('Started watching upstream tx...');
this._jobQueue.onComplete(QUEUE_TX_TRACING, async (job) => {
const { data: { request, failed, state, createdOn } } = job;
await this._indexer.updateBlockProgress(request.data.blockHash);
const blockProgress = await this._indexer.getBlockProgress(request.data.blockHash);
if (blockProgress && request.data.publishBlockProgress) {
await this.publishBlockProgressToSubscribers(blockProgress);
}
const timeElapsedInSeconds = (Date.now() - Date.parse(createdOn)) / 1000;
log(`Job onComplete tx ${request.data.txHash} publish ${!!request.data.publish}`);
if (!failed && state === 'completed' && request.data.publish) {
// Check for max acceptable lag time between tracing request and sending results to live subscribers.
if (timeElapsedInSeconds <= this._jobQueue.maxCompletionLag) {
return await this.publishAddressEventToSubscribers(request.data.txHash, timeElapsedInSeconds);
} else {
log(`tx ${request.data.txHash} is too old (${timeElapsedInSeconds}s), not broadcasting to live subscribers`);
}
}
});
// TODO: Update to pull based watcher.
// this._watchTxSubscription = await this._ethClient.watchTransactions(async (value) => {
// const { txHash, ethHeaderCidByHeaderId: { blockHash, blockNumber } } = _.get(value, 'data.listen.relatedNode');
// log('watchTransaction', JSON.stringify({ txHash, blockHash, blockNumber }, null, 2));
// await this._jobQueue.pushJob(QUEUE_TX_TRACING, { txHash, blockHash, publish: true });
// });
}
async publishAddressEventToSubscribers (txHash: string, timeElapsedInSeconds: number): Promise<void> {
const traceObj = await this._indexer.getTrace(txHash);
if (!traceObj) {
return;
}
const { blockNumber, blockHash, trace } = traceObj;
for (let i = 0; i < traceObj.accounts.length; i++) {
const account = traceObj.accounts[i];
log(`publishing trace for ${txHash} (${timeElapsedInSeconds}s elapsed) to GQL subscribers for address ${account.address}`);
// Publishing the event here will result in pushing the payload to GQL subscribers for `onAddressEvent(address)`.
await this._pubsub.publish(AddressEvent, {
onAddressEvent: {
address: account.address,
txTrace: {
txHash,
blockHash,
blockNumber,
trace
}
}
});
}
}
async publishBlockProgressToSubscribers (blockProgress: BlockProgress): Promise<void> {
const { blockHash, blockNumber, numTx, numTracedTx, isComplete } = blockProgress;
// Publishing the event here will result in pushing the payload to GQL subscribers for `onAddressEvent(address)`.
await this._pubsub.publish(BlockProgressEvent, {
onBlockProgressEvent: {
blockHash,
blockNumber,
numTx,
numTracedTx,
isComplete
}
});
}
async stop (): Promise<void> {
if (this._watchTxSubscription) {
log('Stopped watching upstream tx');
this._watchTxSubscription.unsubscribe();
}
}
}

View File

@ -1,7 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
// https://medium.com/@steveruiz/using-a-javascript-library-without-type-declarations-in-a-typescript-project-3643490015f3
declare module 'canonical-json'
declare module 'lodash-contrib';

View File

@ -1,6 +0,0 @@
{
"name": "common",
"version": "0.1.0",
"license": "AGPL-3.0",
"typings": "main.d.ts"
}

View File

@ -1,150 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { describe, it } from 'mocha';
import { expect } from 'chai';
import { addressesInTrace } from './util';
describe('addressInTrace', () => {
it('should parse an empty trace', () => {
const addresses = addressesInTrace({});
expect(addresses).to.eql([]);
});
it('should parse an unnested trace', () => {
const addresses = addressesInTrace({
from: '0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc',
to: '0xCA6D29232D1435D8198E3E5302495417dD073d61'
});
expect(addresses).to.eql([
'0xCA6D29232D1435D8198E3E5302495417dD073d61',
'0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc'
]);
});
it('should parse an unnested trace with an addresses field', () => {
const addresses = addressesInTrace({
from: '0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc',
to: '0xCA6D29232D1435D8198E3E5302495417dD073d61',
addresses: {
'0x9273D9437B0bf2F1b7999d8dB72960d6379564d1': {},
'0xd86fB467B78901310e9967A2C8B601A5E794c12C': {}
}
});
expect(addresses).to.eql([
'0x9273D9437B0bf2F1b7999d8dB72960d6379564d1',
'0xCA6D29232D1435D8198E3E5302495417dD073d61',
'0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc',
'0xd86fB467B78901310e9967A2C8B601A5E794c12C'
]);
});
it('should parse a nested trace', () => {
const addresses = addressesInTrace({
from: '0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc',
to: '0xCA6D29232D1435D8198E3E5302495417dD073d61',
calls: [{
from: '0x9273D9437B0bf2F1b7999d8dB72960d6379564d1',
to: '0xd86fB467B78901310e9967A2C8B601A5E794c12C'
},
{
from: '0xf29340ca4ad7A797dF2d67Be58d354EC284AE62f',
to: '0xEcFF6b14D3ed9569108b413f846279E64E39BC92'
}]
});
expect(addresses).to.eql([
'0x9273D9437B0bf2F1b7999d8dB72960d6379564d1',
'0xCA6D29232D1435D8198E3E5302495417dD073d61',
'0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc',
'0xEcFF6b14D3ed9569108b413f846279E64E39BC92',
'0xd86fB467B78901310e9967A2C8B601A5E794c12C',
'0xf29340ca4ad7A797dF2d67Be58d354EC284AE62f'
]);
});
it('should parse a nested trace with an addresses field', () => {
const addresses = addressesInTrace({
from: '0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc',
to: '0xCA6D29232D1435D8198E3E5302495417dD073d61',
calls: [{
from: '0x9273D9437B0bf2F1b7999d8dB72960d6379564d1',
to: '0xd86fB467B78901310e9967A2C8B601A5E794c12C',
addresses: {
'0xf29340ca4ad7A797dF2d67Be58d354EC284AE62f': {},
'0xEcFF6b14D3ed9569108b413f846279E64E39BC92': {}
}
}]
});
expect(addresses).to.eql([
'0x9273D9437B0bf2F1b7999d8dB72960d6379564d1',
'0xCA6D29232D1435D8198E3E5302495417dD073d61',
'0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc',
'0xEcFF6b14D3ed9569108b413f846279E64E39BC92',
'0xd86fB467B78901310e9967A2C8B601A5E794c12C',
'0xf29340ca4ad7A797dF2d67Be58d354EC284AE62f'
]);
});
it('should not return duplicate addresses', () => {
const addresses = addressesInTrace({
from: '0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc',
to: '0xCA6D29232D1435D8198E3E5302495417dD073d61',
calls: [{
from: '0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc',
to: '0xCA6D29232D1435D8198E3E5302495417dD073d61',
addresses: {
'0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc': {},
'0xCA6D29232D1435D8198E3E5302495417dD073d61': {}
}
}]
});
expect(addresses).to.eql([
'0xCA6D29232D1435D8198E3E5302495417dD073d61',
'0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc'
]);
});
it('should return correct addresses for an ERC20 transfer', () => {
/* eslint-disable */
const trace = {
"type": "CALL",
"from": "0xdc7d7a8920c8eecc098da5b7522a5f31509b5bfc",
"to": "0x1ca7c995f8ef0a2989bbce08d5b7efe50a584aa1",
"value": "0x0",
"gas": "0x4edf",
"gasUsed": "0x3982",
"input": "0xa9059cbb000000000000000000000000ca6d29232d1435d8198e3e5302495417dd073d610000000000000000000000000000000000000000000000000de0b6b3a7640000",
"output": "0x0000000000000000000000000000000000000000000000000000000000000001",
"time": "66.609994ms",
"addresses": {
"0xca6d29232d1435d8198e3e5302495417dd073d61": {
"confidence": 1,
"opcodes": [
"CALLDATALOAD", "AND", "SWAP1", "DUP5", "DUP3", "AND", "DUP4", "POP", "DUP6", "AND", "AND", "DUP5", "AND", "AND", "DUP2", "AND", "POP", "SWAP2"
]
},
"0xdc7d7a8920c8eecc098da5b7522a5f31509b5bfc": {
"confidence": 1,
"opcodes": [
"CALLER", "POP", "JUMP", "JUMPDEST", "DUP4", "AND", "DUP4", "POP", "DUP8", "AND", "AND", "DUP6", "AND", "AND", "DUP4", "AND", "POP"
]
}
}
};
/* eslint-enable */
const addresses = addressesInTrace(trace);
expect(addresses).to.eql([
'0x1ca7c995f8eF0A2989BbcE08D5B7Efe50A584aa1',
'0xCA6D29232D1435D8198E3E5302495417dD073d61',
'0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc'
]);
});
});

View File

@ -1,33 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import _ from 'lodash';
import { ethers } from 'ethers';
export const addressesInTrace = (obj: any): any => {
return _.uniq(_.compact(_.flattenDeep(addressesIn(obj))))
.sort()
.map(address => ethers.utils.getAddress(<string>address));
};
const addressesIn = (obj: any): any => {
const addresses: any = [];
if (obj) {
addresses.push(obj.from);
addresses.push(obj.to);
if (obj.addresses) {
addresses.push(_.keys(obj.addresses));
}
if (obj.calls) {
obj.calls.forEach((call: any) => {
addresses.push(addressesIn(call));
});
}
}
return addresses;
};

View File

@ -1,77 +0,0 @@
{
"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": false, /* 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", "src/**/*.test.ts"]
}

View File

@ -28,8 +28,10 @@
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.14", "@types/express": "^4.17.14",
"@types/node": "16.11.7", "@types/node": "16.11.7",
"@types/yargs": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^5.47.1", "@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1", "@typescript-eslint/parser": "^5.47.1",
"copyfiles": "^2.4.1",
"eslint-config-semistandard": "^15.0.1", "eslint-config-semistandard": "^15.0.1",
"eslint-config-standard": "^5.0.0", "eslint-config-standard": "^5.0.0",
"eslint-plugin-import": "^2.27.5", "eslint-plugin-import": "^2.27.5",

View File

@ -40,7 +40,9 @@
"devDependencies": { "devDependencies": {
"@openzeppelin/contracts": "^4.3.2", "@openzeppelin/contracts": "^4.3.2",
"@types/js-yaml": "^4.0.3", "@types/js-yaml": "^4.0.3",
"@types/lodash": "^4.14.168",
"@types/node": "^16.9.0", "@types/node": "^16.9.0",
"@types/yargs": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^5.47.1", "@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1", "@typescript-eslint/parser": "^5.47.1",
"eslint": "^8.35.0", "eslint": "^8.35.0",

View File

@ -1,2 +0,0 @@
# Don't lint build output.
dist

View File

@ -1,28 +0,0 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"semistandard",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"indent": ["error", 2, { "SwitchCase": 1 }],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-module-boundary-types": [
"warn",
{
"allowArgumentsExplicitlyTypedAsAny": true
}
]
}
}

View File

@ -1,16 +0,0 @@
# EdenNetwork Watcher
## Setup
First try the [stack orchestrator](https://github.com/cerc-io/stack-orchestrator) to quickly get started. Advanced users can see [here](/docs/README.md) for instructions on setting up a local environment by hand.
## Run
Setup with:
```bash
yarn && yarn build
```
then checkout the [CLI guide](/docs/cli.md) for examples of commands that can be run on this watcher.

View File

@ -1,43 +0,0 @@
# Config to generate eden-watcher using codegen.
# Contracts to watch (required).
contracts:
# Contract name.
- name: EdenNetwork
# Contract file path or an url.
path: ~/eden/governance/contracts/EdenNetwork.sol
# Contract kind (should match that in {subgraphPath}/subgraph.yaml if subgraphPath provided)
kind: EdenNetwork
# Contract name.
- name: MerkleDistributor
# Contract file path or an url.
path: ~/eden/governance/contracts/MerkleDistributor.sol
# Contract kind (should match that in {subgraphPath}/subgraph.yaml if subgraphPath provided)
kind: EdenNetworkDistribution
# Contract name.
- name: DistributorGovernance
# Contract file path or an url.
path: ~/eden/governance/contracts/DistributorGovernance.sol
# Contract kind (should match that in {subgraphPath}/subgraph.yaml if subgraphPath provided)
kind: EdenNetworkGovernance
# Output folder path (logs output using `stdout` if not provided).
outputFolder: ../demo-eden-watcher
# Code generation mode [eth_call | storage | all | none] (default: all).
mode: none
# Kind of watcher [lazy | active] (default: active).
kind: active
# Watcher server port (default: 3008).
port: 3012
# Flatten the input contract file(s) [true | false] (default: true).
flatten: true
# Path to the subgraph build (optional).
subgraphPath: ~/eden/eden-data/packages/subgraph/build
# NOTE: When passed an *URL* as contract path, it is assumed that it points to an already flattened contract file.

View File

@ -1,75 +0,0 @@
[server]
host = "127.0.0.1"
port = 3012
kind = "active"
# Checkpointing state.
checkpointing = true
# Checkpoint interval in number of blocks.
checkpointInterval = 2000
subgraphPath = "../graph-node/test/subgraph/eden"
# Enable state creation
# CAUTION: Disable only if state creation is not desired or can be filled subsequently
enableState = true
# Interval to restart wasm instance periodically
wasmRestartBlocksInterval = 20
# Boolean to filter logs by contract.
filterLogs = true
# Max block range for which to return events in eventsInRange GQL query.
# Use -1 for skipping check on block range.
maxEventsBlockRange = 1000
# Interval in number of blocks at which to clear entities cache.
clearEntitiesCacheInterval = 1000
# GQL cache settings
[server.gqlCache]
enabled = true
# Max in-memory cache size (in bytes) (default 8 MB)
# maxCacheSize
# GQL cache-control max-age settings (in seconds)
maxAge = 15
timeTravelMaxAge = 86400 # 1 day
[metrics]
host = "127.0.0.1"
port = 9000
[metrics.gql]
port = 9001
[database]
type = "postgres"
host = "localhost"
port = 5432
database = "eden-watcher"
username = "postgres"
password = "postgres"
synchronize = true
logging = false
[upstream]
[upstream.ethServer]
gqlApiEndpoint = "http://127.0.0.1:8083/graphql"
rpcProviderEndpoint = "http://127.0.0.1:8082"
[upstream.cache]
name = "requests"
enabled = false
deleteOnStart = false
[jobQueue]
dbConnectionString = "postgres://postgres:postgres@localhost/eden-watcher-job-queue"
maxCompletionLagInSecs = 300
jobDelayInMilliSecs = 100
eventsInBatch = 50
blockDelayInMilliSecs = 2000
prefetchBlocksInMem = true
prefetchBlockCount = 10

View File

@ -1,72 +0,0 @@
{
"name": "@cerc-io/eden-watcher",
"version": "0.2.38",
"description": "eden-watcher",
"private": true,
"main": "dist/index.js",
"scripts": {
"lint": "eslint .",
"build": "yarn clean && tsc && yarn copy-assets",
"clean": "rm -rf ./dist",
"copy-assets": "copyfiles -u 1 src/**/*.gql dist/",
"server": "DEBUG=vulcanize:* YARN_CHILD_PROCESS=true node --enable-source-maps dist/server.js",
"server:dev": "DEBUG=vulcanize:* YARN_CHILD_PROCESS=true ts-node src/server.ts",
"job-runner": "DEBUG=vulcanize:* YARN_CHILD_PROCESS=true node --max-old-space-size=3072 --enable-source-maps dist/job-runner.js",
"job-runner:dev": "DEBUG=vulcanize:* YARN_CHILD_PROCESS=true ts-node src/job-runner.ts",
"watch:contract": "DEBUG=vulcanize:* ts-node src/cli/watch-contract.ts",
"fill": "DEBUG=vulcanize:* ts-node src/fill.ts",
"fill:state": "DEBUG=vulcanize:* ts-node src/fill.ts --state",
"reset": "DEBUG=vulcanize:* ts-node src/cli/reset.ts",
"checkpoint": "DEBUG=vulcanize:* node --enable-source-maps --max-old-space-size=3072 dist/cli/checkpoint.js",
"checkpoint:dev": "DEBUG=vulcanize:* ts-node src/cli/checkpoint.ts",
"export-state": "DEBUG=vulcanize:* node --enable-source-maps --max-old-space-size=3072 dist/cli/export-state.js",
"export-state:dev": "DEBUG=vulcanize:* ts-node src/cli/export-state.ts",
"import-state": "DEBUG=vulcanize:* node --enable-source-maps --max-old-space-size=3072 dist/cli/import-state.js",
"import-state:dev": "DEBUG=vulcanize:* ts-node src/cli/import-state.ts",
"inspect-cid": "DEBUG=vulcanize:* ts-node src/cli/inspect-cid.ts",
"index-block": "DEBUG=vulcanize:* ts-node src/cli/index-block.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/cerc-io/watcher-ts.git"
},
"author": "",
"license": "AGPL-3.0",
"bugs": {
"url": "https://github.com/cerc-io/watcher-ts/issues"
},
"homepage": "https://github.com/cerc-io/watcher-ts#readme",
"dependencies": {
"@apollo/client": "^3.3.19",
"@cerc-io/cli": "^0.2.38",
"@cerc-io/graph-node": "^0.2.38",
"@cerc-io/ipld-eth-client": "^0.2.38",
"@cerc-io/solidity-mapper": "^0.2.38",
"@cerc-io/util": "^0.2.38",
"@ethersproject/providers": "^5.4.4",
"apollo-type-bigint": "^0.1.3",
"debug": "^4.3.1",
"decimal.js": "^10.3.1",
"ethers": "^5.4.4",
"graphql": "^15.5.0",
"reflect-metadata": "^0.1.13",
"typeorm": "^0.2.32",
"yargs": "^17.0.1"
},
"devDependencies": {
"@ethersproject/abi": "^5.3.0",
"@types/yargs": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"copyfiles": "^2.4.1",
"eslint": "^8.35.0",
"eslint-config-semistandard": "^15.0.1",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-standard": "^5.0.0",
"ts-node": "^10.2.1",
"typescript": "^5.0.2"
}
}

View File

@ -1,723 +0,0 @@
{
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "_admin",
"type": "address"
},
{
"internalType": "address[]",
"name": "_blockProducers",
"type": "address[]"
},
{
"internalType": "address[]",
"name": "_collectors",
"type": "address[]"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "producer",
"type": "address"
}
],
"name": "BlockProducerAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "producer",
"type": "address"
}
],
"name": "BlockProducerRemoved",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "producer",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "collector",
"type": "address"
}
],
"name": "BlockProducerRewardCollectorChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [],
"name": "RewardScheduleChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "previousAdminRole",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "newAdminRole",
"type": "bytes32"
}
],
"name": "RoleAdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleGranted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleRevoked",
"type": "event"
},
{
"inputs": [],
"name": "DEFAULT_ADMIN_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "DELEGATOR_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "GOV_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "REWARD_SCHEDULE_ENTRY_LENGTH",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "producer",
"type": "address"
}
],
"name": "add",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "producers",
"type": "address[]"
}
],
"name": "addBatch",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "blockProducer",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "producer",
"type": "address"
},
{
"internalType": "address",
"name": "collector",
"type": "address"
}
],
"name": "delegate",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "producers",
"type": "address[]"
},
{
"internalType": "address[]",
"name": "collectors",
"type": "address[]"
}
],
"name": "delegateBatch",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "getRoleAdmin",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "getRoleMember",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "getRoleMemberCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "grantRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "hasRole",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "producer",
"type": "address"
}
],
"name": "remove",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "producers",
"type": "address[]"
}
],
"name": "removeBatch",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "renounceRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "revokeRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "rewardCollector",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "rewardScheduleEntries",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "rewardScheduleEntry",
"outputs": [
{
"components": [
{
"internalType": "uint64",
"name": "startTime",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "epochDuration",
"type": "uint64"
},
{
"internalType": "uint128",
"name": "rewardsPerEpoch",
"type": "uint128"
}
],
"internalType": "struct IGovernance.RewardScheduleEntry",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "set",
"type": "bytes"
}
],
"name": "setRewardSchedule",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
],
"storageLayout": {
"storage": [
{
"astId": 380,
"contract": "DistributorGovernance.sol:DistributorGovernance",
"label": "_roles",
"offset": 0,
"slot": "0",
"type": "t_mapping(t_bytes32,t_struct(RoleData)375_storage)"
},
{
"astId": 1210,
"contract": "DistributorGovernance.sol:DistributorGovernance",
"label": "_roleMembers",
"offset": 0,
"slot": "1",
"type": "t_mapping(t_bytes32,t_struct(AddressSet)969_storage)"
},
{
"astId": 1721,
"contract": "DistributorGovernance.sol:DistributorGovernance",
"label": "rewardCollector",
"offset": 0,
"slot": "2",
"type": "t_mapping(t_address,t_address)"
},
{
"astId": 1727,
"contract": "DistributorGovernance.sol:DistributorGovernance",
"label": "blockProducer",
"offset": 0,
"slot": "3",
"type": "t_mapping(t_address,t_bool)"
},
{
"astId": 1730,
"contract": "DistributorGovernance.sol:DistributorGovernance",
"label": "_rewardSchedule",
"offset": 0,
"slot": "4",
"type": "t_bytes_storage"
}
],
"types": {
"t_address": {
"encoding": "inplace",
"label": "address",
"numberOfBytes": "20"
},
"t_array(t_bytes32)dyn_storage": {
"base": "t_bytes32",
"encoding": "dynamic_array",
"label": "bytes32[]",
"numberOfBytes": "32"
},
"t_bool": {
"encoding": "inplace",
"label": "bool",
"numberOfBytes": "1"
},
"t_bytes32": {
"encoding": "inplace",
"label": "bytes32",
"numberOfBytes": "32"
},
"t_bytes_storage": {
"encoding": "bytes",
"label": "bytes",
"numberOfBytes": "32"
},
"t_mapping(t_address,t_address)": {
"encoding": "mapping",
"key": "t_address",
"label": "mapping(address => address)",
"numberOfBytes": "32",
"value": "t_address"
},
"t_mapping(t_address,t_bool)": {
"encoding": "mapping",
"key": "t_address",
"label": "mapping(address => bool)",
"numberOfBytes": "32",
"value": "t_bool"
},
"t_mapping(t_bytes32,t_struct(AddressSet)969_storage)": {
"encoding": "mapping",
"key": "t_bytes32",
"label": "mapping(bytes32 => struct EnumerableSet.AddressSet)",
"numberOfBytes": "32",
"value": "t_struct(AddressSet)969_storage"
},
"t_mapping(t_bytes32,t_struct(RoleData)375_storage)": {
"encoding": "mapping",
"key": "t_bytes32",
"label": "mapping(bytes32 => struct AccessControl.RoleData)",
"numberOfBytes": "32",
"value": "t_struct(RoleData)375_storage"
},
"t_mapping(t_bytes32,t_uint256)": {
"encoding": "mapping",
"key": "t_bytes32",
"label": "mapping(bytes32 => uint256)",
"numberOfBytes": "32",
"value": "t_uint256"
},
"t_struct(AddressSet)969_storage": {
"encoding": "inplace",
"label": "struct EnumerableSet.AddressSet",
"members": [
{
"astId": 968,
"contract": "DistributorGovernance.sol:DistributorGovernance",
"label": "_inner",
"offset": 0,
"slot": "0",
"type": "t_struct(Set)698_storage"
}
],
"numberOfBytes": "64"
},
"t_struct(RoleData)375_storage": {
"encoding": "inplace",
"label": "struct AccessControl.RoleData",
"members": [
{
"astId": 372,
"contract": "DistributorGovernance.sol:DistributorGovernance",
"label": "members",
"offset": 0,
"slot": "0",
"type": "t_mapping(t_address,t_bool)"
},
{
"astId": 374,
"contract": "DistributorGovernance.sol:DistributorGovernance",
"label": "adminRole",
"offset": 0,
"slot": "1",
"type": "t_bytes32"
}
],
"numberOfBytes": "64"
},
"t_struct(Set)698_storage": {
"encoding": "inplace",
"label": "struct EnumerableSet.Set",
"members": [
{
"astId": 693,
"contract": "DistributorGovernance.sol:DistributorGovernance",
"label": "_values",
"offset": 0,
"slot": "0",
"type": "t_array(t_bytes32)dyn_storage"
},
{
"astId": 697,
"contract": "DistributorGovernance.sol:DistributorGovernance",
"label": "_indexes",
"offset": 0,
"slot": "1",
"type": "t_mapping(t_bytes32,t_uint256)"
}
],
"numberOfBytes": "64"
},
"t_uint256": {
"encoding": "inplace",
"label": "uint256",
"numberOfBytes": "32"
}
}
}
}

View File

@ -1,942 +0,0 @@
{
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "newAdmin",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "oldAdmin",
"type": "address"
}
],
"name": "AdminUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint8",
"name": "slot",
"type": "uint8"
},
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "delegate",
"type": "address"
},
{
"indexed": false,
"internalType": "uint128",
"name": "newBidAmount",
"type": "uint128"
},
{
"indexed": false,
"internalType": "uint128",
"name": "oldBidAmount",
"type": "uint128"
},
{
"indexed": false,
"internalType": "uint16",
"name": "taxNumerator",
"type": "uint16"
},
{
"indexed": false,
"internalType": "uint16",
"name": "taxDenominator",
"type": "uint16"
}
],
"name": "SlotClaimed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint8",
"name": "slot",
"type": "uint8"
},
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newDelegate",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "oldDelegate",
"type": "address"
}
],
"name": "SlotDelegateUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "staker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "stakeAmount",
"type": "uint256"
}
],
"name": "Stake",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint16",
"name": "newNumerator",
"type": "uint16"
},
{
"indexed": false,
"internalType": "uint16",
"name": "newDenominator",
"type": "uint16"
},
{
"indexed": false,
"internalType": "uint16",
"name": "oldNumerator",
"type": "uint16"
},
{
"indexed": false,
"internalType": "uint16",
"name": "oldDenominator",
"type": "uint16"
}
],
"name": "TaxRateUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "staker",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "unstakedAmount",
"type": "uint256"
}
],
"name": "Unstake",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "withdrawer",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "withdrawalAmount",
"type": "uint256"
}
],
"name": "Withdraw",
"type": "event"
},
{
"inputs": [],
"name": "MIN_BID",
"outputs": [
{
"internalType": "uint128",
"name": "",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "admin",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "slot",
"type": "uint8"
},
{
"internalType": "uint128",
"name": "bid",
"type": "uint128"
},
{
"internalType": "address",
"name": "delegate",
"type": "address"
}
],
"name": "claimSlot",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "slot",
"type": "uint8"
},
{
"internalType": "uint128",
"name": "bid",
"type": "uint128"
},
{
"internalType": "address",
"name": "delegate",
"type": "address"
},
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"name": "claimSlotWithPermit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract IERC20Extended",
"name": "_token",
"type": "address"
},
{
"internalType": "contract ILockManager",
"name": "_lockManager",
"type": "address"
},
{
"internalType": "address",
"name": "_admin",
"type": "address"
},
{
"internalType": "uint16",
"name": "_taxNumerator",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "_taxDenominator",
"type": "uint16"
}
],
"name": "initialize",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "lockManager",
"outputs": [
{
"internalType": "contract ILockManager",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "lockedBalance",
"outputs": [
{
"internalType": "uint128",
"name": "",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newAdmin",
"type": "address"
}
],
"name": "setAdmin",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "slot",
"type": "uint8"
},
{
"internalType": "address",
"name": "delegate",
"type": "address"
}
],
"name": "setSlotDelegate",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint16",
"name": "numerator",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "denominator",
"type": "uint16"
}
],
"name": "setTaxRate",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "slot",
"type": "uint8"
}
],
"name": "slotBalance",
"outputs": [
{
"internalType": "uint128",
"name": "balance",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"name": "slotBid",
"outputs": [
{
"internalType": "address",
"name": "bidder",
"type": "address"
},
{
"internalType": "uint16",
"name": "taxNumerator",
"type": "uint16"
},
{
"internalType": "uint16",
"name": "taxDenominator",
"type": "uint16"
},
{
"internalType": "uint64",
"name": "periodStart",
"type": "uint64"
},
{
"internalType": "uint128",
"name": "bidAmount",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "slot",
"type": "uint8"
}
],
"name": "slotCost",
"outputs": [
{
"internalType": "uint128",
"name": "",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "slot",
"type": "uint8"
}
],
"name": "slotDelegate",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"name": "slotExpiration",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "slot",
"type": "uint8"
}
],
"name": "slotForeclosed",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "slot",
"type": "uint8"
}
],
"name": "slotOwner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint128",
"name": "amount",
"type": "uint128"
}
],
"name": "stake",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint128",
"name": "amount",
"type": "uint128"
},
{
"internalType": "uint256",
"name": "deadline",
"type": "uint256"
},
{
"internalType": "uint8",
"name": "v",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "r",
"type": "bytes32"
},
{
"internalType": "bytes32",
"name": "s",
"type": "bytes32"
}
],
"name": "stakeWithPermit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "stakedBalance",
"outputs": [
{
"internalType": "uint128",
"name": "",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "taxDenominator",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "taxNumerator",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "token",
"outputs": [
{
"internalType": "contract IERC20Extended",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint128",
"name": "amount",
"type": "uint128"
}
],
"name": "unstake",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint128",
"name": "amount",
"type": "uint128"
}
],
"name": "withdraw",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
],
"storageLayout": {
"storage": [
{
"astId": 322,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "_initialized",
"offset": 0,
"slot": "0",
"type": "t_bool"
},
{
"astId": 325,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "_initializing",
"offset": 1,
"slot": "0",
"type": "t_bool"
},
{
"astId": 381,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "slotExpiration",
"offset": 0,
"slot": "1",
"type": "t_mapping(t_uint8,t_uint64)"
},
{
"astId": 386,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "_slotDelegate",
"offset": 0,
"slot": "2",
"type": "t_mapping(t_uint8,t_address)"
},
{
"astId": 391,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "_slotOwner",
"offset": 0,
"slot": "3",
"type": "t_mapping(t_uint8,t_address)"
},
{
"astId": 397,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "slotBid",
"offset": 0,
"slot": "4",
"type": "t_mapping(t_uint8,t_struct(Bid)376_storage)"
},
{
"astId": 402,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "stakedBalance",
"offset": 0,
"slot": "5",
"type": "t_mapping(t_address,t_uint128)"
},
{
"astId": 407,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "lockedBalance",
"offset": 0,
"slot": "6",
"type": "t_mapping(t_address,t_uint128)"
},
{
"astId": 411,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "token",
"offset": 0,
"slot": "7",
"type": "t_contract(IERC20Extended)318"
},
{
"astId": 415,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "lockManager",
"offset": 0,
"slot": "8",
"type": "t_contract(ILockManager)133"
},
{
"astId": 418,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "admin",
"offset": 0,
"slot": "9",
"type": "t_address"
},
{
"astId": 421,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "taxNumerator",
"offset": 20,
"slot": "9",
"type": "t_uint16"
},
{
"astId": 424,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "taxDenominator",
"offset": 22,
"slot": "9",
"type": "t_uint16"
},
{
"astId": 427,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "MIN_BID",
"offset": 0,
"slot": "10",
"type": "t_uint128"
},
{
"astId": 430,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "_NOT_ENTERED",
"offset": 0,
"slot": "11",
"type": "t_uint256"
},
{
"astId": 433,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "_ENTERED",
"offset": 0,
"slot": "12",
"type": "t_uint256"
},
{
"astId": 436,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "_status",
"offset": 0,
"slot": "13",
"type": "t_uint256"
}
],
"types": {
"t_address": {
"encoding": "inplace",
"label": "address",
"numberOfBytes": "20"
},
"t_bool": {
"encoding": "inplace",
"label": "bool",
"numberOfBytes": "1"
},
"t_contract(IERC20Extended)318": {
"encoding": "inplace",
"label": "contract IERC20Extended",
"numberOfBytes": "20"
},
"t_contract(ILockManager)133": {
"encoding": "inplace",
"label": "contract ILockManager",
"numberOfBytes": "20"
},
"t_mapping(t_address,t_uint128)": {
"encoding": "mapping",
"key": "t_address",
"label": "mapping(address => uint128)",
"numberOfBytes": "32",
"value": "t_uint128"
},
"t_mapping(t_uint8,t_address)": {
"encoding": "mapping",
"key": "t_uint8",
"label": "mapping(uint8 => address)",
"numberOfBytes": "32",
"value": "t_address"
},
"t_mapping(t_uint8,t_struct(Bid)376_storage)": {
"encoding": "mapping",
"key": "t_uint8",
"label": "mapping(uint8 => struct EdenNetwork.Bid)",
"numberOfBytes": "32",
"value": "t_struct(Bid)376_storage"
},
"t_mapping(t_uint8,t_uint64)": {
"encoding": "mapping",
"key": "t_uint8",
"label": "mapping(uint8 => uint64)",
"numberOfBytes": "32",
"value": "t_uint64"
},
"t_struct(Bid)376_storage": {
"encoding": "inplace",
"label": "struct EdenNetwork.Bid",
"members": [
{
"astId": 367,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "bidder",
"offset": 0,
"slot": "0",
"type": "t_address"
},
{
"astId": 369,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "taxNumerator",
"offset": 20,
"slot": "0",
"type": "t_uint16"
},
{
"astId": 371,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "taxDenominator",
"offset": 22,
"slot": "0",
"type": "t_uint16"
},
{
"astId": 373,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "periodStart",
"offset": 24,
"slot": "0",
"type": "t_uint64"
},
{
"astId": 375,
"contract": "EdenNetwork.sol:EdenNetwork",
"label": "bidAmount",
"offset": 0,
"slot": "1",
"type": "t_uint128"
}
],
"numberOfBytes": "64"
},
"t_uint128": {
"encoding": "inplace",
"label": "uint128",
"numberOfBytes": "16"
},
"t_uint16": {
"encoding": "inplace",
"label": "uint16",
"numberOfBytes": "2"
},
"t_uint256": {
"encoding": "inplace",
"label": "uint256",
"numberOfBytes": "32"
},
"t_uint64": {
"encoding": "inplace",
"label": "uint64",
"numberOfBytes": "8"
},
"t_uint8": {
"encoding": "inplace",
"label": "uint8",
"numberOfBytes": "1"
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +0,0 @@
//
// Copyright 2022 Vulcanize, Inc.
//
import { CreateCheckpointCmd } from '@cerc-io/cli';
import { getGraphDbAndWatcher } from '@cerc-io/graph-node';
import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../../database';
import { Indexer } from '../../indexer';
export const command = 'create';
export const desc = 'Create checkpoint';
export const builder = {
address: {
type: 'string',
require: true,
demandOption: true,
describe: 'Contract address to create the checkpoint for.'
},
blockHash: {
type: 'string',
describe: 'Blockhash at which to create the checkpoint.'
}
};
export const handler = async (argv: any): Promise<void> => {
const createCheckpointCmd = new CreateCheckpointCmd();
await createCheckpointCmd.init(argv, Database);
const { graphWatcher } = await getGraphDbAndWatcher(
createCheckpointCmd.config.server,
createCheckpointCmd.clients.ethClient,
createCheckpointCmd.ethProvider,
createCheckpointCmd.database.baseDatabase,
ENTITY_QUERY_TYPE_MAP,
ENTITY_TO_LATEST_ENTITY_MAP
);
await createCheckpointCmd.initIndexer(Indexer, graphWatcher);
await createCheckpointCmd.exec();
};

View File

@ -1,40 +0,0 @@
//
// Copyright 2022 Vulcanize, Inc.
//
import { VerifyCheckpointCmd } from '@cerc-io/cli';
import { getGraphDbAndWatcher } from '@cerc-io/graph-node';
import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../../database';
import { Indexer } from '../../indexer';
export const command = 'verify';
export const desc = 'Verify checkpoint';
export const builder = {
cid: {
type: 'string',
alias: 'c',
demandOption: true,
describe: 'Checkpoint CID to be verified'
}
};
export const handler = async (argv: any): Promise<void> => {
const verifyCheckpointCmd = new VerifyCheckpointCmd();
await verifyCheckpointCmd.init(argv, Database);
const { graphWatcher, graphDb } = await getGraphDbAndWatcher(
verifyCheckpointCmd.config.server,
verifyCheckpointCmd.clients.ethClient,
verifyCheckpointCmd.ethProvider,
verifyCheckpointCmd.database.baseDatabase,
ENTITY_QUERY_TYPE_MAP,
ENTITY_TO_LATEST_ENTITY_MAP
);
await verifyCheckpointCmd.initIndexer(Indexer, graphWatcher);
await verifyCheckpointCmd.exec(graphDb);
};

View File

@ -1,39 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import yargs from 'yargs';
import 'reflect-metadata';
import debug from 'debug';
import { DEFAULT_CONFIG_PATH } from '@cerc-io/util';
import { hideBin } from 'yargs/helpers';
const log = debug('vulcanize:checkpoint');
const main = async () => {
return yargs(hideBin(process.argv))
.parserConfiguration({
'parse-numbers': false
}).options({
configFile: {
alias: 'f',
type: 'string',
require: true,
demandOption: true,
describe: 'configuration file path (toml)',
default: DEFAULT_CONFIG_PATH
}
})
.commandDir('checkpoint-cmds', { extensions: ['ts', 'js'], exclude: /([a-zA-Z0-9\s_\\.\-:])+(.d.ts)$/ })
.demandCommand(1)
.help()
.argv;
};
main().then(() => {
process.exit();
}).catch(err => {
log(err);
});

View File

@ -1,38 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import 'reflect-metadata';
import debug from 'debug';
import { ExportStateCmd } from '@cerc-io/cli';
import { getGraphDbAndWatcher } from '@cerc-io/graph-node';
import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../database';
import { Indexer } from '../indexer';
const log = debug('vulcanize:export-state');
const main = async (): Promise<void> => {
const exportStateCmd = new ExportStateCmd();
await exportStateCmd.init(Database);
const { graphWatcher } = await getGraphDbAndWatcher(
exportStateCmd.config.server,
exportStateCmd.clients.ethClient,
exportStateCmd.ethProvider,
exportStateCmd.database.baseDatabase,
ENTITY_QUERY_TYPE_MAP,
ENTITY_TO_LATEST_ENTITY_MAP
);
await exportStateCmd.initIndexer(Indexer, graphWatcher);
await exportStateCmd.exec();
};
main().catch(err => {
log(err);
}).finally(() => {
process.exit(0);
});

View File

@ -1,39 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import 'reflect-metadata';
import debug from 'debug';
import { ImportStateCmd } from '@cerc-io/cli';
import { getGraphDbAndWatcher } from '@cerc-io/graph-node';
import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../database';
import { Indexer } from '../indexer';
import { State } from '../entity/State';
const log = debug('vulcanize:import-state');
export const main = async (): Promise<any> => {
const importStateCmd = new ImportStateCmd();
await importStateCmd.init(Database);
const { graphWatcher, graphDb } = await getGraphDbAndWatcher(
importStateCmd.config.server,
importStateCmd.clients.ethClient,
importStateCmd.ethProvider,
importStateCmd.database.baseDatabase,
ENTITY_QUERY_TYPE_MAP,
ENTITY_TO_LATEST_ENTITY_MAP
);
await importStateCmd.initIndexer(Indexer, graphWatcher);
await importStateCmd.exec(State, graphDb);
};
main().catch(err => {
log(err);
}).finally(() => {
process.exit(0);
});

View File

@ -1,38 +0,0 @@
//
// Copyright 2022 Vulcanize, Inc.
//
import 'reflect-metadata';
import debug from 'debug';
import { IndexBlockCmd } from '@cerc-io/cli';
import { getGraphDbAndWatcher } from '@cerc-io/graph-node';
import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../database';
import { Indexer } from '../indexer';
const log = debug('vulcanize:index-block');
const main = async (): Promise<void> => {
const indexBlockCmd = new IndexBlockCmd();
await indexBlockCmd.init(Database);
const { graphWatcher } = await getGraphDbAndWatcher(
indexBlockCmd.config.server,
indexBlockCmd.clients.ethClient,
indexBlockCmd.ethProvider,
indexBlockCmd.database.baseDatabase,
ENTITY_QUERY_TYPE_MAP,
ENTITY_TO_LATEST_ENTITY_MAP
);
await indexBlockCmd.initIndexer(Indexer, graphWatcher);
await indexBlockCmd.exec();
};
main().catch(err => {
log(err);
}).finally(() => {
process.exit(0);
});

View File

@ -1,38 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import 'reflect-metadata';
import debug from 'debug';
import { InspectCIDCmd } from '@cerc-io/cli';
import { getGraphDbAndWatcher } from '@cerc-io/graph-node';
import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../database';
import { Indexer } from '../indexer';
const log = debug('vulcanize:inspect-cid');
const main = async (): Promise<void> => {
const inspectCIDCmd = new InspectCIDCmd();
await inspectCIDCmd.init(Database);
const { graphWatcher } = await getGraphDbAndWatcher(
inspectCIDCmd.config.server,
inspectCIDCmd.clients.ethClient,
inspectCIDCmd.ethProvider,
inspectCIDCmd.database.baseDatabase,
ENTITY_QUERY_TYPE_MAP,
ENTITY_TO_LATEST_ENTITY_MAP
);
await inspectCIDCmd.initIndexer(Indexer, graphWatcher);
await inspectCIDCmd.exec();
};
main().catch(err => {
log(err);
}).finally(() => {
process.exit(0);
});

View File

@ -1,22 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import debug from 'debug';
import { getConfig, resetJobs, Config } from '@cerc-io/util';
const log = debug('vulcanize:reset-job-queue');
export const command = 'job-queue';
export const desc = 'Reset job queue';
export const builder = {};
export const handler = async (argv: any): Promise<void> => {
const config: Config = await getConfig(argv.configFile);
await resetJobs(config);
log('Job queue reset successfully');
};

View File

@ -1,24 +0,0 @@
//
// Copyright 2022 Vulcanize, Inc.
//
import { ResetStateCmd } from '@cerc-io/cli';
import { Database } from '../../database';
export const command = 'state';
export const desc = 'Reset State to a given block number';
export const builder = {
blockNumber: {
type: 'number'
}
};
export const handler = async (argv: any): Promise<void> => {
const resetStateCmd = new ResetStateCmd();
await resetStateCmd.init(argv, Database);
await resetStateCmd.exec();
};

View File

@ -1,37 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { ResetWatcherCmd } from '@cerc-io/cli';
import { getGraphDbAndWatcher } from '@cerc-io/graph-node';
import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../../database';
import { Indexer } from '../../indexer';
export const command = 'watcher';
export const desc = 'Reset watcher to a block number';
export const builder = {
blockNumber: {
type: 'number'
}
};
export const handler = async (argv: any): Promise<void> => {
const resetWatcherCmd = new ResetWatcherCmd();
await resetWatcherCmd.init(argv, Database);
const { graphWatcher } = await getGraphDbAndWatcher(
resetWatcherCmd.config.server,
resetWatcherCmd.clients.ethClient,
resetWatcherCmd.ethProvider,
resetWatcherCmd.database.baseDatabase,
ENTITY_QUERY_TYPE_MAP,
ENTITY_TO_LATEST_ENTITY_MAP
);
await resetWatcherCmd.initIndexer(Indexer, graphWatcher);
await resetWatcherCmd.exec();
};

View File

@ -1,24 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import 'reflect-metadata';
import debug from 'debug';
import { getResetYargs } from '@cerc-io/util';
const log = debug('vulcanize:reset');
const main = async () => {
return getResetYargs()
.commandDir('reset-cmds', { extensions: ['ts', 'js'], exclude: /([a-zA-Z0-9\s_\\.\-:])+(.d.ts)$/ })
.demandCommand(1)
.help()
.argv;
};
main().then(() => {
process.exit();
}).catch(err => {
log(err);
});

View File

@ -1,38 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import 'reflect-metadata';
import debug from 'debug';
import { WatchContractCmd } from '@cerc-io/cli';
import { getGraphDbAndWatcher } from '@cerc-io/graph-node';
import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from '../database';
import { Indexer } from '../indexer';
const log = debug('vulcanize:watch-contract');
const main = async (): Promise<void> => {
const watchContractCmd = new WatchContractCmd();
await watchContractCmd.init(Database);
const { graphWatcher } = await getGraphDbAndWatcher(
watchContractCmd.config.server,
watchContractCmd.clients.ethClient,
watchContractCmd.ethProvider,
watchContractCmd.database.baseDatabase,
ENTITY_QUERY_TYPE_MAP,
ENTITY_TO_LATEST_ENTITY_MAP
);
await watchContractCmd.initIndexer(Indexer, graphWatcher);
await watchContractCmd.exec();
};
main().catch(err => {
log(err);
}).finally(() => {
process.exit(0);
});

View File

@ -1,55 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { gql } from '@apollo/client/core';
import { GraphQLClient, GraphQLConfig } from '@cerc-io/ipld-eth-client';
import { queries, mutations, subscriptions } from './gql';
export class Client {
_config: GraphQLConfig;
_client: GraphQLClient;
constructor (config: GraphQLConfig) {
this._config = config;
this._client = new GraphQLClient(config);
}
async getEvents (blockHash: string, contractAddress: string, name: string): Promise<any> {
const { events } = await this._client.query(
gql(queries.events),
{ blockHash, contractAddress, name }
);
return events;
}
async getEventsInRange (fromBlockNumber: number, toBlockNumber: number): Promise<any> {
const { eventsInRange } = await this._client.query(
gql(queries.eventsInRange),
{ fromBlockNumber, toBlockNumber }
);
return eventsInRange;
}
async watchContract (contractAddress: string, startingBlock?: number): Promise<any> {
const { watchContract } = await this._client.mutate(
gql(mutations.watchContract),
{ contractAddress, startingBlock }
);
return watchContract;
}
async watchEvents (onNext: (value: any) => void): Promise<ZenObservable.Subscription> {
return this._client.subscribe(
gql(subscriptions.onEvent),
({ data }) => {
onNext(data.onEvent);
}
);
}
}

View File

@ -1,272 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import assert from 'assert';
import { Connection, ConnectionOptions, DeepPartial, FindConditions, QueryRunner, FindManyOptions, EntityTarget } from 'typeorm';
import path from 'path';
import { Database as BaseDatabase, DatabaseInterface, QueryOptions, StateKind, Where } from '@cerc-io/util';
import { Contract } from './entity/Contract';
import { Event } from './entity/Event';
import { SyncStatus } from './entity/SyncStatus';
import { StateSyncStatus } from './entity/StateSyncStatus';
import { BlockProgress } from './entity/BlockProgress';
import { State } from './entity/State';
import { Account } from './entity/Account';
import { Claim } from './entity/Claim';
import { Distribution } from './entity/Distribution';
import { Distributor } from './entity/Distributor';
import { Epoch } from './entity/Epoch';
import { Network } from './entity/Network';
import { Producer } from './entity/Producer';
import { ProducerEpoch } from './entity/ProducerEpoch';
import { ProducerRewardCollectorChange } from './entity/ProducerRewardCollectorChange';
import { ProducerSet } from './entity/ProducerSet';
import { ProducerSetChange } from './entity/ProducerSetChange';
import { RewardSchedule } from './entity/RewardSchedule';
import { RewardScheduleEntry } from './entity/RewardScheduleEntry';
import { Slash } from './entity/Slash';
import { Slot } from './entity/Slot';
import { SlotClaim } from './entity/SlotClaim';
import { Staker } from './entity/Staker';
export const SUBGRAPH_ENTITIES = new Set([Account, Claim, Distribution, Distributor, Epoch, Network, Producer, ProducerEpoch, ProducerRewardCollectorChange, ProducerSet, ProducerSetChange, RewardSchedule, RewardScheduleEntry, Slash, Slot, SlotClaim, Staker]);
export const ENTITIES = [...SUBGRAPH_ENTITIES];
export const ENTITY_TO_LATEST_ENTITY_MAP = new Map();
export const ENTITY_QUERY_TYPE_MAP = new Map();
export class Database implements DatabaseInterface {
_config: ConnectionOptions;
_conn!: Connection;
_baseDatabase: BaseDatabase;
constructor (config: ConnectionOptions) {
assert(config);
this._config = {
...config,
entities: [path.join(__dirname, 'entity/*')],
subscribers: [path.join(__dirname, 'entity/Subscriber.*')]
};
this._baseDatabase = new BaseDatabase(this._config);
}
get baseDatabase (): BaseDatabase {
return this._baseDatabase;
}
async init (): Promise<void> {
this._conn = await this._baseDatabase.init();
}
async close (): Promise<void> {
return this._baseDatabase.close();
}
getNewState (): State {
return new State();
}
async getStates (where: FindConditions<State>): Promise<State[]> {
const repo = this._conn.getRepository(State);
return this._baseDatabase.getStates(repo, where);
}
async getLatestState (contractAddress: string, kind: StateKind | null, blockNumber?: number): Promise<State | undefined> {
const repo = this._conn.getRepository(State);
return this._baseDatabase.getLatestState(repo, contractAddress, kind, blockNumber);
}
async getPrevState (blockHash: string, contractAddress: string, kind?: string): Promise<State | undefined> {
const repo = this._conn.getRepository(State);
return this._baseDatabase.getPrevState(repo, blockHash, contractAddress, kind);
}
// Fetch all diff States after the specified block number.
async getDiffStatesInRange (contractAddress: string, startblock: number, endBlock: number): Promise<State[]> {
const repo = this._conn.getRepository(State);
return this._baseDatabase.getDiffStatesInRange(repo, contractAddress, startblock, endBlock);
}
async saveOrUpdateState (dbTx: QueryRunner, state: State): Promise<State> {
const repo = dbTx.manager.getRepository(State);
return this._baseDatabase.saveOrUpdateState(repo, state);
}
async removeStates (dbTx: QueryRunner, blockNumber: number, kind: string): Promise<void> {
const repo = dbTx.manager.getRepository(State);
await this._baseDatabase.removeStates(repo, blockNumber, kind);
}
async removeStatesAfterBlock (dbTx: QueryRunner, blockNumber: number): Promise<void> {
const repo = dbTx.manager.getRepository(State);
await this._baseDatabase.removeStatesAfterBlock(repo, blockNumber);
}
async getStateSyncStatus (): Promise<StateSyncStatus | undefined> {
const repo = this._conn.getRepository(StateSyncStatus);
return this._baseDatabase.getStateSyncStatus(repo);
}
async updateStateSyncStatusIndexedBlock (queryRunner: QueryRunner, blockNumber: number, force?: boolean): Promise<StateSyncStatus> {
const repo = queryRunner.manager.getRepository(StateSyncStatus);
return this._baseDatabase.updateStateSyncStatusIndexedBlock(repo, blockNumber, force);
}
async updateStateSyncStatusCheckpointBlock (queryRunner: QueryRunner, blockNumber: number, force?: boolean): Promise<StateSyncStatus> {
const repo = queryRunner.manager.getRepository(StateSyncStatus);
return this._baseDatabase.updateStateSyncStatusCheckpointBlock(repo, blockNumber, force);
}
async getContracts (): Promise<Contract[]> {
const repo = this._conn.getRepository(Contract);
return this._baseDatabase.getContracts(repo);
}
async createTransactionRunner (): Promise<QueryRunner> {
return this._baseDatabase.createTransactionRunner();
}
async getProcessedBlockCountForRange (fromBlockNumber: number, toBlockNumber: number): Promise<{ expected: number, actual: number }> {
const repo = this._conn.getRepository(BlockProgress);
return this._baseDatabase.getProcessedBlockCountForRange(repo, fromBlockNumber, toBlockNumber);
}
async getEventsInRange (fromBlockNumber: number, toBlockNumber: number): Promise<Array<Event>> {
const repo = this._conn.getRepository(Event);
return this._baseDatabase.getEventsInRange(repo, fromBlockNumber, toBlockNumber);
}
async saveEventEntity (queryRunner: QueryRunner, entity: Event): Promise<Event> {
const repo = queryRunner.manager.getRepository(Event);
return this._baseDatabase.saveEventEntity(repo, entity);
}
async getBlockEvents (blockHash: string, where: Where, queryOptions: QueryOptions): Promise<Event[]> {
const repo = this._conn.getRepository(Event);
return this._baseDatabase.getBlockEvents(repo, blockHash, where, queryOptions);
}
async saveBlockWithEvents (queryRunner: QueryRunner, block: DeepPartial<BlockProgress>, events: DeepPartial<Event>[]): Promise<BlockProgress> {
const blockRepo = queryRunner.manager.getRepository(BlockProgress);
const eventRepo = queryRunner.manager.getRepository(Event);
return this._baseDatabase.saveBlockWithEvents(blockRepo, eventRepo, block, events);
}
async saveEvents (queryRunner: QueryRunner, events: Event[]): Promise<void> {
const eventRepo = queryRunner.manager.getRepository(Event);
return this._baseDatabase.saveEvents(eventRepo, events);
}
async saveBlockProgress (queryRunner: QueryRunner, block: DeepPartial<BlockProgress>): Promise<BlockProgress> {
const repo = queryRunner.manager.getRepository(BlockProgress);
return this._baseDatabase.saveBlockProgress(repo, block);
}
async saveContract (queryRunner: QueryRunner, address: string, kind: string, checkpoint: boolean, startingBlock: number): Promise<Contract> {
const repo = queryRunner.manager.getRepository(Contract);
return this._baseDatabase.saveContract(repo, address, kind, checkpoint, startingBlock);
}
async updateSyncStatusIndexedBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
const repo = queryRunner.manager.getRepository(SyncStatus);
return this._baseDatabase.updateSyncStatusIndexedBlock(repo, blockHash, blockNumber, force);
}
async updateSyncStatusCanonicalBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
const repo = queryRunner.manager.getRepository(SyncStatus);
return this._baseDatabase.updateSyncStatusCanonicalBlock(repo, blockHash, blockNumber, force);
}
async updateSyncStatusChainHead (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise<SyncStatus> {
const repo = queryRunner.manager.getRepository(SyncStatus);
return this._baseDatabase.updateSyncStatusChainHead(repo, blockHash, blockNumber, force);
}
async getSyncStatus (queryRunner: QueryRunner): Promise<SyncStatus | undefined> {
const repo = queryRunner.manager.getRepository(SyncStatus);
return this._baseDatabase.getSyncStatus(repo);
}
async getEvent (id: string): Promise<Event | undefined> {
const repo = this._conn.getRepository(Event);
return this._baseDatabase.getEvent(repo, id);
}
async getBlocksAtHeight (height: number, isPruned: boolean): Promise<BlockProgress[]> {
const repo = this._conn.getRepository(BlockProgress);
return this._baseDatabase.getBlocksAtHeight(repo, height, isPruned);
}
async markBlocksAsPruned (queryRunner: QueryRunner, blocks: BlockProgress[]): Promise<void> {
const repo = queryRunner.manager.getRepository(BlockProgress);
return this._baseDatabase.markBlocksAsPruned(repo, blocks);
}
async getBlockProgress (blockHash: string): Promise<BlockProgress | undefined> {
const repo = this._conn.getRepository(BlockProgress);
return this._baseDatabase.getBlockProgress(repo, blockHash);
}
async getBlockProgressEntities (where: FindConditions<BlockProgress>, options: FindManyOptions<BlockProgress>): Promise<BlockProgress[]> {
const repo = this._conn.getRepository(BlockProgress);
return this._baseDatabase.getBlockProgressEntities(repo, where, options);
}
async getEntitiesForBlock (blockHash: string, tableName: string): Promise<any[]> {
return this._baseDatabase.getEntitiesForBlock(blockHash, tableName);
}
async updateBlockProgress (queryRunner: QueryRunner, block: BlockProgress, lastProcessedEventIndex: number): Promise<BlockProgress> {
const repo = queryRunner.manager.getRepository(BlockProgress);
return this._baseDatabase.updateBlockProgress(repo, block, lastProcessedEventIndex);
}
async removeEntities<Entity> (queryRunner: QueryRunner, entity: new () => Entity, findConditions?: FindManyOptions<Entity> | FindConditions<Entity>): Promise<void> {
return this._baseDatabase.removeEntities(queryRunner, entity, findConditions);
}
async deleteEntitiesByConditions<Entity> (queryRunner: QueryRunner, entity: EntityTarget<Entity>, findConditions: FindConditions<Entity>): Promise<void> {
await this._baseDatabase.deleteEntitiesByConditions(queryRunner, entity, findConditions);
}
async getAncestorAtDepth (blockHash: string, depth: number): Promise<string> {
return this._baseDatabase.getAncestorAtDepth(blockHash, depth);
}
_getPropertyColumnMapForEntity (entityName: string): Map<string, string> {
return this._conn.getMetadata(entityName).ownColumns.reduce((acc, curr) => {
return acc.set(curr.propertyName, curr.databaseName);
}, new Map<string, string>());
}
}

View File

@ -1,29 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import { bigintTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class Account {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('numeric', { transformer: bigintTransformer })
totalClaimed!: bigint;
@Column('numeric', { transformer: bigintTransformer })
totalSlashed!: bigint;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,67 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import { bigintTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class Block {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('boolean')
fromActiveProducer!: boolean;
@Column('varchar')
hash!: string;
@Column('varchar')
parentHash!: string;
@Column('varchar')
unclesHash!: string;
@Column('varchar')
author!: string;
@Column('varchar')
stateRoot!: string;
@Column('varchar')
transactionsRoot!: string;
@Column('varchar')
receiptsRoot!: string;
@Column('numeric', { transformer: bigintTransformer })
number!: bigint;
@Column('numeric', { transformer: bigintTransformer })
gasUsed!: bigint;
@Column('numeric', { transformer: bigintTransformer })
gasLimit!: bigint;
@Column('numeric', { transformer: bigintTransformer })
timestamp!: bigint;
@Column('numeric', { transformer: bigintTransformer })
difficulty!: bigint;
@Column('numeric', { transformer: bigintTransformer })
totalDifficulty!: bigint;
@Column('numeric', { nullable: true, transformer: bigintTransformer })
size!: bigint;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,48 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryGeneratedColumn, Column, Index, CreateDateColumn } from 'typeorm';
import { BlockProgressInterface } from '@cerc-io/util';
@Entity()
@Index(['blockHash'], { unique: true })
@Index(['blockNumber'])
@Index(['parentHash'])
export class BlockProgress implements BlockProgressInterface {
@PrimaryGeneratedColumn()
id!: number;
@Column('varchar')
cid!: string;
@Column('varchar', { length: 66 })
blockHash!: string;
@Column('varchar', { length: 66 })
parentHash!: string;
@Column('integer')
blockNumber!: number;
@Column('integer')
blockTimestamp!: number;
@Column('integer')
numEvents!: number;
@Column('integer')
numProcessedEvents!: number;
@Column('integer')
lastProcessedEventIndex!: number;
@Column('boolean')
isComplete!: boolean;
@Column('boolean', { default: false })
isPruned!: boolean;
@CreateDateColumn()
createdAt!: Date;
}

View File

@ -1,38 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import { bigintTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class Claim {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('numeric', { transformer: bigintTransformer })
timestamp!: bigint;
@Column('numeric', { transformer: bigintTransformer })
index!: bigint;
@Column('varchar')
account!: string;
@Column('numeric', { transformer: bigintTransformer })
totalEarned!: bigint;
@Column('numeric', { transformer: bigintTransformer })
claimed!: bigint;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,24 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryGeneratedColumn, Column, Index } from 'typeorm';
@Entity()
@Index(['address'], { unique: true })
export class Contract {
@PrimaryGeneratedColumn()
id!: number;
@Column('varchar', { length: 42 })
address!: string;
@Column('varchar')
kind!: string;
@Column('boolean')
checkpoint!: boolean;
@Column('integer')
startingBlock!: number;
}

View File

@ -1,38 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import { bigintTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class Distribution {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('varchar')
distributor!: string;
@Column('numeric', { transformer: bigintTransformer })
timestamp!: bigint;
@Column('numeric', { transformer: bigintTransformer })
distributionNumber!: bigint;
@Column('varchar')
merkleRoot!: string;
@Column('varchar')
metadataURI!: string;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,24 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
@Entity()
@Index(['blockNumber'])
export class Distributor {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('varchar', { nullable: true })
currentDistribution!: string;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,45 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import Decimal from 'decimal.js';
import { bigintTransformer, decimalTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class Epoch {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('boolean')
finalized!: boolean;
@Column('numeric', { transformer: bigintTransformer })
epochNumber!: bigint;
@Column('varchar', { nullable: true })
startBlock!: string;
@Column('varchar', { nullable: true })
endBlock!: string;
@Column('numeric', { transformer: bigintTransformer })
producerBlocks!: bigint;
@Column('numeric', { transformer: bigintTransformer })
allBlocks!: bigint;
@Column('numeric', { default: 0, transformer: decimalTransformer })
producerBlocksRatio!: Decimal;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,38 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryGeneratedColumn, Column, Index, ManyToOne } from 'typeorm';
import { BlockProgress } from './BlockProgress';
@Entity()
@Index(['block', 'contract'])
@Index(['block', 'contract', 'eventName'])
export class Event {
@PrimaryGeneratedColumn()
id!: number;
@ManyToOne(() => BlockProgress, { onDelete: 'CASCADE' })
block!: BlockProgress;
@Column('varchar', { length: 66 })
txHash!: string;
@Column('integer')
index!: number;
@Column('varchar', { length: 42 })
contract!: string;
@Column('varchar', { length: 256 })
eventName!: string;
@Column('text')
eventInfo!: string;
@Column('text')
extraInfo!: string;
@Column('text')
proof!: string;
}

View File

@ -1,21 +0,0 @@
//
// Copyright 2022 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
@Entity()
@Index(['blockNumber'])
export class FrothyEntity {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar')
name!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
}

View File

@ -1,45 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import { bigintArrayTransformer, bigintTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class Network {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('varchar', { nullable: true })
slot0!: string;
@Column('varchar', { nullable: true })
slot1!: string;
@Column('varchar', { nullable: true })
slot2!: string;
@Column('varchar', { array: true })
stakers!: string[];
@Column('numeric', { nullable: true, transformer: bigintTransformer })
numStakers!: bigint;
@Column('numeric', { transformer: bigintTransformer })
totalStaked!: bigint;
// https://github.com/brianc/node-postgres/issues/1943#issuecomment-520500053
@Column('varchar', { transformer: bigintArrayTransformer, array: true })
stakedPercentiles!: bigint[];
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,37 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import { bigintTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class Producer {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('boolean')
active!: boolean;
@Column('varchar', { nullable: true })
rewardCollector!: string;
@Column('numeric', { transformer: bigintTransformer })
rewards!: bigint;
@Column('numeric', { transformer: bigintTransformer })
confirmedBlocks!: bigint;
@Column('numeric', { transformer: bigintTransformer })
pendingEpochBlocks!: bigint;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,39 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import Decimal from 'decimal.js';
import { bigintTransformer, decimalTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class ProducerEpoch {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('varchar')
address!: string;
@Column('varchar')
epoch!: string;
@Column('numeric', { transformer: bigintTransformer })
totalRewards!: bigint;
@Column('numeric', { transformer: bigintTransformer })
blocksProduced!: bigint;
@Column('numeric', { default: 0, transformer: decimalTransformer })
blocksProducedRatio!: Decimal;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,31 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import { bigintTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class ProducerRewardCollectorChange {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('numeric', { transformer: bigintTransformer })
_blockNumber!: bigint;
@Column('varchar')
producer!: string;
@Column('varchar')
rewardCollector!: string;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,24 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
@Entity()
@Index(['blockNumber'])
export class ProducerSet {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('varchar', { array: true })
producers!: string[];
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,39 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import { bigintTransformer } from '@cerc-io/util';
enum ProducerSetChangeType {
Added = 'Added',
Removed = 'Removed'
}
@Entity()
@Index(['blockNumber'])
export class ProducerSetChange {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('numeric', { transformer: bigintTransformer })
_blockNumber!: bigint;
@Column('varchar')
producer!: string;
@Column({
type: 'enum',
enum: ProducerSetChangeType
})
changeType!: ProducerSetChangeType;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,33 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
@Entity()
@Index(['blockNumber'])
export class RewardSchedule {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('varchar', { array: true })
rewardScheduleEntries!: string[];
@Column('varchar', { nullable: true })
lastEpoch!: string;
@Column('varchar', { nullable: true })
pendingEpoch!: string;
@Column('varchar', { nullable: true })
activeRewardScheduleEntry!: string;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,31 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import { bigintTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class RewardScheduleEntry {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('numeric', { transformer: bigintTransformer })
startTime!: bigint;
@Column('numeric', { transformer: bigintTransformer })
epochDuration!: bigint;
@Column('numeric', { transformer: bigintTransformer })
rewardsPerEpoch!: bigint;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,32 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import { bigintTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class Slash {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('numeric', { transformer: bigintTransformer })
timestamp!: bigint;
@Column('varchar')
account!: string;
@Column('numeric', { transformer: bigintTransformer })
slashed!: bigint;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,45 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import Decimal from 'decimal.js';
import { bigintTransformer, decimalTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class Slot {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('varchar')
owner!: string;
@Column('varchar')
delegate!: string;
@Column('numeric', { transformer: bigintTransformer })
winningBid!: bigint;
@Column('numeric', { transformer: bigintTransformer })
oldBid!: bigint;
@Column('numeric', { transformer: bigintTransformer })
startTime!: bigint;
@Column('numeric', { transformer: bigintTransformer })
expirationTime!: bigint;
@Column('numeric', { default: 0, transformer: decimalTransformer })
taxRatePerDay!: Decimal;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,45 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import Decimal from 'decimal.js';
import { bigintTransformer, decimalTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class SlotClaim {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('varchar')
slot!: string;
@Column('varchar')
owner!: string;
@Column('numeric', { transformer: bigintTransformer })
winningBid!: bigint;
@Column('numeric', { transformer: bigintTransformer })
oldBid!: bigint;
@Column('numeric', { transformer: bigintTransformer })
startTime!: bigint;
@Column('numeric', { transformer: bigintTransformer })
expirationTime!: bigint;
@Column('numeric', { default: 0, transformer: decimalTransformer })
taxRatePerDay!: Decimal;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,28 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
import { bigintTransformer } from '@cerc-io/util';
@Entity()
@Index(['blockNumber'])
export class Staker {
@PrimaryColumn('varchar')
id!: string;
@PrimaryColumn('varchar', { length: 66 })
blockHash!: string;
@Column('integer')
blockNumber!: number;
@Column('numeric', { transformer: bigintTransformer })
staked!: bigint;
@Column('numeric', { nullable: true, transformer: bigintTransformer })
rank!: bigint;
@Column('boolean', { default: false })
isPruned!: boolean;
}

View File

@ -1,36 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryGeneratedColumn, Column, Index, ManyToOne } from 'typeorm';
import { StateKind } from '@cerc-io/util';
import { BlockProgress } from './BlockProgress';
@Entity()
@Index(['cid'], { unique: true })
@Index(['block', 'contractAddress'])
@Index(['block', 'contractAddress', 'kind'], { unique: true })
export class State {
@PrimaryGeneratedColumn()
id!: number;
@ManyToOne(() => BlockProgress, { onDelete: 'CASCADE' })
block!: BlockProgress;
@Column('varchar', { length: 42 })
contractAddress!: string;
@Column('varchar')
cid!: string;
@Column({
type: 'enum',
enum: StateKind
})
kind!: StateKind;
@Column('bytea')
data!: Buffer;
}

View File

@ -1,17 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class StateSyncStatus {
@PrimaryGeneratedColumn()
id!: number;
@Column('integer')
latestIndexedBlockNumber!: number;
@Column('integer', { nullable: true })
latestCheckpointBlockNumber!: number;
}

View File

@ -1,21 +0,0 @@
//
// Copyright 2022 Vulcanize, Inc.
//
import { EventSubscriber, EntitySubscriberInterface, InsertEvent, UpdateEvent } from 'typeorm';
import { afterEntityInsertOrUpdate } from '@cerc-io/util';
import { FrothyEntity } from './FrothyEntity';
import { ENTITY_TO_LATEST_ENTITY_MAP, SUBGRAPH_ENTITIES } from '../database';
@EventSubscriber()
export class EntitySubscriber implements EntitySubscriberInterface {
async afterInsert (event: InsertEvent<any>): Promise<void> {
await afterEntityInsertOrUpdate(FrothyEntity, SUBGRAPH_ENTITIES, event, ENTITY_TO_LATEST_ENTITY_MAP);
}
async afterUpdate (event: UpdateEvent<any>): Promise<void> {
await afterEntityInsertOrUpdate(FrothyEntity, SUBGRAPH_ENTITIES, event, ENTITY_TO_LATEST_ENTITY_MAP);
}
}

View File

@ -1,36 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
import { SyncStatusInterface } from '@cerc-io/util';
@Entity()
export class SyncStatus implements SyncStatusInterface {
@PrimaryGeneratedColumn()
id!: number;
@Column('varchar', { length: 66 })
chainHeadBlockHash!: string;
@Column('integer')
chainHeadBlockNumber!: number;
@Column('varchar', { length: 66 })
latestIndexedBlockHash!: string;
@Column('integer')
latestIndexedBlockNumber!: number;
@Column('varchar', { length: 66 })
latestCanonicalBlockHash!: string;
@Column('integer')
latestCanonicalBlockNumber!: number;
@Column('varchar', { length: 66 })
initialIndexedBlockHash!: string;
@Column('integer')
initialIndexedBlockNumber!: number;
}

View File

@ -1,44 +0,0 @@
//
// Copyright 2021 Vulcanize, Inc.
//
import 'reflect-metadata';
import debug from 'debug';
import { FillCmd } from '@cerc-io/cli';
import { getContractEntitiesMap } from '@cerc-io/util';
import { getGraphDbAndWatcher } from '@cerc-io/graph-node';
import { Database, ENTITY_QUERY_TYPE_MAP, ENTITY_TO_LATEST_ENTITY_MAP } from './database';
import { Indexer } from './indexer';
const log = debug('vulcanize:fill');
export const main = async (): Promise<any> => {
const fillCmd = new FillCmd();
await fillCmd.init(Database);
const { graphWatcher } = await getGraphDbAndWatcher(
fillCmd.config.server,
fillCmd.clients.ethClient,
fillCmd.ethProvider,
fillCmd.database.baseDatabase,
ENTITY_QUERY_TYPE_MAP,
ENTITY_TO_LATEST_ENTITY_MAP
);
await fillCmd.initIndexer(Indexer, graphWatcher);
// Get contractEntitiesMap required for fill-state
// NOTE: Assuming each entity type is only mapped to a single contract
// This is true for eden subgraph; may not be the case for other subgraphs
const contractEntitiesMap = getContractEntitiesMap(graphWatcher.dataSources);
await fillCmd.exec(contractEntitiesMap);
};
main().catch(err => {
log(err);
}).finally(() => {
process.exit();
});

View File

@ -1,3 +0,0 @@
export * as mutations from './mutations';
export * as queries from './queries';
export * as subscriptions from './subscriptions';

View File

@ -1,4 +0,0 @@
import fs from 'fs';
import path from 'path';
export const watchContract = fs.readFileSync(path.join(__dirname, 'watchContract.gql'), 'utf8');

View File

@ -1,3 +0,0 @@
mutation watchContract($address: String!, $kind: String!, $checkpoint: Boolean!, $startingBlock: Int){
watchContract(address: $address, kind: $kind, checkpoint: $checkpoint, startingBlock: $startingBlock)
}

View File

@ -1,19 +0,0 @@
query account($id: String!, $block: Block_height){
account(id: $id, block: $block){
id
totalClaimed
totalSlashed
claims{
id
timestamp
index
totalEarned
claimed
}
slashes{
id
timestamp
slashed
}
}
}

View File

@ -1,20 +0,0 @@
query block($id: String!, $block: Block_height){
block(id: $id, block: $block){
id
fromActiveProducer
hash
parentHash
unclesHash
author
stateRoot
transactionsRoot
receiptsRoot
number
gasUsed
gasLimit
timestamp
difficulty
totalDifficulty
size
}
}

View File

@ -1,14 +0,0 @@
query claim($id: String!, $block: Block_height){
claim(id: $id, block: $block){
id
timestamp
index
account{
id
totalClaimed
totalSlashed
}
totalEarned
claimed
}
}

View File

@ -1,12 +0,0 @@
query distribution($id: String!, $block: Block_height){
distribution(id: $id, block: $block){
id
distributor{
id
}
timestamp
distributionNumber
merkleRoot
metadataURI
}
}

View File

@ -1,12 +0,0 @@
query distributor($id: String!, $block: Block_height){
distributor(id: $id, block: $block){
id
currentDistribution{
id
timestamp
distributionNumber
merkleRoot
metadataURI
}
}
}

View File

@ -1,53 +0,0 @@
query epoch($id: String!, $block: Block_height){
epoch(id: $id, block: $block){
id
finalized
epochNumber
startBlock{
id
fromActiveProducer
hash
parentHash
unclesHash
author
stateRoot
transactionsRoot
receiptsRoot
number
gasUsed
gasLimit
timestamp
difficulty
totalDifficulty
size
}
endBlock{
id
fromActiveProducer
hash
parentHash
unclesHash
author
stateRoot
transactionsRoot
receiptsRoot
number
gasUsed
gasLimit
timestamp
difficulty
totalDifficulty
size
}
producerBlocks
allBlocks
producerBlocksRatio
producerRewards{
id
address
totalRewards
blocksProduced
blocksProducedRatio
}
}
}

View File

@ -1,139 +0,0 @@
query events($blockHash: String!, $contractAddress: String!, $name: String){
events(blockHash: $blockHash, contractAddress: $contractAddress, name: $name){
block{
cid
hash
number
timestamp
parentHash
}
tx{
hash
index
from
to
}
contract
eventIndex
event{
... on TransferEvent {
from
to
value
}
... on ApprovalEvent {
owner
spender
value
}
... on AuthorizationUsedEvent {
authorizer
nonce
}
... on AdminUpdatedEvent {
newAdmin
oldAdmin
}
... on TaxRateUpdatedEvent {
newNumerator
newDenominator
oldNumerator
oldDenominator
}
... on SlotClaimedEvent {
slot
owner
delegate
newBidAmount
oldBidAmount
taxNumerator
taxDenominator
}
... on SlotDelegateUpdatedEvent {
slot
owner
newDelegate
oldDelegate
}
... on StakeEvent {
staker
stakeAmount
}
... on UnstakeEvent {
staker
unstakedAmount
}
... on WithdrawEvent {
withdrawer
withdrawalAmount
}
... on ApprovalForAllEvent {
owner
operator
approved
}
... on BlockProducerAddedEvent {
producer
}
... on BlockProducerRemovedEvent {
producer
}
... on BlockProducerRewardCollectorChangedEvent {
producer
collector
}
... on RewardScheduleChangedEvent {
dummy
}
... on ClaimedEvent {
index
totalEarned
account
claimed
}
... on SlashedEvent {
account
slashed
}
... on MerkleRootUpdatedEvent {
merkleRoot
distributionNumber
metadataURI
}
... on AccountUpdatedEvent {
account
totalClaimed
totalSlashed
}
... on PermanentURIEvent {
value
id
}
... on GovernanceChangedEvent {
from
to
}
... on UpdateThresholdChangedEvent {
updateThreshold
}
... on RoleAdminChangedEvent {
role
previousAdminRole
newAdminRole
}
... on RoleGrantedEvent {
role
account
sender
}
... on RoleRevokedEvent {
role
account
sender
}
}
proof{
data
}
}
}

View File

@ -1,139 +0,0 @@
query eventsInRange($fromBlockNumber: Int!, $toBlockNumber: Int!){
eventsInRange(fromBlockNumber: $fromBlockNumber, toBlockNumber: $toBlockNumber){
block{
cid
hash
number
timestamp
parentHash
}
tx{
hash
index
from
to
}
contract
eventIndex
event{
... on TransferEvent {
from
to
value
}
... on ApprovalEvent {
owner
spender
value
}
... on AuthorizationUsedEvent {
authorizer
nonce
}
... on AdminUpdatedEvent {
newAdmin
oldAdmin
}
... on TaxRateUpdatedEvent {
newNumerator
newDenominator
oldNumerator
oldDenominator
}
... on SlotClaimedEvent {
slot
owner
delegate
newBidAmount
oldBidAmount
taxNumerator
taxDenominator
}
... on SlotDelegateUpdatedEvent {
slot
owner
newDelegate
oldDelegate
}
... on StakeEvent {
staker
stakeAmount
}
... on UnstakeEvent {
staker
unstakedAmount
}
... on WithdrawEvent {
withdrawer
withdrawalAmount
}
... on ApprovalForAllEvent {
owner
operator
approved
}
... on BlockProducerAddedEvent {
producer
}
... on BlockProducerRemovedEvent {
producer
}
... on BlockProducerRewardCollectorChangedEvent {
producer
collector
}
... on RewardScheduleChangedEvent {
dummy
}
... on ClaimedEvent {
index
totalEarned
account
claimed
}
... on SlashedEvent {
account
slashed
}
... on MerkleRootUpdatedEvent {
merkleRoot
distributionNumber
metadataURI
}
... on AccountUpdatedEvent {
account
totalClaimed
totalSlashed
}
... on PermanentURIEvent {
value
id
}
... on GovernanceChangedEvent {
from
to
}
... on UpdateThresholdChangedEvent {
updateThreshold
}
... on RoleAdminChangedEvent {
role
previousAdminRole
newAdminRole
}
... on RoleGrantedEvent {
role
account
sender
}
... on RoleRevokedEvent {
role
account
sender
}
}
proof{
data
}
}
}

View File

@ -1,15 +0,0 @@
query getState($blockHash: String!, $contractAddress: String!, $kind: String){
getState(blockHash: $blockHash, contractAddress: $contractAddress, kind: $kind){
block{
cid
hash
number
timestamp
parentHash
}
contractAddress
cid
kind
data
}
}

View File

@ -1,15 +0,0 @@
query getStateByCID($cid: String!){
getStateByCID(cid: $cid){
block{
cid
hash
number
timestamp
parentHash
}
contractAddress
cid
kind
data
}
}

View File

@ -1,24 +0,0 @@
import fs from 'fs';
import path from 'path';
export const events = fs.readFileSync(path.join(__dirname, 'events.gql'), 'utf8');
export const eventsInRange = fs.readFileSync(path.join(__dirname, 'eventsInRange.gql'), 'utf8');
export const producer = fs.readFileSync(path.join(__dirname, 'producer.gql'), 'utf8');
export const producerSet = fs.readFileSync(path.join(__dirname, 'producerSet.gql'), 'utf8');
export const producerSetChange = fs.readFileSync(path.join(__dirname, 'producerSetChange.gql'), 'utf8');
export const producerRewardCollectorChange = fs.readFileSync(path.join(__dirname, 'producerRewardCollectorChange.gql'), 'utf8');
export const rewardScheduleEntry = fs.readFileSync(path.join(__dirname, 'rewardScheduleEntry.gql'), 'utf8');
export const rewardSchedule = fs.readFileSync(path.join(__dirname, 'rewardSchedule.gql'), 'utf8');
export const producerEpoch = fs.readFileSync(path.join(__dirname, 'producerEpoch.gql'), 'utf8');
export const epoch = fs.readFileSync(path.join(__dirname, 'epoch.gql'), 'utf8');
export const slotClaim = fs.readFileSync(path.join(__dirname, 'slotClaim.gql'), 'utf8');
export const slot = fs.readFileSync(path.join(__dirname, 'slot.gql'), 'utf8');
export const staker = fs.readFileSync(path.join(__dirname, 'staker.gql'), 'utf8');
export const network = fs.readFileSync(path.join(__dirname, 'network.gql'), 'utf8');
export const distributor = fs.readFileSync(path.join(__dirname, 'distributor.gql'), 'utf8');
export const distribution = fs.readFileSync(path.join(__dirname, 'distribution.gql'), 'utf8');
export const claim = fs.readFileSync(path.join(__dirname, 'claim.gql'), 'utf8');
export const slash = fs.readFileSync(path.join(__dirname, 'slash.gql'), 'utf8');
export const account = fs.readFileSync(path.join(__dirname, 'account.gql'), 'utf8');
export const getStateByCID = fs.readFileSync(path.join(__dirname, 'getStateByCID.gql'), 'utf8');
export const getState = fs.readFileSync(path.join(__dirname, 'getState.gql'), 'utf8');

View File

@ -1,43 +0,0 @@
query network($id: String!, $block: Block_height){
network(id: $id, block: $block){
id
slot0{
id
owner
delegate
winningBid
oldBid
startTime
expirationTime
taxRatePerDay
}
slot1{
id
owner
delegate
winningBid
oldBid
startTime
expirationTime
taxRatePerDay
}
slot2{
id
owner
delegate
winningBid
oldBid
startTime
expirationTime
taxRatePerDay
}
stakers{
id
staked
rank
}
numStakers
totalStaked
stakedPercentiles
}
}

View File

@ -1,10 +0,0 @@
query producer($id: String!, $block: Block_height){
producer(id: $id, block: $block){
id
active
rewardCollector
rewards
confirmedBlocks
pendingEpochBlocks
}
}

View File

@ -1,17 +0,0 @@
query producerEpoch($id: String!, $block: Block_height){
producerEpoch(id: $id, block: $block){
id
address
epoch{
id
finalized
epochNumber
producerBlocks
allBlocks
producerBlocksRatio
}
totalRewards
blocksProduced
blocksProducedRatio
}
}

View File

@ -1,8 +0,0 @@
query producerRewardCollectorChange($id: String!, $block: Block_height){
producerRewardCollectorChange(id: $id, block: $block){
id
blockNumber
producer
rewardCollector
}
}

View File

@ -1,13 +0,0 @@
query producerSet($id: String!, $block: Block_height){
producerSet(id: $id, block: $block){
id
producers{
id
active
rewardCollector
rewards
confirmedBlocks
pendingEpochBlocks
}
}
}

View File

@ -1,8 +0,0 @@
query producerSetChange($id: String!, $block: Block_height){
producerSetChange(id: $id, block: $block){
id
blockNumber
producer
changeType
}
}

View File

@ -1,33 +0,0 @@
query rewardSchedule($id: String!, $block: Block_height){
rewardSchedule(id: $id, block: $block){
id
rewardScheduleEntries{
id
startTime
epochDuration
rewardsPerEpoch
}
lastEpoch{
id
finalized
epochNumber
producerBlocks
allBlocks
producerBlocksRatio
}
pendingEpoch{
id
finalized
epochNumber
producerBlocks
allBlocks
producerBlocksRatio
}
activeRewardScheduleEntry{
id
startTime
epochDuration
rewardsPerEpoch
}
}
}

View File

@ -1,8 +0,0 @@
query rewardScheduleEntry($id: String!, $block: Block_height){
rewardScheduleEntry(id: $id, block: $block){
id
startTime
epochDuration
rewardsPerEpoch
}
}

View File

@ -1,12 +0,0 @@
query slash($id: String!, $block: Block_height){
slash(id: $id, block: $block){
id
timestamp
account{
id
totalClaimed
totalSlashed
}
slashed
}
}

View File

@ -1,21 +0,0 @@
query slot($id: String!, $block: Block_height){
slot(id: $id, block: $block){
id
owner
delegate
winningBid
oldBid
startTime
expirationTime
taxRatePerDay
claims{
id
owner
winningBid
oldBid
startTime
expirationTime
taxRatePerDay
}
}
}

View File

@ -1,21 +0,0 @@
query slotClaim($id: String!, $block: Block_height){
slotClaim(id: $id, block: $block){
id
slot{
id
owner
delegate
winningBid
oldBid
startTime
expirationTime
taxRatePerDay
}
owner
winningBid
oldBid
startTime
expirationTime
taxRatePerDay
}
}

Some files were not shown because too many files have changed in this diff Show More