UNPKG

@colony/colony-js-contract-client

Version:

Method-like interface for Smart Contracts

434 lines (343 loc) 14.7 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _regenerator = require('babel-runtime/regenerator'); var _regenerator2 = _interopRequireDefault(_regenerator); var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties'); var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _bn = require('bn.js'); var _bn2 = _interopRequireDefault(_bn); var _colonyJsUtils = require('@colony/colony-js-utils'); var _ContractClient = require('./ContractClient'); var _ContractClient2 = _interopRequireDefault(_ContractClient); var _ContractMethod2 = require('./ContractMethod'); var _ContractMethod3 = _interopRequireDefault(_ContractMethod2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* eslint-disable import/no-cycle */ var ContractMethodSender = function (_ContractMethod) { (0, _inherits3.default)(ContractMethodSender, _ContractMethod); function ContractMethodSender(_ref) { var defaultGasLimit = _ref.defaultGasLimit, rest = (0, _objectWithoutProperties3.default)(_ref, ['defaultGasLimit']); (0, _classCallCheck3.default)(this, ContractMethodSender); var _this = (0, _possibleConstructorReturn3.default)(this, (ContractMethodSender.__proto__ || Object.getPrototypeOf(ContractMethodSender)).call(this, rest)); if (defaultGasLimit) _this._defaultGasLimit = defaultGasLimit; return _this; } /** * Given named input values, call the method's contract function * with `eth_call` in order to simulate the transaction. * * The result will be parsed for a `revert` reason, which will throw * an error with the parsed revert reason (if necessary). */ (0, _createClass3.default)(ContractMethodSender, [{ key: 'call', value: function () { var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(inputValues) { var _client$contract$inte, data, from; return _regenerator2.default.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: // Parse the transaction data for this function from the given values _client$contract$inte = this.client.contract.interface.functions[this.functionName].apply(this.client.contract.interface, this.getValidatedArgs(inputValues)), data = _client$contract$inte.data; _context.next = 3; return this.client.adapter.wallet.getAddress(); case 3: from = _context.sent; return _context.abrupt('return', this.client.callTransaction({ data: data, from: from, to: this.client.contract.address })); case 5: case 'end': return _context.stop(); } } }, _callee, this); })); function call(_x) { return _ref2.apply(this, arguments); } return call; }() /** * Given named input values, call the method's contract function in * order to get a gas estimate for calling it with those values. */ }, { key: 'estimate', value: function () { var _ref3 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(inputValues) { var args; return _regenerator2.default.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: args = this.getValidatedArgs(inputValues); // Simulate the transaction before estimation; will throw if erroneous _context2.next = 3; return this.call(inputValues); case 3: return _context2.abrupt('return', this.client.estimate(this.functionName, args)); case 4: case 'end': return _context2.stop(); } } }, _callee2, this); })); function estimate(_x2) { return _ref3.apply(this, arguments); } return estimate; }() /** * Given named input values and options for sending a transaction, create a * transaction which calls the method's contract function with those * values as transformed parameters, and collect the transaction receipt * and (optionally) event data. */ }, { key: 'send', value: function () { var _ref4 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee3(inputValues, options) { var args; return _regenerator2.default.wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: args = this.getValidatedArgs(inputValues); return _context3.abrupt('return', this._send(args, options)); case 2: case 'end': return _context3.stop(); } } }, _callee3, this); })); function send(_x3, _x4) { return _ref4.apply(this, arguments); } return send; }() }, { key: '_sendWithWaitingForMining', value: function () { var _ref5 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee4(transaction, timeoutMs) { var receipt, eventData, from, to, data, gasPrice, gasLimit, value; return _regenerator2.default.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: _context4.next = 2; return (0, _colonyJsUtils.raceAgainstTimeout)(this.client.adapter.getTransactionReceipt(transaction.hash), timeoutMs); case 2: receipt = _context4.sent; eventData = this.client.getReceiptEventData(receipt); // If the transaction failed, call it directly and add the revert // reason to the receipt. if (!(receipt && receipt.status === 0)) { _context4.next = 14; break; } _context4.prev = 5; from = transaction.from, to = transaction.to, data = transaction.data, gasPrice = transaction.gasPrice, gasLimit = transaction.gasLimit, value = transaction.value; _context4.next = 9; return this.client.callTransaction((0, _extends3.default)({ data: data, from: from, gasLimit: gasLimit, gasPrice: gasPrice, value: value }, to != null ? { to: to } : {})); case 9: _context4.next = 14; break; case 11: _context4.prev = 11; _context4.t0 = _context4['catch'](5); Object.assign(receipt, { reason: _context4.t0.reason }); case 14: return _context4.abrupt('return', { successful: receipt && receipt.status === 1, meta: { transaction: transaction, receipt: receipt }, eventData: eventData }); case 15: case 'end': return _context4.stop(); } } }, _callee4, this, [[5, 11]]); })); function _sendWithWaitingForMining(_x5, _x6) { return _ref5.apply(this, arguments); } return _sendWithWaitingForMining; }() }, { key: '_sendWithoutWaitingForMining', value: function _sendWithoutWaitingForMining(transaction, timeoutMs) { var _this2 = this; var receiptPromise = (0, _colonyJsUtils.raceAgainstTimeout)(this.client.adapter.getTransactionReceipt(transaction.hash), timeoutMs); // Wait for the receipt before determining whether it was successful var successfulPromise = new Promise(function () { var _ref6 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee5(resolve, reject) { var receipt; return _regenerator2.default.wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: _context5.prev = 0; _context5.next = 3; return receiptPromise; case 3: receipt = _context5.sent; resolve(receipt && receipt.status === 1); _context5.next = 10; break; case 7: _context5.prev = 7; _context5.t0 = _context5['catch'](0); reject(_context5.t0.toString()); case 10: case 'end': return _context5.stop(); } } }, _callee5, _this2, [[0, 7]]); })); return function (_x7, _x8) { return _ref6.apply(this, arguments); }; }()); // Wait for the receipt before attempting to decode event logs var eventDataPromise = new Promise(function () { var _ref7 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee6(resolve, reject) { var receipt; return _regenerator2.default.wrap(function _callee6$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: _context6.prev = 0; _context6.next = 3; return receiptPromise; case 3: receipt = _context6.sent; try { resolve(_this2.client.getReceiptEventData(receipt)); } catch (decodeError) { reject(decodeError.toString()); } _context6.next = 10; break; case 7: _context6.prev = 7; _context6.t0 = _context6['catch'](0); reject(_context6.t0.toString()); case 10: case 'end': return _context6.stop(); } } }, _callee6, _this2, [[0, 7]]); })); return function (_x9, _x10) { return _ref7.apply(this, arguments); }; }()); return { successfulPromise: successfulPromise, meta: { receiptPromise: receiptPromise, transaction: transaction }, eventDataPromise: eventDataPromise }; } }, { key: '_send', value: function () { var _ref8 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee7(callArgs, options) { var _getDefaultSendOption, timeoutMs, waitForMining, transactionOptions, transaction; return _regenerator2.default.wrap(function _callee7$(_context7) { while (1) { switch (_context7.prev = _context7.next) { case 0: _getDefaultSendOption = this._getDefaultSendOptions(options), timeoutMs = _getDefaultSendOption.timeoutMs, waitForMining = _getDefaultSendOption.waitForMining, transactionOptions = (0, _objectWithoutProperties3.default)(_getDefaultSendOption, ['timeoutMs', 'waitForMining']); _context7.next = 3; return this._sendTransaction(callArgs, transactionOptions); case 3: transaction = _context7.sent; return _context7.abrupt('return', waitForMining ? this._sendWithWaitingForMining(transaction, timeoutMs) : this._sendWithoutWaitingForMining(transaction, timeoutMs)); case 5: case 'end': return _context7.stop(); } } }, _callee7, this); })); function _send(_x11, _x12) { return _ref8.apply(this, arguments); } return _send; }() }, { key: '_sendTransaction', value: function () { var _ref9 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee8(callArgs, transactionOptions) { return _regenerator2.default.wrap(function _callee8$(_context8) { while (1) { switch (_context8.prev = _context8.next) { case 0: return _context8.abrupt('return', this.client.send(this.functionName, callArgs, transactionOptions)); case 1: case 'end': return _context8.stop(); } } }, _callee8, this); })); function _sendTransaction(_x13, _x14) { return _ref9.apply(this, arguments); } return _sendTransaction; }() /** * Given send options, set default values for this Sender. */ }, { key: '_getDefaultSendOptions', value: function _getDefaultSendOptions(options) { var networkName = this.client.adapter.provider.name; // Allow a much longer timeout for mainnet transactions. var minutes = networkName === 'mainnet' ? 60 : 5; return Object.assign({}, (0, _extends3.default)({ timeoutMs: 1000 * 60 * minutes, waitForMining: true }, this._defaultGasLimit ? { gasLimit: this._defaultGasLimit } : null), options); } }]); return ContractMethodSender; }(_ContractMethod3.default); exports.default = ContractMethodSender; //# sourceMappingURL=ContractMethodSender.js.map