Lazy ERC20 watcher (#11)

* Storage mapping utils.

* Resolver factories.

* Get ERC20 balance from upstream ipld-eth-server slot.

* Get ERC20 allowance from storage slot.

* Parse ERC20 events from block events.

* Cache GQL requests in leveldb.

* Refactor fetch/cache from upstream into eth-loader class.

* Refactoring.

* Refactor eth-client, extract cache class.

* Cache config settings.

* Debug logs.

* Rename server to watcher.

* Start local server by default.

* Split into multiple packages.

* eth-client API methods.

* Update docs.
This commit is contained in:
Ashwin Phatak
2021-05-28 16:56:40 +05:30
committed by GitHub
parent 95eb1ac0d1
commit 7213a1dc6d
26 changed files with 1377 additions and 106 deletions
+1
View File
@@ -0,0 +1 @@
export * from './src/cache';
+45
View File
@@ -0,0 +1,45 @@
{
"name": "@vulcanize/cache",
"version": "0.1.0",
"description": "Generic object cache",
"private": true,
"main": "index.ts",
"scripts": {
"test": "mocha -r ts-node/register src/**/*.spec.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/vulcanize/erc20-watcher.git"
},
"author": "",
"license": "UNLICENSED",
"bugs": {
"url": "https://github.com/vulcanize/erc20-watcher/issues"
},
"homepage": "https://github.com/vulcanize/erc20-watcher#readme",
"dependencies": {
"@types/lodash": "^4.14.168",
"apollo-type-bigint": "^0.1.3",
"canonical-json": "^0.0.4",
"debug": "^4.3.1",
"ethers": "^5.2.0",
"express": "^4.17.1",
"express-graphql": "^0.12.0",
"fs-extra": "^10.0.0",
"graphql": "^15.5.0",
"graphql-import-node": "^0.0.4",
"graphql-request": "^3.4.0",
"graphql-tools": "^7.0.4",
"left-pad": "^1.3.0",
"level": "^7.0.0",
"lodash": "^4.17.21",
"toml": "^3.0.0",
"yargs": "^17.0.1"
},
"devDependencies": {
"@types/express": "^4.17.11",
"@types/yargs": "^17.0.0",
"nodemon": "^2.0.7",
"ts-node": "^10.0.0"
}
}
+81
View File
@@ -0,0 +1,81 @@
import assert from 'assert';
import canonicalStringify from 'canonical-json';
import { ethers } from 'ethers';
import level from 'level';
import fs from 'fs-extra';
import path from 'path';
import debug from 'debug';
const log = debug('vulcanize:cache');
export const getCache = async (config) => {
let cache;
// Cache is optional.
if (config) {
log("config", JSON.stringify(config, null, 2));
const { name, enabled, deleteOnStart } = config;
assert(name);
const cacheDirPath = path.join(process.cwd(), 'out', `${name}.db`);
await fs.ensureDir(cacheDirPath);
// Delete cache on start.
if (deleteOnStart) {
await fs.emptyDir(cacheDirPath);
}
// Enable/disable flag for the cache.
if (enabled) {
cache = new Cache(name, cacheDirPath);
}
}
return cache;
};
export class Cache {
_db: any;
_name: string;
constructor(name, dirPath) {
assert(name);
assert(dirPath);
this._name = name;
this._db = level(dirPath, { valueEncoding: 'json' });;
}
key(obj) {
return this._cacheKey(obj);
}
async get(obj) {
const key = this._cacheKey(obj);
try {
const value = await this._db.get(key);
log(`${this._name}: cache hit ${key}`);
return [value, true];
} catch (err) {
log(`${this._name}: cache miss ${key}`);
if (err.notFound) {
return [undefined, false]
}
}
}
async put(obj, value) {
await this._db.put(this._cacheKey(obj), value);
}
_cacheKey(obj) {
return ethers.utils.keccak256(Buffer.from(canonicalStringify(obj)));
}
}