UNPKG

olympus-protocol-connector

Version:

Module made by Olympus Labs for easier access to the Olympus protocol through Javascript/Typescript

536 lines 24 kB
"use strict"; 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 }; } }; Object.defineProperty(exports, "__esModule", { value: true }); var Promisify_1 = require("../utils/Promisify"); var config_1 = require("../config"); var EthereumTx = require("ethereumjs-tx"); var logger_1 = require("../utils/logger"); var Enums_1 = require("../interfaces/Enums"); var Web3 = require("web3"); var RpcService = /** @class */ (function () { function RpcService(web3Url) { this.chainId = 0; this.logger = logger_1.LogService.logger; this.reset(web3Url); } Object.defineProperty(RpcService, "Instance", { /** * RpcService Singleton Instance; */ get: function () { if (!RpcService.instance) { RpcService.instance = new RpcService(config_1.default.web3Url); } return RpcService.instance; }, enumerable: true, configurable: true }); /** * customize RpcService * this method for customize client RpcService, can be override every methods. * @param service RpcService */ RpcService.customize = function (service) { RpcService.instance = service; }; Object.defineProperty(RpcService, "Web3", { /** web3 module export */ get: function () { return Web3; }, enumerable: true, configurable: true }); Object.defineProperty(RpcService, "Config", { /** default config export */ get: function () { return config_1.default; }, enumerable: true, configurable: true }); RpcService.prototype.setChainId = function () { return __awaiter(this, void 0, void 0, function () { var newId; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, Promisify_1.Promisify(function (callback) { return _this.rpc.version.getNetwork(callback); })]; case 1: newId = _a.sent(); if (this.chainId !== newId) { this.chainId = newId; } return [2 /*return*/]; } }); }); }; Object.defineProperty(RpcService.prototype, "MainAddress", { get: function () { if (config_1.default.walletAddress) { return config_1.default.walletAddress; } if (this._mainAddress) { return this._mainAddress; } this._mainAddress = this._rpc.eth.accounts.length > 0 ? this._rpc.eth.accounts[0] : null; return this._mainAddress; }, enumerable: true, configurable: true }); RpcService.prototype.reset = function (web3Url) { if (!this._rpc) { this._rpc = new Web3(); var url = web3Url || config_1.default.web3Url; // If pre configured, don't need to pass the web3Url if (!url) { throw new Error('Web3URL is needed to interact with the block chain in order to work with derivatives'); } this._rpc.setProvider(new Web3.providers.HttpProvider(url, 9000)); } }; Object.defineProperty(RpcService.prototype, "eth", { get: function () { return this.rpc.eth; }, enumerable: true, configurable: true }); Object.defineProperty(RpcService.prototype, "rpc", { // Access to native rpc get: function () { return this._rpc; }, enumerable: true, configurable: true }); // Wrapper RpcService.prototype.toHex = function (number) { return this.rpc.toHex(number); }; RpcService.prototype.contract = function (abi, address) { return this.rpc.eth.contract(abi).at(address); }; RpcService.prototype.fromWei = function (amount, unit) { if (unit === void 0) { unit = 'ether'; } return this.rpc.fromWei(amount, unit); }; RpcService.prototype.toWei = function (amount, unit) { return this.rpc.toWei(amount, unit); }; RpcService.prototype.byte32ToString = function (data) { return this.rpc.toAscii(data).replace(/\u0000/g, '').trim(); }; RpcService.prototype.version = function () { return this.rpc.version.api; }; RpcService.prototype.isValidAddress = function (address) { return this.rpc.isAddress(address); }; RpcService.prototype.getNonce = function (address) { return __awaiter(this, void 0, void 0, function () { var nonce; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, Promisify_1.Promisify(function (callback) { return _this.rpc.eth.getTransactionCount(address, _this.rpc.eth.defaultBlock, callback); })]; case 1: nonce = _a.sent(); return [2 /*return*/, nonce]; } }); }); }; RpcService.prototype.getTransactionReceipt = function (hash) { return __awaiter(this, void 0, void 0, function () { var result; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, Promisify_1.Promisify(function (callback) { return _this.rpc.eth.getTransactionReceipt(hash, callback); })]; case 1: result = _a.sent(); return [2 /*return*/, result]; } }); }); }; RpcService.prototype.getTransactionsReceipts = function (hashes) { return __awaiter(this, void 0, void 0, function () { var receipts; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, Promise.all(hashes.map(function (hash) { return __awaiter(_this, void 0, void 0, function () { var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, Promisify_1.Promisify(function (callback) { return _this.rpc.eth.getTransactionReceipt(hash, callback); })]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }))]; case 1: receipts = _a.sent(); return [2 /*return*/, receipts]; } }); }); }; RpcService.prototype.getBalance = function (address) { return __awaiter(this, void 0, void 0, function () { var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, Promisify_1.Promisify(function (callback) { return _this.rpc.eth.getBalance(address, callback); })]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; RpcService.prototype.getGasPrice = function () { return __awaiter(this, void 0, void 0, function () { var gasPrice; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, Promisify_1.Promisify(function (callback) { return _this.rpc.eth.getGasPrice(callback); })]; case 1: gasPrice = _a.sent(); return [2 /*return*/, gasPrice]; } }); }); }; RpcService.prototype.getGasLimit = function () { return __awaiter(this, void 0, void 0, function () { var block, gasLimit; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, Promisify_1.Promisify(function (callback) { return _this.rpc.eth.getBlock('latest', callback); })]; case 1: block = _a.sent(); gasLimit = block.gasLimit; return [2 /*return*/, gasLimit]; } }); }); }; RpcService.prototype.toAscii = function (hex) { return this.rpc.toAscii(hex); }; RpcService.prototype.toNumber = function (hexadecimal) { return parseInt(hexadecimal + '', 16); }; RpcService.prototype.fromAscii = function (string) { return this.rpc.fromAscii(string); }; RpcService.prototype.connectContract = function (abi, address) { return this.rpc.eth.contract(abi).at(address); }; /** * afterTxBuilt can be override by client * @param caller to identify which method call this * @param tx Tx */ RpcService.prototype.afterTxBuilt = function (caller, tx) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, tx]; }); }); }; RpcService.prototype.buildTx = function (_a) { var from = _a.from, to = _a.to, data = _a.data, _b = _a.amount, amount = _b === void 0 ? 0 : _b, _c = _a.gasPrice, gasPrice = _c === void 0 ? 0 : _c, _d = _a.gasLimit, gasLimit = _d === void 0 ? 0 : _d, caller = _a.caller, description = _a.description; return __awaiter(this, void 0, void 0, function () { var tx; return __generator(this, function (_e) { switch (_e.label) { case 0: return [4 /*yield*/, this.createTx({ from: from, to: to, data: data, amount: amount, gasPrice: gasPrice, gasLimit: gasLimit })]; case 1: tx = _e.sent(); return [4 /*yield*/, this.afterTxBuilt(caller, tx)]; case 2: _e.sent(); return [2 /*return*/, tx]; } }); }); }; RpcService.prototype.createTx = function (_a) { var from = _a.from, to = _a.to, data = _a.data, _b = _a.amount, amount = _b === void 0 ? 0 : _b, _c = _a.gasPrice, gasPrice = _c === void 0 ? 0 : _c, _d = _a.gasLimit, gasLimit = _d === void 0 ? 0 : _d; return __awaiter(this, void 0, void 0, function () { var amountWei, recommendedGasPrice, _e, walletAddress, finalGasLimit, _f, _g, _h, e_1, tx, _j; return __generator(this, function (_k) { switch (_k.label) { case 0: amountWei = amount ? this.rpc.toWei(amount, 'ether') : 0; _e = gasPrice; if (_e) return [3 /*break*/, 2]; return [4 /*yield*/, this.getGasPrice()]; case 1: _e = (_k.sent()).toNumber() + config_1.default.extraGasPrice; _k.label = 2; case 2: recommendedGasPrice = _e; walletAddress = from || this.MainAddress; _k.label = 3; case 3: _k.trys.push([3, 6, , 7]); _f = gasLimit; if (_f) return [3 /*break*/, 5]; _h = (_g = Math).round; return [4 /*yield*/, this.estimateGas({ to: to, data: data, })]; case 4: _f = _h.apply(_g, [(_k.sent()) * config_1.default.gasIncrement]); _k.label = 5; case 5: finalGasLimit = _f; return [3 /*break*/, 7]; case 6: e_1 = _k.sent(); // If it is not an estimation error, still throw it, it will be handled normally and not executed if (e_1 && e_1.message && !e_1.message.includes('gas required exceeds allowance or always failing transaction')) { throw e_1; } this.logger.warn("Estimation error: " + e_1); // We can use this to deduce that the estimation failed // didEstimateFail = finalGasLimit == Config.maximumBlockGas ? true : false finalGasLimit = config_1.default.maximumBlockGas; return [3 /*break*/, 7]; case 7: _j = { from: walletAddress, gasPrice: this.rpc.toHex(recommendedGasPrice), gas: this.rpc.toHex(Math.min(+finalGasLimit, config_1.default.maximumBlockGas)), to: to, value: this.rpc.toHex(amountWei), data: data }; return [4 /*yield*/, this.getNonce(walletAddress)]; case 8: tx = (_j.nonce = _k.sent(), _j); return [2 /*return*/, tx]; } }); }); }; RpcService.prototype.sendTX = function (productAddress, data) { return __awaiter(this, void 0, void 0, function () { var tx, newTx, e_2; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 3, , 4]); return [4 /*yield*/, this.createTx({ to: productAddress, data: data })]; case 1: tx = _a.sent(); return [4 /*yield*/, this.sendRawTransaction(tx)]; case 2: newTx = _a.sent(); return [2 /*return*/, newTx]; case 3: e_2 = _a.sent(); logger_1.LogService.logger.error("Error sending tx for address: " + productAddress + ". Error: " + e_2); return [2 /*return*/, null]; case 4: return [2 /*return*/]; } }); }); }; RpcService.prototype.send = function (tx) { return __awaiter(this, void 0, void 0, function () { var _a; var _this = this; return __generator(this, function (_b) { switch (_b.label) { case 0: _a = tx; return [4 /*yield*/, Promisify_1.Promisify(function (callback) { return _this.rpc.eth.sendTransaction(tx, callback); })]; case 1: _a.hash = _b.sent(); tx.chainId = this.chainId; return [2 /*return*/, tx]; } }); }); }; RpcService.prototype.sendRawTransaction = function (tx) { return __awaiter(this, void 0, void 0, function () { var ethTx, serializedTx, _a; var _this = this; return __generator(this, function (_b) { switch (_b.label) { case 0: ethTx = new EthereumTx(tx); ethTx.sign(new Buffer(config_1.default.privateKey, 'hex')); serializedTx = ethTx.serialize(); // TODO, OL-1732 // if (AppOptions.dry) { // logger.info(`Running dry for ${tx}`); // return tx; // } _a = tx; return [4 /*yield*/, Promisify_1.Promisify(function (callback) { return _this.rpc.eth.sendRawTransaction("0x" + serializedTx.toString('hex'), callback); })]; case 1: // TODO, OL-1732 // if (AppOptions.dry) { // logger.info(`Running dry for ${tx}`); // return tx; // } _a.hash = (_b.sent()); return [2 /*return*/, tx]; } }); }); }; RpcService.prototype.isTxSuccessful = function (hash) { return __awaiter(this, void 0, void 0, function () { var result; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getTransactionReceipt(hash)]; case 1: result = _a.sent(); if (result) { switch (result.status) { case '0x0': return [2 /*return*/, Enums_1.TxStatus.FAIL]; case '0x1': return [2 /*return*/, Enums_1.TxStatus.SUCCESS]; default: return [2 /*return*/, Enums_1.TxStatus.FAIL]; } } return [2 /*return*/, Enums_1.TxStatus.PENDING]; } }); }); }; RpcService.prototype.tryEstimateGas = function (option, gasLimit) { if (gasLimit === void 0) { gasLimit = config_1.default.gasLimit; } return __awaiter(this, void 0, void 0, function () { var ex_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this.estimateGas(option)]; case 1: return [2 /*return*/, _a.sent()]; case 2: ex_1 = _a.sent(); this.logger.warn('estimateGas failure', ex_1); return [2 /*return*/, gasLimit]; case 3: return [2 /*return*/]; } }); }); }; RpcService.prototype.estimateGas = function (option) { return __awaiter(this, void 0, void 0, function () { var from, to, data, _a, amount, _b, gasPrice, gas, amountWei, recommendedGasPrice, _c, walletAddress; var _this = this; return __generator(this, function (_d) { switch (_d.label) { case 0: from = option.from, to = option.to, data = option.data, _a = option.amount, amount = _a === void 0 ? 0 : _a, _b = option.gasPrice, gasPrice = _b === void 0 ? 0 : _b; amountWei = amount ? this.toWei(amount, 'ether') : undefined; _c = gasPrice; if (_c) return [3 /*break*/, 2]; return [4 /*yield*/, this.getGasPrice()]; case 1: _c = (_d.sent()); _d.label = 2; case 2: recommendedGasPrice = _c; walletAddress = from || this.MainAddress; return [4 /*yield*/, Promisify_1.Promisify(function (cb) { _this.rpc.eth.estimateGas({ from: walletAddress, gasPrice: _this.toHex(+recommendedGasPrice), to: to, value: _this.toHex(amountWei), data: data, }, cb); })]; case 3: gas = _d.sent(); return [2 /*return*/, Math.ceil(gas * 1.1)]; } }); }); }; // This expects a pre build tx with hex values RpcService.prototype.repeatTx = function (tx) { return __awaiter(this, void 0, void 0, function () { var gasPrice, newTx; return __generator(this, function (_a) { gasPrice = this.toNumber(tx.gasPrice) * config_1.default.repeatTxIncreasePrice; newTx = { from: tx.from, gasPrice: this.toHex(gasPrice), gas: tx.gas, to: tx.to, value: tx.value, data: tx.data, nonce: tx.nonce, }; return [2 /*return*/, newTx]; }); }); }; return RpcService; }()); exports.RpcService = RpcService; //# sourceMappingURL=RpcService.js.map