@hethers/providers
Version:
Hedera Hashgraph Providers for hethers.
1,075 lines (1,074 loc) • 57.2 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
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) : adopt(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 };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseProvider = exports.Event = void 0;
var abstract_provider_1 = require("@hethers/abstract-provider");
var bignumber_1 = require("@ethersproject/bignumber");
var bytes_1 = require("@ethersproject/bytes");
var networks_1 = require("@hethers/networks");
var properties_1 = require("@ethersproject/properties");
var sdk_1 = require("@hashgraph/sdk");
var logger_1 = require("@hethers/logger");
var _version_1 = require("./_version");
var logger = new logger_1.Logger(_version_1.version);
var formatter_1 = require("./formatter");
var address_1 = require("@hethers/address");
var sdk_2 = require("@hashgraph/sdk");
var axios_1 = __importDefault(require("axios"));
var base64 = __importStar(require("@ethersproject/base64"));
var ZERO_HEDERA_TIMESTAMP = "1000000000.000000000";
//////////////////////////////
// Event Serializeing
// @ts-ignore
function checkTopic(topic) {
if (topic == null) {
return "null";
}
if ((0, bytes_1.hexDataLength)(topic) !== 32) {
logger.throwArgumentError("invalid topic", "topic", topic);
}
return topic.toLowerCase();
}
// @ts-ignore
function serializeTopics(topics) {
// Remove trailing null AND-topics; they are redundant
topics = topics.slice();
while (topics.length > 0 && topics[topics.length - 1] == null) {
topics.pop();
}
return topics.map(function (topic) {
if (Array.isArray(topic)) {
// Only track unique OR-topics
var unique_1 = {};
topic.forEach(function (topic) {
unique_1[checkTopic(topic)] = true;
});
// The order of OR-topics does not matter
var sorted = Object.keys(unique_1);
sorted.sort();
return sorted.join("|");
}
else {
return checkTopic(topic);
}
}).join("&");
}
function deserializeTopics(data) {
if (data === "") {
return [];
}
return data.split(/&/g).map(function (topic) {
if (topic === "") {
return [];
}
var comps = topic.split("|").map(function (topic) {
return ((topic === "null") ? null : topic);
});
return ((comps.length === 1) ? comps[0] : comps);
});
}
//////////////////////////////
// Helper Object
function stall(duration) {
return new Promise(function (resolve) {
setTimeout(resolve, duration);
});
}
function base64ToHex(hash) {
return (0, bytes_1.hexlify)(base64.decode(hash));
}
//////////////////////////////
// Provider Object
/**
* EventType
* - "poll"
* - "didPoll"
* - "pending"
* - "error"
* - "network"
* - filter
* - topics array
* - transaction hash
*/
var PollableEvents = ["network", "pending", "poll"];
var Event = /** @class */ (function () {
function Event(tag, listener, once) {
(0, properties_1.defineReadOnly)(this, "tag", tag);
(0, properties_1.defineReadOnly)(this, "listener", listener);
(0, properties_1.defineReadOnly)(this, "once", once);
}
Object.defineProperty(Event.prototype, "event", {
get: function () {
switch (this.type) {
case "tx":
return this.hash;
case "filter":
return this.filter;
}
return this.tag;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Event.prototype, "type", {
get: function () {
return this.tag.split(":")[0];
},
enumerable: false,
configurable: true
});
Object.defineProperty(Event.prototype, "hash", {
get: function () {
var comps = this.tag.split(":");
if (comps[0] !== "tx") {
return null;
}
return comps[1];
},
enumerable: false,
configurable: true
});
Object.defineProperty(Event.prototype, "filter", {
get: function () {
var comps = this.tag.split(":");
if (comps[0] !== "filter") {
return null;
}
var address = comps[1];
var topics = deserializeTopics(comps[2]);
var filter = {};
if (topics.length > 0) {
filter.topics = topics;
}
if (address && address !== "*") {
filter.address = address;
}
return filter;
},
enumerable: false,
configurable: true
});
Event.prototype.pollable = function () {
return (this.tag.indexOf(":") >= 0 || PollableEvents.indexOf(this.tag) >= 0);
};
return Event;
}());
exports.Event = Event;
var DEFAULT_RETRY_OPTIONS = {
maxAttempts: 3,
waitTime: 2,
errorCodes: [400, 408, 429, 500, 502, 503, 504, 511]
};
var defaultFormatter = null;
var MIRROR_NODE_TRANSACTIONS_ENDPOINT = '/api/v1/transactions/';
var MIRROR_NODE_CONTRACTS_RESULTS_ENDPOINT = '/api/v1/contracts/results/';
var MIRROR_NODE_CONTRACTS_ENDPOINT = '/api/v1/contracts/';
var MIRROR_NODE_ACCOUNTS_ENDPOINT = '/api/v1/accounts/';
var nextPollId = 1;
function formatTimestamp(s) {
var _a = s.split("."), sec = _a[0], nano = _a[1];
return sec.padEnd(10, "0") + "." + nano.padEnd(9, "0");
}
var BaseProvider = /** @class */ (function (_super) {
__extends(BaseProvider, _super);
function BaseProvider(network, options) {
var _newTarget = this.constructor;
var _this = this;
logger.checkNew(_newTarget, abstract_provider_1.Provider);
_this = _super.call(this) || this;
_this._events = [];
_this._emittedEvents = {};
_this._options = _this._getOptions(options);
_this._previousPollingTimestamps = {};
_this.formatter = _newTarget.getFormatter();
// If network is any, this Provider allows the underlying
// network to change dynamically, and we auto-detect the
// current network
(0, properties_1.defineReadOnly)(_this, "anyNetwork", (network === "any"));
if (_this.anyNetwork) {
network = _this.detectNetwork();
}
if (network instanceof Promise) {
_this._networkPromise = network;
// Squash any "unhandled promise" errors; that do not need to be handled
network.catch(function (error) {
});
// Trigger initial network setting (async)
_this._ready().catch(function (error) {
});
}
else {
if (!isHederaNetworkConfigLike(network)) {
var asDefaultNetwork = network;
// defineReadOnly(this, "_network", getNetwork(network));
_this._network = (0, networks_1.getNetwork)(asDefaultNetwork);
_this._networkPromise = Promise.resolve(_this._network);
var knownNetwork = (0, properties_1.getStatic)(_newTarget, "getNetwork")(asDefaultNetwork);
if (knownNetwork) {
(0, properties_1.defineReadOnly)(_this, "_network", knownNetwork);
_this.emit("network", knownNetwork);
}
else {
logger.throwArgumentError("invalid network", "network", network);
}
var hederaNetwork = mapNetworkToHederaNetworkName(asDefaultNetwork);
_this.hederaClient = typeof hederaNetwork === 'string' ? sdk_2.Client.forName(hederaNetwork) : sdk_2.Client.forNetwork(hederaNetwork);
_this._mirrorNodeUrl = resolveMirrorNetworkUrl(_this._network);
}
else {
var asHederaNetwork = network;
_this.hederaClient = sdk_2.Client.forNetwork(asHederaNetwork.network);
_this._mirrorNodeUrl = asHederaNetwork.mirrorNodeUrl;
(0, properties_1.defineReadOnly)(_this, "_network", {
// FIXME: chainId
chainId: 0,
name: _this.hederaClient.networkName
});
}
}
_this._pollingInterval = 3000;
_this._configureAxiosInterceptor(_this._options);
return _this;
}
BaseProvider.prototype._getOptions = function (options) {
var tmpOptions = (typeof options === 'object' && Object.keys(options).length)
? options
: { headers: {}, retry: DEFAULT_RETRY_OPTIONS };
tmpOptions.retry = (typeof options === 'object' && Object.keys(options).length === 3)
? tmpOptions.retry
: DEFAULT_RETRY_OPTIONS;
return tmpOptions;
};
BaseProvider.prototype._configureAxiosInterceptor = function (options) {
var _this = this;
axios_1.default.interceptors.request.use(function (config) {
if (!config._retriedRequest) {
config._retry = true;
config._attempts = 0;
config._waitTime = options.retry.waitTime;
}
return config;
}, function (error) {
return Promise.reject(error);
});
axios_1.default.interceptors.response.use(function (response) {
return response;
}, function (error) {
var config = error.config;
var originalRequest = config;
if (error.response) {
if (_this._options.retry.errorCodes.includes(error.response.status) && originalRequest._retry) {
originalRequest._retriedRequest = true;
originalRequest._attempts += 1;
originalRequest._waitTime = originalRequest._waitTime * originalRequest._attempts;
if (originalRequest._attempts >= _this._options.retry.maxAttempts) {
originalRequest._retry = false;
}
return _this._retryRequest(originalRequest._waitTime, originalRequest);
}
}
return Promise.reject(error);
});
};
BaseProvider.prototype._retryRequest = function (seconds, originalRequest) {
return new Promise(function (resolve, reject) {
setTimeout(function () { return resolve((0, axios_1.default)(originalRequest)); }, seconds * 1000);
});
};
;
BaseProvider.prototype._makeRequest = function (uri) {
return axios_1.default.get(this._mirrorNodeUrl + uri, { headers: this._options.headers });
};
BaseProvider.prototype._ready = function () {
return __awaiter(this, void 0, void 0, function () {
var network, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(this._network == null)) return [3 /*break*/, 7];
network = null;
if (!this._networkPromise) return [3 /*break*/, 4];
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, this._networkPromise];
case 2:
network = _a.sent();
return [3 /*break*/, 4];
case 3:
error_1 = _a.sent();
return [3 /*break*/, 4];
case 4:
if (!(network == null)) return [3 /*break*/, 6];
return [4 /*yield*/, this.detectNetwork()];
case 5:
network = _a.sent();
_a.label = 6;
case 6:
// Possible this call stacked so do not call defineReadOnly again
if (this._network == null) {
if (this.anyNetwork) {
// this._network = network;
(0, properties_1.defineReadOnly)(this, "_network", network);
}
else {
this._network = network;
}
this.emit("network", network, null);
}
_a.label = 7;
case 7: return [2 /*return*/, this._network];
}
});
});
};
// @TODO: Remove this and just create a singleton formatter
BaseProvider.getFormatter = function () {
if (defaultFormatter == null) {
defaultFormatter = new formatter_1.Formatter();
}
return defaultFormatter;
};
// @TODO: Remove this and just use getNetwork
BaseProvider.getNetwork = function (network) {
return (0, networks_1.getNetwork)((network == null) ? "mainnet" : network);
};
Object.defineProperty(BaseProvider.prototype, "network", {
get: function () {
return this._network;
},
enumerable: false,
configurable: true
});
BaseProvider.prototype._checkMirrorNode = function () {
if (!this._mirrorNodeUrl)
logger.throwError("missing provider", logger_1.Logger.errors.UNSUPPORTED_OPERATION);
};
// This method should query the network if the underlying network
// can change, such as when connected to a JSON-RPC backend
// With the current hedera implementation, we do not support changeable networks,
// thus we do not need to query at this level
BaseProvider.prototype.detectNetwork = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
this._networkPromise = Promise.resolve(this._network);
return [2 /*return*/, this._networkPromise];
});
});
};
BaseProvider.prototype.getNetwork = function () {
return __awaiter(this, void 0, void 0, function () {
var network, currentNetwork, error;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._ready()];
case 1:
network = _a.sent();
return [4 /*yield*/, this.detectNetwork()];
case 2:
currentNetwork = _a.sent();
if (!(network.chainId !== currentNetwork.chainId)) return [3 /*break*/, 5];
if (!this.anyNetwork) return [3 /*break*/, 4];
this._network = currentNetwork;
// The "network" event MUST happen before this method resolves
// so any events have a chance to unregister, so we stall an
// additional event loop before returning from /this/ call
this.emit("network", currentNetwork, network);
return [4 /*yield*/, stall(0)];
case 3:
_a.sent();
return [2 /*return*/, this._network];
case 4:
error = logger.makeError("underlying network changed", logger_1.Logger.errors.NETWORK_ERROR, {
event: "changed",
network: network,
detectedNetwork: currentNetwork
});
this.emit("error", error);
throw error;
case 5: return [2 /*return*/, network];
}
});
});
};
Object.defineProperty(BaseProvider.prototype, "pollingInterval", {
get: function () {
return this._pollingInterval;
},
set: function (value) {
if (typeof (value) !== "number" || value <= 0 || parseInt(String(value)) != value) {
throw new Error("invalid polling interval");
}
this._pollingInterval = value;
},
enumerable: false,
configurable: true
});
BaseProvider.prototype.waitForTransaction = function (transactionIdOrTimestamp, timeout) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this._waitForTransaction(transactionIdOrTimestamp, timeout)];
});
});
};
BaseProvider.prototype._waitForTransaction = function (transactionIdOrTimestamp, timeout) {
return __awaiter(this, void 0, void 0, function () {
var remainingTimeout;
var _this = this;
return __generator(this, function (_a) {
remainingTimeout = timeout;
return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
var txResponse;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(remainingTimeout == null || remainingTimeout > 0)) return [3 /*break*/, 5];
return [4 /*yield*/, this.getTransaction(transactionIdOrTimestamp)];
case 1:
txResponse = _a.sent();
if (!(txResponse == null)) return [3 /*break*/, 3];
return [4 /*yield*/, new Promise(function (resolve) {
setTimeout(resolve, _this._pollingInterval);
})];
case 2:
_a.sent();
if (remainingTimeout != null)
remainingTimeout -= this._pollingInterval;
return [3 /*break*/, 4];
case 3: return [2 /*return*/, resolve(this.formatter.receiptFromResponse(txResponse))];
case 4: return [3 /*break*/, 0];
case 5:
reject(logger.makeError("timeout exceeded", logger_1.Logger.errors.TIMEOUT, { timeout: timeout }));
return [2 /*return*/];
}
});
}); })];
});
});
};
BaseProvider.prototype.getEvmAddress = function (accountLike) {
return __awaiter(this, void 0, void 0, function () {
var account, data, error_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this._checkMirrorNode();
return [4 /*yield*/, accountLike];
case 1:
accountLike = _a.sent();
account = (0, address_1.asAccountString)(accountLike);
_a.label = 2;
case 2:
_a.trys.push([2, 4, , 5]);
return [4 /*yield*/, this._makeRequest(MIRROR_NODE_ACCOUNTS_ENDPOINT + account)];
case 3:
data = (_a.sent()).data;
return [2 /*return*/, data.evm_address || accountLike.toString()];
case 4:
error_2 = _a.sent();
return [2 /*return*/, accountLike.toString()];
case 5: return [2 /*return*/];
}
});
});
};
/**
* AccountBalance query implementation, using the hashgraph sdk.
* It returns the tinybar balance of the given address.
*
* @param accountLike The address to check balance of
*/
BaseProvider.prototype.getBalance = function (accountLike) {
return __awaiter(this, void 0, void 0, function () {
var account, balance, error_3;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, accountLike];
case 1:
accountLike = _a.sent();
account = (0, address_1.asAccountString)(accountLike);
_a.label = 2;
case 2:
_a.trys.push([2, 4, , 5]);
return [4 /*yield*/, new sdk_2.AccountBalanceQuery()
.setAccountId(sdk_2.AccountId.fromString(account))
.execute(this.hederaClient)];
case 3:
balance = _a.sent();
return [2 /*return*/, bignumber_1.BigNumber.from(balance.hbars.toTinybars().toString())];
case 4:
error_3 = _a.sent();
return [2 /*return*/, logger.throwError("bad result from backend", logger_1.Logger.errors.SERVER_ERROR, {
method: "AccountBalanceQuery",
params: { address: accountLike },
error: error_3
})];
case 5: return [2 /*return*/];
}
});
});
};
/**
* Get contract bytecode implementation, using the REST Api.
* It returns the bytecode, or a default value as string.
*
* @param accountLike The address to get code for
* @param throwOnNonExisting Whether or not to throw exception if address is not a contract
*/
BaseProvider.prototype.getCode = function (accountLike, throwOnNonExisting) {
return __awaiter(this, void 0, void 0, function () {
var account, data, error_4;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this._checkMirrorNode();
return [4 /*yield*/, accountLike];
case 1:
accountLike = _a.sent();
account = (0, address_1.asAccountString)(accountLike);
_a.label = 2;
case 2:
_a.trys.push([2, 4, , 5]);
return [4 /*yield*/, this._makeRequest(MIRROR_NODE_CONTRACTS_ENDPOINT + account)];
case 3:
data = (_a.sent()).data;
return [2 /*return*/, data.bytecode ? (0, bytes_1.hexlify)(data.bytecode) : "0x"];
case 4:
error_4 = _a.sent();
if (error_4.response && error_4.response.status &&
(error_4.response.status != 404 || (error_4.response.status == 404 && throwOnNonExisting))) {
logger.throwError("bad result from backend", logger_1.Logger.errors.SERVER_ERROR, {
method: "ContractByteCodeQuery",
params: { address: accountLike },
error: error_4
});
}
return [2 /*return*/, "0x"];
case 5: return [2 /*return*/];
}
});
});
};
// This should be called by any subclass wrapping a TransactionResponse
BaseProvider.prototype._wrapTransaction = function (tx, hash, receipt) {
var _this = this;
if (hash != null && (0, bytes_1.hexDataLength)(hash) !== 48) {
throw new Error("invalid response - sendTransaction");
}
var result = tx;
if (!result.customData)
result.customData = {};
if (receipt && receipt.fileId) {
result.customData.fileId = receipt.fileId.toString();
}
if (receipt && receipt.contractId) {
result.customData.contractId = receipt.contractId.toSolidityAddress();
}
if (receipt && receipt.accountId) {
result.customData.accountId = receipt.accountId;
}
// Check the hash we expect is the same as the hash the server reported
if (hash != null && tx.hash !== hash) {
logger.throwError("Transaction hash mismatch from Provider.sendTransaction.", logger_1.Logger.errors.UNKNOWN_ERROR, {
expectedHash: tx.hash,
returnedHash: hash
});
}
result.wait = function (timeout) { return __awaiter(_this, void 0, void 0, function () {
var receipt;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._waitForTransaction(tx.transactionId, timeout)];
case 1:
receipt = _a.sent();
if (receipt.status === 0) {
logger.throwError("transaction failed", logger_1.Logger.errors.CALL_EXCEPTION, {
transactionHash: tx.hash,
transaction: tx,
receipt: receipt
});
}
return [2 /*return*/, receipt];
}
});
}); };
return result;
};
BaseProvider.prototype.getHederaClient = function () {
return this.hederaClient;
};
BaseProvider.prototype.getHederaNetworkConfig = function () {
return this.hederaClient._network.getNodeAccountIdsForExecute();
};
BaseProvider.prototype.sendTransaction = function (signedTransaction) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var txBytes, hederaTx, ethersTx, txHash, _b, resp, receipt, error_5, err;
return __generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, signedTransaction];
case 1:
signedTransaction = _c.sent();
txBytes = (0, bytes_1.arrayify)(signedTransaction);
hederaTx = sdk_2.Transaction.fromBytes(txBytes);
return [4 /*yield*/, this.formatter.transaction(signedTransaction)];
case 2:
ethersTx = _c.sent();
_b = bytes_1.hexlify;
return [4 /*yield*/, hederaTx.getTransactionHash()];
case 3:
txHash = _b.apply(void 0, [_c.sent()]);
_c.label = 4;
case 4:
_c.trys.push([4, 7, , 8]);
return [4 /*yield*/, hederaTx.execute(this.hederaClient)];
case 5:
resp = _c.sent();
return [4 /*yield*/, resp.getReceipt(this.hederaClient)];
case 6:
receipt = _c.sent();
return [2 /*return*/, this._wrapTransaction(ethersTx, txHash, receipt)];
case 7:
error_5 = _c.sent();
err = logger.makeError(error_5.message, (_a = error_5.status) === null || _a === void 0 ? void 0 : _a.toString());
err.transaction = ethersTx;
err.transactionHash = txHash;
throw err;
case 8: return [2 /*return*/];
}
});
});
};
BaseProvider.prototype._getFilter = function (filter) {
return __awaiter(this, void 0, void 0, function () {
var result, _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0: return [4 /*yield*/, filter];
case 1:
filter = _c.sent();
result = {};
if (filter.address != null) {
result.address = filter.address.toString();
}
["topics"].forEach(function (key) {
if (filter[key] == null) {
return;
}
result[key] = filter[key];
});
["fromTimestamp", "toTimestamp"].forEach(function (key) {
if (filter[key] == null) {
return;
}
result[key] = filter[key];
});
_b = (_a = this.formatter).filter;
return [4 /*yield*/, (0, properties_1.resolveProperties)(result)];
case 2: return [2 /*return*/, _b.apply(_a, [_c.sent()])];
}
});
});
};
BaseProvider.prototype.estimateGas = function (transaction) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, logger.throwArgumentError("estimateGas not implemented", logger_1.Logger.errors.NOT_IMPLEMENTED, {
operation: "estimateGas"
})];
});
});
};
/**
* Transaction record query implementation using the mirror node REST API.
*
* @param transactionIdOrTimestamp - id or consensus timestamp of the transaction to search for
*/
BaseProvider.prototype.getTransaction = function (transactionIdOrTimestamp) {
return __awaiter(this, void 0, void 0, function () {
var transactionsEndpoint, data, filtered_1, record_1, transactionName, charityFee_1, toTransfers, contractsEndpoint, dataWithLogs, error_6;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this._checkMirrorNode();
return [4 /*yield*/, transactionIdOrTimestamp];
case 1:
transactionIdOrTimestamp = _a.sent();
transactionsEndpoint = MIRROR_NODE_TRANSACTIONS_ENDPOINT;
!transactionIdOrTimestamp.includes("-") ? transactionsEndpoint += ('?timestamp=' + transactionIdOrTimestamp) : transactionsEndpoint += transactionIdOrTimestamp;
_a.label = 2;
case 2:
_a.trys.push([2, 9, , 10]);
return [4 /*yield*/, this._makeRequest(transactionsEndpoint)];
case 3:
data = (_a.sent()).data;
if (!data) return [3 /*break*/, 8];
filtered_1 = data.transactions.filter(function (e) { return e.result != 'DUPLICATE_TRANSACTION'; });
if (!(filtered_1.length > 0)) return [3 /*break*/, 8];
record_1 = {
chainId: this._network.chainId,
transactionId: filtered_1[0].transaction_id,
result: filtered_1[0].result,
customData: {}
};
transactionName = filtered_1[0].name;
if (!(transactionName === 'CRYPTOCREATEACCOUNT')) return [3 /*break*/, 4];
record_1.from = (0, address_1.getAccountFromTransactionId)(filtered_1[0].transaction_id);
record_1.timestamp = filtered_1[0].consensus_timestamp;
// Different endpoints of the mirror node API returns hashes in different formats.
// In order to ensure consistency with data from MIRROR_NODE_CONTRACTS_ENDPOINT
// the hash from MIRROR_NODE_TRANSACTIONS_ENDPOINT is base64 decoded and then converted to hex.
record_1.hash = base64ToHex(filtered_1[0].transaction_hash);
record_1.accountAddress = (0, address_1.getAddressFromAccount)(filtered_1[0].entity_id);
return [3 /*break*/, 7];
case 4:
if (!(transactionName === 'CRYPTOTRANSFER')) return [3 /*break*/, 5];
record_1.from = (0, address_1.getAccountFromTransactionId)(filtered_1[0].transaction_id);
record_1.timestamp = filtered_1[0].consensus_timestamp;
record_1.hash = base64ToHex(filtered_1[0].transaction_hash);
charityFee_1 = 0;
toTransfers = filtered_1[0].transfers.filter(function (t) {
if (t.account == filtered_1[0].node) {
charityFee_1 = filtered_1[0].charged_tx_fee - t.amount;
return false;
}
return t.account != record_1.from;
}).filter(function (t) {
return t.amount != charityFee_1;
});
if (toTransfers.length > 1) {
record_1.transfersList = toTransfers;
}
else {
record_1.to = toTransfers[0].account;
record_1.amount = toTransfers[0].amount;
}
return [3 /*break*/, 7];
case 5:
contractsEndpoint = MIRROR_NODE_CONTRACTS_RESULTS_ENDPOINT + filtered_1[0].transaction_id;
return [4 /*yield*/, this._makeRequest(contractsEndpoint)];
case 6:
dataWithLogs = _a.sent();
record_1 = Object.assign({}, record_1, __assign({}, dataWithLogs.data));
_a.label = 7;
case 7: return [2 /*return*/, this.formatter.responseFromRecord(record_1)];
case 8: return [3 /*break*/, 10];
case 9:
error_6 = _a.sent();
if (error_6 && error_6.response && error_6.response.status != 404) {
logger.throwError("bad result from backend", logger_1.Logger.errors.SERVER_ERROR, {
method: "TransactionResponseQuery",
error: error_6
});
}
return [3 /*break*/, 10];
case 10: return [2 /*return*/, null];
}
});
});
};
/**
* Transaction record query implementation using the mirror node REST API.
*
* @param transactionId - id of the transaction to search for
*/
BaseProvider.prototype.getTransactionReceipt = function (transactionId) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, logger.throwError("getTransactionReceipt not implemented", logger_1.Logger.errors.NOT_IMPLEMENTED, {
operation: 'getTransactionReceipt'
})
// await this.getNetwork();
// transactionId = await transactionId;
// try {
// let receipt = await new TransactionReceiptQuery()
// .setTransactionId(transactionId)
// .execute(this.hederaClient);
// console.log("getTransactionReceipt: ", receipt);
// return null;
// } catch (error) {
// return logger.throwError("bad result from backend", Logger.errors.SERVER_ERROR, {
// method: "TransactionGetReceiptQuery",
// error
// });
// }
];
});
});
};
/**
* Get contract logs implementation, using the REST Api.
* It returns the logs array, or a default value [].
* Throws an exception, when the result size exceeds the given limit.
*
* @param filter The parameters to filter logs by.
*/
BaseProvider.prototype.getLogs = function (filter) {
return __awaiter(this, void 0, void 0, function () {
var params, fromTimestampFilter, toTimestampFilter, limit, epContractsLogs, i, topic, requestUrl, data, mappedLogs, nextLink, data_1, error_7, errorParams;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this._checkMirrorNode();
return [4 /*yield*/, (0, properties_1.resolveProperties)({ filter: this._getFilter(filter) })];
case 1:
params = _a.sent();
// set default values
params.filter.fromTimestamp = params.filter.fromTimestamp || ZERO_HEDERA_TIMESTAMP;
params.filter.toTimestamp = params.filter.toTimestamp || sdk_1.Timestamp.generate().toString();
fromTimestampFilter = '×tamp=gte%3A' + params.filter.fromTimestamp;
toTimestampFilter = '×tamp=lte%3A' + params.filter.toTimestamp;
limit = 100;
epContractsLogs = '/api/v1/contracts/' + params.filter.address + '/results/logs?limit=' + limit;
if (params.filter.topics && params.filter.topics.length > 0) {
for (i = 0; i < params.filter.topics.length; i++) {
topic = params.filter.topics[i];
if (typeof topic === "string") {
epContractsLogs += "&topic" + i + "=" + topic;
}
else {
return [2 /*return*/, logger.throwArgumentError("OR on topics", logger_1.Logger.errors.UNSUPPORTED_OPERATION, params.filter.topics)];
}
}
}
requestUrl = epContractsLogs + toTimestampFilter + fromTimestampFilter;
_a.label = 2;
case 2:
_a.trys.push([2, 8, , 9]);
return [4 /*yield*/, this._makeRequest(requestUrl)];
case 3:
data = (_a.sent()).data;
if (!data) return [3 /*break*/, 7];
mappedLogs = this.formatter.logsMapper(data.logs);
nextLink = data.links.next;
_a.label = 4;
case 4:
if (!nextLink) return [3 /*break*/, 6];
return [4 /*yield*/, this._makeRequest(nextLink)];
case 5:
data_1 = (_a.sent()).data;
if (!data_1)
return [3 /*break*/, 6];
mappedLogs = mappedLogs.concat(this.formatter.logsMapper(data_1.logs));
nextLink = data_1.links.next;
return [3 /*break*/, 4];
case 6: return [2 /*return*/, formatter_1.Formatter.arrayOf(this.formatter.filterLog.bind(this.formatter))(mappedLogs)];
case 7: return [3 /*break*/, 9];
case 8:
error_7 = _a.sent();
errorParams = { method: "ContractLogsQuery", error: error_7 };
if (error_7.response && error_7.response.status != 404) {
logger.throwError("bad result from backend", logger_1.Logger.errors.SERVER_ERROR, errorParams);
}
logger.throwError(error_7.message, error_7.code, errorParams);
return [3 /*break*/, 9];
case 9: return [2 /*return*/, []];
}
});
});
};
BaseProvider.prototype.getHbarPrice = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, logger.throwError("NOT_IMPLEMENTED", logger_1.Logger.errors.NOT_IMPLEMENTED)];
});
});
};
/* Events, Event Listeners & Polling */
BaseProvider.prototype._startEvent = function (event) {
this.polling = (this._events.filter(function (e) { return e.pollable(); }).length > 0);
this._previousPollingTimestamps[event.tag] = sdk_1.Timestamp.generate();
};
BaseProvider.prototype._stopEvent = function (event) {
this.polling = (this._events.filter(function (e) { return e.pollable(); }).length > 0);
delete this._previousPollingTimestamps[event.tag];
};
BaseProvider.prototype.perform = function (method, params) {
return logger.throwError(method + " not implemented", logger_1.Logger.errors.NOT_IMPLEMENTED, { operation: method });
};
BaseProvider.prototype._addEventListener = function (eventName, listener, once) {
var event = new Event(getEventTag(eventName), listener, once);
this._events.push(event);
this._startEvent(event);
return this;
};
BaseProvider.prototype.on = function (eventName, listener) {
return this._addEventListener(eventName, listener, false);
};
BaseProvider.prototype.once = function (eventName, listener) {
return this._addEventListener(eventName, listener, true);
};
BaseProvider.prototype.emit = function (eventName) {
var _this = this;
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
var result = false;
var stopped = [];
var eventTag = getEventTag(eventName);
this._events = this._events.filter(function (event) {
if (event.tag !== eventTag) {
return true;
}
setTimeout(function () {
event.listener.apply(_this, args);
}, 0);
result = true;
if (event.once) {
stopped.push(event);
return false;
}
return true;
});
stopped.forEach(function (event) {
_this._stopEvent(event);
});
return result;
};
BaseProvider.prototype.listenerCount = function (eventName) {
if (!eventName) {
return this._events.length;
}
var eventTag = getEventTag(eventName);
return this._events.filter(function (event) {
return (event.tag === eventTag);
}).length;
};
BaseProvider.prototype.listeners = function (eventName) {
if (eventName == null) {
return this._events.map(function (event) { return event.listener; });
}
var eventTag = getEventTag(eventName);
return this._events
.filter(function (event) { return (event.tag === eventTag); })
.map(function (event) { return event.listener; });
};
BaseProvider.prototype.off = function (eventName, listener) {
var _this = this;
if (listener == null) {
return this.removeAllListeners(eventName);
}
var stopped = [];
var found = false;
var eventTag = getEventTag(eventName);
this._events = this._events.filter(function (event) {
if (event.tag !== eventTag || event.listener != listener) {
return true;
}
if (found) {
return true;
}
found = true;
stopped.push(event);
return false;
});
stopped.forEach(function (event) {
_this._stopEvent(event);
});
return this;
};
BaseProvider.prototype.removeAllListeners = function (eventName) {
var _this = this;
var stopped = [];
if (eventName == null) {
stopped = this._events;
this._events = [];
}
else {
var eventTag_1 = getEventTag(eventName);
this._events = this._events.filter(function (event) {
if (event.tag !== eventTag_1) {
return true;
}
stopped.push(event);
return false;
});
}
stopped.forEach(function (event) {
_this._stopEvent(event);
});