@colony/colony-js-contract-client
Version:
Method-like interface for Smart Contracts
434 lines (343 loc) • 14.7 kB
JavaScript
'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