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,838 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EAddressType,
|
|
3
|
+
EAvailableNetworks,
|
|
4
|
+
IAddress,
|
|
5
|
+
IAddresses,
|
|
6
|
+
TAddressTypeContent,
|
|
7
|
+
TConnectToElectrumRes,
|
|
8
|
+
IElectrumGetAddressBalanceRes,
|
|
9
|
+
IGetAddressHistoryResponse,
|
|
10
|
+
IGetAddressScriptHashesHistoryResponse,
|
|
11
|
+
IGetHeaderResponse,
|
|
12
|
+
IGetTransactions,
|
|
13
|
+
IGetTransactionsFromInputs,
|
|
14
|
+
IGetUtxosResponse,
|
|
15
|
+
IHeader,
|
|
16
|
+
INewBlock,
|
|
17
|
+
ISubscribeToAddress,
|
|
18
|
+
ISubscribeToHeader,
|
|
19
|
+
ITransaction,
|
|
20
|
+
ITxHash,
|
|
21
|
+
IUtxo,
|
|
22
|
+
TElectrumNetworks,
|
|
23
|
+
TServer,
|
|
24
|
+
TSubscribedReceive,
|
|
25
|
+
TTxResponse,
|
|
26
|
+
TTxResult,
|
|
27
|
+
TUnspentAddressScriptHashData,
|
|
28
|
+
IPeerData,
|
|
29
|
+
TGetAddressHistory,
|
|
30
|
+
TOnMessage
|
|
31
|
+
} from '../types';
|
|
32
|
+
import * as electrum from 'rn-electrum-client/helpers';
|
|
33
|
+
import { err, getAddressFromScriptPubKey, ok, Result } from '../utils';
|
|
34
|
+
import { Wallet } from '../wallet';
|
|
35
|
+
import { CHUNK_LIMIT, GAP_LIMIT } from '../wallet/constants';
|
|
36
|
+
import { getScriptHash, objectKeys } from '../utils';
|
|
37
|
+
import { addressTypes, POLLING_INTERVAL } from '../shapes';
|
|
38
|
+
import { Block } from 'bitcoinjs-lib';
|
|
39
|
+
import { onMessageKeys } from '../shapes';
|
|
40
|
+
import { Server } from 'net';
|
|
41
|
+
import { TLSSocket } from 'tls';
|
|
42
|
+
|
|
43
|
+
let tls, net;
|
|
44
|
+
try {
|
|
45
|
+
tls = require('tls');
|
|
46
|
+
net = require('net');
|
|
47
|
+
} catch {
|
|
48
|
+
// Modules not available, will attempt to use passed instances, if any.
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class Electrum {
|
|
52
|
+
private readonly _wallet: Wallet;
|
|
53
|
+
private onMessage: TOnMessage;
|
|
54
|
+
private latestConnectionState: boolean | null = null;
|
|
55
|
+
private connectionPollingInterval: NodeJS.Timeout | null;
|
|
56
|
+
private tls: TLSSocket;
|
|
57
|
+
private net: Server;
|
|
58
|
+
|
|
59
|
+
public servers?: TServer | TServer[];
|
|
60
|
+
public readonly network: EAvailableNetworks;
|
|
61
|
+
public readonly electrumNetwork: TElectrumNetworks;
|
|
62
|
+
public connectedToElectrum: boolean;
|
|
63
|
+
public onReceive?: (data: unknown) => void;
|
|
64
|
+
constructor({
|
|
65
|
+
wallet,
|
|
66
|
+
servers,
|
|
67
|
+
network,
|
|
68
|
+
onReceive,
|
|
69
|
+
tls: _tls,
|
|
70
|
+
net: _net
|
|
71
|
+
}: {
|
|
72
|
+
wallet: Wallet;
|
|
73
|
+
servers?: TServer | TServer[];
|
|
74
|
+
network: EAvailableNetworks;
|
|
75
|
+
onReceive?: (data: unknown) => void;
|
|
76
|
+
tls?: TLSSocket;
|
|
77
|
+
net?: Server;
|
|
78
|
+
}) {
|
|
79
|
+
this._wallet = wallet;
|
|
80
|
+
this.onMessage = wallet?.onMessage ?? ((): null => null);
|
|
81
|
+
this.servers = servers ?? [];
|
|
82
|
+
this.network = network;
|
|
83
|
+
this.electrumNetwork = this.getElectrumNetwork(network);
|
|
84
|
+
this.connectedToElectrum = false;
|
|
85
|
+
this.onReceive = onReceive;
|
|
86
|
+
this.tls = _tls ?? tls;
|
|
87
|
+
this.net = _net ?? net;
|
|
88
|
+
if (!this.tls || !this.net) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
'TLS and NET modules are not available and were not passed as instances'
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
this.connectionPollingInterval = setInterval(
|
|
94
|
+
(): Promise<void> => this.checkConnection(),
|
|
95
|
+
POLLING_INTERVAL
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public get wallet(): Wallet {
|
|
100
|
+
return this._wallet;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async connectToElectrum({
|
|
104
|
+
network = this.network,
|
|
105
|
+
servers
|
|
106
|
+
}: {
|
|
107
|
+
network?: EAvailableNetworks;
|
|
108
|
+
servers?: TServer | TServer[];
|
|
109
|
+
}): Promise<Result<TConnectToElectrumRes>> {
|
|
110
|
+
let customPeers = servers
|
|
111
|
+
? Array.isArray(servers)
|
|
112
|
+
? servers
|
|
113
|
+
: [servers]
|
|
114
|
+
: [];
|
|
115
|
+
// @ts-ignore
|
|
116
|
+
customPeers = customPeers.length ? customPeers : this?.servers ?? [];
|
|
117
|
+
const electrumNetwork = this.getElectrumNetwork(network);
|
|
118
|
+
if (electrumNetwork === 'bitcoinRegtest' && !customPeers.length) {
|
|
119
|
+
return err('Regtest requires that you pre-specify a server.');
|
|
120
|
+
}
|
|
121
|
+
const startResponse = await electrum.start({
|
|
122
|
+
network: electrumNetwork,
|
|
123
|
+
tls: this.tls,
|
|
124
|
+
net: this.net,
|
|
125
|
+
customPeers
|
|
126
|
+
});
|
|
127
|
+
if (startResponse.error && !this.wallet.isSwitchingNetworks)
|
|
128
|
+
return err(startResponse.error);
|
|
129
|
+
this.publishConnectionChange(true);
|
|
130
|
+
this.subscribeToHeader().then();
|
|
131
|
+
return ok('Connected to Electrum server.');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async isConnected(): Promise<boolean> {
|
|
135
|
+
const { error } = await electrum.pingServer();
|
|
136
|
+
return !error;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns the balance in sats for a given address.
|
|
141
|
+
* @param {string} scriptHash
|
|
142
|
+
* @return {number}
|
|
143
|
+
*/
|
|
144
|
+
async getAddressBalance(
|
|
145
|
+
scriptHash: string
|
|
146
|
+
): Promise<IElectrumGetAddressBalanceRes> {
|
|
147
|
+
if (!this.connectedToElectrum)
|
|
148
|
+
await this.connectToElectrum({
|
|
149
|
+
network: this.network,
|
|
150
|
+
servers: this.servers
|
|
151
|
+
});
|
|
152
|
+
const network = this.electrumNetwork;
|
|
153
|
+
const response = await electrum.getAddressScriptHashBalance({
|
|
154
|
+
scriptHash,
|
|
155
|
+
network
|
|
156
|
+
});
|
|
157
|
+
if (response.error) {
|
|
158
|
+
return { error: response.error, confirmed: 0, unconfirmed: 0 };
|
|
159
|
+
}
|
|
160
|
+
const { confirmed, unconfirmed } = response.data;
|
|
161
|
+
return { error: response.error, confirmed, unconfirmed };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async getAddressScriptHashBalances(scriptHashes: string[]): Promise<any> {
|
|
165
|
+
return await electrum.getAddressScriptHashBalances({
|
|
166
|
+
scriptHashes,
|
|
167
|
+
network: this.electrumNetwork
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Returns currently connected peer.
|
|
173
|
+
* @returns {Promise<Result<IPeerData>>}
|
|
174
|
+
*/
|
|
175
|
+
async getConnectedPeer(): Promise<Result<IPeerData>> {
|
|
176
|
+
const response = await electrum.getConnectedPeer(this.electrumNetwork);
|
|
177
|
+
if (response?.host && response?.port && response?.protocol) {
|
|
178
|
+
return ok(response);
|
|
179
|
+
}
|
|
180
|
+
return err('No peer available.');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Returns the network string for use with Electrum methods.
|
|
185
|
+
* @param {EAvailableNetworks} [network]
|
|
186
|
+
* @return {TElectrumNetworks}
|
|
187
|
+
*/
|
|
188
|
+
getElectrumNetwork(network: EAvailableNetworks): TElectrumNetworks {
|
|
189
|
+
switch (network) {
|
|
190
|
+
case 'bitcoin':
|
|
191
|
+
return 'bitcoin';
|
|
192
|
+
case 'testnet':
|
|
193
|
+
return 'bitcoinTestnet';
|
|
194
|
+
case 'regtest':
|
|
195
|
+
return 'bitcoinRegtest';
|
|
196
|
+
default:
|
|
197
|
+
return 'bitcoinTestnet';
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Queries Electrum to return the available UTXO's and balance of the provided addresses.
|
|
203
|
+
* @param {EAvailableNetworks} [selectedNetwork]
|
|
204
|
+
* @param {TUnspentAddressScriptHashData} addresses
|
|
205
|
+
*/
|
|
206
|
+
async listUnspentAddressScriptHashes({
|
|
207
|
+
addresses
|
|
208
|
+
}: {
|
|
209
|
+
addresses: TUnspentAddressScriptHashData;
|
|
210
|
+
}): Promise<Result<IGetUtxosResponse>> {
|
|
211
|
+
try {
|
|
212
|
+
const unspentAddressResult =
|
|
213
|
+
await electrum.listUnspentAddressScriptHashes({
|
|
214
|
+
scriptHashes: {
|
|
215
|
+
key: 'scriptHash',
|
|
216
|
+
data: addresses
|
|
217
|
+
},
|
|
218
|
+
network: this.electrumNetwork
|
|
219
|
+
});
|
|
220
|
+
if (unspentAddressResult.error) {
|
|
221
|
+
return err(unspentAddressResult.error);
|
|
222
|
+
}
|
|
223
|
+
let balance = 0;
|
|
224
|
+
const utxos: IUtxo[] = [];
|
|
225
|
+
unspentAddressResult.data.map(({ data, result }) => {
|
|
226
|
+
if (result?.length > 0) {
|
|
227
|
+
return result.map((unspentAddress: IUtxo) => {
|
|
228
|
+
balance = balance + unspentAddress.value;
|
|
229
|
+
utxos.push({
|
|
230
|
+
...data,
|
|
231
|
+
...unspentAddress
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
return ok({ utxos, balance });
|
|
237
|
+
} catch (e) {
|
|
238
|
+
return err(e);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Returns the available history for the provided address script hashes.
|
|
244
|
+
* @param {IAddress[]} [scriptHashes]
|
|
245
|
+
* @param {boolean} [scanAllAddresses]
|
|
246
|
+
* @returns {Promise<Result<IGetAddressHistoryResponse[]>>}
|
|
247
|
+
*/
|
|
248
|
+
async getAddressHistory({
|
|
249
|
+
scriptHashes = [],
|
|
250
|
+
scanAllAddresses = false
|
|
251
|
+
}: {
|
|
252
|
+
scriptHashes?: IAddress[];
|
|
253
|
+
scanAllAddresses?: boolean;
|
|
254
|
+
}): Promise<Result<IGetAddressHistoryResponse[]>> {
|
|
255
|
+
try {
|
|
256
|
+
if (!this.connectedToElectrum)
|
|
257
|
+
await this.connectToElectrum({
|
|
258
|
+
network: this.network,
|
|
259
|
+
servers: this.servers
|
|
260
|
+
});
|
|
261
|
+
const currentWallet = this._wallet.data;
|
|
262
|
+
const currentAddresses: TAddressTypeContent<IAddresses> =
|
|
263
|
+
currentWallet.addresses;
|
|
264
|
+
const currentChangeAddresses: TAddressTypeContent<IAddresses> =
|
|
265
|
+
currentWallet.changeAddresses;
|
|
266
|
+
|
|
267
|
+
const addressIndexes = currentWallet.addressIndex;
|
|
268
|
+
const changeAddressIndexes = currentWallet.changeAddressIndex;
|
|
269
|
+
|
|
270
|
+
if (scriptHashes.length < 1) {
|
|
271
|
+
const addressTypeKeys = objectKeys(addressTypes);
|
|
272
|
+
addressTypeKeys.forEach((addressType) => {
|
|
273
|
+
const addresses = currentAddresses[addressType];
|
|
274
|
+
const changeAddresses = currentChangeAddresses[addressType];
|
|
275
|
+
let addressValues = Object.values(addresses);
|
|
276
|
+
let changeAddressValues = Object.values(changeAddresses);
|
|
277
|
+
|
|
278
|
+
const addressIndex = addressIndexes[addressType].index;
|
|
279
|
+
const changeAddressIndex = changeAddressIndexes[addressType].index;
|
|
280
|
+
|
|
281
|
+
// Instead of scanning all addresses, adhere to the gap limit.
|
|
282
|
+
if (
|
|
283
|
+
!scanAllAddresses &&
|
|
284
|
+
addressIndex >= 0 &&
|
|
285
|
+
changeAddressIndex >= 0
|
|
286
|
+
) {
|
|
287
|
+
addressValues = addressValues.filter(
|
|
288
|
+
(a) => Math.abs(addressIndex - a.index) <= GAP_LIMIT
|
|
289
|
+
);
|
|
290
|
+
changeAddressValues = changeAddressValues.filter(
|
|
291
|
+
(a) => Math.abs(changeAddressIndex - a.index) <= GAP_LIMIT
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
scriptHashes = [
|
|
296
|
+
...scriptHashes,
|
|
297
|
+
...addressValues,
|
|
298
|
+
...changeAddressValues
|
|
299
|
+
];
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
// remove items with same path
|
|
303
|
+
scriptHashes = scriptHashes.filter((sh, index, arr) => {
|
|
304
|
+
return index === arr.findIndex((v) => sh.path === v.path);
|
|
305
|
+
});
|
|
306
|
+
if (scriptHashes.length < 1) {
|
|
307
|
+
return err('No scriptHashes available to check.');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const combinedResponse: TTxResponse[] = [];
|
|
311
|
+
|
|
312
|
+
// split payload in chunks of 10 addresses per-request
|
|
313
|
+
for (let i = 0; i < scriptHashes.length; i += CHUNK_LIMIT) {
|
|
314
|
+
const chunk = scriptHashes.slice(i, i + CHUNK_LIMIT);
|
|
315
|
+
const payload = {
|
|
316
|
+
key: 'scriptHash',
|
|
317
|
+
data: chunk
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const response: IGetAddressScriptHashesHistoryResponse =
|
|
321
|
+
await electrum.getAddressScriptHashesHistory({
|
|
322
|
+
scriptHashes: payload,
|
|
323
|
+
network: this.electrumNetwork
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
const mempoolResponse: IGetAddressScriptHashesHistoryResponse =
|
|
327
|
+
await electrum.getAddressScriptHashesMempool({
|
|
328
|
+
scriptHashes: payload,
|
|
329
|
+
network: this.electrumNetwork
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
if (response.error || mempoolResponse.error) {
|
|
333
|
+
return err('Unable to get address history.');
|
|
334
|
+
}
|
|
335
|
+
combinedResponse.push(...response.data, ...mempoolResponse.data);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const history: IGetAddressHistoryResponse[] = [];
|
|
339
|
+
combinedResponse.forEach(
|
|
340
|
+
({ data, result }: { data: IAddress; result: TTxResult[] }): void => {
|
|
341
|
+
if (result && result?.length > 0) {
|
|
342
|
+
result.forEach((item) => {
|
|
343
|
+
history.push({ ...data, ...item });
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
return ok(history);
|
|
349
|
+
} catch (e) {
|
|
350
|
+
return err(e);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Used to retrieve scriptPubkey history for LDK.
|
|
356
|
+
* @param {string} scriptPubkey
|
|
357
|
+
* @returns {Promise<TGetAddressHistory[]>}
|
|
358
|
+
*/
|
|
359
|
+
async getScriptPubKeyHistory(
|
|
360
|
+
scriptPubkey: string
|
|
361
|
+
): Promise<TGetAddressHistory[]> {
|
|
362
|
+
const history: { txid: string; height: number }[] = [];
|
|
363
|
+
const address = getAddressFromScriptPubKey(scriptPubkey, this.network);
|
|
364
|
+
if (!address) {
|
|
365
|
+
return history;
|
|
366
|
+
}
|
|
367
|
+
const scriptHash = getScriptHash({
|
|
368
|
+
network: this.network,
|
|
369
|
+
address
|
|
370
|
+
});
|
|
371
|
+
if (!scriptHash) {
|
|
372
|
+
return history;
|
|
373
|
+
}
|
|
374
|
+
const response = await electrum.getAddressScriptHashesHistory({
|
|
375
|
+
scriptHashes: [scriptHash],
|
|
376
|
+
network: this.electrumNetwork
|
|
377
|
+
});
|
|
378
|
+
if (response.error) {
|
|
379
|
+
return history;
|
|
380
|
+
}
|
|
381
|
+
await Promise.all(
|
|
382
|
+
response.data.map(({ result }): void => {
|
|
383
|
+
if (result && result?.length > 0) {
|
|
384
|
+
result.map((item) => {
|
|
385
|
+
history.push({
|
|
386
|
+
txid: item?.tx_hash ?? '',
|
|
387
|
+
height: item?.height ?? 0
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
})
|
|
392
|
+
);
|
|
393
|
+
return history;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Returns UTXO's for a given wallet and network along with the available balance.
|
|
398
|
+
* @param {boolean} [scanAllAddresses]
|
|
399
|
+
* @returns {Promise<Result<IGetUtxosResponse>>}
|
|
400
|
+
*/
|
|
401
|
+
async getUtxos({
|
|
402
|
+
scanAllAddresses = false
|
|
403
|
+
}: {
|
|
404
|
+
scanAllAddresses?: boolean;
|
|
405
|
+
}): Promise<Result<IGetUtxosResponse>> {
|
|
406
|
+
try {
|
|
407
|
+
if (!this.connectedToElectrum)
|
|
408
|
+
await this.connectToElectrum({
|
|
409
|
+
network: this.network,
|
|
410
|
+
servers: this.servers
|
|
411
|
+
});
|
|
412
|
+
const currentWallet = this._wallet.data;
|
|
413
|
+
|
|
414
|
+
const addressTypeKeys = Object.values(EAddressType);
|
|
415
|
+
let addresses = {} as IAddresses;
|
|
416
|
+
let changeAddresses = {} as IAddresses;
|
|
417
|
+
const existingUtxos: { [key: string]: IUtxo } = {};
|
|
418
|
+
|
|
419
|
+
for (const addressType of addressTypeKeys) {
|
|
420
|
+
const addressCount = Object.keys(currentWallet.addresses[addressType])
|
|
421
|
+
?.length;
|
|
422
|
+
|
|
423
|
+
// Check if addresses of this type have been generated. If not, skip.
|
|
424
|
+
if (addressCount <= 0) {
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Grab the current index for both addresses and change addresses.
|
|
429
|
+
const addressIndex = currentWallet.addressIndex[addressType].index;
|
|
430
|
+
const changeAddressIndex =
|
|
431
|
+
currentWallet.changeAddressIndex[addressType].index;
|
|
432
|
+
|
|
433
|
+
// Grab all addresses and change addresses.
|
|
434
|
+
const allAddresses = currentWallet.addresses[addressType];
|
|
435
|
+
const allChangeAddresses = currentWallet.changeAddresses[addressType];
|
|
436
|
+
|
|
437
|
+
// Instead of scanning all addresses, adhere to the gap limit.
|
|
438
|
+
if (!scanAllAddresses && addressIndex >= 0 && changeAddressIndex >= 0) {
|
|
439
|
+
Object.values(allAddresses).map((a) => {
|
|
440
|
+
if (Math.abs(a.index - addressIndex) <= GAP_LIMIT) {
|
|
441
|
+
addresses[a.scriptHash] = a;
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
Object.values(allChangeAddresses).map((a) => {
|
|
445
|
+
if (Math.abs(a.index - changeAddressIndex) <= GAP_LIMIT) {
|
|
446
|
+
changeAddresses[a.scriptHash] = a;
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
} else {
|
|
450
|
+
addresses = { ...addresses, ...allAddresses };
|
|
451
|
+
changeAddresses = { ...changeAddresses, ...allChangeAddresses };
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Make sure we're re-check existing utxos that may exist outside the gap limit and putting them in the necessary format.
|
|
456
|
+
currentWallet.utxos.map((utxo) => {
|
|
457
|
+
existingUtxos[utxo.scriptHash] = utxo;
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
const data: TUnspentAddressScriptHashData = {
|
|
461
|
+
...addresses,
|
|
462
|
+
...changeAddresses,
|
|
463
|
+
...existingUtxos
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
return this.listUnspentAddressScriptHashes({ addresses: data });
|
|
467
|
+
} catch (e) {
|
|
468
|
+
return err(e);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Returns available transactions from electrum based on the provided txHashes.
|
|
474
|
+
* @param {ITxHash[]} txHashes
|
|
475
|
+
* @return {Promise<Result<IGetTransactions>>}
|
|
476
|
+
*/
|
|
477
|
+
async getTransactions({
|
|
478
|
+
txHashes = []
|
|
479
|
+
}: {
|
|
480
|
+
txHashes: ITxHash[];
|
|
481
|
+
}): Promise<Result<IGetTransactions>> {
|
|
482
|
+
try {
|
|
483
|
+
if (txHashes.length < 1) {
|
|
484
|
+
return ok({
|
|
485
|
+
error: false,
|
|
486
|
+
id: 0,
|
|
487
|
+
method: 'getTransactions',
|
|
488
|
+
network: this.electrumNetwork,
|
|
489
|
+
data: []
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const result: ITransaction<IUtxo>[] = [];
|
|
494
|
+
|
|
495
|
+
// split payload in chunks of 10 transactions per-request
|
|
496
|
+
for (let i = 0; i < txHashes.length; i += CHUNK_LIMIT) {
|
|
497
|
+
const chunk = txHashes.slice(i, i + CHUNK_LIMIT);
|
|
498
|
+
|
|
499
|
+
const data = {
|
|
500
|
+
key: 'tx_hash',
|
|
501
|
+
data: chunk
|
|
502
|
+
};
|
|
503
|
+
const response = await electrum.getTransactions({
|
|
504
|
+
txHashes: data,
|
|
505
|
+
network: this.electrumNetwork
|
|
506
|
+
});
|
|
507
|
+
if (response.error) {
|
|
508
|
+
return err(response);
|
|
509
|
+
}
|
|
510
|
+
result.push(...response.data);
|
|
511
|
+
}
|
|
512
|
+
return ok({
|
|
513
|
+
error: false,
|
|
514
|
+
id: 0,
|
|
515
|
+
method: 'getTransactions',
|
|
516
|
+
network: this.electrumNetwork,
|
|
517
|
+
data: result
|
|
518
|
+
});
|
|
519
|
+
} catch (e) {
|
|
520
|
+
return err(e);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Determines whether a transaction exists based on the transaction response from electrum.
|
|
526
|
+
* @param {ITransaction<IUtxo>} txData
|
|
527
|
+
* @returns {boolean}
|
|
528
|
+
*/
|
|
529
|
+
public transactionExists(txData: ITransaction<IUtxo>): boolean {
|
|
530
|
+
if (
|
|
531
|
+
// @ts-ignore
|
|
532
|
+
txData?.error &&
|
|
533
|
+
// @ts-ignore
|
|
534
|
+
txData?.error?.message &&
|
|
535
|
+
/No such mempool or blockchain transaction|Invalid tx hash/.test(
|
|
536
|
+
// @ts-ignore
|
|
537
|
+
txData?.error?.message
|
|
538
|
+
)
|
|
539
|
+
) {
|
|
540
|
+
//Transaction was removed/bumped from the mempool or potentially reorg'd out.
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
return true;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Returns the block hex of the provided block height.
|
|
548
|
+
* @param {number} [height]
|
|
549
|
+
* @param {TAvailableNetworks} [selectedNetwork]
|
|
550
|
+
* @returns {Promise<Result<string>>}
|
|
551
|
+
*/
|
|
552
|
+
public async getBlockHex({
|
|
553
|
+
height = 0
|
|
554
|
+
}: {
|
|
555
|
+
height?: number;
|
|
556
|
+
}): Promise<Result<string>> {
|
|
557
|
+
const response: IGetHeaderResponse = await electrum.getHeader({
|
|
558
|
+
height,
|
|
559
|
+
network: this.electrumNetwork
|
|
560
|
+
});
|
|
561
|
+
if (response.error) {
|
|
562
|
+
return err(response.data);
|
|
563
|
+
}
|
|
564
|
+
return ok(response.data);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Returns the block hash given a block hex.
|
|
569
|
+
* Leaving blockHex empty will return the last known block hash from storage.
|
|
570
|
+
* @param {string} [blockHex]
|
|
571
|
+
* @param {TAvailableNetworks} [selectedNetwork]
|
|
572
|
+
* @returns {string}
|
|
573
|
+
*/
|
|
574
|
+
public getBlockHashFromHex({ blockHex }: { blockHex?: string }): string {
|
|
575
|
+
// If empty, return the last known block hex from storage.
|
|
576
|
+
if (!blockHex) {
|
|
577
|
+
const { hex } = this.getBlockHeader();
|
|
578
|
+
blockHex = hex;
|
|
579
|
+
}
|
|
580
|
+
if (!blockHex) return '';
|
|
581
|
+
const block = Block.fromHex(blockHex);
|
|
582
|
+
const hash = block.getId();
|
|
583
|
+
return hash;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Returns last known block height, and it's corresponding hex from local storage.
|
|
588
|
+
* @returns {IHeader}
|
|
589
|
+
*/
|
|
590
|
+
public getBlockHeader(): IHeader {
|
|
591
|
+
return this.wallet.data.header;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Returns transactions associated with the provided transaction hashes.
|
|
596
|
+
* @param {ITxHash[]} txHashes
|
|
597
|
+
* @return {Promise<Result<IGetTransactionsFromInputs>>}
|
|
598
|
+
*/
|
|
599
|
+
async getTransactionsFromInputs({
|
|
600
|
+
txHashes = []
|
|
601
|
+
}: {
|
|
602
|
+
txHashes: ITxHash[];
|
|
603
|
+
}): Promise<Result<IGetTransactionsFromInputs>> {
|
|
604
|
+
try {
|
|
605
|
+
const data = {
|
|
606
|
+
key: 'tx_hash',
|
|
607
|
+
data: txHashes
|
|
608
|
+
};
|
|
609
|
+
const response = await electrum.getTransactions({
|
|
610
|
+
txHashes: data,
|
|
611
|
+
network: this.electrumNetwork
|
|
612
|
+
});
|
|
613
|
+
if (!response.error) {
|
|
614
|
+
return ok(response);
|
|
615
|
+
} else {
|
|
616
|
+
return err(response);
|
|
617
|
+
}
|
|
618
|
+
} catch (e) {
|
|
619
|
+
return err(e);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Returns the merkle branch to a confirmed transaction given its hash and height.
|
|
625
|
+
* @param {string} tx_hash
|
|
626
|
+
* @param {number} height
|
|
627
|
+
* @returns {Promise<{ merkle: string[]; block_height: number; pos: number }>}
|
|
628
|
+
*/
|
|
629
|
+
async getTransactionMerkle({
|
|
630
|
+
tx_hash,
|
|
631
|
+
height
|
|
632
|
+
}: {
|
|
633
|
+
tx_hash: string;
|
|
634
|
+
height: number;
|
|
635
|
+
}): Promise<{
|
|
636
|
+
merkle: string[];
|
|
637
|
+
block_height: number;
|
|
638
|
+
pos: number;
|
|
639
|
+
}> {
|
|
640
|
+
return await electrum.getTransactionMerkle({
|
|
641
|
+
tx_hash,
|
|
642
|
+
height,
|
|
643
|
+
network: this.electrumNetwork
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Subscribes to the current networks headers.
|
|
649
|
+
* @return {Promise<Result<string>>}
|
|
650
|
+
*/
|
|
651
|
+
public async subscribeToHeader(): Promise<Result<IHeader>> {
|
|
652
|
+
const subscribeResponse: ISubscribeToHeader =
|
|
653
|
+
await electrum.subscribeHeader({
|
|
654
|
+
network: this.electrumNetwork,
|
|
655
|
+
onReceive: (data: INewBlock[]) => {
|
|
656
|
+
const hex = data[0].hex;
|
|
657
|
+
const hash = this.getBlockHashFromHex({ blockHex: hex });
|
|
658
|
+
const header: IHeader = { ...data[0], hash };
|
|
659
|
+
this._wallet.updateHeader(header);
|
|
660
|
+
this.onReceive?.(data);
|
|
661
|
+
this.onMessage(onMessageKeys.newBlock, data[0]);
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
if (subscribeResponse.error) {
|
|
665
|
+
return err('Unable to subscribe to headers.');
|
|
666
|
+
}
|
|
667
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
668
|
+
// @ts-ignore
|
|
669
|
+
if (subscribeResponse?.data === 'Already Subscribed.') {
|
|
670
|
+
return ok(this.getBlockHeader());
|
|
671
|
+
}
|
|
672
|
+
// Update local storage with current height and hex.
|
|
673
|
+
const hex = subscribeResponse.data.hex;
|
|
674
|
+
const hash = this.getBlockHashFromHex({ blockHex: hex });
|
|
675
|
+
const header = { ...subscribeResponse.data, hash };
|
|
676
|
+
await this._wallet.updateHeader(header);
|
|
677
|
+
return ok(header);
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Subscribes to a number of address script hashes for receiving.
|
|
682
|
+
* @param {string[]} scriptHashes
|
|
683
|
+
* @param onReceive
|
|
684
|
+
* @return {Promise<Result<string>>}
|
|
685
|
+
*/
|
|
686
|
+
async subscribeToAddresses({
|
|
687
|
+
scriptHashes = [],
|
|
688
|
+
onReceive
|
|
689
|
+
}: {
|
|
690
|
+
scriptHashes?: string[];
|
|
691
|
+
onReceive?: (data: TSubscribedReceive) => void;
|
|
692
|
+
} = {}): Promise<Result<string>> {
|
|
693
|
+
const currentWallet = this._wallet.data;
|
|
694
|
+
const addressTypeKeys = objectKeys(addressTypes);
|
|
695
|
+
// Gather the receiving address scripthash for each address type if no scripthashes were provided.
|
|
696
|
+
if (!scriptHashes.length) {
|
|
697
|
+
for (const addressType of addressTypeKeys) {
|
|
698
|
+
const addresses = currentWallet.addresses[addressType];
|
|
699
|
+
const addressCount = Object.keys(addresses).length;
|
|
700
|
+
|
|
701
|
+
// Check if addresses of this type have been generated. If not, skip.
|
|
702
|
+
if (addressCount > 0) {
|
|
703
|
+
let addressIndex = currentWallet.addressIndex[addressType]?.index;
|
|
704
|
+
addressIndex = addressIndex > 0 ? addressIndex : 0;
|
|
705
|
+
|
|
706
|
+
// Only subscribe up to the gap limit.
|
|
707
|
+
const addressesInRange = Object.values(addresses).filter(
|
|
708
|
+
(address) => Math.abs(address.index - addressIndex) <= GAP_LIMIT
|
|
709
|
+
);
|
|
710
|
+
const addressesToSubscribe = addressesInRange.slice(-GAP_LIMIT);
|
|
711
|
+
const addressScriptHashes = addressesToSubscribe.map(
|
|
712
|
+
({ scriptHash }) => scriptHash
|
|
713
|
+
);
|
|
714
|
+
scriptHashes.push(...addressScriptHashes);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Subscribe to all provided script hashes.
|
|
720
|
+
const promises = scriptHashes.map(async (scriptHash) => {
|
|
721
|
+
const response: ISubscribeToAddress = await electrum.subscribeAddress({
|
|
722
|
+
scriptHash,
|
|
723
|
+
network: this.electrumNetwork,
|
|
724
|
+
onReceive: async (data: TSubscribedReceive): Promise<void> => {
|
|
725
|
+
onReceive?.(data);
|
|
726
|
+
this._wallet.refreshWallet({});
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
if (response.error) {
|
|
730
|
+
throw Error('Unable to subscribe to receiving addresses.');
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
try {
|
|
735
|
+
await Promise.all(promises);
|
|
736
|
+
} catch (e) {
|
|
737
|
+
return err(e);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
return ok('Successfully subscribed to addresses.');
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
public async broadcastTransaction({
|
|
744
|
+
rawTx,
|
|
745
|
+
subscribeToOutputAddress = true
|
|
746
|
+
}: {
|
|
747
|
+
rawTx: string;
|
|
748
|
+
subscribeToOutputAddress?: boolean;
|
|
749
|
+
}): Promise<Result<string>> {
|
|
750
|
+
/**
|
|
751
|
+
* Subscribe to the output address and refresh the wallet when the Electrum server detects it.
|
|
752
|
+
* This prevents updating the wallet prior to the Electrum server detecting the new tx in the mempool.
|
|
753
|
+
*/
|
|
754
|
+
if (subscribeToOutputAddress) {
|
|
755
|
+
const transaction = this._wallet.transaction.data;
|
|
756
|
+
for (const o of transaction.outputs) {
|
|
757
|
+
const address = o?.address;
|
|
758
|
+
if (address) {
|
|
759
|
+
const scriptHash = getScriptHash({ address, network: this.network });
|
|
760
|
+
if (scriptHash) {
|
|
761
|
+
await this.subscribeToAddresses({
|
|
762
|
+
scriptHashes: [scriptHash]
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
const broadcastResponse = await electrum.broadcastTransaction({
|
|
770
|
+
rawTx,
|
|
771
|
+
network: this.electrumNetwork
|
|
772
|
+
});
|
|
773
|
+
// TODO: This needs to be resolved in rn-electrum-client
|
|
774
|
+
if (broadcastResponse.error || broadcastResponse.data.includes(' ')) {
|
|
775
|
+
return err(broadcastResponse.data);
|
|
776
|
+
}
|
|
777
|
+
return ok(broadcastResponse.data);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* Attempts to check the current Electrum connection.
|
|
782
|
+
* @private
|
|
783
|
+
* @returns {Promise<void>}
|
|
784
|
+
*/
|
|
785
|
+
private async checkConnection(): Promise<void> {
|
|
786
|
+
try {
|
|
787
|
+
const { error } = await electrum.pingServer();
|
|
788
|
+
|
|
789
|
+
if (error) {
|
|
790
|
+
console.log('Connection to Electrum Server lost, reconnecting...');
|
|
791
|
+
const response = await this.connectToElectrum({
|
|
792
|
+
network: this.network,
|
|
793
|
+
servers: this.servers
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
if (response.isErr()) {
|
|
797
|
+
this.publishConnectionChange(false);
|
|
798
|
+
}
|
|
799
|
+
} else {
|
|
800
|
+
this.publishConnectionChange(true);
|
|
801
|
+
}
|
|
802
|
+
} catch (e) {
|
|
803
|
+
console.error(e);
|
|
804
|
+
this.publishConnectionChange(false);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
private publishConnectionChange(isConnected: boolean): void {
|
|
809
|
+
if (
|
|
810
|
+
this.latestConnectionState !== isConnected &&
|
|
811
|
+
!this.wallet.isSwitchingNetworks
|
|
812
|
+
) {
|
|
813
|
+
this.onMessage('connectedToElectrum', isConnected);
|
|
814
|
+
this.connectedToElectrum = isConnected;
|
|
815
|
+
this.latestConnectionState = isConnected;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
public async disconnect(): Promise<void> {
|
|
820
|
+
this.stopConnectionPolling();
|
|
821
|
+
await electrum.stop();
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
public startConnectionPolling(): void {
|
|
825
|
+
if (this.connectionPollingInterval) return;
|
|
826
|
+
this.connectionPollingInterval = setInterval(
|
|
827
|
+
(): Promise<void> => this.checkConnection(),
|
|
828
|
+
POLLING_INTERVAL
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
public stopConnectionPolling(): void {
|
|
833
|
+
if (this.connectionPollingInterval) {
|
|
834
|
+
clearInterval(this.connectionPollingInterval);
|
|
835
|
+
this.connectionPollingInterval = null;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|