argosjs
Version:
Ethereum smart-contract events visualiser
691 lines (690 loc) • 36.1 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
var ethers_1 = require("ethers");
var neo4j_driver_1 = require("neo4j-driver");
var DatabaseFactory_1 = require("../factory/DatabaseFactory");
var errors = __importStar(require("../utils/error"));
var strategy_1 = require("../utils/strategy");
var Watcher_1 = require("./Watcher");
var EthereumWatcher = /** @class */ (function (_super) {
__extends(EthereumWatcher, _super);
/**
* Create a watcher for Ethereum blockchain
* @param {string} contractAddr the address of the verified contract
* @param {string} abi the ABI of the verified contract
* @param {number} providerType the Etherscan API Token
* @param {DatabaseConstructorType} dbType the database servcice constructor
* @param {ProviderConfig} providerConfig the loaded config file
* @param {boolean} clearDB retrieve from genesis block instead of the latest in DB (db cleared)
* @param {string} exportDir export dir
* @returns {EthereumWatcher} Ethereum instance
*/
function EthereumWatcher(contractAddr, abi, providerType, dbType, providerConfig, clearDB, exportDir) {
var _this = _super.call(this) || this;
_this._contractAddr = contractAddr;
_this._dbType = dbType;
_this._dbService = DatabaseFactory_1.DatabaseFactory.createDbInstance(_this._dbType);
_this._clearDB = clearDB;
_this._config = providerConfig;
_this._provider = _this.getProvider(providerType, providerConfig);
_this._contract = new ethers_1.ethers.Contract(_this._contractAddr, abi, _this._provider);
_this._exportDir = exportDir;
_this._event = undefined;
_this._timeout = _this._config.timeout;
_this._logSizePerOp = _this._config.logSizePerOp || 900;
console.log("Ethereum Watcher initiated!");
return _this;
}
/**
* Watch event with particular model
* @param {string} eventName name of the event
* @param {Neode.SchemaObject} dbModel the model loaded via require()
* @param {number} fromDate timestamp
* @param {number} toDate timestamp
*/
EthereumWatcher.prototype.watchEvents = function (eventName, fromDate, toDate) {
return __awaiter(this, void 0, void 0, function () {
var fromBlock, _a, toBlock, _b, startTime, endTime, elapsedMilli, elapsedSeconds, elapsedMinutes, roundMinutes, roundSeconds, roundMilis;
var _this = this;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
if (!fromDate) return [3 /*break*/, 2];
return [4 /*yield*/, this.timeToBlock(fromDate)];
case 1:
_a = _c.sent();
return [3 /*break*/, 3];
case 2:
_a = 0;
_c.label = 3;
case 3:
fromBlock = _a;
if (!toDate) return [3 /*break*/, 5];
return [4 /*yield*/, this.timeToBlock(toDate)];
case 4:
_b = _c.sent();
return [3 /*break*/, 7];
case 5: return [4 /*yield*/, this._latestBlockNo];
case 6:
_b = _c.sent();
_c.label = 7;
case 7:
toBlock = _b;
this._event = this._contract.interface.events[eventName];
console.log("Start logging " + eventName + " events");
startTime = new Date();
if (!this._clearDB) return [3 /*break*/, 9];
console.log("Update cache...");
return [4 /*yield*/, this.getEvents(eventName, fromBlock, toBlock)];
case 8:
_c.sent();
return [3 /*break*/, 11];
case 9:
console.log("Reload from cache...");
return [4 /*yield*/, this.importCSV()
.then(function () { return __awaiter(_this, void 0, void 0, function () {
var latestInDB, earliestInDB, upperBlock, lowerBlock;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
console.log("Cached reloaded, updating...");
this._clearDB = false;
return [4 /*yield*/, this._dbService.executeQuery({ query: "MATCH ()-[r]->() RETURN max(r.blockheight) as result" })];
case 1:
latestInDB = _a.sent();
return [4 /*yield*/, this._dbService.executeQuery({ query: "MATCH ()-[r]->() RETURN min(r.blockheight) as result" })];
case 2:
earliestInDB = _a.sent();
upperBlock = latestInDB ? parseInt(latestInDB[0].get("result")) : undefined;
lowerBlock = earliestInDB ? parseInt(earliestInDB[0].get("result")) : undefined;
if (!(lowerBlock && upperBlock)) return [3 /*break*/, 11];
if (!(fromBlock > upperBlock || toBlock < lowerBlock)) return [3 /*break*/, 4];
console.log("The required range is outside DB's range");
return [4 /*yield*/, this.getEvents(eventName, fromBlock, toBlock)];
case 3:
_a.sent();
_a.label = 4;
case 4:
if (!(fromBlock >= lowerBlock && toBlock <= upperBlock)) return [3 /*break*/, 6];
console.log("The required range is inside DB's range");
return [4 /*yield*/, this.getEvents(eventName, fromBlock, toBlock)];
case 5:
_a.sent();
_a.label = 6;
case 6:
if (!(fromBlock !== 0 && fromBlock < lowerBlock)) return [3 /*break*/, 8];
console.log("The required fromBlock is earlier than DB's earliest block");
return [4 /*yield*/, this.getEvents(eventName, fromBlock, lowerBlock)];
case 7:
_a.sent();
_a.label = 8;
case 8:
if (!(toBlock > upperBlock)) return [3 /*break*/, 10];
console.log("The required toBlock is more recent than DB's latest block");
return [4 /*yield*/, this.getEvents(eventName, upperBlock, toBlock)];
case 9:
_a.sent();
_a.label = 10;
case 10: return [3 /*break*/, 12];
case 11:
errors.throwError({
type: "ERROR_WATCHER_WATCHEVENTS" /* ERROR_WATCHER_WATCHEVENTS */,
reason: "Could not find block range...",
level: "warn",
dump: {
fromBlock: fromBlock,
toBlock: toBlock
}
});
_a.label = 12;
case 12: return [2 /*return*/];
}
});
}); })
.catch(function (error) { return __awaiter(_this, void 0, void 0, function () {
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = error.name;
switch (_a) {
case "ERROR_WATCHER_WATCHEVENTS" /* ERROR_WATCHER_WATCHEVENTS */: return [3 /*break*/, 1];
}
return [3 /*break*/, 3];
case 1:
console.log("Cache not loaded or corrupted, updating...");
this._clearDB = true;
return [4 /*yield*/, this.getEvents(eventName, fromBlock, toBlock).catch(function (error) { throw error; })];
case 2:
_b.sent();
return [3 /*break*/, 4];
case 3: throw error;
case 4: return [2 /*return*/];
}
});
}); })];
case 10:
_c.sent();
_c.label = 11;
case 11:
endTime = new Date();
elapsedMilli = endTime.getTime() - startTime.getTime();
elapsedSeconds = elapsedMilli / 1000;
elapsedMinutes = elapsedSeconds / 60;
roundMinutes = Math.trunc(elapsedMinutes);
roundSeconds = Math.trunc(elapsedSeconds - roundMinutes * 60);
roundMilis = Math.trunc(elapsedMilli - roundMinutes * 60000 - roundSeconds * 1000);
console.log("Finished in " + roundMinutes + " mins " + roundSeconds + " s " + roundMilis + " ms");
return [2 /*return*/];
}
});
});
};
/**
* Convert timestamp to blocknumber
* @param {Date} date
*/
EthereumWatcher.prototype.timeToBlock = function (date) {
return __awaiter(this, void 0, void 0, function () {
var latestBlockNo, upperBlock, lowerBlock, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._provider.getBlockNumber()];
case 1:
latestBlockNo = _a.sent();
return [4 /*yield*/, this._provider.getBlock(latestBlockNo)];
case 2:
upperBlock = _a.sent();
this._latestBlockNo = latestBlockNo;
this._latestTime = upperBlock.timestamp;
if (!(this._blockTime === undefined)) return [3 /*break*/, 4];
return [4 /*yield*/, this._provider.getBlock(1)];
case 3:
lowerBlock = _a.sent();
// How many time does it take to make one block (on average) in s
this._blockTime = (upperBlock.timestamp - lowerBlock.timestamp) / (latestBlockNo - 1);
_a.label = 4;
case 4:
result = latestBlockNo - Math.floor((upperBlock.timestamp - date.getTime() / 1000) / this._blockTime);
// console.log(blockTime, result);
return [2 /*return*/, result];
}
});
});
};
/**
* Tell the Watcher to clear the database before the next operation
* @param clearFlag
*/
EthereumWatcher.prototype.setClearDBFlag = function (clearFlag) {
this._clearDB = clearFlag;
};
/**
* Assemble a selection of data out of a log part
* @param {ethers.providers.Log[]} logPart the extracted log part
*/
EthereumWatcher.prototype.getLogData = function (logPart) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.checkTimeout();
return [4 /*yield*/, Promise.all(logPart.map(function (logEntry) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.extractData(logEntry)];
case 1: return [2 /*return*/, _a.sent()];
}
}); }); }))];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/**
* Check for timeout
*/
EthereumWatcher.prototype.checkTimeout = function () {
// Stops on timeout
var elapsedTime = new Date().getTime() - this._startTime.getTime();
if (this._timeout > 0 && elapsedTime > this._timeout) {
errors.throwError({
type: "ERROR_WATCHER_GETEVENTS" /* ERROR_WATCHER_GETEVENTS */,
reason: "Timeout while getting events.",
level: "error",
dump: {
elapsedTime: elapsedTime + " ms",
timeoutLimit: this._timeout + " ms"
}
});
}
};
/**
* Get events from provider and store data to database
* @param {string} eventName
* @param {number} fromBlock
* @param {number} toBlock
*/
EthereumWatcher.prototype.getEvents = function (eventName, fromBlock, toBlock) {
return __awaiter(this, void 0, void 0, function () {
var self, start, end, nbEvents, steps, eidss, temp;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!this._clearDB) return [3 /*break*/, 2];
return [4 /*yield*/, this._dbService.dbClearAll()];
case 1:
_a.sent();
_a.label = 2;
case 2:
self = this;
start = fromBlock;
end = toBlock;
nbEvents = 0;
steps = 0;
this._startTime = new Date();
_a.label = 3;
case 3:
if (!(start !== end)) return [3 /*break*/, 8];
eidss = void 0;
_a.label = 4;
case 4:
if (!(eidss === undefined)) return [3 /*break*/, 6];
return [4 /*yield*/, self.getEventPatch(eventName, start, end).catch(function (error) {
// In case of ERROR_WATCHER_PROVIDER_GETLOGS, proceed to dichotomy
if (error.name !== "ERROR_WATCHER_PROVIDER_GETLOGS" /* ERROR_WATCHER_PROVIDER_GETLOGS */) {
throw error;
}
})];
case 5:
temp = _a.sent();
if (temp) {
eidss = temp;
}
else {
// Lower the blockrange
end = start + Math.floor((end - start) / 2);
// Stops if too many events in 1 block
if (start === end) {
errors.throwError({
type: "ERROR_WATCHER_GETEVENTS" /* ERROR_WATCHER_GETEVENTS */,
level: "error",
reason: "Too many events in 1 block! ",
});
}
this.checkTimeout();
steps += 1;
}
return [3 /*break*/, 4];
case 6: return [4 /*yield*/, this.sendToDB(eidss)];
case 7:
_a.sent();
start = (end === toBlock) ? end : end + 1;
end = toBlock;
steps += 1;
nbEvents += eidss.length;
return [3 /*break*/, 3];
case 8:
console.log(nbEvents + " event(s) detected!", "required " + steps + " steps");
return [2 /*return*/];
}
});
});
};
/**
* Load the strategies to the watcher
* @param strategies the user-defined strategy to extract and persists data
*/
EthereumWatcher.prototype.setStrategies = function (strategies) {
var _this = this;
this._strategies = strategies;
this._nbContractCall = Object.keys(this._strategies.DataExtractionStrategy).filter(function (iteration) {
var strategy = _this._strategies.DataExtractionStrategy[parseInt(iteration)].strategy;
return strategy ? true : false;
}).length;
};
/**
* Convert blockNo to timestamp
* @param blockNo
*/
EthereumWatcher.prototype.blockToTime = function (blockNo) {
var howManyBlocks = this._latestBlockNo - blockNo;
var howManyTime = howManyBlocks * this._blockTime;
return Math.ceil(this._latestTime - howManyTime);
};
/**
* Export to CSV
*/
EthereumWatcher.prototype.exportCSV = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this._dbService.exportCSV(this._exportDir + this._contractAddr)];
});
});
};
/**
* Import from CSV
*/
EthereumWatcher.prototype.importCSV = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._dbService.dbClearAll()];
case 1:
_a.sent();
return [2 /*return*/, this._dbService.importCSV(this._contractAddr)];
}
});
});
};
/**
* Call the right provider for the contract
* @param {ProviderEnum} providerType the provider type
* @param {ProviderConfig} config the loaded config file
* @returns {ethers.providers.BaseProvider} a provider
*/
EthereumWatcher.prototype.getProvider = function (providerType, config) {
switch (providerType) {
case 0 /* defaultProvider */:
default:
return ethers_1.ethers.getDefaultProvider(config.default.network);
case 1 /* EtherscanProvider */:
return new ethers_1.ethers.providers.EtherscanProvider(ethers_1.ethers.utils.getNetwork(config.etherscan.network), config.etherscan.api);
case 2 /* InfuraProvider */:
console.log("Infura");
return new ethers_1.ethers.providers.InfuraProvider(ethers_1.ethers.utils.getNetwork(config.infura.network), config.infura.projectId);
case 3 /* JsonRpcProvider */:
console.log("JSON-RPC");
var urlString = (config.jsonrpc.username === "") ? config.jsonrpc.url : {
url: config.jsonrpc.url,
user: config.jsonrpc.username,
password: config.jsonrpc.password,
allowInsecure: config.jsonrpc.allowInsecure
};
return new ethers_1.ethers.providers.JsonRpcProvider(urlString, ethers_1.ethers.utils.getNetwork(config.jsonrpc.network));
case 4 /* Web3Provider */:
return new ethers_1.ethers.providers.Web3Provider({ host: config.web3.host });
case 5 /* IpcProvider */:
return new ethers_1.ethers.providers.IpcProvider(config.ipc.path, ethers_1.ethers.utils.getNetwork(config.ipc.network));
}
};
/**
* Persist processed data to the database
* @param eidss the processed data
*/
EthereumWatcher.prototype.sendToDB = function (eidss) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._dbService.persistDataToDB(eidss, this._strategies.PersistenceStrategy)];
case 1:
_a.sent();
return [4 /*yield*/, this.exportCSV()];
case 2:
_a.sent();
console.log("Database updated!");
return [2 /*return*/];
}
});
});
};
/**
* Extract data from log entry
* @param {ethers.providers.Log} logEntry a log entry
* @returns {EventInfoDataStruct} the required information to build a db node
*/
EthereumWatcher.prototype.extractData = function (logEntry) {
return __awaiter(this, void 0, void 0, function () {
var data, DES, nbIterations, eids, _loop_1, this_1, i;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.checkTimeout();
data = this._event.decode(logEntry.data, logEntry.topics);
DES = this._strategies.DataExtractionStrategy;
nbIterations = Object.keys(DES).length;
eids = {};
eids.blockheight = logEntry.blockNumber;
eids.eventTime = neo4j_driver_1.v1.types.DateTime.fromStandardDate(new Date(this.blockToTime(eids.blockheight) * 1000));
_loop_1 = function (i) {
var strategy, result, s, _a, args, r;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
strategy = Object.keys(DES[i])[1];
result = void 0;
_a = strategy;
switch (_a) {
case "contractCall": return [3 /*break*/, 1];
case "fromData": return [3 /*break*/, 5];
}
return [3 /*break*/, 8];
case 1:
s = DES[i][strategy];
args = Object.keys(s.args).map(function (arg) {
var argProcess = s.args[arg];
return argProcess ? argProcess(data[arg]) : data[arg];
});
return [4 /*yield*/, this_1.contractCall(s.funcName, args, s.ignoreError)];
case 2:
r = _b.sent();
result = r ? r[s.resAttr] : r;
if (!r) return [3 /*break*/, 4];
return [4 /*yield*/, this_1.processData(s, result)];
case 3:
result = _b.sent();
_b.label = 4;
case 4: return [3 /*break*/, 9];
case 5:
s = DES[i][strategy];
result = data[s.attrName];
if (!result) return [3 /*break*/, 7];
return [4 /*yield*/, this_1.processData(s, result)];
case 6:
result = _b.sent();
_b.label = 7;
case 7: return [3 /*break*/, 9];
case 8:
errors.throwError({
type: "ERROR_WATCHER_EXTRACT_DATA" /* ERROR_WATCHER_EXTRACT_DATA */,
level: "error",
reason: "Unable to find strategy for " + DES[i] + "."
});
_b.label = 9;
case 9:
eids[DES[i].propName] = result;
return [2 /*return*/];
}
});
};
this_1 = this;
i = 0;
_a.label = 1;
case 1:
if (!(i < nbIterations)) return [3 /*break*/, 4];
return [5 /*yield**/, _loop_1(i)];
case 2:
_a.sent();
_a.label = 3;
case 3:
i++;
return [3 /*break*/, 1];
case 4: return [2 /*return*/, eids];
}
});
});
};
/**
* Call contract method
* @param funcName method name
* @param args method args
*/
EthereumWatcher.prototype.contractCall = function (funcName, args, ignoreError) {
var contractFuncs = this._contract.functions;
if (!Object.keys(contractFuncs).includes(funcName)) {
errors.throwError({
type: "ERROR_WATCHER_CONTRACT_CALL" /* ERROR_WATCHER_CONTRACT_CALL */,
level: "error",
reason: "This contract does not contain function " + funcName
});
}
var func = this._contract.functions[funcName];
var process = func.apply(this._contract, args);
return process.catch(function (error) {
if (!ignoreError) {
throw error;
}
});
};
/**
* Apply process function after extracting data. By default, the data will be processed as String
* @param strategy DES strategy
* @param init unformatted/raw data
*/
EthereumWatcher.prototype.processData = function (strategy, init) {
return __awaiter(this, void 0, void 0, function () {
var process, contractFuncs, result;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
process = strategy.process || strategy_1.defaultDataProcess;
contractFuncs = this._contract.functions;
return [4 /*yield*/, process(init, contractFuncs)
.catch(function (reason) {
errors.throwError({
type: "ERROR_WATCHER_PROCESS_DATA" /* ERROR_WATCHER_PROCESS_DATA */,
reason: "Could not apply Process function. " + reason.message,
level: "error",
dump: {
usingStrategy: strategy,
initValue: init
}
});
})];
case 1:
result = _a.sent();
return [2 /*return*/, result];
}
});
});
};
/**
* Get the smaller batch of events
* @param {string} eventName
* @param {number} fromBlock
* @param {number} toBlock
* @returns {Promise<ethers.providers.Log[]>}
*/
EthereumWatcher.prototype.getEventPatch = function (eventName, fromBlock, toBlock) {
return __awaiter(this, void 0, void 0, function () {
var logs, eidss;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.checkTimeout();
console.log("Getting events '" + eventName + "' from block #" + fromBlock + " to block #" + toBlock);
return [4 /*yield*/, this._provider.getLogs({
fromBlock: fromBlock,
toBlock: toBlock,
address: this._contractAddr,
topics: [this._event.topic]
}).catch(function (reason) {
errors.throwError({
type: "ERROR_WATCHER_PROVIDER_GETLOGS" /* ERROR_WATCHER_PROVIDER_GETLOGS */,
level: "warn",
reason: "Provider could not get logs. This is due to the provider's restriction on data." + reason.message
});
})];
case 1:
logs = _a.sent();
if (!logs) return [3 /*break*/, 4];
if (!(logs.length >= this._logSizePerOp * this._nbContractCall)) return [3 /*break*/, 2];
errors.throwError({
type: "ERROR_WATCHER_PROVIDER_GETLOGS" /* ERROR_WATCHER_PROVIDER_GETLOGS */,
level: "warn",
reason: "Exceeded the amount of logSize permitted per operation. Consider lower the 'logSizePerOp' in the config.",
dump: {
logLength: logs.length,
maxLength: this._logSizePerOp
}
});
return [3 /*break*/, 4];
case 2: return [4 /*yield*/, this.getLogData(logs)
.catch(function (reason) {
errors.throwError({
type: "ERROR_WATCHER_GETLOGDATA" /* ERROR_WATCHER_GETLOGDATA */,
level: "error",
reason: "Could not get the log data" + reason.message,
dump: {
fromBlock: fromBlock,
toBlock: toBlock
}
});
})];
case 3:
eidss = _a.sent();
return [2 /*return*/, eidss ? eidss : undefined];
case 4: return [2 /*return*/, undefined];
}
});
});
};
return EthereumWatcher;
}(Watcher_1.Watcher));
exports.EthereumWatcher = EthereumWatcher;
exports.default = EthereumWatcher;