UNPKG

@tangany/waas

Version:

node.js SDK for Tangany Wallet as a Service API

442 lines 20.2 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) { 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 }; } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Waas = exports.ethereumRecipientTypeSendAsync = exports.ethereumRecipientType = exports.btcRecipientType = exports.recipientType = exports.ApiVersion = exports.BitcoinTxSpeed = exports.BlockchainTxConfirmations = exports.TezosNetwork = exports.BitcoinNetwork = exports.EthereumTxSpeed = exports.EthereumPublicNetwork = exports.WalletSecurity = exports.WalletVersion = void 0; var axios_1 = require("axios"); var Debug = require("debug"); var qs = require("qs"); var t = require("typeforce"); var btc_1 = require("./btc"); var errors_1 = require("./errors"); var eth_1 = require("./eth"); var limiter_1 = require("./utils/limiter"); var request_1 = require("./request"); var wallet_1 = require("./wallet"); var polling_helper_1 = require("./utils/polling-helper"); var xtz_1 = require("./xtz"); var debug = Debug("waas-js-sdk:main"); var WalletVersion; (function (WalletVersion) { WalletVersion["LATEST"] = "latest"; })(WalletVersion = exports.WalletVersion || (exports.WalletVersion = {})); var WalletSecurity; (function (WalletSecurity) { WalletSecurity["SOFTWARE"] = "software"; WalletSecurity["HSM"] = "hsm"; })(WalletSecurity = exports.WalletSecurity || (exports.WalletSecurity = {})); var EthereumPublicNetwork; (function (EthereumPublicNetwork) { EthereumPublicNetwork["MAINNET"] = "mainnet"; EthereumPublicNetwork["ROPSTEN"] = "ropsten"; EthereumPublicNetwork["POLYGON"] = "polygon"; EthereumPublicNetwork["BINANCE"] = "bsc"; EthereumPublicNetwork["GOERLI"] = "goerli"; })(EthereumPublicNetwork = exports.EthereumPublicNetwork || (exports.EthereumPublicNetwork = {})); var EthereumTxSpeed; (function (EthereumTxSpeed) { EthereumTxSpeed["DEFAULT"] = "default"; EthereumTxSpeed["FAST"] = "fast"; EthereumTxSpeed["SLOW"] = "slow"; EthereumTxSpeed["NONE"] = "none"; })(EthereumTxSpeed = exports.EthereumTxSpeed || (exports.EthereumTxSpeed = {})); var BitcoinNetwork; (function (BitcoinNetwork) { BitcoinNetwork["BITCOIN"] = "bitcoin"; BitcoinNetwork["TESTNET"] = "testnet"; })(BitcoinNetwork = exports.BitcoinNetwork || (exports.BitcoinNetwork = {})); var TezosNetwork; (function (TezosNetwork) { TezosNetwork["MAINNET"] = "mainnet"; })(TezosNetwork = exports.TezosNetwork || (exports.TezosNetwork = {})); var BlockchainTxConfirmations; (function (BlockchainTxConfirmations) { BlockchainTxConfirmations["NONE"] = "none"; BlockchainTxConfirmations["DEFAULT"] = "default"; BlockchainTxConfirmations["SECURE"] = "secure"; })(BlockchainTxConfirmations = exports.BlockchainTxConfirmations || (exports.BlockchainTxConfirmations = {})); var BitcoinTxSpeed; (function (BitcoinTxSpeed) { BitcoinTxSpeed["SLOW"] = "slow"; BitcoinTxSpeed["DEFAULT"] = "default"; BitcoinTxSpeed["FAST"] = "fast"; })(BitcoinTxSpeed = exports.BitcoinTxSpeed || (exports.BitcoinTxSpeed = {})); var ApiVersion; (function (ApiVersion) { ApiVersion["V1"] = "v1"; ApiVersion["V2_ALPHA"] = "v2-alpha"; })(ApiVersion = exports.ApiVersion || (exports.ApiVersion = {})); exports.recipientType = t.compile({ to: "?String", wallet: "?String", amount: "String", }); // Amount is optional for btc recipients exports.btcRecipientType = t.compile({ to: "?String", wallet: "?String", amount: "?String", }); exports.ethereumRecipientType = t.compile({ to: "?String", wallet: "?String", amount: "?String", data: "?String", }); exports.ethereumRecipientTypeSendAsync = t.compile({ to: "?String", wallet: "?String", amount: "?String", }); /** * Instantiates a new API interface. Multiple instances with different settings can run in parallel * @param options - api options * @param options.clientId - Subscription client id * @param options.clientSecret - Subscription client secret * @param options.subscription - Subscription code * @param options.vaultUrl - Tangany vault url * @param options.ethereumNetwork - Public Ethereum network name or private Ethereum network url * @param options.ethereumTxConfirmations - Amount of block confirmations required to consider an Ethereum transaction as valid * @param options.ethereumTxSpeed - Amount of additional gas fee that is added to the base gas fee for the given Ethereum network to speed up the mining process of the transaction * @param options.bitcoinNetwork - Public Bitcoin network name * @param options.bitcoinTxConfirmations - Amount of block confirmations required for Bitcoin balance outputs to be included in the total wallet balance calculation * @param options.bitcoinTxSpeed - Target amount of block confirmations for the transaction to be included to the Bitcoin network * @param options.bitcoinMaxFeeRate - Maximum allowed fee rate in sat/vbyte for a Bitcoin transaction * @param options.bitcoinFeeRate - User-defined transaction fee rate in sat/vbyte for a Bitcoin transaction * @param version - WaaS API version * @param limiterEnabled - Enable API throttling limiter */ var Waas = /** @class */ (function () { function Waas(options, version, limiterEnabled) { var _this = this; if (version === void 0) { version = ApiVersion.V1; } if (limiterEnabled === void 0) { limiterEnabled = true; } var _options = __assign({ clientId: process.env.TANGANY_CLIENT_ID, clientSecret: process.env.TANGANY_CLIENT_SECRET, subscription: process.env.TANGANY_SUBSCRIPTION, vaultUrl: process.env.TANGANY_VAULT_URL }, options); if (!_options.clientId) { throw new errors_1.AuthenticationError("Missing variable 'clientId'"); } if (!_options.clientSecret) { throw new errors_1.AuthenticationError("Missing variable 'clientSecret'"); } if (!_options.subscription) { throw new errors_1.AuthenticationError("Missing variable 'subscription'"); } t({ clientId: "String", clientSecret: "String", subscription: "String", vaultUrl: "?String", ethereumNetwork: "?String", ethereumTxSpeed: "?String", ethereumTxConfirmations: t.anyOf("?String", "?Number"), ethereumGasPrice: "?String", ethereumGas: "?Number", ethereumNonce: "?Number", ethereumChainId: "?Number", useGasTank: "?Boolean", bitcoinNetwork: "?String", bitcoinTxSpeed: "?String", bitcoinTxConfirmations: t.anyOf("?String", "?Number"), bitcoinMaxFeeRate: "?Number", bitcoinFeeRate: "?Number", version: "?Number", tezosNetwork: "?String", tezosGasLimit: "?Number", tezosStorageLimit: "?Number", tezosOperationConfirmation: t.anyOf("?String", "?Number"), requestId: "?String", }, _options, true); axios_1.default.defaults.withCredentials = true; var api = { baseURL: (function () { switch (version) { case ApiVersion.V1: return "https://api.tangany.com/v1"; default: return version; } })(), headers: { "tangany-client-id": _options.clientId, "tangany-client-secret": _options.clientSecret, "tangany-subscription": _options.subscription, "common": { Accept: "application/json", }, }, responseType: "json", paramsSerializer: function (params) { if (params instanceof URLSearchParams) { return params.toString(); } return qs.stringify(params, { arrayFormat: 'repeat' }); }, }; if (_options.vaultUrl) { api.headers["tangany-vault-url"] = _options.vaultUrl; } if (_options.ethereumNetwork) { api.headers["tangany-ethereum-network"] = _options.ethereumNetwork; } if (_options.ethereumTxConfirmations) { api.headers["tangany-ethereum-tx-confirmations"] = _options.ethereumTxConfirmations; } if (_options.ethereumTxSpeed) { api.headers["tangany-ethereum-tx-speed"] = _options.ethereumTxSpeed; } if (_options.ethereumGasPrice) { api.headers["tangany-ethereum-gas-price"] = _options.ethereumGasPrice; } if (_options.ethereumGas) { api.headers["tangany-ethereum-gas"] = _options.ethereumGas; } if (_options.ethereumNonce) { api.headers["tangany-ethereum-nonce"] = _options.ethereumNonce; } if (_options.useGasTank) { api.headers["tangany-use-gas-tank"] = _options.useGasTank; } if (_options.bitcoinNetwork) { api.headers["tangany-bitcoin-network"] = _options.bitcoinNetwork; } if (_options.bitcoinTxSpeed) { api.headers["tangany-bitcoin-tx-speed"] = _options.bitcoinTxSpeed; } if (_options.bitcoinTxConfirmations) { api.headers["tangany-bitcoin-tx-confirmations"] = _options.bitcoinTxConfirmations; } if (_options.bitcoinMaxFeeRate) { api.headers["tangany-bitcoin-max-fee-rate"] = _options.bitcoinMaxFeeRate; } if (_options.bitcoinFeeRate) { api.headers["tangany-bitcoin-fee-rate"] = _options.bitcoinFeeRate; } if (_options.tezosNetwork) { api.headers["tangany-tezos-network"] = _options.tezosNetwork; } if (_options.tezosGasLimit) { api.headers["tangany-tezos-gas-limit"] = _options.tezosGasLimit; } if (_options.tezosStorageLimit) { api.headers["tangany-tezos-storage-limit"] = _options.tezosStorageLimit; } if (_options.tezosOperationConfirmation) { api.headers["tangany-tezos-operation-confirmations"] = _options.tezosOperationConfirmation; } if (_options.requestId) { api.headers["tangany-request-id"] = _options.requestId; } var instance = axios_1.default.create(api); // removes axios' proprietary "delete", "get", "head" etc. functions from its headers object var filterHeaders = function (headers) { return headers && Object.entries(headers) .filter(function (v) { switch (true) { case v[0] === "common": case typeof v[1] === "string": case v[1].constructor === Array: return true; default: return false; } }) .reduce(function (o, e) { var _a; return (__assign(__assign({}, o), (_a = {}, _a[e[0]] = e[1], _a))); }, {}); }; instance.interceptors.request.use(function (req) { var method = req.method, url = req.url, baseURL = req.baseURL, data = req.data, headers = req.headers; debug("interceptors.request", { method: method, url: "".concat(baseURL, "/").concat(url), data: data, headers: filterHeaders(headers) }); return req; }); instance.interceptors.response.use(function (response) { var headers = response.headers, data = response.data, status = response.status, statusText = response.statusText; debug("interceptors.response", { headers: filterHeaders(headers), data: data, status: status, statusText: statusText, }); if (headers && headers.hasOwnProperty("set-cookie")) { var cookie = headers["set-cookie"].map(function (h) { return h.split(";")[0]; }).join("; "); // make cookie available for consequent axios instance calls in current session instance.defaults.headers.cookie = cookie; } return data; }, function (e) { return __awaiter(_this, void 0, void 0, function () { var response, message, noErrorDetails, waasError, activityId, waasMessage; return __generator(this, function (_a) { response = e.response, message = e.message; if (!response) { throw e; } debug("interceptors.response.error", { response: response.data, headers: filterHeaders(response.headers), message: message, }); noErrorDetails = { message: "An error has occurred for which no error details could be retrieved", statusCode: 0, activityId: "" }; waasError = (typeof response.data === "object" && "output" in response.data ? response.data.output : response.data) || noErrorDetails; activityId = waasError.activityId, waasMessage = waasError.message; switch (response.status) { case 401: throw new errors_1.AuthenticationError(waasMessage, activityId); case 409: throw new errors_1.ConflictError(waasMessage, activityId); case 404: throw new errors_1.NotFoundError(waasMessage); default: throw new errors_1.GeneralError(waasMessage, response.status, activityId); } return [2 /*return*/]; }); }); }); this.instance = instance; if (limiterEnabled) { this.limiter = limiter_1.limiter; } } Object.defineProperty(Waas.prototype, "axios", { /** * Exposes the preconfigured AxiosInstance for arbitrary api calls */ get: function () { return this.instance; }, enumerable: false, configurable: true }); /** * Execute the statusGetterCall periodically until timeout and resolves the status * @param statusGetterCall - function to fetch the transaction status from a blockchain * @param [hash} - transaction hash * @param [timeout] - if the statusGetterCall did not resolved during the timeout period (in ms) the function will reject * @param [ms] - milliseconds delay between api polling attempts */ Waas.waitForTxStatus = function (statusGetterCall, hash, timeout, ms) { if (timeout === void 0) { timeout = 20e3; } if (ms === void 0) { ms = 400; } return __awaiter(this, void 0, void 0, function () { var validate; return __generator(this, function (_a) { validate = function (s) { switch (s.status) { case "confirmed": return true; case "error": throw new errors_1.MiningError(s); case "pending": default: return false; } }; return [2 /*return*/, (0, polling_helper_1.poll)(statusGetterCall, validate, "transaction status ".concat(hash), timeout, ms)]; }); }); }; /** * read wallet based api calls * @param [name] - wallet name */ Waas.prototype.wallet = function (name) { var w = new wallet_1.Wallet(this, name); return w; }; /** * read eth based api calls * @param [txHash] - Ethereum transaction hash */ Waas.prototype.eth = function (txHash) { var e = new eth_1.Ethereum(this, txHash); return e; }; /** * read btc based api calls * @param [txHash] - Bitcoin transaction hash */ Waas.prototype.btc = function (txHash) { var b = new btc_1.Bitcoin(this, txHash); return b; }; /** * read xtz based api calls * @param [txHash] - Tezos transaction hash */ Waas.prototype.xtz = function (txHash) { var xtz = new xtz_1.Tezos(this, txHash); return xtz; }; /** * read api calls for asynchronous requests * @param id - Unique identifier for an asynchronous request */ Waas.prototype.request = function (id) { return new request_1.Request(this, id); }; /** * wrap async call to the bottleneck limiter * @param fn - function that returns a promise function. Pass the promise function's arguments via the functions argument * @param args - promise function arguments */ Waas.prototype.wrap = function (fn) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { if (!this.limiter) { // throw new Error("Cannot wrap function without limiter instance"); return [2 /*return*/, fn(args)]; } return [2 /*return*/, this.limiter.schedule(fn, args)]; }); }); }; return Waas; }()); exports.Waas = Waas; //# sourceMappingURL=waas.js.map