UNPKG

@backt/protocol

Version:
472 lines (387 loc) 14.8 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray'); var _slicedToArray3 = _interopRequireDefault(_slicedToArray2); var _regenerator = require('babel-runtime/regenerator'); var _regenerator2 = _interopRequireDefault(_regenerator); var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _bluebird = require('bluebird'); var _bluebird2 = _interopRequireDefault(_bluebird); var _has = require('lodash/has'); var _has2 = _interopRequireDefault(_has); var _contracts = require('./contracts'); var _utils = require('./utils'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var pushGasLimit = 100000; var addMarketGasLimit = 200000; var API = function () { (0, _createClass3.default)(API, [{ key: 'push', /** * Push new read value and timestamp to the contract. * @param marketIdStr Push read for this market (eg. "Poloniex_ETH_USD") * @param read BigNumber|String * @param ts UNIX millisecond timestamp of the read. * @return Promise resolving to the transaction receipt */ value: function () { var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(marketIdStr, read, ts) { var decimals, readBigNumber, marketId; return _regenerator2.default.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: (0, _utils.assertBigNumberOrString)(read); _context.next = 3; return this.feeds.decimals.call(); case 3: decimals = _context.sent; readBigNumber = (0, _utils.toContractBigNumber)(read, decimals).toString(); marketId = this.marketIdStrToBytes(marketIdStr); return _context.abrupt('return', this.feeds.push(marketId, readBigNumber, ts, { gas: pushGasLimit })); case 7: case 'end': return _context.stop(); } } }, _callee, this); })); function push(_x, _x2, _x3) { return _ref.apply(this, arguments); } return push; }() /** * Read latest value from the contract. * * @param marketIdStr Read value for this market (eg. "Poloniex_ETH_USD") * @return {read: <BigNumber read value>, ts: <epoch milliseconds timestamp>} */ }, { key: 'read', value: function () { var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(marketIdStr) { var marketId, _ref3, _ref4, readBigNumber, tsMillis, decimals, read; return _regenerator2.default.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: marketId = this.marketIdStrToBytes(marketIdStr); _context2.next = 3; return this.feeds.read.call(marketId); case 3: _ref3 = _context2.sent; _ref4 = (0, _slicedToArray3.default)(_ref3, 2); readBigNumber = _ref4[0]; tsMillis = _ref4[1]; _context2.next = 9; return this.feeds.decimals.call(); case 9: decimals = _context2.sent; read = (0, _utils.fromContractBigNumber)(readBigNumber, decimals); return _context2.abrupt('return', { read: read, ts: tsMillis.toNumber() }); case 12: case 'end': return _context2.stop(); } } }, _callee2, this); })); function read(_x4) { return _ref2.apply(this, arguments); } return read; }() /** * Add a new market feed. * @param marketIdStr Market ID for new market (eg. "Poloniex_ETH_USD") * @return Promise resolving to the transaction receipt */ }, { key: 'addMarket', value: function () { var _ref5 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee3(marketIdStr) { return _regenerator2.default.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: return _context3.abrupt('return', this.feeds.addMarket(marketIdStr, { from: this.config.ownerAccountAddr, gas: addMarketGasLimit })); case 1: case 'end': return _context3.stop(); } } }, _callee3, this); })); function addMarket(_x5) { return _ref5.apply(this, arguments); } return addMarket; }() /** * Register callback for LogFeedsPush events - whenever a Feeds.push() call * completes. * @param Callback expecting error as the first param and an object with * event arguments as the second param. */ }, { key: 'watchPushEvents', value: function watchPushEvents(onEventCallback) { var _this = this; var event = this.feeds.LogFeedsPush(); event.watch(function (error, event) { if (error) onEventCallback(error, {}); _this.eventParse(event).then(function (eventArgs) { return onEventCallback(error, eventArgs); }); }); } /** * Get all markets in the feeds contract with a mapping to isActive. * @param onSuccessCallback Callback that will receive a list like: * [ * {bytesId: "0xabc...", strId: "Poloniex_BTC_ETH", active: true}, * {bytesId: "0x123...", strId: "Binance_USD_ETH", active: false}, * ... * ] * @param onErrorCallback Callback that will receive any errors */ }, { key: 'getMarkets', value: function getMarkets(onSuccessCallback, onErrorCallback) { var _this2 = this; var event = this.feeds.LogFeedsMarketAdded({}, { fromBlock: 0, toBlock: 'latest' }); event.get(function (error, events) { if (error) { onErrorCallback(error); return; } var markets = events.map(function (event) { return event.args; }); _bluebird2.default.all(markets.map(function (market) { var bytesId = market.bytesId, strId = market.strId; return _this2.feeds.isMarketActive.call(bytesId).then(function (active) { return { bytesId: bytesId, strId: strId, active: active }; }); })).then(onSuccessCallback); }); } /** * Get all the push events for all (or a specific) market(s) at an interval of blocks * @param fromBlock, The beginning of the block interval * @param toBlock, The end of the block interval * @param onSuccessCallback Callback that will receive a list like: * [ * {marketId: "0x123...", timestamp: BigNumber, value: BigNumber} * {marketId: "0x123...", timestamp: BigNumber, value: BigNumber} * ... * ] * @param onErrorCallback Callback that will receive any errors */ }, { key: 'getAllFeedsPushEvents', value: function () { var _ref6 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee4(fromBlock, toBlock, onSuccessCallback, onErrorCallback) { var decimals, event; return _regenerator2.default.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: _context4.next = 2; return this.feeds.decimals.call(); case 2: decimals = _context4.sent; event = this.feeds.LogFeedsPush({}, { fromBlock: fromBlock, toBlock: toBlock }); event.get(function (error, events) { if (error) { onErrorCallback(error); return; } _bluebird2.default.all(events.map(function (event) { event.args.value = (0, _utils.fromContractBigNumber)(event.args.value, decimals); return event.args; })).then(onSuccessCallback); }); case 5: case 'end': return _context4.stop(); } } }, _callee4, this); })); function getAllFeedsPushEvents(_x6, _x7, _x8, _x9) { return _ref6.apply(this, arguments); } return getAllFeedsPushEvents; }() /** * Convert market id in string format to bytes32 format * @param marketIdStr eg. Poloniex_ETH_USD * @return bytes32 sha3 of the marketIdStr */ }, { key: 'marketIdStrToBytes', value: function marketIdStrToBytes(marketIdStr) { return this.web3.sha3(marketIdStr); } /** * Convert market id in bytes32 format to string format by looking up the * Feeds.marketNames smart contract list. * @param marketId sha3 of the market id string * @return Market id string */ }, { key: 'marketIdBytesToStr', value: function marketIdBytesToStr(marketId) { return this.feeds.marketNames.call(marketId); } /** * Takes a raw event and extracts args field only. * Additionally any marketId in bytes32 format is converted back to a string. * @param event Raw JSON event from Ethereum client. * @return Object with the event arguments. */ }, { key: 'eventParse', value: function () { var _ref7 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee5(event) { var eventArgs; return _regenerator2.default.wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: eventArgs = event.args; if (!(0, _has2.default)(eventArgs, 'marketId')) { _context5.next = 5; break; } _context5.next = 4; return this.marketIdBytesToStr(eventArgs.marketId); case 4: eventArgs.marketId = _context5.sent; case 5: return _context5.abrupt('return', eventArgs); case 6: case 'end': return _context5.stop(); } } }, _callee5, this); })); function eventParse(_x10) { return _ref7.apply(this, arguments); } return eventParse; }() /** * NOTE: use API.newInstance to create a new instance rather then this * constructor. * * Construct an API instance setting config and web3. initialise() must be * called after this to setup the contract handler. newInstance() does both * these steps so is the preferred way to get an instance of this class. * * @param config Configuration object with all properties as per * config.json.template * @param web3 Initiated web3 instance for the network to work with. */ }], [{ key: 'newInstance', /** * Create a new instance of this class setting up contract handles and * validiting the config addresses point to actual deployed contracts. * * @param config Configuration object with all properties as per * config.json.template * @param web3 Initiated and connected web3 instance * * @return Constructed and initialised instance of this class */ value: function () { var _ref8 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee6(config, web3) { var api; return _regenerator2.default.wrap(function _callee6$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: if (!(web3.isConnected() !== true)) { _context6.next = 2; break; } return _context6.abrupt('return', _bluebird2.default.reject(new Error('web3 is not connected - check the endpoint'))); case 2: api = new API(config, web3); _context6.next = 5; return api.initialise(); case 5: return _context6.abrupt('return', api); case 6: case 'end': return _context6.stop(); } } }, _callee6, this); })); function newInstance(_x11, _x12) { return _ref8.apply(this, arguments); } return newInstance; }() }]); function API(config, web3) { (0, _classCallCheck3.default)(this, API); this.config = config; this.web3 = web3; this.web3.eth.getCodeAsync = _bluebird2.default.promisify(this.web3.eth.getCode); } /** * NOTE: use newInstance() to create new instances rather then call this * routine. * * Sets up contract handles and validiting the config addresses point to * actual deployed contracts. Seperate to the constructor as it needs to make * asynchronous calls. * * @return api instance */ (0, _createClass3.default)(API, [{ key: 'initialise', value: function () { var _ref9 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee7() { return _regenerator2.default.wrap(function _callee7$(_context7) { while (1) { switch (_context7.prev = _context7.next) { case 0: _context7.next = 2; return (0, _contracts.feedsInstanceDeployed)(this.config, this.web3); case 2: this.feeds = _context7.sent; return _context7.abrupt('return', this); case 4: case 'end': return _context7.stop(); } } }, _callee7, this); })); function initialise() { return _ref9.apply(this, arguments); } return initialise; }() }]); return API; }(); exports.default = API;