mainnet-js 3.1.5 → 3.1.6
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.
- package/dist/index.html +1 -1
- package/dist/{mainnet-3.1.5.js → mainnet-3.1.6.js} +2 -2
- package/dist/module/wallet/Base.d.ts +9 -0
- package/dist/module/wallet/Base.d.ts.map +1 -1
- package/dist/module/wallet/Base.js +5 -0
- package/dist/module/wallet/Base.js.map +1 -1
- package/dist/module/wallet/HDWallet.d.ts +10 -0
- package/dist/module/wallet/HDWallet.d.ts.map +1 -1
- package/dist/module/wallet/HDWallet.js +53 -0
- package/dist/module/wallet/HDWallet.js.map +1 -1
- package/dist/module/wallet/Wif.d.ts.map +1 -1
- package/dist/module/wallet/Wif.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/wallet/Base.ts +12 -0
- package/src/wallet/HDWallet.test.ts +49 -44
- package/src/wallet/HDWallet.ts +67 -0
- package/src/wallet/Wif.test.ts +0 -2
- package/src/wallet/Wif.ts +4 -1
package/dist/index.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<title>The Empty Mainnet App</title>
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1"><script defer src="mainnet-3.1.
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"><script defer src="mainnet-3.1.6.js"></script></head>
|
|
7
7
|
<body><script>document.addEventListener("DOMContentLoaded", async (event) => Object.assign(globalThis, await __mainnetPromise))</script>
|
|
8
8
|
</body>
|
|
9
9
|
</html>
|
|
@@ -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
|
|
|
@@ -177,6 +177,15 @@ export declare class BaseWallet implements WalletI {
|
|
|
177
177
|
* @returns Cancel function to stop watching
|
|
178
178
|
*/
|
|
179
179
|
watchStatus(callback: (status: string | null, address: string) => void): Promise<CancelFn>;
|
|
180
|
+
/**
|
|
181
|
+
* No-op for single-address wallets. HDWallet overrides this to wait for
|
|
182
|
+
* depositIndex/changeIndex advancement.
|
|
183
|
+
*/
|
|
184
|
+
waitForUpdate(_options?: {
|
|
185
|
+
depositIndex?: number;
|
|
186
|
+
changeIndex?: number;
|
|
187
|
+
timeout?: number;
|
|
188
|
+
}): Promise<void>;
|
|
180
189
|
watchBalance(callback: (balance: bigint) => void): Promise<CancelFn>;
|
|
181
190
|
waitForBalance(value: bigint): Promise<bigint>;
|
|
182
191
|
watchTokenBalance(category: string, callback: (balance: bigint) => void): Promise<CancelFn>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Base.d.ts","sourceRoot":"","sources":["../../../src/wallet/Base.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Base.d.ts","sourceRoot":"","sources":["../../../src/wallet/Base.ts"],"names":[],"mappings":"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"}
|
|
@@ -339,6 +339,11 @@ export class BaseWallet {
|
|
|
339
339
|
const cancelFn = await this.provider.watchAddressStatus(this.getDepositAddress(), (status) => callback(status, this.getDepositAddress()));
|
|
340
340
|
return this.trackCancelFn(cancelFn);
|
|
341
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* No-op for single-address wallets. HDWallet overrides this to wait for
|
|
344
|
+
* depositIndex/changeIndex advancement.
|
|
345
|
+
*/
|
|
346
|
+
async waitForUpdate(_options = {}) { }
|
|
342
347
|
// sets up a callback to be called upon wallet's balance change
|
|
343
348
|
// can be cancelled by calling the function returned from this one
|
|
344
349
|
async watchBalance(callback) {
|