UNPKG

@0x/web3-wrapper

Version:
979 lines 47.8 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; 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 assert_1 = require("@0x/assert"); var json_schemas_1 = require("@0x/json-schemas"); var utils_1 = require("@0x/utils"); var ethereum_types_1 = require("ethereum-types"); var _ = require("lodash"); var marshaller_1 = require("./marshaller"); var types_1 = require("./types"); var utils_2 = require("./utils"); var BASE_TEN = 10; // These are unique identifiers contained in the response of the // web3_clientVersion call. var uniqueVersionIds = { geth: 'Geth', ganache: 'EthereumJS TestRPC', }; /** * An alternative to the Web3.js library that provides a consistent, clean, promise-based interface. */ var Web3Wrapper = /** @class */ (function () { /** * Instantiates a new Web3Wrapper. * @param provider The Web3 provider instance you would like the Web3Wrapper to use for interacting with * the backing Ethereum node. * @param txDefaults Override TxData defaults sent with RPC requests to the backing Ethereum node. * @return An instance of the Web3Wrapper class. */ function Web3Wrapper(provider, txDefaults) { /** * Flag to check if this instance is of type Web3Wrapper */ this.isZeroExWeb3Wrapper = true; assert_1.assert.isWeb3Provider('provider', provider); if (_.isUndefined(provider.sendAsync)) { // Web3@1.0 provider doesn't support synchronous http requests, // so it only has an async `send` method, instead of a `send` and `sendAsync` in web3@0.x.x` // We re-assign the send method so that Web3@1.0 providers work with @0x/web3-wrapper provider.sendAsync = provider.send; } this.abiDecoder = new utils_1.AbiDecoder([]); this._provider = provider; this._txDefaults = txDefaults || {}; this._jsonRpcRequestId = 1; } /** * Check if an address is a valid Ethereum address * @param address Address to check * @returns Whether the address is a valid Ethereum address */ Web3Wrapper.isAddress = function (address) { return utils_1.addressUtils.isAddress(address); }; /** * A unit amount is defined as the amount of a token above the specified decimal places (integer part). * E.g: If a currency has 18 decimal places, 1e18 or one quintillion of the currency is equivalent * to 1 unit. * @param amount The amount in baseUnits that you would like converted to units. * @param decimals The number of decimal places the unit amount has. * @return The amount in units. */ Web3Wrapper.toUnitAmount = function (amount, decimals) { assert_1.assert.isValidBaseUnitAmount('amount', amount); assert_1.assert.isNumber('decimals', decimals); var aUnit = new utils_1.BigNumber(BASE_TEN).pow(decimals); var unit = amount.div(aUnit); return unit; }; /** * A baseUnit is defined as the smallest denomination of a token. An amount expressed in baseUnits * is the amount expressed in the smallest denomination. * E.g: 1 unit of a token with 18 decimal places is expressed in baseUnits as 1000000000000000000 * @param amount The amount of units that you would like converted to baseUnits. * @param decimals The number of decimal places the unit amount has. * @return The amount in baseUnits. */ Web3Wrapper.toBaseUnitAmount = function (amount, decimals) { assert_1.assert.isBigNumber('amount', amount); assert_1.assert.isNumber('decimals', decimals); var unit = new utils_1.BigNumber(BASE_TEN).pow(decimals); var baseUnitAmount = amount.times(unit); var hasDecimals = baseUnitAmount.decimalPlaces() !== 0; if (hasDecimals) { throw new Error("Invalid unit amount: " + amount.toString() + " - Too many decimal places"); } return baseUnitAmount; }; /** * Convert an Ether amount from ETH to Wei * @param ethAmount Amount of Ether to convert to wei * @returns Amount in wei */ Web3Wrapper.toWei = function (ethAmount) { assert_1.assert.isBigNumber('ethAmount', ethAmount); var ETH_DECIMALS = 18; var balanceWei = Web3Wrapper.toBaseUnitAmount(ethAmount, ETH_DECIMALS); return balanceWei; }; Web3Wrapper._assertBlockParam = function (blockParam) { if (_.isNumber(blockParam)) { return; } else if (_.isString(blockParam)) { assert_1.assert.doesBelongToStringEnum('blockParam', blockParam, ethereum_types_1.BlockParamLiteral); } }; Web3Wrapper._assertBlockParamOrString = function (blockParam) { try { Web3Wrapper._assertBlockParam(blockParam); } catch (err) { try { assert_1.assert.isHexString('blockParam', blockParam); return; } catch (err) { throw new Error("Expected blockParam to be of type \"string | BlockParam\", encountered " + blockParam); } } }; Web3Wrapper._normalizeTxReceiptStatus = function (status) { // Transaction status might have four values // undefined - Testrpc and other old clients // null - New clients on old transactions // number - Parity // hex - Geth if (_.isString(status)) { return utils_2.utils.convertHexToNumber(status); } else if (_.isUndefined(status)) { return null; } else { return status; } }; /** * Get the contract defaults set to the Web3Wrapper instance * @return TxData defaults (e.g gas, gasPrice, nonce, etc...) */ Web3Wrapper.prototype.getContractDefaults = function () { return this._txDefaults; }; /** * Retrieve the Web3 provider * @return Web3 provider instance */ Web3Wrapper.prototype.getProvider = function () { return this._provider; }; /** * Update the used Web3 provider * @param provider The new Web3 provider to be set */ Web3Wrapper.prototype.setProvider = function (provider) { assert_1.assert.isWeb3Provider('provider', provider); this._provider = provider; }; /** * Check whether an address is available through the backing provider. This can be * useful if you want to know whether a user can sign messages or transactions from * a given Ethereum address. * @param senderAddress Address to check availability for * @returns Whether the address is available through the provider. */ Web3Wrapper.prototype.isSenderAddressAvailableAsync = function (senderAddress) { return __awaiter(this, void 0, void 0, function () { var addresses, normalizedAddress; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isETHAddressHex('senderAddress', senderAddress); return [4 /*yield*/, this.getAvailableAddressesAsync()]; case 1: addresses = _a.sent(); normalizedAddress = senderAddress.toLowerCase(); return [2 /*return*/, _.includes(addresses, normalizedAddress)]; } }); }); }; /** * Fetch the backing Ethereum node's version string (e.g `MetaMask/v4.2.0`) * @returns Ethereum node's version string */ Web3Wrapper.prototype.getNodeVersionAsync = function () { return __awaiter(this, void 0, void 0, function () { var nodeVersion; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'web3_clientVersion' })]; case 1: nodeVersion = _a.sent(); return [2 /*return*/, nodeVersion]; } }); }); }; /** * Fetches the networkId of the backing Ethereum node * @returns The network id */ Web3Wrapper.prototype.getNetworkIdAsync = function () { return __awaiter(this, void 0, void 0, function () { var networkIdStr, networkId; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'net_version' })]; case 1: networkIdStr = _a.sent(); networkId = _.parseInt(networkIdStr); return [2 /*return*/, networkId]; } }); }); }; /** * Retrieves the transaction receipt for a given transaction hash if found * @param txHash Transaction hash * @returns The transaction receipt, including it's status (0: failed, 1: succeeded). Returns undefined if transaction not found. */ Web3Wrapper.prototype.getTransactionReceiptIfExistsAsync = function (txHash) { return __awaiter(this, void 0, void 0, function () { var transactionReceiptRpc, transactionReceipt; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isHexString('txHash', txHash); return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'eth_getTransactionReceipt', params: [txHash], })]; case 1: transactionReceiptRpc = _a.sent(); // HACK Parity can return a pending transaction receipt. We check for a non null // block number before continuing with returning a fully realised receipt. // ref: https://github.com/paritytech/parity-ethereum/issues/1180 if (!_.isNull(transactionReceiptRpc) && !_.isNull(transactionReceiptRpc.blockNumber)) { transactionReceiptRpc.status = Web3Wrapper._normalizeTxReceiptStatus(transactionReceiptRpc.status); transactionReceipt = marshaller_1.marshaller.unmarshalTransactionReceipt(transactionReceiptRpc); return [2 /*return*/, transactionReceipt]; } else { return [2 /*return*/, undefined]; } return [2 /*return*/]; } }); }); }; /** * Retrieves the transaction data for a given transaction * @param txHash Transaction hash * @returns The raw transaction data */ Web3Wrapper.prototype.getTransactionByHashAsync = function (txHash) { return __awaiter(this, void 0, void 0, function () { var transactionRpc, transaction; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isHexString('txHash', txHash); return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'eth_getTransactionByHash', params: [txHash], })]; case 1: transactionRpc = _a.sent(); transaction = marshaller_1.marshaller.unmarshalTransaction(transactionRpc); return [2 /*return*/, transaction]; } }); }); }; /** * Retrieves an accounts Ether balance in wei * @param owner Account whose balance you wish to check * @param defaultBlock The block depth at which to fetch the balance (default=latest) * @returns Balance in wei */ Web3Wrapper.prototype.getBalanceInWeiAsync = function (owner, defaultBlock) { return __awaiter(this, void 0, void 0, function () { var marshalledDefaultBlock, encodedOwner, balanceInWei; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isETHAddressHex('owner', owner); if (!_.isUndefined(defaultBlock)) { Web3Wrapper._assertBlockParam(defaultBlock); } marshalledDefaultBlock = marshaller_1.marshaller.marshalBlockParam(defaultBlock); encodedOwner = marshaller_1.marshaller.marshalAddress(owner); return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'eth_getBalance', params: [encodedOwner, marshalledDefaultBlock], })]; case 1: balanceInWei = _a.sent(); // Rewrap in a new BigNumber return [2 /*return*/, new utils_1.BigNumber(balanceInWei)]; } }); }); }; /** * Check if a contract exists at a given address * @param address Address to which to check * @returns Whether or not contract code was found at the supplied address */ Web3Wrapper.prototype.doesContractExistAtAddressAsync = function (address) { return __awaiter(this, void 0, void 0, function () { var code, isCodeEmpty; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isETHAddressHex('address', address); return [4 /*yield*/, this.getContractCodeAsync(address)]; case 1: code = _a.sent(); isCodeEmpty = /^0x0{0,40}$/i.test(code); return [2 /*return*/, !isCodeEmpty]; } }); }); }; /** * Gets the contract code by address * @param address Address of the contract * @param defaultBlock Block height at which to make the call. Defaults to `latest` * @return Code of the contract */ Web3Wrapper.prototype.getContractCodeAsync = function (address, defaultBlock) { return __awaiter(this, void 0, void 0, function () { var marshalledDefaultBlock, encodedAddress, code; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isETHAddressHex('address', address); if (!_.isUndefined(defaultBlock)) { Web3Wrapper._assertBlockParam(defaultBlock); } marshalledDefaultBlock = marshaller_1.marshaller.marshalBlockParam(defaultBlock); encodedAddress = marshaller_1.marshaller.marshalAddress(address); return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'eth_getCode', params: [encodedAddress, marshalledDefaultBlock], })]; case 1: code = _a.sent(); return [2 /*return*/, code]; } }); }); }; /** * Gets the debug trace of a transaction * @param txHash Hash of the transactuon to get a trace for * @param traceParams Config object allowing you to specify if you need memory/storage/stack traces. * @return Transaction trace */ Web3Wrapper.prototype.getTransactionTraceAsync = function (txHash, traceParams) { return __awaiter(this, void 0, void 0, function () { var trace; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isHexString('txHash', txHash); return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'debug_traceTransaction', params: [txHash, traceParams], })]; case 1: trace = _a.sent(); return [2 /*return*/, trace]; } }); }); }; /** * Sign a message with a specific address's private key (`eth_sign`) * @param address Address of signer * @param message Message to sign * @returns Signature string (might be VRS or RSV depending on the Signer) */ Web3Wrapper.prototype.signMessageAsync = function (address, message) { return __awaiter(this, void 0, void 0, function () { var signData; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isETHAddressHex('address', address); assert_1.assert.isString('message', message); // TODO: Should this be stricter? Hex string? return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'eth_sign', params: [address, message], })]; case 1: signData = _a.sent(); return [2 /*return*/, signData]; } }); }); }; /** * Sign an EIP712 typed data message with a specific address's private key (`eth_signTypedData`) * @param address Address of signer * @param typedData Typed data message to sign * @returns Signature string (as RSV) */ Web3Wrapper.prototype.signTypedDataAsync = function (address, typedData) { return __awaiter(this, void 0, void 0, function () { var signData; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isETHAddressHex('address', address); assert_1.assert.doesConformToSchema('typedData', typedData, json_schemas_1.schemas.eip712TypedDataSchema); return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'eth_signTypedData', params: [address, typedData], })]; case 1: signData = _a.sent(); return [2 /*return*/, signData]; } }); }); }; /** * Fetches the latest block number * @returns Block number */ Web3Wrapper.prototype.getBlockNumberAsync = function () { return __awaiter(this, void 0, void 0, function () { var blockNumberHex, blockNumber; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'eth_blockNumber', params: [], })]; case 1: blockNumberHex = _a.sent(); blockNumber = utils_2.utils.convertHexToNumberOrNull(blockNumberHex); return [2 /*return*/, blockNumber]; } }); }); }; /** * Fetch a specific Ethereum block without transaction data * @param blockParam The block you wish to fetch (blockHash, blockNumber or blockLiteral) * @returns The requested block without transaction data, or undefined if block was not found * (e.g the node isn't fully synced, there was a block re-org and the requested block was uncles, etc...) */ Web3Wrapper.prototype.getBlockIfExistsAsync = function (blockParam) { return __awaiter(this, void 0, void 0, function () { var encodedBlockParam, method, shouldIncludeTransactionData, blockWithoutTransactionDataWithHexValuesOrNull, blockWithoutTransactionDataIfExists; return __generator(this, function (_a) { switch (_a.label) { case 0: Web3Wrapper._assertBlockParamOrString(blockParam); encodedBlockParam = marshaller_1.marshaller.marshalBlockParam(blockParam); method = utils_2.utils.isHexStrict(blockParam) ? 'eth_getBlockByHash' : 'eth_getBlockByNumber'; shouldIncludeTransactionData = false; return [4 /*yield*/, this.sendRawPayloadAsync({ method: method, params: [encodedBlockParam, shouldIncludeTransactionData], })]; case 1: blockWithoutTransactionDataWithHexValuesOrNull = _a.sent(); if (!_.isNull(blockWithoutTransactionDataWithHexValuesOrNull)) { blockWithoutTransactionDataIfExists = marshaller_1.marshaller.unmarshalIntoBlockWithoutTransactionData(blockWithoutTransactionDataWithHexValuesOrNull); } return [2 /*return*/, blockWithoutTransactionDataIfExists]; } }); }); }; /** * Fetch a specific Ethereum block with transaction data * @param blockParam The block you wish to fetch (blockHash, blockNumber or blockLiteral) * @returns The requested block with transaction data */ Web3Wrapper.prototype.getBlockWithTransactionDataAsync = function (blockParam) { return __awaiter(this, void 0, void 0, function () { var encodedBlockParam, method, shouldIncludeTransactionData, blockWithTransactionDataWithHexValues, blockWithoutTransactionData; return __generator(this, function (_a) { switch (_a.label) { case 0: Web3Wrapper._assertBlockParamOrString(blockParam); encodedBlockParam = blockParam; if (_.isNumber(blockParam)) { encodedBlockParam = utils_2.utils.numberToHex(blockParam); } method = utils_2.utils.isHexStrict(blockParam) ? 'eth_getBlockByHash' : 'eth_getBlockByNumber'; shouldIncludeTransactionData = true; return [4 /*yield*/, this.sendRawPayloadAsync({ method: method, params: [encodedBlockParam, shouldIncludeTransactionData], })]; case 1: blockWithTransactionDataWithHexValues = _a.sent(); blockWithoutTransactionData = marshaller_1.marshaller.unmarshalIntoBlockWithTransactionData(blockWithTransactionDataWithHexValues); return [2 /*return*/, blockWithoutTransactionData]; } }); }); }; /** * Fetch a block's timestamp * @param blockParam The block you wish to fetch (blockHash, blockNumber or blockLiteral) * @returns The block's timestamp */ Web3Wrapper.prototype.getBlockTimestampAsync = function (blockParam) { return __awaiter(this, void 0, void 0, function () { var blockIfExists; return __generator(this, function (_a) { switch (_a.label) { case 0: Web3Wrapper._assertBlockParamOrString(blockParam); return [4 /*yield*/, this.getBlockIfExistsAsync(blockParam)]; case 1: blockIfExists = _a.sent(); if (_.isUndefined(blockIfExists)) { throw new Error("Failed to fetch block with blockParam: " + JSON.stringify(blockParam)); } return [2 /*return*/, blockIfExists.timestamp]; } }); }); }; /** * Retrieve the user addresses available through the backing provider * @returns Available user addresses */ Web3Wrapper.prototype.getAvailableAddressesAsync = function () { return __awaiter(this, void 0, void 0, function () { var addresses, normalizedAddresses; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'eth_accounts', params: [], })]; case 1: addresses = _a.sent(); normalizedAddresses = _.map(addresses, function (address) { return address.toLowerCase(); }); return [2 /*return*/, normalizedAddresses]; } }); }); }; /** * Take a snapshot of the blockchain state on a TestRPC/Ganache local node * @returns The snapshot id. This can be used to revert to this snapshot */ Web3Wrapper.prototype.takeSnapshotAsync = function () { return __awaiter(this, void 0, void 0, function () { var snapshotId, _a; return __generator(this, function (_b) { switch (_b.label) { case 0: _a = Number; return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'evm_snapshot', params: [] })]; case 1: snapshotId = _a.apply(void 0, [_b.sent()]); return [2 /*return*/, snapshotId]; } }); }); }; /** * Revert the blockchain state to a previous snapshot state on TestRPC/Ganache local node * @param snapshotId snapshot id to revert to * @returns Whether the revert was successful */ Web3Wrapper.prototype.revertSnapshotAsync = function (snapshotId) { return __awaiter(this, void 0, void 0, function () { var didRevert; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isNumber('snapshotId', snapshotId); return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'evm_revert', params: [snapshotId] })]; case 1: didRevert = _a.sent(); return [2 /*return*/, didRevert]; } }); }); }; /** * Mine a block on a TestRPC/Ganache local node */ Web3Wrapper.prototype.mineBlockAsync = function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'evm_mine', params: [] })]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Increase the next blocks timestamp on TestRPC/Ganache or Geth local node. * Will throw if provider is neither TestRPC/Ganache or Geth. * @param timeDelta Amount of time to add in seconds */ Web3Wrapper.prototype.increaseTimeAsync = function (timeDelta) { return __awaiter(this, void 0, void 0, function () { var version; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isNumber('timeDelta', timeDelta); return [4 /*yield*/, this.getNodeVersionAsync()]; case 1: version = _a.sent(); if (_.includes(version, uniqueVersionIds.geth)) { return [2 /*return*/, this.sendRawPayloadAsync({ method: 'debug_increaseTime', params: [timeDelta] })]; } else if (_.includes(version, uniqueVersionIds.ganache)) { return [2 /*return*/, this.sendRawPayloadAsync({ method: 'evm_increaseTime', params: [timeDelta] })]; } else { throw new Error("Unknown client version: " + version); } return [2 /*return*/]; } }); }); }; /** * Retrieve smart contract logs for a given filter * @param filter Parameters by which to filter which logs to retrieve * @returns The corresponding log entries */ Web3Wrapper.prototype.getLogsAsync = function (filter) { return __awaiter(this, void 0, void 0, function () { var fromBlock, toBlock, serializedFilter, payload, rawLogs, formattedLogs; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!_.isUndefined(filter.blockHash) && (!_.isUndefined(filter.fromBlock) || !_.isUndefined(filter.toBlock))) { throw new Error("Cannot specify 'blockHash' as well as 'fromBlock'/'toBlock' in the filter supplied to 'getLogsAsync'"); } fromBlock = filter.fromBlock; if (_.isNumber(fromBlock)) { fromBlock = utils_2.utils.numberToHex(fromBlock); } toBlock = filter.toBlock; if (_.isNumber(toBlock)) { toBlock = utils_2.utils.numberToHex(toBlock); } serializedFilter = __assign({}, filter, { fromBlock: fromBlock, toBlock: toBlock }); payload = { method: 'eth_getLogs', params: [serializedFilter], }; return [4 /*yield*/, this.sendRawPayloadAsync(payload)]; case 1: rawLogs = _a.sent(); formattedLogs = _.map(rawLogs, marshaller_1.marshaller.unmarshalLog.bind(marshaller_1.marshaller)); return [2 /*return*/, formattedLogs]; } }); }); }; /** * Calculate the estimated gas cost for a given transaction * @param txData Transaction data * @returns Estimated gas cost */ Web3Wrapper.prototype.estimateGasAsync = function (txData) { return __awaiter(this, void 0, void 0, function () { var txDataHex, gasHex, gas; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.doesConformToSchema('txData', txData, json_schemas_1.schemas.txDataSchema, [ json_schemas_1.schemas.addressSchema, json_schemas_1.schemas.numberSchema, json_schemas_1.schemas.jsNumber, ]); txDataHex = marshaller_1.marshaller.marshalTxData(txData); return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'eth_estimateGas', params: [txDataHex] })]; case 1: gasHex = _a.sent(); gas = utils_2.utils.convertHexToNumber(gasHex); return [2 /*return*/, gas]; } }); }); }; /** * Call a smart contract method at a given block height * @param callData Call data * @param defaultBlock Block height at which to make the call. Defaults to `latest` * @returns The raw call result */ Web3Wrapper.prototype.callAsync = function (callData, defaultBlock) { return __awaiter(this, void 0, void 0, function () { var marshalledDefaultBlock, callDataHex, rawCallResult; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.doesConformToSchema('callData', callData, json_schemas_1.schemas.callDataSchema, [ json_schemas_1.schemas.addressSchema, json_schemas_1.schemas.numberSchema, json_schemas_1.schemas.jsNumber, ]); if (!_.isUndefined(defaultBlock)) { Web3Wrapper._assertBlockParam(defaultBlock); } marshalledDefaultBlock = marshaller_1.marshaller.marshalBlockParam(defaultBlock); callDataHex = marshaller_1.marshaller.marshalCallData(callData); return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'eth_call', params: [callDataHex, marshalledDefaultBlock], })]; case 1: rawCallResult = _a.sent(); return [2 /*return*/, rawCallResult]; } }); }); }; /** * Send a transaction * @param txData Transaction data * @returns Transaction hash */ Web3Wrapper.prototype.sendTransactionAsync = function (txData) { return __awaiter(this, void 0, void 0, function () { var txDataHex, txHash; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.doesConformToSchema('txData', txData, json_schemas_1.schemas.txDataSchema, [ json_schemas_1.schemas.addressSchema, json_schemas_1.schemas.numberSchema, json_schemas_1.schemas.jsNumber, ]); txDataHex = marshaller_1.marshaller.marshalTxData(txData); return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'eth_sendTransaction', params: [txDataHex] })]; case 1: txHash = _a.sent(); return [2 /*return*/, txHash]; } }); }); }; /** * Waits for a transaction to be mined and returns the transaction receipt. * Note that just because a transaction was mined does not mean it was * successful. You need to check the status code of the transaction receipt * to find out if it was successful, or use the helper method * awaitTransactionSuccessAsync. * @param txHash Transaction hash * @param pollingIntervalMs How often (in ms) should we check if the transaction is mined. * @param timeoutMs How long (in ms) to poll for transaction mined until aborting. * @return Transaction receipt with decoded log args. */ Web3Wrapper.prototype.awaitTransactionMinedAsync = function (txHash, pollingIntervalMs, timeoutMs) { if (pollingIntervalMs === void 0) { pollingIntervalMs = 1000; } return __awaiter(this, void 0, void 0, function () { var transactionReceipt, logsWithDecodedArgs, transactionReceiptWithDecodedLogArgs, wasTimeoutExceeded, txReceiptPromise, txReceipt; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isHexString('txHash', txHash); assert_1.assert.isNumber('pollingIntervalMs', pollingIntervalMs); if (!_.isUndefined(timeoutMs)) { assert_1.assert.isNumber('timeoutMs', timeoutMs); } return [4 /*yield*/, this.getTransactionReceiptIfExistsAsync(txHash)]; case 1: transactionReceipt = _a.sent(); if (!_.isUndefined(transactionReceipt)) { logsWithDecodedArgs = _.map(transactionReceipt.logs, this.abiDecoder.tryToDecodeLogOrNoop.bind(this.abiDecoder)); transactionReceiptWithDecodedLogArgs = __assign({}, transactionReceipt, { logs: logsWithDecodedArgs }); return [2 /*return*/, transactionReceiptWithDecodedLogArgs]; } wasTimeoutExceeded = false; if (timeoutMs) { setTimeout(function () { return (wasTimeoutExceeded = true); }, timeoutMs); } txReceiptPromise = new Promise(function (resolve, reject) { var intervalId = utils_1.intervalUtils.setAsyncExcludingInterval(function () { return __awaiter(_this, void 0, void 0, function () { var logsWithDecodedArgs, transactionReceiptWithDecodedLogArgs; return __generator(this, function (_a) { switch (_a.label) { case 0: if (wasTimeoutExceeded) { utils_1.intervalUtils.clearAsyncExcludingInterval(intervalId); return [2 /*return*/, reject(types_1.Web3WrapperErrors.TransactionMiningTimeout)]; } return [4 /*yield*/, this.getTransactionReceiptIfExistsAsync(txHash)]; case 1: transactionReceipt = _a.sent(); if (!_.isUndefined(transactionReceipt)) { utils_1.intervalUtils.clearAsyncExcludingInterval(intervalId); logsWithDecodedArgs = _.map(transactionReceipt.logs, this.abiDecoder.tryToDecodeLogOrNoop.bind(this.abiDecoder)); transactionReceiptWithDecodedLogArgs = __assign({}, transactionReceipt, { logs: logsWithDecodedArgs }); resolve(transactionReceiptWithDecodedLogArgs); } return [2 /*return*/]; } }); }); }, pollingIntervalMs, function (err) { utils_1.intervalUtils.clearAsyncExcludingInterval(intervalId); reject(err); }); }); return [4 /*yield*/, txReceiptPromise]; case 2: txReceipt = _a.sent(); return [2 /*return*/, txReceipt]; } }); }); }; /** * Waits for a transaction to be mined and returns the transaction receipt. * Unlike awaitTransactionMinedAsync, it will throw if the receipt has a * status that is not equal to 1. A status of 0 or null indicates that the * transaction was mined, but failed. See: * https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethgettransactionreceipt * @param txHash Transaction hash * @param pollingIntervalMs How often (in ms) should we check if the transaction is mined. * @param timeoutMs How long (in ms) to poll for transaction mined until aborting. * @return Transaction receipt with decoded log args. */ Web3Wrapper.prototype.awaitTransactionSuccessAsync = function (txHash, pollingIntervalMs, timeoutMs) { if (pollingIntervalMs === void 0) { pollingIntervalMs = 1000; } return __awaiter(this, void 0, void 0, function () { var receipt; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.awaitTransactionMinedAsync(txHash, pollingIntervalMs, timeoutMs)]; case 1: receipt = _a.sent(); if (receipt.status !== 1) { throw new Error("Transaction failed: " + txHash); } return [2 /*return*/, receipt]; } }); }); }; /** * Calls the 'debug_setHead' JSON RPC method, which sets the current head of * the local chain by block number. Note, this is a destructive action and * may severely damage your chain. Use with extreme caution. As of now, this * is only supported by Geth. It sill throw if the 'debug_setHead' method is * not supported. * @param blockNumber The block number to reset to. */ Web3Wrapper.prototype.setHeadAsync = function (blockNumber) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: assert_1.assert.isNumber('blockNumber', blockNumber); return [4 /*yield*/, this.sendRawPayloadAsync({ method: 'debug_setHead', params: [utils_2.utils.numberToHex(blockNumber)] })]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Sends a raw Ethereum JSON RPC payload and returns the response's `result` key * @param payload A partial JSON RPC payload. No need to include version, id, params (if none needed) * @return The contents nested under the result key of the response body */ Web3Wrapper.prototype.sendRawPayloadAsync = function (payload) { return __awaiter(this, void 0, void 0, function () { var sendAsync, payloadWithDefaults, response, result; return __generator(this, function (_a) { switch (_a.label) { case 0: sendAsync = this._provider.sendAsync.bind(this._provider); payloadWithDefaults = __assign({ id: this._jsonRpcRequestId++, params: [], jsonrpc: '2.0' }, payload); return [4 /*yield*/, utils_1.promisify(sendAsync)(payloadWithDefaults)]; case 1: response = _a.sent(); if (response.error) { throw new Error(response.error.message); } result = response.result; return [2 /*return*/, result]; } }); }); }; /** * Returns either NodeType.Geth or NodeType.Ganache depending on the type of * the backing Ethereum node. Throws for any other type of node. */ Web3Wrapper.prototype.getNodeTypeAsync = function () { return __awaiter(this, void 0, void 0, function () { var version; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getNodeVersionAsync()]; case 1: version = _a.sent(); if (_.includes(version, uniqueVersionIds.geth)) { return [2 /*return*/, types_1.NodeType.Geth]; } else if (_.includes(version, uniqueVersionIds.ganache)) { return [2 /*return*/, types_1.NodeType.Ganache]; } else { throw new Error("Unknown client version: " + version); } return [2 /*return*/]; } }); }); }; return Web3Wrapper; }()); // tslint:disable-line:max-file-line-count exports.Web3Wrapper = Web3Wrapper; //# sourceMappingURL=web3_wrapper.js.map