@0x/web3-wrapper
Version:
Wraps around web3 and gives a nicer interface
979 lines • 47.8 kB
JavaScript
"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