mainnet-js 3.1.5 → 3.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -274,7 +274,7 @@ eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harm
274
274
  \********************************/
275
275
  /***/ ((module, __webpack_exports__, __webpack_require__) => {
276
276
 
277
- eval("__webpack_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"getGlobalProvider\": () => (/* binding */ getGlobalProvider),\n/* harmony export */ \"getNetworkProvider\": () => (/* binding */ getNetworkProvider),\n/* harmony export */ \"removeGlobalProvider\": () => (/* binding */ removeGlobalProvider),\n/* harmony export */ \"setGlobalProvider\": () => (/* binding */ setGlobalProvider)\n/* harmony export */ });\n/* harmony import */ var _ElectrumNetworkProvider_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./ElectrumNetworkProvider.js */ \"./src/network/ElectrumNetworkProvider.ts\");\n/* harmony import */ var _electrum_cash_network__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @electrum-cash/network */ \"../../node_modules/@electrum-cash/network/dist/index.mjs\");\n/* harmony import */ var _electrum_cash_web_socket__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @electrum-cash/web-socket */ \"../../node_modules/@electrum-cash/web-socket/dist/index.mjs\");\n/* harmony import */ var _configuration_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./configuration.js */ \"./src/network/configuration.ts\");\n/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./util.js */ \"./src/network/util.ts\");\n/* harmony import */ var _interface_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../interface.js */ \"./src/interface.ts\");\n/* harmony import */ var _constant_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./constant.js */ \"./src/network/constant.ts\");\nvar __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_configuration_js__WEBPACK_IMPORTED_MODULE_4__, _ElectrumNetworkProvider_js__WEBPACK_IMPORTED_MODULE_5__]);\n([_configuration_js__WEBPACK_IMPORTED_MODULE_4__, _ElectrumNetworkProvider_js__WEBPACK_IMPORTED_MODULE_5__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);\n\n\n\n\n\n\n\nfunction setGlobalProvider(network, provider) {\n const accessor = _constant_js__WEBPACK_IMPORTED_MODULE_2__.networkTickerMap[network];\n globalThis[accessor] = provider;\n return provider;\n}\nfunction getGlobalProvider(network) {\n const accessor = _constant_js__WEBPACK_IMPORTED_MODULE_2__.networkTickerMap[network];\n return globalThis[accessor];\n}\nfunction removeGlobalProvider(network) {\n const accessor = _constant_js__WEBPACK_IMPORTED_MODULE_2__.networkTickerMap[network];\n if (accessor in globalThis) {\n delete globalThis[accessor];\n }\n}\nfunction getNetworkProvider(network = _interface_js__WEBPACK_IMPORTED_MODULE_3__.Network.MAINNET, servers, manualConnectionManagement, options) {\n const globalContext = servers === undefined &&\n manualConnectionManagement === undefined &&\n options === undefined;\n if (globalContext) {\n const globalProvider = getGlobalProvider(network);\n if (globalProvider) {\n return globalProvider;\n }\n }\n manualConnectionManagement = manualConnectionManagement\n ? manualConnectionManagement\n : false;\n servers = servers ? servers : (0,_configuration_js__WEBPACK_IMPORTED_MODULE_4__.getDefaultServers)(network);\n // If the user has passed a single string, assume a single client connection\n if (typeof servers === \"string\") {\n servers = [servers];\n }\n // There were server(s)\n if (servers) {\n const client = getClient(servers[0], network, options);\n let provider = new _ElectrumNetworkProvider_js__WEBPACK_IMPORTED_MODULE_5__[\"default\"](client, network, manualConnectionManagement);\n if (globalContext) {\n return setGlobalProvider(network, provider);\n }\n return provider;\n }\n else {\n throw Error(\"No servers provided, defaults not available.\");\n }\n}\n// create a client with a server\nfunction getClient(server, network, options) {\n let url = (0,_util_js__WEBPACK_IMPORTED_MODULE_6__.parseElectrumUrl)(server);\n return getElectrumClient(url, options?.timeout ?? 120000, network);\n}\nfunction getElectrumClient(params, timeout, network) {\n if (params.scheme?.includes(\"tcp\")) {\n throw Error(\"TCP connections are not supported.\");\n }\n const webSocket = new _electrum_cash_web_socket__WEBPACK_IMPORTED_MODULE_1__.ElectrumWebSocket(params.host, params.port, params.scheme === \"wss\", timeout);\n return new _electrum_cash_network__WEBPACK_IMPORTED_MODULE_0__.ElectrumClient((0,_configuration_js__WEBPACK_IMPORTED_MODULE_4__.getUserAgent)(), _constant_js__WEBPACK_IMPORTED_MODULE_2__.ELECTRUM_CASH_PROTOCOL_VERSION, webSocket, {\n disableBrowserConnectivityHandling: true,\n disableBrowserVisibilityHandling: true,\n });\n}\n\n__webpack_async_result__();\n} catch(e) { __webpack_async_result__(e); } });\n\n//# sourceURL=webpack://mainnet-js/./src/network/default.ts?");
277
+ eval("__webpack_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"getGlobalProvider\": () => (/* binding */ getGlobalProvider),\n/* harmony export */ \"getNetworkProvider\": () => (/* binding */ getNetworkProvider),\n/* harmony export */ \"removeGlobalProvider\": () => (/* binding */ removeGlobalProvider),\n/* harmony export */ \"setGlobalProvider\": () => (/* binding */ setGlobalProvider)\n/* harmony export */ });\n/* harmony import */ var _ElectrumNetworkProvider_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./ElectrumNetworkProvider.js */ \"./src/network/ElectrumNetworkProvider.ts\");\n/* harmony import */ var _electrum_cash_network__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @electrum-cash/network */ \"../../node_modules/@electrum-cash/network/dist/index.mjs\");\n/* harmony import */ var _electrum_cash_web_socket__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @electrum-cash/web-socket */ \"../../node_modules/@electrum-cash/web-socket/dist/index.mjs\");\n/* harmony import */ var _configuration_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./configuration.js */ \"./src/network/configuration.ts\");\n/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./util.js */ \"./src/network/util.ts\");\n/* harmony import */ var _interface_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../interface.js */ \"./src/interface.ts\");\n/* harmony import */ var _constant_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./constant.js */ \"./src/network/constant.ts\");\nvar __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_configuration_js__WEBPACK_IMPORTED_MODULE_4__, _ElectrumNetworkProvider_js__WEBPACK_IMPORTED_MODULE_5__]);\n([_configuration_js__WEBPACK_IMPORTED_MODULE_4__, _ElectrumNetworkProvider_js__WEBPACK_IMPORTED_MODULE_5__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);\n\n\n\n\n\n\n\nfunction setGlobalProvider(network, provider) {\n const accessor = _constant_js__WEBPACK_IMPORTED_MODULE_2__.networkTickerMap[network];\n globalThis[accessor] = provider;\n return provider;\n}\nfunction getGlobalProvider(network) {\n const accessor = _constant_js__WEBPACK_IMPORTED_MODULE_2__.networkTickerMap[network];\n return globalThis[accessor];\n}\nfunction removeGlobalProvider(network) {\n const accessor = _constant_js__WEBPACK_IMPORTED_MODULE_2__.networkTickerMap[network];\n if (accessor in globalThis) {\n delete globalThis[accessor];\n }\n}\nfunction getNetworkProvider(network = _interface_js__WEBPACK_IMPORTED_MODULE_3__.Network.MAINNET, servers, manualConnectionManagement, options) {\n const globalContext = servers === undefined &&\n manualConnectionManagement === undefined &&\n options === undefined;\n if (globalContext) {\n const globalProvider = getGlobalProvider(network);\n if (globalProvider) {\n return globalProvider;\n }\n }\n manualConnectionManagement = manualConnectionManagement\n ? manualConnectionManagement\n : false;\n servers = servers ? servers : (0,_configuration_js__WEBPACK_IMPORTED_MODULE_4__.getDefaultServers)(network);\n // If the user has passed a single string, assume a single client connection\n if (typeof servers === \"string\") {\n servers = [servers];\n }\n // There were server(s)\n if (servers) {\n const client = getClient(servers[0], network, options);\n let provider = new _ElectrumNetworkProvider_js__WEBPACK_IMPORTED_MODULE_5__[\"default\"](client, network, manualConnectionManagement);\n if (globalContext) {\n return setGlobalProvider(network, provider);\n }\n return provider;\n }\n else {\n throw Error(\"No servers provided, defaults not available.\");\n }\n}\n// create a client with a server\nfunction getClient(server, network, options) {\n let url = (0,_util_js__WEBPACK_IMPORTED_MODULE_6__.parseElectrumUrl)(server);\n return getElectrumClient(url, options?.timeout ?? 120000, network);\n}\nfunction getElectrumClient(params, timeout, network) {\n if (params.scheme?.includes(\"tcp\")) {\n throw Error(\"TCP connections are not supported.\");\n }\n const webSocket = new _electrum_cash_web_socket__WEBPACK_IMPORTED_MODULE_1__.ElectrumWebSocket(params.host, params.port, params.scheme === \"wss\", timeout, {\n disableBrowserConnectivityHandling: true,\n disableBrowserVisibilityHandling: true,\n });\n return new _electrum_cash_network__WEBPACK_IMPORTED_MODULE_0__.ElectrumClient((0,_configuration_js__WEBPACK_IMPORTED_MODULE_4__.getUserAgent)(), _constant_js__WEBPACK_IMPORTED_MODULE_2__.ELECTRUM_CASH_PROTOCOL_VERSION, webSocket, {\n disableBrowserConnectivityHandling: true,\n disableBrowserVisibilityHandling: true,\n });\n}\n\n__webpack_async_result__();\n} catch(e) { __webpack_async_result__(e); } });\n\n//# sourceURL=webpack://mainnet-js/./src/network/default.ts?");
278
278
 
279
279
  /***/ }),
280
280
 
@@ -634,7 +634,7 @@ eval("__webpack_require__.a(module, async (__webpack_handle_async_dependencies__
634
634
  \****************************/
635
635
  /***/ ((module, __webpack_exports__, __webpack_require__) => {
636
636
 
637
- eval("__webpack_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"BaseWallet\": () => (/* binding */ BaseWallet),\n/* harmony export */ \"_checkContextSafety\": () => (/* binding */ _checkContextSafety),\n/* harmony export */ \"getNamedWalletId\": () => (/* binding */ getNamedWalletId),\n/* harmony export */ \"getStorageProvider\": () => (/* binding */ getStorageProvider),\n/* harmony export */ \"placeholderCashAddr\": () => (/* binding */ placeholderCashAddr),\n/* harmony export */ \"placeholderTokenAddr\": () => (/* binding */ placeholderTokenAddr)\n/* harmony export */ });\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/format/hex.js\");\n/* harmony import */ var _enum_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../enum.js */ \"./src/enum.ts\");\n/* harmony import */ var _interface_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../interface.js */ \"./src/interface.ts\");\n/* harmony import */ var _network_default_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../network/default.js */ \"./src/network/default.ts\");\n/* harmony import */ var _network_getRelayFeeCache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../network/getRelayFeeCache.js */ \"./src/network/getRelayFeeCache.ts\");\n/* harmony import */ var _transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../transaction/Wif.js */ \"./src/transaction/Wif.ts\");\n/* harmony import */ var _util_checkUtxos_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../util/checkUtxos.js */ \"./src/util/checkUtxos.ts\");\n/* harmony import */ var _util_index_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../util/index.js */ \"./src/util/sumUtxoValue.ts\");\n/* harmony import */ var _util_index_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../util/index.js */ \"./src/util/asSendRequestObject.ts\");\n/* harmony import */ var _util_index_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../util/index.js */ \"./src/util/deriveCashaddr.ts\");\n/* harmony import */ var _util_index_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../util/index.js */ \"./src/util/getRuntimePlatform.ts\");\n/* harmony import */ var _util_sumSendRequestAmounts_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../util/sumSendRequestAmounts.js */ \"./src/util/sumSendRequestAmounts.ts\");\n/* harmony import */ var _enum_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./enum.js */ \"./src/wallet/enum.ts\");\n/* harmony import */ var _model_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./model.js */ \"./src/wallet/model.ts\");\n/* harmony import */ var _Util_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Util.js */ \"./src/wallet/Util.ts\");\n/* harmony import */ var _message_signed_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../message/signed.js */ \"./src/message/signed.ts\");\nvar __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_network_default_js__WEBPACK_IMPORTED_MODULE_0__, _enum_js__WEBPACK_IMPORTED_MODULE_2__, _Util_js__WEBPACK_IMPORTED_MODULE_3__, _model_js__WEBPACK_IMPORTED_MODULE_6__, _transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__, _util_index_js__WEBPACK_IMPORTED_MODULE_10__, _util_index_js__WEBPACK_IMPORTED_MODULE_11__, _util_sumSendRequestAmounts_js__WEBPACK_IMPORTED_MODULE_12__, _message_signed_js__WEBPACK_IMPORTED_MODULE_14__]);\n([_network_default_js__WEBPACK_IMPORTED_MODULE_0__, _enum_js__WEBPACK_IMPORTED_MODULE_2__, _Util_js__WEBPACK_IMPORTED_MODULE_3__, _model_js__WEBPACK_IMPORTED_MODULE_6__, _transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__, _util_index_js__WEBPACK_IMPORTED_MODULE_10__, _util_index_js__WEBPACK_IMPORTED_MODULE_11__, _util_sumSendRequestAmounts_js__WEBPACK_IMPORTED_MODULE_12__, _message_signed_js__WEBPACK_IMPORTED_MODULE_14__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst placeholderCashAddr = \"bitcoincash:qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfnhks603\";\nconst placeholderTokenAddr = \"bitcoincash:zqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqweyg7usz\";\n/**\n * A class to hold features used by all wallets\n * @class BaseWallet\n */\nclass BaseWallet {\n get networkPrefix() {\n return _enum_js__WEBPACK_IMPORTED_MODULE_2__.prefixFromNetworkMap[this.network];\n }\n // interface to util functions. see Util.ts\n get util() {\n if (!this._util) {\n this._util = new _Util_js__WEBPACK_IMPORTED_MODULE_3__.Util(this.network);\n }\n return this._util;\n }\n // interface to util util. see Util.Util\n static get util() {\n return new this().util;\n }\n // Return wallet info\n getInfo() {\n throw Error(\"getInfo not implemented in BaseWallet\");\n }\n slpSemiAware(value = true) {\n this._slpSemiAware = value;\n return this;\n }\n //#region Accessors\n getNetworkProvider(\n // @ts-ignore\n network = _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet) {\n return (0,_network_default_js__WEBPACK_IMPORTED_MODULE_0__.getNetworkProvider)(network);\n }\n /**\n * getDepositAddress - get a wallet deposit address\n *\n * a high-level function,\n *\n * @see {@link https://rest-unstable.mainnet.cash/api-docs/#/wallet/depositAddress|/wallet/deposit_address} for REST endpoint\n *\n * @returns The deposit address as a string\n */\n getDepositAddress() {\n // return this.cashaddr;\n throw Error(\"getDepositAddress not implemented in BaseWallet\");\n }\n /**\n * getChangeAddress - get a wallet change address\n *\n * a high-level function,\n *\n * @see {@link https://rest-unstable.mainnet.cash/api-docs/#/wallet/changeAddress|/wallet/change_address} for REST endpoint\n *\n * @returns The change address as a string\n */\n getChangeAddress() {\n // return this.cashaddr;\n throw Error(\"getChangeAddress not implemented in BaseWallet\");\n }\n /**\n * getTokenDepositAddress - get a cashtoken aware wallet deposit address\n *\n * @returns The cashtoken aware deposit address as a string\n */\n getTokenDepositAddress() {\n // return this.tokenaddr;\n throw Error(\"getTokenDepositAddress not implemented in BaseWallet\");\n }\n /**\n * getTokenDepositAddress - get a cashtoken aware wallet deposit address\n *\n * @returns The cashtoken aware deposit address as a string\n */\n getTokenChangeAddress() {\n // return this.tokenaddr;\n throw Error(\"getTokenDepositAddress not implemented in BaseWallet\");\n }\n // check if a given address belongs to this wallet\n hasAddress(address) {\n return (address === this.getDepositAddress() ||\n address === this.getChangeAddress());\n }\n //#endregion Accessors\n //#region Constructors and Statics\n /**\n * constructor for a new wallet\n * @param network network for wallet\n *\n * @throws {Error} if called on BaseWallet\n */\n constructor(network = _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet) {\n this._slpSemiAware = false; // a flag which requires an utxo to have more than 546 sats to be spendable and counted in the balance\n this.name = \"\";\n this.cancelFns = [];\n this.network = network;\n this.walletType = _enum_js__WEBPACK_IMPORTED_MODULE_4__.WalletTypeEnum.Watch;\n this.provider = this.getNetworkProvider(this.network);\n this.isTestnet = this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? false : true;\n this.walletCache = new Map();\n }\n //#endregion Constructors\n /**\n * named (internal) get a named wallet from the database or create a new one.\n * Note: this function should behave identically if\n *\n * @param {string} name name of the wallet\n * @param {string} dbName database name the wallet is stored in\n * @param {boolean} forceNew attempt to overwrite an existing wallet\n *\n * @throws {Error} if forceNew is true and the wallet already exists\n * @returns a promise to a named wallet\n */\n async named(name, dbName, forceNew = false) {\n if (name.length === 0) {\n throw Error(\"Named wallets must have a non-empty name\");\n }\n _checkContextSafety(this);\n this.name = name;\n dbName = dbName ? dbName : _enum_js__WEBPACK_IMPORTED_MODULE_2__.prefixFromNetworkMap[this.network];\n const db = getStorageProvider(dbName);\n // If there is a database, force saving or error\n if (db) {\n await db.init();\n const savedWalletRecord = await db.getWallet(name);\n if (savedWalletRecord) {\n await db.close();\n if (forceNew) {\n throw Error(`A wallet with the name ${name} already exists in ${dbName}`);\n }\n const recoveredWallet = await this.fromId(savedWalletRecord.wallet);\n recoveredWallet.name = savedWalletRecord.name;\n return recoveredWallet;\n }\n else {\n const wallet = await this.initialize();\n wallet.name = name;\n await db.addWallet(wallet.name, wallet.toDbString());\n await db.close();\n return wallet;\n }\n }\n else {\n throw Error(\"No database was available or configured to store the named wallet.\");\n }\n }\n /**\n * replaceNamed - Replace (recover) named wallet with a new walletId\n *\n * If wallet with a provided name does not exist yet, it will be created with a `walletId` supplied\n * If wallet exists it will be overwritten without exception\n *\n * @param name user friendly wallet alias\n * @param walletId walletId options to steer the creation process\n * @param dbName name under which the wallet will be stored in the database\n *\n * @returns instantiated wallet\n */\n async replaceNamed(name, walletId, dbName) {\n if (name.length === 0) {\n throw Error(\"Named wallets must have a non-empty name\");\n }\n _checkContextSafety(this);\n this.name = name;\n dbName = dbName ? dbName : _enum_js__WEBPACK_IMPORTED_MODULE_2__.prefixFromNetworkMap[this.network];\n let db = getStorageProvider(dbName);\n if (db) {\n await db.init();\n let savedWalletRecord = await db.getWallet(name);\n await this.fromId(walletId);\n if (savedWalletRecord) {\n await db.updateWallet(name, walletId);\n }\n else {\n await db.addWallet(name, walletId);\n }\n await db.close();\n return this;\n }\n else {\n throw Error(\"No database was available or configured to store the named wallet.\");\n }\n }\n /**\n * namedExists - check if a named wallet already exists\n *\n * @param name user friendly wallet alias\n * @param dbName name under which the wallet will be stored in the database\n *\n * @returns boolean\n */\n async namedExists(name, dbName) {\n if (name.length === 0) {\n throw Error(\"Named wallets must have a non-empty name\");\n }\n _checkContextSafety(this);\n dbName = dbName ? dbName : _enum_js__WEBPACK_IMPORTED_MODULE_2__.prefixFromNetworkMap[this.network];\n let db = getStorageProvider(dbName);\n if (db) {\n await db.init();\n let savedWalletRecord = await db.getWallet(name);\n await db.close();\n return savedWalletRecord !== undefined;\n }\n else {\n throw Error(\"No database was available or configured to store the named wallet.\");\n }\n }\n async initialize() {\n return this;\n }\n //#region Serialization\n /**\n * toDbString - store the serialized version of the wallet in the database, not just the name\n *\n * @throws {Error} if called on BaseWallet\n */\n toDbString() {\n return `${this.walletType}:${this.network}:${this.getDepositAddress()}`;\n }\n // Returns the serialized wallet as a string\n // If storing in a database, set asNamed to false to store secrets\n // In all other cases, the a named wallet is deserialized from the database\n // by the name key\n toString() {\n return `${this.walletType}:${this.network}:${this.getDepositAddress()}`;\n }\n //#endregion Serialization\n /**\n * explorerUrl Web url to a transaction on a block explorer\n *\n * @param txId transaction Id\n * @returns Url string\n */\n explorerUrl(txId) {\n const explorerUrlMap = {\n mainnet: \"https://blockchair.com/bitcoin-cash/transaction/\",\n testnet: \"https://www.blockchain.com/bch-testnet/tx/\",\n regtest: \"\",\n };\n return explorerUrlMap[this.network] + txId;\n }\n /**\n * named - create a named wallet\n *\n * @param name user friendly wallet alias\n * @param dbName name under which the wallet will be stored in the database\n * @param force force recreate wallet in the database if a record already exist\n *\n * @returns instantiated wallet\n */\n static async named(name, dbName, force) {\n return new this().named(name, dbName, force);\n }\n /**\n * replaceNamed - replace (recover) named wallet with a new walletId\n *\n * If wallet with a provided name does not exist yet, it will be created with a `walletId` supplied\n * If wallet exists it will be overwritten without exception\n *\n * @param name user friendly wallet alias\n * @param walletId walletId options to steer the creation process\n * @param dbName name under which the wallet will be stored in the database\n *\n * @returns instantiated wallet\n */\n static async replaceNamed(name, walletId, dbName) {\n return new this().replaceNamed(name, walletId, dbName);\n }\n /**\n * namedExists - check if a named wallet already exists\n *\n * @param name user friendly wallet alias\n * @param dbName name under which the wallet will be stored in the database\n *\n * @returns boolean\n */\n static async namedExists(name, dbName) {\n return new this().namedExists(name, dbName);\n }\n fromId(walletId) {\n throw Error(\"fromId not implemented in BaseWallet\");\n }\n //#region Funds\n /**\n * utxos Get unspent outputs for the wallet\n *\n */\n async getUtxos() {\n throw Error(\"getUtxos not implemented in BaseWallet\");\n }\n // Gets balance by summing value in all utxos in sats\n // Balance includes DUST utxos which could be slp tokens and also cashtokens with BCH amounts\n async getBalance() {\n throw Error(\"getBalance not implemented in BaseWallet\");\n }\n /**\n * Track a cancel function so it can be cancelled by stop()\n * Returns a wrapped cancel function that also removes itself from tracking\n */\n trackCancelFn(cancelFn) {\n this.cancelFns.push(cancelFn);\n return async () => {\n const index = this.cancelFns.indexOf(cancelFn);\n if (index !== -1) {\n this.cancelFns.splice(index, 1);\n }\n await cancelFn();\n };\n }\n /**\n * Stop all active subscriptions on this wallet\n */\n async stop() {\n const fns = this.cancelFns.splice(0);\n await Promise.all(fns.map((fn) => fn()));\n }\n /**\n * Watch wallet for any activity (status changes)\n * This is the foundation for watchWalletBalance and watchWalletTransactions\n * @param callback - Called when the wallet has a status change\n * @returns Cancel function to stop watching\n */\n async watchStatus(callback) {\n const cancelFn = await this.provider.watchAddressStatus(this.getDepositAddress(), (status) => callback(status, this.getDepositAddress()));\n return this.trackCancelFn(cancelFn);\n }\n // sets up a callback to be called upon wallet's balance change\n // can be cancelled by calling the function returned from this one\n async watchBalance(callback) {\n return this.watchStatus(async () => {\n const balance = await this.getBalance();\n callback(balance);\n });\n }\n // waits for address balance to be greater than or equal to the target value\n // this call halts the execution\n async waitForBalance(value) {\n return new Promise(async (resolve) => {\n let watchCancel;\n watchCancel = await this.watchBalance(async (balance) => {\n if (balance >= value) {\n await watchCancel?.();\n resolve(balance);\n }\n });\n });\n }\n // sets up a callback to be called upon wallet's token balance change\n // can be cancelled by calling the function returned from this one\n async watchTokenBalance(category, callback) {\n return await this.watchStatus(async () => {\n const balance = await this.getTokenBalance(category);\n callback(balance);\n });\n }\n // waits for address token balance to be greater than or equal to the target amount\n // this call halts the execution\n async waitForTokenBalance(category, amount) {\n return new Promise(async (resolve) => {\n let watchCancel;\n watchCancel = await this.watchTokenBalance(category, async (balance) => {\n if (balance >= amount) {\n await watchCancel?.();\n resolve(balance);\n }\n });\n });\n }\n /**\n * Watch wallet for new transactions\n * @param callback - Called with new transaction hashes when they appear\n * @returns Cancel function to stop watching\n */\n async watchTransactionHashes(callback) {\n const seenTxHashes = new Set();\n let topHeight = 0;\n return this.watchStatus(async () => {\n const history = (await this.getRawHistory(topHeight)).sort((a, b) => a.height <= 0 || b.height <= 0 ? -1 : b.height - a.height);\n const newTxHashes = [];\n for (const tx of history) {\n if (tx.height > topHeight) {\n topHeight = tx.height;\n }\n if (!seenTxHashes.has(tx.tx_hash)) {\n seenTxHashes.add(tx.tx_hash);\n newTxHashes.push(tx.tx_hash);\n }\n }\n if (newTxHashes.length > 0) {\n newTxHashes.forEach((txHash) => callback(txHash));\n }\n });\n }\n /**\n * Watch wallet for new transactions\n * @param callback - Called with new transaction hashes when they appear\n * @returns Cancel function to stop watching\n */\n async watchTransactions(callback) {\n return this.watchTransactionHashes(async (txHash) => {\n const tx = await this.provider.getRawTransactionObject(txHash);\n callback(tx);\n });\n }\n async watchTokenTransactions(callback) {\n return this.watchTransactions(async (transaction) => {\n if (transaction.vout.some((val) => val.tokenData)) {\n callback(transaction);\n }\n });\n }\n async _getMaxAmountToSend(params = {\n outputCount: 1,\n options: {},\n }) {\n if (params.options && params.options.slpSemiAware) {\n this._slpSemiAware = true;\n }\n let feePaidBy;\n if (params.options && params.options.feePaidBy) {\n feePaidBy = params.options.feePaidBy;\n }\n else {\n feePaidBy = _enum_js__WEBPACK_IMPORTED_MODULE_4__.FeePaidByEnum.change;\n }\n // get inputs\n let utxos;\n const allUtxos = await this.getUtxos();\n if (params.options && params.options.utxoIds) {\n utxos = (0,_util_checkUtxos_js__WEBPACK_IMPORTED_MODULE_5__.checkUtxos)(params.options.utxoIds.map((utxoId) => typeof utxoId === \"string\" ? (0,_model_js__WEBPACK_IMPORTED_MODULE_6__.fromUtxoId)(utxoId) : utxoId), allUtxos);\n }\n else {\n utxos = allUtxos.filter((utxo) => !utxo.token);\n }\n // Get current height to assure recently mined coins are not spent.\n const bestHeight = await this.provider.getBlockHeight();\n // simulate outputs using the sender's address\n const sendRequest = new _model_js__WEBPACK_IMPORTED_MODULE_6__.SendRequest({\n cashaddr: placeholderCashAddr,\n value: 100n,\n });\n const sendRequests = Array(params.outputCount)\n .fill(0)\n .map(() => sendRequest);\n const fundingUtxos = await (0,_transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.getSuitableUtxos)(utxos, undefined, bestHeight, feePaidBy, sendRequests);\n const relayFeePerByteInSatoshi = await (0,_network_getRelayFeeCache_js__WEBPACK_IMPORTED_MODULE_1__.getRelayFeeCache)(this.provider);\n const fee = await (0,_transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.getFeeAmountSimple)({\n utxos: fundingUtxos,\n sendRequests: sendRequests,\n sourceAddress: placeholderCashAddr,\n relayFeePerByteInSatoshi: relayFeePerByteInSatoshi,\n feePaidBy: feePaidBy,\n });\n const spendableAmount = (0,_util_index_js__WEBPACK_IMPORTED_MODULE_8__.sumUtxoValue)(fundingUtxos);\n let result = spendableAmount - fee;\n if (result < 0n) {\n result = 0n;\n }\n return { value: result, utxos: fundingUtxos };\n }\n async getMaxAmountToSend(params = {\n outputCount: 1,\n options: {},\n }) {\n const { value: result } = await this._getMaxAmountToSend(params);\n return result;\n }\n /**\n * send Send some amount to an address\n * this function processes the send requests, encodes the transaction, sends it to the network\n * @returns (depending on the options parameter) the transaction id, new address balance and a link to the transaction on the blockchain explorer\n *\n * This is a first class function with REST analog, maintainers should strive to keep backward-compatibility\n *\n */\n async send(requests, options) {\n const { encodedTransaction, categories, sourceOutputs } = await this.encodeTransaction(requests, undefined, options);\n const resp = new _model_js__WEBPACK_IMPORTED_MODULE_6__.SendResponse({});\n resp.categories = categories;\n if (options?.buildUnsigned !== true) {\n const txId = await this.submitTransaction(encodedTransaction, options?.awaitTransactionPropagation === undefined ||\n options?.awaitTransactionPropagation === true);\n resp.txId = txId;\n resp.explorerUrl = this.explorerUrl(resp.txId);\n if (options?.queryBalance === undefined ||\n options?.queryBalance === true) {\n resp.balance = await this.getBalance();\n }\n }\n else {\n resp.unsignedTransaction = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_9__.binToHex)(encodedTransaction);\n resp.sourceOutputs = sourceOutputs;\n }\n return resp;\n }\n /**\n * sendMax Send all available funds to a destination cash address\n *\n * @param {string} cashaddr destination cash address\n * @param {SendRequestOptionsI} options Options of the send requests\n *\n * @returns (depending on the options parameter) the transaction id, new address balance and a link to the transaction on the blockchain explorer\n */\n async sendMax(cashaddr, options) {\n return await this.sendMaxRaw(cashaddr, options);\n }\n /**\n * sendMaxRaw (internal) Send all available funds to a destination cash address\n *\n * @param {string} cashaddr destination cash address\n * @param {SendRequestOptionsI} options Options of the send requests\n *\n * @returns the transaction id sent to the network\n */\n async sendMaxRaw(cashaddr, options, privateKey) {\n const { value: maxSpendableAmount, utxos } = await this._getMaxAmountToSend({\n outputCount: 1,\n options: options,\n privateKey: privateKey,\n });\n if (!options) {\n options = {};\n }\n options.utxoIds = utxos;\n const sendRequest = new _model_js__WEBPACK_IMPORTED_MODULE_6__.SendRequest({\n cashaddr: cashaddr,\n value: maxSpendableAmount,\n });\n const { encodedTransaction, categories, sourceOutputs } = await this.encodeTransaction([sendRequest], true, options, privateKey);\n const resp = new _model_js__WEBPACK_IMPORTED_MODULE_6__.SendResponse({});\n resp.categories = categories;\n if (options?.buildUnsigned !== true) {\n const txId = await this.submitTransaction(encodedTransaction, options?.awaitTransactionPropagation === undefined ||\n options?.awaitTransactionPropagation === true);\n resp.txId = txId;\n resp.explorerUrl = this.explorerUrl(resp.txId);\n if (options?.queryBalance === undefined ||\n options?.queryBalance === true) {\n resp.balance = await this.getBalance();\n }\n }\n else {\n resp.unsignedTransaction = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_9__.binToHex)(encodedTransaction);\n resp.sourceOutputs = sourceOutputs;\n }\n return resp;\n }\n /**\n * encodeTransaction Encode and sign a transaction given a list of sendRequests, options and estimate fees.\n * @param {SendRequest[]} sendRequests SendRequests\n * @param {boolean} discardChange=false\n * @param {SendRequestOptionsI} options Options of the send requests\n */\n async encodeTransaction(requests, discardChange = false, options, privateKey) {\n let sendRequests = (0,_util_index_js__WEBPACK_IMPORTED_MODULE_10__.asSendRequestObject)(requests);\n if (options && options.slpSemiAware) {\n this._slpSemiAware = true;\n }\n let feePaidBy;\n if (options?.feePaidBy) {\n feePaidBy = options.feePaidBy;\n }\n else {\n feePaidBy = _enum_js__WEBPACK_IMPORTED_MODULE_4__.FeePaidByEnum.change;\n }\n let changeAddress;\n if (options?.changeAddress) {\n changeAddress = options.changeAddress;\n }\n else {\n changeAddress = this.getChangeAddress();\n }\n let checkTokenQuantities = true;\n if (options?.checkTokenQuantities === false) {\n checkTokenQuantities = false;\n }\n // get inputs from options or query all inputs\n let utxos = await this.getUtxos();\n if (options && options.utxoIds) {\n utxos = (0,_util_checkUtxos_js__WEBPACK_IMPORTED_MODULE_5__.checkUtxos)(options.utxoIds.map((utxoId) => typeof utxoId === \"string\" ? (0,_model_js__WEBPACK_IMPORTED_MODULE_6__.fromUtxoId)(utxoId) : utxoId), utxos);\n }\n // filter out token utxos if there are no token requests\n if (checkTokenQuantities &&\n !sendRequests.some((val) => val instanceof _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest)) {\n utxos = utxos.filter((val) => !val.token);\n }\n const addTokenChangeOutputs = (inputs, outputs) => {\n // Allow for implicit token burn if the total amount sent is less than user had\n // allow for token genesis, creating more tokens than we had before (0)\n if (!checkTokenQuantities) {\n return;\n }\n const allTokenInputs = inputs.filter((val) => val.token);\n const allTokenOutputs = outputs.filter((val) => val instanceof _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest);\n const categories = allTokenOutputs\n .map((val) => val.category)\n .filter((val, idx, arr) => arr.indexOf(val) === idx);\n for (let category of categories) {\n const tokenInputs = allTokenInputs.filter((val) => val.token?.category === category);\n const inputAmountSum = tokenInputs.reduce((prev, cur) => prev + cur.token.amount, 0n);\n const tokenOutputs = allTokenOutputs.filter((val) => val.category === category);\n const outputAmountSum = tokenOutputs.reduce((prev, cur) => prev + cur.amount, 0n);\n const diff = inputAmountSum - outputAmountSum;\n if (diff < 0) {\n throw new Error(\"Not enough token amount to send\");\n }\n if (diff >= 0) {\n let available = 0n;\n let change = 0n;\n const ensureUtxos = [];\n for (const token of tokenInputs.filter((val) => val.token?.amount)) {\n ensureUtxos.push(token);\n available += token.token.amount;\n if (available >= outputAmountSum) {\n change = available - outputAmountSum;\n //break;\n }\n }\n if (ensureUtxos.length) {\n if (!options) {\n options = {};\n }\n options.ensureUtxos = [\n ...(options.ensureUtxos ?? []),\n ...ensureUtxos,\n ].filter((val, index, array) => array.findIndex((other) => other.txid === val.txid && other.vout === val.vout) === index);\n }\n if (change > 0) {\n outputs.push(new _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest({\n cashaddr: (0,_util_index_js__WEBPACK_IMPORTED_MODULE_11__.toTokenaddr)(this.getChangeAddress()),\n amount: change,\n category: category,\n nft: tokenOutputs[0].nft,\n value: tokenOutputs[0].value,\n }));\n }\n }\n }\n };\n addTokenChangeOutputs(utxos, sendRequests);\n const bestHeight = await this.provider.getBlockHeight();\n const spendAmount = await (0,_util_sumSendRequestAmounts_js__WEBPACK_IMPORTED_MODULE_12__.sumSendRequestAmounts)(sendRequests);\n if (utxos.length === 0) {\n throw Error(\"There were no Unspent Outputs\");\n }\n if (typeof spendAmount !== \"bigint\") {\n throw Error(\"Couldn't get spend amount when building transaction\");\n }\n const relayFeePerByteInSatoshi = await (0,_network_getRelayFeeCache_js__WEBPACK_IMPORTED_MODULE_1__.getRelayFeeCache)(this.provider);\n const feeEstimate = await (0,_transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.getFeeAmountSimple)({\n utxos: utxos,\n sendRequests: sendRequests,\n sourceAddress: this.getDepositAddress(),\n relayFeePerByteInSatoshi: relayFeePerByteInSatoshi,\n feePaidBy: feePaidBy,\n });\n const fundingUtxos = await (0,_transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.getSuitableUtxos)(utxos, spendAmount + feeEstimate, bestHeight, feePaidBy, sendRequests, options?.ensureUtxos || [], options?.tokenOperation);\n if (fundingUtxos.length === 0) {\n throw Error(\"The available inputs couldn't satisfy the request with fees\");\n }\n const fee = await (0,_transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.getFeeAmount)({\n utxos: fundingUtxos,\n sendRequests: sendRequests,\n sourceAddress: this.getDepositAddress(),\n relayFeePerByteInSatoshi: relayFeePerByteInSatoshi,\n feePaidBy: feePaidBy,\n walletCache: this.walletCache,\n });\n const { encodedTransaction, sourceOutputs } = await (0,_transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.buildEncodedTransaction)({\n inputs: fundingUtxos,\n outputs: sendRequests,\n signingKey: privateKey ?? _transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.placeholderPrivateKeyBin,\n fee,\n discardChange,\n feePaidBy,\n changeAddress,\n buildUnsigned: options?.buildUnsigned === true,\n walletCache: this.walletCache,\n });\n const categories = [\n ...fundingUtxos\n .filter((val) => val.token?.category)\n .map((val) => val.token.category),\n ...sendRequests\n .filter((val) => val instanceof _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest)\n .map((val) => val.category),\n ].filter((value, index, array) => array.indexOf(value) === index);\n return { encodedTransaction, categories, sourceOutputs };\n }\n // Submit a raw transaction\n async submitTransaction(transaction, awaitPropagation = true) {\n if (!this.provider) {\n throw Error(\"Wallet network provider was not initialized\");\n }\n let rawTransaction = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_9__.binToHex)(transaction);\n return await this.provider.sendRawTransaction(rawTransaction, awaitPropagation);\n }\n // gets transaction history of this wallet\n async getRawHistory(fromHeight = 0, toHeight = -1) {\n throw Error(\"getRawHistory not implemented in BaseWallet\");\n }\n // gets last transaction of this wallet\n async getLastTransaction(confirmedOnly = false) {\n let history = await this.getRawHistory();\n if (confirmedOnly) {\n history = history.filter((val) => val.height > 0);\n }\n if (!history.length) {\n return null;\n }\n const [lastTx] = history.slice(-1);\n return this.provider.getRawTransactionObject(lastTx.tx_hash);\n }\n // waits for next transaction, program execution is halted\n async waitForTransaction(options = {\n getTransactionInfo: true,\n getBalance: false,\n txHash: undefined,\n }) {\n if (options.getTransactionInfo === undefined) {\n options.getTransactionInfo = true;\n }\n return new Promise(async (resolve) => {\n let txHashSeen = false;\n const makeResponse = async (txHash) => {\n const response = {};\n const promises = [undefined, undefined];\n if (options.getBalance === true) {\n promises[0] = this.getBalance();\n }\n if (options.getTransactionInfo === true) {\n if (!txHash) {\n promises[1] = this.getLastTransaction();\n }\n else {\n promises[1] = this.provider.getRawTransactionObject(txHash);\n }\n }\n const result = await Promise.all(promises);\n response.balance = result[0];\n response.transactionInfo = result[1];\n return response;\n };\n // waiting for a specific transaction to propagate\n if (options.txHash) {\n let cancel;\n const waitForTransactionCallback = async (data) => {\n if (data && data[0] === options.txHash && data[1] !== null) {\n txHashSeen = true;\n await cancel?.();\n resolve(makeResponse(options.txHash));\n }\n };\n cancel = await this.provider.subscribeToTransaction(options.txHash, waitForTransactionCallback);\n return;\n }\n // waiting for any address transaction\n let watchCancel;\n let initialResponseSeen = false;\n watchCancel = await this.watchStatus(async (_status) => {\n if (initialResponseSeen) {\n await watchCancel?.();\n resolve(makeResponse());\n return;\n }\n initialResponseSeen = true;\n });\n });\n }\n /**\n * watchBlocks Watch network blocks\n *\n * @param callback callback with a block header object\n * @param skipCurrentHeight if set, the notification about current block will not arrive\n *\n * @returns a function which will cancel watching upon evaluation\n */\n async watchBlocks(callback, skipCurrentHeight = true) {\n return this.provider.watchBlocks(callback, skipCurrentHeight);\n }\n /**\n * waitForBlock Wait for a network block\n *\n * @param height if specified waits for this exact blockchain height, otherwise resolves with the next block\n *\n */\n async waitForBlock(height) {\n return this.provider.waitForBlock(height);\n }\n //#endregion Funds\n //#region Cashtokens\n /**\n * Create new cashtoken, both funglible and/or non-fungible (NFT)\n * Refer to spec https://github.com/bitjson/cashtokens\n * @param {number} genesisRequest.amount amount of *fungible* tokens to create\n * @param {NFTCapability?} genesisRequest.capability capability of new NFT\n * @param {string?} genesisRequest.commitment NFT commitment message\n * @param {string?} genesisRequest.cashaddr cash address to send the created token UTXO to; if undefined will default to your address\n * @param {number?} genesisRequest.value satoshi value to send alongside with tokens; if undefined will default to 1000 satoshi\n * @param {SendRequestType | SendRequestType[]} sendRequests single or an array of extra send requests (OP_RETURN, value transfer, etc.) to include in genesis transaction\n * @param {SendRequestOptionsI} options Options of the send requests\n */\n async tokenGenesis(genesisRequest, sendRequests = [], options) {\n if (!Array.isArray(sendRequests)) {\n sendRequests = [sendRequests];\n }\n let utxos = await this.getUtxos();\n if (options?.utxoIds) {\n utxos = (0,_util_checkUtxos_js__WEBPACK_IMPORTED_MODULE_5__.checkUtxos)(options.utxoIds.map((utxoId) => typeof utxoId === \"string\" ? (0,_model_js__WEBPACK_IMPORTED_MODULE_6__.fromUtxoId)(utxoId) : utxoId), utxos);\n }\n const genesisInputs = utxos.filter((val) => val.vout === 0 && !val.token);\n if (genesisInputs.length === 0) {\n throw new Error(\"No suitable inputs with vout=0 available for new token genesis\");\n }\n const genesisSendRequest = new _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest({\n cashaddr: genesisRequest.cashaddr || this.getTokenDepositAddress(),\n amount: genesisRequest.amount,\n value: genesisRequest.value || 1000n,\n nft: genesisRequest.nft,\n category: genesisInputs[0].txid,\n });\n return this.send([genesisSendRequest, ...sendRequests], {\n ...options,\n utxoIds: utxos,\n ensureUtxos: [genesisInputs[0]],\n checkTokenQuantities: false,\n queryBalance: false,\n tokenOperation: \"genesis\",\n });\n }\n /**\n * Mint new NFT cashtokens using an existing minting token\n * Refer to spec https://github.com/bitjson/cashtokens\n * @param {string} category category of an NFT to mint\n * @param {TokenMintRequest | TokenMintRequest[]} mintRequests mint requests with new token properties and recipients\n * @param {NFTCapability?} mintRequest.capability capability of new NFT\n * @param {string?} mintRequest.commitment NFT commitment message\n * @param {string?} mintRequest.cashaddr cash address to send the created token UTXO to; if undefined will default to your address\n * @param {number?} mintRequest.value satoshi value to send alongside with tokens; if undefined will default to 1000 satoshi\n * @param {boolean?} deductTokenAmount if minting token contains fungible amount, deduct from it by amount of minted tokens\n * @param {SendRequestOptionsI} options Options of the send requests\n */\n async tokenMint(category, mintRequests, deductTokenAmount = false, options) {\n if (category?.length !== 64) {\n throw Error(`Invalid category supplied: ${category}`);\n }\n if (!Array.isArray(mintRequests)) {\n mintRequests = [mintRequests];\n }\n const utxos = await this.getUtxos();\n const nftUtxos = utxos.filter((val) => val.token?.category === category &&\n val.token?.nft?.capability === _interface_js__WEBPACK_IMPORTED_MODULE_13__.NFTCapability.minting);\n if (!nftUtxos.length) {\n throw new Error(\"You do not have any token UTXOs with minting capability for specified category\");\n }\n const newAmount = deductTokenAmount && nftUtxos[0].token.amount > 0\n ? nftUtxos[0].token.amount - BigInt(mintRequests.length)\n : nftUtxos[0].token.amount;\n const safeNewAmount = newAmount < 0n ? 0n : newAmount;\n const mintingInput = new _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest({\n cashaddr: (0,_util_index_js__WEBPACK_IMPORTED_MODULE_11__.toTokenaddr)(nftUtxos[0].address),\n category: category,\n nft: nftUtxos[0].token?.nft,\n amount: safeNewAmount,\n value: nftUtxos[0].satoshis,\n });\n return this.send([\n mintingInput,\n ...mintRequests.map((val) => new _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest({\n cashaddr: val.cashaddr || this.getTokenDepositAddress(),\n amount: 0n,\n category: category,\n value: val.value,\n nft: val.nft,\n })),\n ], {\n ...options,\n ensureUtxos: [nftUtxos[0]],\n checkTokenQuantities: false,\n queryBalance: false,\n tokenOperation: \"mint\",\n });\n }\n /**\n * Perform an explicit token burning by spending a token utxo to an OP_RETURN\n *\n * Behaves differently for fungible and non-fungible tokens:\n * * NFTs are always \"destroyed\"\n * * FTs' amount is reduced by the amount specified, if 0 FT amount is left and no NFT present, the token is \"destroyed\"\n *\n * Refer to spec https://github.com/bitjson/cashtokens\n * @param {string} burnRequest.category category of a token to burn\n * @param {NFTCapability} burnRequest.capability capability of the NFT token to select, optional\n * @param {string?} burnRequest.commitment commitment of the NFT token to select, optional\n * @param {number?} burnRequest.amount amount of fungible tokens to burn, optional\n * @param {string?} burnRequest.cashaddr address to return token and satoshi change to\n * @param {string?} message optional message to include in OP_RETURN\n * @param {SendRequestOptionsI} options Options of the send requests\n */\n async tokenBurn(burnRequest, message, options) {\n if (burnRequest.category?.length !== 64) {\n throw Error(`Invalid category supplied: ${burnRequest.category}`);\n }\n const utxos = await this.getUtxos();\n const tokenUtxos = utxos.filter((val) => val.token?.category === burnRequest.category &&\n val.token?.nft?.capability === burnRequest.nft?.capability &&\n val.token?.nft?.commitment === burnRequest.nft?.commitment);\n if (!tokenUtxos.length) {\n throw new Error(\"You do not have suitable token UTXOs to perform burn\");\n }\n const totalFungibleAmount = tokenUtxos.reduce((prev, cur) => prev + (cur.token?.amount || 0n), 0n);\n let fungibleBurnAmount = burnRequest.amount && burnRequest.amount > 0 ? burnRequest.amount : 0n;\n fungibleBurnAmount = BigInt(fungibleBurnAmount);\n const hasNFT = burnRequest.nft !== undefined;\n let utxoIds = [];\n let changeSendRequests;\n if (hasNFT) {\n // does not have FT tokens, let us destroy the token completely\n if (totalFungibleAmount === 0n) {\n changeSendRequests = [];\n utxoIds.push(tokenUtxos[0]);\n }\n else {\n // add utxos to spend from\n let available = 0n;\n for (const token of tokenUtxos.filter((val) => val.token?.amount)) {\n utxoIds.push(token);\n available += token.token.amount;\n if (available >= fungibleBurnAmount) {\n break;\n }\n }\n // if there are FT, reduce their amount\n const newAmount = totalFungibleAmount - fungibleBurnAmount;\n const safeNewAmount = newAmount < 0n ? 0n : newAmount;\n changeSendRequests = [\n new _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest({\n cashaddr: burnRequest.cashaddr || (0,_util_index_js__WEBPACK_IMPORTED_MODULE_11__.toTokenaddr)(this.getChangeAddress()),\n category: burnRequest.category,\n nft: burnRequest.nft,\n amount: safeNewAmount,\n value: tokenUtxos[0].satoshis,\n }),\n ];\n }\n }\n else {\n // if we are burning last fungible tokens, let us destroy the token completely\n if (totalFungibleAmount === fungibleBurnAmount) {\n changeSendRequests = [];\n utxoIds.push(...tokenUtxos);\n }\n else {\n // add utxos to spend from\n let available = 0n;\n for (const token of tokenUtxos.filter((val) => val.token?.amount)) {\n utxoIds.push(token);\n available += token.token.amount;\n if (available >= fungibleBurnAmount) {\n break;\n }\n }\n // reduce the FT amount\n const newAmount = available - fungibleBurnAmount;\n const safeNewAmount = newAmount < 0n ? 0n : newAmount;\n changeSendRequests = [\n new _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest({\n cashaddr: burnRequest.cashaddr || (0,_util_index_js__WEBPACK_IMPORTED_MODULE_11__.toTokenaddr)(this.getChangeAddress()),\n category: burnRequest.category,\n amount: safeNewAmount,\n value: tokenUtxos.reduce((a, c) => a + c.satoshis, 0n),\n }),\n ];\n }\n }\n const opReturn = _model_js__WEBPACK_IMPORTED_MODULE_6__.OpReturnData.fromString(message || \"\");\n return this.send([opReturn, ...changeSendRequests], {\n ...options,\n checkTokenQuantities: false,\n queryBalance: false,\n ensureUtxos: utxoIds.length > 0 ? utxoIds : undefined,\n tokenOperation: \"burn\",\n });\n }\n /**\n * getTokenUtxos Get unspent token outputs for the wallet\n * will return utxos only for the specified token if `category` provided\n * @param {string?} category category to filter utxos by, if not set will return utxos from all tokens\n * @returns {Utxo[]} token utxos\n */\n async getTokenUtxos(category) {\n const utxos = await this.getUtxos();\n return utxos.filter((val) => category ? val.token?.category === category : val.token);\n }\n /**\n * getTokenBalance Gets fungible token balance\n * for NFT token balance see @ref getNftTokenBalance\n * @param {string} category category to get balance for\n * @returns {bigint} fungible token balance\n */\n async getTokenBalance(category) {\n const utxos = (await this.getTokenUtxos(category)).filter((val) => val.token?.amount);\n return (0,_util_index_js__WEBPACK_IMPORTED_MODULE_8__.sumTokenAmounts)(utxos, category);\n }\n /**\n * getNftTokenBalance Gets non-fungible token (NFT) balance for a particular category\n * disregards fungible token balances\n * for fungible token balance see @ref getTokenBalance\n * @param {string} category category to get balance for\n * @returns {number} non-fungible token balance\n */\n async getNftTokenBalance(category) {\n const utxos = (await this.getTokenUtxos(category)).filter((val) => val.token?.nft?.commitment !== undefined);\n return utxos.length;\n }\n /**\n * getAllTokenBalances Gets all fungible token balances in this wallet\n * @returns {Object} a map [category => balance] for all tokens in this wallet\n */\n async getAllTokenBalances() {\n const result = {};\n const utxos = (await this.getTokenUtxos()).filter((val) => val.token?.amount);\n for (const utxo of utxos) {\n if (!result[utxo.token.category]) {\n result[utxo.token.category] = 0n;\n }\n result[utxo.token.category] += utxo.token.amount;\n }\n return result;\n }\n /**\n * getAllNftTokenBalances Gets all non-fungible token (NFT) balances in this wallet\n * @returns {Object} a map [category => balance] for all NFTs in this wallet\n */\n async getAllNftTokenBalances() {\n const result = {};\n const utxos = (await this.getTokenUtxos()).filter((val) => val.token?.nft?.commitment !== undefined);\n for (const utxo of utxos) {\n if (!result[utxo.token.category]) {\n result[utxo.token.category] = 0;\n }\n result[utxo.token.category] += 1;\n }\n return result;\n }\n //#endregion Cashtokens\n sign(message, privateKey = undefined) {\n if (!privateKey) {\n throw new Error(\"Signing private key not provided\");\n }\n return new _message_signed_js__WEBPACK_IMPORTED_MODULE_14__.SignedMessage().sign(message, privateKey);\n }\n // Convenience wrapper to verify interface\n verify(message, sig, address, publicKey) {\n if (!address && !publicKey) {\n throw new Error(\"Either address or publicKey must be provided for verification\");\n }\n return new _message_signed_js__WEBPACK_IMPORTED_MODULE_14__.SignedMessage().verify(message, sig, address, publicKey);\n }\n}\n/**\n * _checkContextSafety (internal) if running in nodejs, will disable saving\n * mainnet wallets on public servers if ALLOW_MAINNET_USER_WALLETS is set to false\n * @param {BaseWallet} wallet a wallet\n */\nconst _checkContextSafety = function (wallet) {\n if ((0,_util_index_js__WEBPACK_IMPORTED_MODULE_15__.getRuntimePlatform)() === \"node\") {\n if (process.env.ALLOW_MAINNET_USER_WALLETS === `false`) {\n if (wallet.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet) {\n throw Error(`Refusing to save wallet in an open public database, remove ALLOW_MAINNET_USER_WALLETS=\"false\", if this service is secure and private`);\n }\n }\n }\n};\n/**\n * getNamedWalletId - get the full wallet id from the database\n *\n * @param name user friendly wallet alias\n * @param dbName name under which the wallet will be stored in the database\n *\n * @returns boolean\n */\nasync function getNamedWalletId(name, dbName) {\n if (name.length === 0) {\n throw Error(\"Named wallets must have a non-empty name\");\n }\n dbName = dbName ? dbName : dbName;\n let db = getStorageProvider(dbName);\n if (db) {\n await db.init();\n let savedWalletRecord = await db.getWallet(name);\n await db.close();\n if (savedWalletRecord !== undefined) {\n return savedWalletRecord.wallet;\n }\n else {\n throw Error(`No record was found for ${name} in db: ${dbName}`);\n }\n }\n else {\n throw Error(\"No database was available or configured to store the named wallet.\");\n }\n}\nfunction getStorageProvider(dbName) {\n if (!BaseWallet.StorageProvider) {\n return undefined;\n }\n return new BaseWallet.StorageProvider(dbName);\n}\n\n__webpack_async_result__();\n} catch(e) { __webpack_async_result__(e); } });\n\n//# sourceURL=webpack://mainnet-js/./src/wallet/Base.ts?");
637
+ eval("__webpack_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"BaseWallet\": () => (/* binding */ BaseWallet),\n/* harmony export */ \"_checkContextSafety\": () => (/* binding */ _checkContextSafety),\n/* harmony export */ \"getNamedWalletId\": () => (/* binding */ getNamedWalletId),\n/* harmony export */ \"getStorageProvider\": () => (/* binding */ getStorageProvider),\n/* harmony export */ \"placeholderCashAddr\": () => (/* binding */ placeholderCashAddr),\n/* harmony export */ \"placeholderTokenAddr\": () => (/* binding */ placeholderTokenAddr)\n/* harmony export */ });\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/format/hex.js\");\n/* harmony import */ var _enum_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../enum.js */ \"./src/enum.ts\");\n/* harmony import */ var _interface_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../interface.js */ \"./src/interface.ts\");\n/* harmony import */ var _network_default_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../network/default.js */ \"./src/network/default.ts\");\n/* harmony import */ var _network_getRelayFeeCache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../network/getRelayFeeCache.js */ \"./src/network/getRelayFeeCache.ts\");\n/* harmony import */ var _transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../transaction/Wif.js */ \"./src/transaction/Wif.ts\");\n/* harmony import */ var _util_checkUtxos_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../util/checkUtxos.js */ \"./src/util/checkUtxos.ts\");\n/* harmony import */ var _util_index_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../util/index.js */ \"./src/util/sumUtxoValue.ts\");\n/* harmony import */ var _util_index_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../util/index.js */ \"./src/util/asSendRequestObject.ts\");\n/* harmony import */ var _util_index_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../util/index.js */ \"./src/util/deriveCashaddr.ts\");\n/* harmony import */ var _util_index_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../util/index.js */ \"./src/util/getRuntimePlatform.ts\");\n/* harmony import */ var _util_sumSendRequestAmounts_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../util/sumSendRequestAmounts.js */ \"./src/util/sumSendRequestAmounts.ts\");\n/* harmony import */ var _enum_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./enum.js */ \"./src/wallet/enum.ts\");\n/* harmony import */ var _model_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./model.js */ \"./src/wallet/model.ts\");\n/* harmony import */ var _Util_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Util.js */ \"./src/wallet/Util.ts\");\n/* harmony import */ var _message_signed_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../message/signed.js */ \"./src/message/signed.ts\");\nvar __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_network_default_js__WEBPACK_IMPORTED_MODULE_0__, _enum_js__WEBPACK_IMPORTED_MODULE_2__, _Util_js__WEBPACK_IMPORTED_MODULE_3__, _model_js__WEBPACK_IMPORTED_MODULE_6__, _transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__, _util_index_js__WEBPACK_IMPORTED_MODULE_10__, _util_index_js__WEBPACK_IMPORTED_MODULE_11__, _util_sumSendRequestAmounts_js__WEBPACK_IMPORTED_MODULE_12__, _message_signed_js__WEBPACK_IMPORTED_MODULE_14__]);\n([_network_default_js__WEBPACK_IMPORTED_MODULE_0__, _enum_js__WEBPACK_IMPORTED_MODULE_2__, _Util_js__WEBPACK_IMPORTED_MODULE_3__, _model_js__WEBPACK_IMPORTED_MODULE_6__, _transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__, _util_index_js__WEBPACK_IMPORTED_MODULE_10__, _util_index_js__WEBPACK_IMPORTED_MODULE_11__, _util_sumSendRequestAmounts_js__WEBPACK_IMPORTED_MODULE_12__, _message_signed_js__WEBPACK_IMPORTED_MODULE_14__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst placeholderCashAddr = \"bitcoincash:qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqfnhks603\";\nconst placeholderTokenAddr = \"bitcoincash:zqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqweyg7usz\";\n/**\n * A class to hold features used by all wallets\n * @class BaseWallet\n */\nclass BaseWallet {\n get networkPrefix() {\n return _enum_js__WEBPACK_IMPORTED_MODULE_2__.prefixFromNetworkMap[this.network];\n }\n // interface to util functions. see Util.ts\n get util() {\n if (!this._util) {\n this._util = new _Util_js__WEBPACK_IMPORTED_MODULE_3__.Util(this.network);\n }\n return this._util;\n }\n // interface to util util. see Util.Util\n static get util() {\n return new this().util;\n }\n // Return wallet info\n getInfo() {\n throw Error(\"getInfo not implemented in BaseWallet\");\n }\n slpSemiAware(value = true) {\n this._slpSemiAware = value;\n return this;\n }\n //#region Accessors\n getNetworkProvider(\n // @ts-ignore\n network = _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet) {\n return (0,_network_default_js__WEBPACK_IMPORTED_MODULE_0__.getNetworkProvider)(network);\n }\n /**\n * getDepositAddress - get a wallet deposit address\n *\n * a high-level function,\n *\n * @see {@link https://rest-unstable.mainnet.cash/api-docs/#/wallet/depositAddress|/wallet/deposit_address} for REST endpoint\n *\n * @returns The deposit address as a string\n */\n getDepositAddress() {\n // return this.cashaddr;\n throw Error(\"getDepositAddress not implemented in BaseWallet\");\n }\n /**\n * getChangeAddress - get a wallet change address\n *\n * a high-level function,\n *\n * @see {@link https://rest-unstable.mainnet.cash/api-docs/#/wallet/changeAddress|/wallet/change_address} for REST endpoint\n *\n * @returns The change address as a string\n */\n getChangeAddress() {\n // return this.cashaddr;\n throw Error(\"getChangeAddress not implemented in BaseWallet\");\n }\n /**\n * getTokenDepositAddress - get a cashtoken aware wallet deposit address\n *\n * @returns The cashtoken aware deposit address as a string\n */\n getTokenDepositAddress() {\n // return this.tokenaddr;\n throw Error(\"getTokenDepositAddress not implemented in BaseWallet\");\n }\n /**\n * getTokenDepositAddress - get a cashtoken aware wallet deposit address\n *\n * @returns The cashtoken aware deposit address as a string\n */\n getTokenChangeAddress() {\n // return this.tokenaddr;\n throw Error(\"getTokenDepositAddress not implemented in BaseWallet\");\n }\n // check if a given address belongs to this wallet\n hasAddress(address) {\n return (address === this.getDepositAddress() ||\n address === this.getChangeAddress());\n }\n //#endregion Accessors\n //#region Constructors and Statics\n /**\n * constructor for a new wallet\n * @param network network for wallet\n *\n * @throws {Error} if called on BaseWallet\n */\n constructor(network = _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet) {\n this._slpSemiAware = false; // a flag which requires an utxo to have more than 546 sats to be spendable and counted in the balance\n this.name = \"\";\n this.cancelFns = [];\n this.network = network;\n this.walletType = _enum_js__WEBPACK_IMPORTED_MODULE_4__.WalletTypeEnum.Watch;\n this.provider = this.getNetworkProvider(this.network);\n this.isTestnet = this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? false : true;\n this.walletCache = new Map();\n }\n //#endregion Constructors\n /**\n * named (internal) get a named wallet from the database or create a new one.\n * Note: this function should behave identically if\n *\n * @param {string} name name of the wallet\n * @param {string} dbName database name the wallet is stored in\n * @param {boolean} forceNew attempt to overwrite an existing wallet\n *\n * @throws {Error} if forceNew is true and the wallet already exists\n * @returns a promise to a named wallet\n */\n async named(name, dbName, forceNew = false) {\n if (name.length === 0) {\n throw Error(\"Named wallets must have a non-empty name\");\n }\n _checkContextSafety(this);\n this.name = name;\n dbName = dbName ? dbName : _enum_js__WEBPACK_IMPORTED_MODULE_2__.prefixFromNetworkMap[this.network];\n const db = getStorageProvider(dbName);\n // If there is a database, force saving or error\n if (db) {\n await db.init();\n const savedWalletRecord = await db.getWallet(name);\n if (savedWalletRecord) {\n await db.close();\n if (forceNew) {\n throw Error(`A wallet with the name ${name} already exists in ${dbName}`);\n }\n const recoveredWallet = await this.fromId(savedWalletRecord.wallet);\n recoveredWallet.name = savedWalletRecord.name;\n return recoveredWallet;\n }\n else {\n const wallet = await this.initialize();\n wallet.name = name;\n await db.addWallet(wallet.name, wallet.toDbString());\n await db.close();\n return wallet;\n }\n }\n else {\n throw Error(\"No database was available or configured to store the named wallet.\");\n }\n }\n /**\n * replaceNamed - Replace (recover) named wallet with a new walletId\n *\n * If wallet with a provided name does not exist yet, it will be created with a `walletId` supplied\n * If wallet exists it will be overwritten without exception\n *\n * @param name user friendly wallet alias\n * @param walletId walletId options to steer the creation process\n * @param dbName name under which the wallet will be stored in the database\n *\n * @returns instantiated wallet\n */\n async replaceNamed(name, walletId, dbName) {\n if (name.length === 0) {\n throw Error(\"Named wallets must have a non-empty name\");\n }\n _checkContextSafety(this);\n this.name = name;\n dbName = dbName ? dbName : _enum_js__WEBPACK_IMPORTED_MODULE_2__.prefixFromNetworkMap[this.network];\n let db = getStorageProvider(dbName);\n if (db) {\n await db.init();\n let savedWalletRecord = await db.getWallet(name);\n await this.fromId(walletId);\n if (savedWalletRecord) {\n await db.updateWallet(name, walletId);\n }\n else {\n await db.addWallet(name, walletId);\n }\n await db.close();\n return this;\n }\n else {\n throw Error(\"No database was available or configured to store the named wallet.\");\n }\n }\n /**\n * namedExists - check if a named wallet already exists\n *\n * @param name user friendly wallet alias\n * @param dbName name under which the wallet will be stored in the database\n *\n * @returns boolean\n */\n async namedExists(name, dbName) {\n if (name.length === 0) {\n throw Error(\"Named wallets must have a non-empty name\");\n }\n _checkContextSafety(this);\n dbName = dbName ? dbName : _enum_js__WEBPACK_IMPORTED_MODULE_2__.prefixFromNetworkMap[this.network];\n let db = getStorageProvider(dbName);\n if (db) {\n await db.init();\n let savedWalletRecord = await db.getWallet(name);\n await db.close();\n return savedWalletRecord !== undefined;\n }\n else {\n throw Error(\"No database was available or configured to store the named wallet.\");\n }\n }\n async initialize() {\n return this;\n }\n //#region Serialization\n /**\n * toDbString - store the serialized version of the wallet in the database, not just the name\n *\n * @throws {Error} if called on BaseWallet\n */\n toDbString() {\n return `${this.walletType}:${this.network}:${this.getDepositAddress()}`;\n }\n // Returns the serialized wallet as a string\n // If storing in a database, set asNamed to false to store secrets\n // In all other cases, the a named wallet is deserialized from the database\n // by the name key\n toString() {\n return `${this.walletType}:${this.network}:${this.getDepositAddress()}`;\n }\n //#endregion Serialization\n /**\n * explorerUrl Web url to a transaction on a block explorer\n *\n * @param txId transaction Id\n * @returns Url string\n */\n explorerUrl(txId) {\n const explorerUrlMap = {\n mainnet: \"https://blockchair.com/bitcoin-cash/transaction/\",\n testnet: \"https://www.blockchain.com/bch-testnet/tx/\",\n regtest: \"\",\n };\n return explorerUrlMap[this.network] + txId;\n }\n /**\n * named - create a named wallet\n *\n * @param name user friendly wallet alias\n * @param dbName name under which the wallet will be stored in the database\n * @param force force recreate wallet in the database if a record already exist\n *\n * @returns instantiated wallet\n */\n static async named(name, dbName, force) {\n return new this().named(name, dbName, force);\n }\n /**\n * replaceNamed - replace (recover) named wallet with a new walletId\n *\n * If wallet with a provided name does not exist yet, it will be created with a `walletId` supplied\n * If wallet exists it will be overwritten without exception\n *\n * @param name user friendly wallet alias\n * @param walletId walletId options to steer the creation process\n * @param dbName name under which the wallet will be stored in the database\n *\n * @returns instantiated wallet\n */\n static async replaceNamed(name, walletId, dbName) {\n return new this().replaceNamed(name, walletId, dbName);\n }\n /**\n * namedExists - check if a named wallet already exists\n *\n * @param name user friendly wallet alias\n * @param dbName name under which the wallet will be stored in the database\n *\n * @returns boolean\n */\n static async namedExists(name, dbName) {\n return new this().namedExists(name, dbName);\n }\n fromId(walletId) {\n throw Error(\"fromId not implemented in BaseWallet\");\n }\n //#region Funds\n /**\n * utxos Get unspent outputs for the wallet\n *\n */\n async getUtxos() {\n throw Error(\"getUtxos not implemented in BaseWallet\");\n }\n // Gets balance by summing value in all utxos in sats\n // Balance includes DUST utxos which could be slp tokens and also cashtokens with BCH amounts\n async getBalance() {\n throw Error(\"getBalance not implemented in BaseWallet\");\n }\n /**\n * Track a cancel function so it can be cancelled by stop()\n * Returns a wrapped cancel function that also removes itself from tracking\n */\n trackCancelFn(cancelFn) {\n this.cancelFns.push(cancelFn);\n return async () => {\n const index = this.cancelFns.indexOf(cancelFn);\n if (index !== -1) {\n this.cancelFns.splice(index, 1);\n }\n await cancelFn();\n };\n }\n /**\n * Stop all active subscriptions on this wallet\n */\n async stop() {\n const fns = this.cancelFns.splice(0);\n await Promise.all(fns.map((fn) => fn()));\n }\n /**\n * Watch wallet for any activity (status changes)\n * This is the foundation for watchWalletBalance and watchWalletTransactions\n * @param callback - Called when the wallet has a status change\n * @returns Cancel function to stop watching\n */\n async watchStatus(callback) {\n const cancelFn = await this.provider.watchAddressStatus(this.getDepositAddress(), (status) => callback(status, this.getDepositAddress()));\n return this.trackCancelFn(cancelFn);\n }\n /**\n * No-op for single-address wallets. HDWallet overrides this to wait for\n * depositIndex/changeIndex advancement.\n */\n async waitForUpdate(_options = {}) { }\n // sets up a callback to be called upon wallet's balance change\n // can be cancelled by calling the function returned from this one\n async watchBalance(callback) {\n return this.watchStatus(async () => {\n const balance = await this.getBalance();\n callback(balance);\n });\n }\n // waits for address balance to be greater than or equal to the target value\n // this call halts the execution\n async waitForBalance(value) {\n return new Promise(async (resolve) => {\n let watchCancel;\n watchCancel = await this.watchBalance(async (balance) => {\n if (balance >= value) {\n await watchCancel?.();\n resolve(balance);\n }\n });\n });\n }\n // sets up a callback to be called upon wallet's token balance change\n // can be cancelled by calling the function returned from this one\n async watchTokenBalance(category, callback) {\n return await this.watchStatus(async () => {\n const balance = await this.getTokenBalance(category);\n callback(balance);\n });\n }\n // waits for address token balance to be greater than or equal to the target amount\n // this call halts the execution\n async waitForTokenBalance(category, amount) {\n return new Promise(async (resolve) => {\n let watchCancel;\n watchCancel = await this.watchTokenBalance(category, async (balance) => {\n if (balance >= amount) {\n await watchCancel?.();\n resolve(balance);\n }\n });\n });\n }\n /**\n * Watch wallet for new transactions\n * @param callback - Called with new transaction hashes when they appear\n * @returns Cancel function to stop watching\n */\n async watchTransactionHashes(callback) {\n const seenTxHashes = new Set();\n let topHeight = 0;\n return this.watchStatus(async () => {\n const history = (await this.getRawHistory(topHeight)).sort((a, b) => a.height <= 0 || b.height <= 0 ? -1 : b.height - a.height);\n const newTxHashes = [];\n for (const tx of history) {\n if (tx.height > topHeight) {\n topHeight = tx.height;\n }\n if (!seenTxHashes.has(tx.tx_hash)) {\n seenTxHashes.add(tx.tx_hash);\n newTxHashes.push(tx.tx_hash);\n }\n }\n if (newTxHashes.length > 0) {\n newTxHashes.forEach((txHash) => callback(txHash));\n }\n });\n }\n /**\n * Watch wallet for new transactions\n * @param callback - Called with new transaction hashes when they appear\n * @returns Cancel function to stop watching\n */\n async watchTransactions(callback) {\n return this.watchTransactionHashes(async (txHash) => {\n const tx = await this.provider.getRawTransactionObject(txHash);\n callback(tx);\n });\n }\n async watchTokenTransactions(callback) {\n return this.watchTransactions(async (transaction) => {\n if (transaction.vout.some((val) => val.tokenData)) {\n callback(transaction);\n }\n });\n }\n async _getMaxAmountToSend(params = {\n outputCount: 1,\n options: {},\n }) {\n if (params.options && params.options.slpSemiAware) {\n this._slpSemiAware = true;\n }\n let feePaidBy;\n if (params.options && params.options.feePaidBy) {\n feePaidBy = params.options.feePaidBy;\n }\n else {\n feePaidBy = _enum_js__WEBPACK_IMPORTED_MODULE_4__.FeePaidByEnum.change;\n }\n // get inputs\n let utxos;\n const allUtxos = await this.getUtxos();\n if (params.options && params.options.utxoIds) {\n utxos = (0,_util_checkUtxos_js__WEBPACK_IMPORTED_MODULE_5__.checkUtxos)(params.options.utxoIds.map((utxoId) => typeof utxoId === \"string\" ? (0,_model_js__WEBPACK_IMPORTED_MODULE_6__.fromUtxoId)(utxoId) : utxoId), allUtxos);\n }\n else {\n utxos = allUtxos.filter((utxo) => !utxo.token);\n }\n // Get current height to assure recently mined coins are not spent.\n const bestHeight = await this.provider.getBlockHeight();\n // simulate outputs using the sender's address\n const sendRequest = new _model_js__WEBPACK_IMPORTED_MODULE_6__.SendRequest({\n cashaddr: placeholderCashAddr,\n value: 100n,\n });\n const sendRequests = Array(params.outputCount)\n .fill(0)\n .map(() => sendRequest);\n const fundingUtxos = await (0,_transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.getSuitableUtxos)(utxos, undefined, bestHeight, feePaidBy, sendRequests);\n const relayFeePerByteInSatoshi = await (0,_network_getRelayFeeCache_js__WEBPACK_IMPORTED_MODULE_1__.getRelayFeeCache)(this.provider);\n const fee = await (0,_transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.getFeeAmountSimple)({\n utxos: fundingUtxos,\n sendRequests: sendRequests,\n sourceAddress: placeholderCashAddr,\n relayFeePerByteInSatoshi: relayFeePerByteInSatoshi,\n feePaidBy: feePaidBy,\n });\n const spendableAmount = (0,_util_index_js__WEBPACK_IMPORTED_MODULE_8__.sumUtxoValue)(fundingUtxos);\n let result = spendableAmount - fee;\n if (result < 0n) {\n result = 0n;\n }\n return { value: result, utxos: fundingUtxos };\n }\n async getMaxAmountToSend(params = {\n outputCount: 1,\n options: {},\n }) {\n const { value: result } = await this._getMaxAmountToSend(params);\n return result;\n }\n /**\n * send Send some amount to an address\n * this function processes the send requests, encodes the transaction, sends it to the network\n * @returns (depending on the options parameter) the transaction id, new address balance and a link to the transaction on the blockchain explorer\n *\n * This is a first class function with REST analog, maintainers should strive to keep backward-compatibility\n *\n */\n async send(requests, options) {\n const { encodedTransaction, categories, sourceOutputs } = await this.encodeTransaction(requests, undefined, options);\n const resp = new _model_js__WEBPACK_IMPORTED_MODULE_6__.SendResponse({});\n resp.categories = categories;\n if (options?.buildUnsigned !== true) {\n const txId = await this.submitTransaction(encodedTransaction, options?.awaitTransactionPropagation === undefined ||\n options?.awaitTransactionPropagation === true);\n resp.txId = txId;\n resp.explorerUrl = this.explorerUrl(resp.txId);\n if (options?.queryBalance === undefined ||\n options?.queryBalance === true) {\n resp.balance = await this.getBalance();\n }\n }\n else {\n resp.unsignedTransaction = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_9__.binToHex)(encodedTransaction);\n resp.sourceOutputs = sourceOutputs;\n }\n return resp;\n }\n /**\n * sendMax Send all available funds to a destination cash address\n *\n * @param {string} cashaddr destination cash address\n * @param {SendRequestOptionsI} options Options of the send requests\n *\n * @returns (depending on the options parameter) the transaction id, new address balance and a link to the transaction on the blockchain explorer\n */\n async sendMax(cashaddr, options) {\n return await this.sendMaxRaw(cashaddr, options);\n }\n /**\n * sendMaxRaw (internal) Send all available funds to a destination cash address\n *\n * @param {string} cashaddr destination cash address\n * @param {SendRequestOptionsI} options Options of the send requests\n *\n * @returns the transaction id sent to the network\n */\n async sendMaxRaw(cashaddr, options, privateKey) {\n const { value: maxSpendableAmount, utxos } = await this._getMaxAmountToSend({\n outputCount: 1,\n options: options,\n privateKey: privateKey,\n });\n if (!options) {\n options = {};\n }\n options.utxoIds = utxos;\n const sendRequest = new _model_js__WEBPACK_IMPORTED_MODULE_6__.SendRequest({\n cashaddr: cashaddr,\n value: maxSpendableAmount,\n });\n const { encodedTransaction, categories, sourceOutputs } = await this.encodeTransaction([sendRequest], true, options, privateKey);\n const resp = new _model_js__WEBPACK_IMPORTED_MODULE_6__.SendResponse({});\n resp.categories = categories;\n if (options?.buildUnsigned !== true) {\n const txId = await this.submitTransaction(encodedTransaction, options?.awaitTransactionPropagation === undefined ||\n options?.awaitTransactionPropagation === true);\n resp.txId = txId;\n resp.explorerUrl = this.explorerUrl(resp.txId);\n if (options?.queryBalance === undefined ||\n options?.queryBalance === true) {\n resp.balance = await this.getBalance();\n }\n }\n else {\n resp.unsignedTransaction = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_9__.binToHex)(encodedTransaction);\n resp.sourceOutputs = sourceOutputs;\n }\n return resp;\n }\n /**\n * encodeTransaction Encode and sign a transaction given a list of sendRequests, options and estimate fees.\n * @param {SendRequest[]} sendRequests SendRequests\n * @param {boolean} discardChange=false\n * @param {SendRequestOptionsI} options Options of the send requests\n */\n async encodeTransaction(requests, discardChange = false, options, privateKey) {\n let sendRequests = (0,_util_index_js__WEBPACK_IMPORTED_MODULE_10__.asSendRequestObject)(requests);\n if (options && options.slpSemiAware) {\n this._slpSemiAware = true;\n }\n let feePaidBy;\n if (options?.feePaidBy) {\n feePaidBy = options.feePaidBy;\n }\n else {\n feePaidBy = _enum_js__WEBPACK_IMPORTED_MODULE_4__.FeePaidByEnum.change;\n }\n let changeAddress;\n if (options?.changeAddress) {\n changeAddress = options.changeAddress;\n }\n else {\n changeAddress = this.getChangeAddress();\n }\n let checkTokenQuantities = true;\n if (options?.checkTokenQuantities === false) {\n checkTokenQuantities = false;\n }\n // get inputs from options or query all inputs\n let utxos = await this.getUtxos();\n if (options && options.utxoIds) {\n utxos = (0,_util_checkUtxos_js__WEBPACK_IMPORTED_MODULE_5__.checkUtxos)(options.utxoIds.map((utxoId) => typeof utxoId === \"string\" ? (0,_model_js__WEBPACK_IMPORTED_MODULE_6__.fromUtxoId)(utxoId) : utxoId), utxos);\n }\n // filter out token utxos if there are no token requests\n if (checkTokenQuantities &&\n !sendRequests.some((val) => val instanceof _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest)) {\n utxos = utxos.filter((val) => !val.token);\n }\n const addTokenChangeOutputs = (inputs, outputs) => {\n // Allow for implicit token burn if the total amount sent is less than user had\n // allow for token genesis, creating more tokens than we had before (0)\n if (!checkTokenQuantities) {\n return;\n }\n const allTokenInputs = inputs.filter((val) => val.token);\n const allTokenOutputs = outputs.filter((val) => val instanceof _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest);\n const categories = allTokenOutputs\n .map((val) => val.category)\n .filter((val, idx, arr) => arr.indexOf(val) === idx);\n for (let category of categories) {\n const tokenInputs = allTokenInputs.filter((val) => val.token?.category === category);\n const inputAmountSum = tokenInputs.reduce((prev, cur) => prev + cur.token.amount, 0n);\n const tokenOutputs = allTokenOutputs.filter((val) => val.category === category);\n const outputAmountSum = tokenOutputs.reduce((prev, cur) => prev + cur.amount, 0n);\n const diff = inputAmountSum - outputAmountSum;\n if (diff < 0) {\n throw new Error(\"Not enough token amount to send\");\n }\n if (diff >= 0) {\n let available = 0n;\n let change = 0n;\n const ensureUtxos = [];\n for (const token of tokenInputs.filter((val) => val.token?.amount)) {\n ensureUtxos.push(token);\n available += token.token.amount;\n if (available >= outputAmountSum) {\n change = available - outputAmountSum;\n //break;\n }\n }\n if (ensureUtxos.length) {\n if (!options) {\n options = {};\n }\n options.ensureUtxos = [\n ...(options.ensureUtxos ?? []),\n ...ensureUtxos,\n ].filter((val, index, array) => array.findIndex((other) => other.txid === val.txid && other.vout === val.vout) === index);\n }\n if (change > 0) {\n outputs.push(new _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest({\n cashaddr: (0,_util_index_js__WEBPACK_IMPORTED_MODULE_11__.toTokenaddr)(this.getChangeAddress()),\n amount: change,\n category: category,\n nft: tokenOutputs[0].nft,\n value: tokenOutputs[0].value,\n }));\n }\n }\n }\n };\n addTokenChangeOutputs(utxos, sendRequests);\n const bestHeight = await this.provider.getBlockHeight();\n const spendAmount = await (0,_util_sumSendRequestAmounts_js__WEBPACK_IMPORTED_MODULE_12__.sumSendRequestAmounts)(sendRequests);\n if (utxos.length === 0) {\n throw Error(\"There were no Unspent Outputs\");\n }\n if (typeof spendAmount !== \"bigint\") {\n throw Error(\"Couldn't get spend amount when building transaction\");\n }\n const relayFeePerByteInSatoshi = await (0,_network_getRelayFeeCache_js__WEBPACK_IMPORTED_MODULE_1__.getRelayFeeCache)(this.provider);\n const feeEstimate = await (0,_transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.getFeeAmountSimple)({\n utxos: utxos,\n sendRequests: sendRequests,\n sourceAddress: this.getDepositAddress(),\n relayFeePerByteInSatoshi: relayFeePerByteInSatoshi,\n feePaidBy: feePaidBy,\n });\n const fundingUtxos = await (0,_transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.getSuitableUtxos)(utxos, spendAmount + feeEstimate, bestHeight, feePaidBy, sendRequests, options?.ensureUtxos || [], options?.tokenOperation);\n if (fundingUtxos.length === 0) {\n throw Error(\"The available inputs couldn't satisfy the request with fees\");\n }\n const fee = await (0,_transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.getFeeAmount)({\n utxos: fundingUtxos,\n sendRequests: sendRequests,\n sourceAddress: this.getDepositAddress(),\n relayFeePerByteInSatoshi: relayFeePerByteInSatoshi,\n feePaidBy: feePaidBy,\n walletCache: this.walletCache,\n });\n const { encodedTransaction, sourceOutputs } = await (0,_transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.buildEncodedTransaction)({\n inputs: fundingUtxos,\n outputs: sendRequests,\n signingKey: privateKey ?? _transaction_Wif_js__WEBPACK_IMPORTED_MODULE_7__.placeholderPrivateKeyBin,\n fee,\n discardChange,\n feePaidBy,\n changeAddress,\n buildUnsigned: options?.buildUnsigned === true,\n walletCache: this.walletCache,\n });\n const categories = [\n ...fundingUtxos\n .filter((val) => val.token?.category)\n .map((val) => val.token.category),\n ...sendRequests\n .filter((val) => val instanceof _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest)\n .map((val) => val.category),\n ].filter((value, index, array) => array.indexOf(value) === index);\n return { encodedTransaction, categories, sourceOutputs };\n }\n // Submit a raw transaction\n async submitTransaction(transaction, awaitPropagation = true) {\n if (!this.provider) {\n throw Error(\"Wallet network provider was not initialized\");\n }\n let rawTransaction = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_9__.binToHex)(transaction);\n return await this.provider.sendRawTransaction(rawTransaction, awaitPropagation);\n }\n // gets transaction history of this wallet\n async getRawHistory(fromHeight = 0, toHeight = -1) {\n throw Error(\"getRawHistory not implemented in BaseWallet\");\n }\n // gets last transaction of this wallet\n async getLastTransaction(confirmedOnly = false) {\n let history = await this.getRawHistory();\n if (confirmedOnly) {\n history = history.filter((val) => val.height > 0);\n }\n if (!history.length) {\n return null;\n }\n const [lastTx] = history.slice(-1);\n return this.provider.getRawTransactionObject(lastTx.tx_hash);\n }\n // waits for next transaction, program execution is halted\n async waitForTransaction(options = {\n getTransactionInfo: true,\n getBalance: false,\n txHash: undefined,\n }) {\n if (options.getTransactionInfo === undefined) {\n options.getTransactionInfo = true;\n }\n return new Promise(async (resolve) => {\n let txHashSeen = false;\n const makeResponse = async (txHash) => {\n const response = {};\n const promises = [undefined, undefined];\n if (options.getBalance === true) {\n promises[0] = this.getBalance();\n }\n if (options.getTransactionInfo === true) {\n if (!txHash) {\n promises[1] = this.getLastTransaction();\n }\n else {\n promises[1] = this.provider.getRawTransactionObject(txHash);\n }\n }\n const result = await Promise.all(promises);\n response.balance = result[0];\n response.transactionInfo = result[1];\n return response;\n };\n // waiting for a specific transaction to propagate\n if (options.txHash) {\n let cancel;\n const waitForTransactionCallback = async (data) => {\n if (data && data[0] === options.txHash && data[1] !== null) {\n txHashSeen = true;\n await cancel?.();\n resolve(makeResponse(options.txHash));\n }\n };\n cancel = await this.provider.subscribeToTransaction(options.txHash, waitForTransactionCallback);\n return;\n }\n // waiting for any address transaction\n let watchCancel;\n let initialResponseSeen = false;\n watchCancel = await this.watchStatus(async (_status) => {\n if (initialResponseSeen) {\n await watchCancel?.();\n resolve(makeResponse());\n return;\n }\n initialResponseSeen = true;\n });\n });\n }\n /**\n * watchBlocks Watch network blocks\n *\n * @param callback callback with a block header object\n * @param skipCurrentHeight if set, the notification about current block will not arrive\n *\n * @returns a function which will cancel watching upon evaluation\n */\n async watchBlocks(callback, skipCurrentHeight = true) {\n return this.provider.watchBlocks(callback, skipCurrentHeight);\n }\n /**\n * waitForBlock Wait for a network block\n *\n * @param height if specified waits for this exact blockchain height, otherwise resolves with the next block\n *\n */\n async waitForBlock(height) {\n return this.provider.waitForBlock(height);\n }\n //#endregion Funds\n //#region Cashtokens\n /**\n * Create new cashtoken, both funglible and/or non-fungible (NFT)\n * Refer to spec https://github.com/bitjson/cashtokens\n * @param {number} genesisRequest.amount amount of *fungible* tokens to create\n * @param {NFTCapability?} genesisRequest.capability capability of new NFT\n * @param {string?} genesisRequest.commitment NFT commitment message\n * @param {string?} genesisRequest.cashaddr cash address to send the created token UTXO to; if undefined will default to your address\n * @param {number?} genesisRequest.value satoshi value to send alongside with tokens; if undefined will default to 1000 satoshi\n * @param {SendRequestType | SendRequestType[]} sendRequests single or an array of extra send requests (OP_RETURN, value transfer, etc.) to include in genesis transaction\n * @param {SendRequestOptionsI} options Options of the send requests\n */\n async tokenGenesis(genesisRequest, sendRequests = [], options) {\n if (!Array.isArray(sendRequests)) {\n sendRequests = [sendRequests];\n }\n let utxos = await this.getUtxos();\n if (options?.utxoIds) {\n utxos = (0,_util_checkUtxos_js__WEBPACK_IMPORTED_MODULE_5__.checkUtxos)(options.utxoIds.map((utxoId) => typeof utxoId === \"string\" ? (0,_model_js__WEBPACK_IMPORTED_MODULE_6__.fromUtxoId)(utxoId) : utxoId), utxos);\n }\n const genesisInputs = utxos.filter((val) => val.vout === 0 && !val.token);\n if (genesisInputs.length === 0) {\n throw new Error(\"No suitable inputs with vout=0 available for new token genesis\");\n }\n const genesisSendRequest = new _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest({\n cashaddr: genesisRequest.cashaddr || this.getTokenDepositAddress(),\n amount: genesisRequest.amount,\n value: genesisRequest.value || 1000n,\n nft: genesisRequest.nft,\n category: genesisInputs[0].txid,\n });\n return this.send([genesisSendRequest, ...sendRequests], {\n ...options,\n utxoIds: utxos,\n ensureUtxos: [genesisInputs[0]],\n checkTokenQuantities: false,\n queryBalance: false,\n tokenOperation: \"genesis\",\n });\n }\n /**\n * Mint new NFT cashtokens using an existing minting token\n * Refer to spec https://github.com/bitjson/cashtokens\n * @param {string} category category of an NFT to mint\n * @param {TokenMintRequest | TokenMintRequest[]} mintRequests mint requests with new token properties and recipients\n * @param {NFTCapability?} mintRequest.capability capability of new NFT\n * @param {string?} mintRequest.commitment NFT commitment message\n * @param {string?} mintRequest.cashaddr cash address to send the created token UTXO to; if undefined will default to your address\n * @param {number?} mintRequest.value satoshi value to send alongside with tokens; if undefined will default to 1000 satoshi\n * @param {boolean?} deductTokenAmount if minting token contains fungible amount, deduct from it by amount of minted tokens\n * @param {SendRequestOptionsI} options Options of the send requests\n */\n async tokenMint(category, mintRequests, deductTokenAmount = false, options) {\n if (category?.length !== 64) {\n throw Error(`Invalid category supplied: ${category}`);\n }\n if (!Array.isArray(mintRequests)) {\n mintRequests = [mintRequests];\n }\n const utxos = await this.getUtxos();\n const nftUtxos = utxos.filter((val) => val.token?.category === category &&\n val.token?.nft?.capability === _interface_js__WEBPACK_IMPORTED_MODULE_13__.NFTCapability.minting);\n if (!nftUtxos.length) {\n throw new Error(\"You do not have any token UTXOs with minting capability for specified category\");\n }\n const newAmount = deductTokenAmount && nftUtxos[0].token.amount > 0\n ? nftUtxos[0].token.amount - BigInt(mintRequests.length)\n : nftUtxos[0].token.amount;\n const safeNewAmount = newAmount < 0n ? 0n : newAmount;\n const mintingInput = new _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest({\n cashaddr: (0,_util_index_js__WEBPACK_IMPORTED_MODULE_11__.toTokenaddr)(nftUtxos[0].address),\n category: category,\n nft: nftUtxos[0].token?.nft,\n amount: safeNewAmount,\n value: nftUtxos[0].satoshis,\n });\n return this.send([\n mintingInput,\n ...mintRequests.map((val) => new _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest({\n cashaddr: val.cashaddr || this.getTokenDepositAddress(),\n amount: 0n,\n category: category,\n value: val.value,\n nft: val.nft,\n })),\n ], {\n ...options,\n ensureUtxos: [nftUtxos[0]],\n checkTokenQuantities: false,\n queryBalance: false,\n tokenOperation: \"mint\",\n });\n }\n /**\n * Perform an explicit token burning by spending a token utxo to an OP_RETURN\n *\n * Behaves differently for fungible and non-fungible tokens:\n * * NFTs are always \"destroyed\"\n * * FTs' amount is reduced by the amount specified, if 0 FT amount is left and no NFT present, the token is \"destroyed\"\n *\n * Refer to spec https://github.com/bitjson/cashtokens\n * @param {string} burnRequest.category category of a token to burn\n * @param {NFTCapability} burnRequest.capability capability of the NFT token to select, optional\n * @param {string?} burnRequest.commitment commitment of the NFT token to select, optional\n * @param {number?} burnRequest.amount amount of fungible tokens to burn, optional\n * @param {string?} burnRequest.cashaddr address to return token and satoshi change to\n * @param {string?} message optional message to include in OP_RETURN\n * @param {SendRequestOptionsI} options Options of the send requests\n */\n async tokenBurn(burnRequest, message, options) {\n if (burnRequest.category?.length !== 64) {\n throw Error(`Invalid category supplied: ${burnRequest.category}`);\n }\n const utxos = await this.getUtxos();\n const tokenUtxos = utxos.filter((val) => val.token?.category === burnRequest.category &&\n val.token?.nft?.capability === burnRequest.nft?.capability &&\n val.token?.nft?.commitment === burnRequest.nft?.commitment);\n if (!tokenUtxos.length) {\n throw new Error(\"You do not have suitable token UTXOs to perform burn\");\n }\n const totalFungibleAmount = tokenUtxos.reduce((prev, cur) => prev + (cur.token?.amount || 0n), 0n);\n let fungibleBurnAmount = burnRequest.amount && burnRequest.amount > 0 ? burnRequest.amount : 0n;\n fungibleBurnAmount = BigInt(fungibleBurnAmount);\n const hasNFT = burnRequest.nft !== undefined;\n let utxoIds = [];\n let changeSendRequests;\n if (hasNFT) {\n // does not have FT tokens, let us destroy the token completely\n if (totalFungibleAmount === 0n) {\n changeSendRequests = [];\n utxoIds.push(tokenUtxos[0]);\n }\n else {\n // add utxos to spend from\n let available = 0n;\n for (const token of tokenUtxos.filter((val) => val.token?.amount)) {\n utxoIds.push(token);\n available += token.token.amount;\n if (available >= fungibleBurnAmount) {\n break;\n }\n }\n // if there are FT, reduce their amount\n const newAmount = totalFungibleAmount - fungibleBurnAmount;\n const safeNewAmount = newAmount < 0n ? 0n : newAmount;\n changeSendRequests = [\n new _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest({\n cashaddr: burnRequest.cashaddr || (0,_util_index_js__WEBPACK_IMPORTED_MODULE_11__.toTokenaddr)(this.getChangeAddress()),\n category: burnRequest.category,\n nft: burnRequest.nft,\n amount: safeNewAmount,\n value: tokenUtxos[0].satoshis,\n }),\n ];\n }\n }\n else {\n // if we are burning last fungible tokens, let us destroy the token completely\n if (totalFungibleAmount === fungibleBurnAmount) {\n changeSendRequests = [];\n utxoIds.push(...tokenUtxos);\n }\n else {\n // add utxos to spend from\n let available = 0n;\n for (const token of tokenUtxos.filter((val) => val.token?.amount)) {\n utxoIds.push(token);\n available += token.token.amount;\n if (available >= fungibleBurnAmount) {\n break;\n }\n }\n // reduce the FT amount\n const newAmount = available - fungibleBurnAmount;\n const safeNewAmount = newAmount < 0n ? 0n : newAmount;\n changeSendRequests = [\n new _model_js__WEBPACK_IMPORTED_MODULE_6__.TokenSendRequest({\n cashaddr: burnRequest.cashaddr || (0,_util_index_js__WEBPACK_IMPORTED_MODULE_11__.toTokenaddr)(this.getChangeAddress()),\n category: burnRequest.category,\n amount: safeNewAmount,\n value: tokenUtxos.reduce((a, c) => a + c.satoshis, 0n),\n }),\n ];\n }\n }\n const opReturn = _model_js__WEBPACK_IMPORTED_MODULE_6__.OpReturnData.fromString(message || \"\");\n return this.send([opReturn, ...changeSendRequests], {\n ...options,\n checkTokenQuantities: false,\n queryBalance: false,\n ensureUtxos: utxoIds.length > 0 ? utxoIds : undefined,\n tokenOperation: \"burn\",\n });\n }\n /**\n * getTokenUtxos Get unspent token outputs for the wallet\n * will return utxos only for the specified token if `category` provided\n * @param {string?} category category to filter utxos by, if not set will return utxos from all tokens\n * @returns {Utxo[]} token utxos\n */\n async getTokenUtxos(category) {\n const utxos = await this.getUtxos();\n return utxos.filter((val) => category ? val.token?.category === category : val.token);\n }\n /**\n * getTokenBalance Gets fungible token balance\n * for NFT token balance see @ref getNftTokenBalance\n * @param {string} category category to get balance for\n * @returns {bigint} fungible token balance\n */\n async getTokenBalance(category) {\n const utxos = (await this.getTokenUtxos(category)).filter((val) => val.token?.amount);\n return (0,_util_index_js__WEBPACK_IMPORTED_MODULE_8__.sumTokenAmounts)(utxos, category);\n }\n /**\n * getNftTokenBalance Gets non-fungible token (NFT) balance for a particular category\n * disregards fungible token balances\n * for fungible token balance see @ref getTokenBalance\n * @param {string} category category to get balance for\n * @returns {number} non-fungible token balance\n */\n async getNftTokenBalance(category) {\n const utxos = (await this.getTokenUtxos(category)).filter((val) => val.token?.nft?.commitment !== undefined);\n return utxos.length;\n }\n /**\n * getAllTokenBalances Gets all fungible token balances in this wallet\n * @returns {Object} a map [category => balance] for all tokens in this wallet\n */\n async getAllTokenBalances() {\n const result = {};\n const utxos = (await this.getTokenUtxos()).filter((val) => val.token?.amount);\n for (const utxo of utxos) {\n if (!result[utxo.token.category]) {\n result[utxo.token.category] = 0n;\n }\n result[utxo.token.category] += utxo.token.amount;\n }\n return result;\n }\n /**\n * getAllNftTokenBalances Gets all non-fungible token (NFT) balances in this wallet\n * @returns {Object} a map [category => balance] for all NFTs in this wallet\n */\n async getAllNftTokenBalances() {\n const result = {};\n const utxos = (await this.getTokenUtxos()).filter((val) => val.token?.nft?.commitment !== undefined);\n for (const utxo of utxos) {\n if (!result[utxo.token.category]) {\n result[utxo.token.category] = 0;\n }\n result[utxo.token.category] += 1;\n }\n return result;\n }\n //#endregion Cashtokens\n sign(message, privateKey = undefined) {\n if (!privateKey) {\n throw new Error(\"Signing private key not provided\");\n }\n return new _message_signed_js__WEBPACK_IMPORTED_MODULE_14__.SignedMessage().sign(message, privateKey);\n }\n // Convenience wrapper to verify interface\n verify(message, sig, address, publicKey) {\n if (!address && !publicKey) {\n throw new Error(\"Either address or publicKey must be provided for verification\");\n }\n return new _message_signed_js__WEBPACK_IMPORTED_MODULE_14__.SignedMessage().verify(message, sig, address, publicKey);\n }\n}\n/**\n * _checkContextSafety (internal) if running in nodejs, will disable saving\n * mainnet wallets on public servers if ALLOW_MAINNET_USER_WALLETS is set to false\n * @param {BaseWallet} wallet a wallet\n */\nconst _checkContextSafety = function (wallet) {\n if ((0,_util_index_js__WEBPACK_IMPORTED_MODULE_15__.getRuntimePlatform)() === \"node\") {\n if (process.env.ALLOW_MAINNET_USER_WALLETS === `false`) {\n if (wallet.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet) {\n throw Error(`Refusing to save wallet in an open public database, remove ALLOW_MAINNET_USER_WALLETS=\"false\", if this service is secure and private`);\n }\n }\n }\n};\n/**\n * getNamedWalletId - get the full wallet id from the database\n *\n * @param name user friendly wallet alias\n * @param dbName name under which the wallet will be stored in the database\n *\n * @returns boolean\n */\nasync function getNamedWalletId(name, dbName) {\n if (name.length === 0) {\n throw Error(\"Named wallets must have a non-empty name\");\n }\n dbName = dbName ? dbName : dbName;\n let db = getStorageProvider(dbName);\n if (db) {\n await db.init();\n let savedWalletRecord = await db.getWallet(name);\n await db.close();\n if (savedWalletRecord !== undefined) {\n return savedWalletRecord.wallet;\n }\n else {\n throw Error(`No record was found for ${name} in db: ${dbName}`);\n }\n }\n else {\n throw Error(\"No database was available or configured to store the named wallet.\");\n }\n}\nfunction getStorageProvider(dbName) {\n if (!BaseWallet.StorageProvider) {\n return undefined;\n }\n return new BaseWallet.StorageProvider(dbName);\n}\n\n__webpack_async_result__();\n} catch(e) { __webpack_async_result__(e); } });\n\n//# sourceURL=webpack://mainnet-js/./src/wallet/Base.ts?");
638
638
 
639
639
  /***/ }),
640
640
 
@@ -644,7 +644,7 @@ eval("__webpack_require__.a(module, async (__webpack_handle_async_dependencies__
644
644
  \********************************/
645
645
  /***/ ((module, __webpack_exports__, __webpack_require__) => {
646
646
 
647
- eval("__webpack_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"GAP_SIZE\": () => (/* binding */ GAP_SIZE),\n/* harmony export */ \"HDWallet\": () => (/* binding */ HDWallet),\n/* harmony export */ \"RegTestHDWallet\": () => (/* binding */ RegTestHDWallet),\n/* harmony export */ \"TestNetHDWallet\": () => (/* binding */ TestNetHDWallet)\n/* harmony export */ });\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/address/cash-address.js\");\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/key/bip39.js\");\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/key/hd-key.js\");\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/format/error.js\");\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/format/hex.js\");\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/crypto/default-crypto-instances.js\");\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/format/utf8.js\");\n/* harmony import */ var _cache_index_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../cache/index.js */ \"./src/cache/walletCache.ts\");\n/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ \"./src/config.ts\");\n/* harmony import */ var _enum_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../enum.js */ \"./src/enum.ts\");\n/* harmony import */ var _history_getHistory_js__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../history/getHistory.js */ \"./src/history/getHistory.ts\");\n/* harmony import */ var _util_checkForEmptySeed_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../util/checkForEmptySeed.js */ \"./src/util/checkForEmptySeed.ts\");\n/* harmony import */ var _Base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Base.js */ \"./src/wallet/Base.ts\");\n/* harmony import */ var _enum_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./enum.js */ \"./src/wallet/enum.ts\");\n/* harmony import */ var _util_hd_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../util/hd.js */ \"./src/util/hd.ts\");\n/* harmony import */ var _constant_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../constant.js */ \"./src/constant.ts\");\n/* harmony import */ var _util_sumUtxoValue_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../util/sumUtxoValue.js */ \"./src/util/sumUtxoValue.ts\");\nvar __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_Base_js__WEBPACK_IMPORTED_MODULE_0__, _enum_js__WEBPACK_IMPORTED_MODULE_2__, _bitauth_libauth__WEBPACK_IMPORTED_MODULE_5__, _util_checkForEmptySeed_js__WEBPACK_IMPORTED_MODULE_6__, _bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__, _bitauth_libauth__WEBPACK_IMPORTED_MODULE_10__, _cache_index_js__WEBPACK_IMPORTED_MODULE_12__, _history_getHistory_js__WEBPACK_IMPORTED_MODULE_16__]);\n([_Base_js__WEBPACK_IMPORTED_MODULE_0__, _enum_js__WEBPACK_IMPORTED_MODULE_2__, _bitauth_libauth__WEBPACK_IMPORTED_MODULE_5__, _util_checkForEmptySeed_js__WEBPACK_IMPORTED_MODULE_6__, _bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__, _bitauth_libauth__WEBPACK_IMPORTED_MODULE_10__, _cache_index_js__WEBPACK_IMPORTED_MODULE_12__, _history_getHistory_js__WEBPACK_IMPORTED_MODULE_16__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);\n\n\n\n\n\n\n\n\n\n\n\nconst GAP_SIZE = 20;\nclass HDWallet extends _Base_js__WEBPACK_IMPORTED_MODULE_0__.BaseWallet {\n static { this.networkPrefix = _bitauth_libauth__WEBPACK_IMPORTED_MODULE_1__.CashAddressNetworkPrefix.mainnet; }\n get networkPrefix() {\n return _enum_js__WEBPACK_IMPORTED_MODULE_2__.prefixFromNetworkMap[this.network];\n }\n /// Create an uninitialized HDWallet, this method should not be called directly\n /// Instead static methods such as `newRandom` or `fromSeed` should be used\n constructor(network = _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet) {\n super(network);\n this.derivation = _config_js__WEBPACK_IMPORTED_MODULE_3__.Config.DefaultParentDerivationPath;\n // Callback type for wallet activity watching\n this.walletWatchCallbacks = [];\n // max index used for deposit address derivation\n this.depositIndex = 0;\n // max index used for change address derivation\n this.changeIndex = 0;\n this.depositWatchCancels = [];\n this.changeWatchCancels = [];\n this.depositStatuses = [];\n this.changeStatuses = [];\n this.depositUtxos = [];\n this.changeUtxos = [];\n this.depositRawHistory = [];\n this.changeRawHistory = [];\n this.watchPromise = undefined;\n // @ts-ignore\n this.walletType = _enum_js__WEBPACK_IMPORTED_MODULE_4__.WalletTypeEnum.Hd;\n }\n /// Initialize the wallet given the options mnemonic, xPriv or xPub\n /// If none provided, a new random mnemonic will be generated\n /// If mnemonic or xPriv provided, the wallet will be able to sign transactions\n /// If xPub provided, the wallet will be watch-only\n /// This internal method is called by the various static constructors\n async initialize({ name = \"\", depositIndex = 0, changeIndex = 0, mnemonic = undefined, derivation = undefined, xPriv = undefined, xPub = undefined, } = {}) {\n // newRandom\n if (!xPriv && !xPub && !mnemonic) {\n mnemonic = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_5__.generateBip39Mnemonic)();\n }\n this.depositIndex = depositIndex;\n this.changeIndex = changeIndex;\n // @ts-ignore\n this.xPub = xPub ? xPub : \"\";\n if (mnemonic?.length) {\n // @ts-ignore\n this.derivation = derivation\n ? derivation\n : _config_js__WEBPACK_IMPORTED_MODULE_3__.Config.DefaultParentDerivationPath;\n // @ts-ignore\n this.mnemonic = mnemonic ? mnemonic : (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_5__.generateBip39Mnemonic)();\n if (this.mnemonic.length == 0) {\n throw Error(\"refusing to create wallet from empty mnemonic\");\n }\n if (![12, 24].includes(this.mnemonic.split(\" \").length)) {\n throw Error(\"Invalid mnemonic, must be 12 or 24 words\");\n }\n const seed = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_5__.deriveSeedFromBip39Mnemonic)(this.mnemonic);\n (0,_util_checkForEmptySeed_js__WEBPACK_IMPORTED_MODULE_6__.checkForEmptySeed)(seed);\n const rootNode = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.deriveHdPrivateNodeFromSeed)(seed, {\n assumeValidity: true,\n throwErrors: true,\n });\n const node = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.deriveHdPath)(rootNode, this.derivation);\n // @ts-ignore\n this.xPriv = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_8__.assertSuccess)((0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.encodeHdPrivateKey)({\n ...node,\n network: this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\",\n node: node,\n })).hdPrivateKey;\n // @ts-ignore\n this.xPrivNode = node;\n // @ts-ignore\n this.xPubNode = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.deriveHdPublicNode)(node);\n // @ts-ignore\n this.xPub = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_8__.assertSuccess)((0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.encodeHdPublicKey)({\n node: this.xPubNode,\n network: this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\",\n })).hdPublicKey;\n }\n else if (xPriv) {\n // @ts-ignore\n this.xPriv = xPriv;\n const decoded = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_8__.assertSuccess)((0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.decodeHdPrivateKey)(xPriv));\n if (decoded.network !==\n (this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\")) {\n throw new Error(`xPriv network (${decoded.network}) does not match wallet network (${this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\"})`);\n }\n // @ts-ignore\n this.xPrivNode = decoded.node;\n // @ts-ignore\n this.xPubNode = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.deriveHdPublicNode)(decoded.node);\n // @ts-ignore\n this.xPub = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_8__.assertSuccess)((0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.encodeHdPublicKey)({\n node: this.xPubNode,\n network: this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\",\n })).hdPublicKey;\n }\n else if (xPub) {\n const decoded = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_8__.assertSuccess)((0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.decodeHdPublicKey)(xPub));\n if (decoded.network !==\n (this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\")) {\n throw new Error(`xPriv network (${decoded.network}) does not match wallet network (${this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\"})`);\n }\n // @ts-ignore\n this.xPubNode = decoded.node;\n // @ts-ignore\n this.xPub = xPub;\n }\n else {\n throw new Error(\"mnemonic, xPriv or xPub must be provided to create an HDWallet\");\n }\n this.name = name;\n // @ts-ignore\n this.walletId = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_9__.binToHex)(_bitauth_libauth__WEBPACK_IMPORTED_MODULE_10__.sha256.hash((0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_11__.utf8ToBin)(`${(this.mnemonic ? this.mnemonic + this.derivation : undefined) ??\n this.xPriv ??\n this.xPub}-${this.network}`)));\n // @ts-ignore\n this.walletCache = new _cache_index_js__WEBPACK_IMPORTED_MODULE_12__.PersistentWalletCache(this.walletId, this.xPrivNode ?? this.xPubNode, this.networkPrefix);\n // init wallet cache\n await this.walletCache.init();\n // start watching addresses asynchronously\n this.watchPromise = this.makeWatchPromise().catch(() => { });\n return this;\n }\n /// Stops the wallet from watching for address changes\n /// After calling this method, the wallet will no longer update and is considered defunct\n async stop() {\n await Promise.all([\n super.stop(),\n ...this.depositWatchCancels.map((fn) => fn?.()),\n ...this.changeWatchCancels.map((fn) => fn?.()),\n ]);\n this.depositWatchCancels = [];\n this.changeWatchCancels = [];\n this.walletWatchCallbacks = [];\n }\n /// Scan more addresses for activity beyond the current gap limit, extending the watched range as needed\n async scanMoreAddresses(amount = GAP_SIZE) {\n await this.watchPromise;\n this.watchPromise = this.makeWatchPromise(amount);\n await this.watchPromise;\n }\n /// Internal method to start watching addresses for activity, extending the watched range as needed\n async makeWatchPromise(gapSize = GAP_SIZE) {\n await this.watchPromise;\n let needsMore = true;\n while (needsMore) {\n await Promise.all([\n this.watchAddressType(false, gapSize),\n this.watchAddressType(true, gapSize),\n ]);\n // Check if we have a full gap of addresses beyond the last used index\n const depositGap = this.depositStatuses.length - this.depositIndex;\n const changeGap = this.changeStatuses.length - this.changeIndex;\n needsMore = depositGap < gapSize || changeGap < gapSize;\n }\n }\n /// Watch addresses of a specific type (deposit or change) for activity\n async watchAddressType(isChange, gapSize) {\n // Select the appropriate arrays based on address type\n const statuses = isChange ? this.changeStatuses : this.depositStatuses;\n const utxosArray = isChange ? this.changeUtxos : this.depositUtxos;\n const historyArray = isChange\n ? this.changeRawHistory\n : this.depositRawHistory;\n const watchCancels = isChange\n ? this.changeWatchCancels\n : this.depositWatchCancels;\n const getCurrentIndex = () => isChange ? this.changeIndex : this.depositIndex;\n const setCurrentIndex = (val) => {\n if (isChange) {\n this.changeIndex = val;\n }\n else {\n this.depositIndex = val;\n }\n };\n const startIndex = statuses.length;\n const stopIndex = getCurrentIndex() + gapSize;\n const addresses = (0,_util_hd_js__WEBPACK_IMPORTED_MODULE_13__.arrayRange)(startIndex, stopIndex).map((i) => this.walletCache.getByIndex(i, isChange).address);\n await Promise.all(addresses.map(async (addr, idx) => new Promise(async (resolve) => {\n const index = startIndex + idx;\n if (statuses[index] !== undefined) {\n resolve();\n return;\n }\n const { status: prevStatus, utxos: prevUtxos, rawHistory: prevRawHistory, lastConfirmedHeight: prevLastConfirmedHeight, } = this.walletCache.getByIndex(index, isChange);\n statuses[index] = prevStatus;\n utxosArray[index] = prevUtxos;\n historyArray[index] = prevRawHistory;\n // Track lastConfirmedHeight in closure, updated after each fetch\n let lastConfirmedHeight = prevLastConfirmedHeight;\n const callback = async (args) => {\n const [address, status] = args;\n if (address != addr) {\n return;\n }\n if (status === null) {\n utxosArray[index] = [];\n historyArray[index] = [];\n }\n if (status !== null && status !== statuses[index]) {\n // Use lastConfirmedHeight from closure for incremental fetch\n const fromHeight = lastConfirmedHeight;\n const currentHistory = historyArray[index] || [];\n const [utxos, newHistory] = await Promise.all([\n this.provider.getUtxos(addr).then((utxos) => utxos.map((utxo) => {\n utxo.address = addr;\n return utxo;\n })),\n // Fetch only from last confirmed height to reduce server load\n this.provider.getHistory(addr, fromHeight),\n ]);\n // Merge: keep confirmed items from current history, add new items\n const confirmedFromHistory = currentHistory.filter((tx) => tx.height > 0 && tx.height < fromHeight);\n const seen = new Set(confirmedFromHistory.map((tx) => tx.tx_hash));\n const merged = [...confirmedFromHistory];\n for (const tx of newHistory) {\n if (!seen.has(tx.tx_hash)) {\n seen.add(tx.tx_hash);\n merged.push(tx);\n }\n }\n // Update lastConfirmedHeight in closure\n lastConfirmedHeight = merged.reduce((max, tx) => (tx.height > 0 ? Math.max(max, tx.height) : max), fromHeight);\n utxosArray[index] = utxos;\n historyArray[index] = merged;\n this.walletCache.setStatusAndUtxos(addr, status, utxos, merged, lastConfirmedHeight);\n }\n statuses[index] = status;\n if (status !== null) {\n const newIndex = index + 1;\n if (newIndex > getCurrentIndex()) {\n setCurrentIndex(newIndex);\n }\n // Maintain the gap: extend watched range if it shrank\n const gap = statuses.length - getCurrentIndex();\n if (gap < gapSize) {\n await this.watchAddressType(isChange, gapSize);\n }\n }\n // Notify wallet watchers of the status change\n this.notifyWalletWatchers(status, addr);\n resolve();\n };\n watchCancels[index] = await this.provider.subscribeToAddress(addr, callback);\n })));\n return addresses.length;\n }\n // Return wallet info\n getInfo() {\n return {\n isTestnet: this.isTestnet,\n name: this.name,\n network: this.network,\n seed: this.mnemonic,\n walletId: this.toString(),\n walletDbEntry: this.toDbString(),\n };\n }\n /// Internal method called when any address status changes\n notifyWalletWatchers(status, address) {\n for (const callback of this.walletWatchCallbacks) {\n try {\n callback(status, address);\n }\n catch (e) {\n // Ignore callback errors to not break other watchers\n }\n }\n }\n /**\n * Watch wallet for any activity (status changes on any address)\n * This is the foundation for watchWalletBalance and watchWalletTransactions\n * @param callback - Called when any address in the wallet has a status change\n * @returns Cancel function to stop watching\n */\n async watchStatus(callback, debounce = 100) {\n await this.watchPromise;\n let debounceTimer;\n let pendingStatus = null;\n let pendingAddress = \"\";\n const debouncedCallback = (status, address) => {\n pendingStatus = status;\n pendingAddress = address;\n if (debounceTimer)\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n debounceTimer = undefined;\n callback(pendingStatus, pendingAddress);\n }, debounce);\n };\n this.walletWatchCallbacks.push(debouncedCallback);\n return async () => {\n if (debounceTimer)\n clearTimeout(debounceTimer);\n const index = this.walletWatchCallbacks.indexOf(debouncedCallback);\n if (index > -1) {\n this.walletWatchCallbacks.splice(index, 1);\n }\n };\n }\n /**\n * Watch wallet for new transactions (HD wallet override)\n *\n * Uses unfiltered history so that seenTxHashes always covers all known\n * transactions, including those from newly discovered addresses when\n * depositIndex/changeIndex extends and widens getRawHistory's scope.\n */\n async watchTransactionHashes(callback) {\n const seenTxHashes = new Set();\n return this.watchStatus(async () => {\n const history = await this.getRawHistory();\n const newTxHashes = [];\n for (const tx of history) {\n if (!seenTxHashes.has(tx.tx_hash)) {\n seenTxHashes.add(tx.tx_hash);\n newTxHashes.push(tx.tx_hash);\n }\n }\n if (newTxHashes.length > 0) {\n newTxHashes.forEach((txHash) => callback(txHash));\n }\n });\n }\n /**\n * utxos Get unspent outputs for the wallet\n *\n */\n async getUtxos() {\n await this.watchPromise;\n const utxos = [...this.depositUtxos, ...this.changeUtxos].flat();\n return this._slpSemiAware\n ? utxos.filter((u) => u.satoshis > _constant_js__WEBPACK_IMPORTED_MODULE_14__.DUST_UTXO_THRESHOLD)\n : utxos;\n }\n // Gets balance by summing value in all utxos in sats\n // Balance includes DUST utxos which could be slp tokens and also cashtokens with BCH amounts\n async getBalance() {\n await this.watchPromise;\n const utxos = [...this.depositUtxos, ...this.changeUtxos].flat();\n return (0,_util_sumUtxoValue_js__WEBPACK_IMPORTED_MODULE_15__.sumUtxoValue)(utxos);\n }\n /// Get next unused deposit address, or the address at the specified index\n getDepositAddress(index = -1) {\n index = (0,_util_hd_js__WEBPACK_IMPORTED_MODULE_13__.getNextUnusedIndex)(index, this.depositStatuses);\n return this.walletCache.getByIndex(index, false).address;\n }\n /// Get next unused token deposit address, or the token address at the specified index\n getTokenDepositAddress(index = -1) {\n index = (0,_util_hd_js__WEBPACK_IMPORTED_MODULE_13__.getNextUnusedIndex)(index, this.depositStatuses);\n return this.walletCache.getByIndex(index, false).tokenAddress;\n }\n /// Get next unused change address, or the address at the specified index\n getChangeAddress(index = -1) {\n index = (0,_util_hd_js__WEBPACK_IMPORTED_MODULE_13__.getNextUnusedIndex)(index, this.changeStatuses);\n return this.walletCache.getByIndex(index, true).address;\n }\n /// Get next unused token change address, or the token address at the specified index\n getChangeTokenAddress(index = -1) {\n index = (0,_util_hd_js__WEBPACK_IMPORTED_MODULE_13__.getNextUnusedIndex)(index, this.changeStatuses);\n return this.walletCache.getByIndex(index, true).tokenAddress;\n }\n hasAddress(address) {\n return this.walletCache.get(address) !== undefined;\n }\n /**\n * fromSeed - create a wallet using the seed phrase and derivation path\n *\n * unless specified the derivation path m/44'/0'/0'/0/0 will be used\n *\n * @param seed BIP39 12 word seed phrase\n * @param derivationPath BIP44 HD wallet derivation path to get a single the private key from hierarchy\n *\n * @returns instantiated wallet\n */\n static async fromSeed(seed, derivationPath, depositIndex, changeIndex) {\n return new this().initialize({\n mnemonic: seed,\n derivation: derivationPath,\n depositIndex: depositIndex,\n changeIndex: changeIndex,\n });\n }\n /**\n * newRandom - create a random wallet\n *\n * if `name` parameter is specified, the wallet will also be persisted to DB\n *\n * @param name user friendly wallet alias\n * @param dbName name under which the wallet will be stored in the database\n *\n * @returns instantiated wallet\n */\n static async newRandom(name = \"\", dbName) {\n dbName = dbName ? dbName : this.networkPrefix;\n if (name.length > 0) {\n return this.named(name, dbName);\n }\n return new this().initialize();\n }\n /**\n * fromXPub - create a watch-only wallet using the HD Wallet Public key\n *\n * @param xPub HD Wallet Public Key\n *\n * @returns instantiated wallet\n */\n static async fromXPub(xPub) {\n return new this().initialize({\n xPub: xPub,\n });\n }\n /**\n * fromXPriv - create a wallet using the HD Wallet Private key\n *\n * @param xPub HD Wallet Private Key\n *\n * @returns instantiated wallet\n */\n static async fromXPriv(xPriv) {\n return new this().initialize({\n xPriv: xPriv,\n });\n }\n /**\n * fromId - create a wallet from encoded walletId string\n *\n * @param walletId walletId options to steer the creation process\n *\n * @returns wallet instantiated accordingly to the walletId rules\n */\n static async fromId(walletId) {\n return new this().fromId(walletId);\n }\n /// override the base class fromId method implementation\n async fromId(walletId) {\n const [walletType, networkGiven, arg1, arg2, arg3, arg4] = walletId.split(\":\");\n if (this.network != networkGiven) {\n throw Error(`Network prefix ${networkGiven} to a ${this.network} wallet`);\n }\n if (walletType === _enum_js__WEBPACK_IMPORTED_MODULE_4__.WalletTypeEnum.Named) {\n if (arg2) {\n // named:testnet:wallet_1:my_database\n return this.named(arg1, arg2);\n }\n else {\n // named:testnet:wallet_1\n return this.named(arg1);\n }\n }\n if (walletType !== _enum_js__WEBPACK_IMPORTED_MODULE_4__.WalletTypeEnum.Hd) {\n throw Error(`fromId called on a ${walletType} wallet, expected a ${_enum_js__WEBPACK_IMPORTED_MODULE_4__.WalletTypeEnum.Hd} wallet`);\n }\n if (arg1.startsWith(\"priv\", 1)) {\n return this.initialize({\n xPriv: arg1,\n depositIndex: parseInt(arg2) || 0,\n changeIndex: parseInt(arg3) || 0,\n });\n }\n if (arg1.startsWith(\"pub\", 1)) {\n return this.initialize({\n xPub: arg1,\n depositIndex: parseInt(arg2) || 0,\n changeIndex: parseInt(arg3) || 0,\n });\n }\n return this.initialize({\n mnemonic: arg1,\n derivation: arg2,\n depositIndex: parseInt(arg3) || 0,\n changeIndex: parseInt(arg4) || 0,\n });\n }\n /**\n * encodeTransaction Encode and sign a transaction given a list of sendRequests, options and estimate fees.\n * @param {SendRequest[]} sendRequests SendRequests\n * @param {boolean} discardChange=false\n * @param {SendRequestOptionsI} options Options of the send requests\n */\n async encodeTransaction(requests, discardChange = false, options, privateKey) {\n if (!this.xPriv && !privateKey && options?.buildUnsigned !== true) {\n throw new Error(`Missing private key`);\n }\n return super.encodeTransaction(requests, discardChange, options, privateKey);\n }\n //#region Serialization\n // Returns the serialized wallet as a string\n // If storing in a database, set asNamed to false to store secrets\n // In all other cases, the a named wallet is deserialized from the database\n // by the name key\n toString() {\n if (this.name) {\n return `named:${this.network}:${this.name}`;\n }\n return this.toDbString();\n }\n /**\n * toDbString - store the serialized version of the wallet in the database, not just the name\n *\n * @throws {Error} if called on BaseWallet\n */\n toDbString() {\n if (this.walletType == _enum_js__WEBPACK_IMPORTED_MODULE_4__.WalletTypeEnum.Hd) {\n if (this.mnemonic?.length > 0) {\n return `${this.walletType}:${this.network}:${this.mnemonic}:${this.derivation}:${this.depositIndex}:${this.changeIndex}`;\n }\n if (this.xPriv?.length > 0) {\n return `${this.walletType}:${this.network}:${this.xPriv}:${this.depositIndex}:${this.changeIndex}`;\n }\n if (this.xPub?.length > 0) {\n return `${this.walletType}:${this.network}:${this.xPub}:${this.depositIndex}:${this.changeIndex}`;\n }\n throw Error(\"HDWallet has no mnemonic, xPriv or xPub to serialize\");\n }\n throw Error(\"toDbString unsupported wallet type\");\n }\n //#endregion Serialization\n /**\n * getHistory gets transaction history of this wallet with most data decoded and ready to present to user\n * @note balance calculations are valid only if querying to the blockchain tip (`toHeight` === -1, `count` === -1)\n * @note this method is heavy on network calls, if invoked in browser use of cache is advised, @see `Config.UseLocalStorageCache`\n * @note this method tries to recreate the history tab view of Electron Cash wallet, however, it may not be 100% accurate if the tnransaction value changes are the same in the same block (ordering)\n *\n * @param unit optional, BCH or currency unit to present balance and balance changes. If unit is currency like USD or EUR, balances will be subject to possible rounding errors. Default 0\n * @param fromHeight optional, if set, history will be limited. Default 0\n * @param toHeight optional, if set, history will be limited. Default -1, meaning that all history items will be returned, including mempool\n * @param start optional, if set, the result set will be paginated with offset `start`\n * @param count optional, if set, the result set will be paginated with `count`. Default -1, meaning that all history items will be returned\n *\n * @returns an array of transaction history items, with input values and addresses encoded in cashaddress format. @see `TransactionHistoryItem` type\n */\n async getHistory({ unit = \"sat\", fromHeight = 0, toHeight = -1, start = 0, count = -1, }) {\n const rawHistory = await this.getRawHistory(fromHeight, toHeight);\n const addresses = this.getUsedAddresses();\n return (0,_history_getHistory_js__WEBPACK_IMPORTED_MODULE_16__.getHistory)({\n addresses: addresses,\n provider: this.provider,\n unit,\n fromHeight,\n toHeight,\n start,\n count,\n rawHistory,\n });\n }\n // get all used addresses (deposit and change) for this wallet\n getUsedAddresses() {\n return [\n ...this.depositStatuses\n .map((status, i) => status !== null && i < this.depositIndex\n ? this.walletCache.getByIndex(i, false).address\n : undefined)\n .filter((address) => address !== undefined),\n ...this.changeStatuses\n .map((status, i) => status !== null && i < this.changeIndex\n ? this.walletCache.getByIndex(i, true).address\n : undefined)\n .filter((address) => address !== undefined),\n ];\n }\n // gets transaction history of this wallet\n async getRawHistory(fromHeight = 0, toHeight = -1) {\n await this.watchPromise;\n // Collect cached raw history from deposit and change addresses\n const historyArrays = [\n ...this.depositRawHistory.slice(0, this.depositIndex),\n ...this.changeRawHistory.slice(0, this.changeIndex),\n ];\n // Deduplicate by tx_hash\n const seen = new Set();\n let history = [];\n for (const arr of historyArrays) {\n for (const tx of arr) {\n if (!seen.has(tx.tx_hash)) {\n seen.add(tx.tx_hash);\n history.push(tx);\n }\n }\n }\n // Apply height filters if specified\n if (fromHeight > 0 || toHeight !== -1) {\n history = history.filter((tx) => {\n // Unconfirmed transactions (height <= 0) pass the filter when toHeight is -1\n if (tx.height <= 0) {\n return toHeight === -1;\n }\n const aboveFrom = tx.height >= fromHeight;\n const belowTo = toHeight === -1 || tx.height <= toHeight;\n return aboveFrom && belowTo;\n });\n }\n // Sort by height (descending, unconfirmed first)\n return history.sort((a, b) => {\n if (a.height <= 0 && b.height > 0)\n return -1;\n if (b.height <= 0 && a.height > 0)\n return 1;\n return b.height - a.height;\n });\n }\n}\n/**\n * Class to manage a testnet wallet.\n */\nclass TestNetHDWallet extends HDWallet {\n static { this.networkPrefix = _bitauth_libauth__WEBPACK_IMPORTED_MODULE_1__.CashAddressNetworkPrefix.testnet; }\n constructor() {\n super(_enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Testnet);\n }\n}\n/**\n * Class to manage a regtest wallet.\n */\nclass RegTestHDWallet extends HDWallet {\n static { this.networkPrefix = _bitauth_libauth__WEBPACK_IMPORTED_MODULE_1__.CashAddressNetworkPrefix.regtest; }\n constructor() {\n super(_enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Regtest);\n }\n}\n\n__webpack_async_result__();\n} catch(e) { __webpack_async_result__(e); } });\n\n//# sourceURL=webpack://mainnet-js/./src/wallet/HDWallet.ts?");
647
+ eval("__webpack_require__.a(module, async (__webpack_handle_async_dependencies__, __webpack_async_result__) => { try {\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"GAP_SIZE\": () => (/* binding */ GAP_SIZE),\n/* harmony export */ \"HDWallet\": () => (/* binding */ HDWallet),\n/* harmony export */ \"RegTestHDWallet\": () => (/* binding */ RegTestHDWallet),\n/* harmony export */ \"TestNetHDWallet\": () => (/* binding */ TestNetHDWallet)\n/* harmony export */ });\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/address/cash-address.js\");\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/key/bip39.js\");\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/key/hd-key.js\");\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/format/error.js\");\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/format/hex.js\");\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/crypto/default-crypto-instances.js\");\n/* harmony import */ var _bitauth_libauth__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @bitauth/libauth */ \"../../node_modules/@bitauth/libauth/build/lib/format/utf8.js\");\n/* harmony import */ var _cache_index_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../cache/index.js */ \"./src/cache/walletCache.ts\");\n/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ \"./src/config.ts\");\n/* harmony import */ var _enum_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../enum.js */ \"./src/enum.ts\");\n/* harmony import */ var _history_getHistory_js__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../history/getHistory.js */ \"./src/history/getHistory.ts\");\n/* harmony import */ var _util_checkForEmptySeed_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../util/checkForEmptySeed.js */ \"./src/util/checkForEmptySeed.ts\");\n/* harmony import */ var _Base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Base.js */ \"./src/wallet/Base.ts\");\n/* harmony import */ var _enum_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./enum.js */ \"./src/wallet/enum.ts\");\n/* harmony import */ var _util_hd_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../util/hd.js */ \"./src/util/hd.ts\");\n/* harmony import */ var _constant_js__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../constant.js */ \"./src/constant.ts\");\n/* harmony import */ var _util_sumUtxoValue_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../util/sumUtxoValue.js */ \"./src/util/sumUtxoValue.ts\");\nvar __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([_Base_js__WEBPACK_IMPORTED_MODULE_0__, _enum_js__WEBPACK_IMPORTED_MODULE_2__, _bitauth_libauth__WEBPACK_IMPORTED_MODULE_5__, _util_checkForEmptySeed_js__WEBPACK_IMPORTED_MODULE_6__, _bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__, _bitauth_libauth__WEBPACK_IMPORTED_MODULE_10__, _cache_index_js__WEBPACK_IMPORTED_MODULE_12__, _history_getHistory_js__WEBPACK_IMPORTED_MODULE_16__]);\n([_Base_js__WEBPACK_IMPORTED_MODULE_0__, _enum_js__WEBPACK_IMPORTED_MODULE_2__, _bitauth_libauth__WEBPACK_IMPORTED_MODULE_5__, _util_checkForEmptySeed_js__WEBPACK_IMPORTED_MODULE_6__, _bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__, _bitauth_libauth__WEBPACK_IMPORTED_MODULE_10__, _cache_index_js__WEBPACK_IMPORTED_MODULE_12__, _history_getHistory_js__WEBPACK_IMPORTED_MODULE_16__] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__);\n\n\n\n\n\n\n\n\n\n\n\nconst GAP_SIZE = 20;\nclass HDWallet extends _Base_js__WEBPACK_IMPORTED_MODULE_0__.BaseWallet {\n static { this.networkPrefix = _bitauth_libauth__WEBPACK_IMPORTED_MODULE_1__.CashAddressNetworkPrefix.mainnet; }\n get networkPrefix() {\n return _enum_js__WEBPACK_IMPORTED_MODULE_2__.prefixFromNetworkMap[this.network];\n }\n /// Create an uninitialized HDWallet, this method should not be called directly\n /// Instead static methods such as `newRandom` or `fromSeed` should be used\n constructor(network = _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet) {\n super(network);\n this.derivation = _config_js__WEBPACK_IMPORTED_MODULE_3__.Config.DefaultParentDerivationPath;\n // Callback type for wallet activity watching\n this.walletWatchCallbacks = [];\n // max index used for deposit address derivation\n this.depositIndex = 0;\n // max index used for change address derivation\n this.changeIndex = 0;\n this.depositWatchCancels = [];\n this.changeWatchCancels = [];\n this.depositStatuses = [];\n this.changeStatuses = [];\n this.depositUtxos = [];\n this.changeUtxos = [];\n this.depositRawHistory = [];\n this.changeRawHistory = [];\n this.watchPromise = undefined;\n // @ts-ignore\n this.walletType = _enum_js__WEBPACK_IMPORTED_MODULE_4__.WalletTypeEnum.Hd;\n }\n /// Initialize the wallet given the options mnemonic, xPriv or xPub\n /// If none provided, a new random mnemonic will be generated\n /// If mnemonic or xPriv provided, the wallet will be able to sign transactions\n /// If xPub provided, the wallet will be watch-only\n /// This internal method is called by the various static constructors\n async initialize({ name = \"\", depositIndex = 0, changeIndex = 0, mnemonic = undefined, derivation = undefined, xPriv = undefined, xPub = undefined, } = {}) {\n // newRandom\n if (!xPriv && !xPub && !mnemonic) {\n mnemonic = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_5__.generateBip39Mnemonic)();\n }\n this.depositIndex = depositIndex;\n this.changeIndex = changeIndex;\n // @ts-ignore\n this.xPub = xPub ? xPub : \"\";\n if (mnemonic?.length) {\n // @ts-ignore\n this.derivation = derivation\n ? derivation\n : _config_js__WEBPACK_IMPORTED_MODULE_3__.Config.DefaultParentDerivationPath;\n // @ts-ignore\n this.mnemonic = mnemonic ? mnemonic : (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_5__.generateBip39Mnemonic)();\n if (this.mnemonic.length == 0) {\n throw Error(\"refusing to create wallet from empty mnemonic\");\n }\n if (![12, 24].includes(this.mnemonic.split(\" \").length)) {\n throw Error(\"Invalid mnemonic, must be 12 or 24 words\");\n }\n const seed = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_5__.deriveSeedFromBip39Mnemonic)(this.mnemonic);\n (0,_util_checkForEmptySeed_js__WEBPACK_IMPORTED_MODULE_6__.checkForEmptySeed)(seed);\n const rootNode = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.deriveHdPrivateNodeFromSeed)(seed, {\n assumeValidity: true,\n throwErrors: true,\n });\n const node = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.deriveHdPath)(rootNode, this.derivation);\n // @ts-ignore\n this.xPriv = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_8__.assertSuccess)((0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.encodeHdPrivateKey)({\n ...node,\n network: this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\",\n node: node,\n })).hdPrivateKey;\n // @ts-ignore\n this.xPrivNode = node;\n // @ts-ignore\n this.xPubNode = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.deriveHdPublicNode)(node);\n // @ts-ignore\n this.xPub = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_8__.assertSuccess)((0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.encodeHdPublicKey)({\n node: this.xPubNode,\n network: this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\",\n })).hdPublicKey;\n }\n else if (xPriv) {\n // @ts-ignore\n this.xPriv = xPriv;\n const decoded = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_8__.assertSuccess)((0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.decodeHdPrivateKey)(xPriv));\n if (decoded.network !==\n (this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\")) {\n throw new Error(`xPriv network (${decoded.network}) does not match wallet network (${this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\"})`);\n }\n // @ts-ignore\n this.xPrivNode = decoded.node;\n // @ts-ignore\n this.xPubNode = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.deriveHdPublicNode)(decoded.node);\n // @ts-ignore\n this.xPub = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_8__.assertSuccess)((0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.encodeHdPublicKey)({\n node: this.xPubNode,\n network: this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\",\n })).hdPublicKey;\n }\n else if (xPub) {\n const decoded = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_8__.assertSuccess)((0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_7__.decodeHdPublicKey)(xPub));\n if (decoded.network !==\n (this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\")) {\n throw new Error(`xPriv network (${decoded.network}) does not match wallet network (${this.network === _enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Mainnet ? \"mainnet\" : \"testnet\"})`);\n }\n // @ts-ignore\n this.xPubNode = decoded.node;\n // @ts-ignore\n this.xPub = xPub;\n }\n else {\n throw new Error(\"mnemonic, xPriv or xPub must be provided to create an HDWallet\");\n }\n this.name = name;\n // @ts-ignore\n this.walletId = (0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_9__.binToHex)(_bitauth_libauth__WEBPACK_IMPORTED_MODULE_10__.sha256.hash((0,_bitauth_libauth__WEBPACK_IMPORTED_MODULE_11__.utf8ToBin)(`${(this.mnemonic ? this.mnemonic + this.derivation : undefined) ??\n this.xPriv ??\n this.xPub}-${this.network}`)));\n // @ts-ignore\n this.walletCache = new _cache_index_js__WEBPACK_IMPORTED_MODULE_12__.PersistentWalletCache(this.walletId, this.xPrivNode ?? this.xPubNode, this.networkPrefix);\n // init wallet cache\n await this.walletCache.init();\n // start watching addresses asynchronously\n this.watchPromise = this.makeWatchPromise().catch(() => { });\n return this;\n }\n /// Stops the wallet from watching for address changes\n /// After calling this method, the wallet will no longer update and is considered defunct\n async stop() {\n await Promise.all([\n super.stop(),\n ...this.depositWatchCancels.map((fn) => fn?.()),\n ...this.changeWatchCancels.map((fn) => fn?.()),\n ]);\n this.depositWatchCancels = [];\n this.changeWatchCancels = [];\n this.walletWatchCallbacks = [];\n }\n /// Scan more addresses for activity beyond the current gap limit, extending the watched range as needed\n async scanMoreAddresses(amount = GAP_SIZE) {\n await this.watchPromise;\n this.watchPromise = this.makeWatchPromise(amount);\n await this.watchPromise;\n }\n /// Internal method to start watching addresses for activity, extending the watched range as needed\n async makeWatchPromise(gapSize = GAP_SIZE) {\n await this.watchPromise;\n let needsMore = true;\n while (needsMore) {\n await Promise.all([\n this.watchAddressType(false, gapSize),\n this.watchAddressType(true, gapSize),\n ]);\n // Check if we have a full gap of addresses beyond the last used index\n const depositGap = this.depositStatuses.length - this.depositIndex;\n const changeGap = this.changeStatuses.length - this.changeIndex;\n needsMore = depositGap < gapSize || changeGap < gapSize;\n }\n }\n /// Watch addresses of a specific type (deposit or change) for activity\n async watchAddressType(isChange, gapSize) {\n // Select the appropriate arrays based on address type\n const statuses = isChange ? this.changeStatuses : this.depositStatuses;\n const utxosArray = isChange ? this.changeUtxos : this.depositUtxos;\n const historyArray = isChange\n ? this.changeRawHistory\n : this.depositRawHistory;\n const watchCancels = isChange\n ? this.changeWatchCancels\n : this.depositWatchCancels;\n const getCurrentIndex = () => isChange ? this.changeIndex : this.depositIndex;\n const setCurrentIndex = (val) => {\n if (isChange) {\n this.changeIndex = val;\n }\n else {\n this.depositIndex = val;\n }\n };\n const startIndex = statuses.length;\n const stopIndex = getCurrentIndex() + gapSize;\n const addresses = (0,_util_hd_js__WEBPACK_IMPORTED_MODULE_13__.arrayRange)(startIndex, stopIndex).map((i) => this.walletCache.getByIndex(i, isChange).address);\n await Promise.all(addresses.map(async (addr, idx) => new Promise(async (resolve) => {\n const index = startIndex + idx;\n if (statuses[index] !== undefined) {\n resolve();\n return;\n }\n const { status: prevStatus, utxos: prevUtxos, rawHistory: prevRawHistory, lastConfirmedHeight: prevLastConfirmedHeight, } = this.walletCache.getByIndex(index, isChange);\n statuses[index] = prevStatus;\n utxosArray[index] = prevUtxos;\n historyArray[index] = prevRawHistory;\n // Track lastConfirmedHeight in closure, updated after each fetch\n let lastConfirmedHeight = prevLastConfirmedHeight;\n const callback = async (args) => {\n const [address, status] = args;\n if (address != addr) {\n return;\n }\n if (status === null) {\n utxosArray[index] = [];\n historyArray[index] = [];\n }\n if (status !== null && status !== statuses[index]) {\n // Use lastConfirmedHeight from closure for incremental fetch\n const fromHeight = lastConfirmedHeight;\n const currentHistory = historyArray[index] || [];\n const [utxos, newHistory] = await Promise.all([\n this.provider.getUtxos(addr).then((utxos) => utxos.map((utxo) => {\n utxo.address = addr;\n return utxo;\n })),\n // Fetch only from last confirmed height to reduce server load\n this.provider.getHistory(addr, fromHeight),\n ]);\n // Merge: keep confirmed items from current history, add new items\n const confirmedFromHistory = currentHistory.filter((tx) => tx.height > 0 && tx.height < fromHeight);\n const seen = new Set(confirmedFromHistory.map((tx) => tx.tx_hash));\n const merged = [...confirmedFromHistory];\n for (const tx of newHistory) {\n if (!seen.has(tx.tx_hash)) {\n seen.add(tx.tx_hash);\n merged.push(tx);\n }\n }\n // Update lastConfirmedHeight in closure\n lastConfirmedHeight = merged.reduce((max, tx) => (tx.height > 0 ? Math.max(max, tx.height) : max), fromHeight);\n utxosArray[index] = utxos;\n historyArray[index] = merged;\n this.walletCache.setStatusAndUtxos(addr, status, utxos, merged, lastConfirmedHeight);\n }\n statuses[index] = status;\n if (status !== null) {\n const newIndex = index + 1;\n if (newIndex > getCurrentIndex()) {\n setCurrentIndex(newIndex);\n }\n // Maintain the gap: extend watched range if it shrank\n const gap = statuses.length - getCurrentIndex();\n if (gap < gapSize) {\n await this.watchAddressType(isChange, gapSize);\n }\n }\n // Notify wallet watchers of the status change\n this.notifyWalletWatchers(status, addr);\n resolve();\n };\n watchCancels[index] = await this.provider.subscribeToAddress(addr, callback);\n })));\n return addresses.length;\n }\n // Return wallet info\n getInfo() {\n return {\n isTestnet: this.isTestnet,\n name: this.name,\n network: this.network,\n seed: this.mnemonic,\n walletId: this.toString(),\n walletDbEntry: this.toDbString(),\n };\n }\n /// Internal method called when any address status changes\n notifyWalletWatchers(status, address) {\n for (const callback of this.walletWatchCallbacks) {\n try {\n callback(status, address);\n }\n catch (e) {\n // Ignore callback errors to not break other watchers\n }\n }\n }\n /**\n * Watch wallet for any activity (status changes on any address)\n * This is the foundation for watchWalletBalance and watchWalletTransactions\n * @param callback - Called when any address in the wallet has a status change\n * @returns Cancel function to stop watching\n */\n async watchStatus(callback, debounce = 100) {\n await this.watchPromise;\n let debounceTimer;\n let pendingStatus = null;\n let pendingAddress = \"\";\n const debouncedCallback = (status, address) => {\n pendingStatus = status;\n pendingAddress = address;\n if (debounceTimer)\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n debounceTimer = undefined;\n callback(pendingStatus, pendingAddress);\n }, debounce);\n };\n this.walletWatchCallbacks.push(debouncedCallback);\n return async () => {\n if (debounceTimer)\n clearTimeout(debounceTimer);\n const index = this.walletWatchCallbacks.indexOf(debouncedCallback);\n if (index > -1) {\n this.walletWatchCallbacks.splice(index, 1);\n }\n };\n }\n /**\n * Wait for the wallet to reach a target depositIndex and/or changeIndex,\n * resolving once the condition is met or after an idle timeout with no\n * status changes.\n */\n async waitForUpdate(options = {}) {\n const timeout = options.timeout ?? 100;\n const isSatisfied = () => {\n if (options.depositIndex !== undefined &&\n this.depositIndex < options.depositIndex)\n return false;\n if (options.changeIndex !== undefined &&\n this.changeIndex < options.changeIndex)\n return false;\n return true;\n };\n if (isSatisfied())\n return;\n return new Promise(async (resolve) => {\n let timer;\n let resolved = false;\n let watchCancel;\n const done = async () => {\n if (resolved)\n return;\n resolved = true;\n clearTimeout(timer);\n await watchCancel?.();\n resolve();\n };\n const resetTimer = () => {\n clearTimeout(timer);\n timer = setTimeout(done, timeout);\n };\n // Uses default 100ms debounce — callback only fires after 100ms of\n // quiet, meaning the cascade has settled before we check the condition.\n watchCancel = await this.watchStatus(async () => {\n if (isSatisfied()) {\n await done();\n }\n else {\n resetTimer(); // cascade settled but target not met — wait for more activity\n }\n });\n // Re-check + start initial idle timer after subscription\n if (isSatisfied()) {\n await done();\n }\n else {\n resetTimer();\n }\n });\n }\n /**\n * Watch wallet for new transactions (HD wallet override)\n *\n * Uses unfiltered history so that seenTxHashes always covers all known\n * transactions, including those from newly discovered addresses when\n * depositIndex/changeIndex extends and widens getRawHistory's scope.\n */\n async watchTransactionHashes(callback) {\n const seenTxHashes = new Set();\n return this.watchStatus(async () => {\n const history = await this.getRawHistory();\n const newTxHashes = [];\n for (const tx of history) {\n if (!seenTxHashes.has(tx.tx_hash)) {\n seenTxHashes.add(tx.tx_hash);\n newTxHashes.push(tx.tx_hash);\n }\n }\n if (newTxHashes.length > 0) {\n newTxHashes.forEach((txHash) => callback(txHash));\n }\n });\n }\n /**\n * utxos Get unspent outputs for the wallet\n *\n */\n async getUtxos() {\n await this.watchPromise;\n const utxos = [...this.depositUtxos, ...this.changeUtxos].flat();\n return this._slpSemiAware\n ? utxos.filter((u) => u.satoshis > _constant_js__WEBPACK_IMPORTED_MODULE_14__.DUST_UTXO_THRESHOLD)\n : utxos;\n }\n // Gets balance by summing value in all utxos in sats\n // Balance includes DUST utxos which could be slp tokens and also cashtokens with BCH amounts\n async getBalance() {\n await this.watchPromise;\n const utxos = [...this.depositUtxos, ...this.changeUtxos].flat();\n return (0,_util_sumUtxoValue_js__WEBPACK_IMPORTED_MODULE_15__.sumUtxoValue)(utxos);\n }\n /// Get next unused deposit address, or the address at the specified index\n getDepositAddress(index = -1) {\n index = (0,_util_hd_js__WEBPACK_IMPORTED_MODULE_13__.getNextUnusedIndex)(index, this.depositStatuses);\n return this.walletCache.getByIndex(index, false).address;\n }\n /// Get next unused token deposit address, or the token address at the specified index\n getTokenDepositAddress(index = -1) {\n index = (0,_util_hd_js__WEBPACK_IMPORTED_MODULE_13__.getNextUnusedIndex)(index, this.depositStatuses);\n return this.walletCache.getByIndex(index, false).tokenAddress;\n }\n /// Get next unused change address, or the address at the specified index\n getChangeAddress(index = -1) {\n index = (0,_util_hd_js__WEBPACK_IMPORTED_MODULE_13__.getNextUnusedIndex)(index, this.changeStatuses);\n return this.walletCache.getByIndex(index, true).address;\n }\n /// Get next unused token change address, or the token address at the specified index\n getChangeTokenAddress(index = -1) {\n index = (0,_util_hd_js__WEBPACK_IMPORTED_MODULE_13__.getNextUnusedIndex)(index, this.changeStatuses);\n return this.walletCache.getByIndex(index, true).tokenAddress;\n }\n hasAddress(address) {\n return this.walletCache.get(address) !== undefined;\n }\n /**\n * fromSeed - create a wallet using the seed phrase and derivation path\n *\n * unless specified the derivation path m/44'/0'/0'/0/0 will be used\n *\n * @param seed BIP39 12 word seed phrase\n * @param derivationPath BIP44 HD wallet derivation path to get a single the private key from hierarchy\n *\n * @returns instantiated wallet\n */\n static async fromSeed(seed, derivationPath, depositIndex, changeIndex) {\n return new this().initialize({\n mnemonic: seed,\n derivation: derivationPath,\n depositIndex: depositIndex,\n changeIndex: changeIndex,\n });\n }\n /**\n * newRandom - create a random wallet\n *\n * if `name` parameter is specified, the wallet will also be persisted to DB\n *\n * @param name user friendly wallet alias\n * @param dbName name under which the wallet will be stored in the database\n *\n * @returns instantiated wallet\n */\n static async newRandom(name = \"\", dbName) {\n dbName = dbName ? dbName : this.networkPrefix;\n if (name.length > 0) {\n return this.named(name, dbName);\n }\n return new this().initialize();\n }\n /**\n * fromXPub - create a watch-only wallet using the HD Wallet Public key\n *\n * @param xPub HD Wallet Public Key\n *\n * @returns instantiated wallet\n */\n static async fromXPub(xPub) {\n return new this().initialize({\n xPub: xPub,\n });\n }\n /**\n * fromXPriv - create a wallet using the HD Wallet Private key\n *\n * @param xPub HD Wallet Private Key\n *\n * @returns instantiated wallet\n */\n static async fromXPriv(xPriv) {\n return new this().initialize({\n xPriv: xPriv,\n });\n }\n /**\n * fromId - create a wallet from encoded walletId string\n *\n * @param walletId walletId options to steer the creation process\n *\n * @returns wallet instantiated accordingly to the walletId rules\n */\n static async fromId(walletId) {\n return new this().fromId(walletId);\n }\n /// override the base class fromId method implementation\n async fromId(walletId) {\n const [walletType, networkGiven, arg1, arg2, arg3, arg4] = walletId.split(\":\");\n if (this.network != networkGiven) {\n throw Error(`Network prefix ${networkGiven} to a ${this.network} wallet`);\n }\n if (walletType === _enum_js__WEBPACK_IMPORTED_MODULE_4__.WalletTypeEnum.Named) {\n if (arg2) {\n // named:testnet:wallet_1:my_database\n return this.named(arg1, arg2);\n }\n else {\n // named:testnet:wallet_1\n return this.named(arg1);\n }\n }\n if (walletType !== _enum_js__WEBPACK_IMPORTED_MODULE_4__.WalletTypeEnum.Hd) {\n throw Error(`fromId called on a ${walletType} wallet, expected a ${_enum_js__WEBPACK_IMPORTED_MODULE_4__.WalletTypeEnum.Hd} wallet`);\n }\n if (arg1.startsWith(\"priv\", 1)) {\n return this.initialize({\n xPriv: arg1,\n depositIndex: parseInt(arg2) || 0,\n changeIndex: parseInt(arg3) || 0,\n });\n }\n if (arg1.startsWith(\"pub\", 1)) {\n return this.initialize({\n xPub: arg1,\n depositIndex: parseInt(arg2) || 0,\n changeIndex: parseInt(arg3) || 0,\n });\n }\n return this.initialize({\n mnemonic: arg1,\n derivation: arg2,\n depositIndex: parseInt(arg3) || 0,\n changeIndex: parseInt(arg4) || 0,\n });\n }\n /**\n * encodeTransaction Encode and sign a transaction given a list of sendRequests, options and estimate fees.\n * @param {SendRequest[]} sendRequests SendRequests\n * @param {boolean} discardChange=false\n * @param {SendRequestOptionsI} options Options of the send requests\n */\n async encodeTransaction(requests, discardChange = false, options, privateKey) {\n if (!this.xPriv && !privateKey && options?.buildUnsigned !== true) {\n throw new Error(`Missing private key`);\n }\n return super.encodeTransaction(requests, discardChange, options, privateKey);\n }\n //#region Serialization\n // Returns the serialized wallet as a string\n // If storing in a database, set asNamed to false to store secrets\n // In all other cases, the a named wallet is deserialized from the database\n // by the name key\n toString() {\n if (this.name) {\n return `named:${this.network}:${this.name}`;\n }\n return this.toDbString();\n }\n /**\n * toDbString - store the serialized version of the wallet in the database, not just the name\n *\n * @throws {Error} if called on BaseWallet\n */\n toDbString() {\n if (this.walletType == _enum_js__WEBPACK_IMPORTED_MODULE_4__.WalletTypeEnum.Hd) {\n if (this.mnemonic?.length > 0) {\n return `${this.walletType}:${this.network}:${this.mnemonic}:${this.derivation}:${this.depositIndex}:${this.changeIndex}`;\n }\n if (this.xPriv?.length > 0) {\n return `${this.walletType}:${this.network}:${this.xPriv}:${this.depositIndex}:${this.changeIndex}`;\n }\n if (this.xPub?.length > 0) {\n return `${this.walletType}:${this.network}:${this.xPub}:${this.depositIndex}:${this.changeIndex}`;\n }\n throw Error(\"HDWallet has no mnemonic, xPriv or xPub to serialize\");\n }\n throw Error(\"toDbString unsupported wallet type\");\n }\n //#endregion Serialization\n /**\n * getHistory gets transaction history of this wallet with most data decoded and ready to present to user\n * @note balance calculations are valid only if querying to the blockchain tip (`toHeight` === -1, `count` === -1)\n * @note this method is heavy on network calls, if invoked in browser use of cache is advised, @see `Config.UseLocalStorageCache`\n * @note this method tries to recreate the history tab view of Electron Cash wallet, however, it may not be 100% accurate if the tnransaction value changes are the same in the same block (ordering)\n *\n * @param unit optional, BCH or currency unit to present balance and balance changes. If unit is currency like USD or EUR, balances will be subject to possible rounding errors. Default 0\n * @param fromHeight optional, if set, history will be limited. Default 0\n * @param toHeight optional, if set, history will be limited. Default -1, meaning that all history items will be returned, including mempool\n * @param start optional, if set, the result set will be paginated with offset `start`\n * @param count optional, if set, the result set will be paginated with `count`. Default -1, meaning that all history items will be returned\n *\n * @returns an array of transaction history items, with input values and addresses encoded in cashaddress format. @see `TransactionHistoryItem` type\n */\n async getHistory({ unit = \"sat\", fromHeight = 0, toHeight = -1, start = 0, count = -1, }) {\n const rawHistory = await this.getRawHistory(fromHeight, toHeight);\n const addresses = this.getUsedAddresses();\n return (0,_history_getHistory_js__WEBPACK_IMPORTED_MODULE_16__.getHistory)({\n addresses: addresses,\n provider: this.provider,\n unit,\n fromHeight,\n toHeight,\n start,\n count,\n rawHistory,\n });\n }\n // get all used addresses (deposit and change) for this wallet\n getUsedAddresses() {\n return [\n ...this.depositStatuses\n .map((status, i) => status !== null && i < this.depositIndex\n ? this.walletCache.getByIndex(i, false).address\n : undefined)\n .filter((address) => address !== undefined),\n ...this.changeStatuses\n .map((status, i) => status !== null && i < this.changeIndex\n ? this.walletCache.getByIndex(i, true).address\n : undefined)\n .filter((address) => address !== undefined),\n ];\n }\n // gets transaction history of this wallet\n async getRawHistory(fromHeight = 0, toHeight = -1) {\n await this.watchPromise;\n // Collect cached raw history from deposit and change addresses\n const historyArrays = [\n ...this.depositRawHistory.slice(0, this.depositIndex),\n ...this.changeRawHistory.slice(0, this.changeIndex),\n ];\n // Deduplicate by tx_hash\n const seen = new Set();\n let history = [];\n for (const arr of historyArrays) {\n for (const tx of arr) {\n if (!seen.has(tx.tx_hash)) {\n seen.add(tx.tx_hash);\n history.push(tx);\n }\n }\n }\n // Apply height filters if specified\n if (fromHeight > 0 || toHeight !== -1) {\n history = history.filter((tx) => {\n // Unconfirmed transactions (height <= 0) pass the filter when toHeight is -1\n if (tx.height <= 0) {\n return toHeight === -1;\n }\n const aboveFrom = tx.height >= fromHeight;\n const belowTo = toHeight === -1 || tx.height <= toHeight;\n return aboveFrom && belowTo;\n });\n }\n // Sort by height (descending, unconfirmed first)\n return history.sort((a, b) => {\n if (a.height <= 0 && b.height > 0)\n return -1;\n if (b.height <= 0 && a.height > 0)\n return 1;\n return b.height - a.height;\n });\n }\n}\n/**\n * Class to manage a testnet wallet.\n */\nclass TestNetHDWallet extends HDWallet {\n static { this.networkPrefix = _bitauth_libauth__WEBPACK_IMPORTED_MODULE_1__.CashAddressNetworkPrefix.testnet; }\n constructor() {\n super(_enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Testnet);\n }\n}\n/**\n * Class to manage a regtest wallet.\n */\nclass RegTestHDWallet extends HDWallet {\n static { this.networkPrefix = _bitauth_libauth__WEBPACK_IMPORTED_MODULE_1__.CashAddressNetworkPrefix.regtest; }\n constructor() {\n super(_enum_js__WEBPACK_IMPORTED_MODULE_2__.NetworkType.Regtest);\n }\n}\n\n__webpack_async_result__();\n} catch(e) { __webpack_async_result__(e); } });\n\n//# sourceURL=webpack://mainnet-js/./src/wallet/HDWallet.ts?");
648
648
 
649
649
  /***/ }),
650
650
 
@@ -1764,7 +1764,7 @@ eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harm
1764
1764
  \****************************************************************/
1765
1765
  /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
1766
1766
 
1767
- eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"ConnectionStatus\": () => (/* binding */ $db7c797e63383364$export$7516420eb880ab68),\n/* harmony export */ \"ElectrumClient\": () => (/* binding */ $558b46d3f899ced5$export$2e2bcd8739ae039)\n/* harmony export */ });\n/* unused harmony exports isVersionRejected, isVersionNegotiated */\n/* harmony import */ var _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @electrum-cash/debug-logs */ \"../../node_modules/@electrum-cash/debug-logs/dist/index.mjs\");\n/* harmony import */ var eventemitter3__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! eventemitter3 */ \"../../node_modules/eventemitter3/index.mjs\");\n/* harmony import */ var async_mutex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! async-mutex */ \"../../node_modules/async-mutex/index.mjs\");\n/* harmony import */ var _electrum_cash_web_socket__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @electrum-cash/web-socket */ \"../../node_modules/@electrum-cash/web-socket/dist/index.mjs\");\n/* harmony import */ var lossless_json__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! lossless-json */ \"../../node_modules/lossless-json/lib/esm/index.js\");\n\n\n\n\n\n\n\nfunction $parcel$export(e, n, v, s) {\n Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});\n}\n\n\n\nclass $24139611f53a54b8$export$5d955335434540c6 {\n /**\n\t * Helper function that builds an Electrum request object.\n\t *\n\t * @param method - method to call.\n\t * @param parameters - method parameters for the call.\n\t * @param requestId - unique string or number referencing this request.\n\t *\n\t * @returns a properly formatted Electrum request string.\n\t */ static buildRequestObject(method, parameters, requestId) {\n // Return the formatted request object.\n // NOTE: Electrum either uses JsonRPC strictly or loosely.\n // If we specify protocol identifier without being 100% compliant, we risk being disconnected/blacklisted.\n // For this reason, we omit the protocol identifier to avoid issues.\n return JSON.stringify({\n method: method,\n params: parameters,\n id: requestId\n });\n }\n /**\n\t * Constant used to verify if a provided string is a valid version number.\n\t *\n\t * @returns a regular expression that matches valid version numbers.\n\t */ static get versionRegexp() {\n return /^\\d+(\\.\\d+)+$/;\n }\n /**\n\t * Constant used to separate statements/messages in a stream of data.\n\t *\n\t * @returns the delimiter used by Electrum to separate statements.\n\t */ static get statementDelimiter() {\n return \"\\n\";\n }\n}\n\n\nvar $e83d2e7688025acd$exports = {};\n\n$parcel$export($e83d2e7688025acd$exports, \"isVersionRejected\", () => $e83d2e7688025acd$export$e1f38ab2b4ebdde6);\n$parcel$export($e83d2e7688025acd$exports, \"isVersionNegotiated\", () => $e83d2e7688025acd$export$9598f0c76aa41d73);\nconst $e83d2e7688025acd$export$e1f38ab2b4ebdde6 = function(object) {\n return \"error\" in object;\n};\nconst $e83d2e7688025acd$export$9598f0c76aa41d73 = function(object) {\n return \"software\" in object && \"protocol\" in object;\n};\n\n\n// Acceptable parameter types for RPC messages\nconst $abcb763a48577a1e$export$d73a2e87a509880 = function(message) {\n return \"id\" in message && \"error\" in message;\n};\nconst $abcb763a48577a1e$export$81276773828ff315 = function(message) {\n return \"id\" in message && \"result\" in message;\n};\nconst $abcb763a48577a1e$export$280de919a0cf6928 = function(message) {\n return !(\"id\" in message) && \"method\" in message;\n};\nconst $abcb763a48577a1e$export$94e3360fcddccc76 = function(message) {\n return \"id\" in message && \"method\" in message;\n};\n\n\n\nvar $db7c797e63383364$exports = {};\n\n$parcel$export($db7c797e63383364$exports, \"ConnectionStatus\", () => $db7c797e63383364$export$7516420eb880ab68);\n// Disable indent rule for this file because it is broken (https://github.com/typescript-eslint/typescript-eslint/issues/1824)\n/* eslint-disable @typescript-eslint/indent */ /**\n * Enum that denotes the connection status of an ElectrumConnection.\n * @enum {number}\n * @property {0} DISCONNECTED The connection is disconnected.\n * @property {1} AVAILABLE The connection is connected.\n * @property {2} DISCONNECTING The connection is disconnecting.\n * @property {3} CONNECTING The connection is connecting.\n * @property {4} RECONNECTING The connection is restarting.\n */ var $db7c797e63383364$export$7516420eb880ab68;\n(function(ConnectionStatus) {\n ConnectionStatus[ConnectionStatus[\"DISCONNECTED\"] = 0] = \"DISCONNECTED\";\n ConnectionStatus[ConnectionStatus[\"CONNECTED\"] = 1] = \"CONNECTED\";\n ConnectionStatus[ConnectionStatus[\"DISCONNECTING\"] = 2] = \"DISCONNECTING\";\n ConnectionStatus[ConnectionStatus[\"CONNECTING\"] = 3] = \"CONNECTING\";\n ConnectionStatus[ConnectionStatus[\"RECONNECTING\"] = 4] = \"RECONNECTING\";\n})($db7c797e63383364$export$7516420eb880ab68 || ($db7c797e63383364$export$7516420eb880ab68 = {}));\n\n\n\nclass $ff134c9a9e1f7361$export$de0f57fc22079b5e extends (0, eventemitter3__WEBPACK_IMPORTED_MODULE_1__.EventEmitter) {\n /**\n\t * Sets up network configuration for an Electrum client connection.\n\t *\n\t * @param application - your application name, used to identify to the electrum host.\n\t * @param version - protocol version to use with the host.\n\t * @param socketOrHostname - pre-configured electrum socket or fully qualified domain name or IP number of the host\n\t * @param options - ...\n\t *\n\t * @throws {Error} if `version` is not a valid version string.\n\t */ constructor(application, version, socketOrHostname, options){\n // Initialize the event emitter.\n super();\n this.application = application;\n this.version = version;\n this.socketOrHostname = socketOrHostname;\n this.options = options;\n this.status = (0, $db7c797e63383364$export$7516420eb880ab68).DISCONNECTED;\n this.verifications = [];\n this.messageBuffer = \"\";\n // Check if the provided version is a valid version number.\n if (!(0, $24139611f53a54b8$export$5d955335434540c6).versionRegexp.test(version)) // Throw an error since the version number was not valid.\n throw new Error(`Provided version string (${version}) is not a valid protocol version number.`);\n // If a hostname was provided..\n if (typeof socketOrHostname === \"string\") // Use a web socket with default parameters.\n this.socket = new (0, _electrum_cash_web_socket__WEBPACK_IMPORTED_MODULE_3__.ElectrumWebSocket)(socketOrHostname);\n else // Use the provided socket.\n this.socket = socketOrHostname;\n // Set up handlers for connection and disconnection.\n this.socket.on(\"connected\", this.onSocketConnect.bind(this));\n this.socket.on(\"disconnected\", this.onSocketDisconnect.bind(this));\n // Set up handler for incoming data.\n this.socket.on(\"data\", this.parseMessageChunk.bind(this));\n // Handle visibility changes when run in a browser environment (if not explicitly disabled).\n if (typeof document !== \"undefined\" && !this.options.disableBrowserVisibilityHandling) document.addEventListener(\"visibilitychange\", this.handleVisibilityChange.bind(this));\n // Handle network connection changes when run in a browser environment (if not explicitly disabled).\n if (typeof window !== \"undefined\" && !this.options.disableBrowserConnectivityHandling) {\n window.addEventListener(\"online\", this.handleNetworkChange.bind(this));\n window.addEventListener(\"offline\", this.handleNetworkChange.bind(this));\n }\n }\n // Expose hostIdentifier from the socket.\n get hostIdentifier() {\n return this.socket.hostIdentifier;\n }\n // Expose port from the socket.\n get encrypted() {\n return this.socket.encrypted;\n }\n /**\n\t * Assembles incoming data into statements and hands them off to the message parser.\n\t *\n\t * @param data - data to append to the current message buffer, as a string.\n\t *\n\t * @throws {SyntaxError} if the passed statement parts are not valid JSON.\n\t */ parseMessageChunk(data) {\n // Update the timestamp for when we last received data.\n this.lastReceivedTimestamp = Date.now();\n // Emit a notification indicating that the connection has received data.\n this.emit(\"received\");\n // Clear and remove all verification timers.\n this.verifications.forEach((timer)=>clearTimeout(timer));\n this.verifications.length = 0;\n // Add the message to the current message buffer.\n this.messageBuffer += data;\n // Check if the new message buffer contains the statement delimiter.\n while(this.messageBuffer.includes((0, $24139611f53a54b8$export$5d955335434540c6).statementDelimiter)){\n // Split message buffer into statements.\n const statementParts = this.messageBuffer.split((0, $24139611f53a54b8$export$5d955335434540c6).statementDelimiter);\n // For as long as we still have statements to parse..\n while(statementParts.length > 1){\n // Move the first statement to its own variable.\n const currentStatementList = String(statementParts.shift());\n // Parse the statement into an object or list of objects.\n let statementList = (0, lossless_json__WEBPACK_IMPORTED_MODULE_4__.parse)(currentStatementList, null, this.options.useBigInt ? (0, lossless_json__WEBPACK_IMPORTED_MODULE_4__.parseNumberAndBigInt) : parseFloat);\n // Wrap the statement in an array if it is not already a batched statement list.\n if (!Array.isArray(statementList)) statementList = [\n statementList\n ];\n // For as long as there is statements in the result set..\n while(statementList.length > 0){\n // Move the first statement from the batch to its own variable.\n const currentStatement = statementList.shift();\n // If the current statement is a subscription notification..\n if ((0, $abcb763a48577a1e$export$280de919a0cf6928)(currentStatement)) {\n // Emit the notification for handling higher up in the stack.\n this.emit(\"response\", currentStatement);\n continue;\n }\n // If the current statement is a version negotiation response..\n if (currentStatement.id === \"versionNegotiation\") {\n if ((0, $abcb763a48577a1e$export$d73a2e87a509880)(currentStatement)) // Then emit a failed version negotiation response signal.\n this.emit(\"version\", {\n error: currentStatement.error\n });\n else {\n // Extract the software and protocol version reported.\n const [software, protocol] = currentStatement.result;\n // Emit a successful version negotiation response signal.\n this.emit(\"version\", {\n software: software,\n protocol: protocol\n });\n }\n continue;\n }\n // If the current statement is a keep-alive response..\n if (currentStatement.id === \"keepAlive\") continue;\n // Emit the statements for handling higher up in the stack.\n this.emit(\"response\", currentStatement);\n }\n }\n // Store the remaining statement as the current message buffer.\n this.messageBuffer = statementParts.shift() || \"\";\n }\n }\n /**\n\t * Sends a keep-alive message to the host.\n\t *\n\t * @returns true if the ping message was fully flushed to the socket, false if\n\t * part of the message is queued in the user memory\n\t */ ping() {\n // Write a log message.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).ping(`Sending keep-alive ping to '${this.hostIdentifier}'`);\n // Craft a keep-alive message.\n const message = (0, $24139611f53a54b8$export$5d955335434540c6).buildRequestObject(\"server.ping\", [], \"keepAlive\");\n // Send the keep-alive message.\n const status = this.send(message);\n // Return the ping status.\n return status;\n }\n /**\n\t * Initiates the network connection negotiates a protocol version. Also emits the 'connect' signal if successful.\n\t *\n\t * @throws {Error} if the socket connection fails.\n\t * @returns a promise resolving when the connection is established\n\t */ async connect() {\n // If we are already connected return true.\n if (this.status === (0, $db7c797e63383364$export$7516420eb880ab68).CONNECTED) return;\n // Indicate that the connection is connecting\n this.status = (0, $db7c797e63383364$export$7516420eb880ab68).CONNECTING;\n // Emit a connect event now that the connection is being set up.\n this.emit(\"connecting\");\n // Define a function to wrap connection as a promise.\n const connectionResolver = (resolve, reject)=>{\n const rejector = (error)=>{\n // Set the status back to disconnected\n this.status = (0, $db7c797e63383364$export$7516420eb880ab68).DISCONNECTED;\n // Emit a connect event indicating that we failed to connect.\n this.emit(\"disconnected\");\n // Reject with the error as reason\n reject(error);\n };\n // Replace previous error handlers to reject the promise on failure.\n this.socket.removeAllListeners(\"error\");\n this.socket.once(\"error\", rejector);\n // Define a function to wrap version negotiation as a callback.\n const versionNegotiator = ()=>{\n // Write a log message to show that we have started version negotiation.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).network(`Requesting protocol version ${this.version} with '${this.hostIdentifier}'.`);\n // remove the one-time error handler since no error was detected.\n this.socket.removeListener(\"error\", rejector);\n // Build a version negotiation message.\n const versionMessage = (0, $24139611f53a54b8$export$5d955335434540c6).buildRequestObject(\"server.version\", [\n this.application,\n this.version\n ], \"versionNegotiation\");\n // Define a function to wrap version validation as a function.\n const versionValidator = (version)=>{\n // Check if version negotiation failed.\n if ((0, $e83d2e7688025acd$export$e1f38ab2b4ebdde6)(version)) {\n // Disconnect from the host.\n this.disconnect(true);\n // Declare an error message.\n const errorMessage = \"unsupported protocol version.\";\n // Log the error.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).errors(`Failed to connect with ${this.hostIdentifier} due to ${errorMessage}`);\n // Reject the connection with false since version negotiation failed.\n reject(errorMessage);\n } else if (version.protocol !== this.version && `${version.protocol}.0` !== this.version && `${version.protocol}.0.0` !== this.version) {\n // Disconnect from the host.\n this.disconnect(true);\n // Declare an error message.\n const errorMessage = `incompatible protocol version negotiated (${version.protocol} !== ${this.version}).`;\n // Log the error.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).errors(`Failed to connect with ${this.hostIdentifier} due to ${errorMessage}`);\n // Reject the connection with false since version negotiation failed.\n reject(errorMessage);\n } else {\n // Write a log message.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).network(`Negotiated protocol version ${version.protocol} with '${this.hostIdentifier}', powered by ${version.software}.`);\n // Set connection status to connected\n this.status = (0, $db7c797e63383364$export$7516420eb880ab68).CONNECTED;\n // Emit a connect event now that the connection is usable.\n this.emit(\"connected\");\n // Resolve the connection promise since we successfully connected and negotiated protocol version.\n resolve();\n }\n };\n // Listen for version negotiation once.\n this.once(\"version\", versionValidator);\n // Send the version negotiation message.\n this.send(versionMessage);\n };\n // Prepare the version negotiation.\n this.socket.once(\"connected\", versionNegotiator);\n // Set up handler for network errors.\n this.socket.on(\"error\", this.onSocketError.bind(this));\n // Connect to the server.\n this.socket.connect();\n };\n // Wait until connection is established and version negotiation succeeds.\n await new Promise(connectionResolver);\n }\n /**\n\t * Restores the network connection.\n\t */ async reconnect() {\n // If a reconnect timer is set, remove it\n await this.clearReconnectTimer();\n // Write a log message.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).network(`Trying to reconnect to '${this.hostIdentifier}'..`);\n // Set the status to reconnecting for more accurate log messages.\n this.status = (0, $db7c797e63383364$export$7516420eb880ab68).RECONNECTING;\n // Emit a connect event now that the connection is usable.\n this.emit(\"reconnecting\");\n // Disconnect the underlying socket.\n this.socket.disconnect();\n try {\n // Try to connect again.\n await this.connect();\n } catch (error) {\n // Do nothing as the error should be handled via the disconnect and error signals.\n }\n }\n /**\n\t * Removes the current reconnect timer.\n\t */ clearReconnectTimer() {\n // If a reconnect timer is set, remove it\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n // Reset the timer reference.\n this.reconnectTimer = undefined;\n }\n /**\n\t * Removes the current keep-alive timer.\n\t */ clearKeepAliveTimer() {\n // If a keep-alive timer is set, remove it\n if (this.keepAliveTimer) clearTimeout(this.keepAliveTimer);\n // Reset the timer reference.\n this.keepAliveTimer = undefined;\n }\n /**\n\t * Initializes the keep alive timer loop.\n\t */ setupKeepAliveTimer() {\n // If the keep-alive timer loop is not currently set up..\n if (!this.keepAliveTimer) // Set a new keep-alive timer.\n this.keepAliveTimer = setTimeout(this.ping.bind(this), this.options.sendKeepAliveIntervalInMilliSeconds);\n }\n /**\n\t * Tears down the current connection and removes all event listeners on disconnect.\n\t *\n\t * @param force - disconnect even if the connection has not been fully established yet.\n\t * @param intentional - update connection state if disconnect is intentional.\n\t *\n\t * @returns true if successfully disconnected, or false if there was no connection.\n\t */ async disconnect(force = false, intentional = true) {\n // Return early when there is nothing to disconnect from\n if (this.status === (0, $db7c797e63383364$export$7516420eb880ab68).DISCONNECTED && !force) // Return false to indicate that there was nothing to disconnect from.\n return false;\n // Update connection state if the disconnection is intentional.\n // NOTE: The state is meant to represent what the client is requesting, but\n // is used internally to handle visibility changes in browsers to ensure functional reconnection.\n if (intentional) // Set connection status to null to indicate tear-down is currently happening.\n this.status = (0, $db7c797e63383364$export$7516420eb880ab68).DISCONNECTING;\n // Emit a connect event to indicate that we are disconnecting.\n this.emit(\"disconnecting\");\n // If a keep-alive timer is set, remove it.\n await this.clearKeepAliveTimer();\n // If a reconnect timer is set, remove it\n await this.clearReconnectTimer();\n const disconnectResolver = (resolve)=>{\n // Resolve to true after the connection emits a disconnect\n this.once(\"disconnected\", ()=>resolve(true));\n // Close the connection on the socket level.\n this.socket.disconnect();\n };\n // Return true to indicate that we disconnected.\n return new Promise(disconnectResolver);\n }\n /**\n\t * Updates the connection state based on browser reported connectivity.\n\t *\n\t * Most modern browsers are able to provide information on the connection state\n\t * which allows for significantly faster response times to network changes compared\n\t * to waiting for network requests to fail.\n\t *\n\t * When available, we make use of this to fail early to provide a better user experience.\n\t */ async handleNetworkChange() {\n // Do nothing if we do not have the navigator available.\n if (typeof window.navigator === \"undefined\") return;\n // Attempt to reconnect to the network now that we may be online again.\n if (window.navigator.onLine === true) this.reconnect();\n // Disconnected from the network so that cleanup can happen while we're offline.\n if (window.navigator.onLine !== true) {\n const forceDisconnect = true;\n const isIntentional = true;\n this.disconnect(forceDisconnect, isIntentional);\n }\n }\n /**\n\t * Updates connection state based on application visibility.\n\t *\n\t * Some browsers will disconnect network connections when the browser is out of focus,\n\t * which would normally cause our reconnect-on-timeout routines to trigger, but that\n\t * results in a poor user experience since the events are not handled consistently\n\t * and sometimes it can take some time after restoring focus to the browser.\n\t *\n\t * By manually disconnecting when this happens we prevent the default reconnection routines\n\t * and make the behavior consistent across browsers.\n\t */ async handleVisibilityChange() {\n // Disconnect when application is removed from focus.\n if (document.visibilityState === \"hidden\") {\n const forceDisconnect = true;\n const isIntentional = true;\n this.disconnect(forceDisconnect, isIntentional);\n }\n // Reconnect when application is returned to focus.\n if (document.visibilityState === \"visible\") this.reconnect();\n }\n /**\n\t * Sends an arbitrary message to the server.\n\t *\n\t * @param message - json encoded request object to send to the server, as a string.\n\t *\n\t * @returns true if the message was fully flushed to the socket, false if part of the message\n\t * is queued in the user memory\n\t */ send(message) {\n // Remove the current keep-alive timer if it exists.\n this.clearKeepAliveTimer();\n // Get the current timestamp in milliseconds.\n const currentTime = Date.now();\n // Follow up and verify that the message got sent..\n const verificationTimer = setTimeout(this.verifySend.bind(this, currentTime), this.socket.timeout);\n // Store the verification timer locally so that it can be cleared when data has been received.\n this.verifications.push(verificationTimer);\n // Set a new keep-alive timer.\n this.setupKeepAliveTimer();\n // Write the message to the network socket.\n return this.socket.write(message + (0, $24139611f53a54b8$export$5d955335434540c6).statementDelimiter);\n }\n // --- Event managers. --- //\n /**\n\t * Marks the connection as timed out and schedules reconnection if we have not\n\t * received data within the expected time frame.\n\t */ verifySend(sentTimestamp) {\n // If we haven't received any data since we last sent data out..\n if (Number(this.lastReceivedTimestamp) < sentTimestamp) {\n // If this connection is already disconnected, we do not change anything\n if (this.status === (0, $db7c797e63383364$export$7516420eb880ab68).DISCONNECTED || this.status === (0, $db7c797e63383364$export$7516420eb880ab68).DISCONNECTING) // debug.warning(`Tried to verify already disconnected connection to '${this.hostIdentifier}'`);\n return;\n // Remove the current keep-alive timer if it exists.\n this.clearKeepAliveTimer();\n // Write a notification to the logs.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).network(`Connection to '${this.hostIdentifier}' timed out.`);\n // Close the connection to avoid re-use.\n // NOTE: This initiates reconnection routines if the connection has not\n // been marked as intentionally disconnected.\n this.socket.disconnect();\n }\n }\n /**\n\t * Updates the connection status when a connection is confirmed.\n\t */ onSocketConnect() {\n // If a reconnect timer is set, remove it.\n this.clearReconnectTimer();\n // Set up the initial timestamp for when we last received data from the server.\n this.lastReceivedTimestamp = Date.now();\n // Set up the initial keep-alive timer.\n this.setupKeepAliveTimer();\n // Clear all temporary error listeners.\n this.socket.removeAllListeners(\"error\");\n // Set up handler for network errors.\n this.socket.on(\"error\", this.onSocketError.bind(this));\n }\n /**\n\t * Updates the connection status when a connection is ended.\n\t */ onSocketDisconnect() {\n // Remove the current keep-alive timer if it exists.\n this.clearKeepAliveTimer();\n // If this is a connection we're trying to tear down..\n if (this.status === (0, $db7c797e63383364$export$7516420eb880ab68).DISCONNECTING) {\n // Mark the connection as disconnected.\n this.status = (0, $db7c797e63383364$export$7516420eb880ab68).DISCONNECTED;\n // Send a disconnect signal higher up the stack.\n this.emit(\"disconnected\");\n // If a reconnect timer is set, remove it.\n this.clearReconnectTimer();\n // Remove all event listeners\n this.removeAllListeners();\n // Write a log message.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).network(`Disconnected from '${this.hostIdentifier}'.`);\n } else {\n // If this is for an established connection..\n if (this.status === (0, $db7c797e63383364$export$7516420eb880ab68).CONNECTED) // Write a notification to the logs.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).errors(`Connection with '${this.hostIdentifier}' was closed, trying to reconnect in ${this.options.reconnectAfterMilliSeconds / 1000} seconds.`);\n // Mark the connection as disconnected for now..\n this.status = (0, $db7c797e63383364$export$7516420eb880ab68).DISCONNECTED;\n // Send a disconnect signal higher up the stack.\n this.emit(\"disconnected\");\n // If we don't have a pending reconnection timer..\n if (!this.reconnectTimer) // Attempt to reconnect after one keep-alive duration.\n this.reconnectTimer = setTimeout(this.reconnect.bind(this), this.options.reconnectAfterMilliSeconds);\n }\n }\n /**\n\t * Notify administrator of any unexpected errors.\n\t */ onSocketError(error) {\n // Report a generic error if no error information is present.\n // NOTE: When using WSS, the error event explicitly\n // only allows to send a \"simple\" event without data.\n // https://stackoverflow.com/a/18804298\n if (typeof error === \"undefined\") // Do nothing, and instead rely on the socket disconnect event for further information.\n return;\n // Log the error, as there is nothing we can do to actually handle it.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).errors(`Network error ('${this.hostIdentifier}'): `, error);\n }\n}\n\n\n\n// Define number of milliseconds per second for legibility.\nconst $d801b1f9b7fc3074$var$MILLI_SECONDS_PER_SECOND = 1000;\nconst $d801b1f9b7fc3074$export$5ba3a4134d0d751d = {\n // By default, all numbers including integers are parsed as regular JavaScript numbers.\n useBigInt: false,\n // Send a ping message every seconds, to detect network problem as early as possible.\n sendKeepAliveIntervalInMilliSeconds: 1 * $d801b1f9b7fc3074$var$MILLI_SECONDS_PER_SECOND,\n // Try to reconnect 5 seconds after unintentional disconnects.\n reconnectAfterMilliSeconds: 5 * $d801b1f9b7fc3074$var$MILLI_SECONDS_PER_SECOND,\n // Try to detect stale connections 5 seconds after every send.\n verifyConnectionTimeoutInMilliSeconds: 5 * $d801b1f9b7fc3074$var$MILLI_SECONDS_PER_SECOND,\n // Automatically manage the connection for a consistent behavior across browsers and devices.\n disableBrowserVisibilityHandling: false,\n disableBrowserConnectivityHandling: false\n};\n\n\n\n\n\n\n/**\n * High-level Electrum client that lets applications send requests and subscribe to notification events from a server.\n */ class $558b46d3f899ced5$var$ElectrumClient extends (0, eventemitter3__WEBPACK_IMPORTED_MODULE_1__.EventEmitter) {\n /**\n\t * Number corresponding to the underlying connection status.\n\t */ get status() {\n return this.connection.status;\n }\n /**\n\t * Initializes an Electrum client.\n\t *\n\t * @param application - your application name, used to identify to the electrum host.\n\t * @param version - protocol version to use with the host.\n\t * @param socketOrHostname - pre-configured electrum socket or fully qualified domain name or IP number of the host\n\t * @param options - ...\n\t *\n\t * @throws {Error} if `version` is not a valid version string.\n\t */ constructor(application, version, socketOrHostname, options = {}){\n // Initialize the event emitter.\n super();\n this.application = application;\n this.version = version;\n this.socketOrHostname = socketOrHostname;\n this.options = options;\n this.subscriptionMethods = {};\n this.requestId = 0;\n this.requestResolvers = {};\n this.connectionLock = new (0, async_mutex__WEBPACK_IMPORTED_MODULE_2__.Mutex)();\n // Update default options with the provided values.\n const networkOptions = {\n ...(0, $d801b1f9b7fc3074$export$5ba3a4134d0d751d),\n ...options\n };\n // Set up a connection to an electrum server.\n this.connection = new (0, $ff134c9a9e1f7361$export$de0f57fc22079b5e)(application, version, socketOrHostname, networkOptions);\n }\n // Expose hostIdentifier from the connection.\n get hostIdentifier() {\n return this.connection.hostIdentifier;\n }\n // Expose port from the connection.\n get encrypted() {\n return this.connection.encrypted;\n }\n /**\n\t * Connects to the remote server.\n\t *\n\t * @throws {Error} if the socket connection fails.\n\t * @returns a promise resolving when the connection is established.\n\t */ async connect() {\n // Create a lock so that multiple connects/disconnects cannot race each other.\n const unlock = await this.connectionLock.acquire();\n try {\n // If we are already connected, do not attempt to connect again.\n if (this.connection.status === (0, $db7c797e63383364$export$7516420eb880ab68).CONNECTED) return;\n // Listen for parsed statements.\n this.connection.on(\"response\", this.response.bind(this));\n // Hook up handles for the connected and disconnected events.\n this.connection.on(\"connected\", this.resubscribeOnConnect.bind(this));\n this.connection.on(\"disconnected\", this.onConnectionDisconnect.bind(this));\n // Relay connecting and reconnecting events.\n this.connection.on(\"connecting\", this.handleConnectionStatusChanges.bind(this, \"connecting\"));\n this.connection.on(\"disconnecting\", this.handleConnectionStatusChanges.bind(this, \"disconnecting\"));\n this.connection.on(\"reconnecting\", this.handleConnectionStatusChanges.bind(this, \"reconnecting\"));\n // Hook up client metadata gathering functions.\n this.connection.on(\"version\", this.storeSoftwareVersion.bind(this));\n this.connection.on(\"received\", this.updateLastReceivedTimestamp.bind(this));\n // Relay error events.\n this.connection.on(\"error\", this.emit.bind(this, \"error\"));\n // Connect with the server.\n await this.connection.connect();\n } finally{\n unlock();\n }\n }\n /**\n\t * Disconnects from the remote server and removes all event listeners/subscriptions and open requests.\n\t *\n\t * @param force - disconnect even if the connection has not been fully established yet.\n\t * @param retainSubscriptions - retain subscription data so they will be restored on reconnection.\n\t *\n\t * @returns true if successfully disconnected, or false if there was no connection.\n\t */ async disconnect(force = false, retainSubscriptions = false) {\n if (!retainSubscriptions) {\n // Cancel all event listeners.\n this.removeAllListeners();\n // Remove all subscription data\n this.subscriptionMethods = {};\n }\n // Disconnect from the remote server.\n return this.connection.disconnect(force);\n }\n /**\n\t * Calls a method on the remote server with the supplied parameters.\n\t *\n\t * @param method - name of the method to call.\n\t * @param parameters - one or more parameters for the method.\n\t *\n\t * @throws {Error} if the client is disconnected.\n\t * @returns a promise that resolves with the result of the method or an Error.\n\t */ async request(method, ...parameters) {\n // If we are not connected to a server..\n if (this.connection.status !== (0, $db7c797e63383364$export$7516420eb880ab68).CONNECTED) // Reject the request with a disconnected error message.\n throw new Error(`Unable to send request to a disconnected server '${this.hostIdentifier}'.`);\n // Increase the request ID by one.\n this.requestId += 1;\n // Store a copy of the request id.\n const id = this.requestId;\n // Format the arguments as an electrum request object.\n const message = (0, $24139611f53a54b8$export$5d955335434540c6).buildRequestObject(method, parameters, id);\n // Define a function to wrap the request in a promise.\n const requestResolver = (resolve)=>{\n // Add a request resolver for this promise to the list of requests.\n this.requestResolvers[id] = (error, data)=>{\n // If the resolution failed..\n if (error) // Resolve the promise with the error for the application to handle.\n resolve(error);\n else // Resolve the promise with the request results.\n resolve(data);\n };\n // Send the request message to the remote server.\n this.connection.send(message);\n };\n // Write a log message.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).network(`Sending request '${method}' to '${this.hostIdentifier}'`);\n // return a promise to deliver results later.\n return new Promise(requestResolver);\n }\n /**\n\t * Subscribes to the method and payload at the server.\n\t *\n\t * @remarks the response for the subscription request is issued as a notification event.\n\t *\n\t * @param method - one of the subscribable methods the server supports.\n\t * @param parameters - one or more parameters for the method.\n\t *\n\t * @throws {Error} if the client is disconnected.\n\t * @returns a promise resolving when the subscription is established.\n\t */ async subscribe(method, ...parameters) {\n // Initialize an empty list of subscription payloads, if needed.\n if (!this.subscriptionMethods[method]) this.subscriptionMethods[method] = new Set();\n // Store the subscription parameters to track what data we have subscribed to.\n this.subscriptionMethods[method].add(JSON.stringify(parameters));\n // Send initial subscription request.\n const requestData = await this.request(method, ...parameters);\n // If the request failed, throw it as an error.\n if (requestData instanceof Error) throw requestData;\n // If the request returned more than one data point..\n if (Array.isArray(requestData)) // .. throw an error, as this breaks our expectation for subscriptions.\n throw new Error(\"Subscription request returned an more than one data point.\");\n // Construct a notification structure to package the initial result as a notification.\n const notification = {\n jsonrpc: \"2.0\",\n method: method,\n params: [\n ...parameters,\n requestData\n ]\n };\n // Manually emit an event for the initial response.\n this.emit(\"notification\", notification);\n // Try to update the chain height.\n this.updateChainHeightFromHeadersNotifications(notification);\n }\n /**\n\t * Unsubscribes to the method at the server and removes any callback functions\n\t * when there are no more subscriptions for the method.\n\t *\n\t * @param method - a previously subscribed to method.\n\t * @param parameters - one or more parameters for the method.\n\t *\n\t * @throws {Error} if no subscriptions exist for the combination of the provided `method` and `parameters.\n\t * @throws {Error} if the client is disconnected.\n\t * @returns a promise resolving when the subscription is removed.\n\t */ async unsubscribe(method, ...parameters) {\n // Throw an error if the client is disconnected.\n if (this.connection.status !== (0, $db7c797e63383364$export$7516420eb880ab68).CONNECTED) throw new Error(`Unable to send unsubscribe request to a disconnected server '${this.hostIdentifier}'.`);\n // If this method has no subscriptions..\n if (!this.subscriptionMethods[method]) // Reject this promise with an explanation.\n throw new Error(`Cannot unsubscribe from '${method}' since the method has no subscriptions.`);\n // Pack up the parameters as a long string.\n const subscriptionParameters = JSON.stringify(parameters);\n // If the method payload could not be located..\n if (!this.subscriptionMethods[method].has(subscriptionParameters)) // Reject this promise with an explanation.\n throw new Error(`Cannot unsubscribe from '${method}' since it has no subscription with the given parameters.`);\n // Remove this specific subscription payload from internal tracking.\n this.subscriptionMethods[method].delete(subscriptionParameters);\n // Send unsubscription request to the server\n // NOTE: As a convenience we allow users to define the method as the subscribe or unsubscribe version.\n await this.request(method.replace(\".subscribe\", \".unsubscribe\"), ...parameters);\n // Write a log message.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).client(`Unsubscribed from '${String(method)}' for the '${subscriptionParameters}' parameters.`);\n }\n /**\n\t * Restores existing subscriptions without updating status or triggering manual callbacks.\n\t *\n\t * @throws {Error} if subscription data cannot be found for all stored event names.\n\t * @throws {Error} if the client is disconnected.\n\t * @returns a promise resolving to true when the subscriptions are restored.\n\t *\n\t * @ignore\n\t */ async resubscribeOnConnect() {\n // Write a log message.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).client(`Connected to '${this.hostIdentifier}'.`);\n // Synchronize with the underlying connection status.\n this.handleConnectionStatusChanges(\"connected\");\n // Initialize an empty list of resubscription promises.\n const resubscriptionPromises = [];\n // For each method we have a subscription for..\n for(const method in this.subscriptionMethods){\n // .. and for each parameter we have previously been subscribed to..\n for (const parameterJSON of this.subscriptionMethods[method].values()){\n // restore the parameters from JSON.\n const parameters = JSON.parse(parameterJSON);\n // Send a subscription request.\n resubscriptionPromises.push(this.subscribe(method, ...parameters));\n }\n // Wait for all re-subscriptions to complete.\n await Promise.all(resubscriptionPromises);\n }\n // Write a log message if there was any subscriptions to restore.\n if (resubscriptionPromises.length > 0) (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).client(`Restored ${resubscriptionPromises.length} previous subscriptions for '${this.hostIdentifier}'`);\n }\n /**\n\t * Parser messages from the remote server to resolve request promises and emit subscription events.\n\t *\n\t * @param message - the response message\n\t *\n\t * @throws {Error} if the message ID does not match an existing request.\n\t * @ignore\n\t */ response(message) {\n // If the received message is a notification, we forward it to all event listeners\n if ((0, $abcb763a48577a1e$export$280de919a0cf6928)(message)) {\n // Write a log message.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).client(`Received notification for '${message.method}' from '${this.hostIdentifier}'`);\n // Forward the message content to all event listeners.\n this.emit(\"notification\", message);\n // Try to update the chain height.\n this.updateChainHeightFromHeadersNotifications(message);\n // Return since it does not have an associated request resolver\n return;\n }\n // If the response ID is null we cannot use it to index our request resolvers\n if (message.id === null) // Throw an internal error, this should not happen.\n throw new Error(\"Internal error: Received an RPC response with ID null.\");\n // Look up which request promise we should resolve this.\n const requestResolver = this.requestResolvers[message.id];\n // If we do not have a request resolver for this response message..\n if (!requestResolver) {\n // Log that a message was ignored since the request has already been rejected.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"]).warning(`Ignoring response #${message.id} as the request has already been rejected.`);\n // Return as this has now been fully handled.\n return;\n }\n // Remove the promise from the request list.\n delete this.requestResolvers[message.id];\n // If the message contains an error..\n if ((0, $abcb763a48577a1e$export$d73a2e87a509880)(message)) // Forward the message error to the request resolver and omit the `result` parameter.\n requestResolver(new Error(message.error.message));\n else {\n // Forward the message content to the request resolver and omit the `error` parameter\n // (by setting it to undefined).\n requestResolver(undefined, message.result);\n // Attempt to extract genesis hash from feature requests.\n this.storeGenesisHashFromFeaturesResponse(message);\n }\n }\n /**\n\t * Callback function that is called when connection to the Electrum server is lost.\n\t * Aborts all active requests with an error message indicating that connection was lost.\n\t *\n\t * @ignore\n\t */ async onConnectionDisconnect() {\n // Loop over active requests\n for(const resolverId in this.requestResolvers){\n // Extract request resolver for readability\n const requestResolver = this.requestResolvers[resolverId];\n // Resolve the active request with an error indicating that the connection was lost.\n requestResolver(new Error(\"Connection lost\"));\n // Remove the promise from the request list.\n delete this.requestResolvers[resolverId];\n }\n // Synchronize with the underlying connection status.\n this.handleConnectionStatusChanges(\"disconnected\");\n }\n /**\n\t * Stores the server provider software version field on successful version negotiation.\n\t *\n\t * @ignore\n\t */ async storeSoftwareVersion(versionStatement) {\n // TODO: handle failed version negotiation better.\n if (versionStatement.error) // Do nothing.\n return;\n // Store the software version.\n this.software = versionStatement.software;\n }\n /**\n\t * Updates the last received timestamp.\n\t *\n\t * @ignore\n\t */ async updateLastReceivedTimestamp() {\n // Update the timestamp for when we last received data.\n this.lastReceivedTimestamp = Date.now();\n }\n /**\n\t * Checks if the provided message is a response to a headers subscription,\n\t * and if so updates the locally stored chain height value for this client.\n\t *\n\t * @ignore\n\t */ async updateChainHeightFromHeadersNotifications(message) {\n // If the message is a notification for a new chain height..\n if (message.method === \"blockchain.headers.subscribe\") // ..also store the updated chain height locally.\n this.chainHeight = message.params[0].height;\n }\n /**\n\t * Checks if the provided message is a response to a server.features request,\n\t * and if so stores the genesis hash for this client locally.\n\t *\n\t * @ignore\n\t */ async storeGenesisHashFromFeaturesResponse(message) {\n try {\n // If the message is a response to a features request..\n if (typeof message.result.genesis_hash !== \"undefined\") // ..store the genesis hash locally.\n this.genesisHash = message.result.genesis_hash;\n } catch (error) {\n // Do nothing.\n }\n }\n /**\n\t * Helper function to synchronize state and events with the underlying connection.\n\t */ async handleConnectionStatusChanges(eventName) {\n // Re-emit the event.\n this.emit(eventName);\n }\n}\nvar // Export the client.\n$558b46d3f899ced5$export$2e2bcd8739ae039 = $558b46d3f899ced5$var$ElectrumClient;\n\n\n\n\n\n\n\n//# sourceMappingURL=index.mjs.map\n\n\n//# sourceURL=webpack://mainnet-js/../../node_modules/@electrum-cash/network/dist/index.mjs?");
1767
+ eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"ConnectionStatus\": () => (/* binding */ ConnectionStatus),\n/* harmony export */ \"ElectrumClient\": () => (/* binding */ electrum_client_default)\n/* harmony export */ });\n/* unused harmony exports isRPCErrorResponse, isRPCNotification, isRPCRequest, isRPCStatement, isVersionNegotiated, isVersionRejected */\n/* harmony import */ var _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @electrum-cash/debug-logs */ \"../../node_modules/@electrum-cash/debug-logs/dist/index.mjs\");\n/* harmony import */ var _electrum_cash_web_socket__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @electrum-cash/web-socket */ \"../../node_modules/@electrum-cash/web-socket/dist/index.mjs\");\n/* harmony import */ var eventemitter3__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! eventemitter3 */ \"../../node_modules/eventemitter3/index.mjs\");\n/* harmony import */ var lossless_json__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! lossless-json */ \"../../node_modules/lossless-json/lib/esm/index.js\");\n/* harmony import */ var async_mutex__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! async-mutex */ \"../../node_modules/async-mutex/index.mjs\");\n\n\n\n\n\n\n//#region source/electrum-protocol.ts\n/**\n* Grouping of utilities that simplifies implementation of the Electrum protocol.\n*\n* @ignore\n*/\nvar ElectrumProtocol = class {\n\t/**\n\t* Helper function that builds an Electrum request object.\n\t*\n\t* @param method - method to call.\n\t* @param parameters - method parameters for the call.\n\t* @param requestId - unique string or number referencing this request.\n\t*\n\t* @returns a properly formatted Electrum request string.\n\t*/\n\tstatic buildRequestObject(method, parameters, requestId) {\n\t\treturn JSON.stringify({\n\t\t\tmethod,\n\t\t\tparams: parameters,\n\t\t\tid: requestId\n\t\t});\n\t}\n\t/**\n\t* Constant used to verify if a provided string is a valid version number.\n\t*\n\t* @returns a regular expression that matches valid version numbers.\n\t*/\n\tstatic get versionRegexp() {\n\t\treturn /^\\d+(\\.\\d+)+$/;\n\t}\n\t/**\n\t* Constant used to separate statements/messages in a stream of data.\n\t*\n\t* @returns the delimiter used by Electrum to separate statements.\n\t*/\n\tstatic get statementDelimiter() {\n\t\treturn \"\\n\";\n\t}\n};\n\n//#endregion\n//#region source/rpc-interfaces.ts\nconst isRPCErrorResponse = function(message) {\n\treturn \"id\" in message && \"error\" in message;\n};\nconst isRPCStatement = function(message) {\n\treturn \"id\" in message && \"result\" in message;\n};\nconst isRPCNotification = function(message) {\n\treturn !(\"id\" in message) && \"method\" in message;\n};\nconst isRPCRequest = function(message) {\n\treturn \"id\" in message && \"method\" in message;\n};\n\n//#endregion\n//#region source/enums.ts\n/**\n* Enum that denotes the connection status of an ElectrumConnection.\n* @enum {number}\n* @property {0} DISCONNECTED The connection is disconnected.\n* @property {1} AVAILABLE The connection is connected.\n* @property {2} DISCONNECTING The connection is disconnecting.\n* @property {3} CONNECTING The connection is connecting.\n* @property {4} RECONNECTING The connection is restarting.\n*/\nlet ConnectionStatus = /* @__PURE__ */ function(ConnectionStatus$1) {\n\tConnectionStatus$1[ConnectionStatus$1[\"DISCONNECTED\"] = 0] = \"DISCONNECTED\";\n\tConnectionStatus$1[ConnectionStatus$1[\"CONNECTED\"] = 1] = \"CONNECTED\";\n\tConnectionStatus$1[ConnectionStatus$1[\"DISCONNECTING\"] = 2] = \"DISCONNECTING\";\n\tConnectionStatus$1[ConnectionStatus$1[\"CONNECTING\"] = 3] = \"CONNECTING\";\n\tConnectionStatus$1[ConnectionStatus$1[\"RECONNECTING\"] = 4] = \"RECONNECTING\";\n\treturn ConnectionStatus$1;\n}({});\n\n//#endregion\n//#region source/interfaces.ts\n/**\n* @ignore\n*/\nconst isVersionRejected = function(object) {\n\treturn \"error\" in object;\n};\n/**\n* @ignore\n*/\nconst isVersionNegotiated = function(object) {\n\treturn \"software\" in object && \"protocol\" in object;\n};\n\n//#endregion\n//#region source/electrum-connection.ts\n/**\n* Wrapper around TLS/WSS sockets that gracefully separates a network stream into Electrum protocol messages.\n*/\nvar ElectrumConnection = class extends eventemitter3__WEBPACK_IMPORTED_MODULE_2__.EventEmitter {\n\tstatus = ConnectionStatus.DISCONNECTED;\n\tlastReceivedTimestamp;\n\tsocket;\n\tkeepAliveTimer;\n\treconnectTimer;\n\tverifications = [];\n\tmessageBuffer = \"\";\n\t/**\n\t* Sets up network configuration for an Electrum client connection.\n\t*\n\t* @param application - your application name, used to identify to the electrum host.\n\t* @param version - protocol version to use with the host.\n\t* @param socketOrHostname - pre-configured electrum socket or fully qualified domain name or IP number of the host\n\t* @param options - ...\n\t*\n\t* @throws {Error} if `version` is not a valid version string.\n\t*/\n\tconstructor(application, version, socketOrHostname, options) {\n\t\tsuper();\n\t\tthis.application = application;\n\t\tthis.version = version;\n\t\tthis.socketOrHostname = socketOrHostname;\n\t\tthis.options = options;\n\t\tif (!ElectrumProtocol.versionRegexp.test(version)) throw /* @__PURE__ */ new Error(`Provided version string (${version}) is not a valid protocol version number.`);\n\t\tif (typeof socketOrHostname === \"string\") this.socket = new _electrum_cash_web_socket__WEBPACK_IMPORTED_MODULE_1__.ElectrumWebSocket(socketOrHostname, void 0, void 0, void 0, this.options);\n\t\telse this.socket = socketOrHostname;\n\t\tthis.socket.on(\"connected\", this.onSocketConnect.bind(this));\n\t\tthis.socket.on(\"disconnected\", this.onSocketDisconnect.bind(this));\n\t\tthis.socket.on(\"data\", this.parseMessageChunk.bind(this));\n\t}\n\tget hostIdentifier() {\n\t\treturn this.socket.hostIdentifier;\n\t}\n\tget encrypted() {\n\t\treturn this.socket.encrypted;\n\t}\n\t/**\n\t* Assembles incoming data into statements and hands them off to the message parser.\n\t*\n\t* @param data - data to append to the current message buffer, as a string.\n\t*\n\t* @throws {SyntaxError} if the passed statement parts are not valid JSON.\n\t*/\n\tparseMessageChunk(data) {\n\t\tthis.lastReceivedTimestamp = Date.now();\n\t\tthis.emit(\"received\");\n\t\tthis.verifications.forEach((timer) => clearTimeout(timer));\n\t\tthis.verifications.length = 0;\n\t\tthis.messageBuffer += data;\n\t\twhile (this.messageBuffer.includes(ElectrumProtocol.statementDelimiter)) {\n\t\t\tconst statementParts = this.messageBuffer.split(ElectrumProtocol.statementDelimiter);\n\t\t\twhile (statementParts.length > 1) {\n\t\t\t\tlet statementList = (0,lossless_json__WEBPACK_IMPORTED_MODULE_3__.parse)(String(statementParts.shift()), null, this.options.useBigInt ? lossless_json__WEBPACK_IMPORTED_MODULE_3__.parseNumberAndBigInt : parseFloat);\n\t\t\t\tif (!Array.isArray(statementList)) statementList = [statementList];\n\t\t\t\twhile (statementList.length > 0) {\n\t\t\t\t\tconst currentStatement = statementList.shift();\n\t\t\t\t\tif (isRPCNotification(currentStatement)) {\n\t\t\t\t\t\tthis.emit(\"response\", currentStatement);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (currentStatement.id === \"versionNegotiation\") {\n\t\t\t\t\t\tif (isRPCErrorResponse(currentStatement)) this.emit(\"version\", { error: currentStatement.error });\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst [software, protocol] = currentStatement.result;\n\t\t\t\t\t\t\tthis.emit(\"version\", {\n\t\t\t\t\t\t\t\tsoftware,\n\t\t\t\t\t\t\t\tprotocol\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (currentStatement.id === \"keepAlive\") continue;\n\t\t\t\t\tthis.emit(\"response\", currentStatement);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.messageBuffer = statementParts.shift() || \"\";\n\t\t}\n\t}\n\t/**\n\t* Sends a keep-alive message to the host.\n\t*\n\t* @returns true if the ping message was fully flushed to the socket, false if\n\t* part of the message is queued in the user memory\n\t*/\n\tping() {\n\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].ping(`Sending keep-alive ping to '${this.hostIdentifier}'`);\n\t\tconst message = ElectrumProtocol.buildRequestObject(\"server.ping\", [], \"keepAlive\");\n\t\treturn this.send(message);\n\t}\n\t/**\n\t* Initiates the network connection negotiates a protocol version. Also emits the 'connect' signal if successful.\n\t*\n\t* @throws {Error} if the socket connection fails.\n\t* @returns a promise resolving when the connection is established\n\t*/\n\tasync connect() {\n\t\tif (this.status === ConnectionStatus.CONNECTED) return;\n\t\tthis.status = ConnectionStatus.CONNECTING;\n\t\tthis.emit(\"connecting\");\n\t\tconst connectionResolver = (resolve, reject) => {\n\t\t\tthis.once(\"connected\", () => {\n\t\t\t\tthis.removeListener(\"disconnected\", reject);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t\tthis.once(\"disconnected\", () => {\n\t\t\t\tthis.removeListener(\"connected\", resolve);\n\t\t\t\treject();\n\t\t\t});\n\t\t\tthis.socket.connect();\n\t\t};\n\t\tawait new Promise(connectionResolver);\n\t}\n\t/**\n\t* Restores the network connection.\n\t*/\n\tasync reconnect() {\n\t\tawait this.clearReconnectTimer();\n\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].network(`Trying to reconnect to '${this.hostIdentifier}'..`);\n\t\tthis.status = ConnectionStatus.RECONNECTING;\n\t\tthis.emit(\"reconnecting\");\n\t\tthis.socket.disconnect();\n\t\ttry {\n\t\t\tawait this.connect();\n\t\t} catch (_error) {}\n\t}\n\t/**\n\t* Removes the current reconnect timer.\n\t*/\n\tclearReconnectTimer() {\n\t\tif (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n\t\tthis.reconnectTimer = void 0;\n\t}\n\t/**\n\t* Removes the current keep-alive timer.\n\t*/\n\tclearKeepAliveTimer() {\n\t\tif (this.keepAliveTimer) clearTimeout(this.keepAliveTimer);\n\t\tthis.keepAliveTimer = void 0;\n\t}\n\t/**\n\t* Initializes the keep alive timer loop.\n\t*/\n\tsetupKeepAliveTimer() {\n\t\tif (!this.keepAliveTimer) this.keepAliveTimer = setTimeout(this.ping.bind(this), this.options.sendKeepAliveIntervalInMilliSeconds);\n\t}\n\t/**\n\t* Tears down the current connection and removes all event listeners on disconnect.\n\t*\n\t* @param force - disconnect even if the connection has not been fully established yet.\n\t* @param intentional - update connection state if disconnect is intentional.\n\t*\n\t* @returns true if successfully disconnected, or false if there was no connection.\n\t*/\n\tasync disconnect(force = false, intentional = true) {\n\t\tif (this.status === ConnectionStatus.DISCONNECTED && !force) return false;\n\t\tif (intentional) this.status = ConnectionStatus.DISCONNECTING;\n\t\tthis.emit(\"disconnecting\");\n\t\tawait this.clearKeepAliveTimer();\n\t\tawait this.clearReconnectTimer();\n\t\tconst disconnectResolver = (resolve) => {\n\t\t\tthis.once(\"disconnected\", () => resolve(true));\n\t\t\tthis.socket.disconnect();\n\t\t};\n\t\treturn new Promise(disconnectResolver);\n\t}\n\t/**\n\t* Sends an arbitrary message to the server.\n\t*\n\t* @param message - json encoded request object to send to the server, as a string.\n\t*\n\t* @returns true if the message was fully flushed to the socket, false if part of the message\n\t* is queued in the user memory\n\t*/\n\tsend(message) {\n\t\tthis.clearKeepAliveTimer();\n\t\tconst currentTime = Date.now();\n\t\tconst verificationTimer = setTimeout(this.verifySend.bind(this, currentTime), this.socket.timeout);\n\t\tthis.verifications.push(verificationTimer);\n\t\tthis.setupKeepAliveTimer();\n\t\treturn this.socket.write(message + ElectrumProtocol.statementDelimiter);\n\t}\n\t/**\n\t* Marks the connection as timed out and schedules reconnection if we have not\n\t* received data within the expected time frame.\n\t*/\n\tverifySend(sentTimestamp) {\n\t\tif (Number(this.lastReceivedTimestamp) < sentTimestamp) {\n\t\t\tif (this.status === ConnectionStatus.DISCONNECTED || this.status === ConnectionStatus.DISCONNECTING) return;\n\t\t\tthis.clearKeepAliveTimer();\n\t\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].network(`Connection to '${this.hostIdentifier}' timed out.`);\n\t\t\tthis.socket.disconnect();\n\t\t}\n\t}\n\t/**\n\t* Updates the connection status when a connection is confirmed.\n\t*/\n\tasync onSocketConnect() {\n\t\tthis.clearReconnectTimer();\n\t\tthis.lastReceivedTimestamp = Date.now();\n\t\tthis.setupKeepAliveTimer();\n\t\tawait new Promise(this.negotiateVersion.bind(this));\n\t\tthis.emit(\"connected\");\n\t\tthis.socket.removeAllListeners(\"error\");\n\t\tthis.socket.on(\"error\", this.onSocketError.bind(this));\n\t}\n\t/**\n\t* Updates the connection status when a connection is ended.\n\t*/\n\tonSocketDisconnect() {\n\t\tthis.clearKeepAliveTimer();\n\t\tif (this.status === ConnectionStatus.DISCONNECTING) {\n\t\t\tthis.status = ConnectionStatus.DISCONNECTED;\n\t\t\tthis.emit(\"disconnected\");\n\t\t\tthis.clearReconnectTimer();\n\t\t\tthis.removeAllListeners();\n\t\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].network(`Disconnected from '${this.hostIdentifier}'.`);\n\t\t} else {\n\t\t\tif (this.status === ConnectionStatus.CONNECTED) _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].errors(`Connection with '${this.hostIdentifier}' was closed, trying to reconnect in ${this.options.reconnectAfterMilliSeconds / 1e3} seconds.`);\n\t\t\tthis.status = ConnectionStatus.DISCONNECTED;\n\t\t\tthis.emit(\"disconnected\");\n\t\t\tif (!this.reconnectTimer) this.reconnectTimer = setTimeout(this.reconnect.bind(this), this.options.reconnectAfterMilliSeconds);\n\t\t}\n\t}\n\t/**\n\t* Notify administrator of any unexpected errors.\n\t*/\n\tonSocketError(error) {\n\t\tif (typeof error === \"undefined\") return;\n\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].errors(`Network error ('${this.hostIdentifier}'): `, error);\n\t}\n\t/**\n\t* Negotiate the protocol version with the server.\n\t* Disconnect the connection if the version negotiation fails.\n\t* @param resolve \n\t* @param reject \n\t*/\n\tasync negotiateVersion(resolve, reject) {\n\t\tconst rejector = (error) => {\n\t\t\tthis.status = ConnectionStatus.DISCONNECTED;\n\t\t\tthis.emit(\"disconnected\");\n\t\t\treject(error);\n\t\t};\n\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].network(`Requesting protocol version ${this.version} with '${this.hostIdentifier}'.`);\n\t\tthis.socket.once(\"error\", rejector);\n\t\tconst versionMessage = ElectrumProtocol.buildRequestObject(\"server.version\", [this.application, this.version], \"versionNegotiation\");\n\t\tconst versionValidator = (version) => {\n\t\t\tif (isVersionRejected(version)) {\n\t\t\t\tthis.disconnect(true);\n\t\t\t\tconst errorMessage = \"unsupported protocol version.\";\n\t\t\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].errors(`Failed to connect with ${this.hostIdentifier} due to ${errorMessage}`);\n\t\t\t\treject(errorMessage);\n\t\t\t} else if (version.protocol !== this.version && `${version.protocol}.0` !== this.version && `${version.protocol}.0.0` !== this.version) {\n\t\t\t\tthis.disconnect(true);\n\t\t\t\tconst errorMessage = `incompatible protocol version negotiated (${version.protocol} !== ${this.version}).`;\n\t\t\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].errors(`Failed to connect with ${this.hostIdentifier} due to ${errorMessage}`);\n\t\t\t\treject(errorMessage);\n\t\t\t} else {\n\t\t\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].network(`Negotiated protocol version ${version.protocol} with '${this.hostIdentifier}', powered by ${version.software}.`);\n\t\t\t\tthis.status = ConnectionStatus.CONNECTED;\n\t\t\t\tresolve();\n\t\t\t}\n\t\t};\n\t\tthis.once(\"version\", versionValidator);\n\t\tthis.send(versionMessage);\n\t}\n};\n\n//#endregion\n//#region source/constants.ts\nconst MILLI_SECONDS_PER_SECOND = 1e3;\n/**\n* Configure default options.\n*/\nconst defaultNetworkOptions = {\n\tuseBigInt: false,\n\tsendKeepAliveIntervalInMilliSeconds: 1 * MILLI_SECONDS_PER_SECOND,\n\treconnectAfterMilliSeconds: 5 * MILLI_SECONDS_PER_SECOND,\n\tverifyConnectionTimeoutInMilliSeconds: 5 * MILLI_SECONDS_PER_SECOND,\n\tdisableBrowserVisibilityHandling: false,\n\tdisableBrowserConnectivityHandling: false\n};\n\n//#endregion\n//#region source/electrum-client.ts\n/**\n* High-level Electrum client that lets applications send requests and subscribe to notification events from a server.\n*/\nvar ElectrumClient = class extends eventemitter3__WEBPACK_IMPORTED_MODULE_2__.EventEmitter {\n\t/**\n\t* The name and version of the server software indexing the blockchain.\n\t*/\n\tsoftware;\n\t/**\n\t* The genesis hash of the blockchain indexed by the server.\n\t* @remarks This is only available after a 'server.features' call.\n\t*/\n\tgenesisHash;\n\t/**\n\t* The chain height of the blockchain indexed by the server.\n\t* @remarks This is only available after a 'blockchain.headers.subscribe' call.\n\t*/\n\tchainHeight;\n\t/**\n\t* Timestamp of when we last received data from the server indexing the blockchain.\n\t*/\n\tlastReceivedTimestamp;\n\t/**\n\t* Number corresponding to the underlying connection status.\n\t*/\n\tget status() {\n\t\treturn this.connection.status;\n\t}\n\tconnection;\n\tsubscriptionMethods = {};\n\trequestId = 0;\n\trequestResolvers = {};\n\tconnectionLock = new async_mutex__WEBPACK_IMPORTED_MODULE_4__.Mutex();\n\t/**\n\t* Initializes an Electrum client.\n\t*\n\t* @param application - your application name, used to identify to the electrum host.\n\t* @param version - protocol version to use with the host.\n\t* @param socketOrHostname - pre-configured electrum socket or fully qualified domain name or IP number of the host\n\t* @param options - ...\n\t*\n\t* @throws {Error} if `version` is not a valid version string.\n\t*/\n\tconstructor(application, version, socketOrHostname, options = {}) {\n\t\tsuper();\n\t\tthis.application = application;\n\t\tthis.version = version;\n\t\tthis.socketOrHostname = socketOrHostname;\n\t\tthis.options = options;\n\t\tthis.connection = new ElectrumConnection(application, version, socketOrHostname, {\n\t\t\t...defaultNetworkOptions,\n\t\t\t...options\n\t\t});\n\t}\n\tget hostIdentifier() {\n\t\treturn this.connection.hostIdentifier;\n\t}\n\tget encrypted() {\n\t\treturn this.connection.encrypted;\n\t}\n\t/**\n\t* Connects to the remote server.\n\t*\n\t* @throws {Error} if the socket connection fails.\n\t* @returns a promise resolving when the connection is established.\n\t*/\n\tasync connect() {\n\t\tconst unlock = await this.connectionLock.acquire();\n\t\ttry {\n\t\t\tif (this.connection.status === ConnectionStatus.CONNECTED) return;\n\t\t\tthis.connection.on(\"response\", this.response.bind(this));\n\t\t\tthis.connection.on(\"connected\", this.resubscribeOnConnect.bind(this));\n\t\t\tthis.connection.on(\"disconnected\", this.onConnectionDisconnect.bind(this));\n\t\t\tthis.connection.on(\"connecting\", this.handleConnectionStatusChanges.bind(this, \"connecting\"));\n\t\t\tthis.connection.on(\"disconnecting\", this.handleConnectionStatusChanges.bind(this, \"disconnecting\"));\n\t\t\tthis.connection.on(\"reconnecting\", this.handleConnectionStatusChanges.bind(this, \"reconnecting\"));\n\t\t\tthis.connection.on(\"version\", this.storeSoftwareVersion.bind(this));\n\t\t\tthis.connection.on(\"received\", this.updateLastReceivedTimestamp.bind(this));\n\t\t\tthis.connection.on(\"error\", this.emit.bind(this, \"error\"));\n\t\t\tawait this.connection.connect();\n\t\t} finally {\n\t\t\tunlock();\n\t\t}\n\t}\n\t/**\n\t* Disconnects from the remote server and removes all event listeners/subscriptions and open requests.\n\t*\n\t* @param force - disconnect even if the connection has not been fully established yet.\n\t* @param retainSubscriptions - retain subscription data so they will be restored on reconnection.\n\t*\n\t* @returns true if successfully disconnected, or false if there was no connection.\n\t*/\n\tasync disconnect(force = false, retainSubscriptions = false) {\n\t\tif (!retainSubscriptions) {\n\t\t\tthis.removeAllListeners();\n\t\t\tthis.subscriptionMethods = {};\n\t\t}\n\t\treturn this.connection.disconnect(force);\n\t}\n\t/**\n\t* Calls a method on the remote server with the supplied parameters.\n\t*\n\t* @param method - name of the method to call.\n\t* @param parameters - one or more parameters for the method.\n\t*\n\t* @throws {Error} if the client is disconnected.\n\t* @returns a promise that resolves with the result of the method or an Error.\n\t*/\n\tasync request(method, ...parameters) {\n\t\tif (this.connection.status !== ConnectionStatus.CONNECTED) throw /* @__PURE__ */ new Error(`Unable to send request to a disconnected server '${this.hostIdentifier}'.`);\n\t\tthis.requestId += 1;\n\t\tconst id = this.requestId;\n\t\tconst message = ElectrumProtocol.buildRequestObject(method, parameters, id);\n\t\tconst requestResolver = (resolve) => {\n\t\t\tthis.requestResolvers[id] = (error, data) => {\n\t\t\t\tif (error) resolve(error);\n\t\t\t\telse resolve(data);\n\t\t\t};\n\t\t\tthis.connection.send(message);\n\t\t};\n\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].network(`Sending request '${method}' to '${this.hostIdentifier}'`);\n\t\treturn new Promise(requestResolver);\n\t}\n\t/**\n\t* Subscribes to the method and payload at the server.\n\t*\n\t* @remarks the response for the subscription request is issued as a notification event.\n\t*\n\t* @param method - one of the subscribable methods the server supports.\n\t* @param parameters - one or more parameters for the method.\n\t*\n\t* @throws {Error} if the client is disconnected.\n\t* @returns a promise resolving when the subscription is established.\n\t*/\n\tasync subscribe(method, ...parameters) {\n\t\tif (!this.subscriptionMethods[method]) this.subscriptionMethods[method] = /* @__PURE__ */ new Set();\n\t\tthis.subscriptionMethods[method].add(JSON.stringify(parameters));\n\t\tconst requestData = await this.request(method, ...parameters);\n\t\tif (requestData instanceof Error) throw requestData;\n\t\tif (Array.isArray(requestData)) throw /* @__PURE__ */ new Error(\"Subscription request returned an more than one data point.\");\n\t\tconst notification = {\n\t\t\tjsonrpc: \"2.0\",\n\t\t\tmethod,\n\t\t\tparams: [...parameters, requestData]\n\t\t};\n\t\tthis.emit(\"notification\", notification);\n\t\tthis.updateChainHeightFromHeadersNotifications(notification);\n\t}\n\t/**\n\t* Unsubscribes to the method at the server and removes any callback functions\n\t* when there are no more subscriptions for the method.\n\t*\n\t* @param method - a previously subscribed to method.\n\t* @param parameters - one or more parameters for the method.\n\t*\n\t* @throws {Error} if no subscriptions exist for the combination of the provided `method` and `parameters.\n\t* @throws {Error} if the client is disconnected.\n\t* @returns a promise resolving when the subscription is removed.\n\t*/\n\tasync unsubscribe(method, ...parameters) {\n\t\tif (this.connection.status !== ConnectionStatus.CONNECTED) throw /* @__PURE__ */ new Error(`Unable to send unsubscribe request to a disconnected server '${this.hostIdentifier}'.`);\n\t\tif (!this.subscriptionMethods[method]) throw /* @__PURE__ */ new Error(`Cannot unsubscribe from '${method}' since the method has no subscriptions.`);\n\t\tconst subscriptionParameters = JSON.stringify(parameters);\n\t\tif (!this.subscriptionMethods[method].has(subscriptionParameters)) throw /* @__PURE__ */ new Error(`Cannot unsubscribe from '${method}' since it has no subscription with the given parameters.`);\n\t\tthis.subscriptionMethods[method].delete(subscriptionParameters);\n\t\tawait this.request(method.replace(\".subscribe\", \".unsubscribe\"), ...parameters);\n\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].client(`Unsubscribed from '${String(method)}' for the '${subscriptionParameters}' parameters.`);\n\t}\n\t/**\n\t* Restores existing subscriptions without updating status or triggering manual callbacks.\n\t*\n\t* @throws {Error} if subscription data cannot be found for all stored event names.\n\t* @throws {Error} if the client is disconnected.\n\t* @returns a promise resolving to true when the subscriptions are restored.\n\t*\n\t* @ignore\n\t*/\n\tasync resubscribeOnConnect() {\n\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].client(`Connected to '${this.hostIdentifier}'.`);\n\t\tthis.handleConnectionStatusChanges(\"connected\");\n\t\tconst resubscriptionPromises = [];\n\t\tfor (const method in this.subscriptionMethods) {\n\t\t\tfor (const parameterJSON of this.subscriptionMethods[method].values()) {\n\t\t\t\tconst parameters = JSON.parse(parameterJSON);\n\t\t\t\tresubscriptionPromises.push(this.subscribe(method, ...parameters));\n\t\t\t}\n\t\t\tawait Promise.all(resubscriptionPromises);\n\t\t}\n\t\tif (resubscriptionPromises.length > 0) _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].client(`Restored ${resubscriptionPromises.length} previous subscriptions for '${this.hostIdentifier}'`);\n\t}\n\t/**\n\t* Parser messages from the remote server to resolve request promises and emit subscription events.\n\t*\n\t* @param message - the response message\n\t*\n\t* @throws {Error} if the message ID does not match an existing request.\n\t* @ignore\n\t*/\n\tresponse(message) {\n\t\tif (isRPCNotification(message)) {\n\t\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].client(`Received notification for '${message.method}' from '${this.hostIdentifier}'`);\n\t\t\tthis.emit(\"notification\", message);\n\t\t\tthis.updateChainHeightFromHeadersNotifications(message);\n\t\t\treturn;\n\t\t}\n\t\tif (message.id === null) throw /* @__PURE__ */ new Error(\"Internal error: Received an RPC response with ID null.\");\n\t\tconst requestResolver = this.requestResolvers[message.id];\n\t\tif (!requestResolver) {\n\t\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_0__[\"default\"].warning(`Ignoring response #${message.id} as the request has already been rejected.`);\n\t\t\treturn;\n\t\t}\n\t\tdelete this.requestResolvers[message.id];\n\t\tif (isRPCErrorResponse(message)) requestResolver(new Error(message.error.message));\n\t\telse {\n\t\t\trequestResolver(void 0, message.result);\n\t\t\tthis.storeGenesisHashFromFeaturesResponse(message);\n\t\t}\n\t}\n\t/**\n\t* Callback function that is called when connection to the Electrum server is lost.\n\t* Aborts all active requests with an error message indicating that connection was lost.\n\t*\n\t* @ignore\n\t*/\n\tasync onConnectionDisconnect() {\n\t\tfor (const resolverId in this.requestResolvers) {\n\t\t\tconst requestResolver = this.requestResolvers[resolverId];\n\t\t\trequestResolver(/* @__PURE__ */ new Error(\"Connection lost\"));\n\t\t\tdelete this.requestResolvers[resolverId];\n\t\t}\n\t\tthis.handleConnectionStatusChanges(\"disconnected\");\n\t}\n\t/**\n\t* Stores the server provider software version field on successful version negotiation.\n\t*\n\t* @ignore\n\t*/\n\tasync storeSoftwareVersion(versionStatement) {\n\t\tif (versionStatement.error) return;\n\t\tthis.software = versionStatement.software;\n\t}\n\t/**\n\t* Updates the last received timestamp.\n\t*\n\t* @ignore\n\t*/\n\tasync updateLastReceivedTimestamp() {\n\t\tthis.lastReceivedTimestamp = Date.now();\n\t}\n\t/**\n\t* Checks if the provided message is a response to a headers subscription,\n\t* and if so updates the locally stored chain height value for this client.\n\t*\n\t* @ignore\n\t*/\n\tasync updateChainHeightFromHeadersNotifications(message) {\n\t\tif (message.method === \"blockchain.headers.subscribe\") this.chainHeight = message.params[0].height;\n\t}\n\t/**\n\t* Checks if the provided message is a response to a server.features request,\n\t* and if so stores the genesis hash for this client locally.\n\t*\n\t* @ignore\n\t*/\n\tasync storeGenesisHashFromFeaturesResponse(message) {\n\t\ttry {\n\t\t\tif (typeof message.result.genesis_hash !== \"undefined\") this.genesisHash = message.result.genesis_hash;\n\t\t} catch (_ignored) {}\n\t}\n\t/**\n\t* Helper function to synchronize state and events with the underlying connection.\n\t*/\n\tasync handleConnectionStatusChanges(eventName) {\n\t\tthis.emit(eventName);\n\t}\n\tconnecting;\n\tconnected;\n\tdisconnecting;\n\tdisconnected;\n\treconnecting;\n\tnotification;\n\terror;\n};\nvar electrum_client_default = ElectrumClient;\n\n//#endregion\n\n//# sourceMappingURL=index.mjs.map\n\n//# sourceURL=webpack://mainnet-js/../../node_modules/@electrum-cash/network/dist/index.mjs?");
1768
1768
 
1769
1769
  /***/ }),
1770
1770
 
@@ -1774,7 +1774,7 @@ eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harm
1774
1774
  \*******************************************************************/
1775
1775
  /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
1776
1776
 
1777
- eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"ElectrumWebSocket\": () => (/* binding */ $05743633fea447d4$export$25b4633f61498e1)\n/* harmony export */ });\n/* harmony import */ var _monsterbitar_isomorphic_ws__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @monsterbitar/isomorphic-ws */ \"../../node_modules/@monsterbitar/isomorphic-ws/browser.mjs\");\n/* harmony import */ var eventemitter3__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! eventemitter3 */ \"../../node_modules/eventemitter3/index.mjs\");\n/* harmony import */ var _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @electrum-cash/debug-logs */ \"../../node_modules/@electrum-cash/debug-logs/dist/index.mjs\");\n\n\n\n\n\nfunction $parcel$export(e, n, v, s) {\n Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true});\n}\nvar $05743633fea447d4$exports = {};\n\n$parcel$export($05743633fea447d4$exports, \"ElectrumWebSocket\", () => $05743633fea447d4$export$25b4633f61498e1);\n\n\n\n// Export a default timeout value of 30 seconds.\nconst $d801b1f9b7fc3074$export$1bddf2b96e25d075 = 30000;\n\n\nclass $05743633fea447d4$export$25b4633f61498e1 extends (0, eventemitter3__WEBPACK_IMPORTED_MODULE_1__.EventEmitter) {\n host;\n port;\n encrypted;\n timeout;\n // Declare an empty WebSocket.\n webSocket;\n // Used to disconnect after some time if initial connection is too slow.\n disconnectTimer;\n // Initialize boolean that indicates whether the onConnect function has run (initialize to false).\n onConnectHasRun;\n // Initialize event forwarding functions.\n eventForwarders;\n /**\n\t * Creates a socket configured with connection information for a given Electrum server.\n\t *\n\t * @param host Fully qualified domain name or IP address of the host\n\t * @param port Network port for the host to connect to, defaults to the standard TLS port\n\t * @param encrypted If false, uses an unencrypted connection instead of the default on TLS\n\t * @param timeout If no connection is established after `timeout` ms, the connection is terminated\n\t */ constructor(host, port = 50004, encrypted = true, timeout = (0, $d801b1f9b7fc3074$export$1bddf2b96e25d075)){\n // Initialize the event emitter.\n super();\n this.host = host;\n this.port = port;\n this.encrypted = encrypted;\n this.timeout = timeout;\n this.onConnectHasRun = false;\n this.eventForwarders = {\n disconnect: ()=>this.emit(\"disconnected\"),\n wsData: (event)=>this.emit(\"data\", `${event.data}\\n`),\n wsError: (event)=>this.emit(\"error\", new Error(event.error))\n };\n }\n /**\n\t * Returns a string for the host identifier for usage in debug messages.\n\t */ get hostIdentifier() {\n return `${this.host}:${this.port}`;\n }\n /**\n\t * Connect to host:port using the specified transport\n\t */ connect() {\n // Check that no existing socket exists before initiating a new connection.\n if (this.webSocket) throw new Error(\"Cannot initiate a new socket connection when an existing connection exists\");\n // Set a timer to force disconnect after `timeout` seconds\n this.disconnectTimer = setTimeout(()=>this.disconnectOnTimeout(), this.timeout);\n // Remove the timer if a connection is successfully established\n this.once(\"connected\", this.clearDisconnectTimerOnTimeout);\n // Set a named connection type for logging purposes.\n const connectionType = this.encrypted ? \"an encrypted WebSocket\" : \"a WebSocket\";\n // Log that we are trying to establish a connection.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_2__[\"default\"]).network(`Initiating ${connectionType} connection to '${this.host}:${this.port}'.`);\n if (this.encrypted) // Initialize this.webSocket (rejecting self-signed certificates).\n // We reject self-signed certificates to match functionality of browsers.\n this.webSocket = new (0, _monsterbitar_isomorphic_ws__WEBPACK_IMPORTED_MODULE_0__.WebSocket)(`wss://${this.host}:${this.port}`);\n else // Initialize this.webSocket.\n this.webSocket = new (0, _monsterbitar_isomorphic_ws__WEBPACK_IMPORTED_MODULE_0__.WebSocket)(`ws://${this.host}:${this.port}`);\n // Trigger successful connection events.\n this.webSocket.addEventListener(\"open\", this.onConnect.bind(this));\n // Forward the encountered errors.\n this.webSocket.addEventListener(\"error\", this.eventForwarders.wsError);\n }\n /**\n\t * Sets up forwarding of events related to the connection.\n\t */ onConnect() {\n // If the onConnect function has already run, do not execute it again.\n if (this.onConnectHasRun) return;\n // Set a named connection type for logging purposes.\n const connectionType = this.encrypted ? \"an encrypted WebSocket\" : \"a WebSocket\";\n // Log that the connection has been established.\n (0, _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_2__[\"default\"]).network(`Established ${connectionType} connection with '${this.host}:${this.port}'.`);\n // Forward the socket events\n this.webSocket.addEventListener(\"close\", this.eventForwarders.disconnect);\n this.webSocket.addEventListener(\"message\", this.eventForwarders.wsData);\n // Indicate that the onConnect function has run.\n this.onConnectHasRun = true;\n // Emit the connect event.\n this.emit(\"connected\");\n }\n /**\n\t * Clears the disconnect timer if it is still active.\n\t */ clearDisconnectTimerOnTimeout() {\n // Clear the retry timer if it is still active.\n if (this.disconnectTimer) clearTimeout(this.disconnectTimer);\n }\n /**\n\t * Forcibly terminate the connection.\n\t *\n\t * @throws {Error} if no connection was found\n\t */ disconnect() {\n // Clear the disconnect timer so that the socket does not try to disconnect again later.\n this.clearDisconnectTimerOnTimeout();\n try {\n // Remove all event forwarders.\n this.webSocket.removeEventListener(\"close\", this.eventForwarders.disconnect);\n this.webSocket.removeEventListener(\"message\", this.eventForwarders.wsData);\n this.webSocket.removeEventListener(\"error\", this.eventForwarders.wsError);\n // Gracefully terminate the connection.\n this.webSocket.close();\n } catch (ignored) {\n // close() will throw an error if the connection has not been established yet.\n // We ignore this error, since no similar error gets thrown in the TLS Socket.\n } finally{\n // Remove the stored socket regardless of any thrown errors.\n this.webSocket = undefined;\n }\n // Indicate that the onConnect function has not run and it has to be run again.\n this.onConnectHasRun = false;\n // Emit a disconnect event\n this.emit(\"disconnected\");\n }\n /**\n\t * Write data to the socket\n\t *\n\t * @param data Data to be written to the socket\n\t * @param callback Callback function to be called when the write has completed\n\t *\n\t * @throws {Error} if no connection was found\n\t * @returns true if the message was fully flushed to the socket, false if part of the message\n\t * is queued in the user memory\n\t */ write(data, callback) {\n // Throw an error if no active connection is found\n if (!this.webSocket) throw new Error(\"Cannot write to socket when there is no active connection\");\n // Write data to the WebSocket\n this.webSocket.send(data, callback);\n // WebSockets always fit everything in a single request, so we return true\n return true;\n }\n /**\n\t * Force a disconnection if no connection is established after `timeout` milliseconds.\n\t */ disconnectOnTimeout() {\n // Remove the connect listener.\n this.removeListener(\"connected\", this.clearDisconnectTimerOnTimeout);\n // Emit an error event so that connect is rejected upstream.\n this.emit(\"error\", new Error(`Connection to '${this.host}:${this.port}' timed out after ${this.timeout} milliseconds`));\n // Forcibly disconnect to clean up the connection on timeout\n this.disconnect();\n }\n // Add magic glue that makes typedoc happy so that we can have the events listed on the class.\n connected;\n disconnected;\n data;\n error;\n}\n\n\n\n\n\n//# sourceMappingURL=index.mjs.map\n\n\n//# sourceURL=webpack://mainnet-js/../../node_modules/@electrum-cash/web-socket/dist/index.mjs?");
1777
+ eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"ElectrumWebSocket\": () => (/* binding */ ElectrumWebSocket)\n/* harmony export */ });\n/* harmony import */ var _monsterbitar_isomorphic_ws__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @monsterbitar/isomorphic-ws */ \"../../node_modules/@monsterbitar/isomorphic-ws/browser.mjs\");\n/* harmony import */ var eventemitter3__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! eventemitter3 */ \"../../node_modules/eventemitter3/index.mjs\");\n/* harmony import */ var _electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @electrum-cash/debug-logs */ \"../../node_modules/@electrum-cash/debug-logs/dist/index.mjs\");\n\n\n\n\n//#region source/constants.ts\nconst defaultTimeout = 30 * 1e3;\n\n//#endregion\n//#region source/web.ts\n/**\n* Web Socket used when communicating with Electrum servers.\n*/\nvar ElectrumWebSocket = class extends eventemitter3__WEBPACK_IMPORTED_MODULE_1__.EventEmitter {\n\twebSocket;\n\tdisconnectTimer;\n\tonConnectHasRun = false;\n\teventForwarders = {\n\t\tdisconnect: () => this.emit(\"disconnected\"),\n\t\twsData: (event) => this.emit(\"data\", `${event.data}\\n`),\n\t\twsError: (event) => this.emit(\"error\", new Error(event.error))\n\t};\n\tboundHandleVisibilityChange = this.handleVisibilityChange.bind(this);\n\tboundHandleConnectivityChange = this.handleConnectivityChange.bind(this);\n\t/**\n\t* Creates a socket configured with connection information for a given Electrum server.\n\t*\n\t* @param host Fully qualified domain name or IP address of the host\n\t* @param port Network port for the host to connect to, defaults to the standard TLS port\n\t* @param encrypted If false, uses an unencrypted connection instead of the default on TLS\n\t* @param timeout If no connection is established after `timeout` ms, the connection is terminated\n\t* @param reconnectionOptions Options to disable the automatic reconnection behavior when browser visibility or connectivity changes\n\t*/\n\tconstructor(host, port = 50004, encrypted = true, timeout = defaultTimeout, reconnectionOptions = {\n\t\tdisableBrowserVisibilityHandling: false,\n\t\tdisableBrowserConnectivityHandling: false\n\t}) {\n\t\tsuper();\n\t\tthis.host = host;\n\t\tthis.port = port;\n\t\tthis.encrypted = encrypted;\n\t\tthis.timeout = timeout;\n\t\tthis.reconnectionOptions = reconnectionOptions;\n\t}\n\t/**\n\t* Returns a string for the host identifier for usage in debug messages.\n\t*/\n\tget hostIdentifier() {\n\t\treturn `${this.host}:${this.port}`;\n\t}\n\t/**\n\t* Connect to host:port using the specified transport\n\t*/\n\tconnect() {\n\t\tif (this.webSocket) throw /* @__PURE__ */ new Error(\"Cannot initiate a new socket connection when an existing connection exists\");\n\t\tthis.disconnectTimer = setTimeout(() => this.disconnectOnTimeout(), this.timeout);\n\t\tthis.once(\"connected\", this.clearDisconnectTimerOnTimeout);\n\t\tconst connectionType = this.encrypted ? \"an encrypted WebSocket\" : \"a WebSocket\";\n\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_2__[\"default\"].network(`Initiating ${connectionType} connection to '${this.host}:${this.port}'.`);\n\t\tif (this.encrypted) this.webSocket = new _monsterbitar_isomorphic_ws__WEBPACK_IMPORTED_MODULE_0__.WebSocket(`wss://${this.host}:${this.port}`);\n\t\telse this.webSocket = new _monsterbitar_isomorphic_ws__WEBPACK_IMPORTED_MODULE_0__.WebSocket(`ws://${this.host}:${this.port}`);\n\t\tthis.webSocket.addEventListener(\"open\", this.onConnect.bind(this));\n\t\tthis.webSocket.addEventListener(\"error\", this.eventForwarders.wsError);\n\t}\n\t/**\n\t* Enables handler for browser consistent behavior with regards to connectivity and visibility events.\n\t*\n\t* Note that some browser disconnect sockets when a tab or window loses focus in order to save battery.\n\t* Note that some browser disconnect sockets when the browser loses connectivity.\n\t*\n\t* This feature allows for consistent behavior across browsers by default, but can be disabled if needed.\n\t*/\n\tconfigureBehaviorConsistency() {\n\t\tconst { disableBrowserVisibilityHandling, disableBrowserConnectivityHandling } = this.reconnectionOptions;\n\t\tif (!disableBrowserVisibilityHandling) this.enforceConsistentVisibilityBehavior();\n\t\tif (!disableBrowserConnectivityHandling) this.enforceConsistentConnectivityBehavior();\n\t}\n\t/**\n\t* Disables all automation regarding browser connectivity and visibility states.\n\t*/\n\tdisableBehaviorConsistency() {\n\t\tthis.disableConsistentVisibilityBehavior();\n\t\tthis.disableConsistentConnectivityBehavior();\n\t}\n\t/**\n\t* Adds event handlers for automatic connection and disconnect on browser visibility changes.\n\t*/\n\tenforceConsistentVisibilityBehavior() {\n\t\tif (typeof document !== \"undefined\") {\n\t\t\tdocument.removeEventListener(\"visibilitychange\", this.boundHandleVisibilityChange);\n\t\t\tdocument.addEventListener(\"visibilitychange\", this.boundHandleVisibilityChange);\n\t\t}\n\t}\n\t/**\n\t* Removes event handlers for browser visibility events.\n\t*/\n\tdisableConsistentVisibilityBehavior() {\n\t\tif (typeof document !== \"undefined\") document.removeEventListener(\"visibilitychange\", this.boundHandleVisibilityChange);\n\t}\n\t/**\n\t* Adds event handlers for automatic connection and disconnect on browser connectivity changes.\n\t*/\n\tenforceConsistentConnectivityBehavior() {\n\t\tif (typeof window !== \"undefined\") {\n\t\t\twindow.removeEventListener(\"online\", this.boundHandleConnectivityChange);\n\t\t\twindow.removeEventListener(\"offline\", this.boundHandleConnectivityChange);\n\t\t\twindow.addEventListener(\"online\", this.boundHandleConnectivityChange);\n\t\t\twindow.addEventListener(\"offline\", this.boundHandleConnectivityChange);\n\t\t}\n\t}\n\t/**\n\t* Removes event handlers for browser connectivity events.\n\t*/\n\tdisableConsistentConnectivityBehavior() {\n\t\tif (typeof window !== \"undefined\") {\n\t\t\twindow.removeEventListener(\"online\", this.boundHandleConnectivityChange);\n\t\t\twindow.removeEventListener(\"offline\", this.boundHandleConnectivityChange);\n\t\t}\n\t}\n\t/**\n\t* Sets up forwarding of events related to the connection.\n\t*/\n\tonConnect() {\n\t\tif (this.onConnectHasRun) return;\n\t\tconst connectionType = this.encrypted ? \"an encrypted WebSocket\" : \"a WebSocket\";\n\t\t_electrum_cash_debug_logs__WEBPACK_IMPORTED_MODULE_2__[\"default\"].network(`Established ${connectionType} connection with '${this.host}:${this.port}'.`);\n\t\tthis.webSocket.addEventListener(\"close\", this.eventForwarders.disconnect);\n\t\tthis.webSocket.addEventListener(\"message\", this.eventForwarders.wsData);\n\t\tthis.configureBehaviorConsistency();\n\t\tthis.onConnectHasRun = true;\n\t\tthis.emit(\"connected\");\n\t}\n\t/**\n\t* Clears the disconnect timer if it is still active.\n\t*/\n\tclearDisconnectTimerOnTimeout() {\n\t\tif (this.disconnectTimer) clearTimeout(this.disconnectTimer);\n\t}\n\t/**\n\t* Forcibly terminate the connection.\n\t*\n\t* @throws {Error} if no connection was found\n\t*/\n\tdisconnect() {\n\t\tthis.disableBehaviorConsistency();\n\t\tthis.closeAndRemoveSocket();\n\t}\n\tcloseAndRemoveSocket() {\n\t\tthis.clearDisconnectTimerOnTimeout();\n\t\ttry {\n\t\t\tthis.webSocket.removeEventListener(\"close\", this.eventForwarders.disconnect);\n\t\t\tthis.webSocket.removeEventListener(\"message\", this.eventForwarders.wsData);\n\t\t\tthis.webSocket.removeEventListener(\"error\", this.eventForwarders.wsError);\n\t\t\tthis.webSocket.addEventListener(\"error\", (_ignored) => {}, { once: true });\n\t\t\tthis.webSocket.close();\n\t\t} catch (_ignored) {} finally {\n\t\t\tthis.webSocket = void 0;\n\t\t}\n\t\tthis.onConnectHasRun = false;\n\t\tthis.emit(\"disconnected\");\n\t}\n\t/**\n\t* Write data to the socket\n\t*\n\t* @param data Data to be written to the socket\n\t* @param callback Callback function to be called when the write has completed\n\t*\n\t* @throws {Error} if no connection was found\n\t* @returns true if the message was fully flushed to the socket, false if part of the message\n\t* is queued in the user memory\n\t*/\n\twrite(data, callback) {\n\t\tif (!this.webSocket) throw /* @__PURE__ */ new Error(\"Cannot write to socket when there is no active connection\");\n\t\tthis.webSocket.send(data, callback);\n\t\treturn true;\n\t}\n\t/**\n\t* Force a disconnection if no connection is established after `timeout` milliseconds.\n\t*/\n\tdisconnectOnTimeout() {\n\t\tthis.removeListener(\"connected\", this.clearDisconnectTimerOnTimeout);\n\t\tthis.emit(\"error\", /* @__PURE__ */ new Error(`Connection to '${this.host}:${this.port}' timed out after ${this.timeout} milliseconds`));\n\t\tthis.closeAndRemoveSocket();\n\t}\n\t/**\n\t* Handles visibility changes when run in a browser environment.\n\t*/\n\thandleVisibilityChange() {\n\t\tif (document?.visibilityState === \"hidden\") {\n\t\t\tthis.closeAndRemoveSocket();\n\t\t\treturn;\n\t\t}\n\t\tif (this.webSocket) return;\n\t\treturn this.connect();\n\t}\n\t/**\n\t* Handles connectivity changes when run in a browser environment.\n\t*/\n\thandleConnectivityChange() {\n\t\tif (window.navigator.onLine === false) {\n\t\t\tthis.closeAndRemoveSocket();\n\t\t\treturn;\n\t\t}\n\t\tif (this.webSocket) return;\n\t\treturn this.connect();\n\t}\n\tconnected;\n\tdisconnected;\n\tdata;\n\terror;\n};\n\n//#endregion\n\n//# sourceMappingURL=index.mjs.map\n\n//# sourceURL=webpack://mainnet-js/../../node_modules/@electrum-cash/web-socket/dist/index.mjs?");
1778
1778
 
1779
1779
  /***/ }),
1780
1780