mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-21 22:42:21 +01:00
REF: upgrade eslint, prettier, fix errors, reformat everything
This commit is contained in:
parent
97a19126bf
commit
71c8b74e92
107 changed files with 1854 additions and 2557 deletions
27
.eslintrc
27
.eslintrc
|
@ -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"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
12
BlueApp.js
12
BlueApp.js
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
193
BlueElectrum.js
193
BlueElectrum.js
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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/'))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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'];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
498
loc/ZAR_Afr.js
498
loc/ZAR_Afr.js
|
@ -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:',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
504
loc/ZAR_Xho.js
504
loc/ZAR_Xho.js
|
@ -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:',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
26
loc/ca.js
26
loc/ca.js
|
@ -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: {
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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
1119
package-lock.json
generated
File diff suppressed because it is too large
Load diff
33
package.json
33
package.json
|
@ -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",
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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}`,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -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');
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 }}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 (_) {
|
||||||
|
|
|
@ -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 (_) {
|
||||||
|
|
|
@ -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';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})()}
|
})()}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 = '';
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 />
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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: () => {},
|
||||||
|
|
|
@ -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: '',
|
||||||
|
|
|
@ -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}`}>
|
||||||
|
|
|
@ -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 />
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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: () => {},
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 />
|
||||||
|
|
2
shim.js
2
shim.js
|
@ -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 ? '*' : '';
|
||||||
}
|
}
|
||||||
|
|
|
@ -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');
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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++;
|
||||||
|
|
|
@ -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');
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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',
|
||||||
);
|
);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
Loading…
Add table
Reference in a new issue