@backt/protocol
Version:
Backt smart contracts implementation
472 lines (387 loc) • 14.8 kB
JavaScript
'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;