REF: upgrade eslint, prettier, fix errors, reformat everything

This commit is contained in:
Ivan Vershigora 2020-06-01 15:54:23 +03:00 committed by Overtorment
parent 97a19126bf
commit 71c8b74e92
107 changed files with 1854 additions and 2557 deletions

View file

@ -1,18 +1,27 @@
{ {
"parser": "babel-eslint", "parser": "babel-eslint",
"plugins": [ "plugins": [
"react", "prettier", "react-hooks" "react-native", // for no-inline-styles rule
],
"extends": [
"standard",
"standard-react",
"plugin:react-hooks/recommended",
// "@react-native-community",
"plugin:prettier/recommended",
"prettier/react",
"prettier/standard",
], ],
"extends": ["standard", "standard-react", "prettier"],
"rules": { "rules": {
"react-hooks/rules-of-hooks": "error", "react/jsx-handler-names": "off", // activated by standard-react config
"react-hooks/exhaustive-deps": "error", "react-native/no-inline-styles": "error",
'prettier/prettier': [ "prettier/prettier": [
'warn', "warn",
{ {
singleQuote: true, "singleQuote": true,
printWidth: 140, "printWidth": 140,
trailingComma: 'all' "trailingComma": "all",
"arrowParens": "avoid"
} }
] ]
}, },

View file

@ -3,11 +3,11 @@
*/ */
import { AppStorage } from './class'; import { AppStorage } from './class';
import DeviceQuickActions from './class/quick-actions'; import DeviceQuickActions from './class/quick-actions';
let prompt = require('./prompt'); const prompt = require('./prompt');
let EV = require('./events'); const EV = require('./events');
let currency = require('./currency'); const currency = require('./currency');
let loc = require('./loc'); const loc = require('./loc');
let BlueElectrum = require('./BlueElectrum'); // eslint-disable-line const BlueElectrum = require('./BlueElectrum'); // eslint-disable-line no-unused-vars
/** @type {AppStorage} */ /** @type {AppStorage} */
const BlueApp = new AppStorage(); const BlueApp = new AppStorage();
@ -25,7 +25,7 @@ async function startAndDecrypt(retry) {
password = await prompt((retry && loc._.bad_password) || loc._.enter_password, loc._.storage_is_encrypted, false); password = await prompt((retry && loc._.bad_password) || loc._.enter_password, loc._.storage_is_encrypted, false);
} while (!password); } while (!password);
} }
let success = await BlueApp.loadFromDisk(password); const success = await BlueApp.loadFromDisk(password);
if (success) { if (success) {
console.log('loaded from disk'); console.log('loaded from disk');
EV(EV.enum.WALLETS_COUNT_CHANGED); EV(EV.enum.WALLETS_COUNT_CHANGED);

View file

@ -1,4 +1,4 @@
/* eslint react/prop-types: 0 */ /* eslint react/prop-types: "off", react-native/no-inline-styles: "off" */
import React, { Component, useEffect, useState } from 'react'; import React, { Component, useEffect, useState } from 'react';
import Ionicons from 'react-native-vector-icons/Ionicons'; import Ionicons from 'react-native-vector-icons/Ionicons';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@ -34,9 +34,9 @@ import { BlurView } from '@react-native-community/blur';
import showPopupMenu from 'react-native-popup-menu-android'; import showPopupMenu from 'react-native-popup-menu-android';
import NetworkTransactionFees, { NetworkTransactionFeeType } from './models/networkTransactionFees'; import NetworkTransactionFees, { NetworkTransactionFeeType } from './models/networkTransactionFees';
import Biometric from './class/biometrics'; import Biometric from './class/biometrics';
let loc = require('./loc/'); const loc = require('./loc/');
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('./BlueApp'); const BlueApp = require('./BlueApp');
const { height, width } = Dimensions.get('window'); const { height, width } = Dimensions.get('window');
const aspectRatio = height / width; const aspectRatio = height / width;
const BigNumber = require('bignumber.js'); const BigNumber = require('bignumber.js');
@ -51,12 +51,12 @@ export class BlueButton extends Component {
render() { render() {
let backgroundColor = this.props.backgroundColor ? this.props.backgroundColor : BlueApp.settings.buttonBackgroundColor; let backgroundColor = this.props.backgroundColor ? this.props.backgroundColor : BlueApp.settings.buttonBackgroundColor;
let fontColor = BlueApp.settings.buttonTextColor; let fontColor = BlueApp.settings.buttonTextColor;
if (this.props.hasOwnProperty('disabled') && this.props.disabled === true) { if (this.props.disabled === true) {
backgroundColor = BlueApp.settings.buttonDisabledBackgroundColor; backgroundColor = BlueApp.settings.buttonDisabledBackgroundColor;
fontColor = BlueApp.settings.buttonDisabledTextColor; fontColor = BlueApp.settings.buttonDisabledTextColor;
} }
let buttonWidth = this.props.width ? this.props.width : width / 1.5; let buttonWidth = this.props.width ? this.props.width : width / 1.5;
if (this.props.hasOwnProperty('noMinWidth')) { if ('noMinWidth' in this.props) {
buttonWidth = 0; buttonWidth = 0;
} }
return ( return (
@ -91,20 +91,16 @@ export class BitcoinButton extends Component {
<TouchableOpacity <TouchableOpacity
testID={this.props.testID} testID={this.props.testID}
onPress={() => { onPress={() => {
// eslint-disable-next-line
if (this.props.onPress) this.props.onPress(); if (this.props.onPress) this.props.onPress();
}} }}
> >
<View <View
style={{ style={{
// eslint-disable-next-line
borderColor: BlueApp.settings.hdborderColor, borderColor: BlueApp.settings.hdborderColor,
borderWidth: 1, borderWidth: 1,
borderRadius: 5, borderRadius: 5,
backgroundColor: (this.props.active && BlueApp.settings.hdbackgroundColor) || BlueApp.settings.brandingColor, backgroundColor: (this.props.active && BlueApp.settings.hdbackgroundColor) || BlueApp.settings.brandingColor,
// eslint-disable-next-line
minWidth: this.props.style.width, minWidth: this.props.style.width,
// eslint-disable-next-line
minHeight: this.props.style.height, minHeight: this.props.style.height,
height: this.props.style.height, height: this.props.style.height,
flex: 1, flex: 1,
@ -128,20 +124,16 @@ export class LightningButton extends Component {
return ( return (
<TouchableOpacity <TouchableOpacity
onPress={() => { onPress={() => {
// eslint-disable-next-line
if (this.props.onPress) this.props.onPress(); if (this.props.onPress) this.props.onPress();
}} }}
> >
<View <View
style={{ style={{
// eslint-disable-next-line
borderColor: BlueApp.settings.lnborderColor, borderColor: BlueApp.settings.lnborderColor,
borderWidth: 1, borderWidth: 1,
borderRadius: 5, borderRadius: 5,
backgroundColor: (this.props.active && BlueApp.settings.lnbackgroundColor) || BlueApp.settings.brandingColor, backgroundColor: (this.props.active && BlueApp.settings.lnbackgroundColor) || BlueApp.settings.brandingColor,
// eslint-disable-next-line
minWidth: this.props.style.width, minWidth: this.props.style.width,
// eslint-disable-next-line
minHeight: this.props.style.height, minHeight: this.props.style.height,
height: this.props.style.height, height: this.props.style.height,
flex: 1, flex: 1,
@ -314,7 +306,7 @@ export class BlueWalletNavigationHeader extends Component {
<BluePrivateBalance /> <BluePrivateBalance />
) : ( ) : (
<Text <Text
testID={'WalletBalance'} testID="WalletBalance"
numberOfLines={1} numberOfLines={1}
adjustsFontSizeToFit adjustsFontSizeToFit
style={{ style={{
@ -580,8 +572,6 @@ export class BlueText extends Component {
<Text <Text
style={{ style={{
color: BlueApp.settings.foregroundColor, color: BlueApp.settings.foregroundColor,
// eslint-disable-next-line
...this.props.style, ...this.props.style,
}} }}
{...this.props} {...this.props}
@ -589,6 +579,7 @@ export class BlueText extends Component {
); );
} }
} }
export class BlueTextCentered extends Component { export class BlueTextCentered extends Component {
render() { render() {
return <Text {...this.props} style={{ color: BlueApp.settings.foregroundColor, textAlign: 'center' }} />; return <Text {...this.props} style={{ color: BlueApp.settings.foregroundColor, textAlign: 'center' }} />;
@ -720,16 +711,12 @@ export class BlueHeaderDefaultSub extends Component {
color: BlueApp.settings.foregroundColor, color: BlueApp.settings.foregroundColor,
}} }}
> >
{ {this.props.leftText}
// eslint-disable-next-line
this.props.leftText
}
</Text> </Text>
} }
rightComponent={ rightComponent={
<TouchableOpacity <TouchableOpacity
onPress={() => { onPress={() => {
// eslint-disable-next-line
if (this.props.onClose) this.props.onClose(); if (this.props.onClose) this.props.onClose();
}} }}
> >
@ -755,7 +742,6 @@ export class BlueHeaderDefaultMain extends Component {
{...this.props} {...this.props}
statusBarProps={{ barStyle: 'default' }} statusBarProps={{ barStyle: 'default' }}
leftComponent={{ leftComponent={{
// eslint-disable-next-line
text: this.props.leftText, text: this.props.leftText,
style: { style: {
fontWeight: 'bold', fontWeight: 'bold',
@ -1067,7 +1053,7 @@ export class BluePlusIcon extends Component {
<View style={stylesBlueIcon.ball}> <View style={stylesBlueIcon.ball}>
<Ionicons <Ionicons
{...this.props} {...this.props}
name={'ios-add'} name="ios-add"
size={26} size={26}
style={{ style={{
color: BlueApp.settings.foregroundColor, color: BlueApp.settings.foregroundColor,
@ -1301,7 +1287,7 @@ export class BlueScanButton extends Component {
export class BlueSendButtonIcon extends Component { export class BlueSendButtonIcon extends Component {
render() { render() {
return ( return (
<TouchableOpacity {...this.props} testID={'SendButton'}> <TouchableOpacity {...this.props} testID="SendButton">
<View <View
style={{ style={{
flex: 1, flex: 1,
@ -1441,8 +1427,8 @@ export const BlueTransactionListItem = ({ item, itemPriceUnit = BitcoinUnit.BTC,
}, [item, itemPriceUnit, shouldRefresh]); }, [item, itemPriceUnit, shouldRefresh]);
const txMemo = () => { const txMemo = () => {
if (BlueApp.tx_metadata[item.hash] && BlueApp.tx_metadata[item.hash]['memo']) { if (BlueApp.tx_metadata[item.hash] && BlueApp.tx_metadata[item.hash].memo) {
return BlueApp.tx_metadata[item.hash]['memo']; return BlueApp.tx_metadata[item.hash].memo;
} }
return ''; return '';
}; };
@ -1578,7 +1564,7 @@ export const BlueTransactionListItem = ({ item, itemPriceUnit = BitcoinUnit.BTC,
} else if (item.type === 'user_invoice' || item.type === 'payment_request' || item.type === 'paid_invoice') { } else if (item.type === 'user_invoice' || item.type === 'payment_request' || item.type === 'paid_invoice') {
const lightningWallet = BlueApp.getWallets().filter(wallet => { const lightningWallet = BlueApp.getWallets().filter(wallet => {
if (typeof wallet === 'object') { if (typeof wallet === 'object') {
if (wallet.hasOwnProperty('secret')) { if ('secret' in wallet) {
return wallet.getSecret() === item.fromWallet; return wallet.getSecret() === item.fromWallet;
} }
} }
@ -1627,8 +1613,8 @@ export class BlueListTransactionItem extends Component {
}; };
txMemo = () => { txMemo = () => {
if (BlueApp.tx_metadata[this.props.item.hash] && BlueApp.tx_metadata[this.props.item.hash]['memo']) { if (BlueApp.tx_metadata[this.props.item.hash] && BlueApp.tx_metadata[this.props.item.hash].memo) {
return BlueApp.tx_metadata[this.props.item.hash]['memo']; return BlueApp.tx_metadata[this.props.item.hash].memo;
} }
return ''; return '';
}; };
@ -1772,7 +1758,7 @@ export class BlueListTransactionItem extends Component {
) { ) {
const lightningWallet = BlueApp.getWallets().filter(wallet => { const lightningWallet = BlueApp.getWallets().filter(wallet => {
if (typeof wallet === 'object') { if (typeof wallet === 'object') {
if (wallet.hasOwnProperty('secret')) { if ('secret' in wallet) {
return wallet.getSecret() === this.props.item.fromWallet; return wallet.getSecret() === this.props.item.fromWallet;
} }
} }
@ -1801,21 +1787,21 @@ export class BlueListTransactionItem extends Component {
} }
const WalletCarouselItem = ({ item, index, onPress, handleLongPress }) => { const WalletCarouselItem = ({ item, index, onPress, handleLongPress }) => {
let scaleValue = new Animated.Value(1.0); const scaleValue = new Animated.Value(1.0);
const onPressedIn = () => { const onPressedIn = () => {
let props = { duration: 50 }; const props = { duration: 50 };
if (Platform.OS === 'android') { if (Platform.OS === 'android') {
props['useNativeDriver'] = true; props.useNativeDriver = true;
} }
props.toValue = 0.9; props.toValue = 0.9;
Animated.spring(scaleValue, props).start(); Animated.spring(scaleValue, props).start();
}; };
const onPressedOut = () => { const onPressedOut = () => {
let props = { duration: 50 }; const props = { duration: 50 };
if (Platform.OS === 'android') { if (Platform.OS === 'android') {
props['useNativeDriver'] = true; props.useNativeDriver = true;
} }
props.toValue = 1.0; props.toValue = 1.0;
@ -2083,7 +2069,7 @@ export class BlueAddressInput extends Component {
}} }}
> >
<TextInput <TextInput
testID={'AddressInput'} testID="AddressInput"
onChangeText={text => { onChangeText={text => {
this.props.onChangeText(text); this.props.onChangeText(text);
}} }}
@ -2177,7 +2163,7 @@ export class BlueReplaceFeeSuggestions extends Component {
onPress={() => this.onFeeSelected(NetworkTransactionFeeType.FAST)} onPress={() => this.onFeeSelected(NetworkTransactionFeeType.FAST)}
containerStyle={{ paddingHorizontal: 0, marginHorizontal: 0 }} containerStyle={{ paddingHorizontal: 0, marginHorizontal: 0 }}
bottomDivider={false} bottomDivider={false}
title={'Fast'} title="Fast"
rightTitle={`${this.state.networkFees.fastestFee} sat/b`} rightTitle={`${this.state.networkFees.fastestFee} sat/b`}
rightTitleStyle={{ fontSize: 13, color: BlueApp.settings.alternativeTextColor }} rightTitleStyle={{ fontSize: 13, color: BlueApp.settings.alternativeTextColor }}
{...(this.state.selectedFeeType === NetworkTransactionFeeType.FAST {...(this.state.selectedFeeType === NetworkTransactionFeeType.FAST
@ -2188,7 +2174,7 @@ export class BlueReplaceFeeSuggestions extends Component {
onPress={() => this.onFeeSelected(NetworkTransactionFeeType.MEDIUM)} onPress={() => this.onFeeSelected(NetworkTransactionFeeType.MEDIUM)}
containerStyle={{ paddingHorizontal: 0, marginHorizontal: 0 }} containerStyle={{ paddingHorizontal: 0, marginHorizontal: 0 }}
bottomDivider={false} bottomDivider={false}
title={'Medium'} title="Medium"
rightTitle={`${this.state.networkFees.mediumFee} sat/b`} rightTitle={`${this.state.networkFees.mediumFee} sat/b`}
rightTitleStyle={{ fontSize: 13, color: BlueApp.settings.alternativeTextColor }} rightTitleStyle={{ fontSize: 13, color: BlueApp.settings.alternativeTextColor }}
{...(this.state.selectedFeeType === NetworkTransactionFeeType.MEDIUM {...(this.state.selectedFeeType === NetworkTransactionFeeType.MEDIUM
@ -2199,7 +2185,7 @@ export class BlueReplaceFeeSuggestions extends Component {
onPress={() => this.onFeeSelected(NetworkTransactionFeeType.SLOW)} onPress={() => this.onFeeSelected(NetworkTransactionFeeType.SLOW)}
containerStyle={{ paddingHorizontal: 0, marginHorizontal: 0 }} containerStyle={{ paddingHorizontal: 0, marginHorizontal: 0 }}
bottomDivider={false} bottomDivider={false}
title={'Slow'} title="Slow"
rightTitle={`${this.state.networkFees.slowFee} sat/b`} rightTitle={`${this.state.networkFees.slowFee} sat/b`}
rightTitleStyle={{ fontSize: 13, color: BlueApp.settings.alternativeTextColor }} rightTitleStyle={{ fontSize: 13, color: BlueApp.settings.alternativeTextColor }}
{...(this.state.selectedFeeType === NetworkTransactionFeeType.SLOW {...(this.state.selectedFeeType === NetworkTransactionFeeType.SLOW
@ -2224,7 +2210,7 @@ export class BlueReplaceFeeSuggestions extends Component {
> >
<TextInput <TextInput
onChangeText={this.onCustomFeeTextChange} onChangeText={this.onCustomFeeTextChange}
keyboardType={'numeric'} keyboardType="numeric"
value={this.state.customFeeValue} value={this.state.customFeeValue}
ref={ref => (this.customTextInput = ref)} ref={ref => (this.customTextInput = ref)}
maxLength={9} maxLength={9}
@ -2295,7 +2281,7 @@ export class BlueBitcoinAmount extends Component {
<View style={{ flexDirection: 'row', justifyContent: 'center', paddingTop: 16, paddingBottom: 2 }}> <View style={{ flexDirection: 'row', justifyContent: 'center', paddingTop: 16, paddingBottom: 2 }}>
<TextInput <TextInput
{...this.props} {...this.props}
testID={'BitcoinAmountInput'} testID="BitcoinAmountInput"
keyboardType="numeric" keyboardType="numeric"
onChangeText={text => { onChangeText={text => {
text = text.trim(); text = text.trim();

View file

@ -3,8 +3,8 @@ import { Platform } from 'react-native';
import { AppStorage, LegacyWallet, SegwitBech32Wallet, SegwitP2SHWallet } from './class'; import { AppStorage, LegacyWallet, SegwitBech32Wallet, SegwitP2SHWallet } from './class';
const bitcoin = require('bitcoinjs-lib'); const bitcoin = require('bitcoinjs-lib');
const ElectrumClient = require('electrum-client'); const ElectrumClient = require('electrum-client');
let reverse = require('buffer-reverse'); const reverse = require('buffer-reverse');
let BigNumber = require('bignumber.js'); const BigNumber = require('bignumber.js');
const storageKey = 'ELECTRUM_PEERS'; const storageKey = 'ELECTRUM_PEERS';
const defaultPeer = { host: 'electrum1.bluewallet.io', ssl: '443' }; const defaultPeer = { host: 'electrum1.bluewallet.io', ssl: '443' };
@ -30,11 +30,11 @@ let wasConnectedAtLeastOnce = false;
let serverName = false; let serverName = false;
let disableBatching = false; let disableBatching = false;
let txhashHeightCache = {}; const txhashHeightCache = {};
async function connectMain() { async function connectMain() {
let usingPeer = await getRandomHardcodedPeer(); let usingPeer = await getRandomHardcodedPeer();
let savedPeer = await getSavedPeer(); const savedPeer = await getSavedPeer();
if (savedPeer && savedPeer.host && (savedPeer.tcp || savedPeer.ssl)) { if (savedPeer && savedPeer.host && (savedPeer.tcp || savedPeer.ssl)) {
usingPeer = savedPeer; usingPeer = savedPeer;
} }
@ -42,7 +42,7 @@ async function connectMain() {
try { try {
console.log('begin connection:', JSON.stringify(usingPeer)); console.log('begin connection:', JSON.stringify(usingPeer));
mainClient = new ElectrumClient(usingPeer.ssl || usingPeer.tcp, usingPeer.host, usingPeer.ssl ? 'tls' : 'tcp'); mainClient = new ElectrumClient(usingPeer.ssl || usingPeer.tcp, usingPeer.host, usingPeer.ssl ? 'tls' : 'tcp');
mainClient.onError = function(e) { mainClient.onError = function (e) {
if (Platform.OS === 'android' && mainConnected) { if (Platform.OS === 'android' && mainConnected) {
// android sockets are buggy and dont always issue CLOSE event, which actually makes the persistence code to reconnect. // android sockets are buggy and dont always issue CLOSE event, which actually makes the persistence code to reconnect.
// so lets do it manually, but only if we were previously connected (mainConnected), otherwise theres other // so lets do it manually, but only if we were previously connected (mainConnected), otherwise theres other
@ -92,9 +92,9 @@ async function getRandomHardcodedPeer() {
} }
async function getSavedPeer() { async function getSavedPeer() {
let host = await AsyncStorage.getItem(AppStorage.ELECTRUM_HOST); const host = await AsyncStorage.getItem(AppStorage.ELECTRUM_HOST);
let port = await AsyncStorage.getItem(AppStorage.ELECTRUM_TCP_PORT); const port = await AsyncStorage.getItem(AppStorage.ELECTRUM_TCP_PORT);
let sslPort = await AsyncStorage.getItem(AppStorage.ELECTRUM_SSL_PORT); const sslPort = await AsyncStorage.getItem(AppStorage.ELECTRUM_SSL_PORT);
return { host, tcp: port, ssl: sslPort }; return { host, tcp: port, ssl: sslPort };
} }
@ -111,10 +111,10 @@ async function getRandomDynamicPeer() {
try { try {
let peers = JSON.parse(await AsyncStorage.getItem(storageKey)); let peers = JSON.parse(await AsyncStorage.getItem(storageKey));
peers = peers.sort(() => Math.random() - 0.5); // shuffle peers = peers.sort(() => Math.random() - 0.5); // shuffle
for (let peer of peers) { for (const peer of peers) {
let ret = {}; const ret = {};
ret.host = peer[1]; ret.host = peer[1];
for (let item of peer[2]) { for (const item of peer[2]) {
if (item.startsWith('t')) { if (item.startsWith('t')) {
ret.tcp = item.replace('t', ''); ret.tcp = item.replace('t', '');
} }
@ -133,17 +133,17 @@ async function getRandomDynamicPeer() {
* @param address {String} * @param address {String}
* @returns {Promise<Object>} * @returns {Promise<Object>}
*/ */
module.exports.getBalanceByAddress = async function(address) { module.exports.getBalanceByAddress = async function (address) {
if (!mainClient) throw new Error('Electrum client is not connected'); if (!mainClient) throw new Error('Electrum client is not connected');
let script = bitcoin.address.toOutputScript(address); const script = bitcoin.address.toOutputScript(address);
let hash = bitcoin.crypto.sha256(script); const hash = bitcoin.crypto.sha256(script);
let reversedHash = Buffer.from(reverse(hash)); const reversedHash = Buffer.from(reverse(hash));
let balance = await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex')); const balance = await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex'));
balance.addr = address; balance.addr = address;
return balance; return balance;
}; };
module.exports.getConfig = async function() { module.exports.getConfig = async function () {
if (!mainClient) throw new Error('Electrum client is not connected'); if (!mainClient) throw new Error('Electrum client is not connected');
return { return {
host: mainClient.host, host: mainClient.host,
@ -158,17 +158,17 @@ module.exports.getConfig = async function() {
* @param address {String} * @param address {String}
* @returns {Promise<Array>} * @returns {Promise<Array>}
*/ */
module.exports.getTransactionsByAddress = async function(address) { module.exports.getTransactionsByAddress = async function (address) {
if (!mainClient) throw new Error('Electrum client is not connected'); if (!mainClient) throw new Error('Electrum client is not connected');
let script = bitcoin.address.toOutputScript(address); const script = bitcoin.address.toOutputScript(address);
let hash = bitcoin.crypto.sha256(script); const hash = bitcoin.crypto.sha256(script);
let reversedHash = Buffer.from(reverse(hash)); const reversedHash = Buffer.from(reverse(hash));
let history = await mainClient.blockchainScripthash_getHistory(reversedHash.toString('hex')); const history = await mainClient.blockchainScripthash_getHistory(reversedHash.toString('hex'));
if (history.tx_hash) txhashHeightCache[history.tx_hash] = history.height; // cache tx height if (history.tx_hash) txhashHeightCache[history.tx_hash] = history.height; // cache tx height
return history; return history;
}; };
module.exports.ping = async function() { module.exports.ping = async function () {
try { try {
await mainClient.server_ping(); await mainClient.server_ping();
} catch (_) { } catch (_) {
@ -178,15 +178,15 @@ module.exports.ping = async function() {
return true; return true;
}; };
module.exports.getTransactionsFullByAddress = async function(address) { module.exports.getTransactionsFullByAddress = async function (address) {
let txs = await this.getTransactionsByAddress(address); const txs = await this.getTransactionsByAddress(address);
let ret = []; const ret = [];
for (let tx of txs) { for (const tx of txs) {
let full = await mainClient.blockchainTransaction_get(tx.tx_hash, true); const full = await mainClient.blockchainTransaction_get(tx.tx_hash, true);
full.address = address; full.address = address;
for (let input of full.vin) { for (const input of full.vin) {
// now we need to fetch previous TX where this VIN became an output, so we can see its amount // now we need to fetch previous TX where this VIN became an output, so we can see its amount
let prevTxForVin = await mainClient.blockchainTransaction_get(input.txid, true); const prevTxForVin = await mainClient.blockchainTransaction_get(input.txid, true);
if (prevTxForVin && prevTxForVin.vout && prevTxForVin.vout[input.vout]) { if (prevTxForVin && prevTxForVin.vout && prevTxForVin.vout[input.vout]) {
input.value = prevTxForVin.vout[input.vout].value; input.value = prevTxForVin.vout[input.vout].value;
// also, we extract destination address from prev output: // also, we extract destination address from prev output:
@ -196,7 +196,7 @@ module.exports.getTransactionsFullByAddress = async function(address) {
} }
} }
for (let output of full.vout) { for (const output of full.vout) {
if (output.scriptPubKey && output.scriptPubKey.addresses) output.addresses = output.scriptPubKey.addresses; if (output.scriptPubKey && output.scriptPubKey.addresses) output.addresses = output.scriptPubKey.addresses;
} }
full.inputs = full.vin; full.inputs = full.vin;
@ -217,18 +217,18 @@ module.exports.getTransactionsFullByAddress = async function(address) {
* @param batchsize {Number} * @param batchsize {Number}
* @returns {Promise<{balance: number, unconfirmed_balance: number, addresses: object}>} * @returns {Promise<{balance: number, unconfirmed_balance: number, addresses: object}>}
*/ */
module.exports.multiGetBalanceByAddress = async function(addresses, batchsize) { module.exports.multiGetBalanceByAddress = async function (addresses, batchsize) {
batchsize = batchsize || 100; batchsize = batchsize || 100;
if (!mainClient) throw new Error('Electrum client is not connected'); if (!mainClient) throw new Error('Electrum client is not connected');
let ret = { balance: 0, unconfirmed_balance: 0, addresses: {} }; const ret = { balance: 0, unconfirmed_balance: 0, addresses: {} };
let chunks = splitIntoChunks(addresses, batchsize); const chunks = splitIntoChunks(addresses, batchsize);
for (let chunk of chunks) { for (const chunk of chunks) {
let scripthashes = []; const scripthashes = [];
let scripthash2addr = {}; const scripthash2addr = {};
for (let addr of chunk) { for (const addr of chunk) {
let script = bitcoin.address.toOutputScript(addr); const script = bitcoin.address.toOutputScript(addr);
let hash = bitcoin.crypto.sha256(script); const hash = bitcoin.crypto.sha256(script);
let reversedHash = Buffer.from(reverse(hash)); let reversedHash = Buffer.from(reverse(hash));
reversedHash = reversedHash.toString('hex'); reversedHash = reversedHash.toString('hex');
scripthashes.push(reversedHash); scripthashes.push(reversedHash);
@ -238,15 +238,15 @@ module.exports.multiGetBalanceByAddress = async function(addresses, batchsize) {
let balances = []; let balances = [];
if (disableBatching) { if (disableBatching) {
for (let sh of scripthashes) { for (const sh of scripthashes) {
let balance = await mainClient.blockchainScripthash_getBalance(sh); const balance = await mainClient.blockchainScripthash_getBalance(sh);
balances.push({ result: balance, param: sh }); balances.push({ result: balance, param: sh });
} }
} else { } else {
balances = await mainClient.blockchainScripthash_getBalanceBatch(scripthashes); balances = await mainClient.blockchainScripthash_getBalanceBatch(scripthashes);
} }
for (let bal of balances) { for (const bal of balances) {
ret.balance += +bal.result.confirmed; ret.balance += +bal.result.confirmed;
ret.unconfirmed_balance += +bal.result.unconfirmed; ret.unconfirmed_balance += +bal.result.unconfirmed;
ret.addresses[scripthash2addr[bal.param]] = bal.result; ret.addresses[scripthash2addr[bal.param]] = bal.result;
@ -256,18 +256,18 @@ module.exports.multiGetBalanceByAddress = async function(addresses, batchsize) {
return ret; return ret;
}; };
module.exports.multiGetUtxoByAddress = async function(addresses, batchsize) { module.exports.multiGetUtxoByAddress = async function (addresses, batchsize) {
batchsize = batchsize || 100; batchsize = batchsize || 100;
if (!mainClient) throw new Error('Electrum client is not connected'); if (!mainClient) throw new Error('Electrum client is not connected');
let ret = {}; const ret = {};
let chunks = splitIntoChunks(addresses, batchsize); const chunks = splitIntoChunks(addresses, batchsize);
for (let chunk of chunks) { for (const chunk of chunks) {
let scripthashes = []; const scripthashes = [];
let scripthash2addr = {}; const scripthash2addr = {};
for (let addr of chunk) { for (const addr of chunk) {
let script = bitcoin.address.toOutputScript(addr); const script = bitcoin.address.toOutputScript(addr);
let hash = bitcoin.crypto.sha256(script); const hash = bitcoin.crypto.sha256(script);
let reversedHash = Buffer.from(reverse(hash)); let reversedHash = Buffer.from(reverse(hash));
reversedHash = reversedHash.toString('hex'); reversedHash = reversedHash.toString('hex');
scripthashes.push(reversedHash); scripthashes.push(reversedHash);
@ -282,9 +282,9 @@ module.exports.multiGetUtxoByAddress = async function(addresses, batchsize) {
results = await mainClient.blockchainScripthash_listunspentBatch(scripthashes); results = await mainClient.blockchainScripthash_listunspentBatch(scripthashes);
} }
for (let utxos of results) { for (const utxos of results) {
ret[scripthash2addr[utxos.param]] = utxos.result; ret[scripthash2addr[utxos.param]] = utxos.result;
for (let utxo of ret[scripthash2addr[utxos.param]]) { for (const utxo of ret[scripthash2addr[utxos.param]]) {
utxo.address = scripthash2addr[utxos.param]; utxo.address = scripthash2addr[utxos.param];
utxo.txId = utxo.tx_hash; utxo.txId = utxo.tx_hash;
utxo.vout = utxo.tx_pos; utxo.vout = utxo.tx_pos;
@ -297,18 +297,18 @@ module.exports.multiGetUtxoByAddress = async function(addresses, batchsize) {
return ret; return ret;
}; };
module.exports.multiGetHistoryByAddress = async function(addresses, batchsize) { module.exports.multiGetHistoryByAddress = async function (addresses, batchsize) {
batchsize = batchsize || 100; batchsize = batchsize || 100;
if (!mainClient) throw new Error('Electrum client is not connected'); if (!mainClient) throw new Error('Electrum client is not connected');
let ret = {}; const ret = {};
let chunks = splitIntoChunks(addresses, batchsize); const chunks = splitIntoChunks(addresses, batchsize);
for (let chunk of chunks) { for (const chunk of chunks) {
let scripthashes = []; const scripthashes = [];
let scripthash2addr = {}; const scripthash2addr = {};
for (let addr of chunk) { for (const addr of chunk) {
let script = bitcoin.address.toOutputScript(addr); const script = bitcoin.address.toOutputScript(addr);
let hash = bitcoin.crypto.sha256(script); const hash = bitcoin.crypto.sha256(script);
let reversedHash = Buffer.from(reverse(hash)); let reversedHash = Buffer.from(reverse(hash));
reversedHash = reversedHash.toString('hex'); reversedHash = reversedHash.toString('hex');
scripthashes.push(reversedHash); scripthashes.push(reversedHash);
@ -318,18 +318,18 @@ module.exports.multiGetHistoryByAddress = async function(addresses, batchsize) {
let results = []; let results = [];
if (disableBatching) { if (disableBatching) {
for (let sh of scripthashes) { for (const sh of scripthashes) {
let history = await mainClient.blockchainScripthash_getHistory(sh); const history = await mainClient.blockchainScripthash_getHistory(sh);
results.push({ result: history, param: sh }); results.push({ result: history, param: sh });
} }
} else { } else {
results = await mainClient.blockchainScripthash_getHistoryBatch(scripthashes); results = await mainClient.blockchainScripthash_getHistoryBatch(scripthashes);
} }
for (let history of results) { for (const history of results) {
ret[scripthash2addr[history.param]] = history.result; ret[scripthash2addr[history.param]] = history.result;
if (history.result[0]) txhashHeightCache[history.result[0].tx_hash] = history.result[0].height; // cache tx height if (history.result[0]) txhashHeightCache[history.result[0].tx_hash] = history.result[0].height; // cache tx height
for (let hist of ret[scripthash2addr[history.param]]) { for (const hist of ret[scripthash2addr[history.param]]) {
hist.address = scripthash2addr[history.param]; hist.address = scripthash2addr[history.param];
} }
} }
@ -338,21 +338,21 @@ module.exports.multiGetHistoryByAddress = async function(addresses, batchsize) {
return ret; return ret;
}; };
module.exports.multiGetTransactionByTxid = async function(txids, batchsize, verbose) { module.exports.multiGetTransactionByTxid = async function (txids, batchsize, verbose) {
batchsize = batchsize || 45; batchsize = batchsize || 45;
// this value is fine-tuned so althrough wallets in test suite will occasionally // this value is fine-tuned so althrough wallets in test suite will occasionally
// throw 'response too large (over 1,000,000 bytes', test suite will pass // throw 'response too large (over 1,000,000 bytes', test suite will pass
verbose = verbose !== false; verbose = verbose !== false;
if (!mainClient) throw new Error('Electrum client is not connected'); if (!mainClient) throw new Error('Electrum client is not connected');
let ret = {}; const ret = {};
txids = [...new Set(txids)]; // deduplicate just for any case txids = [...new Set(txids)]; // deduplicate just for any case
let chunks = splitIntoChunks(txids, batchsize); const chunks = splitIntoChunks(txids, batchsize);
for (let chunk of chunks) { for (const chunk of chunks) {
let results = []; let results = [];
if (disableBatching) { if (disableBatching) {
for (let txid of chunk) { for (const txid of chunk) {
try { try {
// in case of ElectrumPersonalServer it might not track some transactions (like source transactions for our transactions) // in case of ElectrumPersonalServer it might not track some transactions (like source transactions for our transactions)
// so we wrap it in try-catch // so we wrap it in try-catch
@ -379,7 +379,7 @@ module.exports.multiGetTransactionByTxid = async function(txids, batchsize, verb
results = await mainClient.blockchainTransaction_getBatch(chunk, verbose); results = await mainClient.blockchainTransaction_getBatch(chunk, verbose);
} }
for (let txdata of results) { for (const txdata of results) {
ret[txdata.param] = txdata.result; ret[txdata.param] = txdata.result;
} }
} }
@ -394,10 +394,10 @@ module.exports.multiGetTransactionByTxid = async function(txids, batchsize, verb
* *
* @returns {Promise<Promise<*> | Promise<*>>} * @returns {Promise<Promise<*> | Promise<*>>}
*/ */
module.exports.waitTillConnected = async function() { module.exports.waitTillConnected = async function () {
let waitTillConnectedInterval = false; let waitTillConnectedInterval = false;
let retriesCounter = 0; let retriesCounter = 0;
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
waitTillConnectedInterval = setInterval(() => { waitTillConnectedInterval = setInterval(() => {
if (mainConnected) { if (mainConnected) {
clearInterval(waitTillConnectedInterval); clearInterval(waitTillConnectedInterval);
@ -418,7 +418,7 @@ module.exports.waitTillConnected = async function() {
}); });
}; };
module.exports.estimateFees = async function() { module.exports.estimateFees = async function () {
const fast = await module.exports.estimateFee(1); const fast = await module.exports.estimateFee(1);
const medium = await module.exports.estimateFee(18); const medium = await module.exports.estimateFee(18);
const slow = await module.exports.estimateFee(144); const slow = await module.exports.estimateFee(144);
@ -431,25 +431,20 @@ module.exports.estimateFees = async function() {
* @param numberOfBlocks {number} The number of blocks to target for confirmation * @param numberOfBlocks {number} The number of blocks to target for confirmation
* @returns {Promise<number>} Satoshis per byte * @returns {Promise<number>} Satoshis per byte
*/ */
module.exports.estimateFee = async function(numberOfBlocks) { module.exports.estimateFee = async function (numberOfBlocks) {
if (!mainClient) throw new Error('Electrum client is not connected'); if (!mainClient) throw new Error('Electrum client is not connected');
numberOfBlocks = numberOfBlocks || 1; numberOfBlocks = numberOfBlocks || 1;
let coinUnitsPerKilobyte = await mainClient.blockchainEstimatefee(numberOfBlocks); const coinUnitsPerKilobyte = await mainClient.blockchainEstimatefee(numberOfBlocks);
if (coinUnitsPerKilobyte === -1) return 1; if (coinUnitsPerKilobyte === -1) return 1;
return Math.round( return Math.round(new BigNumber(coinUnitsPerKilobyte).dividedBy(1024).multipliedBy(100000000).toNumber());
new BigNumber(coinUnitsPerKilobyte)
.dividedBy(1024)
.multipliedBy(100000000)
.toNumber(),
);
}; };
module.exports.serverFeatures = async function() { module.exports.serverFeatures = async function () {
if (!mainClient) throw new Error('Electrum client is not connected'); if (!mainClient) throw new Error('Electrum client is not connected');
return mainClient.server_features(); return mainClient.server_features();
}; };
module.exports.broadcast = async function(hex) { module.exports.broadcast = async function (hex) {
if (!mainClient) throw new Error('Electrum client is not connected'); if (!mainClient) throw new Error('Electrum client is not connected');
try { try {
const broadcast = await mainClient.blockchainTransaction_broadcast(hex); const broadcast = await mainClient.blockchainTransaction_broadcast(hex);
@ -459,12 +454,12 @@ module.exports.broadcast = async function(hex) {
} }
}; };
module.exports.broadcastV2 = async function(hex) { module.exports.broadcastV2 = async function (hex) {
if (!mainClient) throw new Error('Electrum client is not connected'); if (!mainClient) throw new Error('Electrum client is not connected');
return mainClient.blockchainTransaction_broadcast(hex); return mainClient.blockchainTransaction_broadcast(hex);
}; };
module.exports.estimateCurrentBlockheight = function() { module.exports.estimateCurrentBlockheight = function () {
const baseTs = 1587570465609; // uS const baseTs = 1587570465609; // uS
const baseHeight = 627179; const baseHeight = 627179;
return Math.floor(baseHeight + (+new Date() - baseTs) / 1000 / 60 / 9.5); return Math.floor(baseHeight + (+new Date() - baseTs) / 1000 / 60 / 9.5);
@ -475,7 +470,7 @@ module.exports.estimateCurrentBlockheight = function() {
* @param height * @param height
* @returns {number} Timestamp in seconds * @returns {number} Timestamp in seconds
*/ */
module.exports.calculateBlockTime = function(height) { module.exports.calculateBlockTime = function (height) {
const baseTs = 1585837504; // sec const baseTs = 1585837504; // sec
const baseHeight = 624083; const baseHeight = 624083;
return baseTs + (height - baseHeight) * 10 * 60; return baseTs + (height - baseHeight) * 10 * 60;
@ -488,8 +483,8 @@ module.exports.calculateBlockTime = function(height) {
* @param sslPort * @param sslPort
* @returns {Promise<boolean>} Whether provided host:port is a valid electrum server * @returns {Promise<boolean>} Whether provided host:port is a valid electrum server
*/ */
module.exports.testConnection = async function(host, tcpPort, sslPort) { module.exports.testConnection = async function (host, tcpPort, sslPort) {
let client = new ElectrumClient(sslPort || tcpPort, host, sslPort ? 'tls' : 'tcp'); const client = new ElectrumClient(sslPort || tcpPort, host, sslPort ? 'tls' : 'tcp');
try { try {
await client.connect(); await client.connect();
await client.server_version('2.7.11', '1.4'); await client.server_version('2.7.11', '1.4');
@ -507,8 +502,8 @@ module.exports.forceDisconnect = () => {
module.exports.hardcodedPeers = hardcodedPeers; module.exports.hardcodedPeers = hardcodedPeers;
let splitIntoChunks = function(arr, chunkSize) { const splitIntoChunks = function (arr, chunkSize) {
let groups = []; const groups = [];
let i; let i;
for (i = 0; i < arr.length; i += chunkSize) { for (i = 0; i < arr.length; i += chunkSize) {
groups.push(arr.slice(i, i + chunkSize)); groups.push(arr.slice(i, i + chunkSize));
@ -517,9 +512,9 @@ let splitIntoChunks = function(arr, chunkSize) {
}; };
function txhexToElectrumTransaction(txhex) { function txhexToElectrumTransaction(txhex) {
let tx = bitcoin.Transaction.fromHex(txhex); const tx = bitcoin.Transaction.fromHex(txhex);
let ret = { const ret = {
txid: tx.getId(), txid: tx.getId(),
hash: tx.getId(), hash: tx.getId(),
version: tx.version, version: tx.version,
@ -536,8 +531,8 @@ function txhexToElectrumTransaction(txhex) {
blocktime: 0, blocktime: 0,
}; };
for (let inn of tx.ins) { for (const inn of tx.ins) {
let txinwitness = []; const txinwitness = [];
if (inn.witness[0]) txinwitness.push(inn.witness[0].toString('hex')); if (inn.witness[0]) txinwitness.push(inn.witness[0].toString('hex'));
if (inn.witness[1]) txinwitness.push(inn.witness[1].toString('hex')); if (inn.witness[1]) txinwitness.push(inn.witness[1].toString('hex'));
@ -551,8 +546,8 @@ function txhexToElectrumTransaction(txhex) {
} }
let n = 0; let n = 0;
for (let out of tx.outs) { for (const out of tx.outs) {
let value = new BigNumber(out.value).dividedBy(100000000).toNumber(); const value = new BigNumber(out.value).dividedBy(100000000).toNumber();
let address = false; let address = false;
let type = false; let type = false;

View file

@ -68,7 +68,7 @@ export default class WatchConnectivity {
return InteractionManager.runAfterInteractions(async () => { return InteractionManager.runAfterInteractions(async () => {
if (WatchConnectivity.shared.isAppInstalled) { if (WatchConnectivity.shared.isAppInstalled) {
let wallets = []; const wallets = [];
for (const wallet of allWallets) { for (const wallet of allWallets) {
let receiveAddress = ''; let receiveAddress = '';
@ -85,14 +85,14 @@ export default class WatchConnectivity {
receiveAddress = wallet.getAddress(); receiveAddress = wallet.getAddress();
} }
} }
let transactions = wallet.getTransactions(10); const transactions = wallet.getTransactions(10);
let watchTransactions = []; const watchTransactions = [];
for (const transaction of transactions) { for (const transaction of transactions) {
let type = 'pendingConfirmation'; let type = 'pendingConfirmation';
let memo = ''; let memo = '';
let amount = 0; let amount = 0;
if (transaction.hasOwnProperty('confirmations') && !(transaction.confirmations > 0)) { if ('confirmations' in transaction && !(transaction.confirmations > 0)) {
type = 'pendingConfirmation'; type = 'pendingConfirmation';
} else if (transaction.type === 'user_invoice' || transaction.type === 'payment_request') { } else if (transaction.type === 'user_invoice' || transaction.type === 'payment_request') {
const currentDate = new Date(); const currentDate = new Date();
@ -133,8 +133,8 @@ export default class WatchConnectivity {
} else { } else {
amount = loc.formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString(); amount = loc.formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
} }
if (WatchConnectivity.shared.tx_metadata[transaction.hash] && WatchConnectivity.shared.tx_metadata[transaction.hash]['memo']) { if (WatchConnectivity.shared.tx_metadata[transaction.hash] && WatchConnectivity.shared.tx_metadata[transaction.hash].memo) {
memo = WatchConnectivity.shared.tx_metadata[transaction.hash]['memo']; memo = WatchConnectivity.shared.tx_metadata[transaction.hash].memo;
} else if (transaction.memo) { } else if (transaction.memo) {
memo = transaction.memo; memo = transaction.memo;
} }

View file

@ -8,7 +8,7 @@ amplitude.getInstance().init('8b7cf19e8eea3cdcf16340f5fbf16330', null, {
}); });
amplitude.getInstance().setVersionName(getVersion()); amplitude.getInstance().setVersionName(getVersion());
let A = async event => { const A = async event => {
console.log('posting analytics...', event); console.log('posting analytics...', event);
try { try {
amplitude.getInstance().logEvent(event); amplitude.getInstance().logEvent(event);

View file

@ -18,6 +18,7 @@ export class BitcoinBIP70TransactionError {
export default class BitcoinBIP70TransactionDecode { export default class BitcoinBIP70TransactionDecode {
static decode(data) { static decode(data) {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
let url; let url;
@ -32,7 +33,7 @@ export default class BitcoinBIP70TransactionDecode {
Accept: 'application/payment-request', Accept: 'application/payment-request',
}, },
}); });
let response = await api.get(); const response = await api.get();
if (response && response.body) { if (response && response.body) {
const parsedJSON = JSON.parse(response.body); const parsedJSON = JSON.parse(response.body);
@ -74,6 +75,11 @@ export default class BitcoinBIP70TransactionDecode {
} }
static matchesPaymentURL(data) { static matchesPaymentURL(data) {
return data !== null && (data.match(/bitcoin:\?r=https?:\/\/\S+/gi) !== null || data.startsWith('https://bitpay.com/i/') || data.startsWith('https://www.bitpay.com/i/')); return (
data !== null &&
(data.match(/bitcoin:\?r=https?:\/\/\S+/gi) !== null ||
data.startsWith('https://bitpay.com/i/') ||
data.startsWith('https://www.bitpay.com/i/'))
);
} }
} }

View file

@ -135,7 +135,7 @@ export class AppStorage {
decryptData(data, password) { decryptData(data, password) {
data = JSON.parse(data); data = JSON.parse(data);
let decrypted; let decrypted;
for (let value of data) { for (const value of data) {
try { try {
decrypted = encryption.decrypt(value, password); decrypted = encryption.decrypt(value, password);
} catch (e) { } catch (e) {
@ -179,7 +179,7 @@ export class AppStorage {
let data = await this.getItem('data'); let data = await this.getItem('data');
// TODO: refactor ^^^ (should not save & load to fetch data) // TODO: refactor ^^^ (should not save & load to fetch data)
let encrypted = encryption.encrypt(data, password); const encrypted = encryption.encrypt(data, password);
data = []; data = [];
data.push(encrypted); // putting in array as we might have many buckets with storages data.push(encrypted); // putting in array as we might have many buckets with storages
data = JSON.stringify(data); data = JSON.stringify(data);
@ -200,7 +200,7 @@ export class AppStorage {
this.wallets = []; this.wallets = [];
this.tx_metadata = {}; this.tx_metadata = {};
let data = { const data = {
wallets: [], wallets: [],
tx_metadata: {}, tx_metadata: {},
}; };
@ -234,10 +234,10 @@ export class AppStorage {
if (data !== null) { if (data !== null) {
data = JSON.parse(data); data = JSON.parse(data);
if (!data.wallets) return false; if (!data.wallets) return false;
let wallets = data.wallets; const wallets = data.wallets;
for (let key of wallets) { for (const key of wallets) {
// deciding which type is wallet and instatiating correct object // deciding which type is wallet and instatiating correct object
let tempObj = JSON.parse(key); const tempObj = JSON.parse(key);
let unserializedWallet; let unserializedWallet;
switch (tempObj.type) { switch (tempObj.type) {
case PlaceholderWallet.type: case PlaceholderWallet.type:
@ -270,7 +270,7 @@ export class AppStorage {
case HDSegwitElectrumSeedP2WPKHWallet.type: case HDSegwitElectrumSeedP2WPKHWallet.type:
unserializedWallet = HDSegwitElectrumSeedP2WPKHWallet.fromJson(key); unserializedWallet = HDSegwitElectrumSeedP2WPKHWallet.fromJson(key);
break; break;
case LightningCustodianWallet.type: case LightningCustodianWallet.type: {
/** @type {LightningCustodianWallet} */ /** @type {LightningCustodianWallet} */
unserializedWallet = LightningCustodianWallet.fromJson(key); unserializedWallet = LightningCustodianWallet.fromJson(key);
let lndhub = false; let lndhub = false;
@ -292,6 +292,7 @@ export class AppStorage {
} }
unserializedWallet.init(); unserializedWallet.init();
break; break;
}
case LegacyWallet.type: case LegacyWallet.type:
default: default:
unserializedWallet = LegacyWallet.fromJson(key); unserializedWallet = LegacyWallet.fromJson(key);
@ -336,10 +337,10 @@ export class AppStorage {
* @param wallet {AbstractWallet} * @param wallet {AbstractWallet}
*/ */
deleteWallet(wallet) { deleteWallet(wallet) {
let secret = wallet.getSecret(); const secret = wallet.getSecret();
let tempWallets = []; const tempWallets = [];
for (let value of this.wallets) { for (const value of this.wallets) {
if (value.getSecret() === secret) { if (value.getSecret() === secret) {
// the one we should delete // the one we should delete
// nop // nop
@ -359,8 +360,8 @@ export class AppStorage {
* @returns {Promise} Result of storage save * @returns {Promise} Result of storage save
*/ */
async saveToDisk() { async saveToDisk() {
let walletsToSave = []; const walletsToSave = [];
for (let key of this.wallets) { for (const key of this.wallets) {
if (typeof key === 'boolean' || key.type === PlaceholderWallet.type) continue; if (typeof key === 'boolean' || key.type === PlaceholderWallet.type) continue;
if (key.prepareForSerialization) key.prepareForSerialization(); if (key.prepareForSerialization) key.prepareForSerialization();
walletsToSave.push(JSON.stringify({ ...key, type: key.type })); walletsToSave.push(JSON.stringify({ ...key, type: key.type }));
@ -374,9 +375,9 @@ export class AppStorage {
// should find the correct bucket, encrypt and then save // should find the correct bucket, encrypt and then save
let buckets = await this.getItem('data'); let buckets = await this.getItem('data');
buckets = JSON.parse(buckets); buckets = JSON.parse(buckets);
let newData = []; const newData = [];
for (let bucket of buckets) { for (const bucket of buckets) {
let decrypted = encryption.decrypt(bucket, this.cachedPassword); const decrypted = encryption.decrypt(bucket, this.cachedPassword);
if (!decrypted) { if (!decrypted) {
// no luck decrypting, its not our bucket // no luck decrypting, its not our bucket
newData.push(bucket); newData.push(bucket);
@ -411,13 +412,13 @@ export class AppStorage {
console.log('fetchWalletBalances for wallet#', typeof index === 'undefined' ? '(all)' : index); console.log('fetchWalletBalances for wallet#', typeof index === 'undefined' ? '(all)' : index);
if (index || index === 0) { if (index || index === 0) {
let c = 0; let c = 0;
for (let wallet of this.wallets.filter(wallet => wallet.type !== PlaceholderWallet.type)) { for (const wallet of this.wallets.filter(wallet => wallet.type !== PlaceholderWallet.type)) {
if (c++ === index) { if (c++ === index) {
await wallet.fetchBalance(); await wallet.fetchBalance();
} }
} }
} else { } else {
for (let wallet of this.wallets.filter(wallet => wallet.type !== PlaceholderWallet.type)) { for (const wallet of this.wallets.filter(wallet => wallet.type !== PlaceholderWallet.type)) {
await wallet.fetchBalance(); await wallet.fetchBalance();
} }
} }
@ -437,7 +438,7 @@ export class AppStorage {
console.log('fetchWalletTransactions for wallet#', typeof index === 'undefined' ? '(all)' : index); console.log('fetchWalletTransactions for wallet#', typeof index === 'undefined' ? '(all)' : index);
if (index || index === 0) { if (index || index === 0) {
let c = 0; let c = 0;
for (let wallet of this.wallets.filter(wallet => wallet.type !== PlaceholderWallet.type)) { for (const wallet of this.wallets.filter(wallet => wallet.type !== PlaceholderWallet.type)) {
if (c++ === index) { if (c++ === index) {
await wallet.fetchTransactions(); await wallet.fetchTransactions();
if (wallet.fetchPendingTransactions) { if (wallet.fetchPendingTransactions) {
@ -449,7 +450,7 @@ export class AppStorage {
} }
} }
} else { } else {
for (let wallet of this.wallets) { for (const wallet of this.wallets) {
await wallet.fetchTransactions(); await wallet.fetchTransactions();
if (wallet.fetchPendingTransactions) { if (wallet.fetchPendingTransactions) {
await wallet.fetchPendingTransactions(); await wallet.fetchPendingTransactions();
@ -481,7 +482,7 @@ export class AppStorage {
if (index || index === 0) { if (index || index === 0) {
let txs = []; let txs = [];
let c = 0; let c = 0;
for (let wallet of this.wallets) { for (const wallet of this.wallets) {
if (c++ === index) { if (c++ === index) {
txs = txs.concat(wallet.getTransactions()); txs = txs.concat(wallet.getTransactions());
} }
@ -490,20 +491,20 @@ export class AppStorage {
} }
let txs = []; let txs = [];
for (let wallet of this.wallets) { for (const wallet of this.wallets) {
let walletTransactions = wallet.getTransactions(); const walletTransactions = wallet.getTransactions();
for (let t of walletTransactions) { for (const t of walletTransactions) {
t.walletPreferredBalanceUnit = wallet.getPreferredBalanceUnit(); t.walletPreferredBalanceUnit = wallet.getPreferredBalanceUnit();
} }
txs = txs.concat(walletTransactions); txs = txs.concat(walletTransactions);
} }
for (let t of txs) { for (const t of txs) {
t.sort_ts = +new Date(t.received); t.sort_ts = +new Date(t.received);
} }
return txs return txs
.sort(function(a, b) { .sort(function (a, b) {
return b.sort_ts - a.sort_ts; return b.sort_ts - a.sort_ts;
}) })
.slice(0, limit); .slice(0, limit);
@ -516,7 +517,7 @@ export class AppStorage {
*/ */
getBalance() { getBalance() {
let finalBalance = 0; let finalBalance = 0;
for (let wal of this.wallets) { for (const wal of this.wallets) {
finalBalance += wal.getBalance(); finalBalance += wal.getBalance();
} }
return finalBalance; return finalBalance;

View file

@ -17,7 +17,7 @@ export default class Azteco {
const url = `/blue_despatch.php?CODE_1=${voucher[0]}&CODE_2=${voucher[1]}&CODE_3=${voucher[2]}&CODE_4=${voucher[3]}&ADDRESS=${address}`; const url = `/blue_despatch.php?CODE_1=${voucher[0]}&CODE_2=${voucher[1]}&CODE_3=${voucher[2]}&CODE_4=${voucher[3]}&ADDRESS=${address}`;
try { try {
let response = await api.get(url); const response = await api.get(url);
return response && response.originalResponse && +response.originalResponse.status === 200; return response && response.originalResponse && +response.originalResponse.status === 200;
} catch (_) { } catch (_) {
return false; return false;
@ -29,7 +29,7 @@ export default class Azteco {
} }
static getParamsFromUrl(u) { static getParamsFromUrl(u) {
let urlObject = url.parse(u, true); // eslint-disable-line const urlObject = url.parse(u, true); // eslint-disable-line node/no-deprecated-api
return { return {
uri: u, uri: u,
c1: urlObject.query.c1, c1: urlObject.query.c1,

View file

@ -108,7 +108,7 @@ class DeeplinkSchemaMatch {
}, },
]); ]);
} else if (DeeplinkSchemaMatch.isSafelloRedirect(event)) { } else if (DeeplinkSchemaMatch.isSafelloRedirect(event)) {
let urlObject = url.parse(event.url, true) // eslint-disable-line const urlObject = url.parse(event.url, true); // eslint-disable-line node/no-deprecated-api
const safelloStateToken = urlObject.query['safello-state-token']; const safelloStateToken = urlObject.query['safello-state-token'];
@ -128,16 +128,16 @@ class DeeplinkSchemaMatch {
}, },
]); ]);
} else { } else {
let urlObject = url.parse(event.url, true); // eslint-disable-line const urlObject = url.parse(event.url, true); // eslint-disable-line node/no-deprecated-api
console.log('parsed', event.url, 'into', urlObject); console.log('parsed', event.url, 'into', urlObject);
(async () => { (async () => {
if (urlObject.protocol === 'bluewallet:' || urlObject.protocol === 'lapp:' || urlObject.protocol === 'blue:') { if (urlObject.protocol === 'bluewallet:' || urlObject.protocol === 'lapp:' || urlObject.protocol === 'blue:') {
switch (urlObject.host) { switch (urlObject.host) {
case 'openlappbrowser': case 'openlappbrowser': {
console.log('opening LAPP', urlObject.query.url); console.log('opening LAPP', urlObject.query.url);
// searching for LN wallet: // searching for LN wallet:
let haveLnWallet = false; let haveLnWallet = false;
for (let w of BlueApp.getWallets()) { for (const w of BlueApp.getWallets()) {
if (w.type === LightningCustodianWallet.type) { if (w.type === LightningCustodianWallet.type) {
haveLnWallet = true; haveLnWallet = true;
} }
@ -145,11 +145,11 @@ class DeeplinkSchemaMatch {
if (!haveLnWallet) { if (!haveLnWallet) {
// need to create one // need to create one
let w = new LightningCustodianWallet(); const w = new LightningCustodianWallet();
w.setLabel(w.typeReadable); w.setLabel(w.typeReadable);
try { try {
let lndhub = await AsyncStorage.getItem(AppStorage.LNDHUB); const lndhub = await AsyncStorage.getItem(AppStorage.LNDHUB);
if (lndhub) { if (lndhub) {
w.setBaseURI(lndhub); w.setBaseURI(lndhub);
w.init(); w.init();
@ -167,7 +167,7 @@ class DeeplinkSchemaMatch {
// now, opening lapp browser and navigating it to URL. // now, opening lapp browser and navigating it to URL.
// looking for a LN wallet: // looking for a LN wallet:
let lnWallet; let lnWallet;
for (let w of BlueApp.getWallets()) { for (const w of BlueApp.getWallets()) {
if (w.type === LightningCustodianWallet.type) { if (w.type === LightningCustodianWallet.type) {
lnWallet = w; lnWallet = w;
break; break;
@ -188,6 +188,7 @@ class DeeplinkSchemaMatch {
}, },
]); ]);
break; break;
}
} }
} }
})(); })();
@ -223,11 +224,7 @@ class DeeplinkSchemaMatch {
} }
static isBitcoinAddress(address) { static isBitcoinAddress(address) {
address = address address = address.replace('bitcoin:', '').replace('BITCOIN:', '').replace('bitcoin=', '').split('?')[0];
.replace('bitcoin:', '')
.replace('BITCOIN:', '')
.replace('bitcoin=', '')
.split('?')[0];
let isValidBitcoinAddress = false; let isValidBitcoinAddress = false;
try { try {
bitcoin.address.toOutputScript(address); bitcoin.address.toOutputScript(address);
@ -254,7 +251,7 @@ class DeeplinkSchemaMatch {
} }
static isSafelloRedirect(event) { static isSafelloRedirect(event) {
let urlObject = url.parse(event.url, true) // eslint-disable-line const urlObject = url.parse(event.url, true); // eslint-disable-line node/no-deprecated-api
return !!urlObject.query['safello-state-token']; return !!urlObject.query['safello-state-token'];
} }

View file

@ -39,7 +39,7 @@ export class HDSegwitBech32Transaction {
* @private * @private
*/ */
async _fetchTxhexAndDecode() { async _fetchTxhexAndDecode() {
let hexes = await BlueElectrum.multiGetTransactionByTxid([this._txid], 10, false); const hexes = await BlueElectrum.multiGetTransactionByTxid([this._txid], 10, false);
this._txhex = hexes[this._txid]; this._txhex = hexes[this._txid];
if (!this._txhex) throw new Error("Transaction can't be found in mempool"); if (!this._txhex) throw new Error("Transaction can't be found in mempool");
this._txDecoded = bitcoin.Transaction.fromHex(this._txhex); this._txDecoded = bitcoin.Transaction.fromHex(this._txhex);
@ -55,7 +55,7 @@ export class HDSegwitBech32Transaction {
if (!this._txDecoded) await this._fetchTxhexAndDecode(); if (!this._txDecoded) await this._fetchTxhexAndDecode();
let max = 0; let max = 0;
for (let inp of this._txDecoded.ins) { for (const inp of this._txDecoded.ins) {
max = Math.max(inp.sequence, max); max = Math.max(inp.sequence, max);
} }
@ -80,7 +80,7 @@ export class HDSegwitBech32Transaction {
* @private * @private
*/ */
async _fetchRemoteTx() { async _fetchRemoteTx() {
let result = await BlueElectrum.multiGetTransactionByTxid([this._txid || this._txDecoded.getId()]); const result = await BlueElectrum.multiGetTransactionByTxid([this._txid || this._txDecoded.getId()]);
this._remoteTx = Object.values(result)[0]; this._remoteTx = Object.values(result)[0];
} }
@ -104,7 +104,7 @@ export class HDSegwitBech32Transaction {
async isOurTransaction() { async isOurTransaction() {
if (!this._wallet) throw new Error('Wallet required for this method'); if (!this._wallet) throw new Error('Wallet required for this method');
let found = false; let found = false;
for (let tx of this._wallet.getTransactions()) { for (const tx of this._wallet.getTransactions()) {
if (tx.txid === (this._txid || this._txDecoded.getId())) { if (tx.txid === (this._txid || this._txDecoded.getId())) {
// its our transaction, and its spending transaction, which means we initiated it // its our transaction, and its spending transaction, which means we initiated it
if (tx.value < 0) found = true; if (tx.value < 0) found = true;
@ -123,7 +123,7 @@ export class HDSegwitBech32Transaction {
async isToUsTransaction() { async isToUsTransaction() {
if (!this._wallet) throw new Error('Wallet required for this method'); if (!this._wallet) throw new Error('Wallet required for this method');
let found = false; let found = false;
for (let tx of this._wallet.getTransactions()) { for (const tx of this._wallet.getTransactions()) {
if (tx.txid === (this._txid || this._txDecoded.getId())) { if (tx.txid === (this._txid || this._txDecoded.getId())) {
if (tx.value > 0) found = true; if (tx.value > 0) found = true;
} }
@ -147,26 +147,26 @@ export class HDSegwitBech32Transaction {
if (!this._remoteTx) await this._fetchRemoteTx(); if (!this._remoteTx) await this._fetchRemoteTx();
if (!this._txDecoded) await this._fetchTxhexAndDecode(); if (!this._txDecoded) await this._fetchTxhexAndDecode();
let prevInputs = []; const prevInputs = [];
for (let inp of this._txDecoded.ins) { for (const inp of this._txDecoded.ins) {
let reversedHash = Buffer.from(reverse(inp.hash)); let reversedHash = Buffer.from(reverse(inp.hash));
reversedHash = reversedHash.toString('hex'); reversedHash = reversedHash.toString('hex');
prevInputs.push(reversedHash); prevInputs.push(reversedHash);
} }
let prevTransactions = await BlueElectrum.multiGetTransactionByTxid(prevInputs); const prevTransactions = await BlueElectrum.multiGetTransactionByTxid(prevInputs);
// fetched, now lets count how much satoshis went in // fetched, now lets count how much satoshis went in
let wentIn = 0; let wentIn = 0;
let utxos = []; const utxos = [];
for (let inp of this._txDecoded.ins) { for (const inp of this._txDecoded.ins) {
let reversedHash = Buffer.from(reverse(inp.hash)); let reversedHash = Buffer.from(reverse(inp.hash));
reversedHash = reversedHash.toString('hex'); reversedHash = reversedHash.toString('hex');
if (prevTransactions[reversedHash] && prevTransactions[reversedHash].vout && prevTransactions[reversedHash].vout[inp.index]) { if (prevTransactions[reversedHash] && prevTransactions[reversedHash].vout && prevTransactions[reversedHash].vout[inp.index]) {
let value = prevTransactions[reversedHash].vout[inp.index].value; let value = prevTransactions[reversedHash].vout[inp.index].value;
value = new BigNumber(value).multipliedBy(100000000).toNumber(); value = new BigNumber(value).multipliedBy(100000000).toNumber();
wentIn += value; wentIn += value;
let address = SegwitBech32Wallet.witnessToAddress(inp.witness[inp.witness.length - 1]); const address = SegwitBech32Wallet.witnessToAddress(inp.witness[inp.witness.length - 1]);
utxos.push({ vout: inp.index, value: value, txId: reversedHash, address: address }); utxos.push({ vout: inp.index, value: value, txId: reversedHash, address: address });
} }
} }
@ -174,20 +174,20 @@ export class HDSegwitBech32Transaction {
// counting how much went into actual outputs // counting how much went into actual outputs
let wasSpent = 0; let wasSpent = 0;
for (let outp of this._txDecoded.outs) { for (const outp of this._txDecoded.outs) {
wasSpent += +outp.value; wasSpent += +outp.value;
} }
let fee = wentIn - wasSpent; const fee = wentIn - wasSpent;
let feeRate = Math.floor(fee / (this._txhex.length / 2)); let feeRate = Math.floor(fee / (this._txhex.length / 2));
if (feeRate === 0) feeRate = 1; if (feeRate === 0) feeRate = 1;
// lets take a look at change // lets take a look at change
let changeAmount = 0; let changeAmount = 0;
let targets = []; const targets = [];
for (let outp of this._remoteTx.vout) { for (const outp of this._remoteTx.vout) {
let address = outp.scriptPubKey.addresses[0]; const address = outp.scriptPubKey.addresses[0];
let value = new BigNumber(outp.value).multipliedBy(100000000).toNumber(); const value = new BigNumber(outp.value).multipliedBy(100000000).toNumber();
if (this._wallet.weOwnAddress(address)) { if (this._wallet.weOwnAddress(address)) {
changeAmount += value; changeAmount += value;
} else { } else {
@ -197,10 +197,10 @@ export class HDSegwitBech32Transaction {
} }
// lets find outputs we own that current transaction creates. can be used in CPFP // lets find outputs we own that current transaction creates. can be used in CPFP
let unconfirmedUtxos = []; const unconfirmedUtxos = [];
for (let outp of this._remoteTx.vout) { for (const outp of this._remoteTx.vout) {
let address = outp.scriptPubKey.addresses[0]; const address = outp.scriptPubKey.addresses[0];
let value = new BigNumber(outp.value).multipliedBy(100000000).toNumber(); const value = new BigNumber(outp.value).multipliedBy(100000000).toNumber();
if (this._wallet.weOwnAddress(address)) { if (this._wallet.weOwnAddress(address)) {
unconfirmedUtxos.push({ unconfirmedUtxos.push({
vout: outp.n, vout: outp.n,
@ -225,7 +225,7 @@ export class HDSegwitBech32Transaction {
if (!this._txDecoded) await this._fetchTxhexAndDecode(); if (!this._txDecoded) await this._fetchTxhexAndDecode();
// if theres at least one output we dont own - we can cancel this transaction! // if theres at least one output we dont own - we can cancel this transaction!
for (let outp of this._txDecoded.outs) { for (const outp of this._txDecoded.outs) {
if (!this._wallet.weOwnAddress(SegwitBech32Wallet.scriptPubKeyToAddress(outp.script))) return true; if (!this._wallet.weOwnAddress(SegwitBech32Wallet.scriptPubKeyToAddress(outp.script))) return true;
} }
@ -244,10 +244,10 @@ export class HDSegwitBech32Transaction {
if (!this._wallet) throw new Error('Wallet required for this method'); if (!this._wallet) throw new Error('Wallet required for this method');
if (!this._remoteTx) await this._fetchRemoteTx(); if (!this._remoteTx) await this._fetchRemoteTx();
let { feeRate, utxos } = await this.getInfo(); const { feeRate, utxos } = await this.getInfo();
if (newFeerate <= feeRate) throw new Error('New feerate should be bigger than the old one'); if (newFeerate <= feeRate) throw new Error('New feerate should be bigger than the old one');
let myAddress = await this._wallet.getChangeAddressAsync(); const myAddress = await this._wallet.getChangeAddressAsync();
return this._wallet.createTransaction( return this._wallet.createTransaction(
utxos, utxos,
@ -269,10 +269,10 @@ export class HDSegwitBech32Transaction {
if (!this._wallet) throw new Error('Wallet required for this method'); if (!this._wallet) throw new Error('Wallet required for this method');
if (!this._remoteTx) await this._fetchRemoteTx(); if (!this._remoteTx) await this._fetchRemoteTx();
let { feeRate, targets, changeAmount, utxos } = await this.getInfo(); const { feeRate, targets, changeAmount, utxos } = await this.getInfo();
if (newFeerate <= feeRate) throw new Error('New feerate should be bigger than the old one'); if (newFeerate <= feeRate) throw new Error('New feerate should be bigger than the old one');
let myAddress = await this._wallet.getChangeAddressAsync(); const myAddress = await this._wallet.getChangeAddressAsync();
if (changeAmount === 0) delete targets[0].value; if (changeAmount === 0) delete targets[0].value;
// looks like this was sendMAX transaction (because there was no change), so we cant reuse amount in this // looks like this was sendMAX transaction (because there was no change), so we cant reuse amount in this
@ -299,10 +299,10 @@ export class HDSegwitBech32Transaction {
if (!this._wallet) throw new Error('Wallet required for this method'); if (!this._wallet) throw new Error('Wallet required for this method');
if (!this._remoteTx) await this._fetchRemoteTx(); if (!this._remoteTx) await this._fetchRemoteTx();
let { feeRate, fee: oldFee, unconfirmedUtxos } = await this.getInfo(); const { feeRate, fee: oldFee, unconfirmedUtxos } = await this.getInfo();
if (newFeerate <= feeRate) throw new Error('New feerate should be bigger than the old one'); if (newFeerate <= feeRate) throw new Error('New feerate should be bigger than the old one');
let myAddress = await this._wallet.getChangeAddressAsync(); const myAddress = await this._wallet.getChangeAddressAsync();
// calculating feerate for CPFP tx so that average between current and CPFP tx will equal newFeerate. // calculating feerate for CPFP tx so that average between current and CPFP tx will equal newFeerate.
// this works well if both txs are +/- equal size in bytes // this works well if both txs are +/- equal size in bytes
@ -317,7 +317,7 @@ export class HDSegwitBech32Transaction {
myAddress, myAddress,
HDSegwitBech32Wallet.defaultRBFSequence, HDSegwitBech32Wallet.defaultRBFSequence,
); );
let combinedFeeRate = (oldFee + fee) / (this._txhex.length / 2 + tx.toHex().length / 2); // avg const combinedFeeRate = (oldFee + fee) / (this._txhex.length / 2 + tx.toHex().length / 2); // avg
if (Math.round(combinedFeeRate) < newFeerate) { if (Math.round(combinedFeeRate) < newFeerate) {
add *= 2; add *= 2;
if (!add) add = 2; if (!add) add = 2;

View file

@ -62,9 +62,9 @@ export class HodlHodlApi {
} }
async getCountries() { async getCountries() {
let response = await this._api.get('/api/v1/countries', this._getHeaders()); const response = await this._api.get('/api/v1/countries', this._getHeaders());
let json = response.body; const json = response.body;
if (!json || !json.countries || json.status === 'error') { if (!json || !json.countries || json.status === 'error') {
throw new Error('API failure: ' + JSON.stringify(response)); throw new Error('API failure: ' + JSON.stringify(response));
} }
@ -73,7 +73,7 @@ export class HodlHodlApi {
} }
async getMyCountryCode() { async getMyCountryCode() {
let _api = new Frisbee({ baseURI: 'https://ifconfig.co/' }); const _api = new Frisbee({ baseURI: 'https://ifconfig.co/' });
let response; let response;
let allowedTries = 6; let allowedTries = 6;
@ -97,9 +97,9 @@ export class HodlHodlApi {
} }
async getPaymentMethods(country) { async getPaymentMethods(country) {
let response = await this._api.get('/api/v1/payment_methods?filters[country]=' + country, this._getHeaders()); const response = await this._api.get('/api/v1/payment_methods?filters[country]=' + country, this._getHeaders());
let json = response.body; const json = response.body;
if (!json || !json.payment_methods || json.status === 'error') { if (!json || !json.payment_methods || json.status === 'error') {
throw new Error('API failure: ' + JSON.stringify(response)); throw new Error('API failure: ' + JSON.stringify(response));
} }
@ -108,9 +108,9 @@ export class HodlHodlApi {
} }
async getCurrencies() { async getCurrencies() {
let response = await this._api.get('/api/v1/currencies', this._getHeaders()); const response = await this._api.get('/api/v1/currencies', this._getHeaders());
let json = response.body; const json = response.body;
if (!json || !json.currencies || json.status === 'error') { if (!json || !json.currencies || json.status === 'error') {
throw new Error('API failure: ' + JSON.stringify(response)); throw new Error('API failure: ' + JSON.stringify(response));
} }
@ -119,19 +119,19 @@ export class HodlHodlApi {
} }
async getOffers(pagination = {}, filters = {}, sort = {}) { async getOffers(pagination = {}, filters = {}, sort = {}) {
let uri = []; const uri = [];
for (let key in sort) { for (const key in sort) {
uri.push('sort[' + key + ']=' + sort[key]); uri.push('sort[' + key + ']=' + sort[key]);
} }
for (let key in filters) { for (const key in filters) {
uri.push('filters[' + key + ']=' + filters[key]); uri.push('filters[' + key + ']=' + filters[key]);
} }
for (let key in pagination) { for (const key in pagination) {
uri.push('pagination[' + key + ']=' + pagination[key]); uri.push('pagination[' + key + ']=' + pagination[key]);
} }
let response = await this._api.get('/api/v1/offers?' + uri.join('&'), this._getHeadersWithoutAuthorization()); const response = await this._api.get('/api/v1/offers?' + uri.join('&'), this._getHeadersWithoutAuthorization());
let json = response.body; const json = response.body;
if (!json || !json.offers || json.status === 'error') { if (!json || !json.offers || json.status === 'error') {
throw new Error('API failure: ' + JSON.stringify(response)); throw new Error('API failure: ' + JSON.stringify(response));
} }

View file

@ -19,7 +19,7 @@ export default class DeviceQuickActions {
} }
QuickActions.isSupported((error, _supported) => { QuickActions.isSupported((error, _supported) => {
if (error === null) { if (error === null) {
let shortcutItems = []; const shortcutItems = [];
const loc = require('../loc'); const loc = require('../loc');
for (const wallet of DeviceQuickActions.shared.wallets) { for (const wallet of DeviceQuickActions.shared.wallets) {
shortcutItems.push({ shortcutItems.push({

View file

@ -113,7 +113,7 @@ export default class WalletImport {
password = await prompt('This looks like password-protected private key (BIP38)', 'Enter password to decrypt', false); password = await prompt('This looks like password-protected private key (BIP38)', 'Enter password to decrypt', false);
} while (!password); } while (!password);
let decryptedKey = await bip38.decrypt(importText, password, status => { const decryptedKey = await bip38.decrypt(importText, password, status => {
console.warn(status.percent + '%'); console.warn(status.percent + '%');
}); });
@ -124,7 +124,7 @@ export default class WalletImport {
// is it lightning custodian? // is it lightning custodian?
if (importText.indexOf('blitzhub://') !== -1 || importText.indexOf('lndhub://') !== -1) { if (importText.indexOf('blitzhub://') !== -1 || importText.indexOf('lndhub://') !== -1) {
let lnd = new LightningCustodianWallet(); const lnd = new LightningCustodianWallet();
if (importText.includes('@')) { if (importText.includes('@')) {
const split = importText.split('@'); const split = importText.split('@');
lnd.setBaseURI(split[1]); lnd.setBaseURI(split[1]);
@ -144,7 +144,7 @@ export default class WalletImport {
// trying other wallet types // trying other wallet types
let hd4 = new HDSegwitBech32Wallet(); const hd4 = new HDSegwitBech32Wallet();
hd4.setSecret(importText); hd4.setSecret(importText);
if (hd4.validateMnemonic()) { if (hd4.validateMnemonic()) {
await hd4.fetchBalance(); await hd4.fetchBalance();
@ -154,15 +154,15 @@ export default class WalletImport {
} }
} }
let segwitWallet = new SegwitP2SHWallet(); const segwitWallet = new SegwitP2SHWallet();
segwitWallet.setSecret(importText); segwitWallet.setSecret(importText);
if (segwitWallet.getAddress()) { if (segwitWallet.getAddress()) {
// ok its a valid WIF // ok its a valid WIF
let legacyWallet = new LegacyWallet(); const legacyWallet = new LegacyWallet();
legacyWallet.setSecret(importText); legacyWallet.setSecret(importText);
let segwitBech32Wallet = new SegwitBech32Wallet(); const segwitBech32Wallet = new SegwitBech32Wallet();
segwitBech32Wallet.setSecret(importText); segwitBech32Wallet.setSecret(importText);
await legacyWallet.fetchBalance(); await legacyWallet.fetchBalance();
@ -185,7 +185,7 @@ export default class WalletImport {
// case - WIF is valid, just has uncompressed pubkey // case - WIF is valid, just has uncompressed pubkey
let legacyWallet = new LegacyWallet(); const legacyWallet = new LegacyWallet();
legacyWallet.setSecret(importText); legacyWallet.setSecret(importText);
if (legacyWallet.getAddress()) { if (legacyWallet.getAddress()) {
await legacyWallet.fetchBalance(); await legacyWallet.fetchBalance();
@ -195,7 +195,7 @@ export default class WalletImport {
// if we're here - nope, its not a valid WIF // if we're here - nope, its not a valid WIF
let hd1 = new HDLegacyBreadwalletWallet(); const hd1 = new HDLegacyBreadwalletWallet();
hd1.setSecret(importText); hd1.setSecret(importText);
if (hd1.validateMnemonic()) { if (hd1.validateMnemonic()) {
await hd1.fetchBalance(); await hd1.fetchBalance();
@ -206,7 +206,7 @@ export default class WalletImport {
} }
try { try {
let hdElectrumSeedLegacy = new HDSegwitElectrumSeedP2WPKHWallet(); const hdElectrumSeedLegacy = new HDSegwitElectrumSeedP2WPKHWallet();
hdElectrumSeedLegacy.setSecret(importText); hdElectrumSeedLegacy.setSecret(importText);
if (await hdElectrumSeedLegacy.wasEverUsed()) { if (await hdElectrumSeedLegacy.wasEverUsed()) {
// not fetching txs or balances, fuck it, yolo, life is too short // not fetching txs or balances, fuck it, yolo, life is too short
@ -215,7 +215,7 @@ export default class WalletImport {
} catch (_) {} } catch (_) {}
try { try {
let hdElectrumSeedLegacy = new HDLegacyElectrumSeedP2PKHWallet(); const hdElectrumSeedLegacy = new HDLegacyElectrumSeedP2PKHWallet();
hdElectrumSeedLegacy.setSecret(importText); hdElectrumSeedLegacy.setSecret(importText);
if (await hdElectrumSeedLegacy.wasEverUsed()) { if (await hdElectrumSeedLegacy.wasEverUsed()) {
// not fetching txs or balances, fuck it, yolo, life is too short // not fetching txs or balances, fuck it, yolo, life is too short
@ -223,7 +223,7 @@ export default class WalletImport {
} }
} catch (_) {} } catch (_) {}
let hd2 = new HDSegwitP2SHWallet(); const hd2 = new HDSegwitP2SHWallet();
hd2.setSecret(importText); hd2.setSecret(importText);
if (hd2.validateMnemonic()) { if (hd2.validateMnemonic()) {
await hd2.fetchBalance(); await hd2.fetchBalance();
@ -233,7 +233,7 @@ export default class WalletImport {
} }
} }
let hd3 = new HDLegacyP2PKHWallet(); const hd3 = new HDLegacyP2PKHWallet();
hd3.setSecret(importText); hd3.setSecret(importText);
if (hd3.validateMnemonic()) { if (hd3.validateMnemonic()) {
await hd3.fetchBalance(); await hd3.fetchBalance();
@ -277,7 +277,7 @@ export default class WalletImport {
// not valid? maybe its a watch-only address? // not valid? maybe its a watch-only address?
let watchOnly = new WatchOnlyWallet(); const watchOnly = new WatchOnlyWallet();
watchOnly.setSecret(importText); watchOnly.setSecret(importText);
if (watchOnly.valid()) { if (watchOnly.valid()) {
// await watchOnly.fetchTransactions(); // experiment: dont fetch tx now. it will import faster. user can refresh his wallet later // await watchOnly.fetchTransactions(); // experiment: dont fetch tx now. it will import faster. user can refresh his wallet later

View file

@ -35,10 +35,10 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
*/ */
getBalance() { getBalance() {
let ret = 0; let ret = 0;
for (let bal of Object.values(this._balances_by_external_index)) { for (const bal of Object.values(this._balances_by_external_index)) {
ret += bal.c; ret += bal.c;
} }
for (let bal of Object.values(this._balances_by_internal_index)) { for (const bal of Object.values(this._balances_by_internal_index)) {
ret += bal.c; ret += bal.c;
} }
return ret + (this.getUnconfirmedBalance() < 0 ? this.getUnconfirmedBalance() : 0); return ret + (this.getUnconfirmedBalance() < 0 ? this.getUnconfirmedBalance() : 0);
@ -48,7 +48,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
* @inheritDoc * @inheritDoc
*/ */
timeToRefreshTransaction() { timeToRefreshTransaction() {
for (let tx of this.getTransactions()) { for (const tx of this.getTransactions()) {
if (tx.confirmations < 7) return true; if (tx.confirmations < 7) return true;
} }
return false; return false;
@ -60,10 +60,10 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
*/ */
getUnconfirmedBalance() { getUnconfirmedBalance() {
let ret = 0; let ret = 0;
for (let bal of Object.values(this._balances_by_external_index)) { for (const bal of Object.values(this._balances_by_external_index)) {
ret += bal.u; ret += bal.u;
} }
for (let bal of Object.values(this._balances_by_internal_index)) { for (const bal of Object.values(this._balances_by_internal_index)) {
ret += bal.u; ret += bal.u;
} }
return ret; return ret;
@ -215,13 +215,13 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
// finally, batch fetching txids of all inputs (needed to see amounts & addresses of those inputs) // finally, batch fetching txids of all inputs (needed to see amounts & addresses of those inputs)
// then we combine it all together // then we combine it all together
let addresses2fetch = []; const addresses2fetch = [];
for (let c = 0; c < this.next_free_address_index + this.gap_limit; c++) { for (let c = 0; c < this.next_free_address_index + this.gap_limit; c++) {
// external addresses first // external addresses first
let hasUnconfirmed = false; let hasUnconfirmed = false;
this._txs_by_external_index[c] = this._txs_by_external_index[c] || []; this._txs_by_external_index[c] = this._txs_by_external_index[c] || [];
for (let tx of this._txs_by_external_index[c]) hasUnconfirmed = hasUnconfirmed || !tx.confirmations || tx.confirmations < 7; for (const tx of this._txs_by_external_index[c]) hasUnconfirmed = hasUnconfirmed || !tx.confirmations || tx.confirmations < 7;
if (hasUnconfirmed || this._txs_by_external_index[c].length === 0 || this._balances_by_external_index[c].u !== 0) { if (hasUnconfirmed || this._txs_by_external_index[c].length === 0 || this._balances_by_external_index[c].u !== 0) {
addresses2fetch.push(this._getExternalAddressByIndex(c)); addresses2fetch.push(this._getExternalAddressByIndex(c));
@ -232,7 +232,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
// next, internal addresses // next, internal addresses
let hasUnconfirmed = false; let hasUnconfirmed = false;
this._txs_by_internal_index[c] = this._txs_by_internal_index[c] || []; this._txs_by_internal_index[c] = this._txs_by_internal_index[c] || [];
for (let tx of this._txs_by_internal_index[c]) hasUnconfirmed = hasUnconfirmed || !tx.confirmations || tx.confirmations < 7; for (const tx of this._txs_by_internal_index[c]) hasUnconfirmed = hasUnconfirmed || !tx.confirmations || tx.confirmations < 7;
if (hasUnconfirmed || this._txs_by_internal_index[c].length === 0 || this._balances_by_internal_index[c].u !== 0) { if (hasUnconfirmed || this._txs_by_internal_index[c].length === 0 || this._balances_by_internal_index[c].u !== 0) {
addresses2fetch.push(this._getInternalAddressByIndex(c)); addresses2fetch.push(this._getInternalAddressByIndex(c));
@ -240,34 +240,34 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
} }
// first: batch fetch for all addresses histories // first: batch fetch for all addresses histories
let histories = await BlueElectrum.multiGetHistoryByAddress(addresses2fetch); const histories = await BlueElectrum.multiGetHistoryByAddress(addresses2fetch);
let txs = {}; const txs = {};
for (let history of Object.values(histories)) { for (const history of Object.values(histories)) {
for (let tx of history) { for (const tx of history) {
txs[tx.tx_hash] = tx; txs[tx.tx_hash] = tx;
} }
} }
// next, batch fetching each txid we got // next, batch fetching each txid we got
let txdatas = await BlueElectrum.multiGetTransactionByTxid(Object.keys(txs)); const txdatas = await BlueElectrum.multiGetTransactionByTxid(Object.keys(txs));
// now, tricky part. we collect all transactions from inputs (vin), and batch fetch them too. // 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) // then we combine all this data (we need inputs to see source addresses and amounts)
let vinTxids = []; const vinTxids = [];
for (let txdata of Object.values(txdatas)) { for (const txdata of Object.values(txdatas)) {
for (let vin of txdata.vin) { for (const vin of txdata.vin) {
vinTxids.push(vin.txid); vinTxids.push(vin.txid);
} }
} }
let vintxdatas = await BlueElectrum.multiGetTransactionByTxid(vinTxids); const vintxdatas = await BlueElectrum.multiGetTransactionByTxid(vinTxids);
// fetched all transactions from our inputs. now we need to combine it. // fetched all transactions from our inputs. now we need to combine it.
// iterating all _our_ transactions: // iterating all _our_ transactions:
for (let txid of Object.keys(txdatas)) { for (const txid of Object.keys(txdatas)) {
// iterating all inputs our our single transaction: // iterating all inputs our our single transaction:
for (let inpNum = 0; inpNum < txdatas[txid].vin.length; inpNum++) { for (let inpNum = 0; inpNum < txdatas[txid].vin.length; inpNum++) {
let inpTxid = txdatas[txid].vin[inpNum].txid; const inpTxid = txdatas[txid].vin[inpNum].txid;
let inpVout = txdatas[txid].vin[inpNum].vout; const inpVout = txdatas[txid].vin[inpNum].vout;
// got txid and output number of _previous_ transaction we shoud look into // got txid and output number of _previous_ transaction we shoud look into
if (vintxdatas[inpTxid] && vintxdatas[inpTxid].vout[inpVout]) { if (vintxdatas[inpTxid] && vintxdatas[inpTxid].vout[inpVout]) {
// extracting amount & addresses from previous output and adding it to _our_ input: // extracting amount & addresses from previous output and adding it to _our_ input:
@ -289,12 +289,12 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
// now, we need to put transactions in all relevant `cells` of internal hashmaps: this._txs_by_internal_index && this._txs_by_external_index // now, we need to put transactions in all relevant `cells` of internal hashmaps: this._txs_by_internal_index && this._txs_by_external_index
for (let c = 0; c < this.next_free_address_index + this.gap_limit; c++) { for (let c = 0; c < this.next_free_address_index + this.gap_limit; c++) {
for (let tx of Object.values(txdatas)) { for (const tx of Object.values(txdatas)) {
for (let vin of tx.vin) { for (const vin of tx.vin) {
if (vin.addresses && vin.addresses.indexOf(this._getExternalAddressByIndex(c)) !== -1) { if (vin.addresses && vin.addresses.indexOf(this._getExternalAddressByIndex(c)) !== -1) {
// this TX is related to our address // this TX is related to our address
this._txs_by_external_index[c] = this._txs_by_external_index[c] || []; this._txs_by_external_index[c] = this._txs_by_external_index[c] || [];
let clonedTx = Object.assign({}, tx); const clonedTx = Object.assign({}, tx);
clonedTx.inputs = tx.vin.slice(0); clonedTx.inputs = tx.vin.slice(0);
clonedTx.outputs = tx.vout.slice(0); clonedTx.outputs = tx.vout.slice(0);
delete clonedTx.vin; delete clonedTx.vin;
@ -311,11 +311,11 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
if (!replaced) this._txs_by_external_index[c].push(clonedTx); if (!replaced) this._txs_by_external_index[c].push(clonedTx);
} }
} }
for (let vout of tx.vout) { for (const vout of tx.vout) {
if (vout.scriptPubKey.addresses && vout.scriptPubKey.addresses.indexOf(this._getExternalAddressByIndex(c)) !== -1) { if (vout.scriptPubKey.addresses && vout.scriptPubKey.addresses.indexOf(this._getExternalAddressByIndex(c)) !== -1) {
// this TX is related to our address // this TX is related to our address
this._txs_by_external_index[c] = this._txs_by_external_index[c] || []; this._txs_by_external_index[c] = this._txs_by_external_index[c] || [];
let clonedTx = Object.assign({}, tx); const clonedTx = Object.assign({}, tx);
clonedTx.inputs = tx.vin.slice(0); clonedTx.inputs = tx.vin.slice(0);
clonedTx.outputs = tx.vout.slice(0); clonedTx.outputs = tx.vout.slice(0);
delete clonedTx.vin; delete clonedTx.vin;
@ -336,12 +336,12 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
} }
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) { for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
for (let tx of Object.values(txdatas)) { for (const tx of Object.values(txdatas)) {
for (let vin of tx.vin) { for (const vin of tx.vin) {
if (vin.addresses && vin.addresses.indexOf(this._getInternalAddressByIndex(c)) !== -1) { if (vin.addresses && vin.addresses.indexOf(this._getInternalAddressByIndex(c)) !== -1) {
// this TX is related to our address // this TX is related to our address
this._txs_by_internal_index[c] = this._txs_by_internal_index[c] || []; this._txs_by_internal_index[c] = this._txs_by_internal_index[c] || [];
let clonedTx = Object.assign({}, tx); const clonedTx = Object.assign({}, tx);
clonedTx.inputs = tx.vin.slice(0); clonedTx.inputs = tx.vin.slice(0);
clonedTx.outputs = tx.vout.slice(0); clonedTx.outputs = tx.vout.slice(0);
delete clonedTx.vin; delete clonedTx.vin;
@ -358,11 +358,11 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
if (!replaced) this._txs_by_internal_index[c].push(clonedTx); if (!replaced) this._txs_by_internal_index[c].push(clonedTx);
} }
} }
for (let vout of tx.vout) { for (const vout of tx.vout) {
if (vout.scriptPubKey.addresses && vout.scriptPubKey.addresses.indexOf(this._getInternalAddressByIndex(c)) !== -1) { if (vout.scriptPubKey.addresses && vout.scriptPubKey.addresses.indexOf(this._getInternalAddressByIndex(c)) !== -1) {
// this TX is related to our address // this TX is related to our address
this._txs_by_internal_index[c] = this._txs_by_internal_index[c] || []; this._txs_by_internal_index[c] = this._txs_by_internal_index[c] || [];
let clonedTx = Object.assign({}, tx); const clonedTx = Object.assign({}, tx);
clonedTx.inputs = tx.vin.slice(0); clonedTx.inputs = tx.vin.slice(0);
clonedTx.outputs = tx.vout.slice(0); clonedTx.outputs = tx.vout.slice(0);
delete clonedTx.vin; delete clonedTx.vin;
@ -388,29 +388,29 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
getTransactions() { getTransactions() {
let txs = []; let txs = [];
for (let addressTxs of Object.values(this._txs_by_external_index)) { for (const addressTxs of Object.values(this._txs_by_external_index)) {
txs = txs.concat(addressTxs); txs = txs.concat(addressTxs);
} }
for (let addressTxs of Object.values(this._txs_by_internal_index)) { for (const addressTxs of Object.values(this._txs_by_internal_index)) {
txs = txs.concat(addressTxs); txs = txs.concat(addressTxs);
} }
let ret = []; const ret = [];
for (let tx of txs) { for (const tx of txs) {
tx.received = tx.blocktime * 1000; tx.received = tx.blocktime * 1000;
if (!tx.blocktime) tx.received = +new Date() - 30 * 1000; // unconfirmed if (!tx.blocktime) tx.received = +new Date() - 30 * 1000; // unconfirmed
tx.confirmations = tx.confirmations || 0; // unconfirmed tx.confirmations = tx.confirmations || 0; // unconfirmed
tx.hash = tx.txid; tx.hash = tx.txid;
tx.value = 0; tx.value = 0;
for (let vin of tx.inputs) { for (const vin of tx.inputs) {
// if input (spending) goes from our address - we are loosing! // if input (spending) goes from our address - we are loosing!
if ((vin.address && this.weOwnAddress(vin.address)) || (vin.addresses && vin.addresses[0] && this.weOwnAddress(vin.addresses[0]))) { if ((vin.address && this.weOwnAddress(vin.address)) || (vin.addresses && vin.addresses[0] && this.weOwnAddress(vin.addresses[0]))) {
tx.value -= new BigNumber(vin.value).multipliedBy(100000000).toNumber(); tx.value -= new BigNumber(vin.value).multipliedBy(100000000).toNumber();
} }
} }
for (let vout of tx.outputs) { for (const vout of tx.outputs) {
// when output goes to our address - this means we are gaining! // when output goes to our address - this means we are gaining!
if (vout.scriptPubKey.addresses && vout.scriptPubKey.addresses[0] && this.weOwnAddress(vout.scriptPubKey.addresses[0])) { if (vout.scriptPubKey.addresses && vout.scriptPubKey.addresses[0] && this.weOwnAddress(vout.scriptPubKey.addresses[0])) {
tx.value += new BigNumber(vout.value).multipliedBy(100000000).toNumber(); tx.value += new BigNumber(vout.value).multipliedBy(100000000).toNumber();
@ -420,21 +420,21 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
} }
// now, deduplication: // now, deduplication:
let usedTxIds = {}; const usedTxIds = {};
let ret2 = []; const ret2 = [];
for (let tx of ret) { for (const tx of ret) {
if (!usedTxIds[tx.txid]) ret2.push(tx); if (!usedTxIds[tx.txid]) ret2.push(tx);
usedTxIds[tx.txid] = 1; usedTxIds[tx.txid] = 1;
} }
return ret2.sort(function(a, b) { return ret2.sort(function (a, b) {
return b.received - a.received; return b.received - a.received;
}); });
} }
async _binarySearchIterationForInternalAddress(index) { async _binarySearchIterationForInternalAddress(index) {
const gerenateChunkAddresses = chunkNum => { const gerenateChunkAddresses = chunkNum => {
let ret = []; const ret = [];
for (let c = this.gap_limit * chunkNum; c < this.gap_limit * (chunkNum + 1); c++) { for (let c = this.gap_limit * chunkNum; c < this.gap_limit * (chunkNum + 1); c++) {
ret.push(this._getInternalAddressByIndex(c)); ret.push(this._getInternalAddressByIndex(c));
} }
@ -444,7 +444,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
let lastChunkWithUsedAddressesNum = null; let lastChunkWithUsedAddressesNum = null;
let lastHistoriesWithUsedAddresses = null; let lastHistoriesWithUsedAddresses = null;
for (let c = 0; c < Math.round(index / this.gap_limit); c++) { for (let c = 0; c < Math.round(index / this.gap_limit); c++) {
let histories = await BlueElectrum.multiGetHistoryByAddress(gerenateChunkAddresses(c)); const histories = await BlueElectrum.multiGetHistoryByAddress(gerenateChunkAddresses(c));
if (this.constructor._getTransactionsFromHistories(histories).length > 0) { if (this.constructor._getTransactionsFromHistories(histories).length > 0) {
// in this particular chunk we have used addresses // in this particular chunk we have used addresses
lastChunkWithUsedAddressesNum = c; lastChunkWithUsedAddressesNum = c;
@ -464,7 +464,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
c < lastChunkWithUsedAddressesNum * this.gap_limit + this.gap_limit; c < lastChunkWithUsedAddressesNum * this.gap_limit + this.gap_limit;
c++ c++
) { ) {
let address = this._getInternalAddressByIndex(c); const address = this._getInternalAddressByIndex(c);
if (lastHistoriesWithUsedAddresses[address] && lastHistoriesWithUsedAddresses[address].length > 0) { if (lastHistoriesWithUsedAddresses[address] && lastHistoriesWithUsedAddresses[address].length > 0) {
lastUsedIndex = Math.max(c, lastUsedIndex) + 1; // point to next, which is supposed to be unsued lastUsedIndex = Math.max(c, lastUsedIndex) + 1; // point to next, which is supposed to be unsued
} }
@ -476,7 +476,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
async _binarySearchIterationForExternalAddress(index) { async _binarySearchIterationForExternalAddress(index) {
const gerenateChunkAddresses = chunkNum => { const gerenateChunkAddresses = chunkNum => {
let ret = []; const ret = [];
for (let c = this.gap_limit * chunkNum; c < this.gap_limit * (chunkNum + 1); c++) { for (let c = this.gap_limit * chunkNum; c < this.gap_limit * (chunkNum + 1); c++) {
ret.push(this._getExternalAddressByIndex(c)); ret.push(this._getExternalAddressByIndex(c));
} }
@ -486,7 +486,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
let lastChunkWithUsedAddressesNum = null; let lastChunkWithUsedAddressesNum = null;
let lastHistoriesWithUsedAddresses = null; let lastHistoriesWithUsedAddresses = null;
for (let c = 0; c < Math.round(index / this.gap_limit); c++) { for (let c = 0; c < Math.round(index / this.gap_limit); c++) {
let histories = await BlueElectrum.multiGetHistoryByAddress(gerenateChunkAddresses(c)); const histories = await BlueElectrum.multiGetHistoryByAddress(gerenateChunkAddresses(c));
if (this.constructor._getTransactionsFromHistories(histories).length > 0) { if (this.constructor._getTransactionsFromHistories(histories).length > 0) {
// in this particular chunk we have used addresses // in this particular chunk we have used addresses
lastChunkWithUsedAddressesNum = c; lastChunkWithUsedAddressesNum = c;
@ -506,7 +506,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
c < lastChunkWithUsedAddressesNum * this.gap_limit + this.gap_limit; c < lastChunkWithUsedAddressesNum * this.gap_limit + this.gap_limit;
c++ c++
) { ) {
let address = this._getExternalAddressByIndex(c); const address = this._getExternalAddressByIndex(c);
if (lastHistoriesWithUsedAddresses[address] && lastHistoriesWithUsedAddresses[address].length > 0) { if (lastHistoriesWithUsedAddresses[address] && lastHistoriesWithUsedAddresses[address].length > 0) {
lastUsedIndex = Math.max(c, lastUsedIndex) + 1; // point to next, which is supposed to be unsued lastUsedIndex = Math.max(c, lastUsedIndex) + 1; // point to next, which is supposed to be unsued
} }
@ -558,7 +558,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
// next, business as usuall. fetch balances // next, business as usuall. fetch balances
let addresses2fetch = []; const addresses2fetch = [];
// generating all involved addresses. // generating all involved addresses.
// basically, refetch all from index zero to maximum. doesnt matter // basically, refetch all from index zero to maximum. doesnt matter
@ -574,11 +574,11 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
addresses2fetch.push(this._getInternalAddressByIndex(c)); addresses2fetch.push(this._getInternalAddressByIndex(c));
} }
let balances = await BlueElectrum.multiGetBalanceByAddress(addresses2fetch); const balances = await BlueElectrum.multiGetBalanceByAddress(addresses2fetch);
// converting to a more compact internal format // converting to a more compact internal format
for (let c = 0; c < this.next_free_address_index + this.gap_limit; c++) { for (let c = 0; c < this.next_free_address_index + this.gap_limit; c++) {
let addr = this._getExternalAddressByIndex(c); const addr = this._getExternalAddressByIndex(c);
if (balances.addresses[addr]) { if (balances.addresses[addr]) {
// first, if balances differ from what we store - we delete transactions for that // first, if balances differ from what we store - we delete transactions for that
// address so next fetchTransactions() will refetch everything // address so next fetchTransactions() will refetch everything
@ -598,7 +598,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
} }
} }
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) { for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
let addr = this._getInternalAddressByIndex(c); const addr = this._getInternalAddressByIndex(c);
if (balances.addresses[addr]) { if (balances.addresses[addr]) {
// first, if balances differ from what we store - we delete transactions for that // first, if balances differ from what we store - we delete transactions for that
// address so next fetchTransactions() will refetch everything // address so next fetchTransactions() will refetch everything
@ -656,14 +656,14 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
addressess = [...new Set(addressess)]; // deduplicate just for any case addressess = [...new Set(addressess)]; // deduplicate just for any case
this._utxo = []; this._utxo = [];
for (let arr of Object.values(await BlueElectrum.multiGetUtxoByAddress(addressess))) { for (const arr of Object.values(await BlueElectrum.multiGetUtxoByAddress(addressess))) {
this._utxo = this._utxo.concat(arr); this._utxo = this._utxo.concat(arr);
} }
// backward compatibility TODO: remove when we make sure `.utxo` is not used // backward compatibility TODO: remove when we make sure `.utxo` is not used
this.utxo = this._utxo; this.utxo = this._utxo;
// this belongs in `.getUtxo()` // this belongs in `.getUtxo()`
for (let u of this.utxo) { for (const u of this.utxo) {
u.txid = u.txId; u.txid = u.txId;
u.amount = u.value; u.amount = u.value;
u.wif = this._getWifForAddress(u.address); u.wif = this._getWifForAddress(u.address);
@ -694,15 +694,15 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
} }
getDerivedUtxoFromOurTransaction() { getDerivedUtxoFromOurTransaction() {
let utxos = []; const utxos = [];
for (let tx of this.getTransactions()) { for (const tx of this.getTransactions()) {
for (let output of tx.outputs) { for (const output of tx.outputs) {
let address = false; let address = false;
if (output.scriptPubKey && output.scriptPubKey.addresses && output.scriptPubKey.addresses[0]) { if (output.scriptPubKey && output.scriptPubKey.addresses && output.scriptPubKey.addresses[0]) {
address = output.scriptPubKey.addresses[0]; address = output.scriptPubKey.addresses[0];
} }
if (this.weOwnAddress(address)) { if (this.weOwnAddress(address)) {
let value = new BigNumber(output.value).multipliedBy(100000000).toNumber(); const value = new BigNumber(output.value).multipliedBy(100000000).toNumber();
utxos.push({ utxos.push({
txid: tx.txid, txid: tx.txid,
txId: tx.txid, txId: tx.txid,
@ -719,11 +719,11 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
} }
// got all utxos we ever had. lets filter out the ones that are spent: // got all utxos we ever had. lets filter out the ones that are spent:
let ret = []; const ret = [];
for (let utxo of utxos) { for (const utxo of utxos) {
let spent = false; let spent = false;
for (let tx of this.getTransactions()) { for (const tx of this.getTransactions()) {
for (let input of tx.inputs) { for (const input of tx.inputs) {
if (input.txid === utxo.txid && input.vout === utxo.vout) spent = true; if (input.txid === utxo.txid && input.vout === utxo.vout) spent = true;
// utxo we got previously was actually spent right here ^^ // utxo we got previously was actually spent right here ^^
} }
@ -794,7 +794,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
algo = coinSelectSplit; algo = coinSelectSplit;
} }
let { inputs, outputs, fee } = algo(utxos, targets, feeRate); const { inputs, outputs, fee } = algo(utxos, targets, feeRate);
// .inputs and .outputs will be undefined if no solution was found // .inputs and .outputs will be undefined if no solution was found
if (!inputs || !outputs) { if (!inputs || !outputs) {
@ -804,8 +804,8 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
let psbt = new bitcoin.Psbt(); let psbt = new bitcoin.Psbt();
let c = 0; let c = 0;
let keypairs = {}; const keypairs = {};
let values = {}; const values = {};
inputs.forEach(input => { inputs.forEach(input => {
let keyPair; let keyPair;
@ -844,8 +844,8 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
output.address = changeAddress; output.address = changeAddress;
} }
let path = this._getDerivationPathByAddress(output.address); const path = this._getDerivationPathByAddress(output.address);
let pubkey = this._getPubkeyByAddress(output.address); const pubkey = this._getPubkeyByAddress(output.address);
let masterFingerprintBuffer; let masterFingerprintBuffer;
if (masterFingerprint) { if (masterFingerprint) {
@ -860,13 +860,13 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
// this is not correct fingerprint, as we dont know realfingerprint - we got zpub with 84/0, but fingerpting // this is not correct fingerprint, as we dont know realfingerprint - we got zpub with 84/0, but fingerpting
// should be from root. basically, fingerprint should be provided from outside by user when importing zpub // should be from root. basically, fingerprint should be provided from outside by user when importing zpub
let outputData = { const outputData = {
address: output.address, address: output.address,
value: output.value, value: output.value,
}; };
if (change) { if (change) {
outputData['bip32Derivation'] = [ outputData.bip32Derivation = [
{ {
masterFingerprint: masterFingerprintBuffer, masterFingerprint: masterFingerprintBuffer,
path, path,
@ -959,9 +959,9 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
} }
static _getTransactionsFromHistories(histories) { static _getTransactionsFromHistories(histories) {
let txs = []; const txs = [];
for (let history of Object.values(histories)) { for (const history of Object.values(histories)) {
for (let tx of history) { for (const tx of history) {
txs.push(tx); txs.push(tx);
} }
} }
@ -976,7 +976,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
*/ */
async wasEverUsed() { async wasEverUsed() {
let txs = await BlueElectrum.getTransactionsByAddress(this._getExternalAddressByIndex(0)); const txs = await BlueElectrum.getTransactionsByAddress(this._getExternalAddressByIndex(0));
return txs.length > 0; return txs.length > 0;
} }
} }

View file

@ -74,7 +74,7 @@ export class AbstractHDWallet extends LegacyWallet {
let c; let c;
for (c = 0; c < this.gap_limit + 1; c++) { for (c = 0; c < this.gap_limit + 1; c++) {
if (this.next_free_address_index + c < 0) continue; if (this.next_free_address_index + c < 0) continue;
let address = this._getExternalAddressByIndex(this.next_free_address_index + c); const address = this._getExternalAddressByIndex(this.next_free_address_index + c);
this.external_addresses_cache[this.next_free_address_index + c] = address; // updating cache just for any case this.external_addresses_cache[this.next_free_address_index + c] = address; // updating cache just for any case
let txs = []; let txs = [];
try { try {
@ -112,7 +112,7 @@ export class AbstractHDWallet extends LegacyWallet {
let c; let c;
for (c = 0; c < this.gap_limit + 1; c++) { for (c = 0; c < this.gap_limit + 1; c++) {
if (this.next_free_change_address_index + c < 0) continue; if (this.next_free_change_address_index + c < 0) continue;
let address = this._getInternalAddressByIndex(this.next_free_change_address_index + c); const address = this._getInternalAddressByIndex(this.next_free_change_address_index + c);
this.internal_addresses_cache[this.next_free_change_address_index + c] = address; // updating cache just for any case this.internal_addresses_cache[this.next_free_change_address_index + c] = address; // updating cache just for any case
let txs = []; let txs = [];
try { try {
@ -182,7 +182,7 @@ export class AbstractHDWallet extends LegacyWallet {
let offset = 0; let offset = 0;
while (1) { while (1) {
let response = await api.get('/multiaddr?active=' + this.getXpub() + '&n=100&offset=' + offset); const response = await api.get('/multiaddr?active=' + this.getXpub() + '&n=100&offset=' + offset);
if (response && response.body) { if (response && response.body) {
if (response.body.txs && response.body.txs.length === 0) { if (response.body.txs && response.body.txs.length === 0) {
@ -198,17 +198,17 @@ export class AbstractHDWallet extends LegacyWallet {
// processing TXs and adding to internal memory // processing TXs and adding to internal memory
if (response.body.txs) { if (response.body.txs) {
for (let tx of response.body.txs) { for (const tx of response.body.txs) {
let value = 0; let value = 0;
for (let input of tx.inputs) { for (const input of tx.inputs) {
// ----- INPUTS // ----- INPUTS
if (input.prev_out.xpub) { if (input.prev_out.xpub) {
// sent FROM US // sent FROM US
value -= input.prev_out.value; value -= input.prev_out.value;
// setting internal caches to help ourselves in future... // setting internal caches to help ourselves in future...
let path = input.prev_out.xpub.path.split('/'); const path = input.prev_out.xpub.path.split('/');
if (path[path.length - 2] === '1') { if (path[path.length - 2] === '1') {
// change address // change address
this.next_free_change_address_index = Math.max(path[path.length - 1] * 1 + 1, this.next_free_change_address_index); this.next_free_change_address_index = Math.max(path[path.length - 1] * 1 + 1, this.next_free_change_address_index);
@ -223,14 +223,14 @@ export class AbstractHDWallet extends LegacyWallet {
} }
} }
for (let output of tx.out) { for (const output of tx.out) {
// ----- OUTPUTS // ----- OUTPUTS
if (output.xpub) { if (output.xpub) {
// sent TO US (change) // sent TO US (change)
value += output.value; value += output.value;
// setting internal caches to help ourselves in future... // setting internal caches to help ourselves in future...
let path = output.xpub.path.split('/'); const path = output.xpub.path.split('/');
if (path[path.length - 2] === '1') { if (path[path.length - 2] === '1') {
// change address // change address
this.next_free_change_address_index = Math.max(path[path.length - 1] * 1 + 1, this.next_free_change_address_index); this.next_free_change_address_index = Math.max(path[path.length - 1] * 1 + 1, this.next_free_change_address_index);
@ -282,13 +282,13 @@ export class AbstractHDWallet extends LegacyWallet {
if (this._address_to_wif_cache[address]) return this._address_to_wif_cache[address]; // cache hit if (this._address_to_wif_cache[address]) return this._address_to_wif_cache[address]; // cache hit
// fast approach, first lets iterate over all addressess we have in cache // fast approach, first lets iterate over all addressess we have in cache
for (let index of Object.keys(this.internal_addresses_cache)) { for (const index of Object.keys(this.internal_addresses_cache)) {
if (this._getInternalAddressByIndex(index) === address) { if (this._getInternalAddressByIndex(index) === address) {
return (this._address_to_wif_cache[address] = this._getInternalWIFByIndex(index)); return (this._address_to_wif_cache[address] = this._getInternalWIFByIndex(index));
} }
} }
for (let index of Object.keys(this.external_addresses_cache)) { for (const index of Object.keys(this.external_addresses_cache)) {
if (this._getExternalAddressByIndex(index) === address) { if (this._getExternalAddressByIndex(index) === address) {
return (this._address_to_wif_cache[address] = this._getExternalWIFByIndex(index)); return (this._address_to_wif_cache[address] = this._getExternalWIFByIndex(index));
} }
@ -296,14 +296,14 @@ export class AbstractHDWallet extends LegacyWallet {
// no luck - lets iterate over all addresses we have up to first unused address index // no luck - lets iterate over all addresses we have up to first unused address index
for (let c = 0; c <= this.next_free_change_address_index + this.gap_limit; c++) { for (let c = 0; c <= this.next_free_change_address_index + this.gap_limit; c++) {
let possibleAddress = this._getInternalAddressByIndex(c); const possibleAddress = this._getInternalAddressByIndex(c);
if (possibleAddress === address) { if (possibleAddress === address) {
return (this._address_to_wif_cache[address] = this._getInternalWIFByIndex(c)); return (this._address_to_wif_cache[address] = this._getInternalWIFByIndex(c));
} }
} }
for (let c = 0; c <= this.next_free_address_index + this.gap_limit; c++) { for (let c = 0; c <= this.next_free_address_index + this.gap_limit; c++) {
let possibleAddress = this._getExternalAddressByIndex(c); const possibleAddress = this._getExternalAddressByIndex(c);
if (possibleAddress === address) { if (possibleAddress === address) {
return (this._address_to_wif_cache[address] = this._getExternalWIFByIndex(c)); return (this._address_to_wif_cache[address] = this._getExternalWIFByIndex(c));
} }
@ -324,8 +324,8 @@ export class AbstractHDWallet extends LegacyWallet {
} }
weOwnAddress(addr) { weOwnAddress(addr) {
let hashmap = {}; const hashmap = {};
for (let a of this.usedAddresses) { for (const a of this.usedAddresses) {
hashmap[a] = 1; hashmap[a] = 1;
} }

View file

@ -6,9 +6,9 @@ export class AbstractWallet {
static typeReadable = 'abstract'; static typeReadable = 'abstract';
static fromJson(obj) { static fromJson(obj) {
let obj2 = JSON.parse(obj); const obj2 = JSON.parse(obj);
let temp = new this(); const temp = new this();
for (let key2 of Object.keys(obj2)) { for (const key2 of Object.keys(obj2)) {
temp[key2] = obj2[key2]; temp[key2] = obj2[key2];
} }
@ -34,10 +34,7 @@ export class AbstractWallet {
} }
getID() { getID() {
return createHash('sha256') return createHash('sha256').update(this.getSecret()).digest().toString('hex');
.update(this.getSecret())
.digest()
.toString('hex');
} }
getTransactions() { getTransactions() {
@ -76,7 +73,7 @@ export class AbstractWallet {
} }
getPreferredBalanceUnit() { getPreferredBalanceUnit() {
for (let value of Object.values(BitcoinUnit)) { for (const value of Object.values(BitcoinUnit)) {
if (value === this.preferredBalanceUnit) { if (value === this.preferredBalanceUnit) {
return this.preferredBalanceUnit; return this.preferredBalanceUnit;
} }
@ -132,10 +129,7 @@ export class AbstractWallet {
} }
setSecret(newSecret) { setSecret(newSecret) {
this.secret = newSecret this.secret = newSecret.trim().replace('bitcoin:', '').replace('BITCOIN:', '');
.trim()
.replace('bitcoin:', '')
.replace('BITCOIN:', '');
if (this.secret.startsWith('BC1')) this.secret = this.secret.toLowerCase(); if (this.secret.startsWith('BC1')) this.secret = this.secret.toLowerCase();

View file

@ -85,14 +85,14 @@ export class HDLegacyP2PKHWallet extends AbstractHDElectrumWallet {
async fetchUtxo() { async fetchUtxo() {
await super.fetchUtxo(); await super.fetchUtxo();
// now we need to fetch txhash for each input as required by PSBT // now we need to fetch txhash for each input as required by PSBT
let txhexes = await BlueElectrum.multiGetTransactionByTxid( const txhexes = await BlueElectrum.multiGetTransactionByTxid(
this.getUtxo().map(x => x['txid']), this.getUtxo().map(x => x.txid),
50, 50,
false, false,
); );
let newUtxos = []; const newUtxos = [];
for (let u of this.getUtxo()) { for (const u of this.getUtxo()) {
if (txhexes[u.txid]) u.txhex = txhexes[u.txid]; if (txhexes[u.txid]) u.txhex = txhexes[u.txid];
newUtxos.push(u); newUtxos.push(u);
} }

View file

@ -32,10 +32,7 @@ export class HDSegwitElectrumSeedP2WPKHWallet extends HDSegwitBech32Wallet {
return this._xpub; // cache hit return this._xpub; // cache hit
} }
const root = bitcoin.bip32.fromSeed(mn.mnemonicToSeedSync(this.secret, MNEMONIC_TO_SEED_OPTS)); const root = bitcoin.bip32.fromSeed(mn.mnemonicToSeedSync(this.secret, MNEMONIC_TO_SEED_OPTS));
this._xpub = root this._xpub = root.derivePath("m/0'").neutered().toBase58();
.derivePath("m/0'")
.neutered()
.toBase58();
return this._xpub; return this._xpub;
} }

View file

@ -98,7 +98,7 @@ export class HDSegwitP2SHWallet extends AbstractHDElectrumWallet {
const pubkey = this._getPubkeyByAddress(input.address); const pubkey = this._getPubkeyByAddress(input.address);
const path = this._getDerivationPathByAddress(input.address, 49); const path = this._getDerivationPathByAddress(input.address, 49);
const p2wpkh = bitcoin.payments.p2wpkh({ pubkey }); const p2wpkh = bitcoin.payments.p2wpkh({ pubkey });
let p2sh = bitcoin.payments.p2sh({ redeem: p2wpkh }); const p2sh = bitcoin.payments.p2sh({ redeem: p2wpkh });
psbt.addInput({ psbt.addInput({
hash: input.txid, hash: input.txid,

View file

@ -34,7 +34,7 @@ export class LegacyWallet extends AbstractWallet {
* @return {boolean} * @return {boolean}
*/ */
timeToRefreshTransaction() { timeToRefreshTransaction() {
for (let tx of this.getTransactions()) { for (const tx of this.getTransactions()) {
if (tx.confirmations < 7) { if (tx.confirmations < 7) {
return true; return true;
} }
@ -55,7 +55,7 @@ export class LegacyWallet extends AbstractWallet {
if (this._address) return this._address; if (this._address) return this._address;
let address; let address;
try { try {
let keyPair = bitcoin.ECPair.fromWIF(this.secret); const keyPair = bitcoin.ECPair.fromWIF(this.secret);
address = bitcoin.payments.p2pkh({ address = bitcoin.payments.p2pkh({
pubkey: keyPair.publicKey, pubkey: keyPair.publicKey,
}).address; }).address;
@ -75,7 +75,7 @@ export class LegacyWallet extends AbstractWallet {
*/ */
async fetchBalance() { async fetchBalance() {
try { try {
let balance = await BlueElectrum.getBalanceByAddress(this.getAddress()); const balance = await BlueElectrum.getBalanceByAddress(this.getAddress());
this.balance = Number(balance.confirmed); this.balance = Number(balance.confirmed);
this.unconfirmed_balance = Number(balance.unconfirmed); this.unconfirmed_balance = Number(balance.unconfirmed);
this._lastBalanceFetch = +new Date(); this._lastBalanceFetch = +new Date();
@ -91,22 +91,22 @@ export class LegacyWallet extends AbstractWallet {
*/ */
async fetchUtxo() { async fetchUtxo() {
try { try {
let utxos = await BlueElectrum.multiGetUtxoByAddress([this.getAddress()]); const utxos = await BlueElectrum.multiGetUtxoByAddress([this.getAddress()]);
this.utxo = []; this.utxo = [];
for (let arr of Object.values(utxos)) { for (const arr of Object.values(utxos)) {
this.utxo = this.utxo.concat(arr); this.utxo = this.utxo.concat(arr);
} }
// now we need to fetch txhash for each input as required by PSBT // now we need to fetch txhash for each input as required by PSBT
if (LegacyWallet.type !== this.type) return; // but only for LEGACY single-address wallets if (LegacyWallet.type !== this.type) return; // but only for LEGACY single-address wallets
let txhexes = await BlueElectrum.multiGetTransactionByTxid( const txhexes = await BlueElectrum.multiGetTransactionByTxid(
this.utxo.map(u => u['txId']), this.utxo.map(u => u.txId),
50, 50,
false, false,
); );
let newUtxos = []; const newUtxos = [];
for (let u of this.utxo) { for (const u of this.utxo) {
if (txhexes[u.txId]) u.txhex = txhexes[u.txId]; if (txhexes[u.txId]) u.txhex = txhexes[u.txId];
newUtxos.push(u); newUtxos.push(u);
} }
@ -118,8 +118,8 @@ export class LegacyWallet extends AbstractWallet {
} }
getUtxo() { getUtxo() {
let ret = []; const ret = [];
for (let u of this.utxo) { for (const u of this.utxo) {
if (u.txId) u.txid = u.txId; if (u.txId) u.txid = u.txId;
if (!u.confirmations && u.height) u.confirmations = BlueElectrum.estimateCurrentBlockheight() - u.height; if (!u.confirmations && u.height) u.confirmations = BlueElectrum.estimateCurrentBlockheight() - u.height;
ret.push(u); ret.push(u);
@ -137,37 +137,37 @@ export class LegacyWallet extends AbstractWallet {
async fetchTransactions() { async fetchTransactions() {
// Below is a simplified copypaste from HD electrum wallet // Below is a simplified copypaste from HD electrum wallet
this._txs_by_external_index = []; this._txs_by_external_index = [];
let addresses2fetch = [this.getAddress()]; const addresses2fetch = [this.getAddress()];
// first: batch fetch for all addresses histories // first: batch fetch for all addresses histories
let histories = await BlueElectrum.multiGetHistoryByAddress(addresses2fetch); const histories = await BlueElectrum.multiGetHistoryByAddress(addresses2fetch);
let txs = {}; const txs = {};
for (let history of Object.values(histories)) { for (const history of Object.values(histories)) {
for (let tx of history) { for (const tx of history) {
txs[tx.tx_hash] = tx; txs[tx.tx_hash] = tx;
} }
} }
// next, batch fetching each txid we got // next, batch fetching each txid we got
let txdatas = await BlueElectrum.multiGetTransactionByTxid(Object.keys(txs)); const txdatas = await BlueElectrum.multiGetTransactionByTxid(Object.keys(txs));
// now, tricky part. we collect all transactions from inputs (vin), and batch fetch them too. // 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) // then we combine all this data (we need inputs to see source addresses and amounts)
let vinTxids = []; const vinTxids = [];
for (let txdata of Object.values(txdatas)) { for (const txdata of Object.values(txdatas)) {
for (let vin of txdata.vin) { for (const vin of txdata.vin) {
vinTxids.push(vin.txid); vinTxids.push(vin.txid);
} }
} }
let vintxdatas = await BlueElectrum.multiGetTransactionByTxid(vinTxids); const vintxdatas = await BlueElectrum.multiGetTransactionByTxid(vinTxids);
// fetched all transactions from our inputs. now we need to combine it. // fetched all transactions from our inputs. now we need to combine it.
// iterating all _our_ transactions: // iterating all _our_ transactions:
for (let txid of Object.keys(txdatas)) { for (const txid of Object.keys(txdatas)) {
// iterating all inputs our our single transaction: // iterating all inputs our our single transaction:
for (let inpNum = 0; inpNum < txdatas[txid].vin.length; inpNum++) { for (let inpNum = 0; inpNum < txdatas[txid].vin.length; inpNum++) {
let inpTxid = txdatas[txid].vin[inpNum].txid; const inpTxid = txdatas[txid].vin[inpNum].txid;
let inpVout = txdatas[txid].vin[inpNum].vout; const inpVout = txdatas[txid].vin[inpNum].vout;
// got txid and output number of _previous_ transaction we shoud look into // got txid and output number of _previous_ transaction we shoud look into
if (vintxdatas[inpTxid] && vintxdatas[inpTxid].vout[inpVout]) { if (vintxdatas[inpTxid] && vintxdatas[inpTxid].vout[inpVout]) {
// extracting amount & addresses from previous output and adding it to _our_ input: // extracting amount & addresses from previous output and adding it to _our_ input:
@ -179,11 +179,11 @@ export class LegacyWallet extends AbstractWallet {
// now, we need to put transactions in all relevant `cells` of internal hashmaps: this.transactions_by_internal_index && this.transactions_by_external_index // now, we need to put transactions in all relevant `cells` of internal hashmaps: this.transactions_by_internal_index && this.transactions_by_external_index
for (let tx of Object.values(txdatas)) { for (const tx of Object.values(txdatas)) {
for (let vin of tx.vin) { for (const vin of tx.vin) {
if (vin.addresses && vin.addresses.indexOf(this.getAddress()) !== -1) { if (vin.addresses && vin.addresses.indexOf(this.getAddress()) !== -1) {
// this TX is related to our address // this TX is related to our address
let clonedTx = Object.assign({}, tx); const clonedTx = Object.assign({}, tx);
clonedTx.inputs = tx.vin.slice(0); clonedTx.inputs = tx.vin.slice(0);
clonedTx.outputs = tx.vout.slice(0); clonedTx.outputs = tx.vout.slice(0);
delete clonedTx.vin; delete clonedTx.vin;
@ -192,10 +192,10 @@ export class LegacyWallet extends AbstractWallet {
this._txs_by_external_index.push(clonedTx); this._txs_by_external_index.push(clonedTx);
} }
} }
for (let vout of tx.vout) { for (const vout of tx.vout) {
if (vout.scriptPubKey.addresses && vout.scriptPubKey.addresses.indexOf(this.getAddress()) !== -1) { if (vout.scriptPubKey.addresses && vout.scriptPubKey.addresses.indexOf(this.getAddress()) !== -1) {
// this TX is related to our address // this TX is related to our address
let clonedTx = Object.assign({}, tx); const clonedTx = Object.assign({}, tx);
clonedTx.inputs = tx.vin.slice(0); clonedTx.inputs = tx.vin.slice(0);
clonedTx.outputs = tx.vout.slice(0); clonedTx.outputs = tx.vout.slice(0);
delete clonedTx.vin; delete clonedTx.vin;
@ -214,7 +214,7 @@ export class LegacyWallet extends AbstractWallet {
this._txs_by_external_index = this._txs_by_external_index || []; this._txs_by_external_index = this._txs_by_external_index || [];
this._txs_by_internal_index = []; this._txs_by_internal_index = [];
let hd = new HDSegwitBech32Wallet(); const hd = new HDSegwitBech32Wallet();
return hd.getTransactions.apply(this); return hd.getTransactions.apply(this);
} }
@ -225,7 +225,7 @@ export class LegacyWallet extends AbstractWallet {
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
*/ */
async broadcastTx(txhex) { async broadcastTx(txhex) {
let broadcast = await BlueElectrum.broadcastV2(txhex); const broadcast = await BlueElectrum.broadcastV2(txhex);
console.log({ broadcast }); console.log({ broadcast });
if (broadcast.indexOf('successfully') !== -1) return true; if (broadcast.indexOf('successfully') !== -1) return true;
return broadcast.length === 64; // this means return string is txid (precise length), so it was broadcasted ok return broadcast.length === 64; // this means return string is txid (precise length), so it was broadcasted ok
@ -252,17 +252,17 @@ export class LegacyWallet extends AbstractWallet {
algo = coinSelectSplit; algo = coinSelectSplit;
} }
let { inputs, outputs, fee } = algo(utxos, targets, feeRate); const { inputs, outputs, fee } = algo(utxos, targets, feeRate);
// .inputs and .outputs will be undefined if no solution was found // .inputs and .outputs will be undefined if no solution was found
if (!inputs || !outputs) { if (!inputs || !outputs) {
throw new Error('Not enough balance. Try sending smaller amount'); throw new Error('Not enough balance. Try sending smaller amount');
} }
let psbt = new bitcoin.Psbt(); const psbt = new bitcoin.Psbt();
let c = 0; let c = 0;
let values = {}; const values = {};
let keyPair; let keyPair;
inputs.forEach(input => { inputs.forEach(input => {
@ -290,7 +290,7 @@ export class LegacyWallet extends AbstractWallet {
output.address = changeAddress; output.address = changeAddress;
} }
let outputData = { const outputData = {
address: output.address, address: output.address,
value: output.value, value: output.value,
}; };
@ -317,7 +317,7 @@ export class LegacyWallet extends AbstractWallet {
return 0; return 0;
} }
let max = 0; let max = 0;
for (let tx of this.getTransactions()) { for (const tx of this.getTransactions()) {
max = Math.max(new Date(tx.received) * 1, max); max = Math.max(new Date(tx.received) * 1, max);
} }

View file

@ -68,7 +68,7 @@ export class LightningCustodianWallet extends LegacyWallet {
} }
static fromJson(param) { static fromJson(param) {
let obj = super.fromJson(param); const obj = super.fromJson(param);
obj.init(); obj.init();
return obj; return obj;
} }
@ -92,11 +92,11 @@ export class LightningCustodianWallet extends LegacyWallet {
} }
async createAccount(isTest) { async createAccount(isTest) {
let response = await this._api.post('/create', { const response = await this._api.post('/create', {
body: { partnerid: 'bluewallet', accounttype: (isTest && 'test') || 'common' }, body: { partnerid: 'bluewallet', accounttype: (isTest && 'test') || 'common' },
headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json' }, headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json' },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body));
} }
@ -113,7 +113,7 @@ export class LightningCustodianWallet extends LegacyWallet {
} }
async payInvoice(invoice, freeAmount = 0) { async payInvoice(invoice, freeAmount = 0) {
let response = await this._api.post('/payinvoice', { const response = await this._api.post('/payinvoice', {
body: { invoice: invoice, amount: freeAmount }, body: { invoice: invoice, amount: freeAmount },
headers: { headers: {
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
@ -132,7 +132,7 @@ export class LightningCustodianWallet extends LegacyWallet {
throw new Error('Payment is in transit'); throw new Error('Payment is in transit');
} }
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.originalResponse)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.originalResponse));
} }
@ -152,14 +152,14 @@ export class LightningCustodianWallet extends LegacyWallet {
async getUserInvoices(limit = false) { async getUserInvoices(limit = false) {
let limitString = ''; let limitString = '';
if (limit) limitString = '?limit=' + parseInt(limit); if (limit) limitString = '?limit=' + parseInt(limit);
let response = await this._api.get('/getuserinvoices' + limitString, { const response = await this._api.get('/getuserinvoices' + limitString, {
headers: { headers: {
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
Authorization: 'Bearer' + ' ' + this.access_token, Authorization: 'Bearer' + ' ' + this.access_token,
}, },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.originalResponse)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.originalResponse));
} }
@ -172,10 +172,10 @@ export class LightningCustodianWallet extends LegacyWallet {
// need to merge existing invoices with the ones that arrived // need to merge existing invoices with the ones that arrived
// but the ones received later should overwrite older ones // but the ones received later should overwrite older ones
for (let oldInvoice of this.user_invoices_raw) { for (const oldInvoice of this.user_invoices_raw) {
// iterate all OLD invoices // iterate all OLD invoices
let found = false; let found = false;
for (let newInvoice of json) { for (const newInvoice of json) {
// iterate all NEW invoices // iterate all NEW invoices
if (newInvoice.payment_request === oldInvoice.payment_request) found = true; if (newInvoice.payment_request === oldInvoice.payment_request) found = true;
} }
@ -187,7 +187,7 @@ export class LightningCustodianWallet extends LegacyWallet {
} }
} }
this.user_invoices_raw = json.sort(function(a, b) { this.user_invoices_raw = json.sort(function (a, b) {
return a.timestamp - b.timestamp; return a.timestamp - b.timestamp;
}); });
@ -213,7 +213,7 @@ export class LightningCustodianWallet extends LegacyWallet {
} }
async addInvoice(amt, memo) { async addInvoice(amt, memo) {
let response = await this._api.post('/addinvoice', { const response = await this._api.post('/addinvoice', {
body: { amt: amt + '', memo: memo }, body: { amt: amt + '', memo: memo },
headers: { headers: {
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
@ -221,7 +221,7 @@ export class LightningCustodianWallet extends LegacyWallet {
Authorization: 'Bearer' + ' ' + this.access_token, Authorization: 'Bearer' + ' ' + this.access_token,
}, },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.originalResponse)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.originalResponse));
} }
@ -238,7 +238,7 @@ export class LightningCustodianWallet extends LegacyWallet {
} }
async checkRouteInvoice(invoice) { async checkRouteInvoice(invoice) {
let response = await this._api.get('/checkrouteinvoice?invoice=' + invoice, { const response = await this._api.get('/checkrouteinvoice?invoice=' + invoice, {
headers: { headers: {
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -246,7 +246,7 @@ export class LightningCustodianWallet extends LegacyWallet {
}, },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body));
} }
@ -271,12 +271,12 @@ export class LightningCustodianWallet extends LegacyWallet {
login = this.secret.replace('lndhub://', '').split(':')[0]; login = this.secret.replace('lndhub://', '').split(':')[0];
password = this.secret.replace('lndhub://', '').split(':')[1]; password = this.secret.replace('lndhub://', '').split(':')[1];
} }
let response = await this._api.post('/auth?type=auth', { const response = await this._api.post('/auth?type=auth', {
body: { login: login, password: password }, body: { login: login, password: password },
headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json' }, headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json' },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body));
} }
@ -318,12 +318,12 @@ export class LightningCustodianWallet extends LegacyWallet {
} }
async refreshAcessToken() { async refreshAcessToken() {
let response = await this._api.post('/auth?type=refresh_token', { const response = await this._api.post('/auth?type=refresh_token', {
body: { refresh_token: this.refresh_token }, body: { refresh_token: this.refresh_token },
headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json' }, headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json' },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body));
} }
@ -343,7 +343,7 @@ export class LightningCustodianWallet extends LegacyWallet {
} }
async fetchBtcAddress() { async fetchBtcAddress() {
let response = await this._api.get('/getbtc', { const response = await this._api.get('/getbtc', {
headers: { headers: {
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -351,7 +351,7 @@ export class LightningCustodianWallet extends LegacyWallet {
}, },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body));
} }
@ -362,7 +362,7 @@ export class LightningCustodianWallet extends LegacyWallet {
this.refill_addressess = []; this.refill_addressess = [];
for (let arr of json) { for (const arr of json) {
this.refill_addressess.push(arr.address); this.refill_addressess.push(arr.address);
} }
} }
@ -388,7 +388,7 @@ export class LightningCustodianWallet extends LegacyWallet {
this.transactions_raw = this.transactions_raw || []; this.transactions_raw = this.transactions_raw || [];
txs = txs.concat(this.pending_transactions_raw.slice(), this.transactions_raw.slice().reverse(), this.user_invoices_raw.slice()); // slice so array is cloned txs = txs.concat(this.pending_transactions_raw.slice(), this.transactions_raw.slice().reverse(), this.user_invoices_raw.slice()); // slice so array is cloned
// transforming to how wallets/list screen expects it // transforming to how wallets/list screen expects it
for (let tx of txs) { for (const tx of txs) {
tx.fromWallet = this.getSecret(); tx.fromWallet = this.getSecret();
if (tx.amount) { if (tx.amount) {
// pending tx // pending tx
@ -421,13 +421,13 @@ export class LightningCustodianWallet extends LegacyWallet {
tx.received = new Date(tx.timestamp * 1000).toString(); tx.received = new Date(tx.timestamp * 1000).toString();
} }
return txs.sort(function(a, b) { return txs.sort(function (a, b) {
return b.timestamp - a.timestamp; return b.timestamp - a.timestamp;
}); });
} }
async fetchPendingTransactions() { async fetchPendingTransactions() {
let response = await this._api.get('/getpending', { const response = await this._api.get('/getpending', {
headers: { headers: {
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -435,7 +435,7 @@ export class LightningCustodianWallet extends LegacyWallet {
}, },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response));
} }
@ -451,11 +451,11 @@ export class LightningCustodianWallet extends LegacyWallet {
// TODO: iterate over all available pages // TODO: iterate over all available pages
const limit = 10; const limit = 10;
let queryRes = ''; let queryRes = '';
let offset = 0; const offset = 0;
queryRes += '?limit=' + limit; queryRes += '?limit=' + limit;
queryRes += '&offset=' + offset; queryRes += '&offset=' + offset;
let response = await this._api.get('/gettxs' + queryRes, { const response = await this._api.get('/gettxs' + queryRes, {
headers: { headers: {
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -463,7 +463,7 @@ export class LightningCustodianWallet extends LegacyWallet {
}, },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body));
} }
@ -487,7 +487,7 @@ export class LightningCustodianWallet extends LegacyWallet {
async fetchBalance(noRetry) { async fetchBalance(noRetry) {
await this.checkLogin(); await this.checkLogin();
let response = await this._api.get('/balance', { const response = await this._api.get('/balance', {
headers: { headers: {
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -495,7 +495,7 @@ export class LightningCustodianWallet extends LegacyWallet {
}, },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body));
} }
@ -534,9 +534,9 @@ export class LightningCustodianWallet extends LegacyWallet {
* @return {Promise.<Object>} * @return {Promise.<Object>}
*/ */
decodeInvoice(invoice) { decodeInvoice(invoice) {
let { payeeNodeKey, tags, satoshis, millisatoshis, timestamp } = bolt11.decode(invoice); const { payeeNodeKey, tags, satoshis, millisatoshis, timestamp } = bolt11.decode(invoice);
let decoded = { const decoded = {
destination: payeeNodeKey, destination: payeeNodeKey,
num_satoshis: satoshis ? satoshis.toString() : '0', num_satoshis: satoshis ? satoshis.toString() : '0',
num_millisatoshis: millisatoshis ? millisatoshis.toString() : '0', num_millisatoshis: millisatoshis ? millisatoshis.toString() : '0',
@ -546,7 +546,7 @@ export class LightningCustodianWallet extends LegacyWallet {
}; };
for (let i = 0; i < tags.length; i++) { for (let i = 0; i < tags.length; i++) {
let { tagName, data } = tags[i]; const { tagName, data } = tags[i];
switch (tagName) { switch (tagName) {
case 'payment_hash': case 'payment_hash':
decoded.payment_hash = data; decoded.payment_hash = data;
@ -576,7 +576,7 @@ export class LightningCustodianWallet extends LegacyWallet {
} }
async fetchInfo() { async fetchInfo() {
let response = await this._api.get('/getinfo', { const response = await this._api.get('/getinfo', {
headers: { headers: {
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -584,7 +584,7 @@ export class LightningCustodianWallet extends LegacyWallet {
}, },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body));
} }
@ -600,16 +600,16 @@ export class LightningCustodianWallet extends LegacyWallet {
} }
static async isValidNodeAddress(address) { static async isValidNodeAddress(address) {
let apiCall = new Frisbee({ const apiCall = new Frisbee({
baseURI: address, baseURI: address,
}); });
let response = await apiCall.get('/getinfo', { const response = await apiCall.get('/getinfo', {
headers: { headers: {
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body));
} }
@ -643,7 +643,7 @@ export class LightningCustodianWallet extends LegacyWallet {
async decodeInvoiceRemote(invoice) { async decodeInvoiceRemote(invoice) {
await this.checkLogin(); await this.checkLogin();
let response = await this._api.get('/decodeinvoice?invoice=' + invoice, { const response = await this._api.get('/decodeinvoice?invoice=' + invoice, {
headers: { headers: {
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -651,7 +651,7 @@ export class LightningCustodianWallet extends LegacyWallet {
}, },
}); });
let json = response.body; const json = response.body;
if (typeof json === 'undefined') { if (typeof json === 'undefined') {
throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body)); throw new Error('API failure: ' + response.err + ' ' + JSON.stringify(response.body));
} }

View file

@ -11,7 +11,7 @@ export class SegwitBech32Wallet extends LegacyWallet {
if (this._address) return this._address; if (this._address) return this._address;
let address; let address;
try { try {
let keyPair = bitcoin.ECPair.fromWIF(this.secret); const keyPair = bitcoin.ECPair.fromWIF(this.secret);
if (!keyPair.compressed) { if (!keyPair.compressed) {
console.warn('only compressed public keys are good for segwit'); console.warn('only compressed public keys are good for segwit');
return false; return false;
@ -76,17 +76,17 @@ export class SegwitBech32Wallet extends LegacyWallet {
algo = coinSelectSplit; algo = coinSelectSplit;
} }
let { inputs, outputs, fee } = algo(utxos, targets, feeRate); const { inputs, outputs, fee } = algo(utxos, targets, feeRate);
// .inputs and .outputs will be undefined if no solution was found // .inputs and .outputs will be undefined if no solution was found
if (!inputs || !outputs) { if (!inputs || !outputs) {
throw new Error('Not enough balance. Try sending smaller amount'); throw new Error('Not enough balance. Try sending smaller amount');
} }
let psbt = new bitcoin.Psbt(); const psbt = new bitcoin.Psbt();
let c = 0; let c = 0;
let values = {}; const values = {};
let keyPair; let keyPair;
inputs.forEach(input => { inputs.forEach(input => {
@ -117,7 +117,7 @@ export class SegwitBech32Wallet extends LegacyWallet {
output.address = changeAddress; output.address = changeAddress;
} }
let outputData = { const outputData = {
address: output.address, address: output.address,
value: output.value, value: output.value,
}; };

View file

@ -51,8 +51,8 @@ export class SegwitP2SHWallet extends LegacyWallet {
if (this._address) return this._address; if (this._address) return this._address;
let address; let address;
try { try {
let keyPair = bitcoin.ECPair.fromWIF(this.secret); const keyPair = bitcoin.ECPair.fromWIF(this.secret);
let pubKey = keyPair.publicKey; const pubKey = keyPair.publicKey;
if (!keyPair.compressed) { if (!keyPair.compressed) {
console.warn('only compressed public keys are good for segwit'); console.warn('only compressed public keys are good for segwit');
return false; return false;
@ -87,17 +87,17 @@ export class SegwitP2SHWallet extends LegacyWallet {
algo = coinSelectSplit; algo = coinSelectSplit;
} }
let { inputs, outputs, fee } = algo(utxos, targets, feeRate); const { inputs, outputs, fee } = algo(utxos, targets, feeRate);
// .inputs and .outputs will be undefined if no solution was found // .inputs and .outputs will be undefined if no solution was found
if (!inputs || !outputs) { if (!inputs || !outputs) {
throw new Error('Not enough balance. Try sending smaller amount'); throw new Error('Not enough balance. Try sending smaller amount');
} }
let psbt = new bitcoin.Psbt(); const psbt = new bitcoin.Psbt();
let c = 0; let c = 0;
let values = {}; const values = {};
let keyPair; let keyPair;
inputs.forEach(input => { inputs.forEach(input => {
@ -110,7 +110,7 @@ export class SegwitP2SHWallet extends LegacyWallet {
const pubkey = keyPair.publicKey; const pubkey = keyPair.publicKey;
const p2wpkh = bitcoin.payments.p2wpkh({ pubkey }); const p2wpkh = bitcoin.payments.p2wpkh({ pubkey });
let p2sh = bitcoin.payments.p2sh({ redeem: p2wpkh }); const p2sh = bitcoin.payments.p2sh({ redeem: p2wpkh });
psbt.addInput({ psbt.addInput({
hash: input.txid, hash: input.txid,
@ -130,7 +130,7 @@ export class SegwitP2SHWallet extends LegacyWallet {
output.address = changeAddress; output.address = changeAddress;
} }
let outputData = { const outputData = {
address: output.address, address: output.address,
value: output.value, value: output.value,
}; };

View file

@ -65,7 +65,7 @@ export class WatchOnlyWallet extends LegacyWallet {
hdWalletInstance._xpub = this.secret; hdWalletInstance._xpub = this.secret;
if (this._hdWalletInstance) { if (this._hdWalletInstance) {
// now, porting all properties from old object to new one // now, porting all properties from old object to new one
for (let k of Object.keys(this._hdWalletInstance)) { for (const k of Object.keys(this._hdWalletInstance)) {
hdWalletInstance[k] = this._hdWalletInstance[k]; hdWalletInstance[k] = this._hdWalletInstance[k];
} }

View file

@ -4,9 +4,9 @@ import { AppStorage } from './class';
import { FiatUnit } from './models/fiatUnit'; import { FiatUnit } from './models/fiatUnit';
import DefaultPreference from 'react-native-default-preference'; import DefaultPreference from 'react-native-default-preference';
import DeviceQuickActions from './class/quick-actions'; import DeviceQuickActions from './class/quick-actions';
let BigNumber = require('bignumber.js'); const BigNumber = require('bignumber.js');
let preferredFiatCurrency = FiatUnit.USD; let preferredFiatCurrency = FiatUnit.USD;
let exchangeRates = {}; const exchangeRates = {};
const STRUCT = { const STRUCT = {
LAST_UPDATED: 'LAST_UPDATED', LAST_UPDATED: 'LAST_UPDATED',
@ -28,7 +28,7 @@ async function setPrefferedCurrency(item) {
} }
async function getPreferredCurrency() { async function getPreferredCurrency() {
let preferredCurrency = await JSON.parse(await AsyncStorage.getItem(AppStorage.PREFERRED_CURRENCY)); const preferredCurrency = await JSON.parse(await AsyncStorage.getItem(AppStorage.PREFERRED_CURRENCY));
await DefaultPreference.set('preferredCurrency', preferredCurrency.endPointKey); await DefaultPreference.set('preferredCurrency', preferredCurrency.endPointKey);
await DefaultPreference.set('preferredCurrencyLocale', preferredCurrency.locale.replace('-', '_')); await DefaultPreference.set('preferredCurrencyLocale', preferredCurrency.locale.replace('-', '_'));
return preferredCurrency; return preferredCurrency;
@ -50,7 +50,7 @@ async function updateExchangeRate() {
const api = new Frisbee({ const api = new Frisbee({
baseURI: 'https://api.coindesk.com', baseURI: 'https://api.coindesk.com',
}); });
let response = await api.get('/v1/bpi/currentprice/' + preferredFiatCurrency.endPointKey + '.json'); const response = await api.get('/v1/bpi/currentprice/' + preferredFiatCurrency.endPointKey + '.json');
json = JSON.parse(response.body); json = JSON.parse(response.body);
if (!json || !json.bpi || !json.bpi[preferredFiatCurrency.endPointKey] || !json.bpi[preferredFiatCurrency.endPointKey].rate_float) { if (!json || !json.bpi || !json.bpi[preferredFiatCurrency.endPointKey] || !json.bpi[preferredFiatCurrency.endPointKey].rate_float) {
throw new Error('Could not update currency rate: ' + response.err); throw new Error('Could not update currency rate: ' + response.err);

View file

@ -1,13 +1,13 @@
let CryptoJS = require('crypto-js'); const CryptoJS = require('crypto-js');
module.exports.encrypt = function(data, password) { module.exports.encrypt = function (data, password) {
if (data.length < 10) throw new Error('data length cant be < 10'); if (data.length < 10) throw new Error('data length cant be < 10');
let ciphertext = CryptoJS.AES.encrypt(data, password); const ciphertext = CryptoJS.AES.encrypt(data, password);
return ciphertext.toString(); return ciphertext.toString();
}; };
module.exports.decrypt = function(data, password) { module.exports.decrypt = function (data, password) {
let bytes = CryptoJS.AES.decrypt(data, password); const bytes = CryptoJS.AES.decrypt(data, password);
let str = false; let str = false;
try { try {
str = bytes.toString(CryptoJS.enc.Utf8); str = bytes.toString(CryptoJS.enc.Utf8);

View file

@ -8,7 +8,7 @@ function EV(eventName, arg, isExclusive) {
if (typeof arg !== 'function') { if (typeof arg !== 'function') {
// then its an argument // then its an argument
console.log('got event', eventName, '...'); console.log('got event', eventName, '...');
for (let cc of EV.callbacks[eventName]) { for (const cc of EV.callbacks[eventName]) {
console.log('dispatching event', eventName); console.log('dispatching event', eventName);
cc(arg); cc(arg);
} }

View file

@ -1,249 +1,249 @@
module.exports = { module.exports = {
_: { _: {
storage_is_encrypted: 'U geheue spasie is nou ge-enkripteer. n Wagwoord word benodig om toegang te verkry. ', storage_is_encrypted: 'U geheue spasie is nou ge-enkripteer. n Wagwoord word benodig om toegang te verkry. ',
enter_password: 'Sleutel wagwoord in', enter_password: 'Sleutel wagwoord in',
bad_password: 'Verkeerde wagwoord, probeer weer', bad_password: 'Verkeerde wagwoord, probeer weer',
never: 'nooit', never: 'nooit',
continue: 'Gaan voort', continue: 'Gaan voort',
ok: 'OK', ok: 'OK',
}, },
wallets: { wallets: {
select_wallet: 'Kies Beursie', select_wallet: 'Kies Beursie',
options: 'opsies', options: 'opsies',
createBitcoinWallet: createBitcoinWallet:
'U het nie huidiglik `n geldige Bitcoin Beursie nie. Skep of voer eers n Bitcoin Beursie in, sodat n Bitcoin Lightning Beursie geskep en bevonds mag word. Wil U voortgaan?', 'U het nie huidiglik `n geldige Bitcoin Beursie nie. Skep of voer eers n Bitcoin Beursie in, sodat n Bitcoin Lightning Beursie geskep en bevonds mag word. Wil U voortgaan?',
list: { list: {
app_name: 'BlueWallet', app_name: 'BlueWallet',
title: 'beursies', title: 'beursies',
header: header:
'U beursie verteenwoordig n sleutelkombinasie, bestaande uit geheims (privaat sleutel) en address' + 'U beursie verteenwoordig n sleutelkombinasie, bestaande uit geheims (privaat sleutel) en address' +
'wat u kan gebruik om fondse te ontvang.', 'wat u kan gebruik om fondse te ontvang.',
add: 'Skep Beursie', add: 'Skep Beursie',
create_a_wallet: 'Skep n beursie', create_a_wallet: 'Skep n beursie',
create_a_wallet1: 'Dit is gratis so skep', create_a_wallet1: 'Dit is gratis so skep',
create_a_wallet2: 'soveel as wat u benodig', create_a_wallet2: 'soveel as wat u benodig',
create_a_button: 'Add now', create_a_button: 'Add now',
latest_transaction: 'laaste transaksie', latest_transaction: 'laaste transaksie',
empty_txs1: 'U transaksies is hier beskikbaar,', empty_txs1: 'U transaksies is hier beskikbaar,',
empty_txs2: 'huidiglik geen transaksies', empty_txs2: 'huidiglik geen transaksies',
empty_txs1_lightning: empty_txs1_lightning:
'Lightning wallet should be used for your daily transactions. Fees are unfairly cheap and speed is blazing fast.', 'Lightning wallet should be used for your daily transactions. Fees are unfairly cheap and speed is blazing fast.',
empty_txs2_lightning: '\nTo start using it tap on "manage funds" and topup your balance.', empty_txs2_lightning: '\nTo start using it tap on "manage funds" and topup your balance.',
tap_here_to_buy: 'Raak hier om Bitcoin te koop', tap_here_to_buy: 'Raak hier om Bitcoin te koop',
}, },
reorder: { reorder: {
title: 'Herorganiseer Beursies', title: 'Herorganiseer Beursies',
}, },
add: { add: {
title: 'skep beursie', title: 'skep beursie',
description: description:
'U kan n beursie invoer (in WIF - Wallet Import Format), of n nuwe beursie skep. Beursies ondersteun Segwit as standaard.', 'U kan n beursie invoer (in WIF - Wallet Import Format), of n nuwe beursie skep. Beursies ondersteun Segwit as standaard.',
scan: 'Skandeer', scan: 'Skandeer',
create: 'Skep', create: 'Skep',
label_new_segwit: 'Nuwe SegWit', label_new_segwit: 'Nuwe SegWit',
label_new_lightning: 'Nuwe Lightning', label_new_lightning: 'Nuwe Lightning',
wallet_name: 'beursie naam', wallet_name: 'beursie naam',
wallet_type: 'tipe', wallet_type: 'tipe',
or: 'of', or: 'of',
import_wallet: 'Beursie Invoer', import_wallet: 'Beursie Invoer',
imported: 'Ingevoer', imported: 'Ingevoer',
coming_soon: 'In die toekoms', coming_soon: 'In die toekoms',
lightning: 'Lightning', lightning: 'Lightning',
bitcoin: 'Bitcoin', bitcoin: 'Bitcoin',
}, },
details: { details: {
title: 'Beursiet', title: 'Beursiet',
address: 'AdresAddress', address: 'AdresAddress',
master_fingerprint: 'Master fingerprint', master_fingerprint: 'Master fingerprint',
type: 'Tipe', type: 'Tipe',
label: 'Etiket', label: 'Etiket',
destination: 'bestemming', destination: 'bestemming',
description: 'beskrywing', description: 'beskrywing',
are_you_sure: 'Is u Seker?', are_you_sure: 'Is u Seker?',
yes_delete: 'Ja, vernietig', yes_delete: 'Ja, vernietig',
no_cancel: 'Nee, kanseleerl', no_cancel: 'Nee, kanseleerl',
delete: 'Vernietig', delete: 'Vernietig',
save: 'Berg', save: 'Berg',
delete_this_wallet: 'Vernietig hierdie beursie', delete_this_wallet: 'Vernietig hierdie beursie',
export_backup: 'voer uit / kopieer', export_backup: 'voer uit / kopieer',
buy_bitcoin: 'Koop Bitcoin', buy_bitcoin: 'Koop Bitcoin',
show_xpub: 'Wys beursie XPUB', show_xpub: 'Wys beursie XPUB',
connected_to: 'Connected to', connected_to: 'Connected to',
advanced: 'Advanced', advanced: 'Advanced',
use_with_hardware_wallet: 'Use with hardware wallet', use_with_hardware_wallet: 'Use with hardware wallet',
}, },
export: { export: {
title: 'beursie uitvoer', title: 'beursie uitvoer',
}, },
xpub: { xpub: {
title: 'beursie XPUB', title: 'beursie XPUB',
copiedToClipboard: 'Gestuur na klipbord.', copiedToClipboard: 'Gestuur na klipbord.',
}, },
import: { import: {
title: 'Invoer', title: 'Invoer',
explanation: explanation:
'Sleutel mnemonic, privaat sleutel, WIF, of enige text verwysing. BlueWallet sal die korrekte formaat kies en u beursie importeer ', 'Sleutel mnemonic, privaat sleutel, WIF, of enige text verwysing. BlueWallet sal die korrekte formaat kies en u beursie importeer ',
imported: 'Invoer suksesvol', imported: 'Invoer suksesvol',
error: 'U invoer het misluk. Maak asseblief seker u data is korrek en geldig.', error: 'U invoer het misluk. Maak asseblief seker u data is korrek en geldig.',
success: 'Suksesvol', success: 'Suksesvol',
do_import: 'Invoer', do_import: 'Invoer',
scan_qr: 'of skandeer QR kode?', scan_qr: 'of skandeer QR kode?',
}, },
scanQrWif: { scanQrWif: {
go_back: 'Gaan Terug', go_back: 'Gaan Terug',
cancel: 'Kanseleer', cancel: 'Kanseleer',
decoding: 'Decoding', decoding: 'Decoding',
input_password: 'Input password', input_password: 'Input password',
password_explain: 'Hierdie is n BIP38 ge-enkripteerde privaat sleutel', password_explain: 'Hierdie is n BIP38 ge-enkripteerde privaat sleutel',
bad_password: 'Wagwoord verkeerd', bad_password: 'Wagwoord verkeerd',
wallet_already_exists: 'Hierdie beursie bestaan alreeds', wallet_already_exists: 'Hierdie beursie bestaan alreeds',
bad_wif: 'WIF verkeerd', bad_wif: 'WIF verkeerd',
imported_wif: 'WIF invoer suksesvol ', imported_wif: 'WIF invoer suksesvol ',
with_address: ' met adres ', with_address: ' met adres ',
imported_segwit: 'Segwit Invoer Suksesvol', imported_segwit: 'Segwit Invoer Suksesvol',
imported_legacy: 'Legacy Invoer', imported_legacy: 'Legacy Invoer',
imported_watchonly: 'Kyk Slegs invoer suksesvol', imported_watchonly: 'Kyk Slegs invoer suksesvol',
}, },
}, },
transactions: { transactions: {
list: { list: {
tabBarLabel: 'Transaksies', tabBarLabel: 'Transaksies',
title: 'transaksies', title: 'transaksies',
description: 'Lys met inkomende en uitgaande transaksies van u beursies', description: 'Lys met inkomende en uitgaande transaksies van u beursies',
conf: 'bev.', conf: 'bev.',
}, },
details: { details: {
title: 'Transaksie', title: 'Transaksie',
from: 'Inset', from: 'Inset',
to: 'Resultaat', to: 'Resultaat',
copy: 'Kopieer', copy: 'Kopieer',
transaction_details: 'Transaksie besonderhede', transaction_details: 'Transaksie besonderhede',
show_in_block_explorer: 'Wys in blok verkenner', show_in_block_explorer: 'Wys in blok verkenner',
}, },
}, },
send: { send: {
header: 'Stuur', header: 'Stuur',
details: { details: {
title: 'skep transaksie', title: 'skep transaksie',
amount_field_is_not_valid: 'Bedrag is ongeldig', amount_field_is_not_valid: 'Bedrag is ongeldig',
fee_field_is_not_valid: 'Fooi spasie is ongeldig', fee_field_is_not_valid: 'Fooi spasie is ongeldig',
address_field_is_not_valid: 'Adres is ongeldig', address_field_is_not_valid: 'Adres is ongeldig',
total_exceeds_balance: 'Die bedrag is meer as die beskikbare balans.', total_exceeds_balance: 'Die bedrag is meer as die beskikbare balans.',
create_tx_error: 'Daar was n probleem met die skepping van die transaksie. Bevestig asseblief die adres is geldig.', create_tx_error: 'Daar was n probleem met die skepping van die transaksie. Bevestig asseblief die adres is geldig.',
address: 'adres', address: 'adres',
amount_placeholder: 'bedrag om te stuur (in BTC)', amount_placeholder: 'bedrag om te stuur (in BTC)',
fee_placeholder: 'plus transaksie fooi (in BTC)', fee_placeholder: 'plus transaksie fooi (in BTC)',
note_placeholder: 'persoonlike notas', note_placeholder: 'persoonlike notas',
cancel: 'Kanselleer', cancel: 'Kanselleer',
scan: 'Skandeer', scan: 'Skandeer',
send: 'Stuur', send: 'Stuur',
create: 'Skep', create: 'Skep',
remaining_balance: 'Oorblywende balans', remaining_balance: 'Oorblywende balans',
}, },
confirm: { confirm: {
header: 'Bevestig', header: 'Bevestig',
sendNow: 'Stuur nou', sendNow: 'Stuur nou',
}, },
success: { success: {
done: 'Klaar', done: 'Klaar',
}, },
create: { create: {
details: 'Besonderhede', details: 'Besonderhede',
title: 'skep transaksie', title: 'skep transaksie',
error: 'Daar is n probleem met die transaksie. Ongeldige adres of bedrag?', error: 'Daar is n probleem met die transaksie. Ongeldige adres of bedrag?',
go_back: 'Gaan Terug', go_back: 'Gaan Terug',
this_is_hex: 'Hierdie is die transaksie hex, geteken en gereed om na die netwerk uitgesaai te word.', this_is_hex: 'Hierdie is die transaksie hex, geteken en gereed om na die netwerk uitgesaai te word.',
to: 'Aan', to: 'Aan',
amount: 'Bedrag', amount: 'Bedrag',
fee: 'Fooi', fee: 'Fooi',
tx_size: 'TX groote', tx_size: 'TX groote',
satoshi_per_byte: 'Satoshi per byte', satoshi_per_byte: 'Satoshi per byte',
memo: 'Memo', memo: 'Memo',
broadcast: 'Saai uit', broadcast: 'Saai uit',
not_enough_fee: 'Fooi te laag. Vermeerder die fooi', not_enough_fee: 'Fooi te laag. Vermeerder die fooi',
}, },
}, },
receive: { receive: {
header: 'Ontvang', header: 'Ontvang',
details: { details: {
title: 'Deel adres met krediteur', title: 'Deel adres met krediteur',
share: 'deel', share: 'deel',
copiedToClipboard: 'Gekopieer na klipbord.', copiedToClipboard: 'Gekopieer na klipbord.',
label: 'Beskrywing', label: 'Beskrywing',
create: 'Skep', create: 'Skep',
setAmount: 'Bedrag ontvang', setAmount: 'Bedrag ontvang',
}, },
scan_lnurl: 'Scan to receive', scan_lnurl: 'Scan to receive',
}, },
buyBitcoin: { buyBitcoin: {
header: 'Koop Bitcoin', header: 'Koop Bitcoin',
tap_your_address: 'Raak aan die adres om dit na die klipbord the stuur:', tap_your_address: 'Raak aan die adres om dit na die klipbord the stuur:',
copied: 'Gekopieer na klipbord!', copied: 'Gekopieer na klipbord!',
}, },
settings: { settings: {
header: 'instellings', header: 'instellings',
plausible_deniability: 'Geloofwaardige ontkenbaarheid...', plausible_deniability: 'Geloofwaardige ontkenbaarheid...',
storage_not_encrypted: 'Berging: Nie-geenkripteer nie', storage_not_encrypted: 'Berging: Nie-geenkripteer nie',
storage_encrypted: 'Berging: Ge-enkripteer', storage_encrypted: 'Berging: Ge-enkripteer',
password: 'Wagwoord', password: 'Wagwoord',
password_explain: 'Skep die wagwoord wat u sal gebruik om u berging te de-enkripteer', password_explain: 'Skep die wagwoord wat u sal gebruik om u berging te de-enkripteer',
retype_password: 'Hervoer wagwoord', retype_password: 'Hervoer wagwoord',
passwords_do_not_match: 'Wagwoorde stem nie oor een nie', passwords_do_not_match: 'Wagwoorde stem nie oor een nie',
encrypt_storage: 'Enkripteer Berging', encrypt_storage: 'Enkripteer Berging',
lightning_settings: 'Lightning Instellings', lightning_settings: 'Lightning Instellings',
lightning_settings_explain: lightning_settings_explain:
'Om u eie LND node te konnekteer, installeer asseblief LndHub' + 'Om u eie LND node te konnekteer, installeer asseblief LndHub' +
' and put its URL here in settings. Leave blank om die standaard LndHub' + ' and put its URL here in settings. Leave blank om die standaard LndHub' +
'(lndhub.io) te gebruik', '(lndhub.io) te gebruik',
electrum_settings: 'Electrum Settings', electrum_settings: 'Electrum Settings',
electrum_settings_explain: 'Set to blank to use default', electrum_settings_explain: 'Set to blank to use default',
save: 'stoor', save: 'stoor',
about: 'info', about: 'info',
language: 'Taal', language: 'Taal',
currency: 'Geldeenheid', currency: 'Geldeenheid',
advanced_options: 'Advanced Options', advanced_options: 'Advanced Options',
enable_advanced_mode: 'Enable advanced mode', enable_advanced_mode: 'Enable advanced mode',
}, },
plausibledeniability: { plausibledeniability: {
title: 'Geloofwaardige Ontkenbaarheid', title: 'Geloofwaardige Ontkenbaarheid',
help: help:
'Onder sekere omstandighede mag u dalk geforseer word om u ' + 'Onder sekere omstandighede mag u dalk geforseer word om u ' +
'wagwoord te deel teen u wil. Om u te beskerm kan Bluewallet n ' + 'wagwoord te deel teen u wil. Om u te beskerm kan Bluewallet n ' +
'tweede “fantasie” beursie skep wat as skerm kan dien. Indien u ' + 'tweede “fantasie” beursie skep wat as skerm kan dien. Indien u ' +
'hierdie wagwoord deel sal die 3de party nie toegang tot u hoof fondse kry nie.', 'hierdie wagwoord deel sal die 3de party nie toegang tot u hoof fondse kry nie.',
help2: 'Fantasie berging is heeltemal funksioneel', help2: 'Fantasie berging is heeltemal funksioneel',
create_fake_storage: 'Skep fantasie berging wagwoord', create_fake_storage: 'Skep fantasie berging wagwoord',
go_back: 'Gaan terug', go_back: 'Gaan terug',
create_password: 'Skep n wagwoord', create_password: 'Skep n wagwoord',
create_password_explanation: 'Die wagwoord vir fantasie berging moet verskil van die wagwoord vir hoof berging', create_password_explanation: 'Die wagwoord vir fantasie berging moet verskil van die wagwoord vir hoof berging',
password_should_not_match: 'Die wagwoord vir fantasie berging moet verskil van die wagwoord vir hoof berging.', password_should_not_match: 'Die wagwoord vir fantasie berging moet verskil van die wagwoord vir hoof berging.',
retype_password: 'Hervoer wagwoord', retype_password: 'Hervoer wagwoord',
passwords_do_not_match: 'Wagwoorde vergelyk nie, probeer weer', passwords_do_not_match: 'Wagwoorde vergelyk nie, probeer weer',
success: 'Sukses', success: 'Sukses',
}, },
lnd: { lnd: {
title: 'bestuur fondse', title: 'bestuur fondse',
choose_source_wallet: 'Kies n bron beursie', choose_source_wallet: 'Kies n bron beursie',
refill_lnd_balance: 'Herlaai Lightning beursie', refill_lnd_balance: 'Herlaai Lightning beursie',
refill: 'Herlaai', refill: 'Herlaai',
withdraw: 'Ontrek', withdraw: 'Ontrek',
expired: 'Verval', expired: 'Verval',
placeholder: 'Faktuur', placeholder: 'Faktuur',
sameWalletAsInvoiceError: 'U kan nie n faktuur betaal met die selfde beursie waarmee die faktuur geksep is nie.', sameWalletAsInvoiceError: 'U kan nie n faktuur betaal met die selfde beursie waarmee die faktuur geksep is nie.',
}, },
pleasebackup: { pleasebackup: {
title: 'Your wallet is created...', title: 'Your wallet is created...',
text: text:
"Please take a moment to write down this mnemonic phrase on a piece of paper. It's your backup you can use to restore the wallet on other device.", "Please take a moment to write down this mnemonic phrase on a piece of paper. It's your backup you can use to restore the wallet on other device.",
ok: 'OK, I wrote this down!', ok: 'OK, I wrote this down!',
}, },
lndViewInvoice: { lndViewInvoice: {
wasnt_paid_and_expired: 'This invoice was not paid for and has expired', wasnt_paid_and_expired: 'This invoice was not paid for and has expired',
has_been_paid: 'This invoice has been paid for', has_been_paid: 'This invoice has been paid for',
please_pay: 'Please pay', please_pay: 'Please pay',
sats: 'sats', sats: 'sats',
for: 'For:', for: 'For:',
additional_info: 'Additional Information', additional_info: 'Additional Information',
open_direct_channel: 'Open direct channel with this node:', open_direct_channel: 'Open direct channel with this node:',
}, },
}; };

View file

@ -1,252 +1,252 @@
module.exports = { module.exports = {
_: { _: {
storage_is_encrypted: 'Ukugcinwa kwakho kubhaliwe. Inombolo yokuvula iyadingeka ukuba ichithwe', storage_is_encrypted: 'Ukugcinwa kwakho kubhaliwe. Inombolo yokuvula iyadingeka ukuba ichithwe',
enter_password: 'Faka inombolo yokuvula', enter_password: 'Faka inombolo yokuvula',
bad_password: 'Iphasiwedi engalunganga, zama kwakhona', bad_password: 'Iphasiwedi engalunganga, zama kwakhona',
never: 'Ungalingi', never: 'Ungalingi',
continue: 'Qhubeka', continue: 'Qhubeka',
ok: 'OK', ok: 'OK',
}, },
wallets: { wallets: {
select_wallet: 'Khetha ingxowa', select_wallet: 'Khetha ingxowa',
options: 'Ukhetho', options: 'Ukhetho',
createBitcoinWallet: createBitcoinWallet:
'Okwangoku awunayo ingxowa yebitcoin. Ukuze kuxhaswe ingxowa ekhawulezayo, Ingxowa yeBitcoin kufuneka idalwe okanye ikhutshelwe. Ungathanda ukuqhubeka ?', 'Okwangoku awunayo ingxowa yebitcoin. Ukuze kuxhaswe ingxowa ekhawulezayo, Ingxowa yeBitcoin kufuneka idalwe okanye ikhutshelwe. Ungathanda ukuqhubeka ?',
list: { list: {
app_name: 'BlueWallet', app_name: 'BlueWallet',
title: 'Ingxowa', title: 'Ingxowa',
header: 'Ingxowa imele ukuba nemfihlelo yokuyivula nekheli kwaye unokuyisebenzisa ukwamkela imali.', header: 'Ingxowa imele ukuba nemfihlelo yokuyivula nekheli kwaye unokuyisebenzisa ukwamkela imali.',
add: 'Yongeza Ingxowa', add: 'Yongeza Ingxowa',
create_a_wallet: 'Yenza ingxowa', create_a_wallet: 'Yenza ingxowa',
create_a_wallet1: 'Ayihlawulelwa kwaye ungayenza', create_a_wallet1: 'Ayihlawulelwa kwaye ungayenza',
create_a_wallet2: 'Ungenza zibeninzi indlela zokuhlawula', create_a_wallet2: 'Ungenza zibeninzi indlela zokuhlawula',
create_a_button: 'Add now', create_a_button: 'Add now',
latest_transaction: 'Utshintsho olutsha', latest_transaction: 'Utshintsho olutsha',
empty_txs1: 'Intengiso yakho iya kubonakala apha,', empty_txs1: 'Intengiso yakho iya kubonakala apha,',
empty_txs2: 'akuho nanye okwangoku', empty_txs2: 'akuho nanye okwangoku',
empty_txs1_lightning: empty_txs1_lightning:
'Lightning wallet should be used for your daily transactions. Fees are unfairly cheap and speed is blazing fast.', 'Lightning wallet should be used for your daily transactions. Fees are unfairly cheap and speed is blazing fast.',
empty_txs2_lightning: '\nTo start using it tap on "manage funds" and topup your balance.', empty_txs2_lightning: '\nTo start using it tap on "manage funds" and topup your balance.',
tap_here_to_buy: 'Cofa apha ukuthenga ibitcoin', tap_here_to_buy: 'Cofa apha ukuthenga ibitcoin',
}, },
reorder: { reorder: {
title: 'Yenza kwakhona ingxowa', title: 'Yenza kwakhona ingxowa',
}, },
add: { add: {
title: 'yongeza ingxowa', title: 'yongeza ingxowa',
description: description:
'Unokukhangela ingxowa yephepha yokugcinwa kwephepha ( kwi-WIF indlela lokungenisa ingxowa), okanye wenze ingxowa entsha. Ingxowa yeSegwit exhaswa yi-default.', 'Unokukhangela ingxowa yephepha yokugcinwa kwephepha ( kwi-WIF indlela lokungenisa ingxowa), okanye wenze ingxowa entsha. Ingxowa yeSegwit exhaswa yi-default.',
scan: 'Ukuqondisa', scan: 'Ukuqondisa',
create: 'Yakha', create: 'Yakha',
label_new_segwit: 'SegWit entsha', label_new_segwit: 'SegWit entsha',
label_new_lightning: 'Umbane omtsha', label_new_lightning: 'Umbane omtsha',
wallet_name: 'igama lengxowa', wallet_name: 'igama lengxowa',
wallet_type: 'uhlobo', wallet_type: 'uhlobo',
or: 'okanye', or: 'okanye',
import_wallet: 'Ukungenisa ingxowa', import_wallet: 'Ukungenisa ingxowa',
imported: 'ngeniswa', imported: 'ngeniswa',
coming_soon: 'Kuza ngokukhawuleza', coming_soon: 'Kuza ngokukhawuleza',
lightning: 'Umbane', lightning: 'Umbane',
bitcoin: 'Bitcoin', bitcoin: 'Bitcoin',
}, },
details: { details: {
title: 'Ingxowa', title: 'Ingxowa',
address: 'Ikheli', address: 'Ikheli',
master_fingerprint: 'Master fingerprint', master_fingerprint: 'Master fingerprint',
type: 'Uhlobo', type: 'Uhlobo',
label: 'Igama', label: 'Igama',
destination: 'ukuya kuyo', destination: 'ukuya kuyo',
description: 'ukuya kuyo', description: 'ukuya kuyo',
are_you_sure: 'Ingaba uqinisekile?', are_you_sure: 'Ingaba uqinisekile?',
yes_delete: 'Ewe, yisuse', yes_delete: 'Ewe, yisuse',
no_cancel: 'Hayi, rhoxisa', no_cancel: 'Hayi, rhoxisa',
delete: 'Cima', delete: 'Cima',
save: 'Gcina', save: 'Gcina',
delete_this_wallet: 'Cima le ngxowa', delete_this_wallet: 'Cima le ngxowa',
export_backup: 'Ukuthumela ngaphandle / yokugcina', export_backup: 'Ukuthumela ngaphandle / yokugcina',
buy_bitcoin: 'Thenga ibitcoin', buy_bitcoin: 'Thenga ibitcoin',
show_xpub: 'Bonise ingxowa XPUB', show_xpub: 'Bonise ingxowa XPUB',
connected_to: 'Connected to', connected_to: 'Connected to',
advanced: 'Advanced', advanced: 'Advanced',
use_with_hardware_wallet: 'Use with hardware wallet', use_with_hardware_wallet: 'Use with hardware wallet',
}, },
export: { export: {
title: 'ukuthunyelwa kweebhanki ', title: 'ukuthunyelwa kweebhanki ',
}, },
xpub: { xpub: {
title: 'ingxowa XPUB', title: 'ingxowa XPUB',
copiedToClipboard: 'Ikopishwe kwi-clipboard', copiedToClipboard: 'Ikopishwe kwi-clipboard',
}, },
import: { import: {
title: 'ukungenisa', title: 'ukungenisa',
explanation: explanation:
'Bhale apha imnemonic yakho, ngundoqo, WIF , okanye nantoni na onayo. BlueWallet uya kwenza konke okusemandleni ukuqiqa ifomathi efanelekileyo kwaye ingenise ingxowa yakho', 'Bhale apha imnemonic yakho, ngundoqo, WIF , okanye nantoni na onayo. BlueWallet uya kwenza konke okusemandleni ukuqiqa ifomathi efanelekileyo kwaye ingenise ingxowa yakho',
imported: 'Ngenisiwe', imported: 'Ngenisiwe',
error: 'Ayiphumelelanga ukungenisa. Nceda, uqiniseka ukuba idata ehlinzekiweyo iyasebenza.', error: 'Ayiphumelelanga ukungenisa. Nceda, uqiniseka ukuba idata ehlinzekiweyo iyasebenza.',
success: 'Iphumelele', success: 'Iphumelele',
do_import: 'Ngeniswe', do_import: 'Ngeniswe',
scan_qr: 'okanye ukukhangela iQR code?', scan_qr: 'okanye ukukhangela iQR code?',
}, },
scanQrWif: { scanQrWif: {
go_back: 'Buya Umva', go_back: 'Buya Umva',
cancel: 'Rhoxisa', cancel: 'Rhoxisa',
decoding: 'Ukumisela', decoding: 'Ukumisela',
input_password: 'Igama lokungena', input_password: 'Igama lokungena',
password_explain: 'Yi le BIP38 ikhifidi yangasese itsixe', password_explain: 'Yi le BIP38 ikhifidi yangasese itsixe',
bad_password: 'Inombolo yokuvula eli ngalunganga ', bad_password: 'Inombolo yokuvula eli ngalunganga ',
wallet_already_exists: 'Ikhredithi enjalo sele ikhona', wallet_already_exists: 'Ikhredithi enjalo sele ikhona',
bad_wif: 'Ezimbi WIF', bad_wif: 'Ezimbi WIF',
imported_wif: 'Ngeniswa WIF ', imported_wif: 'Ngeniswa WIF ',
with_address: ' Nge dilesi ', with_address: ' Nge dilesi ',
imported_segwit: 'Ngeniswa SegWit', imported_segwit: 'Ngeniswa SegWit',
imported_legacy: 'Ngeniswa ilifa', imported_legacy: 'Ngeniswa ilifa',
imported_watchonly: 'Ngeniswa bukele-kuphela', imported_watchonly: 'Ngeniswa bukele-kuphela',
}, },
}, },
transactions: { transactions: {
list: { list: {
tabBarLabel: 'Ngeniswa', tabBarLabel: 'Ngeniswa',
title: 'ngeniswa', title: 'ngeniswa',
description: 'Uluhlu lokungena okanye ukuphuma kweekhredithi zakho', description: 'Uluhlu lokungena okanye ukuphuma kweekhredithi zakho',
conf: 'conf', conf: 'conf',
}, },
details: { details: {
title: 'Ngeniswa', title: 'Ngeniswa',
from: 'Negalelo', from: 'Negalelo',
to: 'Mveliso', to: 'Mveliso',
copy: 'Ikopi', copy: 'Ikopi',
transaction_details: 'Iinkcukacha zentengiselwano', transaction_details: 'Iinkcukacha zentengiselwano',
show_in_block_explorer: 'Bonisa ibhloko umhloi', show_in_block_explorer: 'Bonisa ibhloko umhloi',
}, },
}, },
send: { send: {
header: 'Thumela', header: 'Thumela',
details: { details: {
title: 'ukudala ukuthenga', title: 'ukudala ukuthenga',
amount_field_is_not_valid: 'intsimi yexabiso ayivumelekanga', amount_field_is_not_valid: 'intsimi yexabiso ayivumelekanga',
fee_field_is_not_valid: 'Intsimi yentlawulo ayivumelekanga ', fee_field_is_not_valid: 'Intsimi yentlawulo ayivumelekanga ',
address_field_is_not_valid: 'Intsimi yeedilesi ayivumelekanga', address_field_is_not_valid: 'Intsimi yeedilesi ayivumelekanga',
total_exceeds_balance: 'Imali yokuthumela idlula imali ekhoyo.', total_exceeds_balance: 'Imali yokuthumela idlula imali ekhoyo.',
create_tx_error: 'Kukho impazamo yokudala ukuthengiselana. Nceda, qinisekisa ukuba idilesi iyasebenza.', create_tx_error: 'Kukho impazamo yokudala ukuthengiselana. Nceda, qinisekisa ukuba idilesi iyasebenza.',
address: 'idilesi', address: 'idilesi',
amount_placeholder: 'inani lokuthumela (nge BTC)', amount_placeholder: 'inani lokuthumela (nge BTC)',
fee_placeholder: 'kunye nentlawulo yokuthengiswa (nge BTC)', fee_placeholder: 'kunye nentlawulo yokuthengiswa (nge BTC)',
note_placeholder: 'inqaku kumntu', note_placeholder: 'inqaku kumntu',
cancel: 'Rhoxisa', cancel: 'Rhoxisa',
scan: 'Ukutshekisha', scan: 'Ukutshekisha',
send: 'Thumela', send: 'Thumela',
create: 'Yenza', create: 'Yenza',
remaining_balance: 'Ibhalansi eseleyo', remaining_balance: 'Ibhalansi eseleyo',
}, },
confirm: { confirm: {
header: 'Qiniseka', header: 'Qiniseka',
sendNow: 'Thumela ngoku', sendNow: 'Thumela ngoku',
}, },
success: { success: {
done: 'Kwenzekile', done: 'Kwenzekile',
}, },
create: { create: {
details: 'Iinkcukacha', details: 'Iinkcukacha',
title: 'ukudala ukuthenga', title: 'ukudala ukuthenga',
error: 'Impazamo yokudala ukuthengiselana. Idilesi engavumelekanga okanye imali yokuthumela?', error: 'Impazamo yokudala ukuthengiselana. Idilesi engavumelekanga okanye imali yokuthumela?',
go_back: 'Buya umva', go_back: 'Buya umva',
this_is_hex: 'Le yi ntengo hex, ityikityiwe ilungele ukukhutshelwa kumnatha.', this_is_hex: 'Le yi ntengo hex, ityikityiwe ilungele ukukhutshelwa kumnatha.',
to: 'Iya ku', to: 'Iya ku',
amount: 'Isixa', amount: 'Isixa',
fee: 'Ntlawulo', fee: 'Ntlawulo',
tx_size: 'TX ubungakanani', tx_size: 'TX ubungakanani',
satoshi_per_byte: 'Satoshi nge-byte', satoshi_per_byte: 'Satoshi nge-byte',
memo: 'Memo', memo: 'Memo',
broadcast: 'Sasazwa', broadcast: 'Sasazwa',
not_enough_fee: 'Akukho mali e neleyo. UKwandisa intlawulo ', not_enough_fee: 'Akukho mali e neleyo. UKwandisa intlawulo ',
}, },
}, },
receive: { receive: {
header: 'Fumana', header: 'Fumana',
details: { details: {
title: 'Wabelane ngale dilesi nomhlawuli', title: 'Wabelane ngale dilesi nomhlawuli',
share: 'yabelana', share: 'yabelana',
copiedToClipboard: 'Ikhutshelwe kwi-clipboard', copiedToClipboard: 'Ikhutshelwe kwi-clipboard',
label: 'Inkcazo', label: 'Inkcazo',
create: 'Yenza', create: 'Yenza',
setAmount: 'Fumana ngexabiso', setAmount: 'Fumana ngexabiso',
}, },
scan_lnurl: 'Scan to receive', scan_lnurl: 'Scan to receive',
}, },
buyBitcoin: { buyBitcoin: {
header: 'Thenga Ibitcoin', header: 'Thenga Ibitcoin',
tap_your_address: 'Thepha idilesi yakho ukuyikopisha kwi-clipboard:', tap_your_address: 'Thepha idilesi yakho ukuyikopisha kwi-clipboard:',
copied: 'Ikhutshelwe kwi-clipboard!', copied: 'Ikhutshelwe kwi-clipboard!',
}, },
settings: { settings: {
header: 'Izicwangciso', header: 'Izicwangciso',
plausible_deniability: 'Ukuphika...', plausible_deniability: 'Ukuphika...',
storage_not_encrypted: 'Ukugciwa: hayi ngekhodi', storage_not_encrypted: 'Ukugciwa: hayi ngekhodi',
storage_encrypted: 'Ukugciwa: ngekhodi', storage_encrypted: 'Ukugciwa: ngekhodi',
password: 'Inombolo yokuvula', password: 'Inombolo yokuvula',
password_explain: 'Ukudala iinombolo yokuvula oyisebenzisayo ukucima ukugcina', password_explain: 'Ukudala iinombolo yokuvula oyisebenzisayo ukucima ukugcina',
retype_password: 'Phina inombolo yokuvula', retype_password: 'Phina inombolo yokuvula',
passwords_do_not_match: 'Inombolo yokuvula azifani', passwords_do_not_match: 'Inombolo yokuvula azifani',
encrypt_storage: 'Kubhala u kubhala', encrypt_storage: 'Kubhala u kubhala',
lightning_settings: 'Izixhobo zokukhanyisa', lightning_settings: 'Izixhobo zokukhanyisa',
lightning_settings_explain: lightning_settings_explain:
'Ukuxhuma kwi-node yakho ye-LND nceda ufake iLndHub' + 'Ukuxhuma kwi-node yakho ye-LND nceda ufake iLndHub' +
' kwaye ufake iURL apha izicwangciso. Shiya kungenanto yokusebenzisa iLndHub (Indhub.io)', ' kwaye ufake iURL apha izicwangciso. Shiya kungenanto yokusebenzisa iLndHub (Indhub.io)',
electrum_settings: 'Electrum Settings', electrum_settings: 'Electrum Settings',
electrum_settings_explain: 'Set to blank to use default', electrum_settings_explain: 'Set to blank to use default',
save: 'ndoloza', save: 'ndoloza',
about: 'Malunga', about: 'Malunga',
language: 'Ulwimi', language: 'Ulwimi',
currency: 'Lwemali', currency: 'Lwemali',
advanced_options: 'Advanced Options', advanced_options: 'Advanced Options',
enable_advanced_mode: 'Enable advanced mode', enable_advanced_mode: 'Enable advanced mode',
}, },
plausibledeniability: { plausibledeniability: {
title: 'Ukuphika', title: 'Ukuphika',
help: help:
'Phantsi kweemeko unokunyaneliswa ukuba uchaze a ' + 'Phantsi kweemeko unokunyaneliswa ukuba uchaze a ' +
'inombolo yokuvula. BlueWallet ukugcina imali yakho ikhuselekile, unokudala enye ' + 'inombolo yokuvula. BlueWallet ukugcina imali yakho ikhuselekile, unokudala enye ' +
'ukugcinwa kwekhowudi, ngegama eligqithisiweyo. Phantsi kwefuthe, ' + 'ukugcinwa kwekhowudi, ngegama eligqithisiweyo. Phantsi kwefuthe, ' +
'unako ukutyhila le phasiwedi kumntu wesithatu. Ukuba ungenayo ' + 'unako ukutyhila le phasiwedi kumntu wesithatu. Ukuba ungenayo ' +
'BlueWallet, iya kuvula ukugcinwa kwetyala entsha. Oku kuya kubonakala ' + 'BlueWallet, iya kuvula ukugcinwa kwetyala entsha. Oku kuya kubonakala ' +
'Umlenze kumntu wesithathu kodwa uza kugcina ngasese ukugcinwa kwakho ' + 'Umlenze kumntu wesithathu kodwa uza kugcina ngasese ukugcinwa kwakho ' +
'ngemali ekhuselekile..', 'ngemali ekhuselekile..',
help2: help2:
'Igumbi lokugcina elitsha liza kusebenza ngokupheleleyo, kwaye unako ukugcina okunye + lxabiso elincinci apho likhangeleka ngakumbi.', 'Igumbi lokugcina elitsha liza kusebenza ngokupheleleyo, kwaye unako ukugcina okunye + lxabiso elincinci apho likhangeleka ngakumbi.',
create_fake_storage: 'Ukudala igumbi lokugcina elifihlakeleyo', create_fake_storage: 'Ukudala igumbi lokugcina elifihlakeleyo',
go_back: 'Buya Umva', go_back: 'Buya Umva',
create_password: 'Yenza inombolo yokuvula', create_password: 'Yenza inombolo yokuvula',
create_password_explanation: create_password_explanation:
'Inombolo yakho yokuvula igumbi lokugcina inkohliso akumele ifane ne nombolo yokuvula igumbi lakho elinyanisekileyo', 'Inombolo yakho yokuvula igumbi lokugcina inkohliso akumele ifane ne nombolo yokuvula igumbi lakho elinyanisekileyo',
password_should_not_match: password_should_not_match:
'Inombolo yakho yokuvula igumbi lokugcina inkohliso akumele ifane ne nombolo yokuvula igumbi lakho elinyanisekileyo', 'Inombolo yakho yokuvula igumbi lokugcina inkohliso akumele ifane ne nombolo yokuvula igumbi lakho elinyanisekileyo',
retype_password: 'Phinda inombolo yokuvula', retype_password: 'Phinda inombolo yokuvula',
passwords_do_not_match: 'Inombolo yokuvula ayihambelani, zama kwakhona', passwords_do_not_match: 'Inombolo yokuvula ayihambelani, zama kwakhona',
success: 'Iphumelele', success: 'Iphumelele',
}, },
lnd: { lnd: {
title: 'lawula imali', title: 'lawula imali',
choose_source_wallet: 'Ukhethe ingxowa yomthombo', choose_source_wallet: 'Ukhethe ingxowa yomthombo',
refill_lnd_balance: 'Gcwalisa ingxowa yakho yemali', refill_lnd_balance: 'Gcwalisa ingxowa yakho yemali',
refill: 'Gcwalisa', refill: 'Gcwalisa',
withdraw: 'Khupha imali', withdraw: 'Khupha imali',
expired: 'Iphelewe lixesha', expired: 'Iphelewe lixesha',
placeholder: 'Invoyisi', placeholder: 'Invoyisi',
sameWalletAsInvoiceError: ': Awukwazi ukuhlawula i-invoyisi kunye ngengxowa oyisebenzisile ukudala leyo invoyisi.', sameWalletAsInvoiceError: ': Awukwazi ukuhlawula i-invoyisi kunye ngengxowa oyisebenzisile ukudala leyo invoyisi.',
}, },
pleasebackup: { pleasebackup: {
title: 'Your wallet is created...', title: 'Your wallet is created...',
text: text:
"Please take a moment to write down this mnemonic phrase on a piece of paper. It's your backup you can use to restore the wallet on other device.", "Please take a moment to write down this mnemonic phrase on a piece of paper. It's your backup you can use to restore the wallet on other device.",
ok: 'OK, I wrote this down!', ok: 'OK, I wrote this down!',
}, },
lndViewInvoice: { lndViewInvoice: {
wasnt_paid_and_expired: 'This invoice was not paid for and has expired', wasnt_paid_and_expired: 'This invoice was not paid for and has expired',
has_been_paid: 'This invoice has been paid for', has_been_paid: 'This invoice has been paid for',
please_pay: 'Please pay', please_pay: 'Please pay',
sats: 'sats', sats: 'sats',
for: 'For:', for: 'For:',
additional_info: 'Additional Information', additional_info: 'Additional Information',
open_direct_channel: 'Open direct channel with this node:', open_direct_channel: 'Open direct channel with this node:',
}, },
}; };

View file

@ -1,6 +1,6 @@
module.exports = { module.exports = {
_: { _: {
storage_is_encrypted: 'L\'informació està xifrada. Es requereix la contrasenya per a desxifrar-la.', storage_is_encrypted: "L'informació està xifrada. Es requereix la contrasenya per a desxifrar-la.",
enter_password: 'Introduïu la contrasenya', enter_password: 'Introduïu la contrasenya',
bad_password: 'Contrasenya incorrecta. Torna-ho a provar.', bad_password: 'Contrasenya incorrecta. Torna-ho a provar.',
never: 'mai', never: 'mai',
@ -82,7 +82,7 @@ module.exports = {
explanation: explanation:
'Escrigui aquí el mnemotècnic, clau privada, WIF, o quelcom que tingui. BlueWallet fara tot el posible per encertar el formato correcte e importar el moneder.', 'Escrigui aquí el mnemotècnic, clau privada, WIF, o quelcom que tingui. BlueWallet fara tot el posible per encertar el formato correcte e importar el moneder.',
imported: 'Importat', imported: 'Importat',
error: 'No s\'ha pogut importar. ¿És vàlid?', error: "No s'ha pogut importar. ¿És vàlid?",
success: 'Èxit', success: 'Èxit',
do_import: 'Importar', do_import: 'Importar',
scan_qr: 'o escanejar codi QR?', scan_qr: 'o escanejar codi QR?',
@ -116,7 +116,7 @@ module.exports = {
to: 'A', to: 'A',
copy: 'Copiar', copy: 'Copiar',
transaction_details: 'Detalls de la transacció', transaction_details: 'Detalls de la transacció',
show_in_block_explorer: 'Mostrar en l\'explorador de blocs', show_in_block_explorer: "Mostrar en l'explorador de blocs",
}, },
}, },
send: { send: {
@ -133,11 +133,11 @@ module.exports = {
amount_field_is_not_valid: 'Quantitat invalida', amount_field_is_not_valid: 'Quantitat invalida',
fee_field_is_not_valid: 'Comissió invalida', fee_field_is_not_valid: 'Comissió invalida',
address_field_is_not_valid: 'Adreça invalida', address_field_is_not_valid: 'Adreça invalida',
receiver_placeholder: 'L\'adreça del beneficiari', receiver_placeholder: "L'adreça del beneficiari",
amount_placeholder: 'quantitat a enviar (en BTC)', amount_placeholder: 'quantitat a enviar (en BTC)',
fee_placeholder: 'més la comissió per la transacció (en BTC)', fee_placeholder: 'més la comissió per la transacció (en BTC)',
note_placeholder: 'comentari (útil per tu)', note_placeholder: 'comentari (útil per tu)',
create_tx_error: 'S\'ha produït un error en crear la transacció. Si us plau, asseguris que l\'adreça es valida.', create_tx_error: "S'ha produït un error en crear la transacció. Si us plau, asseguris que l'adreça es valida.",
cancel: 'Cancel·lar', cancel: 'Cancel·lar',
scan: 'Escanejar', scan: 'Escanejar',
address: 'Adreça', address: 'Adreça',
@ -149,9 +149,10 @@ module.exports = {
create: { create: {
title: 'Crear una transacció', title: 'Crear una transacció',
details: 'Detalls', details: 'Detalls',
error: 'Error en crear una transacció. Són l\'adreça i la quantitat valides?', error: "Error en crear una transacció. Són l'adreça i la quantitat valides?",
go_back: 'Tornar enrere', go_back: 'Tornar enrere',
this_is_hex: 'Això és la representació en hexadecimal (hex) de la transacció, firmada i llesta per ser enviada a la xarxa. ¿Continuar?', this_is_hex:
'Això és la representació en hexadecimal (hex) de la transacció, firmada i llesta per ser enviada a la xarxa. ¿Continuar?',
to: 'A', to: 'A',
amount: 'Quantitat', amount: 'Quantitat',
fee: 'Comissió', fee: 'Comissió',
@ -186,16 +187,16 @@ module.exports = {
storage_not_encrypted: 'Informació: NO xifrada (es recomana xifrar-la)', storage_not_encrypted: 'Informació: NO xifrada (es recomana xifrar-la)',
storage_encrypted: 'Informació: xifrada', storage_encrypted: 'Informació: xifrada',
password: 'Contrasenya', password: 'Contrasenya',
password_explain: 'Crear la contrasenya que usaràs per desxifrar l\'informació dels moneders', password_explain: "Crear la contrasenya que usaràs per desxifrar l'informació dels moneders",
retype_password: 'Introdueix de nou la contrasenya contrasenya', retype_password: 'Introdueix de nou la contrasenya contrasenya',
passwords_do_not_match: 'La contrasenya no coincideix', passwords_do_not_match: 'La contrasenya no coincideix',
encrypt_storage: 'Xifrar l\'informacio del moneder', encrypt_storage: "Xifrar l'informacio del moneder",
lightning_settings: 'Configuració Lightning', lightning_settings: 'Configuració Lightning',
lightning_settings_explain: lightning_settings_explain:
'Per connectar-te al teu propi node LND node instala LndHub' + 'Per connectar-te al teu propi node LND node instala LndHub' +
' i posa la seva URL aquí. Deixa el camp buit per utilitzar el LndHub per defecte ' + ' i posa la seva URL aquí. Deixa el camp buit per utilitzar el LndHub per defecte ' +
'\n (lndhub.io)', '\n (lndhub.io)',
electrum_settings: 'Configuració d\'Electrum', electrum_settings: "Configuració d'Electrum",
electrum_settings_explain: 'Deixa-ho buit per usar el valor per defecte', electrum_settings_explain: 'Deixa-ho buit per usar el valor per defecte',
save: 'guardar', save: 'guardar',
about: 'Sobre nosaltres', about: 'Sobre nosaltres',
@ -229,12 +230,11 @@ module.exports = {
withdraw: 'Retirar', withdraw: 'Retirar',
placeholder: 'Factura', placeholder: 'Factura',
expired: 'Caducat', expired: 'Caducat',
sameWalletAsInvoiceError: 'No pots pagar una factura amb el mateix moneder que l\'ha creat.', sameWalletAsInvoiceError: "No pots pagar una factura amb el mateix moneder que l'ha creat.",
}, },
pleasebackup: { pleasebackup: {
title: 'El teu moneder ha estat creat...', title: 'El teu moneder ha estat creat...',
text: text: "Si us plau, apunteu en un paper el mnemotècnic. Aquesta 'frase' et permetrà regenerar el teu moneder en altres dispositius.",
"Si us plau, apunteu en un paper el mnemotècnic. Aquesta 'frase' et permetrà regenerar el teu moneder en altres dispositius.",
ok: 'OK, ja he assegurat una còpia en paper!', ok: 'OK, ja he assegurat una còpia en paper!',
}, },
lndViewInvoice: { lndViewInvoice: {

View file

@ -6,7 +6,6 @@ import relativeTime from 'dayjs/plugin/relativeTime';
const dayjs = require('dayjs'); const dayjs = require('dayjs');
const currency = require('../currency'); const currency = require('../currency');
const BigNumber = require('bignumber.js'); const BigNumber = require('bignumber.js');
let strings;
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
// first-time loading sequence // first-time loading sequence
@ -102,7 +101,7 @@ dayjs.extend(relativeTime);
} }
})(); })();
strings = new Localization({ const strings = new Localization({
en: require('./en.js'), en: require('./en.js'),
ru: require('./ru.js'), ru: require('./ru.js'),
pt_br: require('./pt_BR.js'), pt_br: require('./pt_BR.js'),

View file

@ -10,7 +10,8 @@ module.exports = {
wallets: { wallets: {
select_wallet: 'Vyberte peňaženku', select_wallet: 'Vyberte peňaženku',
options: 'možnosti', options: 'možnosti',
createBitcoinWallet: 'Momentálne nemáte Bitcoinovú peňaženku. Na naplnenie Lightning peňaženky potrebujete vytvoriť alebo importovať Bitcoinovú peňaženku. Chcete aj tak pokračovať?', createBitcoinWallet:
'Momentálne nemáte Bitcoinovú peňaženku. Na naplnenie Lightning peňaženky potrebujete vytvoriť alebo importovať Bitcoinovú peňaženku. Chcete aj tak pokračovať?',
list: { list: {
app_name: 'BlueWallet', app_name: 'BlueWallet',
title: 'peňaženky', title: 'peňaženky',
@ -232,8 +233,7 @@ module.exports = {
}, },
pleasebackup: { pleasebackup: {
title: 'Vaša peňaženka je vytvorená...', title: 'Vaša peňaženka je vytvorená...',
text: text: 'Prosím zapíšte si túto mnemonic frázu na papier. Slúži ako záloha na obnovu peňaženky na inom zariadení.',
"Prosím zapíšte si túto mnemonic frázu na papier. Slúži ako záloha na obnovu peňaženky na inom zariadení.",
ok: 'OK, zapísané!', ok: 'OK, zapísané!',
}, },
lndViewInvoice: { lndViewInvoice: {

View file

@ -19,9 +19,10 @@ export class NetworkTransactionFee {
export default class NetworkTransactionFees { export default class NetworkTransactionFees {
static recommendedFees() { static recommendedFees() {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
let response = await BlueElectrum.estimateFees(); const response = await BlueElectrum.estimateFees();
if (typeof response === 'object') { if (typeof response === 'object') {
const networkFee = new NetworkTransactionFee(response.fast, response.medium, response.slow); const networkFee = new NetworkTransactionFee(response.fast, response.medium, response.slow);
resolve(networkFee); resolve(networkFee);

1119
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -5,21 +5,20 @@
"devDependencies": { "devDependencies": {
"@babel/core": "^7.9.6", "@babel/core": "^7.9.6",
"@babel/runtime": "^7.9.6", "@babel/runtime": "^7.9.6",
"@react-native-community/eslint-config": "^0.0.5", "@react-native-community/eslint-config": "^1.1.0",
"babel-cli": "^6.26.0", "babel-cli": "^6.26.0",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"babel-jest": "^26.0.1", "babel-jest": "^26.0.1",
"babel-preset-flow": "^6.23.0", "babel-preset-flow": "^6.23.0",
"eslint": "^6.5.1", "eslint": "^6.8.0",
"eslint-plugin-babel": "^5.3.0", "eslint-plugin-babel": "^5.3.0",
"eslint-plugin-import": "^2.18.0", "eslint-plugin-import": "^2.20.2",
"eslint-plugin-node": "^9.1.0", "eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1", "eslint-plugin-promise": "^4.2.1",
"eslint-plugin-react": "^7.14.2", "eslint-plugin-react": "^7.20.0",
"flow-bin": "^0.125.1", "flow-bin": "^0.125.1",
"jest": "^24.9.0", "jest": "^24.9.0",
"jetifier": "^1.6.3", "jetifier": "^1.6.3",
"prettier-eslint-cli": "^5.0.0",
"react-test-renderer": "16.9.0" "react-test-renderer": "16.9.0"
}, },
"engines": { "engines": {
@ -35,16 +34,16 @@
"android": "react-native run-android", "android": "react-native run-android",
"android:clean": "cd android; ./gradlew clean ; cd .. ; npm run android", "android:clean": "cd android; ./gradlew clean ; cd .. ; npm run android",
"ios": "react-native run-ios", "ios": "react-native run-ios",
"postinstall": "./node_modules/.bin/rn-nodeify --install buffer,events,process,stream,util,inherits,fs,path --hack; npm run releasenotes2json; npm run podinstall; npx jetify", "postinstall": "rn-nodeify --install buffer,events,process,stream,util,inherits,fs,path --hack; npm run releasenotes2json; npm run podinstall; npx jetify",
"test": "npm run lint && npm run unit && npm run jest", "test": "npm run lint && npm run unit && npm run jest",
"jest": "node node_modules/jest/bin/jest.js -b -w 1 tests/integration/*", "jest": "jest -b -w 1 tests/integration/*",
"e2e:release": "detox build -c android.emu.release; npm run e2e:release-no-build", "e2e:release": "detox build -c android.emu.release; npm run e2e:release-no-build",
"e2e:release-no-build": "detox test -c android.emu.release --record-videos all --take-screenshots all --headless", "e2e:release-no-build": "detox test -c android.emu.release --record-videos all --take-screenshots all --headless",
"e2e:debug": "(test -f android/app/build/outputs/apk/debug/app-debug.apk && test -f android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk) || detox build -c android.emu.debug; detox test -c android.emu.debug", "e2e:debug": "(test -f android/app/build/outputs/apk/debug/app-debug.apk && test -f android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk) || detox build -c android.emu.debug; detox test -c android.emu.debug",
"lint": "./node_modules/.bin/eslint *.js screen/**/*.js screen/ class/ models/ loc/ tests/integration/ tests/e2e/ tests/unit/", "lint": "eslint *.js screen/**/*.js bip70/ blue_modules/crypto.js class/**/*.js models/ loc/ tests/**/*.js",
"lint:fix": "./node_modules/.bin/eslint *.js screen/**/*.js screen/ class/ models/ loc/ tests/integration/ tests/e2e/ tests/unit/ --fix", "lint:fix": "npm run lint -- --fix",
"lint:quickfix": "git status --porcelain | grep -v '\\.json' | grep '\\.js' --color=never | awk '{print $2}' | xargs ./node_modules/.bin/eslint --fix; exit 0", "lint:quickfix": "git status --porcelain | grep -v '\\.json' | grep '\\.js' --color=never | awk '{print $2}' | xargs eslint --fix; exit 0",
"unit": "node node_modules/jest/bin/jest.js tests/unit/*" "unit": "jest tests/unit/*"
}, },
"jest": { "jest": {
"preset": "react-native", "preset": "react-native",
@ -86,10 +85,10 @@
"electrum-client": "git+https://github.com/BlueWallet/rn-electrum-client.git#2a5bb11dd9a8d89f328049d9ed59bce49d88a15d", "electrum-client": "git+https://github.com/BlueWallet/rn-electrum-client.git#2a5bb11dd9a8d89f328049d9ed59bce49d88a15d",
"electrum-mnemonic": "2.0.0", "electrum-mnemonic": "2.0.0",
"eslint-config-prettier": "6.11.0", "eslint-config-prettier": "6.11.0",
"eslint-config-standard": "12.0.0", "eslint-config-standard": "14.1.1",
"eslint-config-standard-react": "7.0.2", "eslint-config-standard-react": "9.2.0",
"eslint-plugin-prettier": "3.1.2", "eslint-plugin-prettier": "3.1.3",
"eslint-plugin-standard": "4.0.0", "eslint-plugin-standard": "4.0.1",
"events": "1.1.1", "events": "1.1.1",
"frisbee": "3.1.2", "frisbee": "3.1.2",
"intl": "1.2.5", "intl": "1.2.5",
@ -98,7 +97,7 @@
"node-libs-react-native": "1.2.0", "node-libs-react-native": "1.2.0",
"path-browserify": "1.0.0", "path-browserify": "1.0.0",
"pbkdf2": "3.0.17", "pbkdf2": "3.0.17",
"prettier": "1.19.1", "prettier": "2.0.5",
"process": "0.11.10", "process": "0.11.10",
"prop-types": "15.7.2", "prop-types": "15.7.2",
"react": "16.9.0", "react": "16.9.0",

View file

@ -11,35 +11,35 @@ let lastTimeTriedToPay = 0;
/// /////////////////////////////////////////////////////////////////////// /// ///////////////////////////////////////////////////////////////////////
// this code has no use in RN, it gets copypasted in webview injected code // this code has no use in RN, it gets copypasted in webview injected code
// //
let bluewalletResponses = {}; const bluewalletResponses = {};
// eslint-disable-next-line // eslint-disable-next-line
var webln = { var webln = {
enable: function() { enable: function () {
window.ReactNativeWebView.postMessage(JSON.stringify({ enable: true })); window.ReactNativeWebView.postMessage(JSON.stringify({ enable: true }));
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
resolve(true); resolve(true);
}); });
}, },
getInfo: function() { getInfo: function () {
window.ReactNativeWebView.postMessage('getInfo'); window.ReactNativeWebView.postMessage('getInfo');
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
reject(new Error('not implemented')); reject(new Error('not implemented'));
}); });
}, },
sendPayment: function(paymentRequest) { sendPayment: function (paymentRequest) {
window.ReactNativeWebView.postMessage(JSON.stringify({ sendPayment: paymentRequest })); window.ReactNativeWebView.postMessage(JSON.stringify({ sendPayment: paymentRequest }));
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
/* nop. intentionally, forever hang promise. /* nop. intentionally, forever hang promise.
lapp page usually asynchroniously checks payment itself, via ajax, lapp page usually asynchroniously checks payment itself, via ajax,
so atm there's no need to pass payment preimage from RN to webview and fullfill promise. so atm there's no need to pass payment preimage from RN to webview and fullfill promise.
might change in future */ might change in future */
}); });
}, },
makeInvoice: function(RequestInvoiceArgs) { makeInvoice: function (RequestInvoiceArgs) {
var id = Math.random(); var id = Math.random();
window.ReactNativeWebView.postMessage(JSON.stringify({ makeInvoice: RequestInvoiceArgs, id: id })); window.ReactNativeWebView.postMessage(JSON.stringify({ makeInvoice: RequestInvoiceArgs, id: id }));
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
var interval = setInterval(function() { var interval = setInterval(function () {
if (bluewalletResponses[id]) { if (bluewalletResponses[id]) {
clearInterval(interval); clearInterval(interval);
resolve(bluewalletResponses[id]); resolve(bluewalletResponses[id]);
@ -47,15 +47,15 @@ var webln = {
}, 1000); }, 1000);
}); });
}, },
signMessage: function() { signMessage: function () {
window.ReactNativeWebView.postMessage('signMessage'); window.ReactNativeWebView.postMessage('signMessage');
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
reject(new Error('not implemented')); reject(new Error('not implemented'));
}); });
}, },
verifyMessage: function() { verifyMessage: function () {
window.ReactNativeWebView.postMessage('verifyMessage'); window.ReactNativeWebView.postMessage('verifyMessage');
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
reject(new Error('not implemented')); reject(new Error('not implemented'));
}); });
}, },
@ -361,7 +361,7 @@ export default class Browser extends Component {
} }
if (json && json.makeInvoice) { if (json && json.makeInvoice) {
let amount = Math.max( const amount = Math.max(
json.makeInvoice.minimumAmount || 0, json.makeInvoice.minimumAmount || 0,
json.makeInvoice.maximumAmount || 0, json.makeInvoice.maximumAmount || 0,
json.makeInvoice.defaultAmount || 0, json.makeInvoice.defaultAmount || 0,
@ -381,7 +381,7 @@ export default class Browser extends Component {
// this.webview.postMessage(JSON.stringify({ bluewalletResponse: { paymentRequest: payreq }, id: json.id })); // this.webview.postMessage(JSON.stringify({ bluewalletResponse: { paymentRequest: payreq }, id: json.id }));
// Since webview.postMessage is removed from webview, we inject javascript that will manually triger document // Since webview.postMessage is removed from webview, we inject javascript that will manually triger document
// event; note how data is passed in 'detail', not 'data' // event; note how data is passed in 'detail', not 'data'
let jsonstr = JSON.stringify({ bluewalletResponse: { paymentRequest: payreq }, id: json.id }); const jsonstr = JSON.stringify({ bluewalletResponse: { paymentRequest: payreq }, id: json.id });
this.webview.injectJavaScript("document.dispatchEvent( new CustomEvent('message', { detail: '" + jsonstr + "' }) );"); this.webview.injectJavaScript("document.dispatchEvent( new CustomEvent('message', { detail: '" + jsonstr + "' }) );");
}, },
}, },
@ -471,7 +471,7 @@ export default class Browser extends Component {
<TouchableOpacity <TouchableOpacity
onPress={() => { onPress={() => {
let reloadUrl = this.state.url; const reloadUrl = this.state.url;
this.setState({ url: 'about:blank' }); this.setState({ url: 'about:blank' });
processedInvoices = {}; processedInvoices = {};
setTimeout(() => this.setState({ url: reloadUrl }), 500); setTimeout(() => this.setState({ url: reloadUrl }), 500);

View file

@ -25,9 +25,9 @@ import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
import NavigationService from '../../NavigationService'; import NavigationService from '../../NavigationService';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { Icon } from 'react-native-elements'; import { Icon } from 'react-native-elements';
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
let EV = require('../../events'); const EV = require('../../events');
let loc = require('../../loc'); const loc = require('../../loc');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
createButton: { createButton: {
@ -207,14 +207,14 @@ export default class LNDCreateInvoice extends Component {
// send to lnurl-withdraw callback url if that exists // send to lnurl-withdraw callback url if that exists
if (this.state.lnurlParams) { if (this.state.lnurlParams) {
let { callback, k1 } = this.state.lnurlParams; const { callback, k1 } = this.state.lnurlParams;
let callbackUrl = callback + (callback.indexOf('?') !== -1 ? '&' : '?') + 'k1=' + k1 + '&pr=' + invoiceRequest; const callbackUrl = callback + (callback.indexOf('?') !== -1 ? '&' : '?') + 'k1=' + k1 + '&pr=' + invoiceRequest;
let resp = await fetch(callbackUrl, { method: 'GET' }); const resp = await fetch(callbackUrl, { method: 'GET' });
if (resp.status >= 300) { if (resp.status >= 300) {
let text = await resp.text(); const text = await resp.text();
throw new Error(text); throw new Error(text);
} }
let reply = await resp.json(); const reply = await resp.json();
if (reply.status === 'ERROR') { if (reply.status === 'ERROR') {
throw new Error('Reply from server: ' + reply.reason); throw new Error('Reply from server: ' + reply.reason);
} }
@ -242,7 +242,7 @@ export default class LNDCreateInvoice extends Component {
} }
// handling fallback lnurl // handling fallback lnurl
let ind = data.indexOf('lightning='); const ind = data.indexOf('lightning=');
if (ind !== -1) { if (ind !== -1) {
data = data.substring(ind + 10).split('&')[0]; data = data.substring(ind + 10).split('&')[0];
} }
@ -251,16 +251,16 @@ export default class LNDCreateInvoice extends Component {
console.log(data); console.log(data);
// decoding the lnurl // decoding the lnurl
let decoded = bech32.decode(data, 1500); const decoded = bech32.decode(data, 1500);
let url = Buffer.from(bech32.fromWords(decoded.words)).toString(); const url = Buffer.from(bech32.fromWords(decoded.words)).toString();
// calling the url // calling the url
try { try {
let resp = await fetch(url, { method: 'GET' }); const resp = await fetch(url, { method: 'GET' });
if (resp.status >= 300) { if (resp.status >= 300) {
throw new Error('Bad response from server'); throw new Error('Bad response from server');
} }
let reply = await resp.json(); const reply = await resp.json();
if (reply.status === 'ERROR') { if (reply.status === 'ERROR') {
throw new Error('Reply from server: ' + reply.reason); throw new Error('Reply from server: ' + reply.reason);
} }
@ -382,8 +382,8 @@ export default class LNDCreateInvoice extends Component {
onChangeText={text => { onChangeText={text => {
if (this.state.lnurlParams) { if (this.state.lnurlParams) {
// in this case we prevent the user from changing the amount to < min or > max // in this case we prevent the user from changing the amount to < min or > max
let { min, max } = this.state.lnurlParams; const { min, max } = this.state.lnurlParams;
let nextAmount = parseInt(text); const nextAmount = parseInt(text);
if (nextAmount < min) { if (nextAmount < min) {
text = min.toString(); text = min.toString();
} else if (nextAmount > max) { } else if (nextAmount > max) {

View file

@ -13,7 +13,7 @@ import {
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import QRCode from 'react-native-qrcode-svg'; import QRCode from 'react-native-qrcode-svg';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
const loc = require('../../loc'); const loc = require('../../loc');
const styles = StyleSheet.create({ const styles = StyleSheet.create({

View file

@ -16,7 +16,7 @@ import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { Icon } from 'react-native-elements'; import { Icon } from 'react-native-elements';
import QRCode from 'react-native-qrcode-svg'; import QRCode from 'react-native-qrcode-svg';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
const loc = require('../../loc'); const loc = require('../../loc');
const EV = require('../../events'); const EV = require('../../events');
const { width, height } = Dimensions.get('window'); const { width, height } = Dimensions.get('window');
@ -130,7 +130,7 @@ export default class LNDViewInvoice extends Component {
invoice, invoice,
fromWallet, fromWallet,
isLoading: typeof invoice === 'string', isLoading: typeof invoice === 'string',
addressText: typeof invoice === 'object' && invoice.hasOwnProperty('payment_request') ? invoice.payment_request : invoice, addressText: typeof invoice === 'object' && 'payment_request' in invoice ? invoice.payment_request : invoice,
isFetchingInvoices: true, isFetchingInvoices: true,
qrCodeHeight: height > width ? width - 20 : width / 2, qrCodeHeight: height > width ? width - 20 : width / 2,
}; };
@ -313,7 +313,7 @@ export default class LNDViewInvoice extends Component {
<BlueText> <BlueText>
{loc.lndViewInvoice.please_pay} {invoice.amt} {loc.lndViewInvoice.sats} {loc.lndViewInvoice.please_pay} {invoice.amt} {loc.lndViewInvoice.sats}
</BlueText> </BlueText>
{invoice && invoice.hasOwnProperty('description') && invoice.description.length > 0 && ( {invoice && 'description' in invoice && invoice.description.length > 0 && (
<BlueText> <BlueText>
{loc.lndViewInvoice.for} {invoice.description} {loc.lndViewInvoice.for} {invoice.description}
</BlueText> </BlueText>
@ -333,7 +333,7 @@ export default class LNDViewInvoice extends Component {
} else { } else {
InteractionManager.runAfterInteractions(async () => { InteractionManager.runAfterInteractions(async () => {
this.qrCodeSVG.toDataURL(data => { this.qrCodeSVG.toDataURL(data => {
let shareImageBase64 = { const shareImageBase64 = {
message: `lightning:${invoice.payment_request}`, message: `lightning:${invoice.payment_request}`,
url: `data:image/png;base64,${data}`, url: `data:image/png;base64,${data}`,
}; };

View file

@ -18,8 +18,8 @@ import { Icon } from 'react-native-elements';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import Biometric from '../../class/biometrics'; import Biometric from '../../class/biometrics';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
let EV = require('../../events'); const EV = require('../../events');
const loc = require('../../loc'); const loc = require('../../loc');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -128,7 +128,7 @@ export default class ScanLndInvoice extends React.Component {
} }
} }
for (let w of BlueApp.getWallets()) { for (const w of BlueApp.getWallets()) {
if (w.getSecret() === fromSecret) { if (w.getSecret() === fromSecret) {
fromWallet = w; fromWallet = w;
break; break;
@ -147,7 +147,7 @@ export default class ScanLndInvoice extends React.Component {
if (props.route.params.uri) { if (props.route.params.uri) {
let data = props.route.params.uri; let data = props.route.params.uri;
// handling BIP21 w/BOLT11 support // handling BIP21 w/BOLT11 support
let ind = data.indexOf('lightning='); const ind = data.indexOf('lightning=');
if (ind !== -1) { if (ind !== -1) {
data = data.substring(ind + 10).split('&')[0]; data = data.substring(ind + 10).split('&')[0];
} }
@ -158,7 +158,7 @@ export default class ScanLndInvoice extends React.Component {
/** /**
* @type {LightningCustodianWallet} * @type {LightningCustodianWallet}
*/ */
let w = state.fromWallet; const w = state.fromWallet;
let decoded; let decoded;
try { try {
decoded = w.decodeInvoice(data); decoded = w.decodeInvoice(data);
@ -208,7 +208,7 @@ export default class ScanLndInvoice extends React.Component {
}; };
async pay() { async pay() {
if (!this.state.hasOwnProperty('decoded')) { if ('decoded' in this.state) {
return null; return null;
} }
@ -225,12 +225,12 @@ export default class ScanLndInvoice extends React.Component {
isLoading: true, isLoading: true,
}, },
async () => { async () => {
let decoded = this.state.decoded; const decoded = this.state.decoded;
/** @type {LightningCustodianWallet} */ /** @type {LightningCustodianWallet} */
let fromWallet = this.state.fromWallet; const fromWallet = this.state.fromWallet;
let expiresIn = (decoded.timestamp * 1 + decoded.expiry * 1) * 1000; // ms const expiresIn = (decoded.timestamp * 1 + decoded.expiry * 1) * 1000; // ms
if (+new Date() > expiresIn) { if (+new Date() > expiresIn) {
this.setState({ isLoading: false }); this.setState({ isLoading: false });
ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false }); ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
@ -338,7 +338,7 @@ export default class ScanLndInvoice extends React.Component {
onChangeText={text => { onChangeText={text => {
if (typeof this.state.decoded === 'object') { if (typeof this.state.decoded === 'object') {
text = parseInt(text || 0); text = parseInt(text || 0);
let decoded = this.state.decoded; const decoded = this.state.decoded;
decoded.num_satoshis = text; decoded.num_satoshis = text;
this.setState({ decoded: decoded }); this.setState({ decoded: decoded });
} }
@ -364,7 +364,7 @@ export default class ScanLndInvoice extends React.Component {
/> />
<View style={styles.description}> <View style={styles.description}>
<Text numberOfLines={0} style={styles.descriptionText}> <Text numberOfLines={0} style={styles.descriptionText}>
{this.state.hasOwnProperty('decoded') && this.state.decoded !== undefined ? this.state.decoded.description : ''} {'decoded' in this.state && this.state.decoded !== undefined ? this.state.decoded.description : ''}
</Text> </Text>
</View> </View>
{this.state.expiresIn !== undefined && <Text style={styles.expiresIn}>Expires in: {this.state.expiresIn}</Text>} {this.state.expiresIn !== undefined && <Text style={styles.expiresIn}>Expires in: {this.state.expiresIn}</Text>}
@ -376,7 +376,7 @@ export default class ScanLndInvoice extends React.Component {
</View> </View>
) : ( ) : (
<BlueButton <BlueButton
title={'Pay'} title="Pay"
onPress={() => { onPress={() => {
this.pay(); this.pay();
}} }}

View file

@ -5,10 +5,10 @@ import { BlueLoading, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueNavigati
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { AppStorage } from '../class'; import { AppStorage } from '../class';
let BlueApp: AppStorage = require('../BlueApp'); const BlueApp: AppStorage = require('../BlueApp');
let prompt = require('../prompt'); const prompt = require('../prompt');
let EV = require('../events'); const EV = require('../events');
let loc = require('../loc'); const loc = require('../loc');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
root: { root: {
@ -56,7 +56,7 @@ export default class PlausibleDeniability extends Component {
testID="CreateFakeStorageButton" testID="CreateFakeStorageButton"
title={loc.plausibledeniability.create_fake_storage} title={loc.plausibledeniability.create_fake_storage}
onPress={async () => { onPress={async () => {
let p1 = await prompt(loc.plausibledeniability.create_password, loc.plausibledeniability.create_password_explanation); const p1 = await prompt(loc.plausibledeniability.create_password, loc.plausibledeniability.create_password_explanation);
const isPasswordInUse = p1 === BlueApp.cachedPassword || (await BlueApp.isPasswordInUse(p1)); const isPasswordInUse = p1 === BlueApp.cachedPassword || (await BlueApp.isPasswordInUse(p1));
if (isPasswordInUse) { if (isPasswordInUse) {
ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false }); ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
@ -65,7 +65,7 @@ export default class PlausibleDeniability extends Component {
if (!p1) { if (!p1) {
return; return;
} }
let p2 = await prompt(loc.plausibledeniability.retype_password); const p2 = await prompt(loc.plausibledeniability.retype_password);
if (p1 !== p2) { if (p1 !== p2) {
ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false }); ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
return alert(loc.plausibledeniability.passwords_do_not_match); return alert(loc.plausibledeniability.passwords_do_not_match);

View file

@ -8,7 +8,7 @@ import { AppStorage, PlaceholderWallet } from '../../class';
import Azteco from '../../class/azteco'; import Azteco from '../../class/azteco';
const EV = require('../../events'); const EV = require('../../events');
let BlueApp: AppStorage = require('../../BlueApp'); const BlueApp: AppStorage = require('../../BlueApp');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
loading: { loading: {
@ -162,7 +162,7 @@ export default class AztecoRedeem extends Component {
{this.state.c1}-{this.state.c2}-{this.state.c3}-{this.state.c4} {this.state.c1}-{this.state.c2}-{this.state.c3}-{this.state.c4}
</BlueText> </BlueText>
{this.renderWalletSelectionButton()} {this.renderWalletSelectionButton()}
<BlueButton onPress={this.redeem} title={'Redeem'} /> <BlueButton onPress={this.redeem} title="Redeem" />
<BlueSpacing /> <BlueSpacing />
</View> </View>
</View> </View>

View file

@ -162,7 +162,7 @@ const ReceiveDetails = () => {
} else { } else {
InteractionManager.runAfterInteractions(async () => { InteractionManager.runAfterInteractions(async () => {
qrCodeSVG.toDataURL(data => { qrCodeSVG.toDataURL(data => {
let shareImageBase64 = { const shareImageBase64 = {
message: bip21encoded, message: bip21encoded,
url: `data:image/png;base64,${data}`, url: `data:image/png;base64,${data}`,
}; };
@ -205,7 +205,7 @@ const ReceiveDetails = () => {
logoSize={90} logoSize={90}
color={BlueApp.settings.foregroundColor} color={BlueApp.settings.foregroundColor}
logoBackgroundColor={BlueApp.settings.brandingColor} logoBackgroundColor={BlueApp.settings.brandingColor}
ecl={'H'} ecl="H"
getRef={setQrCodeSVG} getRef={setQrCodeSVG}
/> />
)} )}

View file

@ -5,8 +5,8 @@ import PropTypes from 'prop-types';
import { SegwitP2SHWallet, LegacyWallet, HDSegwitP2SHWallet, HDSegwitBech32Wallet } from '../class'; import { SegwitP2SHWallet, LegacyWallet, HDSegwitP2SHWallet, HDSegwitBech32Wallet } from '../class';
const bitcoin = require('bitcoinjs-lib'); const bitcoin = require('bitcoinjs-lib');
const BlueCrypto = require('react-native-blue-crypto'); const BlueCrypto = require('react-native-blue-crypto');
let encryption = require('../encryption'); const encryption = require('../encryption');
let BlueElectrum = require('../BlueElectrum'); const BlueElectrum = require('../BlueElectrum');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
root: { root: {
@ -36,8 +36,8 @@ export default class Selftest extends Component {
try { try {
if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') { if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
let uniqs = {}; const uniqs = {};
let w = new SegwitP2SHWallet(); const w = new SegwitP2SHWallet();
for (let c = 0; c < 1000; c++) { for (let c = 0; c < 1000; c++) {
await w.generate(); await w.generate();
if (uniqs[w.getSecret()]) { if (uniqs[w.getSecret()]) {
@ -54,12 +54,12 @@ export default class Selftest extends Component {
if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') { if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
await BlueElectrum.ping(); await BlueElectrum.ping();
await BlueElectrum.waitTillConnected(); await BlueElectrum.waitTillConnected();
let addr4elect = '3GCvDBAktgQQtsbN6x5DYiQCMmgZ9Yk8BK'; const addr4elect = '3GCvDBAktgQQtsbN6x5DYiQCMmgZ9Yk8BK';
let electrumBalance = await BlueElectrum.getBalanceByAddress(addr4elect); const electrumBalance = await BlueElectrum.getBalanceByAddress(addr4elect);
if (electrumBalance.confirmed !== 51432) if (electrumBalance.confirmed !== 51432)
throw new Error('BlueElectrum getBalanceByAddress failure, got ' + JSON.stringify(electrumBalance)); throw new Error('BlueElectrum getBalanceByAddress failure, got ' + JSON.stringify(electrumBalance));
let electrumTxs = await BlueElectrum.getTransactionsByAddress(addr4elect); const electrumTxs = await BlueElectrum.getTransactionsByAddress(addr4elect);
if (electrumTxs.length !== 1) throw new Error('BlueElectrum getTransactionsByAddress failure, got ' + JSON.stringify(electrumTxs)); if (electrumTxs.length !== 1) throw new Error('BlueElectrum getTransactionsByAddress failure, got ' + JSON.stringify(electrumTxs));
} else { } else {
// skipping RN-specific test' // skipping RN-specific test'
@ -81,7 +81,7 @@ export default class Selftest extends Component {
]; ];
let txNew = l.createTransaction(utxos, [{ value: 90000, address: '1GX36PGBUrF8XahZEGQqHqnJGW2vCZteoB' }], 1, l.getAddress()); let txNew = l.createTransaction(utxos, [{ value: 90000, address: '1GX36PGBUrF8XahZEGQqHqnJGW2vCZteoB' }], 1, l.getAddress());
let txBitcoin = bitcoin.Transaction.fromHex(txNew.tx.toHex()); const txBitcoin = bitcoin.Transaction.fromHex(txNew.tx.toHex());
assertStrictEqual( assertStrictEqual(
txNew.tx.toHex(), txNew.tx.toHex(),
'0200000001c4ce4282c157a7f1e4524d153d3a251669f10673ad24e49f6d2994a033e944cc000000006a47304402200faed160757433bcd4d9fe5f55eb92420406e8f3099a7e12ef720c77313c8c7e022044bc9e1abca6a81a8ad5c749f5ec4694301589172b83b1803bc134eda0487dbc01210337c09b3cb889801638078fd4e6998218b28c92d338ea2602720a88847aedceb3ffffffff02905f0100000000001976a914aa381cd428a4e91327fd4434aa0a08ff131f1a5a88ac2f260000000000001976a91426e01119d265aa980390c49eece923976c218f1588ac00000000', '0200000001c4ce4282c157a7f1e4524d153d3a251669f10673ad24e49f6d2994a033e944cc000000006a47304402200faed160757433bcd4d9fe5f55eb92420406e8f3099a7e12ef720c77313c8c7e022044bc9e1abca6a81a8ad5c749f5ec4694301589172b83b1803bc134eda0487dbc01210337c09b3cb889801638078fd4e6998218b28c92d338ea2602720a88847aedceb3ffffffff02905f0100000000001976a914aa381cd428a4e91327fd4434aa0a08ff131f1a5a88ac2f260000000000001976a91426e01119d265aa980390c49eece923976c218f1588ac00000000',
@ -101,7 +101,7 @@ export default class Selftest extends Component {
// //
let wallet = new SegwitP2SHWallet(); const wallet = new SegwitP2SHWallet();
wallet.setSecret('Ky1vhqYGCiCbPd8nmbUeGfwLdXB1h5aGwxHwpXrzYRfY5cTZPDo4'); wallet.setSecret('Ky1vhqYGCiCbPd8nmbUeGfwLdXB1h5aGwxHwpXrzYRfY5cTZPDo4');
assertStrictEqual(wallet.getAddress(), '3CKN8HTCews4rYJYsyub5hjAVm5g5VFdQJ'); assertStrictEqual(wallet.getAddress(), '3CKN8HTCews4rYJYsyub5hjAVm5g5VFdQJ');
@ -114,7 +114,7 @@ export default class Selftest extends Component {
]; ];
txNew = wallet.createTransaction(utxos, [{ value: 90000, address: '1GX36PGBUrF8XahZEGQqHqnJGW2vCZteoB' }], 1, wallet.getAddress()); txNew = wallet.createTransaction(utxos, [{ value: 90000, address: '1GX36PGBUrF8XahZEGQqHqnJGW2vCZteoB' }], 1, wallet.getAddress());
let tx = bitcoin.Transaction.fromHex(txNew.tx.toHex()); const tx = bitcoin.Transaction.fromHex(txNew.tx.toHex());
assertStrictEqual( assertStrictEqual(
txNew.tx.toHex(), txNew.tx.toHex(),
'020000000001010c86eb9013616e38b4752e56e5683e864cb34fcd7fe790bdc006b60c08446ba50000000017160014139dc70d73097f9d775f8a3280ba3e3435515641ffffffff02905f0100000000001976a914aa381cd428a4e91327fd4434aa0a08ff131f1a5a88ac6f3303000000000017a914749118baa93fb4b88c28909c8bf0a8202a0484f487024730440220086b55a771f37daadbe64fe557a32fd68ee92995445af0b0a5b9343db67505e1022064c9a9778a19a0276761af69b8917d19ed4b791c785dd8cb4aae327f2a6b526f012103a5de146762f84055db3202c1316cd9008f16047f4f408c1482fdb108217eda0800000000', '020000000001010c86eb9013616e38b4752e56e5683e864cb34fcd7fe790bdc006b60c08446ba50000000017160014139dc70d73097f9d775f8a3280ba3e3435515641ffffffff02905f0100000000001976a914aa381cd428a4e91327fd4434aa0a08ff131f1a5a88ac6f3303000000000017a914749118baa93fb4b88c28909c8bf0a8202a0484f487024730440220086b55a771f37daadbe64fe557a32fd68ee92995445af0b0a5b9343db67505e1022064c9a9778a19a0276761af69b8917d19ed4b791c785dd8cb4aae327f2a6b526f012103a5de146762f84055db3202c1316cd9008f16047f4f408c1482fdb108217eda0800000000',
@ -127,8 +127,8 @@ export default class Selftest extends Component {
// //
const data2encrypt = 'really long data string'; const data2encrypt = 'really long data string';
let crypted = encryption.encrypt(data2encrypt, 'password'); const crypted = encryption.encrypt(data2encrypt, 'password');
let decrypted = encryption.decrypt(crypted, 'password'); const decrypted = encryption.decrypt(crypted, 'password');
if (decrypted !== data2encrypt) { if (decrypted !== data2encrypt) {
throw new Error('encryption lib is not ok'); throw new Error('encryption lib is not ok');
@ -136,15 +136,15 @@ export default class Selftest extends Component {
// //
let bip39 = require('bip39'); const bip39 = require('bip39');
let mnemonic = const mnemonic =
'honey risk juice trip orient galaxy win situate shoot anchor bounce remind horse traffic exotic since escape mimic ramp skin judge owner topple erode'; 'honey risk juice trip orient galaxy win situate shoot anchor bounce remind horse traffic exotic since escape mimic ramp skin judge owner topple erode';
let seed = bip39.mnemonicToSeed(mnemonic); const seed = bip39.mnemonicToSeed(mnemonic);
let root = bitcoin.bip32.fromSeed(seed); const root = bitcoin.bip32.fromSeed(seed);
let path = "m/49'/0'/0'/0/0"; const path = "m/49'/0'/0'/0/0";
let child = root.derivePath(path); const child = root.derivePath(path);
let address = bitcoin.payments.p2sh({ const address = bitcoin.payments.p2sh({
redeem: bitcoin.payments.p2wpkh({ redeem: bitcoin.payments.p2wpkh({
pubkey: child.publicKey, pubkey: child.publicKey,
network: bitcoin.networks.bitcoin, network: bitcoin.networks.bitcoin,
@ -158,11 +158,11 @@ export default class Selftest extends Component {
// //
if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') { if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
let hd = new HDSegwitP2SHWallet(); const hd = new HDSegwitP2SHWallet();
let hashmap = {}; const hashmap = {};
for (let c = 0; c < 1000; c++) { for (let c = 0; c < 1000; c++) {
await hd.generate(); await hd.generate();
let secret = hd.getSecret(); const secret = hd.getSecret();
if (hashmap[secret]) { if (hashmap[secret]) {
throw new Error('Duplicate secret generated!'); throw new Error('Duplicate secret generated!');
} }
@ -172,7 +172,7 @@ export default class Selftest extends Component {
} }
} }
let hd2 = new HDSegwitP2SHWallet(); const hd2 = new HDSegwitP2SHWallet();
hd2.setSecret(hd.getSecret()); hd2.setSecret(hd.getSecret());
if (!hd2.validateMnemonic()) { if (!hd2.validateMnemonic()) {
throw new Error('mnemonic phrase validation not ok'); throw new Error('mnemonic phrase validation not ok');
@ -180,7 +180,7 @@ export default class Selftest extends Component {
// //
let hd4 = new HDSegwitBech32Wallet(); const hd4 = new HDSegwitBech32Wallet();
hd4._xpub = 'zpub6r7jhKKm7BAVx3b3nSnuadY1WnshZYkhK8gKFoRLwK9rF3Mzv28BrGcCGA3ugGtawi1WLb2vyjQAX9ZTDGU5gNk2bLdTc3iEXr6tzR1ipNP'; hd4._xpub = 'zpub6r7jhKKm7BAVx3b3nSnuadY1WnshZYkhK8gKFoRLwK9rF3Mzv28BrGcCGA3ugGtawi1WLb2vyjQAX9ZTDGU5gNk2bLdTc3iEXr6tzR1ipNP';
await hd4.fetchBalance(); await hd4.fetchBalance();
if (hd4.getBalance() !== 200000) throw new Error('Could not fetch HD Bech32 balance'); if (hd4.getBalance() !== 200000) throw new Error('Could not fetch HD Bech32 balance');

View file

@ -73,11 +73,8 @@ const ScanQRCode = () => {
}); });
}, [navigation]); }, [navigation]);
const HashIt = function(s) { const HashIt = function (s) {
return createHash('sha256') return createHash('sha256').update(s).digest().toString('hex');
.update(s)
.digest()
.toString('hex');
}; };
const onBarCodeRead = ret => { const onBarCodeRead = ret => {

View file

@ -36,7 +36,7 @@ export default function Broadcast() {
const walletObj = new HDSegwitBech32Wallet(); const walletObj = new HDSegwitBech32Wallet();
const result = await walletObj.broadcastTx(txHex); const result = await walletObj.broadcastTx(txHex);
if (result) { if (result) {
let tx = bitcoin.Transaction.fromHex(txHex); const tx = bitcoin.Transaction.fromHex(txHex);
const txid = tx.getId(); const txid = tx.getId();
setTx(txid); setTx(txid);
setBroadcastResult(BROADCAST_RESULT.success); setBroadcastResult(BROADCAST_RESULT.success);
@ -63,8 +63,8 @@ export default function Broadcast() {
style={styles.text} style={styles.text}
maxHeight={100} maxHeight={100}
minHeight={100} minHeight={100}
maxWidth={'100%'} maxWidth="100%"
minWidth={'100%'} minWidth="100%"
multiline multiline
editable editable
value={txHex} value={txHex}

View file

@ -17,11 +17,11 @@ import {
SegwitP2SHWallet, SegwitP2SHWallet,
SegwitBech32Wallet, SegwitBech32Wallet,
} from '../../class'; } from '../../class';
let loc = require('../../loc'); const loc = require('../../loc');
let EV = require('../../events'); const EV = require('../../events');
let currency = require('../../currency'); const currency = require('../../currency');
let BlueElectrum = require('../../BlueElectrum'); const BlueElectrum = require('../../BlueElectrum');
let Bignumber = require('bignumber.js'); const Bignumber = require('bignumber.js');
/** @type {AppStorage} */ /** @type {AppStorage} */
const BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
@ -66,7 +66,7 @@ export default class Confirm extends Component {
} }
} }
let result = await this.state.fromWallet.broadcastTx(this.state.tx); const result = await this.state.fromWallet.broadcastTx(this.state.tx);
if (!result) { if (!result) {
throw new Error(`Broadcast failed`); throw new Error(`Broadcast failed`);
} else { } else {
@ -118,7 +118,7 @@ export default class Confirm extends Component {
return ( return (
<> <>
<View style={styles.valueWrap}> <View style={styles.valueWrap}>
<Text testID={'TransactionValue'} style={styles.valueValue}> <Text testID="TransactionValue" style={styles.valueValue}>
{!item.value || item.value === BitcoinUnit.MAX {!item.value || item.value === BitcoinUnit.MAX
? currency.satoshiToBTC(this.state.fromWallet.getBalance() - this.state.feeSatoshi) ? currency.satoshiToBTC(this.state.fromWallet.getBalance() - this.state.feeSatoshi)
: item.amount || currency.satoshiToBTC(item.value)} : item.amount || currency.satoshiToBTC(item.value)}
@ -169,7 +169,7 @@ export default class Confirm extends Component {
)} )}
<TouchableOpacity <TouchableOpacity
testID={'TransactionDetailsButton'} testID="TransactionDetailsButton"
style={styles.txDetails} style={styles.txDetails}
onPress={async () => { onPress={async () => {
if (this.isBiometricUseCapableAndEnabled) { if (this.isBiometricUseCapableAndEnabled) {

View file

@ -139,7 +139,7 @@ export default class SendCreate extends Component {
<ScrollView> <ScrollView>
<BlueCard style={styles.card}> <BlueCard style={styles.card}>
<BlueText style={styles.cardText}>{loc.send.create.this_is_hex}</BlueText> <BlueText style={styles.cardText}>{loc.send.create.this_is_hex}</BlueText>
<TextInput testID={'TxhexInput'} style={styles.cardTx} height={72} multiline editable value={this.state.tx} /> <TextInput testID="TxhexInput" style={styles.cardTx} height={72} multiline editable value={this.state.tx} />
<TouchableOpacity style={styles.actionTouch} onPress={() => Clipboard.setString(this.state.tx)}> <TouchableOpacity style={styles.actionTouch} onPress={() => Clipboard.setString(this.state.tx)}>
<Text style={styles.actionText}>Copy and broadcast later</Text> <Text style={styles.actionText}>Copy and broadcast later</Text>

View file

@ -42,10 +42,10 @@ import DocumentPicker from 'react-native-document-picker';
import RNFS from 'react-native-fs'; import RNFS from 'react-native-fs';
import DeeplinkSchemaMatch from '../../class/deeplink-schema-match'; import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
const bitcoin = require('bitcoinjs-lib'); const bitcoin = require('bitcoinjs-lib');
let BigNumber = require('bignumber.js'); const BigNumber = require('bignumber.js');
const { width } = Dimensions.get('window'); const { width } = Dimensions.get('window');
let BlueApp: AppStorage = require('../../BlueApp'); const BlueApp: AppStorage = require('../../BlueApp');
let loc = require('../../loc'); const loc = require('../../loc');
const btcAddressRx = /^[a-zA-Z0-9]{26,35}$/; const btcAddressRx = /^[a-zA-Z0-9]{26,35}$/;
@ -293,7 +293,7 @@ export default class SendDetails extends Component {
}); });
} else { } else {
console.warn('2'); console.warn('2');
let recipients = this.state.addresses; const recipients = this.state.addresses;
const dataWithoutSchema = data.replace('bitcoin:', '').replace('BITCOIN:', ''); const dataWithoutSchema = data.replace('bitcoin:', '').replace('BITCOIN:', '');
if (this.state.fromWallet.isAddressValid(dataWithoutSchema)) { if (this.state.fromWallet.isAddressValid(dataWithoutSchema)) {
recipients[[this.state.recipientsScrollIndex]].address = dataWithoutSchema; recipients[[this.state.recipientsScrollIndex]].address = dataWithoutSchema;
@ -342,7 +342,7 @@ export default class SendDetails extends Component {
this.renderNavigationHeader(); this.renderNavigationHeader();
console.log('send/details - componentDidMount'); console.log('send/details - componentDidMount');
StatusBar.setBarStyle('dark-content'); StatusBar.setBarStyle('dark-content');
let addresses = []; const addresses = [];
let initialMemo = ''; let initialMemo = '';
if (this.props.route.params.uri) { if (this.props.route.params.uri) {
const uri = this.props.route.params.uri; const uri = this.props.route.params.uri;
@ -373,7 +373,7 @@ export default class SendDetails extends Component {
try { try {
const cachedNetworkTransactionFees = JSON.parse(await AsyncStorage.getItem(NetworkTransactionFee.StorageKey)); const cachedNetworkTransactionFees = JSON.parse(await AsyncStorage.getItem(NetworkTransactionFee.StorageKey));
if (cachedNetworkTransactionFees && cachedNetworkTransactionFees.hasOwnProperty('mediumFee')) { if (cachedNetworkTransactionFees && 'mediumFee' in cachedNetworkTransactionFees) {
this.setState({ this.setState({
fee: cachedNetworkTransactionFees.fastestFee, fee: cachedNetworkTransactionFees.fastestFee,
networkTransactionFees: cachedNetworkTransactionFees, networkTransactionFees: cachedNetworkTransactionFees,
@ -383,8 +383,8 @@ export default class SendDetails extends Component {
} catch (_) {} } catch (_) {}
try { try {
let recommendedFees = await NetworkTransactionFees.recommendedFees(); const recommendedFees = await NetworkTransactionFees.recommendedFees();
if (recommendedFees && recommendedFees.hasOwnProperty('fastestFee')) { if (recommendedFees && 'fastestFee' in recommendedFees) {
await AsyncStorage.setItem(NetworkTransactionFee.StorageKey, JSON.stringify(recommendedFees)); await AsyncStorage.setItem(NetworkTransactionFee.StorageKey, JSON.stringify(recommendedFees));
this.setState({ this.setState({
fee: recommendedFees.fastestFee, fee: recommendedFees.fastestFee,
@ -432,13 +432,13 @@ export default class SendDetails extends Component {
let memo = ''; let memo = '';
try { try {
parsedBitcoinUri = DeeplinkSchemaMatch.bip21decode(uri); parsedBitcoinUri = DeeplinkSchemaMatch.bip21decode(uri);
address = parsedBitcoinUri.hasOwnProperty('address') ? parsedBitcoinUri.address : address; address = 'address' in parsedBitcoinUri ? parsedBitcoinUri.address : address;
if (parsedBitcoinUri.hasOwnProperty('options')) { if ('options' in parsedBitcoinUri) {
if (parsedBitcoinUri.options.hasOwnProperty('amount')) { if ('amount' in parsedBitcoinUri.options) {
amount = parsedBitcoinUri.options.amount.toString(); amount = parsedBitcoinUri.options.amount.toString();
amount = parsedBitcoinUri.options.amount; amount = parsedBitcoinUri.options.amount;
} }
if (parsedBitcoinUri.options.hasOwnProperty('label')) { if ('label' in parsedBitcoinUri.options) {
memo = parsedBitcoinUri.options.label || memo; memo = parsedBitcoinUri.options.label || memo;
} }
} }
@ -496,7 +496,7 @@ export default class SendDetails extends Component {
Keyboard.dismiss(); Keyboard.dismiss();
this.setState({ isLoading: true }); this.setState({ isLoading: true });
let error = false; let error = false;
let requestedSatPerByte = this.state.fee.toString().replace(/\D/g, ''); const requestedSatPerByte = this.state.fee.toString().replace(/\D/g, '');
for (const [index, transaction] of this.state.addresses.entries()) { for (const [index, transaction] of this.state.addresses.entries()) {
if (!transaction.amount || transaction.amount < 0 || parseFloat(transaction.amount) === 0) { if (!transaction.amount || transaction.amount < 0 || parseFloat(transaction.amount) === 0) {
error = loc.send.details.amount_field_is_not_valid; error = loc.send.details.amount_field_is_not_valid;
@ -583,7 +583,7 @@ export default class SendDetails extends Component {
} }
} }
let { tx, fee, psbt } = wallet.createTransaction( const { tx, fee, psbt } = wallet.createTransaction(
wallet.getUtxo(), wallet.getUtxo(),
targets, targets,
requestedSatPerByte, requestedSatPerByte,
@ -705,7 +705,7 @@ export default class SendDetails extends Component {
} }
}} }}
onChangeText={value => { onChangeText={value => {
let newValue = value.replace(/\D/g, ''); const newValue = value.replace(/\D/g, '');
this.setState({ fee: newValue, feeSliderValue: Number(newValue) }); this.setState({ fee: newValue, feeSliderValue: Number(newValue) });
}} }}
maxLength={9} maxLength={9}
@ -877,7 +877,7 @@ export default class SendDetails extends Component {
{this.state.isLoading ? ( {this.state.isLoading ? (
<ActivityIndicator /> <ActivityIndicator />
) : ( ) : (
<BlueButton onPress={() => this.createTransaction()} title={'Next'} testID={'CreateTransactionButton'} /> <BlueButton onPress={() => this.createTransaction()} title="Next" testID="CreateTransactionButton" />
)} )}
</View> </View>
); );
@ -934,8 +934,8 @@ export default class SendDetails extends Component {
}; };
renderBitcoinTransactionInfoFields = () => { renderBitcoinTransactionInfoFields = () => {
let rows = []; const rows = [];
for (let [index, item] of this.state.addresses.entries()) { for (const [index, item] of this.state.addresses.entries()) {
rows.push( rows.push(
<View key={index} style={{ minWidth: width, maxWidth: width, width: width }}> <View key={index} style={{ minWidth: width, maxWidth: width, width: width }}>
<BlueBitcoinAmount <BlueBitcoinAmount
@ -952,7 +952,7 @@ export default class SendDetails extends Component {
<BlueAddressInput <BlueAddressInput
onChangeText={async text => { onChangeText={async text => {
text = text.trim(); text = text.trim();
let transactions = this.state.addresses; const transactions = this.state.addresses;
try { try {
const { recipient, memo, fee, feeSliderValue } = await this.processBIP70Invoice(text); const { recipient, memo, fee, feeSliderValue } = await this.processBIP70Invoice(text);
transactions[index].address = recipient.address; transactions[index].address = recipient.address;

View file

@ -32,9 +32,9 @@ import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { RNCamera } from 'react-native-camera'; import { RNCamera } from 'react-native-camera';
import RNFS from 'react-native-fs'; import RNFS from 'react-native-fs';
import DocumentPicker from 'react-native-document-picker'; import DocumentPicker from 'react-native-document-picker';
let loc = require('../../loc'); const loc = require('../../loc');
let EV = require('../../events'); const EV = require('../../events');
let BlueElectrum = require('../../BlueElectrum'); const BlueElectrum = require('../../BlueElectrum');
/** @type {AppStorage} */ /** @type {AppStorage} */
const BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
const bitcoin = require('bitcoinjs-lib'); const bitcoin = require('bitcoinjs-lib');
@ -133,7 +133,7 @@ export default class PsbtWithHardwareWallet extends Component {
this.setState({ renderScanner: false }, () => { this.setState({ renderScanner: false }, () => {
try { try {
let Tx = this.state.fromWallet.combinePsbt( const Tx = this.state.fromWallet.combinePsbt(
this.state.isFirstPSBTAlreadyBase64 ? this.state.psbt : this.state.psbt.toBase64(), this.state.isFirstPSBTAlreadyBase64 ? this.state.psbt : this.state.psbt.toBase64(),
ret.data, ret.data,
); );
@ -166,7 +166,7 @@ export default class PsbtWithHardwareWallet extends Component {
const txhex = nextProps.route.params.txhex; const txhex = nextProps.route.params.txhex;
if (deepLinkPSBT) { if (deepLinkPSBT) {
try { try {
let Tx = prevState.fromWallet.combinePsbt( const Tx = prevState.fromWallet.combinePsbt(
prevState.isFirstPSBTAlreadyBase64 ? prevState.psbt : prevState.psbt.toBase64(), prevState.isFirstPSBTAlreadyBase64 ? prevState.psbt : prevState.psbt.toBase64(),
deepLinkPSBT, deepLinkPSBT,
); );
@ -195,12 +195,12 @@ export default class PsbtWithHardwareWallet extends Component {
try { try {
await BlueElectrum.ping(); await BlueElectrum.ping();
await BlueElectrum.waitTillConnected(); await BlueElectrum.waitTillConnected();
let result = await this.state.fromWallet.broadcastTx(this.state.txhex); const result = await this.state.fromWallet.broadcastTx(this.state.txhex);
if (result) { if (result) {
EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED); // someone should fetch txs EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED); // someone should fetch txs
this.setState({ success: true, isLoading: false }); this.setState({ success: true, isLoading: false });
if (this.state.memo) { if (this.state.memo) {
let txDecoded = bitcoin.Transaction.fromHex(this.state.txhex); const txDecoded = bitcoin.Transaction.fromHex(this.state.txhex);
const txid = txDecoded.getId(); const txid = txDecoded.getId();
BlueApp.tx_metadata[txid] = { memo: this.state.memo }; BlueApp.tx_metadata[txid] = { memo: this.state.memo };
} }
@ -339,7 +339,7 @@ export default class PsbtWithHardwareWallet extends Component {
<ScrollView centerContent contentContainerStyle={styles.scrollViewContent}> <ScrollView centerContent contentContainerStyle={styles.scrollViewContent}>
<View style={styles.container}> <View style={styles.container}>
<BlueCard> <BlueCard>
<BlueText testID={'TextHelperForPSBT'}> <BlueText testID="TextHelperForPSBT">
This is partially signed bitcoin transaction (PSBT). Please finish signing it with your hardware wallet. This is partially signed bitcoin transaction (PSBT). Please finish signing it with your hardware wallet.
</BlueText> </BlueText>
<BlueSpacing20 /> <BlueSpacing20 />
@ -348,7 +348,7 @@ export default class PsbtWithHardwareWallet extends Component {
size={this.state.qrCodeHeight} size={this.state.qrCodeHeight}
color={BlueApp.settings.foregroundColor} color={BlueApp.settings.foregroundColor}
logoBackgroundColor={BlueApp.settings.brandingColor} logoBackgroundColor={BlueApp.settings.brandingColor}
ecl={'L'} ecl="L"
/> />
<BlueSpacing20 /> <BlueSpacing20 />
<BlueButton <BlueButton
@ -358,7 +358,7 @@ export default class PsbtWithHardwareWallet extends Component {
color: BlueApp.settings.buttonTextColor, color: BlueApp.settings.buttonTextColor,
}} }}
onPress={() => this.setState({ renderScanner: true })} onPress={() => this.setState({ renderScanner: true })}
title={'Scan Signed Transaction'} title="Scan Signed Transaction"
/> />
<BlueSpacing20 /> <BlueSpacing20 />
<BlueButton <BlueButton
@ -368,7 +368,7 @@ export default class PsbtWithHardwareWallet extends Component {
color: BlueApp.settings.buttonTextColor, color: BlueApp.settings.buttonTextColor,
}} }}
onPress={this.openSignedTransaction} onPress={this.openSignedTransaction}
title={'Open Signed Transaction'} title="Open Signed Transaction"
/> />
<BlueSpacing20 /> <BlueSpacing20 />
<BlueButton <BlueButton
@ -378,13 +378,13 @@ export default class PsbtWithHardwareWallet extends Component {
color: BlueApp.settings.buttonTextColor, color: BlueApp.settings.buttonTextColor,
}} }}
onPress={this.exportPSBT} onPress={this.exportPSBT}
title={'Export to file'} title="Export to file"
/> />
<BlueSpacing20 /> <BlueSpacing20 />
<View style={styles.copyToClipboard}> <View style={styles.copyToClipboard}>
<BlueCopyToClipboardButton <BlueCopyToClipboardButton
stringToCopy={this.state.isFirstPSBTAlreadyBase64 ? this.state.psbt : this.state.psbt.toBase64()} stringToCopy={this.state.isFirstPSBTAlreadyBase64 ? this.state.psbt : this.state.psbt.toBase64()}
displayText={'Copy to Clipboard'} displayText="Copy to Clipboard"
/> />
</View> </View>
</BlueCard> </BlueCard>

View file

@ -6,7 +6,7 @@ import { Text } from 'react-native-elements';
import { BlueButton, SafeBlueArea, BlueCard } from '../../BlueComponents'; import { BlueButton, SafeBlueArea, BlueCard } from '../../BlueComponents';
import { BitcoinUnit } from '../../models/bitcoinUnits'; import { BitcoinUnit } from '../../models/bitcoinUnits';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
let loc = require('../../loc'); const loc = require('../../loc');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
root: { root: {
@ -54,6 +54,10 @@ const styles = StyleSheet.create({
marginTop: 43, marginTop: 43,
marginBottom: 53, marginBottom: 53,
}, },
lottie: {
width: 400,
height: 400,
},
}); });
export default class Success extends Component { export default class Success extends Component {
@ -99,7 +103,7 @@ export default class Success extends Component {
)} )}
</BlueCard> </BlueCard>
<View style={styles.ready}> <View style={styles.ready}>
<LottieView style={{ width: 400, height: 400 }} source={require('../../img/bluenice.json')} autoPlay loop={false} /> <LottieView style={styles.lottie} source={require('../../img/bluenice.json')} autoPlay loop={false} />
</View> </View>
<BlueCard> <BlueCard>
<BlueButton <BlueButton

View file

@ -5,8 +5,8 @@ import PropTypes from 'prop-types';
import { AppStorage } from '../../class'; import { AppStorage } from '../../class';
import { useNavigation } from '@react-navigation/native'; import { useNavigation } from '@react-navigation/native';
import HandoffSettings from '../../class/handoff'; import HandoffSettings from '../../class/handoff';
let BlueApp: AppStorage = require('../../BlueApp'); const BlueApp: AppStorage = require('../../BlueApp');
let loc = require('../../loc'); const loc = require('../../loc');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
root: { root: {
@ -51,7 +51,7 @@ const GeneralSettings = () => {
<> <>
<BlueListItem <BlueListItem
hideChevron hideChevron
title={'Continuity'} title="Continuity"
Component={TouchableWithoutFeedback} Component={TouchableWithoutFeedback}
switch={{ onValueChange: onHandOffEnabledSwitch, value: isHandoffUseEnabled }} switch={{ onValueChange: onHandOffEnabledSwitch, value: isHandoffUseEnabled }}
/> />

View file

@ -23,7 +23,7 @@ const NetworkSettings = () => {
) : ( ) : (
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={styles.root}> <SafeBlueArea forceInset={{ horizontal: 'always' }} style={styles.root}>
<ScrollView> <ScrollView>
<BlueListItem title={'Electrum server'} component={TouchableOpacity} onPress={() => navigate('ElectrumSettings')} chevron /> <BlueListItem title="Electrum server" component={TouchableOpacity} onPress={() => navigate('ElectrumSettings')} chevron />
<BlueListItem <BlueListItem
title={loc.settings.lightning_settings} title={loc.settings.lightning_settings}
component={TouchableOpacity} component={TouchableOpacity}

View file

@ -4,8 +4,8 @@ import { SafeBlueArea, BlueNavigationStyle, BlueListItem, BlueText, BlueCard } f
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Icon } from 'react-native-elements'; import { Icon } from 'react-native-elements';
import { FiatUnit } from '../../models/fiatUnit'; import { FiatUnit } from '../../models/fiatUnit';
let loc = require('../../loc'); const loc = require('../../loc');
let currency = require('../../currency'); const currency = require('../../currency');
const data = Object.values(FiatUnit); const data = Object.values(FiatUnit);

View file

@ -6,8 +6,8 @@ import AsyncStorage from '@react-native-community/async-storage';
import { ScrollView } from 'react-native-gesture-handler'; import { ScrollView } from 'react-native-gesture-handler';
import { BlueLoading, BlueSpacing20, BlueButton, SafeBlueArea, BlueCard, BlueNavigationStyle, BlueText } from '../../BlueComponents'; import { BlueLoading, BlueSpacing20, BlueButton, SafeBlueArea, BlueCard, BlueNavigationStyle, BlueText } from '../../BlueComponents';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
let loc = require('../../loc'); const loc = require('../../loc');
let BlueElectrum = require('../../BlueElectrum'); const BlueElectrum = require('../../BlueElectrum');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
root: { root: {
@ -94,9 +94,9 @@ export default class ElectrumSettings extends Component {
} }
async componentDidMount() { async componentDidMount() {
let host = await AsyncStorage.getItem(AppStorage.ELECTRUM_HOST); const host = await AsyncStorage.getItem(AppStorage.ELECTRUM_HOST);
let port = await AsyncStorage.getItem(AppStorage.ELECTRUM_TCP_PORT); const port = await AsyncStorage.getItem(AppStorage.ELECTRUM_TCP_PORT);
let sslPort = await AsyncStorage.getItem(AppStorage.ELECTRUM_SSL_PORT); const sslPort = await AsyncStorage.getItem(AppStorage.ELECTRUM_SSL_PORT);
this.setState({ this.setState({
isLoading: false, isLoading: false,
@ -175,7 +175,7 @@ export default class ElectrumSettings extends Component {
<BlueCard> <BlueCard>
<View style={styles.inputWrap}> <View style={styles.inputWrap}>
<TextInput <TextInput
placeholder={'host, for example 111.222.333.444'} placeholder="host, for example 111.222.333.444"
value={this.state.host} value={this.state.host}
onChangeText={text => this.setState({ host: text })} onChangeText={text => this.setState({ host: text })}
numberOfLines={1} numberOfLines={1}
@ -187,7 +187,7 @@ export default class ElectrumSettings extends Component {
<BlueSpacing20 /> <BlueSpacing20 />
<View style={styles.inputWrap}> <View style={styles.inputWrap}>
<TextInput <TextInput
placeholder={'TCP port, usually 50001'} placeholder="TCP port, usually 50001"
value={this.state.port} value={this.state.port}
onChangeText={text => this.setState({ port: text })} onChangeText={text => this.setState({ port: text })}
numberOfLines={1} numberOfLines={1}
@ -199,7 +199,7 @@ export default class ElectrumSettings extends Component {
<BlueSpacing20 /> <BlueSpacing20 />
<View style={styles.inputWrap}> <View style={styles.inputWrap}>
<TextInput <TextInput
placeholder={'SSL port, usually 50002'} placeholder="SSL port, usually 50002"
value={this.state.sslPort} value={this.state.sslPort}
onChangeText={text => this.setState({ sslPort: text })} onChangeText={text => this.setState({ sslPort: text })}
numberOfLines={1} numberOfLines={1}

View file

@ -15,9 +15,9 @@ import PropTypes from 'prop-types';
import { AppStorage } from '../../class'; import { AppStorage } from '../../class';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import Biometric from '../../class/biometrics'; import Biometric from '../../class/biometrics';
let BlueApp: AppStorage = require('../../BlueApp'); const BlueApp: AppStorage = require('../../BlueApp');
let prompt = require('../../prompt'); const prompt = require('../../prompt');
let loc = require('../../loc'); const loc = require('../../loc');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
root: { root: {
@ -90,7 +90,7 @@ export default class EncryptStorage extends Component {
this.setState({ isLoading: false }); this.setState({ isLoading: false });
return; return;
} }
let p2 = await prompt(loc.settings.password, loc.settings.retype_password).catch(() => { const p2 = await prompt(loc.settings.password, loc.settings.retype_password).catch(() => {
this.setState({ isLoading: false }); this.setState({ isLoading: false });
}); });
if (p1 === p2) { if (p1 === p2) {
@ -126,7 +126,7 @@ export default class EncryptStorage extends Component {
}; };
onUseBiometricSwitch = async value => { onUseBiometricSwitch = async value => {
let isBiometricsEnabled = this.state.biometrics; const isBiometricsEnabled = this.state.biometrics;
if (await Biometric.unlockWithBiometrics()) { if (await Biometric.unlockWithBiometrics()) {
isBiometricsEnabled.isBiometricsEnabled = value; isBiometricsEnabled.isBiometricsEnabled = value;
await Biometric.setBiometricUseEnabled(value); await Biometric.setBiometricUseEnabled(value);

View file

@ -3,7 +3,7 @@ import { FlatList, StyleSheet } from 'react-native';
import { BlueLoading, BlueText, SafeBlueArea, BlueListItem, BlueCard, BlueNavigationStyle } from '../../BlueComponents'; import { BlueLoading, BlueText, SafeBlueArea, BlueListItem, BlueCard, BlueNavigationStyle } from '../../BlueComponents';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Icon } from 'react-native-elements'; import { Icon } from 'react-native-elements';
let loc = require('../../loc'); const loc = require('../../loc');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
flex: { flex: {

View file

@ -8,8 +8,8 @@ import PropTypes from 'prop-types';
import { Button } from 'react-native-elements'; import { Button } from 'react-native-elements';
import { LightningCustodianWallet } from '../../class/wallets/lightning-custodian-wallet'; import { LightningCustodianWallet } from '../../class/wallets/lightning-custodian-wallet';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
let loc = require('../../loc'); const loc = require('../../loc');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
root: { root: {
@ -33,6 +33,9 @@ const styles = StyleSheet.create({
minHeight: 36, minHeight: 36,
height: 36, height: 36,
}, },
buttonStyle: {
backgroundColor: 'transparent',
},
}); });
export default class LightningSettings extends Component { export default class LightningSettings extends Component {
@ -49,7 +52,7 @@ export default class LightningSettings extends Component {
} }
async componentDidMount() { async componentDidMount() {
let URI = await AsyncStorage.getItem(AppStorage.LNDHUB); const URI = await AsyncStorage.getItem(AppStorage.LNDHUB);
this.setState({ this.setState({
isLoading: false, isLoading: false,
@ -95,9 +98,7 @@ export default class LightningSettings extends Component {
titleStyle={{ color: BlueApp.settings.buttonAlternativeTextColor }} titleStyle={{ color: BlueApp.settings.buttonAlternativeTextColor }}
title="github.com/BlueWallet/LndHub" title="github.com/BlueWallet/LndHub"
color={BlueApp.settings.buttonTextColor} color={BlueApp.settings.buttonTextColor}
buttonStyle={{ buttonStyle={styles.buttonStyle}
backgroundColor: 'transparent',
}}
/> />
<BlueCard> <BlueCard>

View file

@ -24,7 +24,7 @@ const Settings = () => {
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={styles.root}> <SafeBlueArea forceInset={{ horizontal: 'always' }} style={styles.root}>
<ScrollView> <ScrollView>
<BlueHeaderDefaultSub leftText={loc.settings.header} rightComponent={null} /> <BlueHeaderDefaultSub leftText={loc.settings.header} rightComponent={null} />
<BlueListItem title={'General'} component={TouchableOpacity} onPress={() => navigate('GeneralSettings')} chevron /> <BlueListItem title="General" component={TouchableOpacity} onPress={() => navigate('GeneralSettings')} chevron />
<BlueListItem title={loc.settings.currency} component={TouchableOpacity} onPress={() => navigate('Currency')} chevron /> <BlueListItem title={loc.settings.currency} component={TouchableOpacity} onPress={() => navigate('Currency')} chevron />
<BlueListItem title={loc.settings.language} component={TouchableOpacity} onPress={() => navigate('Language')} chevron /> <BlueListItem title={loc.settings.language} component={TouchableOpacity} onPress={() => navigate('Language')} chevron />
<BlueListItem <BlueListItem

View file

@ -17,11 +17,11 @@ import { HDSegwitBech32Transaction, HDSegwitBech32Wallet } from '../../class';
import { Text } from 'react-native-elements'; import { Text } from 'react-native-elements';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
/** @type {AppStorage} */ /** @type {AppStorage} */
let EV = require('../../events'); const EV = require('../../events');
let BlueElectrum = require('../../BlueElectrum'); const BlueElectrum = require('../../BlueElectrum');
let loc = require('../../loc'); const loc = require('../../loc');
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
root: { root: {
@ -103,7 +103,7 @@ export default class CPFP extends Component {
try { try {
await BlueElectrum.ping(); await BlueElectrum.ping();
await BlueElectrum.waitTillConnected(); await BlueElectrum.waitTillConnected();
let result = await this.state.wallet.broadcastTx(this.state.txhex); const result = await this.state.wallet.broadcastTx(this.state.txhex);
if (result) { if (result) {
EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED); // someone should fetch txs EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED); // someone should fetch txs
this.setState({ stage: 3, isLoading: false }); this.setState({ stage: 3, isLoading: false });
@ -140,9 +140,9 @@ export default class CPFP extends Component {
return this.setState({ nonReplaceable: true, isLoading: false }); return this.setState({ nonReplaceable: true, isLoading: false });
} }
let tx = new HDSegwitBech32Transaction(null, this.state.txid, this.state.wallet); const tx = new HDSegwitBech32Transaction(null, this.state.txid, this.state.wallet);
if ((await tx.isToUsTransaction()) && (await tx.getRemoteConfirmationsNum()) === 0) { if ((await tx.isToUsTransaction()) && (await tx.getRemoteConfirmationsNum()) === 0) {
let info = await tx.getInfo(); const info = await tx.getInfo();
return this.setState({ nonReplaceable: false, feeRate: info.feeRate + 1, isLoading: false, tx }); return this.setState({ nonReplaceable: false, feeRate: info.feeRate + 1, isLoading: false, tx });
// 1 sat makes a lot of difference, since sometimes because of rounding created tx's fee might be insufficient // 1 sat makes a lot of difference, since sometimes because of rounding created tx's fee might be insufficient
} else { } else {
@ -157,7 +157,7 @@ export default class CPFP extends Component {
const tx = this.state.tx; const tx = this.state.tx;
this.setState({ isLoading: true }); this.setState({ isLoading: true });
try { try {
let { tx: newTx } = await tx.createCPFPbumpFee(newFeeRate); const { tx: newTx } = await tx.createCPFPbumpFee(newFeeRate);
this.setState({ stage: 2, txhex: newTx.toHex(), newTxid: newTx.getId() }); this.setState({ stage: 2, txhex: newTx.toHex(), newTxid: newTx.getId() });
this.setState({ isLoading: false }); this.setState({ isLoading: false });
} catch (_) { } catch (_) {

View file

@ -6,7 +6,7 @@ import PropTypes from 'prop-types';
import { HDSegwitBech32Transaction, HDSegwitBech32Wallet } from '../../class'; import { HDSegwitBech32Transaction, HDSegwitBech32Wallet } from '../../class';
import CPFP from './CPFP'; import CPFP from './CPFP';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
root: { root: {
@ -36,9 +36,9 @@ export default class RBFBumpFee extends CPFP {
return this.setState({ nonReplaceable: true, isLoading: false }); return this.setState({ nonReplaceable: true, isLoading: false });
} }
let tx = new HDSegwitBech32Transaction(null, this.state.txid, this.state.wallet); const tx = new HDSegwitBech32Transaction(null, this.state.txid, this.state.wallet);
if ((await tx.isOurTransaction()) && (await tx.getRemoteConfirmationsNum()) === 0 && (await tx.isSequenceReplaceable())) { if ((await tx.isOurTransaction()) && (await tx.getRemoteConfirmationsNum()) === 0 && (await tx.isSequenceReplaceable())) {
let info = await tx.getInfo(); const info = await tx.getInfo();
return this.setState({ nonReplaceable: false, feeRate: info.feeRate + 1, isLoading: false, tx }); return this.setState({ nonReplaceable: false, feeRate: info.feeRate + 1, isLoading: false, tx });
// 1 sat makes a lot of difference, since sometimes because of rounding created tx's fee might be insufficient // 1 sat makes a lot of difference, since sometimes because of rounding created tx's fee might be insufficient
} else { } else {
@ -53,7 +53,7 @@ export default class RBFBumpFee extends CPFP {
const tx = this.state.tx; const tx = this.state.tx;
this.setState({ isLoading: true }); this.setState({ isLoading: true });
try { try {
let { tx: newTx } = await tx.createRBFbumpFee(newFeeRate); const { tx: newTx } = await tx.createRBFbumpFee(newFeeRate);
this.setState({ stage: 2, txhex: newTx.toHex(), newTxid: newTx.getId() }); this.setState({ stage: 2, txhex: newTx.toHex(), newTxid: newTx.getId() });
this.setState({ isLoading: false }); this.setState({ isLoading: false });
} catch (_) { } catch (_) {

View file

@ -6,7 +6,7 @@ import PropTypes from 'prop-types';
import { HDSegwitBech32Transaction, HDSegwitBech32Wallet } from '../../class'; import { HDSegwitBech32Transaction, HDSegwitBech32Wallet } from '../../class';
import CPFP from './CPFP'; import CPFP from './CPFP';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
common: { common: {
@ -36,14 +36,14 @@ export default class RBFCancel extends CPFP {
return this.setState({ nonReplaceable: true, isLoading: false }); return this.setState({ nonReplaceable: true, isLoading: false });
} }
let tx = new HDSegwitBech32Transaction(null, this.state.txid, this.state.wallet); const tx = new HDSegwitBech32Transaction(null, this.state.txid, this.state.wallet);
if ( if (
(await tx.isOurTransaction()) && (await tx.isOurTransaction()) &&
(await tx.getRemoteConfirmationsNum()) === 0 && (await tx.getRemoteConfirmationsNum()) === 0 &&
(await tx.isSequenceReplaceable()) && (await tx.isSequenceReplaceable()) &&
(await tx.canCancelTx()) (await tx.canCancelTx())
) { ) {
let info = await tx.getInfo(); const info = await tx.getInfo();
console.log({ info }); console.log({ info });
return this.setState({ nonReplaceable: false, feeRate: info.feeRate + 1, isLoading: false, tx }); return this.setState({ nonReplaceable: false, feeRate: info.feeRate + 1, isLoading: false, tx });
// 1 sat makes a lot of difference, since sometimes because of rounding created tx's fee might be insufficient // 1 sat makes a lot of difference, since sometimes because of rounding created tx's fee might be insufficient
@ -59,7 +59,7 @@ export default class RBFCancel extends CPFP {
const tx = this.state.tx; const tx = this.state.tx;
this.setState({ isLoading: true }); this.setState({ isLoading: true });
try { try {
let { tx: newTx } = await tx.createRBFcancelTx(newFeeRate); const { tx: newTx } = await tx.createRBFcancelTx(newFeeRate);
this.setState({ stage: 2, txhex: newTx.toHex(), newTxid: newTx.getId() }); this.setState({ stage: 2, txhex: newTx.toHex(), newTxid: newTx.getId() });
this.setState({ isLoading: false }); this.setState({ isLoading: false });
} catch (_) { } catch (_) {
@ -74,10 +74,10 @@ export default class RBFCancel extends CPFP {
BlueApp.tx_metadata[this.state.newTxid] = BlueApp.tx_metadata[this.state.txid] || {}; BlueApp.tx_metadata[this.state.newTxid] = BlueApp.tx_metadata[this.state.txid] || {};
// porting tx memo // porting tx memo
if (BlueApp.tx_metadata[this.state.newTxid]['memo']) { if (BlueApp.tx_metadata[this.state.newTxid].memo) {
BlueApp.tx_metadata[this.state.newTxid]['memo'] = 'Cancelled: ' + BlueApp.tx_metadata[this.state.newTxid]['memo']; BlueApp.tx_metadata[this.state.newTxid].memo = 'Cancelled: ' + BlueApp.tx_metadata[this.state.newTxid].memo;
} else { } else {
BlueApp.tx_metadata[this.state.newTxid]['memo'] = 'Cancelled transaction'; BlueApp.tx_metadata[this.state.newTxid].memo = 'Cancelled transaction';
} }
} }

View file

@ -14,8 +14,8 @@ import HandoffSettings from '../../class/handoff';
import Handoff from 'react-native-handoff'; import Handoff from 'react-native-handoff';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
let loc = require('../../loc'); const loc = require('../../loc');
const dayjs = require('dayjs'); const dayjs = require('dayjs');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -59,8 +59,8 @@ function onlyUnique(value, index, self) {
} }
function arrDiff(a1, a2) { function arrDiff(a1, a2) {
let ret = []; const ret = [];
for (let v of a2) { for (const v of a2) {
if (a1.indexOf(v) === -1) { if (a1.indexOf(v) === -1) {
ret.push(v); ret.push(v);
} }
@ -75,17 +75,17 @@ export default class TransactionsDetails extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
let hash = props.route.params.hash; const hash = props.route.params.hash;
let foundTx = {}; let foundTx = {};
let from = []; let from = [];
let to = []; let to = [];
for (let tx of BlueApp.getTransactions()) { for (const tx of BlueApp.getTransactions()) {
if (tx.hash === hash) { if (tx.hash === hash) {
foundTx = tx; foundTx = tx;
for (let input of foundTx.inputs) { for (const input of foundTx.inputs) {
from = from.concat(input.addresses); from = from.concat(input.addresses);
} }
for (let output of foundTx.outputs) { for (const output of foundTx.outputs) {
if (output.addresses) to = to.concat(output.addresses); if (output.addresses) to = to.concat(output.addresses);
if (output.scriptPubKey && output.scriptPubKey.addresses) to = to.concat(output.scriptPubKey.addresses); if (output.scriptPubKey && output.scriptPubKey.addresses) to = to.concat(output.scriptPubKey.addresses);
} }
@ -93,8 +93,8 @@ export default class TransactionsDetails extends Component {
} }
let wallet = false; let wallet = false;
for (let w of BlueApp.getWallets()) { for (const w of BlueApp.getWallets()) {
for (let t of w.getTransactions()) { for (const t of w.getTransactions()) {
if (t.hash === hash) { if (t.hash === hash) {
console.log('tx', hash, 'belongs to', w.getLabel()); console.log('tx', hash, 'belongs to', w.getLabel());
wallet = w; wallet = w;
@ -121,7 +121,7 @@ export default class TransactionsDetails extends Component {
} }
render() { render() {
if (this.state.isLoading || !this.state.hasOwnProperty('tx')) { if (this.state.isLoading || !('tx' in this.state)) {
return <BlueLoading />; return <BlueLoading />;
} }
@ -139,10 +139,10 @@ export default class TransactionsDetails extends Component {
<BlueCard> <BlueCard>
{(() => { {(() => {
if (BlueApp.tx_metadata[this.state.tx.hash]) { if (BlueApp.tx_metadata[this.state.tx.hash]) {
if (BlueApp.tx_metadata[this.state.tx.hash]['memo']) { if (BlueApp.tx_metadata[this.state.tx.hash].memo) {
return ( return (
<View> <View>
<BlueText h4>{BlueApp.tx_metadata[this.state.tx.hash]['memo']}</BlueText> <BlueText h4>{BlueApp.tx_metadata[this.state.tx.hash].memo}</BlueText>
<BlueSpacing20 /> <BlueSpacing20 />
</View> </View>
); );
@ -150,35 +150,35 @@ export default class TransactionsDetails extends Component {
} }
})()} })()}
{this.state.hasOwnProperty('from') && ( {'from' in this.state && (
<React.Fragment> <>
<View style={styles.rowHeader}> <View style={styles.rowHeader}>
<BlueText style={styles.rowCaption}>{loc.transactions.details.from}</BlueText> <BlueText style={styles.rowCaption}>{loc.transactions.details.from}</BlueText>
<BlueCopyToClipboardButton stringToCopy={this.state.from.filter(onlyUnique).join(', ')} /> <BlueCopyToClipboardButton stringToCopy={this.state.from.filter(onlyUnique).join(', ')} />
</View> </View>
<BlueText style={styles.rowValue}>{this.state.from.filter(onlyUnique).join(', ')}</BlueText> <BlueText style={styles.rowValue}>{this.state.from.filter(onlyUnique).join(', ')}</BlueText>
</React.Fragment> </>
)} )}
{this.state.hasOwnProperty('to') && ( {'to' in this.state && (
<React.Fragment> <>
<View style={styles.rowHeader}> <View style={styles.rowHeader}>
<BlueText style={styles.rowCaption}>{loc.transactions.details.to}</BlueText> <BlueText style={styles.rowCaption}>{loc.transactions.details.to}</BlueText>
<BlueCopyToClipboardButton stringToCopy={this.state.to.filter(onlyUnique).join(', ')} /> <BlueCopyToClipboardButton stringToCopy={this.state.to.filter(onlyUnique).join(', ')} />
</View> </View>
<BlueText style={styles.rowValue}>{arrDiff(this.state.from, this.state.to.filter(onlyUnique)).join(', ')}</BlueText> <BlueText style={styles.rowValue}>{arrDiff(this.state.from, this.state.to.filter(onlyUnique)).join(', ')}</BlueText>
</React.Fragment> </>
)} )}
{this.state.tx.hasOwnProperty('fee') && ( {'fee' in this.state.tx && (
<React.Fragment> <>
<BlueText style={styles.rowCaption}>{loc.send.create.fee}</BlueText> <BlueText style={styles.rowCaption}>{loc.send.create.fee}</BlueText>
<BlueText style={styles.rowValue}>{this.state.tx.fee + ' sats'}</BlueText> <BlueText style={styles.rowValue}>{this.state.tx.fee + ' sats'}</BlueText>
</React.Fragment> </>
)} )}
{this.state.tx.hasOwnProperty('hash') && ( {'hash' in this.state.tx && (
<React.Fragment> <>
<View style={styles.rowHeader}> <View style={styles.rowHeader}>
<BlueText style={styles.txId}>Txid</BlueText> <BlueText style={styles.txId}>Txid</BlueText>
<BlueCopyToClipboardButton stringToCopy={this.state.tx.hash} /> <BlueCopyToClipboardButton stringToCopy={this.state.tx.hash} />
@ -196,35 +196,35 @@ export default class TransactionsDetails extends Component {
> >
<BlueText style={styles.txLink}>{loc.transactions.details.show_in_block_explorer}</BlueText> <BlueText style={styles.txLink}>{loc.transactions.details.show_in_block_explorer}</BlueText>
</TouchableOpacity> </TouchableOpacity>
</React.Fragment> </>
)} )}
{this.state.tx.hasOwnProperty('received') && ( {'received' in this.state.tx && (
<React.Fragment> <>
<BlueText style={styles.rowCaption}>Received</BlueText> <BlueText style={styles.rowCaption}>Received</BlueText>
<BlueText style={styles.rowValue}>{dayjs(this.state.tx.received).format('MM/DD/YYYY h:mm A')}</BlueText> <BlueText style={styles.rowValue}>{dayjs(this.state.tx.received).format('MM/DD/YYYY h:mm A')}</BlueText>
</React.Fragment> </>
)} )}
{this.state.tx.hasOwnProperty('block_height') && this.state.tx.block_height > 0 && ( {'block_height' in this.state.tx && this.state.tx.block_height > 0 && (
<React.Fragment> <>
<BlueText style={styles.rowCaption}>Block Height</BlueText> <BlueText style={styles.rowCaption}>Block Height</BlueText>
<BlueText style={styles.rowValue}>{this.state.tx.block_height}</BlueText> <BlueText style={styles.rowValue}>{this.state.tx.block_height}</BlueText>
</React.Fragment> </>
)} )}
{this.state.tx.hasOwnProperty('inputs') && ( {'inputs' in this.state.tx && (
<React.Fragment> <>
<BlueText style={styles.rowCaption}>Inputs</BlueText> <BlueText style={styles.rowCaption}>Inputs</BlueText>
<BlueText style={styles.rowValue}>{this.state.tx.inputs.length}</BlueText> <BlueText style={styles.rowValue}>{this.state.tx.inputs.length}</BlueText>
</React.Fragment> </>
)} )}
{this.state.tx.hasOwnProperty('outputs') && this.state.tx.outputs.length > 0 && ( {'outputs' in this.state.tx && this.state.tx.outputs.length > 0 && (
<React.Fragment> <>
<BlueText style={styles.rowCaption}>Outputs</BlueText> <BlueText style={styles.rowCaption}>Outputs</BlueText>
<BlueText style={styles.rowValue}>{this.state.tx.outputs.length}</BlueText> <BlueText style={styles.rowValue}>{this.state.tx.outputs.length}</BlueText>
</React.Fragment> </>
)} )}
</BlueCard> </BlueCard>
</ScrollView> </ScrollView>

View file

@ -19,8 +19,8 @@ import { Icon } from 'react-native-elements';
import Handoff from 'react-native-handoff'; import Handoff from 'react-native-handoff';
import HandoffSettings from '../../class/handoff'; import HandoffSettings from '../../class/handoff';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
let loc = require('../../loc'); const loc = require('../../loc');
const buttonStatus = Object.freeze({ const buttonStatus = Object.freeze({
possible: 1, possible: 1,
@ -138,17 +138,17 @@ export default class TransactionsStatus extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
let hash = props.route.params.hash; const hash = props.route.params.hash;
let foundTx = {}; let foundTx = {};
let from = []; let from = [];
let to = []; let to = [];
for (let tx of BlueApp.getTransactions()) { for (const tx of BlueApp.getTransactions()) {
if (tx.hash === hash) { if (tx.hash === hash) {
foundTx = tx; foundTx = tx;
for (let input of foundTx.inputs) { for (const input of foundTx.inputs) {
from = from.concat(input.addresses); from = from.concat(input.addresses);
} }
for (let output of foundTx.outputs) { for (const output of foundTx.outputs) {
if (output.addresses) to = to.concat(output.addresses); if (output.addresses) to = to.concat(output.addresses);
if (output.scriptPubKey && output.scriptPubKey.addresses) to = to.concat(output.scriptPubKey.addresses); if (output.scriptPubKey && output.scriptPubKey.addresses) to = to.concat(output.scriptPubKey.addresses);
} }
@ -156,8 +156,8 @@ export default class TransactionsStatus extends Component {
} }
let wallet = false; let wallet = false;
for (let w of BlueApp.getWallets()) { for (const w of BlueApp.getWallets()) {
for (let t of w.getTransactions()) { for (const t of w.getTransactions()) {
if (t.hash === hash) { if (t.hash === hash) {
console.log('tx', hash, 'belongs to', w.getLabel()); console.log('tx', hash, 'belongs to', w.getLabel());
wallet = w; wallet = w;
@ -204,7 +204,7 @@ export default class TransactionsStatus extends Component {
return this.setState({ isCPFPpossible: buttonStatus.notPossible }); return this.setState({ isCPFPpossible: buttonStatus.notPossible });
} }
let tx = new HDSegwitBech32Transaction(null, this.state.tx.hash, this.state.wallet); const tx = new HDSegwitBech32Transaction(null, this.state.tx.hash, this.state.wallet);
if ((await tx.isToUsTransaction()) && (await tx.getRemoteConfirmationsNum()) === 0) { if ((await tx.isToUsTransaction()) && (await tx.getRemoteConfirmationsNum()) === 0) {
return this.setState({ isCPFPpossible: buttonStatus.possible }); return this.setState({ isCPFPpossible: buttonStatus.possible });
} else { } else {
@ -217,7 +217,7 @@ export default class TransactionsStatus extends Component {
return this.setState({ isRBFBumpFeePossible: buttonStatus.notPossible }); return this.setState({ isRBFBumpFeePossible: buttonStatus.notPossible });
} }
let tx = new HDSegwitBech32Transaction(null, this.state.tx.hash, this.state.wallet); const tx = new HDSegwitBech32Transaction(null, this.state.tx.hash, this.state.wallet);
if ((await tx.isOurTransaction()) && (await tx.getRemoteConfirmationsNum()) === 0 && (await tx.isSequenceReplaceable())) { if ((await tx.isOurTransaction()) && (await tx.getRemoteConfirmationsNum()) === 0 && (await tx.isSequenceReplaceable())) {
return this.setState({ isRBFBumpFeePossible: buttonStatus.possible }); return this.setState({ isRBFBumpFeePossible: buttonStatus.possible });
} else { } else {
@ -230,7 +230,7 @@ export default class TransactionsStatus extends Component {
return this.setState({ isRBFCancelPossible: buttonStatus.notPossible }); return this.setState({ isRBFCancelPossible: buttonStatus.notPossible });
} }
let tx = new HDSegwitBech32Transaction(null, this.state.tx.hash, this.state.wallet); const tx = new HDSegwitBech32Transaction(null, this.state.tx.hash, this.state.wallet);
if ( if (
(await tx.isOurTransaction()) && (await tx.isOurTransaction()) &&
(await tx.getRemoteConfirmationsNum()) === 0 && (await tx.getRemoteConfirmationsNum()) === 0 &&
@ -244,7 +244,7 @@ export default class TransactionsStatus extends Component {
} }
render() { render() {
if (this.state.isLoading || !this.state.hasOwnProperty('tx')) { if (this.state.isLoading || !('tx' in this.state)) {
return <BlueLoading />; return <BlueLoading />;
} }
@ -270,10 +270,10 @@ export default class TransactionsStatus extends Component {
{(() => { {(() => {
if (BlueApp.tx_metadata[this.state.tx.hash]) { if (BlueApp.tx_metadata[this.state.tx.hash]) {
if (BlueApp.tx_metadata[this.state.tx.hash]['memo']) { if (BlueApp.tx_metadata[this.state.tx.hash].memo) {
return ( return (
<View style={styles.memo}> <View style={styles.memo}>
<Text style={styles.memoText}>{BlueApp.tx_metadata[this.state.tx.hash]['memo']}</Text> <Text style={styles.memoText}>{BlueApp.tx_metadata[this.state.tx.hash].memo}</Text>
<BlueSpacing20 /> <BlueSpacing20 />
</View> </View>
); );
@ -310,7 +310,7 @@ export default class TransactionsStatus extends Component {
</View> </View>
</View> </View>
{this.state.tx.hasOwnProperty('fee') && ( {'fee' in this.state.tx && (
<View style={styles.fee}> <View style={styles.fee}>
<BlueText style={styles.feeText}> <BlueText style={styles.feeText}>
{loc.send.create.fee.toLowerCase()}{' '} {loc.send.create.fee.toLowerCase()}{' '}
@ -331,14 +331,14 @@ export default class TransactionsStatus extends Component {
{(() => { {(() => {
if (this.state.isCPFPpossible === buttonStatus.unknown) { if (this.state.isCPFPpossible === buttonStatus.unknown) {
return ( return (
<React.Fragment> <>
<ActivityIndicator /> <ActivityIndicator />
<BlueSpacing20 /> <BlueSpacing20 />
</React.Fragment> </>
); );
} else if (this.state.isCPFPpossible === buttonStatus.possible) { } else if (this.state.isCPFPpossible === buttonStatus.possible) {
return ( return (
<React.Fragment> <>
<BlueButton <BlueButton
onPress={() => onPress={() =>
this.props.navigation.navigate('CPFP', { this.props.navigation.navigate('CPFP', {
@ -349,7 +349,7 @@ export default class TransactionsStatus extends Component {
title="Bump Fee" title="Bump Fee"
/> />
<BlueSpacing20 /> <BlueSpacing20 />
</React.Fragment> </>
); );
} }
})()} })()}
@ -357,14 +357,14 @@ export default class TransactionsStatus extends Component {
{(() => { {(() => {
if (this.state.isRBFBumpFeePossible === buttonStatus.unknown) { if (this.state.isRBFBumpFeePossible === buttonStatus.unknown) {
return ( return (
<React.Fragment> <>
<ActivityIndicator /> <ActivityIndicator />
<BlueSpacing20 /> <BlueSpacing20 />
</React.Fragment> </>
); );
} else if (this.state.isRBFBumpFeePossible === buttonStatus.possible) { } else if (this.state.isRBFBumpFeePossible === buttonStatus.possible) {
return ( return (
<React.Fragment> <>
<BlueButton <BlueButton
onPress={() => onPress={() =>
this.props.navigation.navigate('RBFBumpFee', { this.props.navigation.navigate('RBFBumpFee', {
@ -374,20 +374,20 @@ export default class TransactionsStatus extends Component {
} }
title="Bump Fee" title="Bump Fee"
/> />
</React.Fragment> </>
); );
} }
})()} })()}
{(() => { {(() => {
if (this.state.isRBFCancelPossible === buttonStatus.unknown) { if (this.state.isRBFCancelPossible === buttonStatus.unknown) {
return ( return (
<React.Fragment> <>
<ActivityIndicator /> <ActivityIndicator />
</React.Fragment> </>
); );
} else if (this.state.isRBFCancelPossible === buttonStatus.possible) { } else if (this.state.isRBFCancelPossible === buttonStatus.possible) {
return ( return (
<React.Fragment> <>
<TouchableOpacity style={styles.cancel}> <TouchableOpacity style={styles.cancel}>
<Text <Text
onPress={() => onPress={() =>
@ -398,10 +398,10 @@ export default class TransactionsStatus extends Component {
} }
style={styles.cancelText} style={styles.cancelText}
> >
{'Cancel Transaction'} Cancel Transaction
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</React.Fragment> </>
); );
} }
})()} })()}

View file

@ -31,10 +31,10 @@ import { HDSegwitBech32Wallet, SegwitP2SHWallet, HDSegwitP2SHWallet, LightningCu
import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { Icon } from 'react-native-elements'; import { Icon } from 'react-native-elements';
let EV = require('../../events'); const EV = require('../../events');
let A = require('../../analytics'); const A = require('../../analytics');
let BlueApp: AppStorage = require('../../BlueApp'); const BlueApp: AppStorage = require('../../BlueApp');
let loc = require('../../loc'); const loc = require('../../loc');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
loading: { loading: {
@ -127,7 +127,7 @@ export default class WalletsAdd extends Component {
async componentDidMount() { async componentDidMount() {
let walletBaseURI = await AsyncStorage.getItem(AppStorage.LNDHUB); let walletBaseURI = await AsyncStorage.getItem(AppStorage.LNDHUB);
let isAdvancedOptionsEnabled = await BlueApp.isAdancedModeEnabled(); const isAdvancedOptionsEnabled = await BlueApp.isAdancedModeEnabled();
walletBaseURI = walletBaseURI || ''; walletBaseURI = walletBaseURI || '';
this.setState({ this.setState({
isLoading: false, isLoading: false,
@ -265,7 +265,7 @@ export default class WalletsAdd extends Component {
); );
} else if (this.state.activeLightning && this.state.isAdvancedOptionsEnabled) { } else if (this.state.activeLightning && this.state.isAdvancedOptionsEnabled) {
return ( return (
<React.Fragment> <>
<BlueSpacing20 /> <BlueSpacing20 />
<Text style={styles.advancedText}>{loc.settings.advanced_options}</Text> <Text style={styles.advancedText}>{loc.settings.advanced_options}</Text>
<BlueSpacing20 /> <BlueSpacing20 />
@ -286,7 +286,7 @@ export default class WalletsAdd extends Component {
underlineColorAndroid="transparent" underlineColorAndroid="transparent"
/> />
</View> </View>
</React.Fragment> </>
); );
} else if (this.state.activeBitcoin === undefined && this.state.isAdvancedOptionsEnabled) { } else if (this.state.activeBitcoin === undefined && this.state.isAdvancedOptionsEnabled) {
return <View />; return <View />;
@ -303,14 +303,12 @@ export default class WalletsAdd extends Component {
let w; let w;
if (this.state.activeLightning) { if (this.state.activeLightning) {
// eslint-disable-next-line
this.createLightningWallet = async () => { this.createLightningWallet = async () => {
w = new LightningCustodianWallet(); w = new LightningCustodianWallet();
w.setLabel(this.state.label || loc.wallets.details.title); w.setLabel(this.state.label || loc.wallets.details.title);
try { try {
let lndhub = const lndhub =
this.state.walletBaseURI.trim().length > 0 this.state.walletBaseURI.trim().length > 0
? this.state.walletBaseURI ? this.state.walletBaseURI
: LightningCustodianWallet.defaultBaseUri; : LightningCustodianWallet.defaultBaseUri;

View file

@ -5,8 +5,8 @@ import PropTypes from 'prop-types';
import { WebView } from 'react-native-webview'; import { WebView } from 'react-native-webview';
import { AppStorage, LightningCustodianWallet, WatchOnlyWallet } from '../../class'; import { AppStorage, LightningCustodianWallet, WatchOnlyWallet } from '../../class';
const currency = require('../../currency'); const currency = require('../../currency');
let BlueApp: AppStorage = require('../../BlueApp'); const BlueApp: AppStorage = require('../../BlueApp');
let loc = require('../../loc'); const loc = require('../../loc');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
root: { root: {
@ -23,7 +23,7 @@ export default class BuyBitcoin extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
let wallet = props.route.params.wallet; const wallet = props.route.params.wallet;
if (!wallet) console.warn('wallet was not passed to buyBitcoin'); if (!wallet) console.warn('wallet was not passed to buyBitcoin');
this.state = { this.state = {
@ -40,7 +40,7 @@ export default class BuyBitcoin extends Component {
preferredCurrency = preferredCurrency.endPointKey; preferredCurrency = preferredCurrency.endPointKey;
/** @type {AbstractHDWallet|WatchOnlyWallet|LightningCustodianWallet} */ /** @type {AbstractHDWallet|WatchOnlyWallet|LightningCustodianWallet} */
let wallet = this.state.wallet; const wallet = this.state.wallet;
let address = ''; let address = '';

View file

@ -180,7 +180,7 @@ export default class WalletDetails extends Component {
async onUseWithHardwareWalletSwitch(value) { async onUseWithHardwareWalletSwitch(value) {
this.setState((state, props) => { this.setState((state, props) => {
let wallet = state.wallet; const wallet = state.wallet;
wallet.setUseWithHardwareWalletEnabled(value); wallet.setUseWithHardwareWalletEnabled(value);
return { useWithHardwareWallet: !!value, wallet }; return { useWithHardwareWallet: !!value, wallet };
}); });
@ -229,10 +229,10 @@ export default class WalletDetails extends Component {
(this.state.wallet.type === WatchOnlyWallet.type && !this.state.wallet.isHd()) (this.state.wallet.type === WatchOnlyWallet.type && !this.state.wallet.isHd())
) { ) {
return ( return (
<React.Fragment> <>
<Text style={styles.textLabel1}>{loc.wallets.details.address.toLowerCase()}</Text> <Text style={styles.textLabel1}>{loc.wallets.details.address.toLowerCase()}</Text>
<Text style={styles.textValue}>{this.state.wallet.getAddress()}</Text> <Text style={styles.textValue}>{this.state.wallet.getAddress()}</Text>
</React.Fragment> </>
); );
} }
})()} })()}
@ -261,10 +261,10 @@ export default class WalletDetails extends Component {
<Text style={styles.textLabel1}>{loc.wallets.details.type.toLowerCase()}</Text> <Text style={styles.textLabel1}>{loc.wallets.details.type.toLowerCase()}</Text>
<Text style={styles.textValue}>{this.state.wallet.typeReadable}</Text> <Text style={styles.textValue}>{this.state.wallet.typeReadable}</Text>
{this.state.wallet.type === LightningCustodianWallet.type && ( {this.state.wallet.type === LightningCustodianWallet.type && (
<React.Fragment> <>
<Text style={styles.textLabel1}>{loc.wallets.details.connected_to.toLowerCase()}</Text> <Text style={styles.textLabel1}>{loc.wallets.details.connected_to.toLowerCase()}</Text>
<BlueText>{this.state.wallet.getBaseURI()}</BlueText> <BlueText>{this.state.wallet.getBaseURI()}</BlueText>
</React.Fragment> </>
)} )}
<View> <View>
<BlueSpacing20 /> <BlueSpacing20 />
@ -278,10 +278,10 @@ export default class WalletDetails extends Component {
onValueChange={value => this.onUseWithHardwareWalletSwitch(value)} onValueChange={value => this.onUseWithHardwareWalletSwitch(value)}
/> />
</View> </View>
<React.Fragment> <>
<Text style={styles.textLabel1}>{loc.wallets.details.master_fingerprint.toLowerCase()}</Text> <Text style={styles.textLabel1}>{loc.wallets.details.master_fingerprint.toLowerCase()}</Text>
<Text style={styles.textValue}>{this.state.wallet.getMasterFingerprintHex()}</Text> <Text style={styles.textValue}>{this.state.wallet.getMasterFingerprintHex()}</Text>
</React.Fragment> </>
<BlueSpacing20 /> <BlueSpacing20 />
</> </>
)} )}
@ -301,7 +301,7 @@ export default class WalletDetails extends Component {
this.state.wallet.type === HDLegacyP2PKHWallet.type || this.state.wallet.type === HDLegacyP2PKHWallet.type ||
this.state.wallet.type === HDSegwitBech32Wallet.type || this.state.wallet.type === HDSegwitBech32Wallet.type ||
this.state.wallet.type === HDSegwitP2SHWallet.type) && ( this.state.wallet.type === HDSegwitP2SHWallet.type) && (
<React.Fragment> <>
<BlueButton <BlueButton
onPress={() => onPress={() =>
this.props.navigation.navigate('WalletXpub', { this.props.navigation.navigate('WalletXpub', {
@ -313,13 +313,13 @@ export default class WalletDetails extends Component {
<BlueSpacing20 /> <BlueSpacing20 />
{this.renderMarketplaceButton()} {this.renderMarketplaceButton()}
</React.Fragment> </>
)} )}
{this.state.wallet.type !== LightningCustodianWallet.type && ( {this.state.wallet.type !== LightningCustodianWallet.type && (
<React.Fragment> <>
<BlueSpacing20 /> <BlueSpacing20 />
<BlueButton onPress={() => this.props.navigation.navigate('Broadcast')} title="Broadcast transaction" /> <BlueButton onPress={() => this.props.navigation.navigate('Broadcast')} title="Broadcast transaction" />
</React.Fragment> </>
)} )}
<BlueSpacing20 /> <BlueSpacing20 />
<TouchableOpacity <TouchableOpacity

View file

@ -7,8 +7,8 @@ import Privacy from '../../Privacy';
import Biometric from '../../class/biometrics'; import Biometric from '../../class/biometrics';
import { LegacyWallet, LightningCustodianWallet, SegwitBech32Wallet, SegwitP2SHWallet, WatchOnlyWallet } from '../../class'; import { LegacyWallet, LightningCustodianWallet, SegwitBech32Wallet, SegwitP2SHWallet, WatchOnlyWallet } from '../../class';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
let loc = require('../../loc'); const loc = require('../../loc');
const { height, width } = Dimensions.get('window'); const { height, width } = Dimensions.get('window');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -47,7 +47,7 @@ export default class WalletExport extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
let wallet = props.route.params.wallet; const wallet = props.route.params.wallet;
this.state = { this.state = {
isLoading: true, isLoading: true,
qrCodeHeight: height > width ? width - 40 : width / 2, qrCodeHeight: height > width ? width - 40 : width / 2,
@ -119,7 +119,7 @@ export default class WalletExport extends Component {
logoSize={70} logoSize={70}
color={BlueApp.settings.foregroundColor} color={BlueApp.settings.foregroundColor}
logoBackgroundColor={BlueApp.settings.brandingColor} logoBackgroundColor={BlueApp.settings.brandingColor}
ecl={'H'} ecl="H"
/> />
<BlueSpacing20 /> <BlueSpacing20 />

View file

@ -312,7 +312,7 @@ export default class HodlHodl extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
/** @type {AbstractWallet} */ /** @type {AbstractWallet} */
let wallet = props.route.params.wallet; const wallet = props.route.params.wallet;
this.state = { this.state = {
isLoading: true, isLoading: true,
@ -340,10 +340,10 @@ export default class HodlHodl extends Component {
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
async fetchOffers() { async fetchOffers() {
let pagination = { const pagination = {
[HodlHodlApi.PAGINATION_LIMIT]: 200, [HodlHodlApi.PAGINATION_LIMIT]: 200,
}; };
let filters = { const filters = {
[HodlHodlApi.FILTERS_COUNTRY]: this.state.country, [HodlHodlApi.FILTERS_COUNTRY]: this.state.country,
[HodlHodlApi.FILTERS_SIDE]: this.state.side, [HodlHodlApi.FILTERS_SIDE]: this.state.side,
[HodlHodlApi.FILTERS_ASSET_CODE]: HodlHodlApi.FILTERS_ASSET_CODE_VALUE_BTC, [HodlHodlApi.FILTERS_ASSET_CODE]: HodlHodlApi.FILTERS_ASSET_CODE_VALUE_BTC,
@ -359,7 +359,7 @@ export default class HodlHodl extends Component {
filters[HodlHodlApi.FILTERS_PAYMENT_METHOD_ID] = this.state.method; filters[HodlHodlApi.FILTERS_PAYMENT_METHOD_ID] = this.state.method;
} }
let sort = { const sort = {
[HodlHodlApi.SORT_BY]: HodlHodlApi.SORT_BY_VALUE_PRICE, [HodlHodlApi.SORT_BY]: HodlHodlApi.SORT_BY_VALUE_PRICE,
[HodlHodlApi.SORT_DIRECTION]: HodlHodlApi.SORT_DIRECTION_VALUE_ASC, [HodlHodlApi.SORT_DIRECTION]: HodlHodlApi.SORT_DIRECTION_VALUE_ASC,
}; };
@ -371,7 +371,7 @@ export default class HodlHodl extends Component {
} }
async fetchMyCountry() { async fetchMyCountry() {
let myCountryCode = await HodlApi.getMyCountryCode(); const myCountryCode = await HodlApi.getMyCountryCode();
this.setState({ this.setState({
myCountryCode, myCountryCode,
country: myCountryCode, // we start with orders from current country country: myCountryCode, // we start with orders from current country
@ -384,7 +384,7 @@ export default class HodlHodl extends Component {
* @returns {Promise<void>} * @returns {Promise<void>}
**/ **/
async fetchListOfCountries() { async fetchListOfCountries() {
let countries = await HodlApi.getCountries(); const countries = await HodlApi.getCountries();
this.setState({ countries }); this.setState({ countries });
} }
@ -394,7 +394,7 @@ export default class HodlHodl extends Component {
* @returns {Promise<void>} * @returns {Promise<void>}
**/ **/
async fetchListOfCurrencies() { async fetchListOfCurrencies() {
let currencies = await HodlApi.getCurrencies(); const currencies = await HodlApi.getCurrencies();
this.setState({ currencies }); this.setState({ currencies });
} }
@ -404,7 +404,7 @@ export default class HodlHodl extends Component {
* @returns {Promise<void>} * @returns {Promise<void>}
**/ **/
async fetchListOfMethods() { async fetchListOfMethods() {
let methods = await HodlApi.getPaymentMethods(this.state.country || HodlHodlApi.FILTERS_COUNTRY_VALUE_GLOBAL); const methods = await HodlApi.getPaymentMethods(this.state.country || HodlHodlApi.FILTERS_COUNTRY_VALUE_GLOBAL);
this.setState({ methods }); this.setState({ methods });
} }
@ -520,20 +520,14 @@ export default class HodlHodl extends Component {
let ret = title; let ret = title;
if (description) { if (description) {
if (description.startsWith(title)) title = ''; if (description.startsWith(title)) title = '';
ret = ret = title + '\n' + description.split('\n').slice(0, 2).join('\n');
title +
'\n' +
description
.split('\n')
.slice(0, 2)
.join('\n');
} }
if (ret.length >= 200) ret = ret.substr(0, 200) + '...'; if (ret.length >= 200) ret = ret.substr(0, 200) + '...';
return ret; return ret;
} }
getMethodName(id) { getMethodName(id) {
for (let m of this.state.methods) { for (const m of this.state.methods) {
if (m.id === id) return m.name; if (m.id === id) return m.name;
} }
return ''; return '';
@ -561,7 +555,7 @@ export default class HodlHodl extends Component {
getNativeCountryName() { getNativeCountryName() {
if (this.state.country === this.state.myCountryCode) return 'Near me'; if (this.state.country === this.state.myCountryCode) return 'Near me';
for (let c of this.state.countries) { for (const c of this.state.countries) {
if (c.code === this.state.country) return c.native_name; if (c.code === this.state.country) return c.native_name;
} }
return 'Global offers'; return 'Global offers';
@ -675,10 +669,10 @@ export default class HodlHodl extends Component {
}; };
renderChooseContryModal = () => { renderChooseContryModal = () => {
let countries2render = []; const countries2render = [];
// first, we include in the list current country // first, we include in the list current country
for (let country of this.state.countries) { for (const country of this.state.countries) {
if (country.code === this.state.country) { if (country.code === this.state.country) {
countries2render.push(country); countries2render.push(country);
} }
@ -692,7 +686,7 @@ export default class HodlHodl extends Component {
}); });
// lastly, we include other countries // lastly, we include other countries
for (let country of this.state.countries) { for (const country of this.state.countries) {
if (country.code !== this.state.country) { if (country.code !== this.state.country) {
// except currently selected one // except currently selected one
if (this.state.countrySearchInput) { if (this.state.countrySearchInput) {
@ -724,7 +718,7 @@ export default class HodlHodl extends Component {
<View style={styles.modalSearch}> <View style={styles.modalSearch}>
<TextInput <TextInput
onChangeText={text => this.setState({ countrySearchInput: text })} onChangeText={text => this.setState({ countrySearchInput: text })}
placeholder={'Search..'} placeholder="Search.."
placeholderTextColor="#9AA0AA" placeholderTextColor="#9AA0AA"
value={this.state.countrySearchInput || ''} value={this.state.countrySearchInput || ''}
numberOfLines={1} numberOfLines={1}
@ -762,7 +756,7 @@ export default class HodlHodl extends Component {
}; };
renderChooseCurrencyModal = () => { renderChooseCurrencyModal = () => {
let currencies2render = []; const currencies2render = [];
// first, option to choose any currency // first, option to choose any currency
currencies2render.push({ currencies2render.push({
@ -771,7 +765,7 @@ export default class HodlHodl extends Component {
}); });
// lastly, we include other countries // lastly, we include other countries
for (let curr of this.state.currencies) { for (const curr of this.state.currencies) {
if (this.state.currencySearchInput) { if (this.state.currencySearchInput) {
// if user typed something in search box we apply that filter // if user typed something in search box we apply that filter
if ( if (
@ -800,7 +794,7 @@ export default class HodlHodl extends Component {
<View style={styles.modalSearch}> <View style={styles.modalSearch}>
<TextInput <TextInput
onChangeText={text => this.setState({ currencySearchInput: text })} onChangeText={text => this.setState({ currencySearchInput: text })}
placeholder={'Search..'} placeholder="Search.."
placeholderTextColor="#9AA0AA" placeholderTextColor="#9AA0AA"
value={this.state.currencySearchInput || ''} value={this.state.currencySearchInput || ''}
numberOfLines={1} numberOfLines={1}
@ -845,7 +839,7 @@ export default class HodlHodl extends Component {
}; };
renderChooseMethodModal = () => { renderChooseMethodModal = () => {
let methods2render = []; const methods2render = [];
// first, option to choose any currency // first, option to choose any currency
methods2render.push({ methods2render.push({
@ -854,7 +848,7 @@ export default class HodlHodl extends Component {
}); });
// lastly, we include other countries // lastly, we include other countries
for (let curr of this.state.methods) { for (const curr of this.state.methods) {
if (this.state.methodSearchInput) { if (this.state.methodSearchInput) {
// if user typed something in search box we apply that filter // if user typed something in search box we apply that filter
if ( if (
@ -883,7 +877,7 @@ export default class HodlHodl extends Component {
<View style={styles.modalSearch}> <View style={styles.modalSearch}>
<TextInput <TextInput
onChangeText={text => this.setState({ methodSearchInput: text })} onChangeText={text => this.setState({ methodSearchInput: text })}
placeholder={'Search..'} placeholder="Search.."
placeholderTextColor="#9AA0AA" placeholderTextColor="#9AA0AA"
value={this.state.methodSearchInput || ''} value={this.state.methodSearchInput || ''}
numberOfLines={1} numberOfLines={1}

View file

@ -15,7 +15,7 @@ import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import Privacy from '../../Privacy'; import Privacy from '../../Privacy';
import { useNavigation, useRoute } from '@react-navigation/native'; import { useNavigation, useRoute } from '@react-navigation/native';
import WalletImport from '../../class/wallet-import'; import WalletImport from '../../class/wallet-import';
let loc = require('../../loc'); const loc = require('../../loc');
const { width } = Dimensions.get('window'); const { width } = Dimensions.get('window');
const styles = StyleSheet.create({ const styles = StyleSheet.create({

View file

@ -25,7 +25,7 @@ import ImagePicker from 'react-native-image-picker';
import NavigationService from '../../NavigationService'; import NavigationService from '../../NavigationService';
const EV = require('../../events'); const EV = require('../../events');
const A = require('../../analytics'); const A = require('../../analytics');
let BlueApp: AppStorage = require('../../BlueApp'); const BlueApp: AppStorage = require('../../BlueApp');
const loc = require('../../loc'); const loc = require('../../loc');
const BlueElectrum = require('../../BlueElectrum'); const BlueElectrum = require('../../BlueElectrum');
const LocalQRCode = require('@remobile/react-native-qrcode-local-image'); const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
@ -192,13 +192,13 @@ export default class WalletsList extends Component {
InteractionManager.runAfterInteractions(async () => { InteractionManager.runAfterInteractions(async () => {
try { try {
await BlueElectrum.waitTillConnected(); await BlueElectrum.waitTillConnected();
let balanceStart = +new Date(); const balanceStart = +new Date();
await BlueApp.fetchWalletBalances(); await BlueApp.fetchWalletBalances();
let balanceEnd = +new Date(); const balanceEnd = +new Date();
console.log('fetch all wallet balances took', (balanceEnd - balanceStart) / 1000, 'sec'); console.log('fetch all wallet balances took', (balanceEnd - balanceStart) / 1000, 'sec');
let start = +new Date(); const start = +new Date();
await BlueApp.fetchWalletTransactions(); await BlueApp.fetchWalletTransactions();
let end = +new Date(); const end = +new Date();
console.log('fetch all wallet txs took', (end - start) / 1000, 'sec'); console.log('fetch all wallet txs took', (end - start) / 1000, 'sec');
} catch (error) { } catch (error) {
console.log(error); console.log(error);
@ -233,13 +233,13 @@ export default class WalletsList extends Component {
try { try {
await BlueElectrum.ping(); await BlueElectrum.ping();
await BlueElectrum.waitTillConnected(); await BlueElectrum.waitTillConnected();
let balanceStart = +new Date(); const balanceStart = +new Date();
await BlueApp.fetchWalletBalances(this.walletsCarousel.current.currentIndex || 0); await BlueApp.fetchWalletBalances(this.walletsCarousel.current.currentIndex || 0);
let balanceEnd = +new Date(); const balanceEnd = +new Date();
console.log('fetch balance took', (balanceEnd - balanceStart) / 1000, 'sec'); console.log('fetch balance took', (balanceEnd - balanceStart) / 1000, 'sec');
let start = +new Date(); const start = +new Date();
await BlueApp.fetchWalletTransactions(this.walletsCarousel.current.currentIndex || 0); await BlueApp.fetchWalletTransactions(this.walletsCarousel.current.currentIndex || 0);
let end = +new Date(); const end = +new Date();
console.log('fetch tx took', (end - start) / 1000, 'sec'); console.log('fetch tx took', (end - start) / 1000, 'sec');
} catch (err) { } catch (err) {
noErr = false; noErr = false;
@ -288,15 +288,15 @@ export default class WalletsList extends Component {
}; };
txMemo(hash) { txMemo(hash) {
if (BlueApp.tx_metadata[hash] && BlueApp.tx_metadata[hash]['memo']) { if (BlueApp.tx_metadata[hash] && BlueApp.tx_metadata[hash].memo) {
return BlueApp.tx_metadata[hash]['memo']; return BlueApp.tx_metadata[hash].memo;
} }
return ''; return '';
} }
handleClick = index => { handleClick = index => {
console.log('click', index); console.log('click', index);
let wallet = BlueApp.wallets[index]; const wallet = BlueApp.wallets[index];
if (wallet) { if (wallet) {
if (wallet.type === PlaceholderWallet.type) { if (wallet.type === PlaceholderWallet.type) {
Alert.alert( Alert.alert(
@ -359,12 +359,12 @@ export default class WalletsList extends Component {
*/ */
async lazyRefreshWallet(index) { async lazyRefreshWallet(index) {
/** @type {Array.<AbstractWallet>} wallets */ /** @type {Array.<AbstractWallet>} wallets */
let wallets = BlueApp.getWallets(); const wallets = BlueApp.getWallets();
if (!wallets[index]) { if (!wallets[index]) {
return; return;
} }
let oldBalance = wallets[index].getBalance(); const oldBalance = wallets[index].getBalance();
let noErr = true; let noErr = true;
let didRefresh = false; let didRefresh = false;
@ -586,7 +586,7 @@ export default class WalletsList extends Component {
sendButtonLongPress = async () => { sendButtonLongPress = async () => {
const isClipboardEmpty = (await Clipboard.getString()).replace(' ', '').length === 0; const isClipboardEmpty = (await Clipboard.getString()).replace(' ', '').length === 0;
if (Platform.OS === 'ios') { if (Platform.OS === 'ios') {
let options = [loc.send.details.cancel, 'Choose Photo', 'Scan QR Code']; const options = [loc.send.details.cancel, 'Choose Photo', 'Scan QR Code'];
if (!isClipboardEmpty) { if (!isClipboardEmpty) {
options.push('Copy from Clipboard'); options.push('Copy from Clipboard');
} }
@ -607,7 +607,7 @@ export default class WalletsList extends Component {
} }
}); });
} else if (Platform.OS === 'android') { } else if (Platform.OS === 'android') {
let buttons = [ const buttons = [
{ {
text: loc.send.details.cancel, text: loc.send.details.cancel,
onPress: () => {}, onPress: () => {},

View file

@ -16,7 +16,7 @@ export default class Marketplace extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
if (!props.route.params.fromWallet) throw new Error('Invalid param'); if (!props.route.params.fromWallet) throw new Error('Invalid param');
let fromWallet = props.route.params.fromWallet; const fromWallet = props.route.params.fromWallet;
this.state = { this.state = {
url: '', url: '',

View file

@ -82,7 +82,7 @@ const PleaseBackup = () => {
}, [handleBackButton, words]); }, [handleBackButton, words]);
const renderSecret = () => { const renderSecret = () => {
let component = []; const component = [];
for (const [index, secret] of words.entries()) { for (const [index, secret] of words.entries()) {
component.push( component.push(
<View style={styles.word} key={`${secret}${index}`}> <View style={styles.word} key={`${secret}${index}`}>

View file

@ -44,7 +44,7 @@ const PleaseBackupLNDHub = () => {
size={qrCodeHeight} size={qrCodeHeight}
color={BlueApp.settings.foregroundColor} color={BlueApp.settings.foregroundColor}
logoBackgroundColor={BlueApp.settings.brandingColor} logoBackgroundColor={BlueApp.settings.brandingColor}
ecl={'H'} ecl="H"
/> />
<BlueSpacing20 /> <BlueSpacing20 />

View file

@ -7,10 +7,10 @@ import PropTypes from 'prop-types';
import { PlaceholderWallet, LightningCustodianWallet } from '../../class'; import { PlaceholderWallet, LightningCustodianWallet } from '../../class';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import WalletGradient from '../../class/wallet-gradient'; import WalletGradient from '../../class/wallet-gradient';
let EV = require('../../events'); const EV = require('../../events');
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
let loc = require('../../loc/'); const loc = require('../../loc/');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
loading: { loading: {
@ -89,13 +89,13 @@ export default class ReorderWallets extends Component {
this.props.navigation.setParams({ this.props.navigation.setParams({
customCloseButtonFunction: async () => { customCloseButtonFunction: async () => {
if (this.sortableList.state.data.length === this.state.data.length && this.state.hasMovedARow) { if (this.sortableList.state.data.length === this.state.data.length && this.state.hasMovedARow) {
let newWalletsOrderArray = []; const newWalletsOrderArray = [];
this.sortableList.state.order.forEach(element => { this.sortableList.state.order.forEach(element => {
newWalletsOrderArray.push(this.state.data[element]); newWalletsOrderArray.push(this.state.data[element]);
}); });
BlueApp.wallets = newWalletsOrderArray; BlueApp.wallets = newWalletsOrderArray;
await BlueApp.saveToDisk(); await BlueApp.saveToDisk();
setTimeout(function() { setTimeout(function () {
EV(EV.enum.WALLETS_COUNT_CHANGED); EV(EV.enum.WALLETS_COUNT_CHANGED);
}, 500); // adds some animaton }, 500); // adds some animaton
this.props.navigation.goBack(); this.props.navigation.goBack();

View file

@ -38,10 +38,10 @@ import HandoffSettings from '../../class/handoff';
import Handoff from 'react-native-handoff'; import Handoff from 'react-native-handoff';
import ActionSheet from '../ActionSheet'; import ActionSheet from '../ActionSheet';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
let loc = require('../../loc'); const loc = require('../../loc');
let EV = require('../../events'); const EV = require('../../events');
let BlueElectrum = require('../../BlueElectrum'); const BlueElectrum = require('../../BlueElectrum');
const LocalQRCode = require('@remobile/react-native-qrcode-local-image'); const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -242,8 +242,8 @@ export default class WalletTransactions extends Component {
* Forcefully fetches TXs and balance for wallet * Forcefully fetches TXs and balance for wallet
*/ */
refreshTransactionsFunction() { refreshTransactionsFunction() {
let that = this; const that = this;
setTimeout(function() { setTimeout(function () {
that.refreshTransactions(); that.refreshTransactions();
}, 4000); // giving a chance to remote server to propagate }, 4000); // giving a chance to remote server to propagate
} }
@ -256,13 +256,13 @@ export default class WalletTransactions extends Component {
* @returns {Array} * @returns {Array}
*/ */
getTransactions(limit = Infinity) { getTransactions(limit = Infinity) {
let wallet = this.props.route.params.wallet; const wallet = this.props.route.params.wallet;
let txs = wallet.getTransactions(); let txs = wallet.getTransactions();
for (let tx of txs) { for (const tx of txs) {
tx.sort_ts = +new Date(tx.received); tx.sort_ts = +new Date(tx.received);
} }
txs = txs.sort(function(a, b) { txs = txs.sort(function (a, b) {
return b.sort_ts - a.sort_ts; return b.sort_ts - a.sort_ts;
}); });
return txs.slice(0, limit); return txs.slice(0, limit);
@ -281,7 +281,7 @@ export default class WalletTransactions extends Component {
} }
isLightning() { isLightning() {
let w = this.state.wallet; const w = this.state.wallet;
if (w && w.chain === Chain.OFFCHAIN) { if (w && w.chain === Chain.OFFCHAIN) {
return true; return true;
} }
@ -306,14 +306,14 @@ export default class WalletTransactions extends Component {
await BlueElectrum.ping(); await BlueElectrum.ping();
await BlueElectrum.waitTillConnected(); await BlueElectrum.waitTillConnected();
/** @type {LegacyWallet} */ /** @type {LegacyWallet} */
let wallet = this.state.wallet; const wallet = this.state.wallet;
let balanceStart = +new Date(); const balanceStart = +new Date();
const oldBalance = wallet.getBalance(); const oldBalance = wallet.getBalance();
await wallet.fetchBalance(); await wallet.fetchBalance();
if (oldBalance !== wallet.getBalance()) smthChanged = true; if (oldBalance !== wallet.getBalance()) smthChanged = true;
let balanceEnd = +new Date(); const balanceEnd = +new Date();
console.log(wallet.getLabel(), 'fetch balance took', (balanceEnd - balanceStart) / 1000, 'sec'); console.log(wallet.getLabel(), 'fetch balance took', (balanceEnd - balanceStart) / 1000, 'sec');
let start = +new Date(); const start = +new Date();
const oldTxLen = wallet.getTransactions().length; const oldTxLen = wallet.getTransactions().length;
await wallet.fetchTransactions(); await wallet.fetchTransactions();
if (wallet.fetchPendingTransactions) { if (wallet.fetchPendingTransactions) {
@ -323,7 +323,7 @@ export default class WalletTransactions extends Component {
await wallet.fetchUserInvoices(); await wallet.fetchUserInvoices();
} }
if (oldTxLen !== wallet.getTransactions().length) smthChanged = true; if (oldTxLen !== wallet.getTransactions().length) smthChanged = true;
let end = +new Date(); const end = +new Date();
console.log(wallet.getLabel(), 'fetch tx took', (end - start) / 1000, 'sec'); console.log(wallet.getLabel(), 'fetch tx took', (end - start) / 1000, 'sec');
} catch (err) { } catch (err) {
noErr = false; noErr = false;
@ -415,7 +415,7 @@ export default class WalletTransactions extends Component {
}), }),
); );
}} }}
title={'Refill with External Wallet'} title="Refill with External Wallet"
/> />
<BlueListItem <BlueListItem
@ -428,7 +428,7 @@ export default class WalletTransactions extends Component {
}); });
}); });
}} }}
title={'Refill with bank card'} title="Refill with bank card"
/> />
<BlueListItem <BlueListItem
@ -493,6 +493,7 @@ export default class WalletTransactions extends Component {
</TouchableOpacity> </TouchableOpacity>
); );
}; };
renderSellFiat = () => { renderSellFiat = () => {
return ( return (
<TouchableOpacity <TouchableOpacity
@ -626,7 +627,7 @@ export default class WalletTransactions extends Component {
sendButtonLongPress = async () => { sendButtonLongPress = async () => {
const isClipboardEmpty = (await Clipboard.getString()).replace(' ', '').length === 0; const isClipboardEmpty = (await Clipboard.getString()).replace(' ', '').length === 0;
if (Platform.OS === 'ios') { if (Platform.OS === 'ios') {
let options = [loc.send.details.cancel, 'Choose Photo', 'Scan QR Code']; const options = [loc.send.details.cancel, 'Choose Photo', 'Scan QR Code'];
if (!isClipboardEmpty) { if (!isClipboardEmpty) {
options.push('Copy from Clipboard'); options.push('Copy from Clipboard');
} }
@ -644,7 +645,7 @@ export default class WalletTransactions extends Component {
} }
}); });
} else if (Platform.OS === 'android') { } else if (Platform.OS === 'android') {
let buttons = [ const buttons = [
{ {
text: loc.send.details.cancel, text: loc.send.details.cancel,
onPress: () => {}, onPress: () => {},

View file

@ -15,7 +15,7 @@ export default class WalletMigrate {
const isNotFirstLaunch = await AsyncStorage.getItem('RnSksIsAppInstalled'); const isNotFirstLaunch = await AsyncStorage.getItem('RnSksIsAppInstalled');
if (!isNotFirstLaunch) { if (!isNotFirstLaunch) {
try { try {
console.warn('It is the first launch...') console.warn('It is the first launch...');
await RNSecureKeyStore.setResetOnAppUninstallTo(false); await RNSecureKeyStore.setResetOnAppUninstallTo(false);
const deleteWalletsFromKeychain = await RNSecureKeyStore.get(AppStorage.DELETE_WALLET_AFTER_UNINSTALL); const deleteWalletsFromKeychain = await RNSecureKeyStore.get(AppStorage.DELETE_WALLET_AFTER_UNINSTALL);
await RNSecureKeyStore.setResetOnAppUninstallTo(deleteWalletsFromKeychain === '1'); await RNSecureKeyStore.setResetOnAppUninstallTo(deleteWalletsFromKeychain === '1');
@ -61,12 +61,12 @@ export default class WalletMigrate {
if (file.name === 'manifest.json') { if (file.name === 'manifest.json') {
const manifestFile = await RNFS.readFile(file.path); const manifestFile = await RNFS.readFile(file.path);
const manifestFileParsed = JSON.parse(manifestFile); const manifestFileParsed = JSON.parse(manifestFile);
if (manifestFileParsed.hasOwnProperty('data')) { if ('data' in manifestFileParsed) {
if (typeof manifestFileParsed.data === 'string') { if (typeof manifestFileParsed.data === 'string') {
await AsyncStorage.setItem('data', manifestFileParsed.data); await AsyncStorage.setItem('data', manifestFileParsed.data);
} }
} }
if (manifestFileParsed.hasOwnProperty('data_encrypted')) { if ('data_encrypted' in manifestFileParsed) {
if (typeof manifestFileParsed.data_encrypted === 'string') { if (typeof manifestFileParsed.data_encrypted === 'string') {
await AsyncStorage.setItem('data_encrypted', manifestFileParsed.data_encrypted); await AsyncStorage.setItem('data_encrypted', manifestFileParsed.data_encrypted);
} }

View file

@ -6,8 +6,8 @@ import PropTypes from 'prop-types';
import Privacy from '../../Privacy'; import Privacy from '../../Privacy';
import Biometric from '../../class/biometrics'; import Biometric from '../../class/biometrics';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); const BlueApp = require('../../BlueApp');
let loc = require('../../loc'); const loc = require('../../loc');
const { height, width } = Dimensions.get('window'); const { height, width } = Dimensions.get('window');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -32,10 +32,10 @@ export default class WalletXpub extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
let secret = props.route.params.secret; const secret = props.route.params.secret;
let wallet; let wallet;
for (let w of BlueApp.getWallets()) { for (const w of BlueApp.getWallets()) {
if (w.getSecret() === secret) { if (w.getSecret() === secret) {
// found our wallet // found our wallet
wallet = w; wallet = w;
@ -99,7 +99,7 @@ export default class WalletXpub extends Component {
logoSize={90} logoSize={90}
color={BlueApp.settings.foregroundColor} color={BlueApp.settings.foregroundColor}
logoBackgroundColor={BlueApp.settings.brandingColor} logoBackgroundColor={BlueApp.settings.brandingColor}
ecl={'H'} ecl="H"
/> />
<BlueSpacing20 /> <BlueSpacing20 />

View file

@ -20,7 +20,7 @@ global.tls = require('react-native-tcp/tls');
// global.location = global.location || { port: 80 } // global.location = global.location || { port: 80 }
const isDev = typeof __DEV__ === 'boolean' && __DEV__; const isDev = typeof __DEV__ === 'boolean' && __DEV__;
process.env['NODE_ENV'] = isDev ? 'development' : 'production'; process.env.NODE_ENV = isDev ? 'development' : 'production';
if (typeof localStorage !== 'undefined') { if (typeof localStorage !== 'undefined') {
localStorage.debug = isDev ? '*' : ''; localStorage.debug = isDev ? '*' : '';
} }

View file

@ -397,7 +397,7 @@ describe('BlueWallet UI Tests', () => {
} }
} }
let transaction = bitcoin.Transaction.fromHex(txhex); const transaction = bitcoin.Transaction.fromHex(txhex);
assert.ok(transaction.ins.length === 1 || transaction.ins.length === 2); // depending on current fees gona use either 1 or 2 inputs assert.ok(transaction.ins.length === 1 || transaction.ins.length === 2); // depending on current fees gona use either 1 or 2 inputs
assert.strictEqual(transaction.outs.length, 2); assert.strictEqual(transaction.outs.length, 2);
assert.strictEqual(bitcoin.address.fromOutputScript(transaction.outs[0].script), 'bc1q063ctu6jhe5k4v8ka99qac8rcm2tzjjnuktyrl'); // to address assert.strictEqual(bitcoin.address.fromOutputScript(transaction.outs[0].script), 'bc1q063ctu6jhe5k4v8ka99qac8rcm2tzjjnuktyrl'); // to address
@ -488,8 +488,5 @@ async function helperImportWallet(importText, expectedWalletLabel, expectedBalan
} }
function hashIt(s) { function hashIt(s) {
return createHash('sha256') return createHash('sha256').update(s).digest().toString('hex');
.update(s)
.digest()
.toString('hex');
} }

View file

@ -4,12 +4,12 @@ import TestRenderer from 'react-test-renderer';
import Settings from '../../screen/settings/settings'; import Settings from '../../screen/settings/settings';
import Selftest from '../../screen/selftest'; import Selftest from '../../screen/selftest';
import { BlueHeader } from '../../BlueComponents'; import { BlueHeader } from '../../BlueComponents';
let assert = require('assert'); const assert = require('assert');
jest.mock('react-native-qrcode-svg', () => 'Video'); jest.mock('react-native-qrcode-svg', () => 'Video');
jest.useFakeTimers(); jest.useFakeTimers();
jest.mock('amplitude-js', () => ({ jest.mock('amplitude-js', () => ({
getInstance: function() { getInstance: function () {
return { return {
init: jest.fn(), init: jest.fn(),
logEvent: jest.fn(), logEvent: jest.fn(),
@ -35,7 +35,7 @@ it('Selftest work', () => {
// console.log((root.findAllByType('Text')[0].props)); // console.log((root.findAllByType('Text')[0].props));
let okFound = false; let okFound = false;
let allTests = []; const allTests = [];
for (var v of root.findAllByType('Text')) { for (var v of root.findAllByType('Text')) {
let text = v.props.children; let text = v.props.children;
if (text.join) { if (text.join) {

File diff suppressed because one or more lines are too long

View file

@ -2,32 +2,32 @@
import { AppStorage } from '../../class'; import { AppStorage } from '../../class';
import { FiatUnit } from '../../models/fiatUnit'; import { FiatUnit } from '../../models/fiatUnit';
import AsyncStorage from '@react-native-community/async-storage'; import AsyncStorage from '@react-native-community/async-storage';
let assert = require('assert'); const assert = require('assert');
jest.useFakeTimers(); jest.useFakeTimers();
describe('currency', () => { describe('currency', () => {
it('fetches exchange rate and saves to AsyncStorage', async () => { it('fetches exchange rate and saves to AsyncStorage', async () => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 15000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 15000;
let currency = require('../../currency'); const currency = require('../../currency');
await currency.startUpdater(); await currency.startUpdater();
let cur = await AsyncStorage.getItem(AppStorage.EXCHANGE_RATES); let cur = await AsyncStorage.getItem(AppStorage.EXCHANGE_RATES);
cur = JSON.parse(cur); cur = JSON.parse(cur);
assert.ok(Number.isInteger(cur[currency.STRUCT.LAST_UPDATED])); assert.ok(Number.isInteger(cur[currency.STRUCT.LAST_UPDATED]));
assert.ok(cur[currency.STRUCT.LAST_UPDATED] > 0); assert.ok(cur[currency.STRUCT.LAST_UPDATED] > 0);
assert.ok(cur['BTC_USD'] > 0); assert.ok(cur.BTC_USD > 0);
// now, setting other currency as default // now, setting other currency as default
await AsyncStorage.setItem(AppStorage.PREFERRED_CURRENCY, JSON.stringify(FiatUnit.JPY)); await AsyncStorage.setItem(AppStorage.PREFERRED_CURRENCY, JSON.stringify(FiatUnit.JPY));
await currency.startUpdater(); await currency.startUpdater();
cur = JSON.parse(await AsyncStorage.getItem(AppStorage.EXCHANGE_RATES)); cur = JSON.parse(await AsyncStorage.getItem(AppStorage.EXCHANGE_RATES));
assert.ok(cur['BTC_JPY'] > 0); assert.ok(cur.BTC_JPY > 0);
// now setting with a proper setter // now setting with a proper setter
await currency.setPrefferedCurrency(FiatUnit.EUR); await currency.setPrefferedCurrency(FiatUnit.EUR);
await currency.startUpdater(); await currency.startUpdater();
let preferred = await currency.getPreferredCurrency(); const preferred = await currency.getPreferredCurrency();
assert.strictEqual(preferred.endPointKey, 'EUR'); assert.strictEqual(preferred.endPointKey, 'EUR');
cur = JSON.parse(await AsyncStorage.getItem(AppStorage.EXCHANGE_RATES)); cur = JSON.parse(await AsyncStorage.getItem(AppStorage.EXCHANGE_RATES));
assert.ok(cur['BTC_EUR'] > 0); assert.ok(cur.BTC_EUR > 0);
}); });
}); });

View file

@ -3,7 +3,7 @@ const bitcoin = require('bitcoinjs-lib');
global.net = require('net'); global.net = require('net');
global.tls = require('tls'); global.tls = require('tls');
let assert = require('assert'); const assert = require('assert');
jasmine.DEFAULT_TIMEOUT_INTERVAL = 150 * 1000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 150 * 1000;
const hardcodedPeers = [ const hardcodedPeers = [
@ -19,8 +19,8 @@ describe('ElectrumClient', () => {
it('can connect and query', async () => { it('can connect and query', async () => {
const ElectrumClient = require('electrum-client'); const ElectrumClient = require('electrum-client');
for (let peer of hardcodedPeers) { for (const peer of hardcodedPeers) {
let mainClient = new ElectrumClient(peer.ssl || peer.tcp, peer.host, peer.ssl ? 'tls' : 'tcp'); const mainClient = new ElectrumClient(peer.ssl || peer.tcp, peer.host, peer.ssl ? 'tls' : 'tcp');
try { try {
await mainClient.connect(); await mainClient.connect();
@ -35,9 +35,9 @@ describe('ElectrumClient', () => {
let script = bitcoin.address.toOutputScript(addr4elect); let script = bitcoin.address.toOutputScript(addr4elect);
let hash = bitcoin.crypto.sha256(script); let hash = bitcoin.crypto.sha256(script);
let reversedHash = Buffer.from(hash.reverse()); let reversedHash = Buffer.from(hash.reverse());
let start = +new Date(); const start = +new Date();
let balance = await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex')); let balance = await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex'));
let end = +new Date(); const end = +new Date();
end - start > 1000 && console.warn(peer.host, 'took', (end - start) / 1000, 'seconds to fetch balance'); end - start > 1000 && console.warn(peer.host, 'took', (end - start) / 1000, 'seconds to fetch balance');
assert.ok(balance.confirmed > 0); assert.ok(balance.confirmed > 0);

View file

@ -32,10 +32,10 @@ it('can create escrow address', () => {
assert.strictEqual(address, '391ygT71qeF7vbYjxsUZPzH6oDc7Rv4vTs'); assert.strictEqual(address, '391ygT71qeF7vbYjxsUZPzH6oDc7Rv4vTs');
let signedByServerReleaseTransaction = const signedByServerReleaseTransaction =
'01000000000101356493a6b93bf17e66d7ec12f1a54e279da17f669f41bf11405a6f2617e1022501000000232200208ec72df31adaa132e40a5f5033589c0e18b67a64cdc65e9c75027fe1efd10f4cffffffff02227e010000000000160014b1c61a73a529c315a1f2b87df12c7948d86ba10c26020000000000001976a914d0b77eb1502c81c4093da9aa6eccfdf560cdd6b288ac040047304402205a447563db8e74177a1fbcdcfe7b7b22556c39d68c17ffe0a4a02609d78c83130220772fbf3261b6031a915eca7e441092df3fe6e4c7d4f389c4921c1f18661c20f401460000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000069522103141024b18929bfec5b567c12b1693d4ae02783873e2e3aa444f0d6950cb97dee210208137b6cb23cef02c0529948a2ed12fbeed0813cce555de073319f56e215ee1b21035ed5825258d4f1685df804f21296b9957cd319cf5949ace92fa5767eb7a946f253ae00000000'; '01000000000101356493a6b93bf17e66d7ec12f1a54e279da17f669f41bf11405a6f2617e1022501000000232200208ec72df31adaa132e40a5f5033589c0e18b67a64cdc65e9c75027fe1efd10f4cffffffff02227e010000000000160014b1c61a73a529c315a1f2b87df12c7948d86ba10c26020000000000001976a914d0b77eb1502c81c4093da9aa6eccfdf560cdd6b288ac040047304402205a447563db8e74177a1fbcdcfe7b7b22556c39d68c17ffe0a4a02609d78c83130220772fbf3261b6031a915eca7e441092df3fe6e4c7d4f389c4921c1f18661c20f401460000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000069522103141024b18929bfec5b567c12b1693d4ae02783873e2e3aa444f0d6950cb97dee210208137b6cb23cef02c0529948a2ed12fbeed0813cce555de073319f56e215ee1b21035ed5825258d4f1685df804f21296b9957cd319cf5949ace92fa5767eb7a946f253ae00000000';
let txDecoded = bitcoin.Transaction.fromHex(signedByServerReleaseTransaction); const txDecoded = bitcoin.Transaction.fromHex(signedByServerReleaseTransaction);
// console.warn(txDecoded.ins[0].witness); // console.warn(txDecoded.ins[0].witness);
// we always expect only one input: // we always expect only one input:
@ -50,9 +50,9 @@ it('can create escrow address', () => {
witnessScript: p2shP2wshP2ms.redeem.redeem.output, witnessScript: p2shP2wshP2ms.redeem.redeem.output,
}); });
for (let out of txDecoded.outs) { for (const out of txDecoded.outs) {
let scripthex = out.script.toString('hex'); const scripthex = out.script.toString('hex');
let address = const address =
LegacyWallet.scriptPubKeyToAddress(scripthex) || LegacyWallet.scriptPubKeyToAddress(scripthex) ||
SegwitP2SHWallet.scriptPubKeyToAddress(scripthex) || SegwitP2SHWallet.scriptPubKeyToAddress(scripthex) ||
SegwitBech32Wallet.scriptPubKeyToAddress(scripthex); SegwitBech32Wallet.scriptPubKeyToAddress(scripthex);
@ -71,10 +71,10 @@ it('can create escrow address', () => {
// console.log(tx.toHex()); // console.log(tx.toHex());
}); });
describe('HodlHodl API', function() { describe('HodlHodl API', function () {
it('can fetch countries & and own country code', async () => { it('can fetch countries & and own country code', async () => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000;
let Hodl = new HodlHodlApi(); const Hodl = new HodlHodlApi();
const countries = await Hodl.getCountries(); const countries = await Hodl.getCountries();
assert.ok(countries[0]); assert.ok(countries[0]);
assert.ok(countries[0].code); assert.ok(countries[0].code);
@ -83,12 +83,12 @@ describe('HodlHodl API', function() {
assert.ok(countries[0].currency_code); assert.ok(countries[0].currency_code);
assert.ok(countries[0].currency_name); assert.ok(countries[0].currency_name);
let countryCode = await Hodl.getMyCountryCode(); const countryCode = await Hodl.getMyCountryCode();
assert.strictEqual(countryCode.length, 2); assert.strictEqual(countryCode.length, 2);
}); });
it('can get offers', async () => { it('can get offers', async () => {
let Hodl = new HodlHodlApi(); const Hodl = new HodlHodlApi();
const offers = await Hodl.getOffers( const offers = await Hodl.getOffers(
{ {
[HodlHodlApi.PAGINATION_LIMIT]: 10, [HodlHodlApi.PAGINATION_LIMIT]: 10,
@ -116,7 +116,7 @@ describe('HodlHodl API', function() {
}); });
it('can get payment methods', async () => { it('can get payment methods', async () => {
let Hodl = new HodlHodlApi(); const Hodl = new HodlHodlApi();
const methods = await Hodl.getPaymentMethods(HodlHodlApi.FILTERS_COUNTRY_VALUE_GLOBAL); const methods = await Hodl.getPaymentMethods(HodlHodlApi.FILTERS_COUNTRY_VALUE_GLOBAL);
assert.ok(methods[0]); assert.ok(methods[0]);
assert.ok(methods[0].id); assert.ok(methods[0].id);
@ -125,7 +125,7 @@ describe('HodlHodl API', function() {
}); });
it('cat get currencies', async () => { it('cat get currencies', async () => {
let Hodl = new HodlHodlApi(); const Hodl = new HodlHodlApi();
const currencies = await Hodl.getCurrencies(); const currencies = await Hodl.getCurrencies();
assert.ok(currencies[0]); assert.ok(currencies[0]);
assert.ok(currencies[0].code); assert.ok(currencies[0].code);

View file

@ -1,10 +1,10 @@
/* global it, describe, jasmine, afterAll, beforeAll */ /* global it, describe, jasmine, afterAll, beforeAll */
import { HDSegwitBech32Wallet, SegwitP2SHWallet, HDSegwitBech32Transaction, SegwitBech32Wallet } from '../../class'; import { HDSegwitBech32Wallet, SegwitP2SHWallet, HDSegwitBech32Transaction, SegwitBech32Wallet } from '../../class';
const bitcoin = require('bitcoinjs-lib'); const bitcoin = require('bitcoinjs-lib');
let assert = require('assert'); const assert = require('assert');
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js
let BlueElectrum = require('../../BlueElectrum'); const BlueElectrum = require('../../BlueElectrum');
jasmine.DEFAULT_TIMEOUT_INTERVAL = 150 * 1000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 150 * 1000;
afterAll(async () => { afterAll(async () => {
@ -29,7 +29,7 @@ async function _getHdWallet() {
} }
describe('HDSegwitBech32Transaction', () => { describe('HDSegwitBech32Transaction', () => {
it('can decode & check sequence', async function() { it('can decode & check sequence', async function () {
let T = new HDSegwitBech32Transaction(null, 'e9ef58baf4cff3ad55913a360c2fa1fd124309c59dcd720cdb172ce46582097b'); let T = new HDSegwitBech32Transaction(null, 'e9ef58baf4cff3ad55913a360c2fa1fd124309c59dcd720cdb172ce46582097b');
assert.strictEqual(await T.getMaxUsedSequence(), 0xffffffff); assert.strictEqual(await T.getMaxUsedSequence(), 0xffffffff);
assert.strictEqual(await T.isSequenceReplaceable(), false); assert.strictEqual(await T.isSequenceReplaceable(), false);
@ -44,13 +44,13 @@ describe('HDSegwitBech32Transaction', () => {
assert.ok((await T.getRemoteConfirmationsNum()) >= 292); assert.ok((await T.getRemoteConfirmationsNum()) >= 292);
}); });
it('can tell if its our transaction', async function() { it('can tell if its our transaction', async function () {
if (!process.env.HD_MNEMONIC_BIP84) { if (!process.env.HD_MNEMONIC_BIP84) {
console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped'); console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped');
return; return;
} }
let hd = await _getHdWallet(); const hd = await _getHdWallet();
let tt = new HDSegwitBech32Transaction(null, '881c54edd95cbdd1583d6b9148eb35128a47b64a2e67a5368a649d6be960f08e', hd); let tt = new HDSegwitBech32Transaction(null, '881c54edd95cbdd1583d6b9148eb35128a47b64a2e67a5368a649d6be960f08e', hd);
@ -61,17 +61,17 @@ describe('HDSegwitBech32Transaction', () => {
assert.ok(!(await tt.isOurTransaction())); assert.ok(!(await tt.isOurTransaction()));
}); });
it('can tell tx info', async function() { it('can tell tx info', async function () {
if (!process.env.HD_MNEMONIC_BIP84) { if (!process.env.HD_MNEMONIC_BIP84) {
console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped'); console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped');
return; return;
} }
let hd = await _getHdWallet(); const hd = await _getHdWallet();
let tt = new HDSegwitBech32Transaction(null, '881c54edd95cbdd1583d6b9148eb35128a47b64a2e67a5368a649d6be960f08e', hd); const tt = new HDSegwitBech32Transaction(null, '881c54edd95cbdd1583d6b9148eb35128a47b64a2e67a5368a649d6be960f08e', hd);
let { fee, feeRate, targets, changeAmount, utxos } = await tt.getInfo(); const { fee, feeRate, targets, changeAmount, utxos } = await tt.getInfo();
assert.strictEqual(fee, 4464); assert.strictEqual(fee, 4464);
assert.strictEqual(changeAmount, 103686); assert.strictEqual(changeAmount, 103686);
assert.strictEqual(feeRate, 12); assert.strictEqual(feeRate, 12);
@ -97,74 +97,74 @@ describe('HDSegwitBech32Transaction', () => {
); );
}); });
it('can do RBF - cancel tx', async function() { it('can do RBF - cancel tx', async function () {
if (!process.env.HD_MNEMONIC_BIP84) { if (!process.env.HD_MNEMONIC_BIP84) {
console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped'); console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped');
return; return;
} }
let hd = await _getHdWallet(); const hd = await _getHdWallet();
let tt = new HDSegwitBech32Transaction(null, '881c54edd95cbdd1583d6b9148eb35128a47b64a2e67a5368a649d6be960f08e', hd); const tt = new HDSegwitBech32Transaction(null, '881c54edd95cbdd1583d6b9148eb35128a47b64a2e67a5368a649d6be960f08e', hd);
assert.strictEqual(await tt.canCancelTx(), true); assert.strictEqual(await tt.canCancelTx(), true);
let { tx } = await tt.createRBFcancelTx(15); const { tx } = await tt.createRBFcancelTx(15);
let createdTx = bitcoin.Transaction.fromHex(tx.toHex()); const createdTx = bitcoin.Transaction.fromHex(tx.toHex());
assert.strictEqual(createdTx.ins.length, 2); assert.strictEqual(createdTx.ins.length, 2);
assert.strictEqual(createdTx.outs.length, 1); assert.strictEqual(createdTx.outs.length, 1);
let addr = SegwitBech32Wallet.scriptPubKeyToAddress(createdTx.outs[0].script); const addr = SegwitBech32Wallet.scriptPubKeyToAddress(createdTx.outs[0].script);
assert.ok(hd.weOwnAddress(addr)); assert.ok(hd.weOwnAddress(addr));
let actualFeerate = (108150 + 200000 - createdTx.outs[0].value) / (tx.toHex().length / 2); const actualFeerate = (108150 + 200000 - createdTx.outs[0].value) / (tx.toHex().length / 2);
assert.strictEqual(Math.round(actualFeerate), 15); assert.strictEqual(Math.round(actualFeerate), 15);
let tt2 = new HDSegwitBech32Transaction(tx.toHex(), null, hd); const tt2 = new HDSegwitBech32Transaction(tx.toHex(), null, hd);
assert.strictEqual(await tt2.canCancelTx(), false); // newly created cancel tx is not cancellable anymore assert.strictEqual(await tt2.canCancelTx(), false); // newly created cancel tx is not cancellable anymore
}); });
it('can do RBF - bumpfees tx', async function() { it('can do RBF - bumpfees tx', async function () {
if (!process.env.HD_MNEMONIC_BIP84) { if (!process.env.HD_MNEMONIC_BIP84) {
console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped'); console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped');
return; return;
} }
let hd = await _getHdWallet(); const hd = await _getHdWallet();
let tt = new HDSegwitBech32Transaction(null, '881c54edd95cbdd1583d6b9148eb35128a47b64a2e67a5368a649d6be960f08e', hd); const tt = new HDSegwitBech32Transaction(null, '881c54edd95cbdd1583d6b9148eb35128a47b64a2e67a5368a649d6be960f08e', hd);
assert.strictEqual(await tt.canCancelTx(), true); assert.strictEqual(await tt.canCancelTx(), true);
let { tx } = await tt.createRBFbumpFee(17); const { tx } = await tt.createRBFbumpFee(17);
let createdTx = bitcoin.Transaction.fromHex(tx.toHex()); const createdTx = bitcoin.Transaction.fromHex(tx.toHex());
assert.strictEqual(createdTx.ins.length, 2); assert.strictEqual(createdTx.ins.length, 2);
assert.strictEqual(createdTx.outs.length, 2); assert.strictEqual(createdTx.outs.length, 2);
let addr0 = SegwitP2SHWallet.scriptPubKeyToAddress(createdTx.outs[0].script); const addr0 = SegwitP2SHWallet.scriptPubKeyToAddress(createdTx.outs[0].script);
assert.ok(!hd.weOwnAddress(addr0)); assert.ok(!hd.weOwnAddress(addr0));
assert.strictEqual(addr0, '3NLnALo49CFEF4tCRhCvz45ySSfz3UktZC'); // dest address assert.strictEqual(addr0, '3NLnALo49CFEF4tCRhCvz45ySSfz3UktZC'); // dest address
let addr1 = SegwitBech32Wallet.scriptPubKeyToAddress(createdTx.outs[1].script); const addr1 = SegwitBech32Wallet.scriptPubKeyToAddress(createdTx.outs[1].script);
assert.ok(hd.weOwnAddress(addr1)); assert.ok(hd.weOwnAddress(addr1));
let actualFeerate = (108150 + 200000 - (createdTx.outs[0].value + createdTx.outs[1].value)) / (tx.toHex().length / 2); const actualFeerate = (108150 + 200000 - (createdTx.outs[0].value + createdTx.outs[1].value)) / (tx.toHex().length / 2);
assert.strictEqual(Math.round(actualFeerate), 17); assert.strictEqual(Math.round(actualFeerate), 17);
let tt2 = new HDSegwitBech32Transaction(tx.toHex(), null, hd); const tt2 = new HDSegwitBech32Transaction(tx.toHex(), null, hd);
assert.strictEqual(await tt2.canCancelTx(), true); // new tx is still cancellable since we only bumped fees assert.strictEqual(await tt2.canCancelTx(), true); // new tx is still cancellable since we only bumped fees
}); });
it('can do CPFP - bump fees', async function() { it('can do CPFP - bump fees', async function () {
if (!process.env.HD_MNEMONIC_BIP84) { if (!process.env.HD_MNEMONIC_BIP84) {
console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped'); console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped');
return; return;
} }
let hd = await _getHdWallet(); const hd = await _getHdWallet();
let tt = new HDSegwitBech32Transaction(null, '2ec8a1d0686dcccffc102ba5453a28d99c8a1e5061c27b41f5c0a23b0b27e75f', hd); const tt = new HDSegwitBech32Transaction(null, '2ec8a1d0686dcccffc102ba5453a28d99c8a1e5061c27b41f5c0a23b0b27e75f', hd);
assert.ok(await tt.isToUsTransaction()); assert.ok(await tt.isToUsTransaction());
let { unconfirmedUtxos, fee: oldFee } = await tt.getInfo(); const { unconfirmedUtxos, fee: oldFee } = await tt.getInfo();
assert.strictEqual( assert.strictEqual(
JSON.stringify(unconfirmedUtxos), JSON.stringify(unconfirmedUtxos),
@ -178,8 +178,8 @@ describe('HDSegwitBech32Transaction', () => {
]), ]),
); );
let { tx, fee } = await tt.createCPFPbumpFee(20); const { tx, fee } = await tt.createCPFPbumpFee(20);
let avgFeeRate = (oldFee + fee) / (tt._txhex.length / 2 + tx.toHex().length / 2); const avgFeeRate = (oldFee + fee) / (tt._txhex.length / 2 + tx.toHex().length / 2);
assert.ok(Math.round(avgFeeRate) >= 20); assert.ok(Math.round(avgFeeRate) >= 20);
}); });
}); });

View file

@ -1,9 +1,9 @@
/* global it, describe, jasmine, afterAll, beforeAll */ /* global it, describe, jasmine, afterAll, beforeAll */
import { HDSegwitBech32Wallet } from '../../class'; import { HDSegwitBech32Wallet } from '../../class';
let assert = require('assert'); const assert = require('assert');
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js
let BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP const BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP
jasmine.DEFAULT_TIMEOUT_INTERVAL = 300 * 1000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 300 * 1000;
@ -19,7 +19,7 @@ beforeAll(async () => {
}); });
describe('Bech32 Segwit HD (BIP84)', () => { describe('Bech32 Segwit HD (BIP84)', () => {
it('can fetch balance, transactions & utxo', async function() { it('can fetch balance, transactions & utxo', async function () {
if (!process.env.HD_MNEMONIC) { if (!process.env.HD_MNEMONIC) {
console.error('process.env.HD_MNEMONIC not set, skipped'); console.error('process.env.HD_MNEMONIC not set, skipped');
return; return;
@ -58,7 +58,7 @@ describe('Bech32 Segwit HD (BIP84)', () => {
assert.strictEqual(hd.timeToRefreshBalance(), false); assert.strictEqual(hd.timeToRefreshBalance(), false);
assert.strictEqual(hd.getTransactions().length, 4); assert.strictEqual(hd.getTransactions().length, 4);
for (let tx of hd.getTransactions()) { for (const tx of hd.getTransactions()) {
assert.ok(tx.hash); assert.ok(tx.hash);
assert.strictEqual(tx.value, 50000); assert.strictEqual(tx.value, 50000);
assert.ok(tx.received); assert.ok(tx.received);
@ -67,7 +67,7 @@ describe('Bech32 Segwit HD (BIP84)', () => {
// now fetch UTXO // now fetch UTXO
await hd.fetchUtxo(); await hd.fetchUtxo();
let utxo = hd.getUtxo(); const utxo = hd.getUtxo();
assert.strictEqual(utxo.length, 4); assert.strictEqual(utxo.length, 4);
assert.ok(utxo[0].txId); assert.ok(utxo[0].txId);
assert.ok(utxo[0].vout === 0 || utxo[0].vout === 1); assert.ok(utxo[0].vout === 0 || utxo[0].vout === 1);
@ -90,15 +90,15 @@ describe('Bech32 Segwit HD (BIP84)', () => {
console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped'); console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped');
return; return;
} }
let hd = new HDSegwitBech32Wallet(); const hd = new HDSegwitBech32Wallet();
hd.setSecret(process.env.HD_MNEMONIC_BIP84); hd.setSecret(process.env.HD_MNEMONIC_BIP84);
assert.ok(hd.validateMnemonic()); assert.ok(hd.validateMnemonic());
await hd.fetchBalance(); await hd.fetchBalance();
let oldBalance = hd.getBalance(); const oldBalance = hd.getBalance();
await hd.fetchTransactions(); await hd.fetchTransactions();
let oldTransactions = hd.getTransactions(); const oldTransactions = hd.getTransactions();
// now, mess with internal state, make it 'obsolete' // now, mess with internal state, make it 'obsolete'
@ -125,7 +125,7 @@ describe('Bech32 Segwit HD (BIP84)', () => {
console.error('process.env.FAULTY_ZPUB not set, skipped'); console.error('process.env.FAULTY_ZPUB not set, skipped');
return; return;
} }
let hd = new HDSegwitBech32Wallet(); const hd = new HDSegwitBech32Wallet();
hd._xpub = process.env.FAULTY_ZPUB; hd._xpub = process.env.FAULTY_ZPUB;
await hd.fetchBalance(); await hd.fetchBalance();
@ -139,7 +139,7 @@ describe('Bech32 Segwit HD (BIP84)', () => {
console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped'); console.error('process.env.HD_MNEMONIC_BIP84 not set, skipped');
return; return;
} }
let hd = new HDSegwitBech32Wallet(); const hd = new HDSegwitBech32Wallet();
hd.setSecret(process.env.HD_MNEMONIC_BIP84); hd.setSecret(process.env.HD_MNEMONIC_BIP84);
assert.ok(hd.validateMnemonic()); assert.ok(hd.validateMnemonic());
assert.strictEqual( assert.strictEqual(
@ -173,7 +173,7 @@ describe('Bech32 Segwit HD (BIP84)', () => {
end - start > 2000 && console.warn('warm fetchTransactions took', (end - start) / 1000, 'sec'); end - start > 2000 && console.warn('warm fetchTransactions took', (end - start) / 1000, 'sec');
let txFound = 0; let txFound = 0;
for (let tx of hd.getTransactions()) { for (const tx of hd.getTransactions()) {
if (tx.hash === 'e9ef58baf4cff3ad55913a360c2fa1fd124309c59dcd720cdb172ce46582097b') { if (tx.hash === 'e9ef58baf4cff3ad55913a360c2fa1fd124309c59dcd720cdb172ce46582097b') {
assert.strictEqual(tx.value, -129545); assert.strictEqual(tx.value, -129545);
assert.strictEqual(tx.inputs[0].addresses[0], 'bc1qffcl35r05wyf06meu3dalfevawx559n0ufrxcw'); assert.strictEqual(tx.inputs[0].addresses[0], 'bc1qffcl35r05wyf06meu3dalfevawx559n0ufrxcw');
@ -201,17 +201,17 @@ describe('Bech32 Segwit HD (BIP84)', () => {
await hd.fetchUtxo(); await hd.fetchUtxo();
assert.strictEqual(hd.getUtxo().length, 2); assert.strictEqual(hd.getUtxo().length, 2);
assert.strictEqual(hd.getDerivedUtxoFromOurTransaction().length, 2); assert.strictEqual(hd.getDerivedUtxoFromOurTransaction().length, 2);
let u1 = hd.getUtxo()[0]; const u1 = hd.getUtxo()[0];
let u2 = hd.getDerivedUtxoFromOurTransaction()[0]; const u2 = hd.getDerivedUtxoFromOurTransaction()[0];
delete u1.confirmations; delete u1.confirmations;
delete u2.confirmations; delete u2.confirmations;
delete u1.height; delete u1.height;
delete u2.height; delete u2.height;
assert.deepStrictEqual(u1, u2); assert.deepStrictEqual(u1, u2);
let changeAddress = await hd.getChangeAddressAsync(); const changeAddress = await hd.getChangeAddressAsync();
assert.ok(changeAddress && changeAddress.startsWith('bc1')); assert.ok(changeAddress && changeAddress.startsWith('bc1'));
let { tx, inputs, outputs, fee } = hd.createTransaction( const { tx, inputs, outputs, fee } = hd.createTransaction(
hd.getUtxo(), hd.getUtxo(),
[{ address: 'bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu', value: 51000 }], [{ address: 'bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu', value: 51000 }],
13, 13,
@ -221,13 +221,13 @@ describe('Bech32 Segwit HD (BIP84)', () => {
assert.strictEqual(Math.round(fee / tx.byteLength()), 13); assert.strictEqual(Math.round(fee / tx.byteLength()), 13);
let totalInput = 0; let totalInput = 0;
for (let inp of inputs) { for (const inp of inputs) {
totalInput += inp.value; totalInput += inp.value;
} }
assert.strictEqual(outputs.length, 2); assert.strictEqual(outputs.length, 2);
let totalOutput = 0; let totalOutput = 0;
for (let outp of outputs) { for (const outp of outputs) {
totalOutput += outp.value; totalOutput += outp.value;
} }

View file

@ -1,10 +1,10 @@
/* global it, jasmine, afterAll, beforeAll */ /* global it, jasmine, afterAll, beforeAll */
import { HDSegwitP2SHWallet } from '../../class'; import { HDSegwitP2SHWallet } from '../../class';
const bitcoin = require('bitcoinjs-lib'); const bitcoin = require('bitcoinjs-lib');
let assert = require('assert'); const assert = require('assert');
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js
let BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP const BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP
jasmine.DEFAULT_TIMEOUT_INTERVAL = 300 * 1000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 300 * 1000;
afterAll(() => { afterAll(() => {
@ -23,8 +23,8 @@ beforeAll(async () => {
} }
}); });
it('HD (BIP49) can work with a gap', async function() { it('HD (BIP49) can work with a gap', async function () {
let hd = new HDSegwitP2SHWallet(); const hd = new HDSegwitP2SHWallet();
hd._xpub = 'ypub6XRzrn3HB1tjhhvrHbk1vnXCecZEdXohGzCk3GXwwbDoJ3VBzZ34jNGWbC6WrS7idXrYjjXEzcPDX5VqnHEnuNf5VAXgLfSaytMkJ2rwVqy'; // has gap hd._xpub = 'ypub6XRzrn3HB1tjhhvrHbk1vnXCecZEdXohGzCk3GXwwbDoJ3VBzZ34jNGWbC6WrS7idXrYjjXEzcPDX5VqnHEnuNf5VAXgLfSaytMkJ2rwVqy'; // has gap
await hd.fetchBalance(); await hd.fetchBalance();
@ -39,8 +39,8 @@ it('HD (BIP49) can work with a gap', async function() {
assert.ok(hd.getTransactions().length >= 3); assert.ok(hd.getTransactions().length >= 3);
}); });
it('Segwit HD (BIP49) can fetch more data if pointers to last_used_addr are lagging behind', async function() { it('Segwit HD (BIP49) can fetch more data if pointers to last_used_addr are lagging behind', async function () {
let hd = new HDSegwitP2SHWallet(); const hd = new HDSegwitP2SHWallet();
hd._xpub = 'ypub6WZ2c7YJ1SQ1rBYftwMqwV9bBmybXzETFxWmkzMz25bCf6FkDdXjNgR7zRW8JGSnoddNdUH7ZQS7JeQAddxdGpwgPskcsXFcvSn1JdGVcPQ'; hd._xpub = 'ypub6WZ2c7YJ1SQ1rBYftwMqwV9bBmybXzETFxWmkzMz25bCf6FkDdXjNgR7zRW8JGSnoddNdUH7ZQS7JeQAddxdGpwgPskcsXFcvSn1JdGVcPQ';
hd.next_free_change_address_index = 40; hd.next_free_change_address_index = 40;
hd.next_free_address_index = 50; hd.next_free_address_index = 50;
@ -54,7 +54,7 @@ it('HD (BIP49) can create TX', async () => {
console.error('process.env.HD_MNEMONIC_BIP49 not set, skipped'); console.error('process.env.HD_MNEMONIC_BIP49 not set, skipped');
return; return;
} }
let hd = new HDSegwitP2SHWallet(); const hd = new HDSegwitP2SHWallet();
hd.setSecret(process.env.HD_MNEMONIC_BIP49); hd.setSecret(process.env.HD_MNEMONIC_BIP49);
assert.ok(hd.validateMnemonic()); assert.ok(hd.validateMnemonic());
@ -83,7 +83,7 @@ it('HD (BIP49) can create TX', async () => {
assert.strictEqual(tx.outs[0].value, 500); assert.strictEqual(tx.outs[0].value, 500);
assert.strictEqual(tx.outs[1].value, 25275); assert.strictEqual(tx.outs[1].value, 25275);
let toAddress = bitcoin.address.fromOutputScript(tx.outs[0].script); let toAddress = bitcoin.address.fromOutputScript(tx.outs[0].script);
let changeAddress = bitcoin.address.fromOutputScript(tx.outs[1].script); const changeAddress = bitcoin.address.fromOutputScript(tx.outs[1].script);
assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress); assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress);
assert.strictEqual(hd._getInternalAddressByIndex(hd.next_free_change_address_index), changeAddress); assert.strictEqual(hd._getInternalAddressByIndex(hd.next_free_change_address_index), changeAddress);
@ -147,18 +147,18 @@ it('HD (BIP49) can create TX', async () => {
assert.ok(tx.outs[0].value > 77000); assert.ok(tx.outs[0].value > 77000);
}); });
it('Segwit HD (BIP49) can fetch balance with many used addresses in hierarchy', async function() { it('Segwit HD (BIP49) can fetch balance with many used addresses in hierarchy', async function () {
if (!process.env.HD_MNEMONIC_BIP49_MANY_TX) { if (!process.env.HD_MNEMONIC_BIP49_MANY_TX) {
console.error('process.env.HD_MNEMONIC_BIP49_MANY_TX not set, skipped'); console.error('process.env.HD_MNEMONIC_BIP49_MANY_TX not set, skipped');
return; return;
} }
let hd = new HDSegwitP2SHWallet(); const hd = new HDSegwitP2SHWallet();
hd.setSecret(process.env.HD_MNEMONIC_BIP49_MANY_TX); hd.setSecret(process.env.HD_MNEMONIC_BIP49_MANY_TX);
assert.ok(hd.validateMnemonic()); assert.ok(hd.validateMnemonic());
let start = +new Date(); const start = +new Date();
await hd.fetchBalance(); await hd.fetchBalance();
let end = +new Date(); const end = +new Date();
const took = (end - start) / 1000; const took = (end - start) / 1000;
took > 15 && console.warn('took', took, "sec to fetch huge HD wallet's balance"); took > 15 && console.warn('took', took, "sec to fetch huge HD wallet's balance");
assert.strictEqual(hd.getBalance(), 51432); assert.strictEqual(hd.getBalance(), 51432);

View file

@ -1,9 +1,9 @@
/* global describe, it, jasmine, afterAll, beforeAll */ /* global describe, it, jasmine, afterAll, beforeAll */
import { LegacyWallet, SegwitP2SHWallet, SegwitBech32Wallet } from '../../class'; import { LegacyWallet, SegwitP2SHWallet, SegwitBech32Wallet } from '../../class';
let assert = require('assert'); const assert = require('assert');
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js
let BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP const BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
@ -18,19 +18,19 @@ beforeAll(async () => {
await BlueElectrum.waitTillConnected(); await BlueElectrum.waitTillConnected();
}); });
describe('LegacyWallet', function() { describe('LegacyWallet', function () {
it('can serialize and unserialize correctly', () => { it('can serialize and unserialize correctly', () => {
let a = new LegacyWallet(); const a = new LegacyWallet();
a.setLabel('my1'); a.setLabel('my1');
let key = JSON.stringify(a); const key = JSON.stringify(a);
let b = LegacyWallet.fromJson(key); const b = LegacyWallet.fromJson(key);
assert.strictEqual(b.type, LegacyWallet.type); assert.strictEqual(b.type, LegacyWallet.type);
assert.strictEqual(key, JSON.stringify(b)); assert.strictEqual(key, JSON.stringify(b));
}); });
it('can validate addresses', () => { it('can validate addresses', () => {
let w = new LegacyWallet(); const w = new LegacyWallet();
assert.ok(w.isAddressValid('12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG')); assert.ok(w.isAddressValid('12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG'));
assert.ok(!w.isAddressValid('12eQ9m4sgAwTSQoNXkRABKhCXCsjm2j')); assert.ok(!w.isAddressValid('12eQ9m4sgAwTSQoNXkRABKhCXCsjm2j'));
assert.ok(w.isAddressValid('3BDsBDxDimYgNZzsqszNZobqQq3yeUoJf2')); assert.ok(w.isAddressValid('3BDsBDxDimYgNZzsqszNZobqQq3yeUoJf2'));
@ -41,7 +41,7 @@ describe('LegacyWallet', function() {
}); });
it('can fetch balance', async () => { it('can fetch balance', async () => {
let w = new LegacyWallet(); const w = new LegacyWallet();
w._address = '115fUy41sZkAG14CmdP1VbEKcNRZJWkUWG'; // hack internals w._address = '115fUy41sZkAG14CmdP1VbEKcNRZJWkUWG'; // hack internals
assert.ok(w.weOwnAddress('115fUy41sZkAG14CmdP1VbEKcNRZJWkUWG')); assert.ok(w.weOwnAddress('115fUy41sZkAG14CmdP1VbEKcNRZJWkUWG'));
assert.ok(!w.weOwnAddress('aaa')); assert.ok(!w.weOwnAddress('aaa'));
@ -55,12 +55,12 @@ describe('LegacyWallet', function() {
}); });
it('can fetch TXs', async () => { it('can fetch TXs', async () => {
let w = new LegacyWallet(); const w = new LegacyWallet();
w._address = '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG'; w._address = '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG';
await w.fetchTransactions(); await w.fetchTransactions();
assert.strictEqual(w.getTransactions().length, 2); assert.strictEqual(w.getTransactions().length, 2);
for (let tx of w.getTransactions()) { for (const tx of w.getTransactions()) {
assert.ok(tx.hash); assert.ok(tx.hash);
assert.ok(tx.value); assert.ok(tx.value);
assert.ok(tx.received); assert.ok(tx.received);
@ -70,12 +70,12 @@ describe('LegacyWallet', function() {
it('can fetch TXs when addresses for vout are missing', async () => { it('can fetch TXs when addresses for vout are missing', async () => {
// Transaction with missing address output https://www.blockchain.com/btc/tx/d45818ae11a584357f7b74da26012d2becf4ef064db015a45bdfcd9cb438929d // Transaction with missing address output https://www.blockchain.com/btc/tx/d45818ae11a584357f7b74da26012d2becf4ef064db015a45bdfcd9cb438929d
let w = new LegacyWallet(); const w = new LegacyWallet();
w._address = '1PVfrmbn1vSMoFZB2Ga7nDuXLFDyJZHrHK'; w._address = '1PVfrmbn1vSMoFZB2Ga7nDuXLFDyJZHrHK';
await w.fetchTransactions(); await w.fetchTransactions();
assert.ok(w.getTransactions().length > 0); assert.ok(w.getTransactions().length > 0);
for (let tx of w.getTransactions()) { for (const tx of w.getTransactions()) {
assert.ok(tx.hash); assert.ok(tx.hash);
assert.ok(tx.value); assert.ok(tx.value);
assert.ok(tx.received); assert.ok(tx.received);
@ -89,12 +89,12 @@ describe('LegacyWallet', function() {
])( ])(
'can fetch TXs when %s', 'can fetch TXs when %s',
async (useCase, address) => { async (useCase, address) => {
let w = new LegacyWallet(); const w = new LegacyWallet();
w._address = address; w._address = address;
await w.fetchTransactions(); await w.fetchTransactions();
assert.ok(w.getTransactions().length > 0); assert.ok(w.getTransactions().length > 0);
for (let tx of w.getTransactions()) { for (const tx of w.getTransactions()) {
assert.ok(tx.hash); assert.ok(tx.hash);
assert.ok(tx.value); assert.ok(tx.value);
assert.ok(tx.received); assert.ok(tx.received);
@ -105,22 +105,22 @@ describe('LegacyWallet', function() {
); );
it('can fetch UTXO', async () => { it('can fetch UTXO', async () => {
let w = new LegacyWallet(); const w = new LegacyWallet();
w._address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX'; w._address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX';
await w.fetchUtxo(); await w.fetchUtxo();
assert.ok(w.utxo.length > 0, 'unexpected empty UTXO'); assert.ok(w.utxo.length > 0, 'unexpected empty UTXO');
assert.ok(w.getUtxo().length > 0, 'unexpected empty UTXO'); assert.ok(w.getUtxo().length > 0, 'unexpected empty UTXO');
assert.ok(w.getUtxo()[0]['value']); assert.ok(w.getUtxo()[0].value);
assert.ok(w.getUtxo()[0]['vout'] === 1, JSON.stringify(w.getUtxo()[0])); assert.ok(w.getUtxo()[0].vout === 1, JSON.stringify(w.getUtxo()[0]));
assert.ok(w.getUtxo()[0]['txid']); assert.ok(w.getUtxo()[0].txid);
assert.ok(w.getUtxo()[0]['confirmations']); assert.ok(w.getUtxo()[0].confirmations);
}); });
}); });
describe('SegwitP2SHWallet', function() { describe('SegwitP2SHWallet', function () {
it('can generate segwit P2SH address from WIF', async () => { it('can generate segwit P2SH address from WIF', async () => {
let l = new SegwitP2SHWallet(); const l = new SegwitP2SHWallet();
l.setSecret('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct'); l.setSecret('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct');
assert.ok(l.getAddress() === '34AgLJhwXrvmkZS1o5TrcdeevMt22Nar53', 'expected ' + l.getAddress()); assert.ok(l.getAddress() === '34AgLJhwXrvmkZS1o5TrcdeevMt22Nar53', 'expected ' + l.getAddress());
assert.ok(l.getAddress() === (await l.getAddressAsync())); assert.ok(l.getAddress() === (await l.getAddressAsync()));
@ -128,9 +128,9 @@ describe('SegwitP2SHWallet', function() {
}); });
}); });
describe('SegwitBech32Wallet', function() { describe('SegwitBech32Wallet', function () {
it('can fetch balance', async () => { it('can fetch balance', async () => {
let w = new SegwitBech32Wallet(); const w = new SegwitBech32Wallet();
w._address = 'bc1qn887fmetaytw4vj68vsh529ft408q8j9x3dndc'; w._address = 'bc1qn887fmetaytw4vj68vsh529ft408q8j9x3dndc';
assert.ok(w.weOwnAddress('bc1qn887fmetaytw4vj68vsh529ft408q8j9x3dndc')); assert.ok(w.weOwnAddress('bc1qn887fmetaytw4vj68vsh529ft408q8j9x3dndc'));
await w.fetchBalance(); await w.fetchBalance();
@ -138,16 +138,16 @@ describe('SegwitBech32Wallet', function() {
}); });
it('can fetch UTXO', async () => { it('can fetch UTXO', async () => {
let w = new SegwitBech32Wallet(); const w = new SegwitBech32Wallet();
w._address = 'bc1qn887fmetaytw4vj68vsh529ft408q8j9x3dndc'; w._address = 'bc1qn887fmetaytw4vj68vsh529ft408q8j9x3dndc';
await w.fetchUtxo(); await w.fetchUtxo();
const l1 = w.getUtxo().length; const l1 = w.getUtxo().length;
assert.ok(w.getUtxo().length > 0, 'unexpected empty UTXO'); assert.ok(w.getUtxo().length > 0, 'unexpected empty UTXO');
assert.ok(w.getUtxo()[0]['value']); assert.ok(w.getUtxo()[0].value);
assert.ok(w.getUtxo()[0]['vout'] === 0); assert.ok(w.getUtxo()[0].vout === 0);
assert.ok(w.getUtxo()[0]['txid']); assert.ok(w.getUtxo()[0].txid);
assert.ok(w.getUtxo()[0]['confirmations'], JSON.stringify(w.getUtxo()[0], null, 2)); assert.ok(w.getUtxo()[0].confirmations, JSON.stringify(w.getUtxo()[0], null, 2));
// double fetch shouldnt duplicate UTXOs: // double fetch shouldnt duplicate UTXOs:
await w.fetchUtxo(); await w.fetchUtxo();
const l2 = w.getUtxo().length; const l2 = w.getUtxo().length;
@ -155,12 +155,12 @@ describe('SegwitBech32Wallet', function() {
}); });
it('can fetch TXs', async () => { it('can fetch TXs', async () => {
let w = new LegacyWallet(); const w = new LegacyWallet();
w._address = 'bc1quhnve8q4tk3unhmjts7ymxv8cd6w9xv8wy29uv'; w._address = 'bc1quhnve8q4tk3unhmjts7ymxv8cd6w9xv8wy29uv';
await w.fetchTransactions(); await w.fetchTransactions();
assert.strictEqual(w.getTransactions().length, 2); assert.strictEqual(w.getTransactions().length, 2);
for (let tx of w.getTransactions()) { for (const tx of w.getTransactions()) {
assert.ok(tx.hash); assert.ok(tx.hash);
assert.ok(tx.value); assert.ok(tx.value);
assert.ok(tx.received); assert.ok(tx.received);
@ -172,23 +172,23 @@ describe('SegwitBech32Wallet', function() {
}); });
it('can fetch TXs', async () => { it('can fetch TXs', async () => {
let w = new LegacyWallet(); const w = new LegacyWallet();
w._address = 'bc1qn887fmetaytw4vj68vsh529ft408q8j9x3dndc'; w._address = 'bc1qn887fmetaytw4vj68vsh529ft408q8j9x3dndc';
assert.ok(w.weOwnAddress('bc1qn887fmetaytw4vj68vsh529ft408q8j9x3dndc')); assert.ok(w.weOwnAddress('bc1qn887fmetaytw4vj68vsh529ft408q8j9x3dndc'));
await w.fetchTransactions(); await w.fetchTransactions();
assert.strictEqual(w.getTransactions().length, 1); assert.strictEqual(w.getTransactions().length, 1);
for (let tx of w.getTransactions()) { for (const tx of w.getTransactions()) {
assert.ok(tx.hash); assert.ok(tx.hash);
assert.strictEqual(tx.value, 100000); assert.strictEqual(tx.value, 100000);
assert.ok(tx.received); assert.ok(tx.received);
assert.ok(tx.confirmations > 1); assert.ok(tx.confirmations > 1);
} }
let tx0 = w.getTransactions()[0]; const tx0 = w.getTransactions()[0];
assert.ok(tx0['inputs']); assert.ok(tx0.inputs);
assert.ok(tx0['inputs'].length === 1); assert.ok(tx0.inputs.length === 1);
assert.ok(tx0['outputs']); assert.ok(tx0.outputs);
assert.ok(tx0['outputs'].length === 3); assert.ok(tx0.outputs.length === 3);
}); });
}); });

View file

@ -1,10 +1,10 @@
/* global it, describe, jasmine */ /* global it, describe, jasmine */
import Frisbee from 'frisbee'; import Frisbee from 'frisbee';
import { LightningCustodianWallet } from '../../class'; import { LightningCustodianWallet } from '../../class';
let assert = require('assert'); const assert = require('assert');
describe('LightningCustodianWallet', () => { describe('LightningCustodianWallet', () => {
let l1 = new LightningCustodianWallet(); const l1 = new LightningCustodianWallet();
it.skip('issue credentials', async () => { it.skip('issue credentials', async () => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000;
@ -52,8 +52,8 @@ describe('LightningCustodianWallet', () => {
it('can refresh token', async () => { it('can refresh token', async () => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000;
let oldRefreshToken = l1.refresh_token; const oldRefreshToken = l1.refresh_token;
let oldAccessToken = l1.access_token; const oldAccessToken = l1.access_token;
await l1.refreshAcessToken(); await l1.refreshAcessToken();
assert.ok(oldRefreshToken !== l1.refresh_token); assert.ok(oldRefreshToken !== l1.refresh_token);
assert.ok(oldAccessToken !== l1.access_token); assert.ok(oldAccessToken !== l1.access_token);
@ -67,7 +67,7 @@ describe('LightningCustodianWallet', () => {
console.error('process.env.BLITZHUB not set, skipped'); console.error('process.env.BLITZHUB not set, skipped');
return; return;
} }
let l2 = new LightningCustodianWallet(); const l2 = new LightningCustodianWallet();
l2.setSecret(process.env.BLITZHUB); l2.setSecret(process.env.BLITZHUB);
await l2.authorize(); await l2.authorize();
await l2.fetchPendingTransactions(); await l2.fetchPendingTransactions();
@ -76,7 +76,7 @@ describe('LightningCustodianWallet', () => {
assert.ok(l2.pending_transactions_raw.length === 0); assert.ok(l2.pending_transactions_raw.length === 0);
assert.ok(l2.transactions_raw.length > 0); assert.ok(l2.transactions_raw.length > 0);
assert.ok(l2.transactions_raw.length === l2.getTransactions().length); assert.ok(l2.transactions_raw.length === l2.getTransactions().length);
for (let tx of l2.getTransactions()) { for (const tx of l2.getTransactions()) {
assert.ok(typeof tx.fee !== 'undefined'); assert.ok(typeof tx.fee !== 'undefined');
assert.ok(tx.value); assert.ok(tx.value);
assert.ok(tx.timestamp); assert.ok(tx.timestamp);
@ -94,13 +94,13 @@ describe('LightningCustodianWallet', () => {
return; return;
} }
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30 * 1000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 30 * 1000;
let l2 = new LightningCustodianWallet(); const l2 = new LightningCustodianWallet();
l2.setSecret(process.env.BLITZHUB); l2.setSecret(process.env.BLITZHUB);
await l2.authorize(); await l2.authorize();
let invoice = let invoice =
'lnbc1u1pdcqpt3pp5ltuevvq2g69kdrzcegrs9gfqjer45rwjc0w736qjl92yvwtxhn6qdp8dp6kuerjv4j9xct5daeks6tnyp3xc6t50f582cscqp2zrkghzl535xjav52ns0rpskcn20takzdr2e02wn4xqretlgdemg596acq5qtfqhjk4jpr7jk8qfuuka2k0lfwjsk9mchwhxcgxzj3tsp09gfpy'; 'lnbc1u1pdcqpt3pp5ltuevvq2g69kdrzcegrs9gfqjer45rwjc0w736qjl92yvwtxhn6qdp8dp6kuerjv4j9xct5daeks6tnyp3xc6t50f582cscqp2zrkghzl535xjav52ns0rpskcn20takzdr2e02wn4xqretlgdemg596acq5qtfqhjk4jpr7jk8qfuuka2k0lfwjsk9mchwhxcgxzj3tsp09gfpy';
let decoded = l2.decodeInvoice(invoice); const decoded = l2.decodeInvoice(invoice);
assert.ok(decoded.payment_hash); assert.ok(decoded.payment_hash);
assert.ok(decoded.description); assert.ok(decoded.description);
@ -121,8 +121,8 @@ describe('LightningCustodianWallet', () => {
}); });
it('decode can handle zero sats but present msats', async () => { it('decode can handle zero sats but present msats', async () => {
let l = new LightningCustodianWallet(); const l = new LightningCustodianWallet();
let decoded = l.decodeInvoice( const decoded = l.decodeInvoice(
'lnbc89n1p0zptvhpp5j3h5e80vdlzn32df8y80nl2t7hssn74lzdr96ve0u4kpaupflx2sdphgfkx7cmtwd68yetpd5s9xct5v4kxc6t5v5s9gunpdeek66tnwd5k7mscqp2sp57m89zv0lrgc9zzaxy5p3d5rr2cap2pm6zm4n0ew9vyp2d5zf2mfqrzjqfxj8p6qjf5l8du7yuytkwdcjhylfd4gxgs48t65awjg04ye80mq7z990yqq9jsqqqqqqqqqqqqq05qqrc9qy9qsq9mynpa9ucxg53hwnvw323r55xdd3l6lcadzs584zvm4wdw5pv3eksdlcek425pxaqrn9u5gpw0dtpyl9jw2pynjtqexxgh50akwszjgq4ht4dh', 'lnbc89n1p0zptvhpp5j3h5e80vdlzn32df8y80nl2t7hssn74lzdr96ve0u4kpaupflx2sdphgfkx7cmtwd68yetpd5s9xct5v4kxc6t5v5s9gunpdeek66tnwd5k7mscqp2sp57m89zv0lrgc9zzaxy5p3d5rr2cap2pm6zm4n0ew9vyp2d5zf2mfqrzjqfxj8p6qjf5l8du7yuytkwdcjhylfd4gxgs48t65awjg04ye80mq7z990yqq9jsqqqqqqqqqqqqq05qqrc9qy9qsq9mynpa9ucxg53hwnvw323r55xdd3l6lcadzs584zvm4wdw5pv3eksdlcek425pxaqrn9u5gpw0dtpyl9jw2pynjtqexxgh50akwszjgq4ht4dh',
); );
assert.strictEqual(decoded.num_satoshis, '8.9'); assert.strictEqual(decoded.num_satoshis, '8.9');
@ -133,13 +133,13 @@ describe('LightningCustodianWallet', () => {
console.error('process.env.BLITZHUB not set, skipped'); console.error('process.env.BLITZHUB not set, skipped');
return; return;
} }
let l2 = new LightningCustodianWallet(); const l2 = new LightningCustodianWallet();
l2.setSecret(process.env.BLITZHUB); l2.setSecret(process.env.BLITZHUB);
await l2.authorize(); await l2.authorize();
let invoice = const invoice =
'lnbc1u1pdcqpt3pp5ltuevvq2g69kdrzcegrs9gfqjer45rwjc0w736qjl92yvwtxhn6qdp8dp6kuerjv4j9xct5daeks6tnyp3xc6t50f582cscqp2zrkghzl535xjav52ns0rpskcn20takzdr2e02wn4xqretlgdemg596acq5qtfqhjk4jpr7jk8qfuuka2k0lfwjsk9mchwhxcgxzj3tsp09gfpy'; 'lnbc1u1pdcqpt3pp5ltuevvq2g69kdrzcegrs9gfqjer45rwjc0w736qjl92yvwtxhn6qdp8dp6kuerjv4j9xct5daeks6tnyp3xc6t50f582cscqp2zrkghzl535xjav52ns0rpskcn20takzdr2e02wn4xqretlgdemg596acq5qtfqhjk4jpr7jk8qfuuka2k0lfwjsk9mchwhxcgxzj3tsp09gfpy';
let decodedLocally = l2.decodeInvoice(invoice); const decodedLocally = l2.decodeInvoice(invoice);
let decodedRemotely = await l2.decodeInvoiceRemote(invoice); const decodedRemotely = await l2.decodeInvoiceRemote(invoice);
assert.strictEqual(decodedLocally.destination, decodedRemotely.destination); assert.strictEqual(decodedLocally.destination, decodedRemotely.destination);
assert.strictEqual(decodedLocally.num_satoshis, decodedRemotely.num_satoshis); assert.strictEqual(decodedLocally.num_satoshis, decodedRemotely.num_satoshis);
assert.strictEqual(decodedLocally.timestamp, decodedRemotely.timestamp); assert.strictEqual(decodedLocally.timestamp, decodedRemotely.timestamp);
@ -176,22 +176,22 @@ describe('LightningCustodianWallet', () => {
const invoice = res.body.data.lightning_invoice.payreq; const invoice = res.body.data.lightning_invoice.payreq;
let l2 = new LightningCustodianWallet(); const l2 = new LightningCustodianWallet();
l2.setSecret(process.env.BLITZHUB); l2.setSecret(process.env.BLITZHUB);
await l2.authorize(); await l2.authorize();
await l2.fetchTransactions(); await l2.fetchTransactions();
let txLen = l2.transactions_raw.length; const txLen = l2.transactions_raw.length;
let start = +new Date(); const start = +new Date();
await l2.payInvoice(invoice); await l2.payInvoice(invoice);
let end = +new Date(); const end = +new Date();
if ((end - start) / 1000 > 9) { if ((end - start) / 1000 > 9) {
console.warn('payInvoice took', (end - start) / 1000, 'sec'); console.warn('payInvoice took', (end - start) / 1000, 'sec');
} }
await l2.fetchTransactions(); await l2.fetchTransactions();
assert.strictEqual(l2.transactions_raw.length, txLen + 1); assert.strictEqual(l2.transactions_raw.length, txLen + 1);
let lastTx = l2.transactions_raw[l2.transactions_raw.length - 1]; const lastTx = l2.transactions_raw[l2.transactions_raw.length - 1];
assert.strictEqual(typeof lastTx.payment_preimage, 'string', 'preimage is present and is a string'); assert.strictEqual(typeof lastTx.payment_preimage, 'string', 'preimage is present and is a string');
assert.strictEqual(lastTx.payment_preimage.length, 64, 'preimage is present and is a string of 32 hex-encoded bytes'); assert.strictEqual(lastTx.payment_preimage.length, 64, 'preimage is present and is a string of 32 hex-encoded bytes');
// transactions became more after paying an invoice // transactions became more after paying an invoice
@ -226,15 +226,15 @@ describe('LightningCustodianWallet', () => {
throw new Error('Strike problem: ' + JSON.stringify(res)); throw new Error('Strike problem: ' + JSON.stringify(res));
} }
let invoice = res.body.payment_request; const invoice = res.body.payment_request;
let l2 = new LightningCustodianWallet(); const l2 = new LightningCustodianWallet();
l2.setSecret(process.env.BLITZHUB); l2.setSecret(process.env.BLITZHUB);
await l2.authorize(); await l2.authorize();
await l2.fetchTransactions(); await l2.fetchTransactions();
let txLen = l2.transactions_raw.length; const txLen = l2.transactions_raw.length;
let decoded = l2.decodeInvoice(invoice); const decoded = l2.decodeInvoice(invoice);
assert.ok(decoded.payment_hash); assert.ok(decoded.payment_hash);
assert.ok(decoded.description); assert.ok(decoded.description);
@ -249,7 +249,7 @@ describe('LightningCustodianWallet', () => {
await l2.fetchTransactions(); await l2.fetchTransactions();
assert.strictEqual(l2.transactions_raw.length, txLen + 1); assert.strictEqual(l2.transactions_raw.length, txLen + 1);
let lastTx = l2.transactions_raw[l2.transactions_raw.length - 1]; const lastTx = l2.transactions_raw[l2.transactions_raw.length - 1];
assert.strictEqual(typeof lastTx.payment_preimage, 'string', 'preimage is present and is a string'); assert.strictEqual(typeof lastTx.payment_preimage, 'string', 'preimage is present and is a string');
assert.strictEqual(lastTx.payment_preimage.length, 64, 'preimage is present and is a string of 32 hex-encoded bytes'); assert.strictEqual(lastTx.payment_preimage.length, 64, 'preimage is present and is a string of 32 hex-encoded bytes');
// transactions became more after paying an invoice // transactions became more after paying an invoice
@ -279,14 +279,14 @@ describe('LightningCustodianWallet', () => {
return; return;
} }
let lOld = new LightningCustodianWallet(); const lOld = new LightningCustodianWallet();
lOld.setSecret(process.env.BLITZHUB); lOld.setSecret(process.env.BLITZHUB);
await lOld.authorize(); await lOld.authorize();
await lOld.fetchTransactions(); await lOld.fetchTransactions();
let txLen = lOld.transactions_raw.length; let txLen = lOld.transactions_raw.length;
// creating LND wallet // creating LND wallet
let lNew = new LightningCustodianWallet(); const lNew = new LightningCustodianWallet();
await lNew.createAccount(true); await lNew.createAccount(true);
await lNew.authorize(); await lNew.authorize();
await lNew.fetchBalance(); await lNew.fetchBalance();
@ -303,7 +303,7 @@ describe('LightningCustodianWallet', () => {
assert.ok(invoices2[0].timestamp); assert.ok(invoices2[0].timestamp);
assert.ok(invoices2[0].expire_time); assert.ok(invoices2[0].expire_time);
assert.strictEqual(invoices2[0].amt, 1); assert.strictEqual(invoices2[0].amt, 1);
for (let inv of invoices2) { for (const inv of invoices2) {
assert.strictEqual(inv.type, 'user_invoice'); assert.strictEqual(inv.type, 'user_invoice');
} }
@ -312,9 +312,9 @@ describe('LightningCustodianWallet', () => {
await lOld.checkRouteInvoice(invoice); await lOld.checkRouteInvoice(invoice);
let start = +new Date(); const start = +new Date();
await lOld.payInvoice(invoice); await lOld.payInvoice(invoice);
let end = +new Date(); const end = +new Date();
if ((end - start) / 1000 > 9) { if ((end - start) / 1000 > 9) {
console.warn('payInvoice took', (end - start) / 1000, 'sec'); console.warn('payInvoice took', (end - start) / 1000, 'sec');
} }
@ -329,7 +329,7 @@ describe('LightningCustodianWallet', () => {
await lOld.fetchTransactions(); await lOld.fetchTransactions();
assert.strictEqual(lOld.transactions_raw.length, txLen + 1, 'internal invoice should also produce record in payer`s tx list'); assert.strictEqual(lOld.transactions_raw.length, txLen + 1, 'internal invoice should also produce record in payer`s tx list');
let newTx = lOld.transactions_raw.slice().pop(); const newTx = lOld.transactions_raw.slice().pop();
assert.ok(typeof newTx.fee !== 'undefined'); assert.ok(typeof newTx.fee !== 'undefined');
assert.ok(newTx.value); assert.ok(newTx.value);
assert.ok(newTx.description || newTx.memo, JSON.stringify(newTx)); assert.ok(newTx.description || newTx.memo, JSON.stringify(newTx));
@ -351,7 +351,7 @@ describe('LightningCustodianWallet', () => {
let coughtError = false; let coughtError = false;
await lOld.fetchTransactions(); await lOld.fetchTransactions();
txLen = lOld.transactions_raw.length; txLen = lOld.transactions_raw.length;
let invLen = (await lNew.getUserInvoices()).length; const invLen = (await lNew.getUserInvoices()).length;
try { try {
await lOld.payInvoice(invoice); await lOld.payInvoice(invoice);
} catch (Err) { } catch (Err) {
@ -372,7 +372,7 @@ describe('LightningCustodianWallet', () => {
assert.strictEqual(invoices[1].amt, 666); assert.strictEqual(invoices[1].amt, 666);
}); });
it('can pay invoice with free amount (tippin.me)', async function() { it('can pay invoice with free amount (tippin.me)', async function () {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000;
if (!process.env.BLITZHUB) { if (!process.env.BLITZHUB) {
console.error('process.env.BLITZHUB not set, skipped'); console.error('process.env.BLITZHUB not set, skipped');
@ -407,15 +407,15 @@ describe('LightningCustodianWallet', () => {
// invoice = // invoice =
// 'lnbc1pwrp35spp5z62nvj8yw6luq7ns4a8utpwn2qkkdwdt0ludwm54wjeazk2xv5wsdpu235hqurfdcsx7an9wf6x7undv4h8ggpgw35hqurfdchx6eff9p6nzvfc8q5scqzysxqyz5vqj8xq6wz6dezmunw6qxleuw67ensjnt3fldltrmmkvzurge0dczpn94fkwwh7hkh5wqrhsvfegtvhswn252hn6uw5kx99dyumz4v5n9sp337py2'; // 'lnbc1pwrp35spp5z62nvj8yw6luq7ns4a8utpwn2qkkdwdt0ludwm54wjeazk2xv5wsdpu235hqurfdcsx7an9wf6x7undv4h8ggpgw35hqurfdchx6eff9p6nzvfc8q5scqzysxqyz5vqj8xq6wz6dezmunw6qxleuw67ensjnt3fldltrmmkvzurge0dczpn94fkwwh7hkh5wqrhsvfegtvhswn252hn6uw5kx99dyumz4v5n9sp337py2';
let l2 = new LightningCustodianWallet(); const l2 = new LightningCustodianWallet();
l2.setSecret(process.env.BLITZHUB); l2.setSecret(process.env.BLITZHUB);
await l2.authorize(); await l2.authorize();
await l2.fetchTransactions(); await l2.fetchTransactions();
await l2.fetchBalance(); await l2.fetchBalance();
const oldBalance = +l2.balance; const oldBalance = +l2.balance;
let txLen = l2.transactions_raw.length; const txLen = l2.transactions_raw.length;
let decoded = l2.decodeInvoice(invoice); const decoded = l2.decodeInvoice(invoice);
assert.ok(decoded.payment_hash); assert.ok(decoded.payment_hash);
assert.ok(decoded.description); assert.ok(decoded.description);
assert.strictEqual(+decoded.num_satoshis, 0); assert.strictEqual(+decoded.num_satoshis, 0);
@ -433,9 +433,9 @@ describe('LightningCustodianWallet', () => {
// then, pay: // then, pay:
let start = +new Date(); const start = +new Date();
await l2.payInvoice(invoice, 3); await l2.payInvoice(invoice, 3);
let end = +new Date(); const end = +new Date();
if ((end - start) / 1000 > 9) { if ((end - start) / 1000 > 9) {
console.warn('payInvoice took', (end - start) / 1000, 'sec'); console.warn('payInvoice took', (end - start) / 1000, 'sec');
} }
@ -450,7 +450,7 @@ describe('LightningCustodianWallet', () => {
}); });
it('cant create zemo amt invoices yet', async () => { it('cant create zemo amt invoices yet', async () => {
let l1 = new LightningCustodianWallet(); const l1 = new LightningCustodianWallet();
jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000; jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000;
assert.ok(l1.refill_addressess.length === 0); assert.ok(l1.refill_addressess.length === 0);
assert.ok(l1._refresh_token_created_ts === 0); assert.ok(l1._refresh_token_created_ts === 0);
@ -515,15 +515,15 @@ describe('LightningCustodianWallet', () => {
throw new Error('tippin.me problem: ' + JSON.stringify(res)); throw new Error('tippin.me problem: ' + JSON.stringify(res));
} }
let l2 = new LightningCustodianWallet(); const l2 = new LightningCustodianWallet();
l2.setSecret(process.env.BLITZHUB); l2.setSecret(process.env.BLITZHUB);
await l2.authorize(); await l2.authorize();
await l2.fetchTransactions(); await l2.fetchTransactions();
await l2.fetchBalance(); await l2.fetchBalance();
let oldBalance = +l2.balance; const oldBalance = +l2.balance;
let txLen = l2.transactions_raw.length; const txLen = l2.transactions_raw.length;
let decoded = l2.decodeInvoice(invoice); const decoded = l2.decodeInvoice(invoice);
assert.ok(decoded.payment_hash); assert.ok(decoded.payment_hash);
assert.ok(decoded.description); assert.ok(decoded.description);
assert.strictEqual(+decoded.num_satoshis, 0); assert.strictEqual(+decoded.num_satoshis, 0);

View file

@ -1,9 +1,9 @@
/* global it, describe, jasmine, afterAll, beforeAll */ /* global it, describe, jasmine, afterAll, beforeAll */
import { WatchOnlyWallet } from '../../class'; import { WatchOnlyWallet } from '../../class';
let assert = require('assert'); const assert = require('assert');
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js global.tls = require('tls'); // needed by Electrum client. For RN it is proviced in shim.js
let BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP const BlueElectrum = require('../../BlueElectrum'); // so it connects ASAP
afterAll(async () => { afterAll(async () => {
// after all tests we close socket so the test suite can actually terminate // after all tests we close socket so the test suite can actually terminate
@ -20,7 +20,7 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 500 * 1000;
describe('Watch only wallet', () => { describe('Watch only wallet', () => {
it('can fetch balance', async () => { it('can fetch balance', async () => {
let w = new WatchOnlyWallet(); const w = new WatchOnlyWallet();
w.setSecret('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa'); w.setSecret('1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa');
await w.fetchBalance(); await w.fetchBalance();
assert.ok(w.getBalance() > 16); assert.ok(w.getBalance() > 16);
@ -44,8 +44,8 @@ describe('Watch only wallet', () => {
}); });
it('can fetch TXs with values', async () => { it('can fetch TXs with values', async () => {
let w = new WatchOnlyWallet(); const w = new WatchOnlyWallet();
for (let sec of [ for (const sec of [
'bc1quhnve8q4tk3unhmjts7ymxv8cd6w9xv8wy29uv', 'bc1quhnve8q4tk3unhmjts7ymxv8cd6w9xv8wy29uv',
'BC1QUHNVE8Q4TK3UNHMJTS7YMXV8CD6W9XV8WY29UV', 'BC1QUHNVE8Q4TK3UNHMJTS7YMXV8CD6W9XV8WY29UV',
'bitcoin:bc1quhnve8q4tk3unhmjts7ymxv8cd6w9xv8wy29uv', 'bitcoin:bc1quhnve8q4tk3unhmjts7ymxv8cd6w9xv8wy29uv',
@ -59,7 +59,7 @@ describe('Watch only wallet', () => {
assert.ok(w.weOwnAddress('bc1quhnve8q4tk3unhmjts7ymxv8cd6w9xv8wy29uv')); assert.ok(w.weOwnAddress('bc1quhnve8q4tk3unhmjts7ymxv8cd6w9xv8wy29uv'));
await w.fetchTransactions(); await w.fetchTransactions();
for (let tx of w.getTransactions()) { for (const tx of w.getTransactions()) {
assert.ok(tx.hash); assert.ok(tx.hash);
assert.ok(tx.value); assert.ok(tx.value);
assert.ok(tx.received); assert.ok(tx.received);
@ -72,16 +72,16 @@ describe('Watch only wallet', () => {
}); });
it('can fetch complex TXs', async () => { it('can fetch complex TXs', async () => {
let w = new WatchOnlyWallet(); const w = new WatchOnlyWallet();
w.setSecret('3NLnALo49CFEF4tCRhCvz45ySSfz3UktZC'); w.setSecret('3NLnALo49CFEF4tCRhCvz45ySSfz3UktZC');
await w.fetchTransactions(); await w.fetchTransactions();
for (let tx of w.getTransactions()) { for (const tx of w.getTransactions()) {
assert.ok(tx.value, 'incorrect tx.value'); assert.ok(tx.value, 'incorrect tx.value');
} }
}); });
it('can fetch balance & transactions from zpub HD', async () => { it('can fetch balance & transactions from zpub HD', async () => {
let w = new WatchOnlyWallet(); const w = new WatchOnlyWallet();
w.setSecret('zpub6r7jhKKm7BAVx3b3nSnuadY1WnshZYkhK8gKFoRLwK9rF3Mzv28BrGcCGA3ugGtawi1WLb2vyjQAX9ZTDGU5gNk2bLdTc3iEXr6tzR1ipNP'); w.setSecret('zpub6r7jhKKm7BAVx3b3nSnuadY1WnshZYkhK8gKFoRLwK9rF3Mzv28BrGcCGA3ugGtawi1WLb2vyjQAX9ZTDGU5gNk2bLdTc3iEXr6tzR1ipNP');
await w.fetchBalance(); await w.fetchBalance();
assert.strictEqual(w.getBalance(), 200000); assert.strictEqual(w.getBalance(), 200000);

View file

@ -1,12 +1,12 @@
/* global it, jasmine */ /* global it, jasmine */
let assert = require('assert'); const assert = require('assert');
it('bip38 decodes', async () => { it('bip38 decodes', async () => {
const bip38 = require('../../blue_modules/bip38'); const bip38 = require('../../blue_modules/bip38');
const wif = require('wif'); const wif = require('wif');
let encryptedKey = '6PRVWUbkzq2VVjRuv58jpwVjTeN46MeNmzUHqUjQptBJUHGcBakduhrUNc'; const encryptedKey = '6PRVWUbkzq2VVjRuv58jpwVjTeN46MeNmzUHqUjQptBJUHGcBakduhrUNc';
let decryptedKey = await bip38.decrypt( const decryptedKey = await bip38.decrypt(
encryptedKey, encryptedKey,
'TestingOneTwoThree', 'TestingOneTwoThree',
() => {}, () => {},
@ -28,9 +28,9 @@ it('bip38 decodes slow', async () => {
const bip38 = require('../../blue_modules/bip38'); const bip38 = require('../../blue_modules/bip38');
const wif = require('wif'); const wif = require('wif');
let encryptedKey = '6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN'; const encryptedKey = '6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN';
let callbackWasCalled = false; let callbackWasCalled = false;
let decryptedKey = await bip38.decrypt(encryptedKey, 'qwerty', () => { const decryptedKey = await bip38.decrypt(encryptedKey, 'qwerty', () => {
// callbacks make sense only with pure js scrypt implementation (nodejs and browsers). // callbacks make sense only with pure js scrypt implementation (nodejs and browsers).
// on RN scrypt is handled by native module and takes ~4 secs // on RN scrypt is handled by native module and takes ~4 secs
callbackWasCalled = true; callbackWasCalled = true;

View file

@ -1,21 +1,21 @@
/* global it, describe */ /* global it, describe */
let assert = require('assert'); const assert = require('assert');
const fs = require('fs'); const fs = require('fs');
describe('Localization', () => { describe('Localization', () => {
it('has all keys in all locales', async () => { it('has all keys in all locales', async () => {
let en = require('../../loc/en'); const en = require('../../loc/en');
let issues = 0; let issues = 0;
for (let key1 of Object.keys(en)) { for (const key1 of Object.keys(en)) {
for (let key2 of Object.keys(en[key1])) { for (const key2 of Object.keys(en[key1])) {
// iterating all keys and subkeys in EN locale, which is main // iterating all keys and subkeys in EN locale, which is main
let files = fs.readdirSync('./loc/'); const files = fs.readdirSync('./loc/');
for (let lang of files) { for (const lang of files) {
if (lang === 'en.js') continue; // iteratin all locales except EN if (lang === 'en.js') continue; // iteratin all locales except EN
if (lang === 'index.js') continue; if (lang === 'index.js') continue;
let locale = require('../../loc/' + lang); const locale = require('../../loc/' + lang);
if (typeof locale[key1] === 'undefined') { if (typeof locale[key1] === 'undefined') {
console.error('Missing: ' + lang + '.' + key1); console.error('Missing: ' + lang + '.' + key1);
@ -28,7 +28,7 @@ describe('Localization', () => {
// level 1 & 2 done, doing level 3 (if it exists): // level 1 & 2 done, doing level 3 (if it exists):
if (typeof en[key1][key2] !== 'string') { if (typeof en[key1][key2] !== 'string') {
for (let key3 of Object.keys(en[key1][key2])) { for (const key3 of Object.keys(en[key1][key2])) {
if (typeof locale[key1][key2][key3] === 'undefined') { if (typeof locale[key1][key2][key3] === 'undefined') {
console.error('Missing: ' + lang + '.' + key1 + '.' + key2 + '.' + key3); console.error('Missing: ' + lang + '.' + key1 + '.' + key2 + '.' + key3);
issues++; issues++;

View file

@ -1,12 +1,12 @@
/* global it */ /* global it */
import { SegwitP2SHWallet, AppStorage } from '../../class'; import { SegwitP2SHWallet, AppStorage } from '../../class';
import AsyncStorage from '@react-native-community/async-storage'; import AsyncStorage from '@react-native-community/async-storage';
let assert = require('assert'); const assert = require('assert');
it('Appstorage - loadFromDisk works', async () => { it('Appstorage - loadFromDisk works', async () => {
/** @type {AppStorage} */ /** @type {AppStorage} */
let Storage = new AppStorage(); const Storage = new AppStorage();
let w = new SegwitP2SHWallet(); const w = new SegwitP2SHWallet();
w.setLabel('testlabel'); w.setLabel('testlabel');
await w.generate(); await w.generate();
Storage.wallets.push(w); Storage.wallets.push(w);
@ -14,7 +14,7 @@ it('Appstorage - loadFromDisk works', async () => {
// saved, now trying to load // saved, now trying to load
let Storage2 = new AppStorage(); const Storage2 = new AppStorage();
await Storage2.loadFromDisk(); await Storage2.loadFromDisk();
assert.strictEqual(Storage2.wallets.length, 1); assert.strictEqual(Storage2.wallets.length, 1);
assert.strictEqual(Storage2.wallets[0].getLabel(), 'testlabel'); assert.strictEqual(Storage2.wallets[0].getLabel(), 'testlabel');
@ -25,14 +25,14 @@ it('Appstorage - loadFromDisk works', async () => {
await AsyncStorage.setItem('data', false); await AsyncStorage.setItem('data', false);
await AsyncStorage.setItem(AppStorage.FLAG_ENCRYPTED, '1'); await AsyncStorage.setItem(AppStorage.FLAG_ENCRYPTED, '1');
let Storage3 = new AppStorage(); const Storage3 = new AppStorage();
isEncrypted = await Storage3.storageIsEncrypted(); isEncrypted = await Storage3.storageIsEncrypted();
assert.ok(isEncrypted); assert.ok(isEncrypted);
}); });
it('Appstorage - encryptStorage & load encrypted storage works', async () => { it('Appstorage - encryptStorage & load encrypted storage works', async () => {
/** @type {AppStorage} */ /** @type {AppStorage} */
let Storage = new AppStorage(); const Storage = new AppStorage();
let w = new SegwitP2SHWallet(); let w = new SegwitP2SHWallet();
w.setLabel('testlabel'); w.setLabel('testlabel');
await w.generate(); await w.generate();
@ -92,7 +92,7 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.strictEqual(Storage2.wallets[1].getLabel(), 'testlabel2'); assert.strictEqual(Storage2.wallets[1].getLabel(), 'testlabel2');
// next, adding new `fake` storage which should be unlocked with `fake` password // next, adding new `fake` storage which should be unlocked with `fake` password
let createFakeStorageResult = await Storage2.createFakeStorage('fakePassword'); const createFakeStorageResult = await Storage2.createFakeStorage('fakePassword');
assert.ok(createFakeStorageResult); assert.ok(createFakeStorageResult);
assert.strictEqual(Storage2.wallets.length, 0); assert.strictEqual(Storage2.wallets.length, 0);
assert.strictEqual(Storage2.cachedPassword, 'fakePassword'); assert.strictEqual(Storage2.cachedPassword, 'fakePassword');
@ -118,7 +118,7 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load storage works', async () => { it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load storage works', async () => {
/** @type {AppStorage} */ /** @type {AppStorage} */
let Storage = new AppStorage(); const Storage = new AppStorage();
let w = new SegwitP2SHWallet(); let w = new SegwitP2SHWallet();
w.setLabel('testlabel'); w.setLabel('testlabel');
await w.generate(); await w.generate();
@ -178,7 +178,7 @@ it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load s
assert.strictEqual(Storage2.wallets[1].getLabel(), 'testlabel2'); assert.strictEqual(Storage2.wallets[1].getLabel(), 'testlabel2');
// next, adding new `fake` storage which should be unlocked with `fake` password // next, adding new `fake` storage which should be unlocked with `fake` password
let createFakeStorageResult = await Storage2.createFakeStorage('fakePassword'); const createFakeStorageResult = await Storage2.createFakeStorage('fakePassword');
assert.ok(createFakeStorageResult); assert.ok(createFakeStorageResult);
assert.strictEqual(Storage2.wallets.length, 0); assert.strictEqual(Storage2.wallets.length, 0);
assert.strictEqual(Storage2.cachedPassword, 'fakePassword'); assert.strictEqual(Storage2.cachedPassword, 'fakePassword');
@ -223,7 +223,7 @@ it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load s
it('can decrypt storage that is second in a list of buckets; and isPasswordInUse() works', async () => { it('can decrypt storage that is second in a list of buckets; and isPasswordInUse() works', async () => {
/** @type {AppStorage} */ /** @type {AppStorage} */
let Storage = new AppStorage(); const Storage = new AppStorage();
let w = new SegwitP2SHWallet(); let w = new SegwitP2SHWallet();
w.setLabel('testlabel'); w.setLabel('testlabel');
await w.generate(); await w.generate();
@ -237,7 +237,7 @@ it('can decrypt storage that is second in a list of buckets; and isPasswordInUse
assert.ok(isEncrypted); assert.ok(isEncrypted);
// next, adding new `fake` storage which should be unlocked with `fake` password // next, adding new `fake` storage which should be unlocked with `fake` password
let createFakeStorageResult = await Storage.createFakeStorage('fakePassword'); const createFakeStorageResult = await Storage.createFakeStorage('fakePassword');
assert.ok(createFakeStorageResult); assert.ok(createFakeStorageResult);
assert.strictEqual(Storage.wallets.length, 0); assert.strictEqual(Storage.wallets.length, 0);
assert.strictEqual(Storage.cachedPassword, 'fakePassword'); assert.strictEqual(Storage.cachedPassword, 'fakePassword');

View file

@ -2,7 +2,7 @@
import DeeplinkSchemaMatch from '../../class/deeplink-schema-match'; import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
const assert = require('assert'); const assert = require('assert');
describe('unit - DeepLinkSchemaMatch', function() { describe('unit - DeepLinkSchemaMatch', function () {
it('hasSchema', () => { it('hasSchema', () => {
assert.ok(DeeplinkSchemaMatch.hasSchema('bitcoin:12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG')); assert.ok(DeeplinkSchemaMatch.hasSchema('bitcoin:12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG'));
assert.ok(DeeplinkSchemaMatch.hasSchema('bitcoin:bc1qh6tf004ty7z7un2v5ntu4mkf630545gvhs45u7?amount=666&label=Yo')); assert.ok(DeeplinkSchemaMatch.hasSchema('bitcoin:bc1qh6tf004ty7z7un2v5ntu4mkf630545gvhs45u7?amount=666&label=Yo'));
@ -153,16 +153,16 @@ describe('unit - DeepLinkSchemaMatch', function() {
}, },
]; ];
const asyncNavigationRouteFor = async function(event) { const asyncNavigationRouteFor = async function (event) {
return new Promise(function(resolve) { return new Promise(function (resolve) {
DeeplinkSchemaMatch.navigationRouteFor(event, navValue => { DeeplinkSchemaMatch.navigationRouteFor(event, navValue => {
resolve(navValue); resolve(navValue);
}); });
}); });
}; };
for (let event of events) { for (const event of events) {
let navValue = await asyncNavigationRouteFor(event.argument); const navValue = await asyncNavigationRouteFor(event.argument);
assert.deepStrictEqual(navValue, event.expected); assert.deepStrictEqual(navValue, event.expected);
} }
}); });

View file

@ -1,9 +1,9 @@
/* global describe, it */ /* global describe, it */
let assert = require('assert'); const assert = require('assert');
let c = require('../../encryption'); const c = require('../../encryption');
describe('unit - encryption', function() { describe('unit - encryption', function () {
it('encrypts and decrypts', function() { it('encrypts and decrypts', function () {
const data2encrypt = 'really long data string bla bla really long data string bla bla really long data string bla bla'; const data2encrypt = 'really long data string bla bla really long data string bla bla really long data string bla bla';
const crypted = c.encrypt(data2encrypt, 'password'); const crypted = c.encrypt(data2encrypt, 'password');
const decrypted = c.decrypt(crypted, 'password'); const decrypted = c.decrypt(crypted, 'password');
@ -28,8 +28,8 @@ describe('unit - encryption', function() {
assert.ok(exceptionRaised); assert.ok(exceptionRaised);
}); });
it('handles ok malformed data', function() { it('handles ok malformed data', function () {
let decrypted = c.decrypt( const decrypted = c.decrypt(
'U2FsdGVkX1/OSNdi0JrLANn9qdNEiXgP20MJgT13CMKC7xKe+sb7x0An6r8lzrYeL2vjoPm2Xi5I3UdBcsgjgh0TR4PypNdDaW1tW8LhFH1wVCh1hacrFsJjoKMBmdCn4IVMwtIffGPptqBrGZl+6kjOc3BBbgq4uaAavFIwTS86WdaRt9qAboBcoPJZxsj37othbZfZfl2GBTCWnR1tOYAbElKWv4lBwNQpX7HqX3wTQkAbamBslsH5FfZRY1c38lOHrZMwNSyxhgspydksTxKkhPqWQu3XWT4GpRoRuVvYlBNvJOCUu2JbiVSp4NiOMSfnA8ahvpCGRNy+qPWsXqmJtz9BwyzedzDkgg6QOqxXz4oOeEJa/XLKiuv3ItsLrZb+sSA6wjB1Cx6/Oh2vW7eiHjCITeC7KUK1fAxVwufLcprNkvG8qFzkOcHxDyzG+sNL0cMipAxhpMX7qIcYcZFoLYkQRQHpOZKZCIAdNTfPGJ7M4cxGM0V+Uuirjyn+KAPJwNElwmPpX8sTQyEqlIlEwVjFXBpz28N5RAGN2zzCzEjD8NVYQJ2QyHj0gfWe', 'U2FsdGVkX1/OSNdi0JrLANn9qdNEiXgP20MJgT13CMKC7xKe+sb7x0An6r8lzrYeL2vjoPm2Xi5I3UdBcsgjgh0TR4PypNdDaW1tW8LhFH1wVCh1hacrFsJjoKMBmdCn4IVMwtIffGPptqBrGZl+6kjOc3BBbgq4uaAavFIwTS86WdaRt9qAboBcoPJZxsj37othbZfZfl2GBTCWnR1tOYAbElKWv4lBwNQpX7HqX3wTQkAbamBslsH5FfZRY1c38lOHrZMwNSyxhgspydksTxKkhPqWQu3XWT4GpRoRuVvYlBNvJOCUu2JbiVSp4NiOMSfnA8ahvpCGRNy+qPWsXqmJtz9BwyzedzDkgg6QOqxXz4oOeEJa/XLKiuv3ItsLrZb+sSA6wjB1Cx6/Oh2vW7eiHjCITeC7KUK1fAxVwufLcprNkvG8qFzkOcHxDyzG+sNL0cMipAxhpMX7qIcYcZFoLYkQRQHpOZKZCIAdNTfPGJ7M4cxGM0V+Uuirjyn+KAPJwNElwmPpX8sTQyEqlIlEwVjFXBpz28N5RAGN2zzCzEjD8NVYQJ2QyHj0gfWe',
'fakePassword', 'fakePassword',
); );

View file

@ -7,7 +7,7 @@ it('Legacy HD Breadwallet works', async () => {
console.error('process.env.HD_MNEMONIC_BREAD not set, skipped'); console.error('process.env.HD_MNEMONIC_BREAD not set, skipped');
return; return;
} }
let hdBread = new HDLegacyBreadwalletWallet(); const hdBread = new HDLegacyBreadwalletWallet();
hdBread.setSecret(process.env.HD_MNEMONIC_BREAD); hdBread.setSecret(process.env.HD_MNEMONIC_BREAD);
assert.strictEqual(hdBread.validateMnemonic(), true); assert.strictEqual(hdBread.validateMnemonic(), true);

View file

@ -1,10 +1,10 @@
/* global describe, it */ /* global describe, it */
import { HDLegacyElectrumSeedP2PKHWallet } from '../../class'; import { HDLegacyElectrumSeedP2PKHWallet } from '../../class';
let assert = require('assert'); const assert = require('assert');
describe('HDLegacyElectrumSeedP2PKHWallet', () => { describe('HDLegacyElectrumSeedP2PKHWallet', () => {
it('can import mnemonics and generate addresses and WIFs', async function() { it('can import mnemonics and generate addresses and WIFs', async function () {
let hd = new HDLegacyElectrumSeedP2PKHWallet(); const hd = new HDLegacyElectrumSeedP2PKHWallet();
hd.setSecret('receive happy wash prosper update pet neck acid try profit proud hungry '); hd.setSecret('receive happy wash prosper update pet neck acid try profit proud hungry ');
assert.ok(hd.validateMnemonic()); assert.ok(hd.validateMnemonic());
assert.strictEqual( assert.strictEqual(

View file

@ -8,7 +8,7 @@ it('Legacy HD (BIP44) works', async () => {
console.error('process.env.HD_MNEMONIC not set, skipped'); console.error('process.env.HD_MNEMONIC not set, skipped');
return; return;
} }
let hd = new HDLegacyP2PKHWallet(); const hd = new HDLegacyP2PKHWallet();
hd.setSecret(process.env.HD_MNEMONIC); hd.setSecret(process.env.HD_MNEMONIC);
assert.ok(hd.validateMnemonic()); assert.ok(hd.validateMnemonic());
@ -41,7 +41,7 @@ it.only('Legacy HD (BIP44) can create TX', async () => {
console.error('process.env.HD_MNEMONIC not set, skipped'); console.error('process.env.HD_MNEMONIC not set, skipped');
return; return;
} }
let hd = new HDLegacyP2PKHWallet(); const hd = new HDLegacyP2PKHWallet();
hd.setSecret(process.env.HD_MNEMONIC); hd.setSecret(process.env.HD_MNEMONIC);
assert.ok(hd.validateMnemonic()); assert.ok(hd.validateMnemonic());
@ -112,7 +112,7 @@ it.only('Legacy HD (BIP44) can create TX', async () => {
assert.strictEqual(tx.outs[0].value, 80000); // payee assert.strictEqual(tx.outs[0].value, 80000); // payee
assert.strictEqual(tx.outs[1].value, 19334); // change assert.strictEqual(tx.outs[1].value, 19334); // change
let toAddress = bitcoin.address.fromOutputScript(tx.outs[0].script); let toAddress = bitcoin.address.fromOutputScript(tx.outs[0].script);
let changeAddress = bitcoin.address.fromOutputScript(tx.outs[1].script); const changeAddress = bitcoin.address.fromOutputScript(tx.outs[1].script);
assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress); assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress);
assert.strictEqual(hd._getInternalAddressByIndex(hd.next_free_change_address_index), changeAddress); assert.strictEqual(hd._getInternalAddressByIndex(hd.next_free_change_address_index), changeAddress);

Some files were not shown because too many files have changed in this diff Show more