mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 01:40:12 +01:00
REF: start transition to Electrum server
This commit is contained in:
parent
95c98db486
commit
240f2c35cb
@ -7,6 +7,7 @@ let EV = require('./events');
|
||||
let currency = require('./currency');
|
||||
let loc = require('./loc');
|
||||
let A = require('./analytics');
|
||||
let BlueElectrum = require('./BlueElectrum'); // eslint-disable-line
|
||||
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = new AppStorage();
|
||||
|
105
BlueElectrum.js
Normal file
105
BlueElectrum.js
Normal file
@ -0,0 +1,105 @@
|
||||
import { AsyncStorage } from 'react-native';
|
||||
const ElectrumClient = require('electrum-client');
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
let reverse = require('buffer-reverse');
|
||||
|
||||
const defaultPeer = { host: 'electrum.coinucopia.io', ssl: 50002, tcp: 50001, pruning: null, http: null, https: null };
|
||||
console.log('begin connection:', JSON.stringify(defaultPeer));
|
||||
|
||||
let mainClient = new ElectrumClient(defaultPeer.tcp, defaultPeer.host, 'tcp');
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
await mainClient.connect();
|
||||
const ver = await mainClient.server_version('2.7.11', '1.2');
|
||||
console.log('connected to ', ver);
|
||||
let peers = await mainClient.serverPeers_subscribe();
|
||||
// console.log('peers', peers);
|
||||
if (peers && peers.length > 0) {
|
||||
AsyncStorage.setItem('ELECTRUM_PEERS', JSON.stringify(peers));
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('bad connection:', JSON.stringify(defaultPeer));
|
||||
throw new Error();
|
||||
}
|
||||
})();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param address {String}
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
async function getBalanceByAddress(address) {
|
||||
let script = bitcoin.address.toOutputScript(address);
|
||||
let hash = bitcoin.crypto.sha256(script);
|
||||
let reversedHash = Buffer.from(reverse(hash));
|
||||
let balance = await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex'));
|
||||
balance.addr = address;
|
||||
return balance;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param address {String}
|
||||
* @returns {Promise<Array>}
|
||||
*/
|
||||
async function getTransactionsByAddress(address) {
|
||||
let script = bitcoin.address.toOutputScript(address);
|
||||
let hash = bitcoin.crypto.sha256(script);
|
||||
let reversedHash = Buffer.from(reverse(hash));
|
||||
let history = await mainClient.blockchainScripthash_getHistory(reversedHash.toString('hex'));
|
||||
return history;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param addresses {Array}
|
||||
* @returns {Promise<{balance: number, unconfirmed_balance: number}>}
|
||||
*/
|
||||
async function multiGetBalanceByAddress(addresses) {
|
||||
let balance = 0;
|
||||
let unconfirmedBalance = 0;
|
||||
for (let addr of addresses) {
|
||||
let b = await getBalanceByAddress(addr);
|
||||
|
||||
balance += b.confirmed;
|
||||
unconfirmedBalance += b.unconfirmed_balance;
|
||||
}
|
||||
|
||||
return { balance, unconfirmed_balance: unconfirmedBalance };
|
||||
}
|
||||
|
||||
module.exports.getBalanceByAddress = getBalanceByAddress;
|
||||
module.exports.getTransactionsByAddress = getTransactionsByAddress;
|
||||
module.exports.multiGetBalanceByAddress = multiGetBalanceByAddress;
|
||||
|
||||
module.exports.forceDisconnect = () => {
|
||||
mainClient.keepAlive = () => {}; // dirty hack to make it stop reconnecting
|
||||
mainClient.reconnect = () => {}; // dirty hack to make it stop reconnecting
|
||||
mainClient.close();
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
|
||||
|
||||
let addr4elect = 'bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej';
|
||||
let script = bitcoin.address.toOutputScript(addr4elect);
|
||||
let hash = bitcoin.crypto.sha256(script);
|
||||
let reversedHash = Buffer.from(hash.reverse());
|
||||
console.log(addr4elect, ' maps to ', reversedHash.toString('hex'));
|
||||
console.log(await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex')));
|
||||
|
||||
addr4elect = '1BWwXJH3q6PRsizBkSGm2Uw4Sz1urZ5sCj';
|
||||
script = bitcoin.address.toOutputScript(addr4elect);
|
||||
hash = bitcoin.crypto.sha256(script);
|
||||
reversedHash = Buffer.from(hash.reverse());
|
||||
console.log(addr4elect, ' maps to ', reversedHash.toString('hex'));
|
||||
console.log(await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex')));
|
||||
|
||||
// let peers = await mainClient.serverPeers_subscribe();
|
||||
// console.log(peers);
|
||||
mainClient.keepAlive = () => {}; // dirty hack to make it stop reconnecting
|
||||
mainClient.reconnect = () => {}; // dirty hack to make it stop reconnecting
|
||||
mainClient.close();
|
||||
// setTimeout(()=>process.exit(), 3000); */
|
64
Electrum.test.js
Normal file
64
Electrum.test.js
Normal file
@ -0,0 +1,64 @@
|
||||
/* global it, describe, jasmine */
|
||||
global.net = require('net');
|
||||
let BlueElectrum = require('./BlueElectrum');
|
||||
let assert = require('assert');
|
||||
|
||||
describe('Electrum', () => {
|
||||
it('ElectrumClient can connect and query', async () => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100 * 1000;
|
||||
const ElectrumClient = require('electrum-client');
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
// let bitcoin = require('bitcoinjs-lib');
|
||||
|
||||
const peer = { host: 'electrum.coinucopia.io', ssl: 50002, tcp: 50001, pruning: null, http: null, https: null };
|
||||
console.log('begin connection:', JSON.stringify(peer));
|
||||
let mainClient = new ElectrumClient(peer.tcp, peer.host, 'tcp');
|
||||
|
||||
try {
|
||||
await mainClient.connect();
|
||||
const ver = await mainClient.server_version('2.7.11', '1.2');
|
||||
console.log('connected to ', ver);
|
||||
} catch (e) {
|
||||
console.log('bad connection:', JSON.stringify(peer));
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
let addr4elect = 'bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej';
|
||||
let script = bitcoin.address.toOutputScript(addr4elect);
|
||||
let hash = bitcoin.crypto.sha256(script);
|
||||
let reversedHash = Buffer.from(hash.reverse());
|
||||
let balance = await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex'));
|
||||
assert.ok(balance.confirmed > 0);
|
||||
|
||||
addr4elect = '3GCvDBAktgQQtsbN6x5DYiQCMmgZ9Yk8BK';
|
||||
script = bitcoin.address.toOutputScript(addr4elect);
|
||||
hash = bitcoin.crypto.sha256(script);
|
||||
reversedHash = Buffer.from(hash.reverse());
|
||||
balance = await mainClient.blockchainScripthash_getBalance(reversedHash.toString('hex'));
|
||||
assert.ok(balance.confirmed === 51432);
|
||||
|
||||
// let peers = await mainClient.serverPeers_subscribe();
|
||||
// console.log(peers);
|
||||
mainClient.keepAlive = () => {}; // dirty hack to make it stop reconnecting
|
||||
mainClient.reconnect = () => {}; // dirty hack to make it stop reconnecting
|
||||
mainClient.close();
|
||||
// setTimeout(()=>process.exit(), 3000);
|
||||
});
|
||||
|
||||
it('BlueElectrum works', async function() {
|
||||
let address = '3GCvDBAktgQQtsbN6x5DYiQCMmgZ9Yk8BK';
|
||||
let balance = await BlueElectrum.getBalanceByAddress(address);
|
||||
assert.strictEqual(balance.confirmed, 51432);
|
||||
assert.strictEqual(balance.unconfirmed, 0);
|
||||
assert.strictEqual(balance.addr, address);
|
||||
|
||||
let txs = await BlueElectrum.getTransactionsByAddress(address);
|
||||
assert.strictEqual(txs.length, 1);
|
||||
for (let tx of txs) {
|
||||
assert.ok(tx.tx_hash);
|
||||
assert.ok(tx.height);
|
||||
}
|
||||
|
||||
BlueElectrum.forceDisconnect();
|
||||
});
|
||||
});
|
@ -1,8 +1,15 @@
|
||||
/* global it, jasmine */
|
||||
/* global it, jasmine, afterAll */
|
||||
import { SegwitP2SHWallet, SegwitBech32Wallet, HDSegwitP2SHWallet, HDLegacyBreadwalletWallet, HDLegacyP2PKHWallet } from './class';
|
||||
global.crypto = require('crypto'); // shall be used by tests under nodejs CLI, but not in RN environment
|
||||
let assert = require('assert');
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
|
||||
let BlueElectrum = require('./BlueElectrum'); // so it connects ASAP
|
||||
|
||||
afterAll(() => {
|
||||
// after all tests we close socket so the test suite can actually terminate
|
||||
return BlueElectrum.forceDisconnect();
|
||||
});
|
||||
|
||||
it('can convert witness to address', () => {
|
||||
let address = SegwitP2SHWallet.witnessToAddress('035c618df829af694cb99e664ce1b34f80ad2c3b49bcd0d9c0b1836c66b2d25fd8');
|
||||
@ -148,6 +155,30 @@ it('Segwit HD (BIP49) can fetch UTXO', 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) {
|
||||
console.error('process.env.HD_MNEMONIC_BIP49_MANY_TX not set, skipped');
|
||||
return;
|
||||
}
|
||||
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 90 * 1000;
|
||||
let hd = new HDSegwitP2SHWallet();
|
||||
hd.setSecret(process.env.HD_MNEMONIC_BIP49_MANY_TX);
|
||||
assert.ok(hd.validateMnemonic());
|
||||
let start = +new Date();
|
||||
await hd.fetchBalance();
|
||||
let end = +new Date();
|
||||
const took = (end - start) / 1000;
|
||||
took > 15 && console.warn('took', took, "sec to fetch huge HD wallet's balance");
|
||||
assert.strictEqual(hd.getBalance(), 0.00051432);
|
||||
|
||||
await hd.fetchUtxo();
|
||||
assert.ok(hd.utxo.length > 0);
|
||||
|
||||
await hd.fetchTransactions();
|
||||
assert.strictEqual(hd.getTransactions().length, 107);
|
||||
});
|
||||
|
||||
it('can work with malformed mnemonic', () => {
|
||||
let 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';
|
||||
|
@ -106,6 +106,7 @@ android {
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
multiDexEnabled true
|
||||
}
|
||||
splits {
|
||||
abi {
|
||||
@ -137,6 +138,7 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':react-native-tcp')
|
||||
implementation project(':@remobile_react-native-qrcode-local-image')
|
||||
implementation project(':react-native-image-picker')
|
||||
implementation project(':react-native-webview')
|
||||
@ -155,6 +157,7 @@ dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
|
||||
implementation "com.facebook.react:react-native:+" // From node_modules
|
||||
implementation 'com.android.support:multidex:1.0.3'
|
||||
}
|
||||
|
||||
// Run this once to be able to run the application with BUCK
|
||||
|
@ -3,6 +3,7 @@ package io.bluewallet.bluewallet;
|
||||
import android.app.Application;
|
||||
|
||||
import com.facebook.react.ReactApplication;
|
||||
import com.peel.react.TcpSocketsModule;
|
||||
import com.remobile.qrcodeLocalImage.RCTQRCodeLocalImagePackage;
|
||||
import com.imagepicker.ImagePickerPackage;
|
||||
import com.reactnativecommunity.webview.RNCWebViewPackage;
|
||||
@ -55,6 +56,7 @@ public class MainApplication extends Application implements ReactApplication {
|
||||
protected List<ReactPackage> getPackages() {
|
||||
return Arrays.<ReactPackage>asList(
|
||||
new MainReactPackage(),
|
||||
new TcpSocketsModule(),
|
||||
new RCTQRCodeLocalImagePackage(),
|
||||
new ImagePickerPackage(),
|
||||
new RNCWebViewPackage(),
|
||||
|
@ -1,4 +1,6 @@
|
||||
rootProject.name = 'BlueWallet'
|
||||
include ':react-native-tcp'
|
||||
project(':react-native-tcp').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-tcp/android')
|
||||
include ':@remobile_react-native-qrcode-local-image'
|
||||
project(':@remobile_react-native-qrcode-local-image').projectDir = new File(rootProject.projectDir, '../node_modules/@remobile/react-native-qrcode-local-image/android')
|
||||
include ':react-native-image-picker'
|
||||
|
@ -4,6 +4,7 @@ import { WatchOnlyWallet } from './watch-only-wallet';
|
||||
const bip39 = require('bip39');
|
||||
const BigNumber = require('bignumber.js');
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const BlueElectrum = require('../BlueElectrum');
|
||||
|
||||
export class AbstractHDWallet extends LegacyWallet {
|
||||
static type = 'abstract';
|
||||
@ -346,24 +347,69 @@ export class AbstractHDWallet extends LegacyWallet {
|
||||
|
||||
async fetchBalance() {
|
||||
try {
|
||||
const api = new Frisbee({ baseURI: 'https://www.blockonomics.co' });
|
||||
let response = await api.post('/api/balance', { body: JSON.stringify({ addr: this.getXpub() }) });
|
||||
// doing binary search for last used externa address
|
||||
|
||||
if (response && response.body && response.body.response) {
|
||||
this.balance = 0;
|
||||
this.unconfirmed_balance = 0;
|
||||
this.usedAddresses = [];
|
||||
for (let addr of response.body.response) {
|
||||
this.balance += addr.confirmed;
|
||||
this.unconfirmed_balance += addr.unconfirmed;
|
||||
this.usedAddresses.push(addr.addr);
|
||||
let that = this;
|
||||
|
||||
// refactor me
|
||||
// eslint-disable-next-line
|
||||
async function binarySearchIterationForInternalAddress(index, maxUsedIndex = 0, minUnusedIndex = 100500100, depth = 0) {
|
||||
if (depth >= 20) return maxUsedIndex + 1; // fail
|
||||
let txs = await BlueElectrum.getTransactionsByAddress(that._getInternalAddressByIndex(index));
|
||||
if (txs.length === 0) {
|
||||
minUnusedIndex = Math.min(minUnusedIndex, index); // set
|
||||
index = Math.round((index - maxUsedIndex) / 2 + maxUsedIndex);
|
||||
} else {
|
||||
maxUsedIndex = Math.max(maxUsedIndex, index); // set
|
||||
let txs2 = await BlueElectrum.getTransactionsByAddress(that._getInternalAddressByIndex(index + 1));
|
||||
if (txs2.length === 0) return index + 1; // thats our next free address
|
||||
|
||||
index = Math.round((minUnusedIndex - index) / 2 + index);
|
||||
}
|
||||
this.balance = new BigNumber(this.balance).dividedBy(100000000).toString() * 1;
|
||||
this.unconfirmed_balance = new BigNumber(this.unconfirmed_balance).dividedBy(100000000).toString() * 1;
|
||||
this._lastBalanceFetch = +new Date();
|
||||
} else {
|
||||
throw new Error('Could not fetch balance from API: ' + response.err);
|
||||
|
||||
return binarySearchIterationForInternalAddress(index, maxUsedIndex, minUnusedIndex, depth + 1);
|
||||
}
|
||||
|
||||
this.next_free_change_address_index = await binarySearchIterationForInternalAddress(100);
|
||||
|
||||
// refactor me
|
||||
// eslint-disable-next-line
|
||||
async function binarySearchIterationForExternalAddress(index, maxUsedIndex = 0, minUnusedIndex = 100500100, depth = 0) {
|
||||
if (depth >= 20) return maxUsedIndex + 1; // fail
|
||||
let txs = await BlueElectrum.getTransactionsByAddress(that._getExternalAddressByIndex(index));
|
||||
if (txs.length === 0) {
|
||||
minUnusedIndex = Math.min(minUnusedIndex, index); // set
|
||||
index = Math.round((index - maxUsedIndex) / 2 + maxUsedIndex);
|
||||
} else {
|
||||
maxUsedIndex = Math.max(maxUsedIndex, index); // set
|
||||
let txs2 = await BlueElectrum.getTransactionsByAddress(that._getExternalAddressByIndex(index + 1));
|
||||
if (txs2.length === 0) return index + 1; // thats our next free address
|
||||
|
||||
index = Math.round((minUnusedIndex - index) / 2 + index);
|
||||
}
|
||||
|
||||
return binarySearchIterationForExternalAddress(index, maxUsedIndex, minUnusedIndex, depth + 1);
|
||||
}
|
||||
|
||||
this.next_free_address_index = await binarySearchIterationForExternalAddress(100);
|
||||
|
||||
this.balance = 0;
|
||||
this.unconfirmed_balance = 0;
|
||||
this.usedAddresses = [];
|
||||
|
||||
// generating all involved addresses:
|
||||
for (let c = 0; c < this.next_free_address_index; c++) {
|
||||
this.usedAddresses.push(this._getExternalAddressByIndex(c));
|
||||
}
|
||||
for (let c = 0; c < this.next_free_change_address_index; c++) {
|
||||
this.usedAddresses.push(this._getInternalAddressByIndex(c));
|
||||
}
|
||||
|
||||
// finally fetching balance
|
||||
let balance = await BlueElectrum.multiGetBalanceByAddress(this.usedAddresses);
|
||||
this.balance = new BigNumber(balance.balance).dividedBy(100000000).toNumber();
|
||||
this.unconfirmed_balance = new BigNumber(balance.unconfirmed_balance).dividedBy(100000000).toNumber();
|
||||
this._lastBalanceFetch = +new Date();
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
|
||||
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
|
||||
@ -80,6 +79,7 @@
|
||||
ED2971652150620600B7C4FE /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED2971642150620600B7C4FE /* JavaScriptCore.framework */; };
|
||||
F21429E1449249038A7F3444 /* FontAwesome.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 334051161886419EA186F4BA /* FontAwesome.ttf */; };
|
||||
FBB34FB8F9B248A89346FE61 /* libRNDeviceInfo-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6EB3338E347F4AFAA8C85C04 /* libRNDeviceInfo-tvOS.a */; };
|
||||
34582CAA4AD140F7B80C961A /* libTcpSockets.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DF4E6C040764E4BA1ACC1EB /* libTcpSockets.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -613,6 +613,8 @@
|
||||
F9065403A26440679749C7AA /* BVLinearGradient.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = BVLinearGradient.xcodeproj; path = "../node_modules/react-native-linear-gradient/BVLinearGradient.xcodeproj"; sourceTree = "<group>"; };
|
||||
FC98DC24A81A463AB8B2E6B1 /* libRNImagePicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNImagePicker.a; sourceTree = "<group>"; };
|
||||
FD7977067E1A496F94D8B1B7 /* libRNDeviceInfo.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNDeviceInfo.a; sourceTree = "<group>"; };
|
||||
910283A2A9EB4D00902DE78E /* TcpSockets.xcodeproj */ = {isa = PBXFileReference; name = "TcpSockets.xcodeproj"; path = "../node_modules/react-native-tcp/ios/TcpSockets.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
|
||||
9DF4E6C040764E4BA1ACC1EB /* libTcpSockets.a */ = {isa = PBXFileReference; name = "libTcpSockets.a"; path = "libTcpSockets.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -661,6 +663,7 @@
|
||||
02DEC1C9F61B405E8E357B2E /* libRCTWKWebView.a in Frameworks */,
|
||||
A6E5EEC7A4B54F5A9C9D92FC /* libRNImagePicker.a in Frameworks */,
|
||||
C1056BF235EE4E23AAF21975 /* libRCTQRCodeLocalImage.a in Frameworks */,
|
||||
34582CAA4AD140F7B80C961A /* libTcpSockets.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -898,6 +901,7 @@
|
||||
E7173EC6B95B4981AD3D4C70 /* RCTWKWebView.xcodeproj */,
|
||||
1A03CFBC35DD4AC28FA4A619 /* RNImagePicker.xcodeproj */,
|
||||
7EA61BC8FF6E4AD2A67F1557 /* RCTQRCodeLocalImage.xcodeproj */,
|
||||
910283A2A9EB4D00902DE78E /* TcpSockets.xcodeproj */,
|
||||
);
|
||||
name = Libraries;
|
||||
sourceTree = "<group>";
|
||||
@ -1964,6 +1968,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-wkwebview-reborn/ios/RCTWKWebView",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios",
|
||||
"$(SRCROOT)/../node_modules/@remobile/react-native-qrcode-local-image/ios/RCTQRCodeLocalImage",
|
||||
"$(SRCROOT)/../node_modules/react-native-tcp/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = BlueWalletTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
@ -1992,6 +1997,7 @@
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@ -2028,6 +2034,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-wkwebview-reborn/ios/RCTWKWebView",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios",
|
||||
"$(SRCROOT)/../node_modules/@remobile/react-native-qrcode-local-image/ios/RCTQRCodeLocalImage",
|
||||
"$(SRCROOT)/../node_modules/react-native-tcp/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = BlueWalletTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
@ -2056,6 +2063,7 @@
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@ -2093,6 +2101,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-wkwebview-reborn/ios/RCTWKWebView",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios",
|
||||
"$(SRCROOT)/../node_modules/@remobile/react-native-qrcode-local-image/ios/RCTQRCodeLocalImage",
|
||||
"$(SRCROOT)/../node_modules/react-native-tcp/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = BlueWallet/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
@ -2134,6 +2143,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-wkwebview-reborn/ios/RCTWKWebView",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios",
|
||||
"$(SRCROOT)/../node_modules/@remobile/react-native-qrcode-local-image/ios/RCTQRCodeLocalImage",
|
||||
"$(SRCROOT)/../node_modules/react-native-tcp/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = BlueWallet/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
@ -2182,6 +2192,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-wkwebview-reborn/ios/RCTWKWebView",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios",
|
||||
"$(SRCROOT)/../node_modules/@remobile/react-native-qrcode-local-image/ios/RCTQRCodeLocalImage",
|
||||
"$(SRCROOT)/../node_modules/react-native-tcp/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = "BlueWallet-tvOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@ -2209,6 +2220,7 @@
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@ -2254,6 +2266,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-wkwebview-reborn/ios/RCTWKWebView",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios",
|
||||
"$(SRCROOT)/../node_modules/@remobile/react-native-qrcode-local-image/ios/RCTQRCodeLocalImage",
|
||||
"$(SRCROOT)/../node_modules/react-native-tcp/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = "BlueWallet-tvOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
@ -2281,6 +2294,7 @@
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@ -2325,6 +2339,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-wkwebview-reborn/ios/RCTWKWebView",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios",
|
||||
"$(SRCROOT)/../node_modules/@remobile/react-native-qrcode-local-image/ios/RCTQRCodeLocalImage",
|
||||
"$(SRCROOT)/../node_modules/react-native-tcp/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = "BlueWallet-tvOSTests/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
@ -2352,6 +2367,7 @@
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
@ -2396,6 +2412,7 @@
|
||||
"$(SRCROOT)/../node_modules/react-native-wkwebview-reborn/ios/RCTWKWebView",
|
||||
"$(SRCROOT)/../node_modules/react-native-image-picker/ios",
|
||||
"$(SRCROOT)/../node_modules/@remobile/react-native-qrcode-local-image/ios/RCTQRCodeLocalImage",
|
||||
"$(SRCROOT)/../node_modules/react-native-tcp/ios/**",
|
||||
);
|
||||
INFOPLIST_FILE = "BlueWallet-tvOSTests/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
@ -2423,6 +2440,7 @@
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
"\"$(SRCROOT)/$(TARGET_NAME)\"",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
|
49
package-lock.json
generated
49
package-lock.json
generated
@ -3004,8 +3004,7 @@
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
||||
"optional": true
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
|
||||
},
|
||||
"constants-browserify": {
|
||||
"version": "1.0.0",
|
||||
@ -3468,6 +3467,15 @@
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.105.tgz",
|
||||
"integrity": "sha512-MWZZTThmQR82yzSPOn0BJ2ayZL1l7QyQpS22Frkxn1se9ZJ1WlSwnH8/CeBVhv4IStRxUDBvypeNy2dqsKR6sQ=="
|
||||
},
|
||||
"electrum-client": {
|
||||
"version": "git+https://github.com/Overtorment/node-electrum-client.git#59712b3b7dbe666431eeb5649d6f6541529d386a",
|
||||
"from": "git+https://github.com/Overtorment/node-electrum-client.git"
|
||||
},
|
||||
"electrum-host-parse": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/electrum-host-parse/-/electrum-host-parse-0.1.1.tgz",
|
||||
"integrity": "sha512-N1ua6Xc5aMcVWPqxlIyiSV/tDGlbGP+S4bIR6KKGDv227VnzXibcin+4t25b5spjDmhfbbk0rIqV1T3MV5WlBQ=="
|
||||
},
|
||||
"elliptic": {
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz",
|
||||
@ -9665,7 +9673,6 @@
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
|
||||
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.0"
|
||||
@ -9674,8 +9681,7 @@
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
|
||||
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
|
||||
"optional": true
|
||||
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -11763,6 +11769,39 @@
|
||||
"prop-types": "^15.6.1"
|
||||
}
|
||||
},
|
||||
"react-native-tcp": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-tcp/-/react-native-tcp-3.3.0.tgz",
|
||||
"integrity": "sha512-WAiL3IGhVxvmM0iw7/5ZRzdkiJBfBbLoFKNaHLJIsTZVqD/N5ZHUlJMjIQ+RrmB/f5nJ82bUEZ2vPCxe+rlNqQ==",
|
||||
"requires": {
|
||||
"base64-js": "0.0.8",
|
||||
"buffer": "^5.0.0",
|
||||
"events": "^1.0.2",
|
||||
"ip-regex": "^1.0.3",
|
||||
"process": "^0.11.9",
|
||||
"util": "^0.10.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"base64-js": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
|
||||
"integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg="
|
||||
},
|
||||
"ip-regex": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz",
|
||||
"integrity": "sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0="
|
||||
},
|
||||
"util": {
|
||||
"version": "0.10.4",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
|
||||
"integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
|
||||
"requires": {
|
||||
"inherits": "2.0.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-native-vector-icons": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-6.2.0.tgz",
|
||||
|
@ -45,6 +45,8 @@
|
||||
"buffer-reverse": "^1.0.1",
|
||||
"crypto-js": "^3.1.9-1",
|
||||
"dayjs": "^1.8.0",
|
||||
"electrum-client": "git+https://github.com/Overtorment/node-electrum-client.git",
|
||||
"electrum-host-parse": "^0.1.1",
|
||||
"eslint-config-prettier": "^3.6.0",
|
||||
"eslint-config-standard": "^12.0.0",
|
||||
"eslint-config-standard-react": "^7.0.2",
|
||||
@ -83,6 +85,7 @@
|
||||
"react-native-snap-carousel": "^3.7.5",
|
||||
"react-native-sortable-list": "0.0.22",
|
||||
"react-native-svg": "^9.0.4",
|
||||
"react-native-tcp": "^3.3.0",
|
||||
"react-native-vector-icons": "^6.2.0",
|
||||
"react-native-webview": "^3.2.1",
|
||||
"react-native-wkwebview-reborn": "^2.0.0",
|
||||
|
@ -5,6 +5,8 @@ import PropTypes from 'prop-types';
|
||||
import { SegwitP2SHWallet, LegacyWallet, HDSegwitP2SHWallet } from '../class';
|
||||
let BigNumber = require('bignumber.js');
|
||||
let encryption = require('../encryption');
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
let BlueElectrum = require('../BlueElectrum');
|
||||
|
||||
export default class Selftest extends Component {
|
||||
static navigationOptions = () => ({
|
||||
@ -42,6 +44,20 @@ export default class Selftest extends Component {
|
||||
|
||||
//
|
||||
|
||||
if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
|
||||
let addr4elect = '3GCvDBAktgQQtsbN6x5DYiQCMmgZ9Yk8BK';
|
||||
let electrumBalance = await BlueElectrum.getBalanceByAddress(addr4elect);
|
||||
if (electrumBalance.confirmed !== 51432)
|
||||
throw new Error('BlueElectrum getBalanceByAddress failure, got ' + JSON.stringify(electrumBalance));
|
||||
|
||||
let electrumTxs = await BlueElectrum.getTransactionsByAddress(addr4elect);
|
||||
if (electrumTxs.length !== 1) throw new Error('BlueElectrum getTransactionsByAddress failure, got ' + JSON.stringify(electrumTxs));
|
||||
} else {
|
||||
console.warn('skipping RN-specific test');
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
let l = new LegacyWallet();
|
||||
l.setSecret('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct');
|
||||
if (l.getAddress() !== '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31') {
|
||||
@ -158,7 +174,6 @@ export default class Selftest extends Component {
|
||||
];
|
||||
|
||||
let tx = l.createTx(utxo, 0.001, 0.0001, '1QHf8Gp3wfmFiSdEX4FtrssCGR68diN1cj');
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
let txDecoded = bitcoin.Transaction.fromHex(tx);
|
||||
let txid = txDecoded.getId();
|
||||
|
||||
|
@ -82,7 +82,10 @@ export default class WalletsList extends Component {
|
||||
// more responsive
|
||||
let noErr = true;
|
||||
try {
|
||||
let balanceStart = +new Date();
|
||||
await BlueApp.fetchWalletBalances(that.lastSnappedTo || 0);
|
||||
let balanceEnd = +new Date();
|
||||
console.log('fetch balance took', (balanceEnd - balanceStart) / 1000, 'sec');
|
||||
let start = +new Date();
|
||||
await BlueApp.fetchWalletTransactions(that.lastSnappedTo || 0);
|
||||
let end = +new Date();
|
||||
|
@ -150,9 +150,12 @@ export default class WalletTransactions extends Component {
|
||||
try {
|
||||
/** @type {LegacyWallet} */
|
||||
let wallet = that.state.wallet;
|
||||
let balanceStart = +new Date();
|
||||
const oldBalance = wallet.getBalance();
|
||||
await wallet.fetchBalance();
|
||||
if (oldBalance !== wallet.getBalance()) smthChanged = true;
|
||||
let balanceEnd = +new Date();
|
||||
console.log(wallet.getLabel(), 'fetch balance took', (balanceEnd - balanceStart) / 1000, 'sec');
|
||||
let start = +new Date();
|
||||
const oldTxLen = wallet.getTransactions().length;
|
||||
await wallet.fetchTransactions();
|
||||
|
Loading…
Reference in New Issue
Block a user