beignet 0.0.1
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/.eslintignore +4 -0
- package/.eslintrc +40 -0
- package/.prettierrc +9 -0
- package/LICENSE +21 -0
- package/README.md +166 -0
- package/dist/electrum/constants.js +31 -0
- package/dist/electrum/constants.js.map +1 -0
- package/dist/electrum/index.js +552 -0
- package/dist/electrum/index.js.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/shapes/electrum.js +14 -0
- package/dist/shapes/electrum.js.map +1 -0
- package/dist/shapes/index.js +19 -0
- package/dist/shapes/index.js.map +1 -0
- package/dist/shapes/wallet.js +115 -0
- package/dist/shapes/wallet.js.map +1 -0
- package/dist/transaction/index.js +692 -0
- package/dist/transaction/index.js.map +1 -0
- package/dist/types/electrum/constants.d.ts +7 -0
- package/dist/types/electrum/index.d.ts +85 -0
- package/dist/types/electrum.js +9 -0
- package/dist/types/electrum.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.js +20 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/shapes/electrum.d.ts +5 -0
- package/dist/types/shapes/index.d.ts +2 -0
- package/dist/types/shapes/wallet.d.ts +10 -0
- package/dist/types/transaction/index.d.ts +92 -0
- package/dist/types/transaction.js +12 -0
- package/dist/types/transaction.js.map +1 -0
- package/dist/types/types/electrum.d.ts +113 -0
- package/dist/types/types/index.d.ts +3 -0
- package/dist/types/types/transaction.d.ts +51 -0
- package/dist/types/types/wallet.d.ts +400 -0
- package/dist/types/utils/conversion.d.ts +10 -0
- package/dist/types/utils/derivation-path.d.ts +19 -0
- package/dist/types/utils/electrum.d.ts +10 -0
- package/dist/types/utils/exchange-rate.d.ts +30 -0
- package/dist/types/utils/helpers.d.ts +23 -0
- package/dist/types/utils/index.d.ts +7 -0
- package/dist/types/utils/result.d.ts +16 -0
- package/dist/types/utils/transaction.d.ts +21 -0
- package/dist/types/utils/wallet.d.ts +47 -0
- package/dist/types/wallet/constants.d.ts +12 -0
- package/dist/types/wallet/index.d.ts +214 -0
- package/dist/types/wallet.js +36 -0
- package/dist/types/wallet.js.map +1 -0
- package/dist/utils/conversion.js +52 -0
- package/dist/utils/conversion.js.map +1 -0
- package/dist/utils/derivation-path.js +104 -0
- package/dist/utils/derivation-path.js.map +1 -0
- package/dist/utils/electrum.js +149 -0
- package/dist/utils/electrum.js.map +1 -0
- package/dist/utils/exchange-rate.js +49 -0
- package/dist/utils/exchange-rate.js.map +1 -0
- package/dist/utils/helpers.js +137 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/index.js +24 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/result.js +36 -0
- package/dist/utils/result.js.map +1 -0
- package/dist/utils/transaction.js +327 -0
- package/dist/utils/transaction.js.map +1 -0
- package/dist/utils/wallet.js +227 -0
- package/dist/utils/wallet.js.map +1 -0
- package/dist/wallet/constants.js +15 -0
- package/dist/wallet/constants.js.map +1 -0
- package/dist/wallet/index.js +2113 -0
- package/dist/wallet/index.js.map +1 -0
- package/docs/html/.nojekyll +1 -0
- package/docs/html/assets/highlight.css +22 -0
- package/docs/html/assets/main.js +58 -0
- package/docs/html/assets/search.js +1 -0
- package/docs/html/assets/style.css +1367 -0
- package/docs/html/classes/Electrum.html +812 -0
- package/docs/html/classes/Transaction.html +687 -0
- package/docs/html/classes/Wallet.html +2030 -0
- package/docs/html/enums/EAddressType.html +227 -0
- package/docs/html/enums/EAvailableNetworks.html +255 -0
- package/docs/html/enums/EBoostType.html +220 -0
- package/docs/html/enums/EFeeId.html +241 -0
- package/docs/html/enums/EPaymentType.html +220 -0
- package/docs/html/enums/EProtocol.html +220 -0
- package/docs/html/enums/EUnit.html +227 -0
- package/docs/html/functions/availableNetworks.html +200 -0
- package/docs/html/functions/constructByteCountParam.html +210 -0
- package/docs/html/functions/decodeOpReturnMessage.html +202 -0
- package/docs/html/functions/decodeRawTransaction.html +210 -0
- package/docs/html/functions/err.html +214 -0
- package/docs/html/functions/formatKeyDerivationPath.html +219 -0
- package/docs/html/functions/formatPeerData.html +207 -0
- package/docs/html/functions/generateMnemonic.html +223 -0
- package/docs/html/functions/generateWalletId.html +202 -0
- package/docs/html/functions/getAddressFromScriptPubKey.html +209 -0
- package/docs/html/functions/getAddressTypeFromPath.html +206 -0
- package/docs/html/functions/getByteCount.html +206 -0
- package/docs/html/functions/getDataFallback.html +207 -0
- package/docs/html/functions/getDefaultPort.html +209 -0
- package/docs/html/functions/getDefaultWalletData.html +200 -0
- package/docs/html/functions/getDefaultWalletDataKeys.html +200 -0
- package/docs/html/functions/getExchangeRates.html +200 -0
- package/docs/html/functions/getHighestUsedIndexFromTxHashes.html +216 -0
- package/docs/html/functions/getKeyDerivationPath.html +211 -0
- package/docs/html/functions/getKeyDerivationPathObject.html +216 -0
- package/docs/html/functions/getKeyDerivationPathString.html +220 -0
- package/docs/html/functions/getKeyValue.html +206 -0
- package/docs/html/functions/getPeers.html +211 -0
- package/docs/html/functions/getProtocolForPort.html +209 -0
- package/docs/html/functions/getScriptHash.html +210 -0
- package/docs/html/functions/getSeed.html +209 -0
- package/docs/html/functions/getSeedHash.html +206 -0
- package/docs/html/functions/getSha256.html +206 -0
- package/docs/html/functions/getStorageKeyValues.html +209 -0
- package/docs/html/functions/getTxFee.html +210 -0
- package/docs/html/functions/getWalletDataStorageKey.html +206 -0
- package/docs/html/functions/isValidBech32mEncodedString.html +211 -0
- package/docs/html/functions/objectKeys-1.html +211 -0
- package/docs/html/functions/objectsMatch.html +210 -0
- package/docs/html/functions/ok.html +214 -0
- package/docs/html/functions/parseOnChainPaymentRequest.html +204 -0
- package/docs/html/functions/reduceValue.html +215 -0
- package/docs/html/functions/removeDustOutputs.html +206 -0
- package/docs/html/functions/setReplaceByFee.html +210 -0
- package/docs/html/functions/shuffleArray.html +211 -0
- package/docs/html/functions/validateAddress.html +216 -0
- package/docs/html/functions/validateMnemonic.html +206 -0
- package/docs/html/functions/validateTransaction.html +206 -0
- package/docs/html/index.html +360 -0
- package/docs/html/interfaces/IAddInput.html +231 -0
- package/docs/html/interfaces/IAddress.html +247 -0
- package/docs/html/interfaces/IAddressData.html +231 -0
- package/docs/html/interfaces/IAddressType.html +199 -0
- package/docs/html/interfaces/IAddressTypeData.html +252 -0
- package/docs/html/interfaces/IAddresses.html +199 -0
- package/docs/html/interfaces/IBoostedTransaction.html +238 -0
- package/docs/html/interfaces/IBoostedTransactions.html +199 -0
- package/docs/html/interfaces/ICreateTransaction.html +224 -0
- package/docs/html/interfaces/ICustomGetAddress.html +231 -0
- package/docs/html/interfaces/ICustomGetScriptHash.html +224 -0
- package/docs/html/interfaces/IElectrumGetAddressBalanceRes.html +235 -0
- package/docs/html/interfaces/IExchangeRates.html +210 -0
- package/docs/html/interfaces/IFormattedPeerData.html +245 -0
- package/docs/html/interfaces/IFormattedTransaction.html +343 -0
- package/docs/html/interfaces/IFormattedTransactions.html +199 -0
- package/docs/html/interfaces/IGenerateAddresses.html +252 -0
- package/docs/html/interfaces/IGenerateAddressesResponse.html +224 -0
- package/docs/html/interfaces/IGetAddress.html +231 -0
- package/docs/html/interfaces/IGetAddressBalanceRes.html +226 -0
- package/docs/html/interfaces/IGetAddressByPath.html +224 -0
- package/docs/html/interfaces/IGetAddressHistoryResponse.html +269 -0
- package/docs/html/interfaces/IGetAddressResponse.html +231 -0
- package/docs/html/interfaces/IGetAddressScriptHashesHistoryResponse.html +245 -0
- package/docs/html/interfaces/IGetDerivationPath.html +259 -0
- package/docs/html/interfaces/IGetFeeEstimatesResponse.html +238 -0
- package/docs/html/interfaces/IGetHeaderResponse.html +245 -0
- package/docs/html/interfaces/IGetNextAvailableAddressResponse.html +238 -0
- package/docs/html/interfaces/IGetTransactions.html +245 -0
- package/docs/html/interfaces/IGetTransactionsFromInputs.html +245 -0
- package/docs/html/interfaces/IGetUtxosResponse.html +224 -0
- package/docs/html/interfaces/IHeader.html +231 -0
- package/docs/html/interfaces/IIndexes.html +238 -0
- package/docs/html/interfaces/IKeyDerivationPath.html +247 -0
- package/docs/html/interfaces/IKeyDerivationPathData.html +224 -0
- package/docs/html/interfaces/INewBlock.html +224 -0
- package/docs/html/interfaces/IOnchainFees.html +245 -0
- package/docs/html/interfaces/IOutput.html +231 -0
- package/docs/html/interfaces/IPeerData.html +231 -0
- package/docs/html/interfaces/IRbfData.html +252 -0
- package/docs/html/interfaces/ISend.html +224 -0
- package/docs/html/interfaces/ISendTransaction.html +322 -0
- package/docs/html/interfaces/ISendTx.html +231 -0
- package/docs/html/interfaces/ISetupTransaction.html +238 -0
- package/docs/html/interfaces/ISubscribeToAddress.html +247 -0
- package/docs/html/interfaces/ISubscribeToHeader.html +245 -0
- package/docs/html/interfaces/ITargets.html +238 -0
- package/docs/html/interfaces/ITransaction.html +281 -0
- package/docs/html/interfaces/ITxHash.html +217 -0
- package/docs/html/interfaces/ITxHashes.html +235 -0
- package/docs/html/interfaces/IUtxo.html +275 -0
- package/docs/html/interfaces/IVin.html +252 -0
- package/docs/html/interfaces/IVout.html +246 -0
- package/docs/html/interfaces/IWallet.html +350 -0
- package/docs/html/interfaces/IWalletData.html +343 -0
- package/docs/html/types/ElectrumConnectionPubSub.html +233 -0
- package/docs/html/types/ElectrumConnectionSubscription.html +204 -0
- package/docs/html/types/InputData.html +203 -0
- package/docs/html/types/ObjectKeys.html +198 -0
- package/docs/html/types/Result.html +201 -0
- package/docs/html/types/TAddressIndexInfo.html +204 -0
- package/docs/html/types/TAddressLabel.html +193 -0
- package/docs/html/types/TAddressType.html +193 -0
- package/docs/html/types/TAddressTypeContent.html +198 -0
- package/docs/html/types/TAddressTypes.html +193 -0
- package/docs/html/types/TAvailableNetworks.html +193 -0
- package/docs/html/types/TConnectToElectrumRes.html +193 -0
- package/docs/html/types/TDecodeRawTx.html +214 -0
- package/docs/html/types/TElectrumNetworks.html +193 -0
- package/docs/html/types/TGetAddressHistory.html +200 -0
- package/docs/html/types/TGetByteCountInput.html +193 -0
- package/docs/html/types/TGetByteCountInputs.html +193 -0
- package/docs/html/types/TGetByteCountOutput.html +193 -0
- package/docs/html/types/TGetByteCountOutputs.html +193 -0
- package/docs/html/types/TGetData.html +211 -0
- package/docs/html/types/TGetTotalFeeObj.html +204 -0
- package/docs/html/types/TKeyDerivationAccount.html +193 -0
- package/docs/html/types/TKeyDerivationChange.html +193 -0
- package/docs/html/types/TKeyDerivationCoinType.html +193 -0
- package/docs/html/types/TKeyDerivationIndex.html +193 -0
- package/docs/html/types/TKeyDerivationPurpose.html +193 -0
- package/docs/html/types/TMessageDataMap.html +210 -0
- package/docs/html/types/TMessageKeys.html +193 -0
- package/docs/html/types/TOnMessage.html +213 -0
- package/docs/html/types/TProcessUnconfirmedTransactions.html +202 -0
- package/docs/html/types/TProtocol.html +193 -0
- package/docs/html/types/TServer.html +204 -0
- package/docs/html/types/TSetData.html +213 -0
- package/docs/html/types/TSetupTransactionResponse.html +193 -0
- package/docs/html/types/TStorage.html +200 -0
- package/docs/html/types/TSubscribedReceive.html +193 -0
- package/docs/html/types/TTransactionMessage.html +198 -0
- package/docs/html/types/TTxResponse.html +206 -0
- package/docs/html/types/TTxResult.html +200 -0
- package/docs/html/types/TUnspentAddressScriptHashData.html +198 -0
- package/docs/html/types/TWalletDataKeys.html +193 -0
- package/docs/html/variables/defaultElectrumPorts.html +193 -0
- package/docs/html/variables/electrumConnection.html +199 -0
- package/docs/html/variables/mostUsedExchangeTickers.html +241 -0
- package/docs/markdown/.nojekyll +1 -0
- package/docs/markdown/README.md +1875 -0
- package/docs/markdown/classes/Electrum.md +718 -0
- package/docs/markdown/classes/Transaction.md +536 -0
- package/docs/markdown/classes/Wallet.md +2189 -0
- package/docs/markdown/enums/EAddressType.md +41 -0
- package/docs/markdown/enums/EAvailableNetworks.md +85 -0
- package/docs/markdown/enums/EBoostType.md +30 -0
- package/docs/markdown/enums/EFeeId.md +63 -0
- package/docs/markdown/enums/EPaymentType.md +30 -0
- package/docs/markdown/enums/EProtocol.md +30 -0
- package/docs/markdown/enums/EUnit.md +41 -0
- package/docs/markdown/interfaces/IAddInput.md +41 -0
- package/docs/markdown/interfaces/IAddress.md +69 -0
- package/docs/markdown/interfaces/IAddressData.md +41 -0
- package/docs/markdown/interfaces/IAddressType.md +7 -0
- package/docs/markdown/interfaces/IAddressTypeData.md +74 -0
- package/docs/markdown/interfaces/IAddresses.md +7 -0
- package/docs/markdown/interfaces/IBoostedTransaction.md +52 -0
- package/docs/markdown/interfaces/IBoostedTransactions.md +7 -0
- package/docs/markdown/interfaces/ICreateTransaction.md +30 -0
- package/docs/markdown/interfaces/ICustomGetAddress.md +41 -0
- package/docs/markdown/interfaces/ICustomGetScriptHash.md +30 -0
- package/docs/markdown/interfaces/IElectrumGetAddressBalanceRes.md +55 -0
- package/docs/markdown/interfaces/IExchangeRates.md +7 -0
- package/docs/markdown/interfaces/IFormattedPeerData.md +63 -0
- package/docs/markdown/interfaces/IFormattedTransaction.md +217 -0
- package/docs/markdown/interfaces/IFormattedTransactions.md +7 -0
- package/docs/markdown/interfaces/IGenerateAddresses.md +74 -0
- package/docs/markdown/interfaces/IGenerateAddressesResponse.md +30 -0
- package/docs/markdown/interfaces/IGetAddress.md +41 -0
- package/docs/markdown/interfaces/IGetAddressBalanceRes.md +36 -0
- package/docs/markdown/interfaces/IGetAddressByPath.md +30 -0
- package/docs/markdown/interfaces/IGetAddressHistoryResponse.md +121 -0
- package/docs/markdown/interfaces/IGetAddressResponse.md +41 -0
- package/docs/markdown/interfaces/IGetAddressScriptHashesHistoryResponse.md +63 -0
- package/docs/markdown/interfaces/IGetDerivationPath.md +100 -0
- package/docs/markdown/interfaces/IGetFeeEstimatesResponse.md +52 -0
- package/docs/markdown/interfaces/IGetHeaderResponse.md +63 -0
- package/docs/markdown/interfaces/IGetNextAvailableAddressResponse.md +52 -0
- package/docs/markdown/interfaces/IGetTransactions.md +63 -0
- package/docs/markdown/interfaces/IGetTransactionsFromInputs.md +63 -0
- package/docs/markdown/interfaces/IGetUtxosResponse.md +30 -0
- package/docs/markdown/interfaces/IHeader.md +41 -0
- package/docs/markdown/interfaces/IIndexes.md +52 -0
- package/docs/markdown/interfaces/IKeyDerivationPath.md +69 -0
- package/docs/markdown/interfaces/IKeyDerivationPathData.md +30 -0
- package/docs/markdown/interfaces/INewBlock.md +30 -0
- package/docs/markdown/interfaces/IOnchainFees.md +63 -0
- package/docs/markdown/interfaces/IOutput.md +41 -0
- package/docs/markdown/interfaces/IPeerData.md +41 -0
- package/docs/markdown/interfaces/IRbfData.md +74 -0
- package/docs/markdown/interfaces/ISend.md +30 -0
- package/docs/markdown/interfaces/ISendTransaction.md +184 -0
- package/docs/markdown/interfaces/ISendTx.md +41 -0
- package/docs/markdown/interfaces/ISetupTransaction.md +52 -0
- package/docs/markdown/interfaces/ISubscribeToAddress.md +60 -0
- package/docs/markdown/interfaces/ISubscribeToHeader.md +59 -0
- package/docs/markdown/interfaces/ITargets.md +52 -0
- package/docs/markdown/interfaces/ITransaction.md +88 -0
- package/docs/markdown/interfaces/ITxHash.md +19 -0
- package/docs/markdown/interfaces/ITxHashes.md +55 -0
- package/docs/markdown/interfaces/IUtxo.md +112 -0
- package/docs/markdown/interfaces/IVin.md +70 -0
- package/docs/markdown/interfaces/IVout.md +52 -0
- package/docs/markdown/interfaces/IWallet.md +209 -0
- package/docs/markdown/interfaces/IWalletData.md +217 -0
- package/example/helpers.ts +76 -0
- package/example/index.ts +77 -0
- package/package.json +69 -0
- package/src/electrum/constants.ts +28 -0
- package/src/electrum/index.ts +838 -0
- package/src/index.ts +6 -0
- package/src/shapes/electrum.ts +13 -0
- package/src/shapes/index.ts +2 -0
- package/src/shapes/wallet.ts +133 -0
- package/src/transaction/index.ts +1078 -0
- package/src/types/electrum.ts +139 -0
- package/src/types/index.ts +3 -0
- package/src/types/transaction.ts +58 -0
- package/src/types/wallet.ts +503 -0
- package/src/utils/conversion.ts +88 -0
- package/src/utils/derivation-path.ts +171 -0
- package/src/utils/electrum.ts +188 -0
- package/src/utils/exchange-rate.ts +70 -0
- package/src/utils/helpers.ts +191 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/result.ts +79 -0
- package/src/utils/transaction.ts +417 -0
- package/src/utils/wallet.ts +351 -0
- package/src/wallet/constants.ts +24 -0
- package/src/wallet/index.ts +3304 -0
- package/tests/constants.ts +9 -0
- package/tests/derivation.test.ts +146 -0
- package/tests/electrum.test.ts +137 -0
- package/tests/storage.test.ts +222 -0
- package/tests/transaction.test.ts +187 -0
- package/tests/wallet.test.ts +307 -0
- package/tsconfig.json +32 -0
- package/typedoc.json +5 -0
|
@@ -0,0 +1,2113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.Wallet = void 0;
|
|
30
|
+
const bitcoin = __importStar(require("bitcoinjs-lib"));
|
|
31
|
+
const bitcoinjs_lib_1 = require("bitcoinjs-lib");
|
|
32
|
+
const bip32_1 = __importDefault(require("bip32"));
|
|
33
|
+
const ecc = __importStar(require("@bitcoinerlab/secp256k1"));
|
|
34
|
+
const types_1 = require("../types");
|
|
35
|
+
const utils_1 = require("../utils");
|
|
36
|
+
const shapes_1 = require("../shapes");
|
|
37
|
+
const electrum_1 = require("../electrum");
|
|
38
|
+
const transaction_1 = require("../transaction");
|
|
39
|
+
const constants_1 = require("./constants");
|
|
40
|
+
const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep"));
|
|
41
|
+
const conversion_1 = require("../utils/conversion");
|
|
42
|
+
const bip39 = __importStar(require("bip39"));
|
|
43
|
+
const bip32 = (0, bip32_1.default)(ecc);
|
|
44
|
+
class Wallet {
|
|
45
|
+
constructor({ mnemonic, passphrase, name, network = types_1.EAvailableNetworks.mainnet, addressType = types_1.EAddressType.p2wpkh, storage, electrumOptions, onMessage = () => null, customGetAddress, customGetScriptHash, rbf = false, selectedFeeId = types_1.EFeeId.normal }) {
|
|
46
|
+
var _a;
|
|
47
|
+
this._pendingRefreshPromises = [];
|
|
48
|
+
this.getReceiveAddress = async ({ addressType = this.data.addressType }) => {
|
|
49
|
+
try {
|
|
50
|
+
const wallet = this.data;
|
|
51
|
+
const addressIndex = wallet.addressIndex;
|
|
52
|
+
const receiveAddress = addressIndex[addressType].address;
|
|
53
|
+
if (receiveAddress) {
|
|
54
|
+
return (0, utils_1.ok)(receiveAddress);
|
|
55
|
+
}
|
|
56
|
+
const addresses = wallet === null || wallet === void 0 ? void 0 : wallet.addresses[addressType];
|
|
57
|
+
if (Object.keys(addresses).length > 0 &&
|
|
58
|
+
addressIndex[addressType].index < 0) {
|
|
59
|
+
const address = Object.values(addresses).find(({ index }) => index === 0);
|
|
60
|
+
if (address) {
|
|
61
|
+
return (0, utils_1.ok)(address.address);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const generatedAddress = await this.generateNewReceiveAddress({
|
|
65
|
+
addressType
|
|
66
|
+
});
|
|
67
|
+
if (generatedAddress.isOk()) {
|
|
68
|
+
return (0, utils_1.ok)(generatedAddress.value.address);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
console.log(generatedAddress.error.message);
|
|
72
|
+
}
|
|
73
|
+
return (0, utils_1.err)('No receive address available.');
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
return (0, utils_1.err)(e);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
this.getBoostedTransactionParents = ({ txid, boostedTransactions }) => {
|
|
80
|
+
var _a;
|
|
81
|
+
if (!boostedTransactions) {
|
|
82
|
+
boostedTransactions = this.getBoostedTransactions();
|
|
83
|
+
}
|
|
84
|
+
const boostObj = Object.values(boostedTransactions).find((boostObject) => {
|
|
85
|
+
return boostObject.childTransaction === txid;
|
|
86
|
+
});
|
|
87
|
+
return (_a = boostObj === null || boostObj === void 0 ? void 0 : boostObj.parentTransactions) !== null && _a !== void 0 ? _a : [];
|
|
88
|
+
};
|
|
89
|
+
this.getBoostedTransactions = () => {
|
|
90
|
+
return this.data.boostedTransactions;
|
|
91
|
+
};
|
|
92
|
+
this.getBip32Interface = async () => {
|
|
93
|
+
const network = bitcoinjs_lib_1.networks[this._network];
|
|
94
|
+
const seed = await bip39.mnemonicToSeed(this._mnemonic, this._passphrase);
|
|
95
|
+
const root = bip32.fromSeed(seed, network);
|
|
96
|
+
return (0, utils_1.ok)(root);
|
|
97
|
+
};
|
|
98
|
+
if (!mnemonic)
|
|
99
|
+
throw new Error('No mnemonic specified.');
|
|
100
|
+
if (!(0, utils_1.validateMnemonic)(mnemonic))
|
|
101
|
+
throw new Error('Invalid mnemonic.');
|
|
102
|
+
if (name && name.includes('-'))
|
|
103
|
+
throw new Error('Wallet name cannot include a hyphen (-).');
|
|
104
|
+
this._network = network;
|
|
105
|
+
this._mnemonic = mnemonic;
|
|
106
|
+
this._passphrase = passphrase !== null && passphrase !== void 0 ? passphrase : '';
|
|
107
|
+
this._seed = (0, utils_1.getSeed)(this._mnemonic, this._passphrase);
|
|
108
|
+
this._root = bip32.fromSeed(this._seed, this.getBitcoinNetwork(this._network));
|
|
109
|
+
this._data = Object.assign(Object.assign({}, (0, utils_1.getDefaultWalletData)()), { addressType });
|
|
110
|
+
this._getData = (_a = storage === null || storage === void 0 ? void 0 : storage.getData) !== null && _a !== void 0 ? _a : utils_1.getDataFallback;
|
|
111
|
+
this._setData = storage === null || storage === void 0 ? void 0 : storage.setData;
|
|
112
|
+
if (customGetAddress)
|
|
113
|
+
this._customGetAddress = customGetAddress;
|
|
114
|
+
if (customGetScriptHash)
|
|
115
|
+
this._customGetScriptHash = customGetScriptHash;
|
|
116
|
+
this.id = (0, utils_1.generateWalletId)(this._seed);
|
|
117
|
+
this.name = name !== null && name !== void 0 ? name : this.id;
|
|
118
|
+
this.exchangeRates = {};
|
|
119
|
+
this.transaction = new transaction_1.Transaction({
|
|
120
|
+
wallet: this
|
|
121
|
+
});
|
|
122
|
+
this.feeEstimates = (0, lodash_clonedeep_1.default)(shapes_1.defaultFeesShape);
|
|
123
|
+
this.onMessage = onMessage;
|
|
124
|
+
this.electrumOptions = electrumOptions;
|
|
125
|
+
this.electrum = new electrum_1.Electrum({
|
|
126
|
+
wallet: this,
|
|
127
|
+
network: this.network,
|
|
128
|
+
servers: electrumOptions === null || electrumOptions === void 0 ? void 0 : electrumOptions.servers,
|
|
129
|
+
tls: electrumOptions === null || electrumOptions === void 0 ? void 0 : electrumOptions.tls,
|
|
130
|
+
net: electrumOptions === null || electrumOptions === void 0 ? void 0 : electrumOptions.net
|
|
131
|
+
});
|
|
132
|
+
this.rbf = rbf;
|
|
133
|
+
this.selectedFeeId = selectedFeeId;
|
|
134
|
+
this.isRefreshing = false;
|
|
135
|
+
this.isSwitchingNetworks = false;
|
|
136
|
+
}
|
|
137
|
+
get data() {
|
|
138
|
+
return this._data;
|
|
139
|
+
}
|
|
140
|
+
get network() {
|
|
141
|
+
return this._network;
|
|
142
|
+
}
|
|
143
|
+
static async create(params) {
|
|
144
|
+
try {
|
|
145
|
+
const wallet = new Wallet(params);
|
|
146
|
+
const res = await wallet.setWalletData();
|
|
147
|
+
if (res.isErr())
|
|
148
|
+
return (0, utils_1.err)(res.error.message);
|
|
149
|
+
wallet.updateExchangeRates();
|
|
150
|
+
wallet.updateFeeEstimates();
|
|
151
|
+
console.log('Syncing Wallet...');
|
|
152
|
+
await wallet.refreshWallet({});
|
|
153
|
+
return (0, utils_1.ok)(wallet);
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
return (0, utils_1.err)(e);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
async switchNetwork(network, servers) {
|
|
160
|
+
var _a, _b;
|
|
161
|
+
this.isSwitchingNetworks = true;
|
|
162
|
+
await this.electrum.disconnect();
|
|
163
|
+
this._network = network;
|
|
164
|
+
this._data = (0, utils_1.getDefaultWalletData)();
|
|
165
|
+
const params = Object.assign(Object.assign({}, this), { mnemonic: this._mnemonic, passphrase: this._passphrase, network, electrumOptions: {
|
|
166
|
+
servers,
|
|
167
|
+
tls: (_a = this.electrumOptions) === null || _a === void 0 ? void 0 : _a.tls,
|
|
168
|
+
net: (_b = this.electrumOptions) === null || _b === void 0 ? void 0 : _b.net
|
|
169
|
+
}, storage: {
|
|
170
|
+
getData: this._getData,
|
|
171
|
+
setData: this._setData
|
|
172
|
+
}, data: (0, utils_1.getDefaultWalletData)() });
|
|
173
|
+
const createRes = await Wallet.create(params);
|
|
174
|
+
if (createRes.isErr())
|
|
175
|
+
return (0, utils_1.err)(createRes.error.message);
|
|
176
|
+
Object.assign(this, createRes.value);
|
|
177
|
+
await this.updateFeeEstimates(true);
|
|
178
|
+
this.isSwitchingNetworks = false;
|
|
179
|
+
return (0, utils_1.ok)(`Successfully switched to ${network}.`);
|
|
180
|
+
}
|
|
181
|
+
async updateAddressType(addressType) {
|
|
182
|
+
this._data.addressType = addressType;
|
|
183
|
+
await this.saveWalletData('addressType', addressType);
|
|
184
|
+
await this.refreshWallet({});
|
|
185
|
+
}
|
|
186
|
+
async refreshWallet({ scanAllAddresses = false, updateAllAddressTypes = true } = {}) {
|
|
187
|
+
if (this.isRefreshing) {
|
|
188
|
+
return new Promise((resolve) => {
|
|
189
|
+
this._pendingRefreshPromises.push(resolve);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
this.isRefreshing = true;
|
|
193
|
+
try {
|
|
194
|
+
await this.setZeroIndexAddresses();
|
|
195
|
+
const addressType = updateAllAddressTypes
|
|
196
|
+
? undefined
|
|
197
|
+
: this.data.addressType;
|
|
198
|
+
const r1 = await this.updateAddressIndexes({ addressType });
|
|
199
|
+
if (r1.isErr()) {
|
|
200
|
+
return this._handleRefreshError(r1.error.message);
|
|
201
|
+
}
|
|
202
|
+
const r2 = await this.getUtxos({ scanAllAddresses });
|
|
203
|
+
if (r2.isErr()) {
|
|
204
|
+
return this._handleRefreshError(r2.error.message);
|
|
205
|
+
}
|
|
206
|
+
const r3 = await this.updateTransactions({ scanAllAddresses });
|
|
207
|
+
if (r3.isErr()) {
|
|
208
|
+
return this._handleRefreshError(r3.error.message);
|
|
209
|
+
}
|
|
210
|
+
await this.electrum.subscribeToAddresses();
|
|
211
|
+
this._resolveAllPendingRefreshPromises((0, utils_1.ok)(this.data));
|
|
212
|
+
return (0, utils_1.ok)(this.data);
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
return this._handleRefreshError(e);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
_resolveAllPendingRefreshPromises(result) {
|
|
219
|
+
this.isRefreshing = false;
|
|
220
|
+
while (this._pendingRefreshPromises.length > 0) {
|
|
221
|
+
const resolve = this._pendingRefreshPromises.shift();
|
|
222
|
+
if (resolve) {
|
|
223
|
+
resolve(result);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
_handleRefreshError(errorMessage) {
|
|
228
|
+
this.isRefreshing = false;
|
|
229
|
+
this._resolveAllPendingRefreshPromises((0, utils_1.err)(errorMessage));
|
|
230
|
+
return (0, utils_1.err)(errorMessage);
|
|
231
|
+
}
|
|
232
|
+
async setWalletData() {
|
|
233
|
+
try {
|
|
234
|
+
const storageIdCheckRes = await this.storageIdCheck(this.id);
|
|
235
|
+
if (storageIdCheckRes.isErr())
|
|
236
|
+
return (0, utils_1.err)(storageIdCheckRes.error.message);
|
|
237
|
+
this._data = (0, utils_1.getDefaultWalletData)();
|
|
238
|
+
const walletDataResponse = await this.getWalletData();
|
|
239
|
+
if (walletDataResponse.isErr())
|
|
240
|
+
return (0, utils_1.err)(walletDataResponse.error.message);
|
|
241
|
+
this._data = walletDataResponse.value;
|
|
242
|
+
return (0, utils_1.ok)(true);
|
|
243
|
+
}
|
|
244
|
+
catch (e) {
|
|
245
|
+
return (0, utils_1.err)(e);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
async storageIdCheck(id) {
|
|
249
|
+
const storageKey = this.getWalletDataKey('id');
|
|
250
|
+
const res = await this._getData(storageKey);
|
|
251
|
+
if (res.isErr() || !res.value) {
|
|
252
|
+
this._data.id = id;
|
|
253
|
+
await this.saveWalletData('id', id);
|
|
254
|
+
return (0, utils_1.ok)('Saved ID to storage.');
|
|
255
|
+
}
|
|
256
|
+
if (res.value !== id) {
|
|
257
|
+
const msg = 'Mismatched id found in storage. Change the wallet name or delete the old wallet from storage and try again.';
|
|
258
|
+
console.log(msg);
|
|
259
|
+
return (0, utils_1.err)(msg);
|
|
260
|
+
}
|
|
261
|
+
return (0, utils_1.ok)("ID's match, it's safe to continue.");
|
|
262
|
+
}
|
|
263
|
+
getWalletDataKey(key) {
|
|
264
|
+
return (0, utils_1.getWalletDataStorageKey)(this.name, this._network, key);
|
|
265
|
+
}
|
|
266
|
+
async getWalletData() {
|
|
267
|
+
try {
|
|
268
|
+
const walletDataKeys = (0, utils_1.getDefaultWalletDataKeys)();
|
|
269
|
+
const walletData = (0, utils_1.getDefaultWalletData)();
|
|
270
|
+
for (const key of walletDataKeys) {
|
|
271
|
+
let dataResult;
|
|
272
|
+
try {
|
|
273
|
+
const walletDataKey = this.getWalletDataKey(key);
|
|
274
|
+
const getDataRes = await this._getData(walletDataKey);
|
|
275
|
+
if (getDataRes.isErr()) {
|
|
276
|
+
return (0, utils_1.err)(dataResult.error.message);
|
|
277
|
+
}
|
|
278
|
+
dataResult = getDataRes === null || getDataRes === void 0 ? void 0 : getDataRes.value;
|
|
279
|
+
}
|
|
280
|
+
catch (e) {
|
|
281
|
+
console.log(e);
|
|
282
|
+
}
|
|
283
|
+
const data = dataResult !== null && dataResult !== void 0 ? dataResult : walletData[key];
|
|
284
|
+
switch (key) {
|
|
285
|
+
case 'id':
|
|
286
|
+
walletData[key] = data;
|
|
287
|
+
break;
|
|
288
|
+
case 'addressType':
|
|
289
|
+
walletData[key] = data;
|
|
290
|
+
break;
|
|
291
|
+
case 'addresses':
|
|
292
|
+
case 'changeAddresses':
|
|
293
|
+
walletData[key] = data;
|
|
294
|
+
break;
|
|
295
|
+
case 'addressIndex':
|
|
296
|
+
case 'changeAddressIndex':
|
|
297
|
+
walletData[key] = data;
|
|
298
|
+
break;
|
|
299
|
+
case 'lastUsedAddressIndex':
|
|
300
|
+
case 'lastUsedChangeAddressIndex':
|
|
301
|
+
walletData[key] = data;
|
|
302
|
+
break;
|
|
303
|
+
case 'utxos':
|
|
304
|
+
walletData[key] = data;
|
|
305
|
+
break;
|
|
306
|
+
case 'blacklistedUtxos':
|
|
307
|
+
walletData[key] = data;
|
|
308
|
+
break;
|
|
309
|
+
case 'unconfirmedTransactions':
|
|
310
|
+
case 'transactions':
|
|
311
|
+
walletData[key] = data;
|
|
312
|
+
break;
|
|
313
|
+
case 'transaction':
|
|
314
|
+
walletData[key] = data;
|
|
315
|
+
break;
|
|
316
|
+
case 'balance':
|
|
317
|
+
walletData[key] = data;
|
|
318
|
+
break;
|
|
319
|
+
case 'header':
|
|
320
|
+
walletData[key] = data;
|
|
321
|
+
break;
|
|
322
|
+
case 'boostedTransactions':
|
|
323
|
+
walletData[key] = data;
|
|
324
|
+
break;
|
|
325
|
+
case 'selectedFeeId':
|
|
326
|
+
walletData[key] = data;
|
|
327
|
+
break;
|
|
328
|
+
case 'exchangeRates':
|
|
329
|
+
walletData[key] = data;
|
|
330
|
+
break;
|
|
331
|
+
case 'feeEstimates':
|
|
332
|
+
walletData[key] = data;
|
|
333
|
+
break;
|
|
334
|
+
default:
|
|
335
|
+
return (0, utils_1.err)(`Unhandled key in getWalletData: ${key}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return (0, utils_1.ok)(walletData);
|
|
339
|
+
}
|
|
340
|
+
catch (e) {
|
|
341
|
+
console.log(e);
|
|
342
|
+
return (0, utils_1.err)(e);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
getBitcoinNetwork(network) {
|
|
346
|
+
if (!network)
|
|
347
|
+
network = this._network;
|
|
348
|
+
return bitcoin.networks[network];
|
|
349
|
+
}
|
|
350
|
+
isValid(mnemonic) {
|
|
351
|
+
return mnemonic === this._mnemonic && (0, utils_1.validateMnemonic)(mnemonic);
|
|
352
|
+
}
|
|
353
|
+
async _getAddress(path, addressType) {
|
|
354
|
+
var _a, _b, _c;
|
|
355
|
+
if (this._customGetAddress) {
|
|
356
|
+
const data = {
|
|
357
|
+
path,
|
|
358
|
+
type: addressType,
|
|
359
|
+
selectedNetwork: this.electrum.getElectrumNetwork(this._network)
|
|
360
|
+
};
|
|
361
|
+
const res = await this._customGetAddress(data);
|
|
362
|
+
if (res.isErr()) {
|
|
363
|
+
return {
|
|
364
|
+
address: '',
|
|
365
|
+
path,
|
|
366
|
+
publicKey: ''
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
return res.value;
|
|
370
|
+
}
|
|
371
|
+
const keyPair = this._root.derivePath(path);
|
|
372
|
+
let address;
|
|
373
|
+
switch (addressType) {
|
|
374
|
+
case types_1.EAddressType.p2wpkh:
|
|
375
|
+
address =
|
|
376
|
+
(_a = bitcoin.payments.p2wpkh({
|
|
377
|
+
pubkey: keyPair.publicKey,
|
|
378
|
+
network: this.getBitcoinNetwork()
|
|
379
|
+
}).address) !== null && _a !== void 0 ? _a : '';
|
|
380
|
+
break;
|
|
381
|
+
case types_1.EAddressType.p2sh:
|
|
382
|
+
address =
|
|
383
|
+
(_b = bitcoin.payments.p2sh({
|
|
384
|
+
redeem: bitcoin.payments.p2wpkh({
|
|
385
|
+
pubkey: keyPair.publicKey,
|
|
386
|
+
network: this.getBitcoinNetwork()
|
|
387
|
+
}),
|
|
388
|
+
network: this.getBitcoinNetwork()
|
|
389
|
+
}).address) !== null && _b !== void 0 ? _b : '';
|
|
390
|
+
break;
|
|
391
|
+
case types_1.EAddressType.p2pkh:
|
|
392
|
+
address =
|
|
393
|
+
(_c = bitcoin.payments.p2pkh({
|
|
394
|
+
pubkey: keyPair.publicKey,
|
|
395
|
+
network: this.getBitcoinNetwork()
|
|
396
|
+
}).address) !== null && _c !== void 0 ? _c : '';
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
return {
|
|
400
|
+
address,
|
|
401
|
+
path,
|
|
402
|
+
publicKey: keyPair.publicKey.toString('hex')
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
async getAddress({ index, changeAddress = false, addressType = this.data.addressType } = {}) {
|
|
406
|
+
try {
|
|
407
|
+
if (index === undefined) {
|
|
408
|
+
const addressIndex = this.data.addressIndex[addressType];
|
|
409
|
+
index = addressIndex.index >= 0 ? String(addressIndex.index) : '0';
|
|
410
|
+
}
|
|
411
|
+
const pathRes = (0, utils_1.getKeyDerivationPathString)({
|
|
412
|
+
addressType,
|
|
413
|
+
changeAddress,
|
|
414
|
+
index,
|
|
415
|
+
network: this._network
|
|
416
|
+
});
|
|
417
|
+
if (pathRes.isErr()) {
|
|
418
|
+
return '';
|
|
419
|
+
}
|
|
420
|
+
const path = pathRes.value;
|
|
421
|
+
const res = await this._getAddress(path, addressType);
|
|
422
|
+
if (!(res === null || res === void 0 ? void 0 : res.address))
|
|
423
|
+
return '';
|
|
424
|
+
return res.address;
|
|
425
|
+
}
|
|
426
|
+
catch (_a) {
|
|
427
|
+
return '';
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
async getAddressByPath({ path, addressType }) {
|
|
431
|
+
if (!path) {
|
|
432
|
+
return (0, utils_1.err)('No path specified');
|
|
433
|
+
}
|
|
434
|
+
if (!addressType) {
|
|
435
|
+
const res = (0, utils_1.getAddressTypeFromPath)(path);
|
|
436
|
+
if (res.isErr())
|
|
437
|
+
return (0, utils_1.err)(res.error.message);
|
|
438
|
+
addressType = res.value;
|
|
439
|
+
}
|
|
440
|
+
try {
|
|
441
|
+
const getAddressRes = await this._getAddress(path, addressType);
|
|
442
|
+
if (!(getAddressRes === null || getAddressRes === void 0 ? void 0 : getAddressRes.address))
|
|
443
|
+
return (0, utils_1.err)('Unable to get address.');
|
|
444
|
+
return (0, utils_1.ok)(getAddressRes);
|
|
445
|
+
}
|
|
446
|
+
catch (e) {
|
|
447
|
+
return (0, utils_1.err)(e);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
async connectToElectrum(servers) {
|
|
451
|
+
var _a;
|
|
452
|
+
const res = await this.electrum.connectToElectrum({
|
|
453
|
+
network: this._network,
|
|
454
|
+
servers: servers !== null && servers !== void 0 ? servers : (_a = this.electrumOptions) === null || _a === void 0 ? void 0 : _a.servers
|
|
455
|
+
});
|
|
456
|
+
let msg = 'Unable to connect to Electrum server.';
|
|
457
|
+
if (res.isErr()) {
|
|
458
|
+
console.log(msg);
|
|
459
|
+
return (0, utils_1.err)(msg);
|
|
460
|
+
}
|
|
461
|
+
msg = 'Connected to Electrum server.';
|
|
462
|
+
return (0, utils_1.ok)(msg);
|
|
463
|
+
}
|
|
464
|
+
async getAddressBalance(address) {
|
|
465
|
+
const scriptHash = await this.getScriptHash({
|
|
466
|
+
address,
|
|
467
|
+
network: this._network
|
|
468
|
+
});
|
|
469
|
+
const res = await this.electrum.getAddressBalance(scriptHash);
|
|
470
|
+
if (res.error)
|
|
471
|
+
return (0, utils_1.err)('Unable to get address balance at this time.');
|
|
472
|
+
return (0, utils_1.ok)({ unconfirmed: res.unconfirmed, confirmed: res.confirmed });
|
|
473
|
+
}
|
|
474
|
+
async getAddressesBalance(addresses = []) {
|
|
475
|
+
try {
|
|
476
|
+
const network = this._network;
|
|
477
|
+
const scriptHashes = await Promise.all(addresses.map(async (address) => {
|
|
478
|
+
return await this.getScriptHash({ address, network });
|
|
479
|
+
}));
|
|
480
|
+
const res = await this.electrum.getAddressScriptHashBalances(scriptHashes);
|
|
481
|
+
if (res.error) {
|
|
482
|
+
return (0, utils_1.err)(res.data);
|
|
483
|
+
}
|
|
484
|
+
return (0, utils_1.ok)(res.data.reduce((acc, cur) => {
|
|
485
|
+
var _a, _b, _c, _d;
|
|
486
|
+
return (acc +
|
|
487
|
+
Number((_b = (_a = cur.result) === null || _a === void 0 ? void 0 : _a.confirmed) !== null && _b !== void 0 ? _b : 0) +
|
|
488
|
+
Number((_d = (_c = cur.result) === null || _c === void 0 ? void 0 : _c.unconfirmed) !== null && _d !== void 0 ? _d : 0));
|
|
489
|
+
}, 0) || 0);
|
|
490
|
+
}
|
|
491
|
+
catch (e) {
|
|
492
|
+
return (0, utils_1.err)(e);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
async getScriptHash({ address, network }) {
|
|
496
|
+
if (this._customGetScriptHash) {
|
|
497
|
+
const selectedNetwork = this.electrum.getElectrumNetwork(network);
|
|
498
|
+
return await this._customGetScriptHash({ address, selectedNetwork });
|
|
499
|
+
}
|
|
500
|
+
return (0, utils_1.getScriptHash)({ address, network });
|
|
501
|
+
}
|
|
502
|
+
getPrivateKey(path) {
|
|
503
|
+
const keyPair = this._root.derivePath(path);
|
|
504
|
+
return keyPair.toWIF();
|
|
505
|
+
}
|
|
506
|
+
async getScriptHashBalance(scriptHash) {
|
|
507
|
+
const res = await this.electrum.getAddressBalance(scriptHash);
|
|
508
|
+
if (res.error)
|
|
509
|
+
return (0, utils_1.err)('Unable to get address balance at this time.');
|
|
510
|
+
return (0, utils_1.ok)({ unconfirmed: res.unconfirmed, confirmed: res.confirmed });
|
|
511
|
+
}
|
|
512
|
+
getBalance() {
|
|
513
|
+
var _a, _b;
|
|
514
|
+
return (_b = (_a = this === null || this === void 0 ? void 0 : this.data) === null || _a === void 0 ? void 0 : _a.balance) !== null && _b !== void 0 ? _b : 0;
|
|
515
|
+
}
|
|
516
|
+
async generateAddresses({ addressAmount = 10, changeAddressAmount = 10, addressIndex = 0, changeAddressIndex = 0, keyDerivationPath, addressType = this.data.addressType }) {
|
|
517
|
+
const network = this._network;
|
|
518
|
+
try {
|
|
519
|
+
if (!keyDerivationPath) {
|
|
520
|
+
const keyDerivationPathResponse = (0, utils_1.getKeyDerivationPath)({
|
|
521
|
+
network,
|
|
522
|
+
addressType
|
|
523
|
+
});
|
|
524
|
+
if (keyDerivationPathResponse.isErr())
|
|
525
|
+
return (0, utils_1.err)(keyDerivationPathResponse.error.message);
|
|
526
|
+
keyDerivationPath = keyDerivationPathResponse.value;
|
|
527
|
+
}
|
|
528
|
+
const addresses = {};
|
|
529
|
+
const changeAddresses = {};
|
|
530
|
+
const addressArray = new Array(addressAmount).fill(null);
|
|
531
|
+
const changeAddressArray = new Array(changeAddressAmount).fill(null);
|
|
532
|
+
await Promise.all(addressArray.map(async (_item, i) => {
|
|
533
|
+
const index = i + addressIndex;
|
|
534
|
+
const path = Object.assign({}, keyDerivationPath);
|
|
535
|
+
path.index = `${index}`;
|
|
536
|
+
const addressPath = (0, utils_1.formatKeyDerivationPath)({
|
|
537
|
+
path,
|
|
538
|
+
network,
|
|
539
|
+
changeAddress: false,
|
|
540
|
+
index: `${index}`
|
|
541
|
+
});
|
|
542
|
+
if (addressPath.isErr()) {
|
|
543
|
+
throw addressPath.error;
|
|
544
|
+
}
|
|
545
|
+
const address = await this.getAddressByPath({
|
|
546
|
+
path: addressPath.value.pathString
|
|
547
|
+
});
|
|
548
|
+
if (address.isErr()) {
|
|
549
|
+
throw address.error;
|
|
550
|
+
}
|
|
551
|
+
const scriptHash = await this.getScriptHash({
|
|
552
|
+
address: address.value.address,
|
|
553
|
+
network
|
|
554
|
+
});
|
|
555
|
+
if (!scriptHash) {
|
|
556
|
+
throw new Error('Unable to get script hash.');
|
|
557
|
+
}
|
|
558
|
+
addresses[scriptHash] = Object.assign(Object.assign({}, address.value), { index,
|
|
559
|
+
scriptHash });
|
|
560
|
+
}));
|
|
561
|
+
await Promise.all(changeAddressArray.map(async (_item, i) => {
|
|
562
|
+
const index = i + changeAddressIndex;
|
|
563
|
+
const path = Object.assign({}, keyDerivationPath);
|
|
564
|
+
path.index = `${index}`;
|
|
565
|
+
const changeAddressPath = (0, utils_1.formatKeyDerivationPath)({
|
|
566
|
+
path,
|
|
567
|
+
network,
|
|
568
|
+
changeAddress: true,
|
|
569
|
+
index: `${index}`
|
|
570
|
+
});
|
|
571
|
+
if (changeAddressPath.isErr()) {
|
|
572
|
+
throw changeAddressPath.error;
|
|
573
|
+
}
|
|
574
|
+
const address = await this.getAddressByPath({
|
|
575
|
+
path: changeAddressPath.value.pathString
|
|
576
|
+
});
|
|
577
|
+
if (address.isErr()) {
|
|
578
|
+
throw address.error;
|
|
579
|
+
}
|
|
580
|
+
const scriptHash = await this.getScriptHash({
|
|
581
|
+
address: address.value.address,
|
|
582
|
+
network
|
|
583
|
+
});
|
|
584
|
+
if (!scriptHash) {
|
|
585
|
+
throw new Error('Unable to get script hash.');
|
|
586
|
+
}
|
|
587
|
+
changeAddresses[scriptHash] = Object.assign(Object.assign({}, address.value), { index,
|
|
588
|
+
scriptHash });
|
|
589
|
+
}));
|
|
590
|
+
return (0, utils_1.ok)({ addresses, changeAddresses });
|
|
591
|
+
}
|
|
592
|
+
catch (e) {
|
|
593
|
+
return (0, utils_1.err)(e);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
async checkElectrumConnection() {
|
|
597
|
+
const isConnected = this.electrum.connectedToElectrum;
|
|
598
|
+
if (!isConnected) {
|
|
599
|
+
return await this.connectToElectrum();
|
|
600
|
+
}
|
|
601
|
+
const pingRes = await this.electrum.isConnected();
|
|
602
|
+
if (pingRes)
|
|
603
|
+
return (0, utils_1.ok)('Is connected to Electrum.Z');
|
|
604
|
+
return (0, utils_1.err)('Failed Electrum connection check.');
|
|
605
|
+
}
|
|
606
|
+
async getNextAvailableAddress(addressType) {
|
|
607
|
+
const checkRes = await this.checkElectrumConnection();
|
|
608
|
+
if (checkRes.isErr())
|
|
609
|
+
return (0, utils_1.err)(checkRes.error.message);
|
|
610
|
+
try {
|
|
611
|
+
const network = this._network;
|
|
612
|
+
addressType = addressType !== null && addressType !== void 0 ? addressType : this.data.addressType;
|
|
613
|
+
const currentWallet = this.data;
|
|
614
|
+
const { path } = shapes_1.addressTypes[addressType];
|
|
615
|
+
const result = (0, utils_1.formatKeyDerivationPath)({ path, network });
|
|
616
|
+
if (result.isErr()) {
|
|
617
|
+
return (0, utils_1.err)(result.error.message);
|
|
618
|
+
}
|
|
619
|
+
const { pathObject: keyDerivationPath } = result.value;
|
|
620
|
+
let addressIndex = currentWallet.addressIndex[addressType];
|
|
621
|
+
let lastUsedAddressIndex = currentWallet.lastUsedAddressIndex[addressType];
|
|
622
|
+
let changeAddressIndex = currentWallet.changeAddressIndex[addressType];
|
|
623
|
+
let lastUsedChangeAddressIndex = currentWallet.lastUsedChangeAddressIndex[addressType];
|
|
624
|
+
if ((addressIndex === null || addressIndex === void 0 ? void 0 : addressIndex.index) < 0 || !(addressIndex === null || addressIndex === void 0 ? void 0 : addressIndex.address)) {
|
|
625
|
+
const generatedAddresses = await this.generateAddresses({
|
|
626
|
+
addressAmount: constants_1.GENERATE_ADDRESS_AMOUNT,
|
|
627
|
+
addressIndex: 0,
|
|
628
|
+
changeAddressAmount: 0,
|
|
629
|
+
keyDerivationPath,
|
|
630
|
+
addressType
|
|
631
|
+
});
|
|
632
|
+
if (generatedAddresses.isErr()) {
|
|
633
|
+
return (0, utils_1.err)(generatedAddresses.error);
|
|
634
|
+
}
|
|
635
|
+
const addresses = generatedAddresses.value.addresses;
|
|
636
|
+
const sorted = Object.values(addresses).sort((a, b) => a.index - b.index);
|
|
637
|
+
addressIndex = sorted[0];
|
|
638
|
+
}
|
|
639
|
+
if ((changeAddressIndex === null || changeAddressIndex === void 0 ? void 0 : changeAddressIndex.index) < 0 || !(changeAddressIndex === null || changeAddressIndex === void 0 ? void 0 : changeAddressIndex.address)) {
|
|
640
|
+
const generatedAddresses = await this.generateAddresses({
|
|
641
|
+
addressAmount: 0,
|
|
642
|
+
changeAddressAmount: constants_1.GENERATE_ADDRESS_AMOUNT,
|
|
643
|
+
changeAddressIndex: 0,
|
|
644
|
+
keyDerivationPath,
|
|
645
|
+
addressType
|
|
646
|
+
});
|
|
647
|
+
if (generatedAddresses.isErr()) {
|
|
648
|
+
return (0, utils_1.err)(generatedAddresses.error);
|
|
649
|
+
}
|
|
650
|
+
const addresses = generatedAddresses.value.changeAddresses;
|
|
651
|
+
const sorted = Object.values(addresses).sort((a, b) => a.index - b.index);
|
|
652
|
+
changeAddressIndex = sorted[0];
|
|
653
|
+
}
|
|
654
|
+
let addresses = currentWallet.addresses[addressType];
|
|
655
|
+
let changeAddresses = currentWallet.changeAddresses[addressType];
|
|
656
|
+
const addressCount = Object.values(addresses).length;
|
|
657
|
+
const changeAddressCount = Object.values(changeAddresses).length;
|
|
658
|
+
if (addressCount < constants_1.GENERATE_ADDRESS_AMOUNT ||
|
|
659
|
+
addressIndex.index === addressCount) {
|
|
660
|
+
const newAddresses = await this.addAddresses({
|
|
661
|
+
addressAmount: constants_1.GENERATE_ADDRESS_AMOUNT,
|
|
662
|
+
changeAddressAmount: 0,
|
|
663
|
+
addressIndex: addressIndex.index,
|
|
664
|
+
changeAddressIndex: 0,
|
|
665
|
+
keyDerivationPath,
|
|
666
|
+
addressType
|
|
667
|
+
});
|
|
668
|
+
if (newAddresses.isOk()) {
|
|
669
|
+
addresses = newAddresses.value.addresses;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
if (changeAddressCount < constants_1.GENERATE_ADDRESS_AMOUNT ||
|
|
673
|
+
changeAddressIndex.index === changeAddressCount) {
|
|
674
|
+
const newChangeAddresses = await this.addAddresses({
|
|
675
|
+
addressAmount: 0,
|
|
676
|
+
changeAddressAmount: constants_1.GENERATE_ADDRESS_AMOUNT,
|
|
677
|
+
addressIndex: 0,
|
|
678
|
+
changeAddressIndex: changeAddressIndex.index,
|
|
679
|
+
keyDerivationPath,
|
|
680
|
+
addressType
|
|
681
|
+
});
|
|
682
|
+
if (newChangeAddresses.isOk()) {
|
|
683
|
+
changeAddresses = newChangeAddresses.value.changeAddresses;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
let allAddresses = Object.values(addresses).filter(({ index }) => index >= addressIndex.index);
|
|
687
|
+
let addressesToScan = allAddresses;
|
|
688
|
+
let allChangeAddresses = Object.values(changeAddresses).filter(({ index }) => index >= changeAddressIndex.index);
|
|
689
|
+
let changeAddressesToScan = allChangeAddresses;
|
|
690
|
+
let combinedAddressesToScan = [
|
|
691
|
+
...addressesToScan,
|
|
692
|
+
...changeAddressesToScan
|
|
693
|
+
];
|
|
694
|
+
let foundLastUsedAddress = false;
|
|
695
|
+
let foundLastUsedChangeAddress = false;
|
|
696
|
+
let addressHasBeenUsed = false;
|
|
697
|
+
let changeAddressHasBeenUsed = false;
|
|
698
|
+
const lastKnownIndexes = (0, utils_1.ok)({
|
|
699
|
+
addressIndex,
|
|
700
|
+
lastUsedAddressIndex,
|
|
701
|
+
changeAddressIndex,
|
|
702
|
+
lastUsedChangeAddressIndex
|
|
703
|
+
});
|
|
704
|
+
while (!foundLastUsedAddress || !foundLastUsedChangeAddress) {
|
|
705
|
+
const addressHistory = await this.electrum.getAddressHistory({
|
|
706
|
+
scriptHashes: combinedAddressesToScan
|
|
707
|
+
});
|
|
708
|
+
if (addressHistory.isErr()) {
|
|
709
|
+
console.log(addressHistory.error.message);
|
|
710
|
+
return lastKnownIndexes;
|
|
711
|
+
}
|
|
712
|
+
const txHashes = addressHistory.value;
|
|
713
|
+
const highestUsedIndex = (0, utils_1.getHighestUsedIndexFromTxHashes)({
|
|
714
|
+
txHashes,
|
|
715
|
+
addresses,
|
|
716
|
+
changeAddresses,
|
|
717
|
+
addressIndex,
|
|
718
|
+
changeAddressIndex
|
|
719
|
+
});
|
|
720
|
+
if (highestUsedIndex.isErr()) {
|
|
721
|
+
console.log(highestUsedIndex.error.message);
|
|
722
|
+
return lastKnownIndexes;
|
|
723
|
+
}
|
|
724
|
+
addressIndex = highestUsedIndex.value.addressIndex;
|
|
725
|
+
changeAddressIndex = highestUsedIndex.value.changeAddressIndex;
|
|
726
|
+
if (highestUsedIndex.value.foundAddressIndex) {
|
|
727
|
+
addressHasBeenUsed = true;
|
|
728
|
+
}
|
|
729
|
+
if (highestUsedIndex.value.foundChangeAddressIndex) {
|
|
730
|
+
changeAddressHasBeenUsed = true;
|
|
731
|
+
}
|
|
732
|
+
const highestStoredIndex = this.getHighestStoredAddressIndex({
|
|
733
|
+
addressType
|
|
734
|
+
});
|
|
735
|
+
if (highestStoredIndex.isErr()) {
|
|
736
|
+
console.log(highestStoredIndex.error.message);
|
|
737
|
+
return lastKnownIndexes;
|
|
738
|
+
}
|
|
739
|
+
const { addressIndex: highestUsedAddressIndex, changeAddressIndex: highestUsedChangeAddressIndex } = highestUsedIndex.value;
|
|
740
|
+
const { addressIndex: highestStoredAddressIndex, changeAddressIndex: highestStoredChangeAddressIndex } = highestStoredIndex.value;
|
|
741
|
+
if (highestUsedAddressIndex.index < highestStoredAddressIndex.index) {
|
|
742
|
+
foundLastUsedAddress = true;
|
|
743
|
+
}
|
|
744
|
+
if (highestUsedChangeAddressIndex.index <
|
|
745
|
+
highestStoredChangeAddressIndex.index) {
|
|
746
|
+
foundLastUsedChangeAddress = true;
|
|
747
|
+
}
|
|
748
|
+
if (foundLastUsedAddress && foundLastUsedChangeAddress) {
|
|
749
|
+
let newAddressIndex = addressIndex.index;
|
|
750
|
+
if (highestUsedAddressIndex.index > addressIndex.index ||
|
|
751
|
+
addressHasBeenUsed) {
|
|
752
|
+
const index = highestUsedAddressIndex.index;
|
|
753
|
+
if (highestUsedAddressIndex && index >= 0) {
|
|
754
|
+
lastUsedAddressIndex = highestUsedAddressIndex;
|
|
755
|
+
}
|
|
756
|
+
newAddressIndex = index >= 0 ? index + 1 : index;
|
|
757
|
+
}
|
|
758
|
+
let newChangeAddressIndex = changeAddressIndex.index;
|
|
759
|
+
if (highestUsedChangeAddressIndex.index > changeAddressIndex.index ||
|
|
760
|
+
changeAddressHasBeenUsed) {
|
|
761
|
+
const index = highestUsedChangeAddressIndex.index;
|
|
762
|
+
if (highestUsedChangeAddressIndex && index >= 0) {
|
|
763
|
+
lastUsedChangeAddressIndex = highestUsedChangeAddressIndex;
|
|
764
|
+
}
|
|
765
|
+
newChangeAddressIndex = index >= 0 ? index + 1 : index;
|
|
766
|
+
}
|
|
767
|
+
const nextAvailableAddress = Object.values(allAddresses).find(({ index }) => index === newAddressIndex);
|
|
768
|
+
const nextAvailableChangeAddress = Object.values(allChangeAddresses).find(({ index }) => index === newChangeAddressIndex);
|
|
769
|
+
if (!nextAvailableAddress || !nextAvailableChangeAddress) {
|
|
770
|
+
return lastKnownIndexes;
|
|
771
|
+
}
|
|
772
|
+
return (0, utils_1.ok)({
|
|
773
|
+
addressIndex: nextAvailableAddress,
|
|
774
|
+
lastUsedAddressIndex,
|
|
775
|
+
changeAddressIndex: nextAvailableChangeAddress,
|
|
776
|
+
lastUsedChangeAddressIndex
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
if (!foundLastUsedAddress) {
|
|
780
|
+
const newAddresses = await this.addAddresses({
|
|
781
|
+
addressAmount: constants_1.GENERATE_ADDRESS_AMOUNT,
|
|
782
|
+
changeAddressAmount: 0,
|
|
783
|
+
addressIndex: highestStoredIndex.value.addressIndex.index,
|
|
784
|
+
changeAddressIndex: 0,
|
|
785
|
+
keyDerivationPath,
|
|
786
|
+
addressType
|
|
787
|
+
});
|
|
788
|
+
if (newAddresses.isOk()) {
|
|
789
|
+
addresses = newAddresses.value.addresses || {};
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
if (!foundLastUsedChangeAddress) {
|
|
793
|
+
const newChangeAddresses = await this.addAddresses({
|
|
794
|
+
addressAmount: 0,
|
|
795
|
+
changeAddressAmount: constants_1.GENERATE_ADDRESS_AMOUNT,
|
|
796
|
+
addressIndex: 0,
|
|
797
|
+
changeAddressIndex: highestStoredIndex.value.changeAddressIndex.index,
|
|
798
|
+
keyDerivationPath,
|
|
799
|
+
addressType
|
|
800
|
+
});
|
|
801
|
+
if (newChangeAddresses.isOk()) {
|
|
802
|
+
changeAddresses = newChangeAddresses.value.changeAddresses || {};
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
addressesToScan = Object.values(addresses);
|
|
806
|
+
changeAddressesToScan = Object.values(changeAddresses);
|
|
807
|
+
combinedAddressesToScan = [
|
|
808
|
+
...addressesToScan,
|
|
809
|
+
...changeAddressesToScan
|
|
810
|
+
];
|
|
811
|
+
allAddresses = [...allAddresses, ...addressesToScan];
|
|
812
|
+
allChangeAddresses = [...allChangeAddresses, ...changeAddressesToScan];
|
|
813
|
+
}
|
|
814
|
+
return lastKnownIndexes;
|
|
815
|
+
}
|
|
816
|
+
catch (e) {
|
|
817
|
+
return (0, utils_1.err)(e);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
getHighestStoredAddressIndex({ addressType }) {
|
|
821
|
+
try {
|
|
822
|
+
const currentWallet = this.data;
|
|
823
|
+
const addresses = currentWallet.addresses[addressType];
|
|
824
|
+
const changeAddresses = currentWallet.changeAddresses[addressType];
|
|
825
|
+
const addressIndex = Object.values(addresses).reduce((prev, current) => {
|
|
826
|
+
return prev.index > current.index ? prev : current;
|
|
827
|
+
});
|
|
828
|
+
const changeAddressIndex = Object.values(changeAddresses).reduce((prev, current) => (prev.index > current.index ? prev : current));
|
|
829
|
+
return (0, utils_1.ok)({ addressIndex, changeAddressIndex });
|
|
830
|
+
}
|
|
831
|
+
catch (e) {
|
|
832
|
+
return (0, utils_1.err)(e);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
async addAddresses({ addressAmount = 5, changeAddressAmount = 5, addressIndex = 0, changeAddressIndex = 0, addressType, keyDerivationPath }) {
|
|
836
|
+
if (!addressType) {
|
|
837
|
+
addressType = this.data.addressType;
|
|
838
|
+
}
|
|
839
|
+
const network = this._network;
|
|
840
|
+
const { path, type } = shapes_1.addressTypes[addressType];
|
|
841
|
+
if (!keyDerivationPath) {
|
|
842
|
+
const keyDerivationPathResponse = (0, utils_1.getKeyDerivationPathObject)({
|
|
843
|
+
path,
|
|
844
|
+
network
|
|
845
|
+
});
|
|
846
|
+
if (keyDerivationPathResponse.isErr()) {
|
|
847
|
+
return (0, utils_1.err)(keyDerivationPathResponse.error.message);
|
|
848
|
+
}
|
|
849
|
+
keyDerivationPath = keyDerivationPathResponse.value;
|
|
850
|
+
}
|
|
851
|
+
const generatedAddresses = await this.generateAddresses({
|
|
852
|
+
addressAmount,
|
|
853
|
+
changeAddressAmount,
|
|
854
|
+
addressIndex,
|
|
855
|
+
changeAddressIndex,
|
|
856
|
+
keyDerivationPath,
|
|
857
|
+
addressType: type
|
|
858
|
+
});
|
|
859
|
+
if (generatedAddresses.isErr()) {
|
|
860
|
+
return (0, utils_1.err)(generatedAddresses.error);
|
|
861
|
+
}
|
|
862
|
+
const removeDuplicateResponse = await this.removeDuplicateAddresses({
|
|
863
|
+
addresses: generatedAddresses.value.addresses,
|
|
864
|
+
changeAddresses: generatedAddresses.value.changeAddresses
|
|
865
|
+
});
|
|
866
|
+
if (removeDuplicateResponse.isErr()) {
|
|
867
|
+
return (0, utils_1.err)(removeDuplicateResponse.error.message);
|
|
868
|
+
}
|
|
869
|
+
const addresses = removeDuplicateResponse.value.addresses;
|
|
870
|
+
const changeAddresses = removeDuplicateResponse.value.changeAddresses;
|
|
871
|
+
if (Object.keys(addresses).length) {
|
|
872
|
+
this._data.addresses[addressType] = Object.assign(Object.assign({}, this.data.addresses[addressType]), addresses);
|
|
873
|
+
await this.saveWalletData('addresses', this._data.addresses);
|
|
874
|
+
}
|
|
875
|
+
if (Object.keys(changeAddresses).length) {
|
|
876
|
+
this._data.changeAddresses[addressType] = Object.assign(Object.assign({}, this.data.changeAddresses[addressType]), changeAddresses);
|
|
877
|
+
await this.saveWalletData('changeAddresses', this._data.changeAddresses);
|
|
878
|
+
}
|
|
879
|
+
return (0, utils_1.ok)(Object.assign(Object.assign({}, generatedAddresses.value), { addressType: type }));
|
|
880
|
+
}
|
|
881
|
+
async removeDuplicateAddresses({ addresses = {}, changeAddresses = {} }) {
|
|
882
|
+
try {
|
|
883
|
+
const currentWallet = this.data;
|
|
884
|
+
const currentAddressTypeContent = currentWallet.addresses;
|
|
885
|
+
const currentChangeAddressTypeContent = currentWallet.changeAddresses;
|
|
886
|
+
await Promise.all([
|
|
887
|
+
(0, utils_1.objectKeys)(currentAddressTypeContent).map(async (addressType) => {
|
|
888
|
+
await Promise.all((0, utils_1.objectKeys)(addresses).map((scriptHash) => {
|
|
889
|
+
if (scriptHash in currentAddressTypeContent[addressType]) {
|
|
890
|
+
delete addresses[scriptHash];
|
|
891
|
+
}
|
|
892
|
+
}));
|
|
893
|
+
}),
|
|
894
|
+
(0, utils_1.objectKeys)(currentChangeAddressTypeContent).map(async (addressType) => {
|
|
895
|
+
await Promise.all((0, utils_1.objectKeys)(changeAddresses).map((scriptHash) => {
|
|
896
|
+
if (scriptHash in currentChangeAddressTypeContent[addressType]) {
|
|
897
|
+
delete changeAddresses[scriptHash];
|
|
898
|
+
}
|
|
899
|
+
}));
|
|
900
|
+
})
|
|
901
|
+
]);
|
|
902
|
+
return (0, utils_1.ok)({ addresses, changeAddresses });
|
|
903
|
+
}
|
|
904
|
+
catch (e) {
|
|
905
|
+
return (0, utils_1.err)(e);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
async updateAddressIndexes({ addressType } = {}) {
|
|
909
|
+
const checkRes = await this.checkElectrumConnection();
|
|
910
|
+
if (checkRes.isErr())
|
|
911
|
+
return (0, utils_1.err)(checkRes.error.message);
|
|
912
|
+
const currentWallet = this.data;
|
|
913
|
+
let addressTypeKeys = Object.values(types_1.EAddressType);
|
|
914
|
+
if (addressType) {
|
|
915
|
+
addressTypeKeys = [addressType];
|
|
916
|
+
}
|
|
917
|
+
let updated = false;
|
|
918
|
+
const promises = addressTypeKeys.map(async (addressTypeKey) => {
|
|
919
|
+
const response = await this.getNextAvailableAddress(addressTypeKey);
|
|
920
|
+
if (response.isErr()) {
|
|
921
|
+
throw response.error;
|
|
922
|
+
}
|
|
923
|
+
const result = response.value;
|
|
924
|
+
let addressIndex = currentWallet.addressIndex[addressTypeKey];
|
|
925
|
+
let changeAddressIndex = currentWallet.changeAddressIndex[addressTypeKey];
|
|
926
|
+
let lastUsedAddressIndex = currentWallet.lastUsedAddressIndex[addressTypeKey];
|
|
927
|
+
let lastUsedChangeAddressIndex = currentWallet.lastUsedChangeAddressIndex[addressTypeKey];
|
|
928
|
+
if (addressIndex.index < 0 ||
|
|
929
|
+
changeAddressIndex.index < 0 ||
|
|
930
|
+
result.addressIndex.index > addressIndex.index ||
|
|
931
|
+
result.changeAddressIndex.index > changeAddressIndex.index ||
|
|
932
|
+
result.lastUsedAddressIndex.index > lastUsedAddressIndex.index ||
|
|
933
|
+
result.lastUsedChangeAddressIndex.index >
|
|
934
|
+
(lastUsedChangeAddressIndex === null || lastUsedChangeAddressIndex === void 0 ? void 0 : lastUsedChangeAddressIndex.index)) {
|
|
935
|
+
if (result.addressIndex) {
|
|
936
|
+
addressIndex = result.addressIndex;
|
|
937
|
+
}
|
|
938
|
+
if (result.changeAddressIndex) {
|
|
939
|
+
changeAddressIndex = result.changeAddressIndex;
|
|
940
|
+
}
|
|
941
|
+
if (result.lastUsedAddressIndex) {
|
|
942
|
+
lastUsedAddressIndex = result.lastUsedAddressIndex;
|
|
943
|
+
}
|
|
944
|
+
if (result.lastUsedChangeAddressIndex) {
|
|
945
|
+
lastUsedChangeAddressIndex = result.lastUsedChangeAddressIndex;
|
|
946
|
+
}
|
|
947
|
+
const lastUsedIndex = lastUsedAddressIndex.index > 0 ? lastUsedAddressIndex.index : 0;
|
|
948
|
+
const currentGap = Math.abs(addressIndex.index - lastUsedIndex);
|
|
949
|
+
if (currentGap > constants_1.GAP_LIMIT) {
|
|
950
|
+
const excessAmount = currentGap - constants_1.GAP_LIMIT;
|
|
951
|
+
const newIndex = addressIndex.index - excessAmount;
|
|
952
|
+
const _addressIndex = await this.generateAddresses({
|
|
953
|
+
addressType: addressTypeKey,
|
|
954
|
+
addressAmount: 1,
|
|
955
|
+
changeAddressAmount: 0,
|
|
956
|
+
addressIndex: newIndex
|
|
957
|
+
});
|
|
958
|
+
if (_addressIndex.isErr()) {
|
|
959
|
+
return (0, utils_1.err)(_addressIndex.error.message);
|
|
960
|
+
}
|
|
961
|
+
addressIndex = Object.values(_addressIndex.value.addresses)[0];
|
|
962
|
+
}
|
|
963
|
+
const lastUsedChangeIndex = lastUsedChangeAddressIndex.index > 0
|
|
964
|
+
? lastUsedChangeAddressIndex.index
|
|
965
|
+
: 0;
|
|
966
|
+
const currentChangeAddressGap = Math.abs(changeAddressIndex.index - lastUsedChangeIndex);
|
|
967
|
+
if (currentChangeAddressGap > constants_1.GAP_LIMIT) {
|
|
968
|
+
const excessAmount = currentGap - constants_1.GAP_LIMIT;
|
|
969
|
+
const newIndex = addressIndex.index - excessAmount;
|
|
970
|
+
const _changeAddressIndex = await this.generateAddresses({
|
|
971
|
+
addressType: addressTypeKey,
|
|
972
|
+
addressAmount: 0,
|
|
973
|
+
changeAddressAmount: 1,
|
|
974
|
+
changeAddressIndex: newIndex
|
|
975
|
+
});
|
|
976
|
+
if (_changeAddressIndex.isErr()) {
|
|
977
|
+
return (0, utils_1.err)(_changeAddressIndex.error.message);
|
|
978
|
+
}
|
|
979
|
+
changeAddressIndex = Object.values(_changeAddressIndex.value.changeAddresses)[0];
|
|
980
|
+
}
|
|
981
|
+
this._data.addressIndex[addressTypeKey] = addressIndex;
|
|
982
|
+
this._data.changeAddressIndex[addressTypeKey] = changeAddressIndex;
|
|
983
|
+
this._data.lastUsedAddressIndex[addressTypeKey] = lastUsedAddressIndex;
|
|
984
|
+
this._data.lastUsedChangeAddressIndex[addressTypeKey] =
|
|
985
|
+
lastUsedChangeAddressIndex;
|
|
986
|
+
await Promise.all([
|
|
987
|
+
this.saveWalletData('addressIndex', this._data.addressIndex),
|
|
988
|
+
this.saveWalletData('changeAddressIndex', this._data.changeAddressIndex),
|
|
989
|
+
this.saveWalletData('lastUsedAddressIndex', this._data.lastUsedAddressIndex),
|
|
990
|
+
this.saveWalletData('lastUsedChangeAddressIndex', this._data.lastUsedChangeAddressIndex)
|
|
991
|
+
]);
|
|
992
|
+
updated = true;
|
|
993
|
+
}
|
|
994
|
+
});
|
|
995
|
+
try {
|
|
996
|
+
await Promise.all(promises);
|
|
997
|
+
return (0, utils_1.ok)(updated ? 'Successfully updated indexes.' : 'No update needed.');
|
|
998
|
+
}
|
|
999
|
+
catch (e) {
|
|
1000
|
+
return (0, utils_1.err)(e);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
async resetAddressIndexes() {
|
|
1004
|
+
const defaultWalletShape = (0, utils_1.getDefaultWalletData)();
|
|
1005
|
+
this._data.addressIndex = defaultWalletShape.addressIndex;
|
|
1006
|
+
this._data.changeAddressIndex = defaultWalletShape.changeAddressIndex;
|
|
1007
|
+
this._data.lastUsedAddressIndex = defaultWalletShape.lastUsedAddressIndex;
|
|
1008
|
+
this._data.lastUsedChangeAddressIndex =
|
|
1009
|
+
defaultWalletShape.lastUsedChangeAddressIndex;
|
|
1010
|
+
await Promise.all([
|
|
1011
|
+
this.saveWalletData('addressIndex', this._data.addressIndex),
|
|
1012
|
+
this.saveWalletData('changeAddressIndex', this._data.changeAddressIndex),
|
|
1013
|
+
this.saveWalletData('lastUsedAddressIndex', this._data.lastUsedAddressIndex),
|
|
1014
|
+
this.saveWalletData('lastUsedChangeAddressIndex', this._data.lastUsedChangeAddressIndex)
|
|
1015
|
+
]);
|
|
1016
|
+
}
|
|
1017
|
+
async generateNewReceiveAddress({ addressType = this.data.addressType, keyDerivationPath }) {
|
|
1018
|
+
try {
|
|
1019
|
+
const network = this._network;
|
|
1020
|
+
const currentWallet = this.data;
|
|
1021
|
+
const getGapLimitResponse = this.getGapLimit({
|
|
1022
|
+
addressType
|
|
1023
|
+
});
|
|
1024
|
+
if (getGapLimitResponse.isErr()) {
|
|
1025
|
+
return (0, utils_1.err)(getGapLimitResponse.error.message);
|
|
1026
|
+
}
|
|
1027
|
+
const { addressDelta } = getGapLimitResponse.value;
|
|
1028
|
+
if (addressDelta >= constants_1.GAP_LIMIT) {
|
|
1029
|
+
const addressIndex = currentWallet.addressIndex;
|
|
1030
|
+
const receiveAddress = addressIndex[addressType];
|
|
1031
|
+
return (0, utils_1.ok)(receiveAddress);
|
|
1032
|
+
}
|
|
1033
|
+
const { path } = shapes_1.addressTypes[addressType];
|
|
1034
|
+
if (!keyDerivationPath) {
|
|
1035
|
+
const keyDerivationPathResponse = (0, utils_1.getKeyDerivationPathObject)({
|
|
1036
|
+
network,
|
|
1037
|
+
path
|
|
1038
|
+
});
|
|
1039
|
+
if (keyDerivationPathResponse.isErr()) {
|
|
1040
|
+
return (0, utils_1.err)(keyDerivationPathResponse.error.message);
|
|
1041
|
+
}
|
|
1042
|
+
keyDerivationPath = keyDerivationPathResponse.value;
|
|
1043
|
+
}
|
|
1044
|
+
const addresses = currentWallet.addresses[addressType];
|
|
1045
|
+
const currentAddressIndex = currentWallet.addressIndex[addressType].index;
|
|
1046
|
+
const nextAddressIndex = Object.values(addresses).find((address) => {
|
|
1047
|
+
return address.index === currentAddressIndex + 1;
|
|
1048
|
+
});
|
|
1049
|
+
if (nextAddressIndex) {
|
|
1050
|
+
this._data.addressIndex[addressType] = nextAddressIndex;
|
|
1051
|
+
await Promise.all([
|
|
1052
|
+
this.saveWalletData('addressIndex', this._data.addressIndex)
|
|
1053
|
+
]);
|
|
1054
|
+
return (0, utils_1.ok)(nextAddressIndex);
|
|
1055
|
+
}
|
|
1056
|
+
const addAddressesRes = await this.addAddresses({
|
|
1057
|
+
addressAmount: 1,
|
|
1058
|
+
changeAddressAmount: 0,
|
|
1059
|
+
addressIndex: currentAddressIndex + 1,
|
|
1060
|
+
changeAddressIndex: 0,
|
|
1061
|
+
keyDerivationPath,
|
|
1062
|
+
addressType
|
|
1063
|
+
});
|
|
1064
|
+
if (addAddressesRes.isErr()) {
|
|
1065
|
+
return (0, utils_1.err)(addAddressesRes.error.message);
|
|
1066
|
+
}
|
|
1067
|
+
const addressKeys = Object.keys(addAddressesRes.value.addresses);
|
|
1068
|
+
if (!addressKeys.length) {
|
|
1069
|
+
return (0, utils_1.err)('Unable to generate addresses at this time.');
|
|
1070
|
+
}
|
|
1071
|
+
const newAddressIndex = addAddressesRes.value.addresses[addressKeys[0]];
|
|
1072
|
+
this._data.addressIndex[addressType] = newAddressIndex;
|
|
1073
|
+
await this.saveWalletData('addressIndex', this._data.addressIndex);
|
|
1074
|
+
return (0, utils_1.ok)(newAddressIndex);
|
|
1075
|
+
}
|
|
1076
|
+
catch (e) {
|
|
1077
|
+
return (0, utils_1.err)(e);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
getGapLimit({ addressType }) {
|
|
1081
|
+
try {
|
|
1082
|
+
if (!addressType) {
|
|
1083
|
+
addressType = this.data.addressType;
|
|
1084
|
+
}
|
|
1085
|
+
const currentWallet = this.data;
|
|
1086
|
+
const addressIndex = currentWallet.addressIndex[addressType].index;
|
|
1087
|
+
const lastUsedAddressIndex = currentWallet.lastUsedAddressIndex[addressType].index;
|
|
1088
|
+
const changeAddressIndex = currentWallet.changeAddressIndex[addressType].index;
|
|
1089
|
+
const lastUsedChangeAddressIndex = currentWallet.lastUsedChangeAddressIndex[addressType].index;
|
|
1090
|
+
const addressDelta = Math.abs(addressIndex - (lastUsedAddressIndex > 0 ? lastUsedAddressIndex : 0));
|
|
1091
|
+
const changeAddressDelta = Math.abs(changeAddressIndex -
|
|
1092
|
+
(lastUsedChangeAddressIndex > 0 ? lastUsedChangeAddressIndex : 0));
|
|
1093
|
+
return (0, utils_1.ok)({ addressDelta, changeAddressDelta });
|
|
1094
|
+
}
|
|
1095
|
+
catch (e) {
|
|
1096
|
+
return (0, utils_1.err)(e);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
async getUtxos({ scanAllAddresses = false }) {
|
|
1100
|
+
var _a, _b, _c, _d;
|
|
1101
|
+
const checkRes = await this.checkElectrumConnection();
|
|
1102
|
+
if (checkRes.isErr())
|
|
1103
|
+
return (0, utils_1.err)(checkRes.error.message);
|
|
1104
|
+
const getUtxosRes = await this.electrum.getUtxos({ scanAllAddresses });
|
|
1105
|
+
if (getUtxosRes.isErr()) {
|
|
1106
|
+
return (0, utils_1.err)(getUtxosRes.error.message);
|
|
1107
|
+
}
|
|
1108
|
+
const utxos = (_b = (_a = getUtxosRes.value) === null || _a === void 0 ? void 0 : _a.utxos) !== null && _b !== void 0 ? _b : [];
|
|
1109
|
+
const balance = (_d = (_c = getUtxosRes.value) === null || _c === void 0 ? void 0 : _c.balance) !== null && _d !== void 0 ? _d : 0;
|
|
1110
|
+
this._data.utxos = utxos;
|
|
1111
|
+
this._data.balance = balance;
|
|
1112
|
+
await Promise.all([
|
|
1113
|
+
this.saveWalletData('utxos', this._data.utxos),
|
|
1114
|
+
this.saveWalletData('balance', this._data.balance)
|
|
1115
|
+
]);
|
|
1116
|
+
return (0, utils_1.ok)({ utxos, balance });
|
|
1117
|
+
}
|
|
1118
|
+
listUtxos() {
|
|
1119
|
+
return this.data.utxos;
|
|
1120
|
+
}
|
|
1121
|
+
async saveWalletData(key, data) {
|
|
1122
|
+
if (!this._setData)
|
|
1123
|
+
return;
|
|
1124
|
+
const walletDataKey = this.getWalletDataKey(key);
|
|
1125
|
+
await this._setData(walletDataKey, data);
|
|
1126
|
+
}
|
|
1127
|
+
async updateAndSaveWalletData(key, data, addressType) {
|
|
1128
|
+
if (addressType) {
|
|
1129
|
+
this.data[key][addressType] = data;
|
|
1130
|
+
await this.saveWalletData(key, this._data[key]);
|
|
1131
|
+
}
|
|
1132
|
+
else {
|
|
1133
|
+
this.data[key] = data;
|
|
1134
|
+
await this.saveWalletData(key, this._data[key]);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
async updateTransactions({ scanAllAddresses = false, replaceStoredTransactions = false }) {
|
|
1138
|
+
await this.checkUnconfirmedTransactions();
|
|
1139
|
+
const history = await this.electrum.getAddressHistory({
|
|
1140
|
+
scanAllAddresses: scanAllAddresses || replaceStoredTransactions
|
|
1141
|
+
});
|
|
1142
|
+
if (history.isErr()) {
|
|
1143
|
+
return (0, utils_1.err)(history.error.message);
|
|
1144
|
+
}
|
|
1145
|
+
if (!history.value.length) {
|
|
1146
|
+
return (0, utils_1.ok)(undefined);
|
|
1147
|
+
}
|
|
1148
|
+
const getTransactionsResponse = await this.electrum.getTransactions({
|
|
1149
|
+
txHashes: history.value
|
|
1150
|
+
});
|
|
1151
|
+
if (getTransactionsResponse.isErr()) {
|
|
1152
|
+
return (0, utils_1.err)(getTransactionsResponse.error.message);
|
|
1153
|
+
}
|
|
1154
|
+
const formatTransactionsResponse = await this.formatTransactions({
|
|
1155
|
+
transactions: getTransactionsResponse.value.data
|
|
1156
|
+
});
|
|
1157
|
+
if (formatTransactionsResponse.isErr()) {
|
|
1158
|
+
return (0, utils_1.err)(formatTransactionsResponse.error.message);
|
|
1159
|
+
}
|
|
1160
|
+
const transactions = formatTransactionsResponse.value;
|
|
1161
|
+
this.addUnconfirmedTransactions({
|
|
1162
|
+
transactions
|
|
1163
|
+
});
|
|
1164
|
+
if (replaceStoredTransactions) {
|
|
1165
|
+
this._data.transactions = transactions;
|
|
1166
|
+
await this.saveWalletData('transactions', this._data.transactions);
|
|
1167
|
+
return (0, utils_1.ok)(undefined);
|
|
1168
|
+
}
|
|
1169
|
+
const formattedTransactions = {};
|
|
1170
|
+
let notificationTxid;
|
|
1171
|
+
const storedTransactions = this.data.transactions;
|
|
1172
|
+
const confirmedTxs = [];
|
|
1173
|
+
const receivedTxs = [];
|
|
1174
|
+
const sentTxs = [];
|
|
1175
|
+
Object.keys(transactions).forEach((txid) => {
|
|
1176
|
+
var _a, _b, _c, _d, _e;
|
|
1177
|
+
if (!storedTransactions[txid] ||
|
|
1178
|
+
storedTransactions[txid].height !== transactions[txid].height) {
|
|
1179
|
+
formattedTransactions[txid] = Object.assign(Object.assign({}, transactions[txid]), { timestamp: (_d = (_b = (_a = storedTransactions[txid]) === null || _a === void 0 ? void 0 : _a.timestamp) !== null && _b !== void 0 ? _b : (_c = transactions[txid]) === null || _c === void 0 ? void 0 : _c.timestamp) !== null && _d !== void 0 ? _d : Date.now() });
|
|
1180
|
+
if (this.onMessage && ((_e = formattedTransactions[txid]) === null || _e === void 0 ? void 0 : _e.height) > 0)
|
|
1181
|
+
confirmedTxs.push({ transaction: formattedTransactions[txid] });
|
|
1182
|
+
}
|
|
1183
|
+
if (!(txid in storedTransactions)) {
|
|
1184
|
+
if (this.onMessage) {
|
|
1185
|
+
if (transactions[txid].type === types_1.EPaymentType.received) {
|
|
1186
|
+
receivedTxs.push({ transaction: transactions[txid] });
|
|
1187
|
+
}
|
|
1188
|
+
else if (transactions[txid].type === types_1.EPaymentType.sent) {
|
|
1189
|
+
sentTxs.push({ transaction: transactions[txid] });
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
notificationTxid = txid;
|
|
1193
|
+
}
|
|
1194
|
+
});
|
|
1195
|
+
if (!Object.keys(formattedTransactions).length) {
|
|
1196
|
+
return (0, utils_1.ok)(undefined);
|
|
1197
|
+
}
|
|
1198
|
+
this._data.transactions = Object.assign(Object.assign({}, this._data.transactions), formattedTransactions);
|
|
1199
|
+
await this.saveWalletData('transactions', this._data.transactions);
|
|
1200
|
+
if (this.onMessage) {
|
|
1201
|
+
confirmedTxs.forEach((tx) => {
|
|
1202
|
+
this.onMessage('transactionConfirmed', tx);
|
|
1203
|
+
});
|
|
1204
|
+
sentTxs.forEach((tx) => {
|
|
1205
|
+
this.onMessage('transactionSent', tx);
|
|
1206
|
+
});
|
|
1207
|
+
receivedTxs.forEach((tx) => {
|
|
1208
|
+
this.onMessage('transactionReceived', tx);
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
return (0, utils_1.ok)(notificationTxid);
|
|
1212
|
+
}
|
|
1213
|
+
async checkUnconfirmedTransactions() {
|
|
1214
|
+
try {
|
|
1215
|
+
const processRes = await this.processUnconfirmedTransactions();
|
|
1216
|
+
if (processRes.isErr()) {
|
|
1217
|
+
return (0, utils_1.err)(processRes.error.message);
|
|
1218
|
+
}
|
|
1219
|
+
const { unconfirmedTxs, outdatedTxs, ghostTxs } = processRes.value;
|
|
1220
|
+
if (outdatedTxs.length > 0) {
|
|
1221
|
+
if (this.onMessage)
|
|
1222
|
+
this.onMessage('reorg', outdatedTxs);
|
|
1223
|
+
await this.updateTransactionHeights(outdatedTxs);
|
|
1224
|
+
}
|
|
1225
|
+
if (ghostTxs.length > 0) {
|
|
1226
|
+
if (this.onMessage)
|
|
1227
|
+
this.onMessage('rbf', ghostTxs);
|
|
1228
|
+
await this.updateGhostTransactions({
|
|
1229
|
+
txIds: ghostTxs
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
else {
|
|
1233
|
+
this._data.unconfirmedTransactions = unconfirmedTxs;
|
|
1234
|
+
await Promise.all([
|
|
1235
|
+
this.saveWalletData('unconfirmedTransactions', this._data.unconfirmedTransactions)
|
|
1236
|
+
]);
|
|
1237
|
+
}
|
|
1238
|
+
return (0, utils_1.ok)('Successfully updated unconfirmed transactions.');
|
|
1239
|
+
}
|
|
1240
|
+
catch (e) {
|
|
1241
|
+
return (0, utils_1.err)(e);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
async processUnconfirmedTransactions() {
|
|
1245
|
+
try {
|
|
1246
|
+
const oldUnconfirmedTxs = this.getUnconfirmedTransactions();
|
|
1247
|
+
const tx_hashes = Object.values(oldUnconfirmedTxs).map((transaction) => {
|
|
1248
|
+
return { tx_hash: transaction.txid };
|
|
1249
|
+
});
|
|
1250
|
+
const txs = await this.electrum.getTransactions({
|
|
1251
|
+
txHashes: tx_hashes
|
|
1252
|
+
});
|
|
1253
|
+
if (txs.isErr()) {
|
|
1254
|
+
return (0, utils_1.err)(txs.error);
|
|
1255
|
+
}
|
|
1256
|
+
const unconfirmedTxs = {};
|
|
1257
|
+
const outdatedTxs = [];
|
|
1258
|
+
const ghostTxs = [];
|
|
1259
|
+
txs.value.data.forEach((txData) => {
|
|
1260
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1261
|
+
if (!this.electrum.transactionExists(txData)) {
|
|
1262
|
+
ghostTxs.push(txData.data.tx_hash);
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
const newHeight = this.confirmationsToBlockHeight({
|
|
1266
|
+
confirmations: (_b = (_a = txData.result) === null || _a === void 0 ? void 0 : _a.confirmations) !== null && _b !== void 0 ? _b : 0
|
|
1267
|
+
});
|
|
1268
|
+
if (!((_c = txData.result) === null || _c === void 0 ? void 0 : _c.confirmations)) {
|
|
1269
|
+
const oldHeight = (_e = (_d = oldUnconfirmedTxs[txData.data.tx_hash]) === null || _d === void 0 ? void 0 : _d.height) !== null && _e !== void 0 ? _e : 0;
|
|
1270
|
+
if (oldHeight > newHeight) {
|
|
1271
|
+
outdatedTxs.push(txData.data);
|
|
1272
|
+
}
|
|
1273
|
+
unconfirmedTxs[txData.data.tx_hash] = Object.assign(Object.assign({}, oldUnconfirmedTxs[txData.data.tx_hash]), { height: newHeight });
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
if (((_f = txData.result) === null || _f === void 0 ? void 0 : _f.confirmations) < 6) {
|
|
1277
|
+
unconfirmedTxs[txData.data.tx_hash] = Object.assign(Object.assign({}, oldUnconfirmedTxs[txData.data.tx_hash]), { height: newHeight });
|
|
1278
|
+
}
|
|
1279
|
+
});
|
|
1280
|
+
return (0, utils_1.ok)({
|
|
1281
|
+
unconfirmedTxs,
|
|
1282
|
+
outdatedTxs,
|
|
1283
|
+
ghostTxs
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
catch (e) {
|
|
1287
|
+
return (0, utils_1.err)(e);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
getUnconfirmedTransactions() {
|
|
1291
|
+
var _a;
|
|
1292
|
+
const currentWallet = this.data;
|
|
1293
|
+
return (_a = currentWallet === null || currentWallet === void 0 ? void 0 : currentWallet.unconfirmedTransactions) !== null && _a !== void 0 ? _a : {};
|
|
1294
|
+
}
|
|
1295
|
+
confirmationsToBlockHeight({ confirmations, currentHeight }) {
|
|
1296
|
+
if (!currentHeight) {
|
|
1297
|
+
const header = this.data.header;
|
|
1298
|
+
currentHeight = header.height;
|
|
1299
|
+
}
|
|
1300
|
+
if (confirmations > currentHeight) {
|
|
1301
|
+
return 0;
|
|
1302
|
+
}
|
|
1303
|
+
return currentHeight - confirmations;
|
|
1304
|
+
}
|
|
1305
|
+
async updateHeader(headerData) {
|
|
1306
|
+
this._data.header = headerData;
|
|
1307
|
+
await this.saveWalletData('header', headerData);
|
|
1308
|
+
}
|
|
1309
|
+
async updateGhostTransactions({ txIds }) {
|
|
1310
|
+
try {
|
|
1311
|
+
const transactions = this.data.transactions;
|
|
1312
|
+
const unconfirmedTransactions = this.data.unconfirmedTransactions;
|
|
1313
|
+
txIds.forEach((txId) => {
|
|
1314
|
+
if (txId in transactions) {
|
|
1315
|
+
transactions[txId]['exists'] = false;
|
|
1316
|
+
}
|
|
1317
|
+
if (txId in unconfirmedTransactions) {
|
|
1318
|
+
delete unconfirmedTransactions[txId];
|
|
1319
|
+
}
|
|
1320
|
+
});
|
|
1321
|
+
this._data.transactions = transactions;
|
|
1322
|
+
await this.saveWalletData('transactions', transactions);
|
|
1323
|
+
this._data.unconfirmedTransactions = unconfirmedTransactions;
|
|
1324
|
+
await this.saveWalletData('unconfirmedTransactions', unconfirmedTransactions);
|
|
1325
|
+
await this.rescanAddresses({
|
|
1326
|
+
shouldClearAddresses: false
|
|
1327
|
+
});
|
|
1328
|
+
return (0, utils_1.ok)('Successfully deleted transactions.');
|
|
1329
|
+
}
|
|
1330
|
+
catch (e) {
|
|
1331
|
+
return (0, utils_1.err)(e);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
async rescanAddresses({ shouldClearAddresses = true, shouldClearTransactions = false }) {
|
|
1335
|
+
if (shouldClearAddresses) {
|
|
1336
|
+
await this.clearAddresses();
|
|
1337
|
+
}
|
|
1338
|
+
if (shouldClearTransactions) {
|
|
1339
|
+
await this.clearTransactions();
|
|
1340
|
+
}
|
|
1341
|
+
await this.clearUtxos();
|
|
1342
|
+
await this.resetAddressIndexes();
|
|
1343
|
+
await this.setZeroIndexAddresses();
|
|
1344
|
+
return await this.refreshWallet({
|
|
1345
|
+
scanAllAddresses: true
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
async clearUtxos() {
|
|
1349
|
+
this._data.balance = 0;
|
|
1350
|
+
this._data.utxos = [];
|
|
1351
|
+
await Promise.all([
|
|
1352
|
+
this.saveWalletData('balance', this._data.balance),
|
|
1353
|
+
this.saveWalletData('utxos', this._data.utxos)
|
|
1354
|
+
]);
|
|
1355
|
+
return "Successfully cleared UTXO's.";
|
|
1356
|
+
}
|
|
1357
|
+
async clearTransactions() {
|
|
1358
|
+
this._data.transactions = (0, utils_1.getDefaultWalletData)().transactions;
|
|
1359
|
+
await this.saveWalletData('transactions', this._data.transactions);
|
|
1360
|
+
return 'Successfully reset transactions.';
|
|
1361
|
+
}
|
|
1362
|
+
async clearAddresses() {
|
|
1363
|
+
this._data.addresses = (0, shapes_1.getAddressTypeContent)({});
|
|
1364
|
+
this._data.changeAddresses = (0, shapes_1.getAddressTypeContent)({});
|
|
1365
|
+
await Promise.all([
|
|
1366
|
+
this.saveWalletData('addresses', this._data.addresses),
|
|
1367
|
+
this.saveWalletData('changeAddresses', this._data.changeAddresses)
|
|
1368
|
+
]);
|
|
1369
|
+
return 'Successfully reset transactions.';
|
|
1370
|
+
}
|
|
1371
|
+
async updateTransactionHeights(txs) {
|
|
1372
|
+
let needsSave = false;
|
|
1373
|
+
const transactions = this.data.transactions;
|
|
1374
|
+
txs.forEach((tx) => {
|
|
1375
|
+
const txId = tx.tx_hash;
|
|
1376
|
+
if (txId in transactions) {
|
|
1377
|
+
transactions[txId].confirmTimestamp = 0;
|
|
1378
|
+
needsSave = true;
|
|
1379
|
+
}
|
|
1380
|
+
});
|
|
1381
|
+
if (needsSave) {
|
|
1382
|
+
await this.saveWalletData('transactions', transactions);
|
|
1383
|
+
}
|
|
1384
|
+
return 'Successfully updated reorg transactions.';
|
|
1385
|
+
}
|
|
1386
|
+
async addUnconfirmedTransactions({ transactions }) {
|
|
1387
|
+
try {
|
|
1388
|
+
const unconfirmedTransactions = {};
|
|
1389
|
+
Object.keys(transactions).forEach((key) => {
|
|
1390
|
+
const confirmations = this.blockHeightToConfirmations({
|
|
1391
|
+
blockHeight: transactions[key].height
|
|
1392
|
+
});
|
|
1393
|
+
if (confirmations < 6) {
|
|
1394
|
+
unconfirmedTransactions[key] = transactions[key];
|
|
1395
|
+
}
|
|
1396
|
+
});
|
|
1397
|
+
if (!Object.keys(unconfirmedTransactions).length) {
|
|
1398
|
+
return (0, utils_1.ok)('No unconfirmed transactions found.');
|
|
1399
|
+
}
|
|
1400
|
+
this._data.unconfirmedTransactions = Object.assign(Object.assign({}, this.data.unconfirmedTransactions), unconfirmedTransactions);
|
|
1401
|
+
await this.saveWalletData('unconfirmedTransactions', this._data.unconfirmedTransactions);
|
|
1402
|
+
return (0, utils_1.ok)('Successfully updated unconfirmed transactions.');
|
|
1403
|
+
}
|
|
1404
|
+
catch (e) {
|
|
1405
|
+
console.log(e);
|
|
1406
|
+
return (0, utils_1.err)(e);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
blockHeightToConfirmations({ blockHeight, currentHeight }) {
|
|
1410
|
+
if (!blockHeight) {
|
|
1411
|
+
return 0;
|
|
1412
|
+
}
|
|
1413
|
+
if (!currentHeight) {
|
|
1414
|
+
const header = this.electrum.getBlockHeader();
|
|
1415
|
+
currentHeight = header.height;
|
|
1416
|
+
}
|
|
1417
|
+
if (currentHeight < blockHeight) {
|
|
1418
|
+
return 0;
|
|
1419
|
+
}
|
|
1420
|
+
return currentHeight - blockHeight + 1;
|
|
1421
|
+
}
|
|
1422
|
+
async formatTransactions({ transactions }) {
|
|
1423
|
+
if (transactions.length < 1) {
|
|
1424
|
+
return (0, utils_1.ok)({});
|
|
1425
|
+
}
|
|
1426
|
+
const currentWallet = this.data;
|
|
1427
|
+
const inputs = [];
|
|
1428
|
+
transactions.forEach(({ result }) => {
|
|
1429
|
+
if (result === null || result === void 0 ? void 0 : result.vin) {
|
|
1430
|
+
result.vin.forEach((v) => inputs.push({ tx_hash: v.txid, vout: v.vout }));
|
|
1431
|
+
}
|
|
1432
|
+
});
|
|
1433
|
+
const inputDataResponse = await this.getInputData({
|
|
1434
|
+
inputs
|
|
1435
|
+
});
|
|
1436
|
+
if (inputDataResponse.isErr()) {
|
|
1437
|
+
return (0, utils_1.err)(inputDataResponse.error.message);
|
|
1438
|
+
}
|
|
1439
|
+
const addressTypeKeys = Object.values(types_1.EAddressType);
|
|
1440
|
+
const inputData = inputDataResponse.value;
|
|
1441
|
+
const currentAddresses = currentWallet.addresses;
|
|
1442
|
+
const currentChangeAddresses = currentWallet.changeAddresses;
|
|
1443
|
+
let addresses = {};
|
|
1444
|
+
let changeAddresses = {};
|
|
1445
|
+
let rbf = false;
|
|
1446
|
+
addressTypeKeys.map((addressType) => {
|
|
1447
|
+
var _a, _b;
|
|
1448
|
+
if (((_a = Object.keys(currentAddresses[addressType])) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
|
1449
|
+
addresses = Object.assign(Object.assign({}, addresses), currentAddresses[addressType]);
|
|
1450
|
+
}
|
|
1451
|
+
if (((_b = Object.keys(currentChangeAddresses[addressType])) === null || _b === void 0 ? void 0 : _b.length) > 0) {
|
|
1452
|
+
changeAddresses = Object.assign(Object.assign({}, changeAddresses), currentChangeAddresses[addressType]);
|
|
1453
|
+
}
|
|
1454
|
+
});
|
|
1455
|
+
const combinedAddressObj = {};
|
|
1456
|
+
[...Object.values(addresses), ...Object.values(changeAddresses)].map((data) => {
|
|
1457
|
+
combinedAddressObj[data.address] = data;
|
|
1458
|
+
});
|
|
1459
|
+
const formattedTransactions = {};
|
|
1460
|
+
transactions.map(async ({ data, result }) => {
|
|
1461
|
+
if (!result.txid) {
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
let totalInputValue = 0;
|
|
1465
|
+
let matchedInputValue = 0;
|
|
1466
|
+
let totalOutputValue = 0;
|
|
1467
|
+
let matchedOutputValue = 0;
|
|
1468
|
+
let messages = [];
|
|
1469
|
+
result.vin.map(({ txid, scriptSig, vout, sequence }) => {
|
|
1470
|
+
try {
|
|
1471
|
+
const asm = scriptSig.asm;
|
|
1472
|
+
if (asm !== '' && asm.includes('OP_RETURN')) {
|
|
1473
|
+
const OpReturnMessages = (0, utils_1.decodeOpReturnMessage)(asm);
|
|
1474
|
+
messages = messages.concat(OpReturnMessages);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
catch (_a) { }
|
|
1478
|
+
try {
|
|
1479
|
+
if (sequence < 0xffffffff - 1)
|
|
1480
|
+
rbf = true;
|
|
1481
|
+
}
|
|
1482
|
+
catch (_b) { }
|
|
1483
|
+
const { addresses: _addresses, value } = inputData[`${txid}${vout}`];
|
|
1484
|
+
totalInputValue = totalInputValue + value;
|
|
1485
|
+
_addresses.map((address) => {
|
|
1486
|
+
if (address in combinedAddressObj) {
|
|
1487
|
+
matchedInputValue = matchedInputValue + value;
|
|
1488
|
+
}
|
|
1489
|
+
});
|
|
1490
|
+
});
|
|
1491
|
+
result.vout.map(({ scriptPubKey, value }) => {
|
|
1492
|
+
const _addresses = scriptPubKey.addresses
|
|
1493
|
+
? scriptPubKey.addresses
|
|
1494
|
+
: scriptPubKey.address
|
|
1495
|
+
? [scriptPubKey.address]
|
|
1496
|
+
: [];
|
|
1497
|
+
totalOutputValue = totalOutputValue + value;
|
|
1498
|
+
_addresses.map((address) => {
|
|
1499
|
+
if (address in combinedAddressObj) {
|
|
1500
|
+
matchedOutputValue = matchedOutputValue + value;
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1503
|
+
});
|
|
1504
|
+
const txid = result.txid;
|
|
1505
|
+
const type = matchedInputValue > matchedOutputValue
|
|
1506
|
+
? types_1.EPaymentType.sent
|
|
1507
|
+
: types_1.EPaymentType.received;
|
|
1508
|
+
const totalMatchedValue = matchedOutputValue - matchedInputValue;
|
|
1509
|
+
const value = Number(totalMatchedValue.toFixed(8));
|
|
1510
|
+
const totalValue = totalInputValue - totalOutputValue;
|
|
1511
|
+
const fee = Number(Math.abs(totalValue).toFixed(8));
|
|
1512
|
+
const vsize = result.vsize;
|
|
1513
|
+
const satsPerByte = Math.round((0, conversion_1.btcToSats)(fee) / vsize);
|
|
1514
|
+
const { address, height, scriptHash } = data;
|
|
1515
|
+
let timestamp = Date.now();
|
|
1516
|
+
let confirmTimestamp;
|
|
1517
|
+
if (height > 0 && result.blocktime) {
|
|
1518
|
+
confirmTimestamp = result.blocktime * 1000;
|
|
1519
|
+
if (confirmTimestamp < timestamp) {
|
|
1520
|
+
timestamp = confirmTimestamp;
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
formattedTransactions[txid] = {
|
|
1524
|
+
address,
|
|
1525
|
+
height,
|
|
1526
|
+
scriptHash,
|
|
1527
|
+
totalInputValue,
|
|
1528
|
+
matchedInputValue,
|
|
1529
|
+
totalOutputValue,
|
|
1530
|
+
matchedOutputValue,
|
|
1531
|
+
fee,
|
|
1532
|
+
satsPerByte,
|
|
1533
|
+
type,
|
|
1534
|
+
value,
|
|
1535
|
+
txid,
|
|
1536
|
+
messages,
|
|
1537
|
+
timestamp,
|
|
1538
|
+
confirmTimestamp,
|
|
1539
|
+
vin: result.vin,
|
|
1540
|
+
rbf,
|
|
1541
|
+
exists: true,
|
|
1542
|
+
vsize
|
|
1543
|
+
};
|
|
1544
|
+
});
|
|
1545
|
+
return (0, utils_1.ok)(formattedTransactions);
|
|
1546
|
+
}
|
|
1547
|
+
async getInputData({ inputs }) {
|
|
1548
|
+
try {
|
|
1549
|
+
const inputData = {};
|
|
1550
|
+
for (let i = 0; i < inputs.length; i += constants_1.CHUNK_LIMIT) {
|
|
1551
|
+
const chunk = inputs.slice(i, i + constants_1.CHUNK_LIMIT);
|
|
1552
|
+
const getTransactionsResponse = await this.electrum.getTransactionsFromInputs({
|
|
1553
|
+
txHashes: chunk
|
|
1554
|
+
});
|
|
1555
|
+
if (getTransactionsResponse.isErr()) {
|
|
1556
|
+
return (0, utils_1.err)(getTransactionsResponse.error.message);
|
|
1557
|
+
}
|
|
1558
|
+
getTransactionsResponse.value.data.map(({ data, result }) => {
|
|
1559
|
+
const vout = result.vout[data.vout];
|
|
1560
|
+
const addresses = vout.scriptPubKey.addresses
|
|
1561
|
+
? vout.scriptPubKey.addresses
|
|
1562
|
+
: vout.scriptPubKey.address
|
|
1563
|
+
? [vout.scriptPubKey.address]
|
|
1564
|
+
: [];
|
|
1565
|
+
const value = vout.value;
|
|
1566
|
+
const key = `${data.tx_hash}${vout.n}`;
|
|
1567
|
+
inputData[key] = { addresses, value };
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
return (0, utils_1.ok)(inputData);
|
|
1571
|
+
}
|
|
1572
|
+
catch (e) {
|
|
1573
|
+
return (0, utils_1.err)(e);
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
getExchangeRate(currency = 'EUR') {
|
|
1577
|
+
var _a, _b;
|
|
1578
|
+
try {
|
|
1579
|
+
if (currency in this.exchangeRates) {
|
|
1580
|
+
return (_b = (_a = this.exchangeRates[currency]) === null || _a === void 0 ? void 0 : _a.rate) !== null && _b !== void 0 ? _b : 0;
|
|
1581
|
+
}
|
|
1582
|
+
return 0;
|
|
1583
|
+
}
|
|
1584
|
+
catch (_c) {
|
|
1585
|
+
return 0;
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
validateAddress(address) {
|
|
1589
|
+
return (0, utils_1.validateAddress)({ address, network: this._network }).isValid;
|
|
1590
|
+
}
|
|
1591
|
+
async getChangeAddress(addressType = this.data.addressType) {
|
|
1592
|
+
const currentWallet = this.data;
|
|
1593
|
+
const changeAddressIndexContent = currentWallet.changeAddressIndex[addressType];
|
|
1594
|
+
if ((changeAddressIndexContent === null || changeAddressIndexContent === void 0 ? void 0 : changeAddressIndexContent.address) &&
|
|
1595
|
+
changeAddressIndexContent.index >= 0) {
|
|
1596
|
+
return (0, utils_1.ok)(changeAddressIndexContent);
|
|
1597
|
+
}
|
|
1598
|
+
const generateAddressResponse = await this.generateAddresses({
|
|
1599
|
+
addressAmount: 0,
|
|
1600
|
+
changeAddressAmount: 1,
|
|
1601
|
+
addressType
|
|
1602
|
+
});
|
|
1603
|
+
if (generateAddressResponse.isErr()) {
|
|
1604
|
+
console.log(generateAddressResponse.error.message);
|
|
1605
|
+
return (0, utils_1.err)('Unable to successfully generate a change address.');
|
|
1606
|
+
}
|
|
1607
|
+
return (0, utils_1.ok)(generateAddressResponse.value.changeAddresses[0]);
|
|
1608
|
+
}
|
|
1609
|
+
async getFeeEstimates(network = this._network) {
|
|
1610
|
+
try {
|
|
1611
|
+
if (network === types_1.EAvailableNetworks.bitcoinRegtest) {
|
|
1612
|
+
return {
|
|
1613
|
+
fast: 60,
|
|
1614
|
+
normal: 50,
|
|
1615
|
+
slow: 40,
|
|
1616
|
+
minimum: 30,
|
|
1617
|
+
timestamp: Date.now()
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
const urlModifier = network === 'bitcoin' ? '' : 'testnet/';
|
|
1621
|
+
const response = await fetch(`https://mempool.space/${urlModifier}api/v1/fees/recommended`);
|
|
1622
|
+
const res = await response.json();
|
|
1623
|
+
return {
|
|
1624
|
+
fast: res.fastestFee,
|
|
1625
|
+
normal: res.halfHourFee,
|
|
1626
|
+
slow: res.hourFee,
|
|
1627
|
+
minimum: res.minimumFee,
|
|
1628
|
+
timestamp: Date.now()
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
catch (_a) {
|
|
1632
|
+
return shapes_1.defaultFeesShape;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
async setupTransaction(params = {}) {
|
|
1636
|
+
return await this.transaction.setupTransaction(params);
|
|
1637
|
+
}
|
|
1638
|
+
getFeeInfo({ satsPerByte = this.feeEstimates.normal, message = '', transaction, fundingLightning = false } = {}) {
|
|
1639
|
+
return this.transaction.getTotalFeeObj({
|
|
1640
|
+
satsPerByte,
|
|
1641
|
+
message,
|
|
1642
|
+
transaction,
|
|
1643
|
+
fundingLightning
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
async sendMany({ txs = [], satsPerByte = this.feeEstimates.normal, rbf, broadcast = true, shuffleOutputs = true }) {
|
|
1647
|
+
const setupTransactionRes = await this.transaction.setupTransaction({
|
|
1648
|
+
rbf
|
|
1649
|
+
});
|
|
1650
|
+
if (setupTransactionRes.isErr()) {
|
|
1651
|
+
return (0, utils_1.err)(setupTransactionRes.error.message);
|
|
1652
|
+
}
|
|
1653
|
+
if (!Array.isArray(txs))
|
|
1654
|
+
txs = [txs];
|
|
1655
|
+
const shuffledTxs = shuffleOutputs ? (0, utils_1.shuffleArray)(txs) : txs;
|
|
1656
|
+
let index = 0;
|
|
1657
|
+
for (const tx of shuffledTxs) {
|
|
1658
|
+
const updateSendTransactionRes = this.transaction.updateSendTransaction({
|
|
1659
|
+
transaction: {
|
|
1660
|
+
label: tx.message,
|
|
1661
|
+
outputs: [{ address: tx.address, value: tx.amount, index }]
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
if (updateSendTransactionRes.isErr())
|
|
1665
|
+
(0, utils_1.err)(updateSendTransactionRes.error.message);
|
|
1666
|
+
index++;
|
|
1667
|
+
}
|
|
1668
|
+
const updateFeeRes = this.transaction.updateFee({ satsPerByte });
|
|
1669
|
+
if (updateFeeRes.isErr()) {
|
|
1670
|
+
if (updateFeeRes.error.message.includes('Unable to increase the fee')) {
|
|
1671
|
+
const feeInfo = this.getFeeInfo({ satsPerByte: 1 });
|
|
1672
|
+
if (feeInfo.isOk()) {
|
|
1673
|
+
return (0, utils_1.err)(`Fee is too high. The maximum fee for this transaction is ${feeInfo.value.maxSatPerByte}`);
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
else {
|
|
1677
|
+
return (0, utils_1.err)(updateFeeRes.error.message);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
const createRes = await this.transaction.createTransaction({
|
|
1681
|
+
shuffleOutputs
|
|
1682
|
+
});
|
|
1683
|
+
if (createRes.isErr())
|
|
1684
|
+
return (0, utils_1.err)(createRes.error.message);
|
|
1685
|
+
const { hex } = createRes.value;
|
|
1686
|
+
if (!broadcast) {
|
|
1687
|
+
return (0, utils_1.ok)(hex);
|
|
1688
|
+
}
|
|
1689
|
+
const broadcastRes = await this.electrum.broadcastTransaction({
|
|
1690
|
+
rawTx: hex
|
|
1691
|
+
});
|
|
1692
|
+
if (broadcastRes.isErr())
|
|
1693
|
+
return (0, utils_1.err)(broadcastRes.error.message);
|
|
1694
|
+
return (0, utils_1.ok)(broadcastRes.value);
|
|
1695
|
+
}
|
|
1696
|
+
async send({ address, amount, message = '', satsPerByte = this.feeEstimates.normal, rbf, broadcast = true, shuffleOutputs = true }) {
|
|
1697
|
+
return await this.sendMany({
|
|
1698
|
+
txs: [{ address, amount, message }],
|
|
1699
|
+
satsPerByte,
|
|
1700
|
+
rbf,
|
|
1701
|
+
broadcast,
|
|
1702
|
+
shuffleOutputs
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
getAddressFromScriptHash(scriptHash) {
|
|
1706
|
+
const addresses = this.data.addresses;
|
|
1707
|
+
const changeAddresses = this.data.changeAddresses;
|
|
1708
|
+
const combinedAddresses = [
|
|
1709
|
+
...Object.values(addresses),
|
|
1710
|
+
...Object.values(changeAddresses)
|
|
1711
|
+
].flatMap((addressGroup) => Object.values(addressGroup));
|
|
1712
|
+
return combinedAddresses.find((addressObj) => addressObj.scriptHash === scriptHash);
|
|
1713
|
+
}
|
|
1714
|
+
async setZeroIndexAddresses() {
|
|
1715
|
+
const types = Object.values(types_1.EAddressType);
|
|
1716
|
+
const currentWallet = this.data;
|
|
1717
|
+
let saveAddressIndexes = false;
|
|
1718
|
+
let saveChangeAddressIndexes = false;
|
|
1719
|
+
for (const addressType of types) {
|
|
1720
|
+
const addressIndex = currentWallet.addressIndex[addressType];
|
|
1721
|
+
const changeAddressIndex = currentWallet.changeAddressIndex[addressType];
|
|
1722
|
+
if ((addressIndex === null || addressIndex === void 0 ? void 0 : addressIndex.index) < 0) {
|
|
1723
|
+
await this.updateAddressIndex(addressType, false);
|
|
1724
|
+
saveAddressIndexes = true;
|
|
1725
|
+
}
|
|
1726
|
+
if ((changeAddressIndex === null || changeAddressIndex === void 0 ? void 0 : changeAddressIndex.index) < 0) {
|
|
1727
|
+
await this.updateAddressIndex(addressType, true);
|
|
1728
|
+
saveChangeAddressIndexes = true;
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
if (saveAddressIndexes) {
|
|
1732
|
+
await this.saveWalletData('addressIndex', this._data.addressIndex);
|
|
1733
|
+
}
|
|
1734
|
+
if (saveChangeAddressIndexes) {
|
|
1735
|
+
await this.saveWalletData('changeAddressIndex', this._data.changeAddressIndex);
|
|
1736
|
+
}
|
|
1737
|
+
return (0, utils_1.ok)('Set Zero Index Addresses.');
|
|
1738
|
+
}
|
|
1739
|
+
async updateAddressIndex(addressType, isChangeAddress, index = 0) {
|
|
1740
|
+
const address = await this.generateAddresses({
|
|
1741
|
+
addressAmount: isChangeAddress ? 0 : 1,
|
|
1742
|
+
addressIndex: index,
|
|
1743
|
+
changeAddressAmount: isChangeAddress ? 1 : 0,
|
|
1744
|
+
changeAddressIndex: index,
|
|
1745
|
+
addressType
|
|
1746
|
+
});
|
|
1747
|
+
const indexToUpdate = isChangeAddress
|
|
1748
|
+
? 'changeAddressIndex'
|
|
1749
|
+
: 'addressIndex';
|
|
1750
|
+
if (address.isOk()) {
|
|
1751
|
+
const key = isChangeAddress ? 'changeAddresses' : 'addresses';
|
|
1752
|
+
this._data[indexToUpdate][addressType] =
|
|
1753
|
+
address.value[key][Object.keys(address.value[key])[0]];
|
|
1754
|
+
}
|
|
1755
|
+
let addresses = {};
|
|
1756
|
+
if (indexToUpdate === 'addressIndex') {
|
|
1757
|
+
addresses = this.data.addresses[addressType];
|
|
1758
|
+
}
|
|
1759
|
+
else {
|
|
1760
|
+
addresses = this.data.changeAddresses[addressType];
|
|
1761
|
+
}
|
|
1762
|
+
if (!Object.keys(addresses).length) {
|
|
1763
|
+
await this.addAddresses({
|
|
1764
|
+
addressAmount: indexToUpdate === 'addressIndex' ? constants_1.GENERATE_ADDRESS_AMOUNT : 0,
|
|
1765
|
+
addressIndex: index,
|
|
1766
|
+
changeAddressAmount: indexToUpdate === 'changeAddressIndex' ? constants_1.GENERATE_ADDRESS_AMOUNT : 0,
|
|
1767
|
+
changeAddressIndex: index,
|
|
1768
|
+
addressType
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
getAddressIndexInfo() {
|
|
1773
|
+
const addressType = this.data.addressType;
|
|
1774
|
+
const currentWallet = this.data;
|
|
1775
|
+
const addressIndex = currentWallet.addressIndex[addressType];
|
|
1776
|
+
const changeAddressIndex = currentWallet.addressIndex[addressType];
|
|
1777
|
+
const lastUsedAddressIndex = currentWallet.lastUsedAddressIndex[addressType];
|
|
1778
|
+
const lastUsedChangeAddressIndex = currentWallet.lastUsedChangeAddressIndex[addressType];
|
|
1779
|
+
return {
|
|
1780
|
+
addressIndex,
|
|
1781
|
+
changeAddressIndex,
|
|
1782
|
+
lastUsedAddressIndex,
|
|
1783
|
+
lastUsedChangeAddressIndex
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
async getRbfData({ txHash }) {
|
|
1787
|
+
var _a, _b, _c, _d, _e;
|
|
1788
|
+
const txResponse = await this.electrum.getTransactions({
|
|
1789
|
+
txHashes: [txHash]
|
|
1790
|
+
});
|
|
1791
|
+
if (txResponse.isErr()) {
|
|
1792
|
+
return (0, utils_1.err)(txResponse.error.message);
|
|
1793
|
+
}
|
|
1794
|
+
const txData = txResponse.value.data;
|
|
1795
|
+
const wallet = this.data;
|
|
1796
|
+
const addressTypeKeys = (0, utils_1.objectKeys)(types_1.EAddressType);
|
|
1797
|
+
const addresses = wallet.addresses;
|
|
1798
|
+
const changeAddresses = wallet.changeAddresses;
|
|
1799
|
+
let allAddresses = {};
|
|
1800
|
+
let allChangeAddresses = {};
|
|
1801
|
+
await Promise.all(addressTypeKeys.map((addressType) => {
|
|
1802
|
+
allAddresses = Object.assign(Object.assign(Object.assign({}, allAddresses), addresses[addressType]), changeAddresses[addressType]);
|
|
1803
|
+
allChangeAddresses = Object.assign(Object.assign({}, allChangeAddresses), changeAddresses[addressType]);
|
|
1804
|
+
}));
|
|
1805
|
+
let changeAddressData = {
|
|
1806
|
+
address: '',
|
|
1807
|
+
value: 0,
|
|
1808
|
+
index: 0
|
|
1809
|
+
};
|
|
1810
|
+
const inputs = [];
|
|
1811
|
+
let address = '';
|
|
1812
|
+
let scriptHash = '';
|
|
1813
|
+
let path = '';
|
|
1814
|
+
let value = 0;
|
|
1815
|
+
const addressType = types_1.EAddressType.p2wpkh;
|
|
1816
|
+
const outputs = [];
|
|
1817
|
+
let message = '';
|
|
1818
|
+
let inputTotal = 0;
|
|
1819
|
+
let outputTotal = 0;
|
|
1820
|
+
let fee = 0;
|
|
1821
|
+
const insAndOuts = await Promise.all(txData.map(({ result }) => {
|
|
1822
|
+
var _a, _b;
|
|
1823
|
+
const vin = (_a = result.vin) !== null && _a !== void 0 ? _a : [];
|
|
1824
|
+
const vout = (_b = result.vout) !== null && _b !== void 0 ? _b : [];
|
|
1825
|
+
return { vins: vin, vouts: vout };
|
|
1826
|
+
}));
|
|
1827
|
+
const { vins, vouts } = insAndOuts[0];
|
|
1828
|
+
for (let i = 0; i < vins.length; i++) {
|
|
1829
|
+
try {
|
|
1830
|
+
const input = vins[i];
|
|
1831
|
+
const txId = input.txid;
|
|
1832
|
+
const tx = await this.electrum.getTransactions({
|
|
1833
|
+
txHashes: [{ tx_hash: txId }]
|
|
1834
|
+
});
|
|
1835
|
+
if (tx.isErr()) {
|
|
1836
|
+
return (0, utils_1.err)(tx.error.message);
|
|
1837
|
+
}
|
|
1838
|
+
if (tx.value.data[0].data.height > 0) {
|
|
1839
|
+
return (0, utils_1.err)('Transaction is already confirmed. Unable to RBF.');
|
|
1840
|
+
}
|
|
1841
|
+
const txVout = tx.value.data[0].result.vout[input.vout];
|
|
1842
|
+
if ((_a = txVout.scriptPubKey) === null || _a === void 0 ? void 0 : _a.address) {
|
|
1843
|
+
address = txVout.scriptPubKey.address;
|
|
1844
|
+
}
|
|
1845
|
+
else if (((_b = txVout.scriptPubKey) === null || _b === void 0 ? void 0 : _b.addresses) &&
|
|
1846
|
+
txVout.scriptPubKey.addresses.length) {
|
|
1847
|
+
address = txVout.scriptPubKey.addresses[0];
|
|
1848
|
+
}
|
|
1849
|
+
if (!address) {
|
|
1850
|
+
continue;
|
|
1851
|
+
}
|
|
1852
|
+
scriptHash = (0, utils_1.getScriptHash)({ address, network: this._network });
|
|
1853
|
+
if (!(scriptHash in allAddresses)) {
|
|
1854
|
+
continue;
|
|
1855
|
+
}
|
|
1856
|
+
path = allAddresses[scriptHash].path;
|
|
1857
|
+
value = (0, conversion_1.btcToSats)(txVout.value);
|
|
1858
|
+
inputs.push({
|
|
1859
|
+
tx_hash: input.txid,
|
|
1860
|
+
index: input.vout,
|
|
1861
|
+
tx_pos: input.vout,
|
|
1862
|
+
height: 0,
|
|
1863
|
+
address,
|
|
1864
|
+
scriptHash,
|
|
1865
|
+
path,
|
|
1866
|
+
value
|
|
1867
|
+
});
|
|
1868
|
+
if (value) {
|
|
1869
|
+
inputTotal = inputTotal + value;
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
catch (e) {
|
|
1873
|
+
console.log(e);
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
for (let i = 0; i < vouts.length; i++) {
|
|
1877
|
+
const vout = vouts[i];
|
|
1878
|
+
const voutValue = (0, conversion_1.btcToSats)(vout.value);
|
|
1879
|
+
if ((_c = vout.scriptPubKey) === null || _c === void 0 ? void 0 : _c.addresses) {
|
|
1880
|
+
address = vout.scriptPubKey.addresses[0];
|
|
1881
|
+
}
|
|
1882
|
+
else if ((_d = vout.scriptPubKey) === null || _d === void 0 ? void 0 : _d.address) {
|
|
1883
|
+
address = vout.scriptPubKey.address;
|
|
1884
|
+
}
|
|
1885
|
+
else {
|
|
1886
|
+
try {
|
|
1887
|
+
if (vout.scriptPubKey.asm.includes('OP_RETURN')) {
|
|
1888
|
+
message = (0, utils_1.decodeOpReturnMessage)(vout.scriptPubKey.asm)[0] || '';
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
catch (_f) { }
|
|
1892
|
+
}
|
|
1893
|
+
if (!address) {
|
|
1894
|
+
continue;
|
|
1895
|
+
}
|
|
1896
|
+
const changeAddressScriptHash = await (0, utils_1.getScriptHash)({
|
|
1897
|
+
address,
|
|
1898
|
+
network: this._network
|
|
1899
|
+
});
|
|
1900
|
+
if (Object.keys(allAddresses).includes(changeAddressScriptHash)) {
|
|
1901
|
+
changeAddressData = {
|
|
1902
|
+
address,
|
|
1903
|
+
value: voutValue,
|
|
1904
|
+
index: i
|
|
1905
|
+
};
|
|
1906
|
+
}
|
|
1907
|
+
const index = (_e = outputs === null || outputs === void 0 ? void 0 : outputs.length) !== null && _e !== void 0 ? _e : 0;
|
|
1908
|
+
outputs.push({
|
|
1909
|
+
address,
|
|
1910
|
+
value: voutValue,
|
|
1911
|
+
index
|
|
1912
|
+
});
|
|
1913
|
+
outputTotal = outputTotal + voutValue;
|
|
1914
|
+
}
|
|
1915
|
+
if (!(changeAddressData === null || changeAddressData === void 0 ? void 0 : changeAddressData.address) && outputs.length >= 2) {
|
|
1916
|
+
return (0, utils_1.err)('cpfp');
|
|
1917
|
+
}
|
|
1918
|
+
if (outputTotal > inputTotal) {
|
|
1919
|
+
return (0, utils_1.err)('Outputs should not be greater than the inputs.');
|
|
1920
|
+
}
|
|
1921
|
+
fee = Math.abs(Number(inputTotal - outputTotal));
|
|
1922
|
+
return (0, utils_1.ok)({
|
|
1923
|
+
changeAddress: changeAddressData.address,
|
|
1924
|
+
inputs,
|
|
1925
|
+
balance: inputTotal,
|
|
1926
|
+
outputs,
|
|
1927
|
+
fee,
|
|
1928
|
+
message,
|
|
1929
|
+
addressType,
|
|
1930
|
+
rbf: true
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
async deleteOnChainTransactionById({ txid }) {
|
|
1934
|
+
const transactions = this.data.transactions;
|
|
1935
|
+
if (txid in transactions) {
|
|
1936
|
+
delete transactions[txid];
|
|
1937
|
+
}
|
|
1938
|
+
await this.saveWalletData('transactions', transactions);
|
|
1939
|
+
}
|
|
1940
|
+
async addGhostTransaction({ txid }) {
|
|
1941
|
+
if (txid in this._data.transactions) {
|
|
1942
|
+
this._data.transactions[txid].exists = false;
|
|
1943
|
+
}
|
|
1944
|
+
await this.saveWalletData('transactions', this._data.transactions);
|
|
1945
|
+
}
|
|
1946
|
+
async addBoostedTransaction({ newTxId, oldTxId, type = types_1.EBoostType.cpfp, fee }) {
|
|
1947
|
+
try {
|
|
1948
|
+
const boostedTransactions = this.data.boostedTransactions;
|
|
1949
|
+
const parentTransactions = this.getBoostedTransactionParents({
|
|
1950
|
+
txid: oldTxId,
|
|
1951
|
+
boostedTransactions
|
|
1952
|
+
});
|
|
1953
|
+
parentTransactions.push(oldTxId);
|
|
1954
|
+
const boostedTx = {
|
|
1955
|
+
parentTransactions: parentTransactions,
|
|
1956
|
+
childTransaction: newTxId,
|
|
1957
|
+
type,
|
|
1958
|
+
fee
|
|
1959
|
+
};
|
|
1960
|
+
const boostedTransaction = {
|
|
1961
|
+
[oldTxId]: boostedTx
|
|
1962
|
+
};
|
|
1963
|
+
this._data.boostedTransactions = Object.assign(Object.assign({}, this.data.boostedTransactions), boostedTransaction);
|
|
1964
|
+
await this.saveWalletData('boostedTransactions', this._data.boostedTransactions);
|
|
1965
|
+
return (0, utils_1.ok)(boostedTx);
|
|
1966
|
+
}
|
|
1967
|
+
catch (e) {
|
|
1968
|
+
return (0, utils_1.err)(e);
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
async resetSendTransaction() {
|
|
1972
|
+
return await this.transaction.resetSendTransaction();
|
|
1973
|
+
}
|
|
1974
|
+
getBoostableTransactions() {
|
|
1975
|
+
const cpfp = [];
|
|
1976
|
+
const rbf = [];
|
|
1977
|
+
Object.values(this.data.unconfirmedTransactions).map((tx) => {
|
|
1978
|
+
if (tx.rbf)
|
|
1979
|
+
rbf.push(tx);
|
|
1980
|
+
cpfp.push(tx);
|
|
1981
|
+
});
|
|
1982
|
+
return { cpfp, rbf };
|
|
1983
|
+
}
|
|
1984
|
+
addTxInput({ input }) {
|
|
1985
|
+
var _a;
|
|
1986
|
+
try {
|
|
1987
|
+
const txData = this.transaction.data;
|
|
1988
|
+
const inputs = (_a = txData === null || txData === void 0 ? void 0 : txData.inputs) !== null && _a !== void 0 ? _a : [];
|
|
1989
|
+
const newInputs = [...inputs, input];
|
|
1990
|
+
this.transaction.updateSendTransaction({
|
|
1991
|
+
transaction: {
|
|
1992
|
+
inputs: newInputs
|
|
1993
|
+
}
|
|
1994
|
+
});
|
|
1995
|
+
return (0, utils_1.ok)(newInputs);
|
|
1996
|
+
}
|
|
1997
|
+
catch (e) {
|
|
1998
|
+
console.log(e);
|
|
1999
|
+
return (0, utils_1.err)(e);
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
removeTxInput({ input }) {
|
|
2003
|
+
var _a;
|
|
2004
|
+
try {
|
|
2005
|
+
const txData = this.transaction.data;
|
|
2006
|
+
const txInputs = (_a = txData === null || txData === void 0 ? void 0 : txData.inputs) !== null && _a !== void 0 ? _a : [];
|
|
2007
|
+
const newInputs = txInputs.filter((txInput) => {
|
|
2008
|
+
if (!(0, utils_1.objectsMatch)(input, txInput)) {
|
|
2009
|
+
return txInput;
|
|
2010
|
+
}
|
|
2011
|
+
});
|
|
2012
|
+
this.transaction.updateSendTransaction({
|
|
2013
|
+
transaction: {
|
|
2014
|
+
inputs: newInputs
|
|
2015
|
+
}
|
|
2016
|
+
});
|
|
2017
|
+
return (0, utils_1.ok)(newInputs);
|
|
2018
|
+
}
|
|
2019
|
+
catch (e) {
|
|
2020
|
+
console.log(e);
|
|
2021
|
+
return (0, utils_1.err)(e);
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
addTxTag({ tag }) {
|
|
2025
|
+
try {
|
|
2026
|
+
const txData = this.transaction.data;
|
|
2027
|
+
let tags = [...txData.tags, tag];
|
|
2028
|
+
tags = [...new Set(tags)];
|
|
2029
|
+
this.transaction.updateSendTransaction({
|
|
2030
|
+
transaction: Object.assign(Object.assign({}, txData), { tags })
|
|
2031
|
+
});
|
|
2032
|
+
return (0, utils_1.ok)('Tag successfully added');
|
|
2033
|
+
}
|
|
2034
|
+
catch (e) {
|
|
2035
|
+
console.log(e);
|
|
2036
|
+
return (0, utils_1.err)(e);
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
removeTxTag({ tag }) {
|
|
2040
|
+
try {
|
|
2041
|
+
const txData = this.transaction.data;
|
|
2042
|
+
const tags = txData.tags;
|
|
2043
|
+
const newTags = tags.filter((t) => t !== tag);
|
|
2044
|
+
this.transaction.updateSendTransaction({
|
|
2045
|
+
transaction: Object.assign(Object.assign({}, txData), { tags: newTags })
|
|
2046
|
+
});
|
|
2047
|
+
return (0, utils_1.ok)('Tag successfully added');
|
|
2048
|
+
}
|
|
2049
|
+
catch (e) {
|
|
2050
|
+
console.log(e);
|
|
2051
|
+
return (0, utils_1.err)(e);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
setupFeeForOnChainTransaction({ satsPerByte, selectedFeeId }) {
|
|
2055
|
+
var _a;
|
|
2056
|
+
try {
|
|
2057
|
+
const transactionData = this.transaction.data;
|
|
2058
|
+
if (!satsPerByte) {
|
|
2059
|
+
satsPerByte = (_a = transactionData === null || transactionData === void 0 ? void 0 : transactionData.satsPerByte) !== null && _a !== void 0 ? _a : 1;
|
|
2060
|
+
satsPerByte =
|
|
2061
|
+
this.selectedFeeId === types_1.EFeeId.none
|
|
2062
|
+
? satsPerByte
|
|
2063
|
+
: this.feeEstimates[this.selectedFeeId];
|
|
2064
|
+
}
|
|
2065
|
+
const res = this.transaction.updateFee({
|
|
2066
|
+
satsPerByte: satsPerByte !== null && satsPerByte !== void 0 ? satsPerByte : 1,
|
|
2067
|
+
selectedFeeId
|
|
2068
|
+
});
|
|
2069
|
+
if (res.isErr()) {
|
|
2070
|
+
console.log(res.error.message);
|
|
2071
|
+
return (0, utils_1.err)(res.error.message);
|
|
2072
|
+
}
|
|
2073
|
+
return (0, utils_1.ok)('Fee has been changed successfully');
|
|
2074
|
+
}
|
|
2075
|
+
catch (e) {
|
|
2076
|
+
return (0, utils_1.err)(e);
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
updateWalletBalance({ balance }) {
|
|
2080
|
+
try {
|
|
2081
|
+
this._data.balance = balance;
|
|
2082
|
+
this.saveWalletData('balance', balance);
|
|
2083
|
+
return (0, utils_1.ok)('Successfully updated balance.');
|
|
2084
|
+
}
|
|
2085
|
+
catch (e) {
|
|
2086
|
+
return (0, utils_1.err)(e);
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
async updateExchangeRates() {
|
|
2090
|
+
const exchangeRates = await (0, utils_1.getExchangeRates)();
|
|
2091
|
+
if (exchangeRates.isErr())
|
|
2092
|
+
return (0, utils_1.err)(exchangeRates.error.message);
|
|
2093
|
+
this.exchangeRates = exchangeRates.value;
|
|
2094
|
+
await this.saveWalletData('exchangeRates', this.exchangeRates);
|
|
2095
|
+
return (0, utils_1.ok)(this.exchangeRates);
|
|
2096
|
+
}
|
|
2097
|
+
async updateFeeEstimates(forceUpdate = false) {
|
|
2098
|
+
const timestamp = this.feeEstimates.timestamp;
|
|
2099
|
+
const difference = Math.floor((Date.now() - timestamp) / 1000);
|
|
2100
|
+
if (!forceUpdate && difference < 1800) {
|
|
2101
|
+
return (0, utils_1.ok)(this.feeEstimates);
|
|
2102
|
+
}
|
|
2103
|
+
const feeEstimates = await this.getFeeEstimates();
|
|
2104
|
+
if (!feeEstimates) {
|
|
2105
|
+
return (0, utils_1.err)('Unable to retrieve fee estimates.');
|
|
2106
|
+
}
|
|
2107
|
+
this.feeEstimates = feeEstimates;
|
|
2108
|
+
await this.saveWalletData('feeEstimates', feeEstimates);
|
|
2109
|
+
return (0, utils_1.ok)(feeEstimates);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
exports.Wallet = Wallet;
|
|
2113
|
+
//# sourceMappingURL=index.js.map
|