feat: refactor BlueElectrum to Typescript

This commit is contained in:
Ivan Vershigora 2024-03-25 00:07:43 +03:00
parent 986167329c
commit 17477f91f5
No known key found for this signature in database
GPG key ID: DCCF7FB5ED2CEBD7
24 changed files with 398 additions and 435 deletions

View file

@ -6,7 +6,7 @@ import * as Keychain from 'react-native-keychain';
import RNSecureKeyStore, { ACCESSIBLE } from 'react-native-secure-key-store';
import Realm from 'realm';
import BlueElectrum from './blue_modules/BlueElectrum';
import * as BlueElectrum from './blue_modules/BlueElectrum';
import { initCurrencyDaemon } from './blue_modules/currency';
import * as encryption from './blue_modules/encryption';
import {

View file

@ -1,98 +0,0 @@
type Utxo = {
height: number;
value: number;
address: string;
txid: string;
vout: number;
wif?: string;
};
export type ElectrumTransaction = {
txid: string;
hash: string;
version: number;
size: number;
vsize: number;
weight: number;
locktime: number;
vin: {
txid: string;
vout: number;
scriptSig: { asm: string; hex: string };
txinwitness: string[];
sequence: number;
addresses?: string[];
value?: number;
}[];
vout: {
value: number;
n: number;
scriptPubKey: {
asm: string;
hex: string;
reqSigs: number;
type: string;
addresses: string[];
};
}[];
blockhash: string;
confirmations?: number;
time: number;
blocktime: number;
};
type MempoolTransaction = {
height: 0;
tx_hash: string;
fee: number;
};
export async function connectMain(): Promise<void>;
export async function waitTillConnected(): Promise<boolean>;
export function forceDisconnect(): void;
export function getBalanceByAddress(address: string): Promise<{ confirmed: number; unconfirmed: number }>;
export function multiGetUtxoByAddress(addresses: string[]): Promise<Record<string, Utxo[]>>;
// TODO: this function returns different results based on the value of `verbose`, consider splitting it into two
export function multiGetTransactionByTxid(
txids: string[],
batchsize: number = 45,
verbose: true = true,
): Promise<Record<string, ElectrumTransaction>>;
export function multiGetTransactionByTxid(txids: string[], batchsize: number, verbose: false): Promise<Record<string, string>>;
export type MultiGetBalanceResponse = {
balance: number;
unconfirmed_balance: number;
addresses: Record<string, { confirmed: number; unconfirmed: number }>;
};
export function multiGetBalanceByAddress(addresses: string[], batchsize?: number): Promise<MultiGetBalanceResponse>;
export function getTransactionsByAddress(address: string): ElectrumTransaction[];
export function getMempoolTransactionsByAddress(address: string): Promise<MempoolTransaction[]>;
export function estimateCurrentBlockheight(): number;
export type ElectrumHistory = {
tx_hash: string;
height: number;
address: string;
};
export function multiGetHistoryByAddress(addresses: string[]): Promise<Record<string, ElectrumHistory[]>>;
export function estimateFees(): Promise<{ fast: number; medium: number; slow: number }>;
export function broadcastV2(txhex: string): Promise<string>;
export function getTransactionsFullByAddress(address: string): Promise<ElectrumTransaction[]>;
export function txhexToElectrumTransaction(txhes: string): ElectrumTransaction;
export function isDisabled(): Promise<boolean>;

File diff suppressed because it is too large Load diff

View file

@ -1,8 +0,0 @@
function WidgetCommunication(props) {
WidgetCommunication.isBalanceDisplayAllowed = () => {};
WidgetCommunication.setBalanceDisplayAllowed = () => {};
WidgetCommunication.reloadAllTimelines = () => {};
return null;
}
export default WidgetCommunication;

View file

@ -0,0 +1,9 @@
function WidgetCommunication() {
return null;
}
WidgetCommunication.isBalanceDisplayAllowed = () => {};
WidgetCommunication.setBalanceDisplayAllowed = () => {};
WidgetCommunication.reloadAllTimelines = () => {};
export default WidgetCommunication;

View file

@ -8,12 +8,11 @@ import type { TWallet } from '../class/wallets/types';
import presentAlert from '../components/Alert';
import loc, { STORAGE_KEY as LOC_STORAGE_KEY } from '../loc';
import { FiatUnit, TFiatUnit } from '../models/fiatUnit';
import * as BlueElectrum from './BlueElectrum';
import { PREFERRED_CURRENCY_STORAGE_KEY } from './currency';
import triggerHapticFeedback, { HapticFeedbackTypes } from './hapticFeedback';
import A from '../blue_modules/analytics';
const BlueElectrum = require('./BlueElectrum');
// hashmap of timestamps we _started_ refetching some wallet
const _lastTimeTriedToRefetchWallet: { [walletID: string]: number } = {};

View file

@ -1,7 +1,7 @@
import { HDSegwitBech32Wallet } from './wallets/hd-segwit-bech32-wallet';
import { SegwitBech32Wallet } from './wallets/segwit-bech32-wallet';
import * as BlueElectrum from '../blue_modules/BlueElectrum';
const bitcoin = require('bitcoinjs-lib');
const BlueElectrum = require('../blue_modules/BlueElectrum');
const BigNumber = require('bignumber.js');
/**
@ -39,7 +39,7 @@ export class HDSegwitBech32Transaction {
* @private
*/
async _fetchTxhexAndDecode() {
const hexes = await BlueElectrum.multiGetTransactionByTxid([this._txid], 10, false);
const hexes = await BlueElectrum.multiGetTransactionByTxid([this._txid], false, 10);
this._txhex = hexes[this._txid];
if (!this._txhex) throw new Error("Transaction can't be found in mempool");
this._txDecoded = bitcoin.Transaction.fromHex(this._txhex);
@ -80,7 +80,7 @@ export class HDSegwitBech32Transaction {
* @private
*/
async _fetchRemoteTx() {
const result = await BlueElectrum.multiGetTransactionByTxid([this._txid || this._txDecoded.getId()]);
const result = await BlueElectrum.multiGetTransactionByTxid([this._txid || this._txDecoded.getId()], true);
this._remoteTx = Object.values(result)[0];
}
@ -154,7 +154,7 @@ export class HDSegwitBech32Transaction {
prevInputs.push(reversedHash);
}
const prevTransactions = await BlueElectrum.multiGetTransactionByTxid(prevInputs);
const prevTransactions = await BlueElectrum.multiGetTransactionByTxid(prevInputs, true);
// fetched, now lets count how much satoshis went in
let wentIn = 0;

View file

@ -10,7 +10,7 @@ import { CoinSelectReturnInput, CoinSelectTarget } from 'coinselect';
import { ECPairFactory } from 'ecpair';
import { ECPairInterface } from 'ecpair/src/ecpair';
import type BlueElectrumNs from '../../blue_modules/BlueElectrum';
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
import { ElectrumHistory } from '../../blue_modules/BlueElectrum';
import ecc from '../../blue_modules/noble_ecc';
import { randomBytes } from '../rng';
@ -18,7 +18,6 @@ import { AbstractHDWallet } from './abstract-hd-wallet';
import { CreateTransactionResult, CreateTransactionUtxo, Transaction, Utxo } from './types';
const ECPair = ECPairFactory(ecc);
const BlueElectrum: typeof BlueElectrumNs = require('../../blue_modules/BlueElectrum');
const bip32 = BIP32Factory(ecc);
const bip47 = BIP47Factory(ecc);
@ -319,7 +318,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
}
// next, batch fetching each txid we got
const txdatas = await BlueElectrum.multiGetTransactionByTxid(Object.keys(txs));
const txdatas = await BlueElectrum.multiGetTransactionByTxid(Object.keys(txs), true);
// now, tricky part. we collect all transactions from inputs (vin), and batch fetch them too.
// then we combine all this data (we need inputs to see source addresses and amounts)
@ -330,7 +329,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
// ^^^^ not all inputs have txid, some of them are Coinbase (newly-created coins)
}
}
const vintxdatas = await BlueElectrum.multiGetTransactionByTxid(vinTxids);
const vintxdatas = await BlueElectrum.multiGetTransactionByTxid(vinTxids, true);
// fetched all transactions from our inputs. now we need to combine it.
// iterating all _our_ transactions:
@ -1505,7 +1504,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
const histories = await BlueElectrum.multiGetHistoryByAddress([address]);
const txHashes = histories[address].map(({ tx_hash }) => tx_hash);
const txHexs = await BlueElectrum.multiGetTransactionByTxid(txHashes, 50, false);
const txHexs = await BlueElectrum.multiGetTransactionByTxid(txHashes, false);
for (const txHex of Object.values(txHexs)) {
try {
const paymentCode = bip47_instance.getPaymentCodeFromRawNotificationTransaction(txHex);

View file

@ -1,8 +1,8 @@
import { LegacyWallet } from './legacy-wallet';
import * as bip39 from 'bip39';
import { BIP32Interface } from 'bip32';
import * as bip39 from 'bip39';
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
import * as bip39custom from '../../blue_modules/bip39';
import BlueElectrum from '../../blue_modules/BlueElectrum';
import { LegacyWallet } from './legacy-wallet';
import { Transaction } from './types';
type AbstractHDWalletStatics = {

View file

@ -2,7 +2,8 @@ import BIP32Factory, { BIP32Interface } from 'bip32';
import * as bitcoinjs from 'bitcoinjs-lib';
import { Psbt } from 'bitcoinjs-lib';
import { CoinSelectReturnInput } from 'coinselect';
import BlueElectrum, { ElectrumHistory } from '../../blue_modules/BlueElectrum';
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
import { ElectrumHistory } from '../../blue_modules/BlueElectrum';
import ecc from '../../blue_modules/noble_ecc';
import { AbstractHDElectrumWallet } from './abstract-hd-electrum-wallet';
import { HDLegacyP2PKHWallet } from './hd-legacy-p2pkh-wallet';

View file

@ -1,10 +1,11 @@
import BIP32Factory, { BIP32Interface } from 'bip32';
import { Psbt } from 'bitcoinjs-lib';
import { CoinSelectReturnInput } from 'coinselect';
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
import ecc from '../../blue_modules/noble_ecc';
import { AbstractHDElectrumWallet } from './abstract-hd-electrum-wallet';
const bip32 = BIP32Factory(ecc);
const BlueElectrum = require('../../blue_modules/BlueElectrum');
/**
* HD Wallet (BIP39).
@ -70,7 +71,6 @@ export class HDLegacyP2PKHWallet extends AbstractHDElectrumWallet {
// now we need to fetch txhash for each input as required by PSBT
const txhexes = await BlueElectrum.multiGetTransactionByTxid(
this.getUtxo().map(x => x.txid),
50,
false,
);

View file

@ -140,7 +140,6 @@ export class LegacyWallet extends AbstractWallet {
if (LegacyWallet.type !== this.type) return; // but only for LEGACY single-address wallets
const txhexes = await BlueElectrum.multiGetTransactionByTxid(
this._utxo.map(u => u.txid),
50,
false,
);
@ -275,7 +274,7 @@ export class LegacyWallet extends AbstractWallet {
// is safe because in that case our cache is filled
// next, batch fetching each txid we got
const txdatas = await BlueElectrum.multiGetTransactionByTxid(Object.keys(txs));
const txdatas = await BlueElectrum.multiGetTransactionByTxid(Object.keys(txs), true);
const transactions = Object.values(txdatas);
// now, tricky part. we collect all transactions from inputs (vin), and batch fetch them too.
@ -287,7 +286,7 @@ export class LegacyWallet extends AbstractWallet {
// ^^^^ not all inputs have txid, some of them are Coinbase (newly-created coins)
}
}
const vintxdatas = await BlueElectrum.multiGetTransactionByTxid(vinTxids);
const vintxdatas = await BlueElectrum.multiGetTransactionByTxid(vinTxids, true);
// fetched all transactions from our inputs. now we need to combine it.
// iterating all _our_ transactions:

View file

@ -3,17 +3,17 @@ import * as bip39 from 'bip39';
import * as bitcoin from 'bitcoinjs-lib';
import { Psbt, Transaction } from 'bitcoinjs-lib';
import b58 from 'bs58check';
import { CoinSelectReturnInput, CoinSelectTarget } from 'coinselect';
import createHash from 'create-hash';
import { ECPairFactory } from 'ecpair';
import * as mn from 'electrum-mnemonic';
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
import ecc from '../../blue_modules/noble_ecc';
import { decodeUR } from '../../blue_modules/ur';
import { AbstractHDElectrumWallet } from './abstract-hd-electrum-wallet';
import { CoinSelectReturnInput, CoinSelectTarget } from 'coinselect';
import { CreateTransactionResult, CreateTransactionUtxo } from './types';
const ECPair = ECPairFactory(ecc);
const BlueElectrum = require('../../blue_modules/BlueElectrum');
const bip32 = BIP32Factory(ecc);
type SeedOpts = {
@ -1072,7 +1072,6 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet {
// now we need to fetch txhash for each input as required by PSBT
const txhexes = await BlueElectrum.multiGetTransactionByTxid(
this.getUtxo(true).map(x => x.txid),
50,
false,
);

View file

@ -1,4 +1,4 @@
const BlueElectrum = require('../blue_modules/BlueElectrum');
import * as BlueElectrum from '../blue_modules/BlueElectrum';
export const NetworkTransactionFeeType = Object.freeze({
FAST: 'Fast',

View file

@ -117,7 +117,7 @@ const ReceiveDetails = () => {
const txs = await BlueElectrum.getMempoolTransactionsByAddress(addressToUse);
const tx = txs.pop();
if (tx) {
const rez = await BlueElectrum.multiGetTransactionByTxid([tx.tx_hash], 10, true);
const rez = await BlueElectrum.multiGetTransactionByTxid([tx.tx_hash], true, 10);
if (rez && rez[tx.tx_hash] && rez[tx.tx_hash].vsize) {
const satPerVbyte = Math.round(tx.fee / rez[tx.tx_hash].vsize);
const fees = await BlueElectrum.estimateFees();

View file

@ -24,9 +24,10 @@ import presentAlert from '../components/Alert';
import * as encryption from '../blue_modules/encryption';
import * as fs from '../blue_modules/fs';
import SaveFileButton from '../components/SaveFileButton';
import * as BlueElectrum from '../blue_modules/BlueElectrum';
const BlueCrypto = require('react-native-blue-crypto');
const BlueElectrum = require('../blue_modules/BlueElectrum');
const bip32 = BIP32Factory(ecc);
const styles = StyleSheet.create({

View file

@ -16,7 +16,7 @@ import {
BlueSpacing20,
BlueTextCentered,
} from '../../BlueComponents';
import BlueElectrum from '../../blue_modules/BlueElectrum';
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
import Notifications from '../../blue_modules/notifications';
import { useTheme } from '../../components/themes';
import Button from '../../components/Button';

View file

@ -18,7 +18,7 @@ import Button from '../../components/Button';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import SafeArea from '../../components/SafeArea';
import { satoshiToBTC, satoshiToLocalCurrency } from '../../blue_modules/currency';
const BlueElectrum = require('../../blue_modules/BlueElectrum');
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
const Bignumber = require('bignumber.js');
const bitcoin = require('bitcoinjs-lib');

View file

@ -5,6 +5,7 @@ import React, { useContext, useEffect, useRef, useState } from 'react';
import { ActivityIndicator, Linking, Platform, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
import DocumentPicker from 'react-native-document-picker';
import RNFS from 'react-native-fs';
import { BlueCard, BlueSpacing20, BlueText } from '../../BlueComponents';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import Notifications from '../../blue_modules/notifications';
@ -20,8 +21,7 @@ import { useTheme } from '../../components/themes';
import { requestCameraAuthorization } from '../../helpers/scan-qr';
import loc from '../../loc';
import SaveFileButton from '../../components/SaveFileButton';
const BlueElectrum = require('../../blue_modules/BlueElectrum');
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
const PsbtWithHardwareWallet = () => {
const { txMetadata, fetchAndSaveWalletTransactions, isElectrumDisabled } = useContext(BlueStorageContext);

View file

@ -36,8 +36,7 @@ import { requestCameraAuthorization } from '../../helpers/scan-qr';
import Button from '../../components/Button';
import ListItem from '../../components/ListItem';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
const BlueElectrum = require('../../blue_modules/BlueElectrum');
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
export default class ElectrumSettings extends Component {
static contextType = BlueStorageContext;

View file

@ -25,7 +25,7 @@ import presentAlert from '../../components/Alert';
import Button from '../../components/Button';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import SafeArea from '../../components/SafeArea';
const BlueElectrum = require('../../blue_modules/BlueElectrum');
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
const styles = StyleSheet.create({
root: {

View file

@ -114,7 +114,7 @@ const TransactionsStatus = () => {
setIntervalMs(31000); // upon first execution we increase poll interval;
console.log('checking tx', hash, 'for confirmations...');
const transactions = await BlueElectrum.multiGetTransactionByTxid([hash], 10, true);
const transactions = await BlueElectrum.multiGetTransactionByTxid([hash], true, 10);
const txFromElectrum = transactions[hash];
console.log('got txFromElectrum=', txFromElectrum);

View file

@ -8,6 +8,7 @@ import {
FlatList,
I18nManager,
InteractionManager,
LayoutAnimation,
PixelRatio,
ScrollView,
StyleSheet,
@ -15,16 +16,17 @@ import {
TouchableOpacity,
View,
findNodeHandle,
LayoutAnimation,
} from 'react-native';
import { Icon } from 'react-native-elements';
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
import BlueClipboard from '../../blue_modules/clipboard';
import { isDesktop } from '../../blue_modules/environment';
import * as fs from '../../blue_modules/fs';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { BlueStorageContext, WalletTransactionsStatus } from '../../blue_modules/storage-context';
import { LightningCustodianWallet, LightningLdkWallet, MultisigHDWallet, WatchOnlyWallet } from '../../class';
import Biometric from '../../class/biometrics';
import WalletGradient from '../../class/wallet-gradient';
import presentAlert from '../../components/Alert';
import { FButton, FContainer } from '../../components/FloatButtons';
@ -39,9 +41,6 @@ import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import loc from '../../loc';
import { Chain } from '../../models/bitcoinUnits';
import ActionSheet from '../ActionSheet';
import Biometric from '../../class/biometrics';
const BlueElectrum = require('../../blue_modules/BlueElectrum');
const buttonFontSize =
PixelRatio.roundToNearestPixel(Dimensions.get('window').width / 26) > 22

File diff suppressed because one or more lines are too long