mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-01-18 21:35:21 +01:00
Merge branch 'master' into master
This commit is contained in:
commit
7bb7ca9948
@ -1,5 +1,4 @@
|
||||
/* eslint react/prop-types: 0 */
|
||||
/* global alert */
|
||||
/** @type {AppStorage} */
|
||||
import React, { Component } from 'react';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
@ -29,13 +28,11 @@ import { LightningCustodianWallet } from './class';
|
||||
import Carousel from 'react-native-snap-carousel';
|
||||
import { BitcoinUnit } from './models/bitcoinUnits';
|
||||
import NavigationService from './NavigationService';
|
||||
import ImagePicker from 'react-native-image-picker';
|
||||
import WalletGradient from './class/walletGradient';
|
||||
import ToolTip from 'react-native-tooltip';
|
||||
import { BlurView } from '@react-native-community/blur';
|
||||
import showPopupMenu from 'react-native-popup-menu-android';
|
||||
import NetworkTransactionFees, { NetworkTransactionFeeType } from './models/networkTransactionFees';
|
||||
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
|
||||
let loc = require('./loc/');
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('./BlueApp');
|
||||
@ -1986,29 +1983,8 @@ export class BlueAddressInput extends Component {
|
||||
<TouchableOpacity
|
||||
disabled={this.props.isLoading}
|
||||
onPress={() => {
|
||||
NavigationService.navigate('ScanQrAddress', { onBarScanned: this.props.onBarScanned });
|
||||
Keyboard.dismiss();
|
||||
ImagePicker.showImagePicker(
|
||||
{
|
||||
title: null,
|
||||
mediaType: 'photo',
|
||||
takePhotoButtonTitle: null,
|
||||
customButtons: [{ name: 'navigatetoQRScan', title: 'Use Camera' }],
|
||||
},
|
||||
response => {
|
||||
if (response.customButton) {
|
||||
NavigationService.navigate('ScanQrAddress', { onBarScanned: this.props.onBarScanned });
|
||||
} else if (response.uri) {
|
||||
const uri = response.uri.toString().replace('file://', '');
|
||||
LocalQRCode.decode(uri, (error, result) => {
|
||||
if (!error) {
|
||||
this.props.onBarScanned(result);
|
||||
} else {
|
||||
alert('The selected image does not contain a QR Code.');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}}
|
||||
style={{
|
||||
height: 36,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
import { AppStorage } from './class';
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const ElectrumClient = require('electrum-client');
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
let reverse = require('buffer-reverse');
|
||||
let BigNumber = require('bignumber.js');
|
||||
|
||||
|
@ -36,7 +36,7 @@ import receiveDetails from './screen/receive/details';
|
||||
import setReceiveAmount from './screen/receive/receiveAmount';
|
||||
|
||||
import sendDetails from './screen/send/details';
|
||||
import sendScanQrAddress from './screen/send/scanQrAddress';
|
||||
import ScanQRCode from './screen/send/scanQrAddress';
|
||||
import sendCreate from './screen/send/create';
|
||||
import Confirm from './screen/send/confirm';
|
||||
import Success from './screen/send/success';
|
||||
@ -288,7 +288,7 @@ const MainBottomTabs = createStackNavigator(
|
||||
},
|
||||
},
|
||||
ScanQrAddress: {
|
||||
screen: sendScanQrAddress,
|
||||
screen: ScanQRCode,
|
||||
},
|
||||
LappBrowser: {
|
||||
screen: LappBrowser,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { LegacyWallet } from './legacy-wallet';
|
||||
import Frisbee from 'frisbee';
|
||||
const bip39 = require('bip39');
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const bip39 = require('bip39');
|
||||
const BlueElectrum = require('../BlueElectrum');
|
||||
|
||||
export class AbstractHDWallet extends LegacyWallet {
|
||||
@ -498,8 +498,7 @@ export class AbstractHDWallet extends LegacyWallet {
|
||||
unspent.vout = unspent.tx_output_n;
|
||||
unspent.amount = unspent.value;
|
||||
|
||||
let chunksIn = bitcoin.script.decompile(Buffer.from(unspent.script, 'hex'));
|
||||
unspent.address = bitcoin.address.fromOutputScript(chunksIn);
|
||||
unspent.address = bitcoin.address.fromOutputScript(Buffer.from(unspent.script, 'hex'));
|
||||
utxos.push(unspent);
|
||||
}
|
||||
} catch (err) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { AbstractHDWallet } from './abstract-hd-wallet';
|
||||
import Frisbee from 'frisbee';
|
||||
import bitcoin from 'bitcoinjs-lib';
|
||||
import bip39 from 'bip39';
|
||||
const bip32 = require('bip32');
|
||||
const bitcoinjs = require('bitcoinjs-lib');
|
||||
|
||||
/**
|
||||
* HD Wallet (BIP39).
|
||||
@ -22,7 +23,7 @@ export class HDLegacyBreadwalletWallet extends AbstractHDWallet {
|
||||
}
|
||||
const mnemonic = this.secret;
|
||||
const seed = bip39.mnemonicToSeed(mnemonic);
|
||||
const root = bitcoin.HDNode.fromSeedBuffer(seed);
|
||||
const root = bip32.fromSeed(seed);
|
||||
|
||||
const path = "m/0'";
|
||||
const child = root.derivePath(path).neutered();
|
||||
@ -36,12 +37,16 @@ export class HDLegacyBreadwalletWallet extends AbstractHDWallet {
|
||||
if (this.external_addresses_cache[index]) return this.external_addresses_cache[index]; // cache hit
|
||||
const mnemonic = this.secret;
|
||||
const seed = bip39.mnemonicToSeed(mnemonic);
|
||||
const root = bitcoin.HDNode.fromSeedBuffer(seed);
|
||||
const root = bip32.fromSeed(seed);
|
||||
|
||||
const path = "m/0'/0/" + index;
|
||||
const child = root.derivePath(path);
|
||||
|
||||
return (this.external_addresses_cache[index] = child.getAddress());
|
||||
const address = bitcoinjs.payments.p2pkh({
|
||||
pubkey: child.publicKey,
|
||||
}).address;
|
||||
|
||||
return (this.external_addresses_cache[index] = address);
|
||||
}
|
||||
|
||||
_getInternalAddressByIndex(index) {
|
||||
@ -49,12 +54,16 @@ export class HDLegacyBreadwalletWallet extends AbstractHDWallet {
|
||||
if (this.internal_addresses_cache[index]) return this.internal_addresses_cache[index]; // cache hit
|
||||
const mnemonic = this.secret;
|
||||
const seed = bip39.mnemonicToSeed(mnemonic);
|
||||
const root = bitcoin.HDNode.fromSeedBuffer(seed);
|
||||
const root = bip32.fromSeed(seed);
|
||||
|
||||
const path = "m/0'/1/" + index;
|
||||
const child = root.derivePath(path);
|
||||
|
||||
return (this.internal_addresses_cache[index] = child.getAddress());
|
||||
const address = bitcoinjs.payments.p2pkh({
|
||||
pubkey: child.publicKey,
|
||||
}).address;
|
||||
|
||||
return (this.internal_addresses_cache[index] = address);
|
||||
}
|
||||
|
||||
_getExternalWIFByIndex(index) {
|
||||
@ -75,7 +84,7 @@ export class HDLegacyBreadwalletWallet extends AbstractHDWallet {
|
||||
_getWIFByIndex(internal, index) {
|
||||
const mnemonic = this.secret;
|
||||
const seed = bip39.mnemonicToSeed(mnemonic);
|
||||
const root = bitcoin.HDNode.fromSeedBuffer(seed);
|
||||
const root = bitcoinjs.bip32.fromSeed(seed);
|
||||
const path = `m/0'/${internal ? 1 : 0}/${index}`;
|
||||
const child = root.derivePath(path);
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { AbstractHDWallet } from './abstract-hd-wallet';
|
||||
import bitcoin from 'bitcoinjs-lib';
|
||||
import bip39 from 'bip39';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import signer from '../models/signer';
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const HDNode = require('bip32');
|
||||
|
||||
/**
|
||||
* HD Wallet (BIP39).
|
||||
@ -23,7 +24,7 @@ export class HDLegacyP2PKHWallet extends AbstractHDWallet {
|
||||
}
|
||||
const mnemonic = this.secret;
|
||||
const seed = bip39.mnemonicToSeed(mnemonic);
|
||||
const root = bitcoin.HDNode.fromSeedBuffer(seed);
|
||||
const root = bitcoin.bip32.fromSeed(seed);
|
||||
|
||||
const path = "m/44'/0'/0'";
|
||||
const child = root.derivePath(path).neutered();
|
||||
@ -50,22 +51,22 @@ export class HDLegacyP2PKHWallet extends AbstractHDWallet {
|
||||
_getWIFByIndex(internal, index) {
|
||||
const mnemonic = this.secret;
|
||||
const seed = bip39.mnemonicToSeed(mnemonic);
|
||||
const root = bitcoin.HDNode.fromSeedBuffer(seed);
|
||||
|
||||
const root = HDNode.fromSeed(seed);
|
||||
const path = `m/44'/0'/0'/${internal ? 1 : 0}/${index}`;
|
||||
const child = root.derivePath(path);
|
||||
|
||||
return child.keyPair.toWIF();
|
||||
return child.toWIF();
|
||||
}
|
||||
|
||||
_getExternalAddressByIndex(index) {
|
||||
index = index * 1; // cast to int
|
||||
if (this.external_addresses_cache[index]) return this.external_addresses_cache[index]; // cache hit
|
||||
|
||||
const node = bitcoin.HDNode.fromBase58(this.getXpub());
|
||||
const address = node
|
||||
.derive(0)
|
||||
.derive(index)
|
||||
.getAddress();
|
||||
const node = bitcoin.bip32.fromBase58(this.getXpub());
|
||||
const address = bitcoin.payments.p2pkh({
|
||||
pubkey: node.derive(0).derive(index).publicKey,
|
||||
}).address;
|
||||
|
||||
return (this.external_addresses_cache[index] = address);
|
||||
}
|
||||
@ -74,11 +75,10 @@ export class HDLegacyP2PKHWallet extends AbstractHDWallet {
|
||||
index = index * 1; // cast to int
|
||||
if (this.internal_addresses_cache[index]) return this.internal_addresses_cache[index]; // cache hit
|
||||
|
||||
const node = bitcoin.HDNode.fromBase58(this.getXpub());
|
||||
const address = node
|
||||
.derive(1)
|
||||
.derive(index)
|
||||
.getAddress();
|
||||
const node = bitcoin.bip32.fromBase58(this.getXpub());
|
||||
const address = bitcoin.payments.p2pkh({
|
||||
pubkey: node.derive(1).derive(index).publicKey,
|
||||
}).address;
|
||||
|
||||
return (this.internal_addresses_cache[index] = address);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { HDSegwitBech32Wallet, SegwitBech32Wallet } from './';
|
||||
const bitcoin = require('bitcoinjs5');
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const BlueElectrum = require('../BlueElectrum');
|
||||
const reverse = require('buffer-reverse');
|
||||
const BigNumber = require('bignumber.js');
|
||||
|
@ -3,8 +3,8 @@ import { NativeModules } from 'react-native';
|
||||
import bip39 from 'bip39';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import b58 from 'bs58check';
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const BlueElectrum = require('../BlueElectrum');
|
||||
const bitcoin5 = require('bitcoinjs5');
|
||||
const HDNode = require('bip32');
|
||||
const coinSelectAccumulative = require('coinselect/accumulative');
|
||||
const coinSelectSplit = require('coinselect/split');
|
||||
@ -693,20 +693,28 @@ export class HDSegwitBech32Wallet extends AbstractHDWallet {
|
||||
throw new Error('Not enough balance. Try sending smaller amount');
|
||||
}
|
||||
|
||||
let txb = new bitcoin5.TransactionBuilder();
|
||||
let psbt = new bitcoin.Psbt();
|
||||
|
||||
let c = 0;
|
||||
let keypairs = {};
|
||||
let values = {};
|
||||
|
||||
inputs.forEach(input => {
|
||||
const keyPair = bitcoin5.ECPair.fromWIF(this._getWifForAddress(input.address));
|
||||
const keyPair = bitcoin.ECPair.fromWIF(this._getWifForAddress(input.address));
|
||||
keypairs[c] = keyPair;
|
||||
values[c] = input.value;
|
||||
c++;
|
||||
if (!input.address || !this._getWifForAddress(input.address)) throw new Error('Internal error: no address or WIF to sign input');
|
||||
const p2wpkh = bitcoin5.payments.p2wpkh({ pubkey: keyPair.publicKey });
|
||||
txb.addInput(input.txId, input.vout, sequence, p2wpkh.output); // NOTE: provide the prevOutScript!
|
||||
const p2wpkh = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey });
|
||||
psbt.addInput({
|
||||
hash: input.txId,
|
||||
index: input.vout,
|
||||
sequence,
|
||||
witnessUtxo: {
|
||||
script: p2wpkh.output,
|
||||
value: input.value,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
outputs.forEach(output => {
|
||||
@ -715,14 +723,17 @@ export class HDSegwitBech32Wallet extends AbstractHDWallet {
|
||||
output.address = changeAddress;
|
||||
}
|
||||
|
||||
txb.addOutput(output.address, output.value);
|
||||
psbt.addOutput({
|
||||
address: output.address,
|
||||
value: output.value,
|
||||
});
|
||||
});
|
||||
|
||||
for (let cc = 0; cc < c; cc++) {
|
||||
txb.sign(cc, keypairs[cc], null, null, values[cc]); // NOTE: no redeem script
|
||||
psbt.signInput(cc, keypairs[cc]);
|
||||
}
|
||||
|
||||
const tx = txb.build();
|
||||
const tx = psbt.finalizeAllInputs().extractTransaction();
|
||||
return { tx, inputs, outputs, fee };
|
||||
}
|
||||
|
||||
@ -733,7 +744,7 @@ export class HDSegwitBech32Wallet extends AbstractHDWallet {
|
||||
* @returns {String}
|
||||
*/
|
||||
static _nodeToBech32SegwitAddress(hdNode) {
|
||||
return bitcoin5.payments.p2wpkh({
|
||||
return bitcoin.payments.p2wpkh({
|
||||
pubkey: hdNode.publicKey,
|
||||
}).address;
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import b58 from 'bs58check';
|
||||
import signer from '../models/signer';
|
||||
import { BitcoinUnit } from '../models/bitcoinUnits';
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const bitcoin5 = require('bitcoinjs5');
|
||||
const HDNode = require('bip32');
|
||||
|
||||
const { RNRandomBytes } = NativeModules;
|
||||
@ -19,6 +18,7 @@ const { RNRandomBytes } = NativeModules;
|
||||
*/
|
||||
function ypubToXpub(ypub) {
|
||||
let data = b58.decode(ypub);
|
||||
if (data.readUInt32BE() !== 0x049d7cb2) throw new Error('Not a valid ypub extended key!');
|
||||
data = data.slice(4);
|
||||
data = Buffer.concat([Buffer.from('0488b21e', 'hex'), data]);
|
||||
|
||||
@ -31,8 +31,8 @@ function ypubToXpub(ypub) {
|
||||
* @returns {String}
|
||||
*/
|
||||
function nodeToP2shSegwitAddress(hdNode) {
|
||||
const { address } = bitcoin5.payments.p2sh({
|
||||
redeem: bitcoin5.payments.p2wpkh({ pubkey: hdNode.publicKey }),
|
||||
const { address } = bitcoin.payments.p2sh({
|
||||
redeem: bitcoin.payments.p2wpkh({ pubkey: hdNode.publicKey }),
|
||||
});
|
||||
return address;
|
||||
}
|
||||
@ -95,11 +95,11 @@ export class HDSegwitP2SHWallet extends AbstractHDWallet {
|
||||
_getWIFByIndex(internal, index) {
|
||||
const mnemonic = this.secret;
|
||||
const seed = bip39.mnemonicToSeed(mnemonic);
|
||||
const root = bitcoin.HDNode.fromSeedBuffer(seed);
|
||||
const root = bitcoin.bip32.fromSeed(seed);
|
||||
const path = `m/49'/0'/0'/${internal ? 1 : 0}/${index}`;
|
||||
const child = root.derivePath(path);
|
||||
|
||||
return child.keyPair.toWIF();
|
||||
return bitcoin.ECPair.fromPrivateKey(child.privateKey).toWIF();
|
||||
}
|
||||
|
||||
_getExternalAddressByIndex(index) {
|
||||
|
@ -3,9 +3,9 @@ import { SegwitBech32Wallet } from './';
|
||||
import { useBlockcypherTokens } from './constants';
|
||||
import Frisbee from 'frisbee';
|
||||
import { NativeModules } from 'react-native';
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const { RNRandomBytes } = NativeModules;
|
||||
const BigNumber = require('bignumber.js');
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const signer = require('../models/signer');
|
||||
const BlueElectrum = require('../BlueElectrum');
|
||||
|
||||
@ -85,7 +85,9 @@ export class LegacyWallet extends AbstractWallet {
|
||||
let address;
|
||||
try {
|
||||
let keyPair = bitcoin.ECPair.fromWIF(this.secret);
|
||||
address = keyPair.getAddress();
|
||||
address = bitcoin.payments.p2pkh({
|
||||
pubkey: keyPair.publicKey,
|
||||
}).address;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
|
@ -10,9 +10,9 @@ export class SegwitBech32Wallet extends LegacyWallet {
|
||||
let address;
|
||||
try {
|
||||
let keyPair = bitcoin.ECPair.fromWIF(this.secret);
|
||||
let pubKey = keyPair.getPublicKeyBuffer();
|
||||
let scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(pubKey));
|
||||
address = bitcoin.address.fromOutputScript(scriptPubKey);
|
||||
address = bitcoin.payments.p2wpkh({
|
||||
pubkey: keyPair.publicKey,
|
||||
}).address;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
@ -23,13 +23,17 @@ export class SegwitBech32Wallet extends LegacyWallet {
|
||||
|
||||
static witnessToAddress(witness) {
|
||||
const pubKey = Buffer.from(witness, 'hex');
|
||||
const pubKeyHash = bitcoin.crypto.hash160(pubKey);
|
||||
const scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(pubKeyHash);
|
||||
return bitcoin.address.fromOutputScript(scriptPubKey, bitcoin.networks.bitcoin);
|
||||
return bitcoin.payments.p2wpkh({
|
||||
pubkey: pubKey,
|
||||
network: bitcoin.networks.bitcoin,
|
||||
}).address;
|
||||
}
|
||||
|
||||
static scriptPubKeyToAddress(scriptPubKey) {
|
||||
const scriptPubKey2 = Buffer.from(scriptPubKey, 'hex');
|
||||
return bitcoin.address.fromOutputScript(scriptPubKey2, bitcoin.networks.bitcoin);
|
||||
return bitcoin.payments.p2wpkh({
|
||||
output: scriptPubKey2,
|
||||
network: bitcoin.networks.bitcoin,
|
||||
}).address;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,21 @@ const bitcoin = require('bitcoinjs-lib');
|
||||
const signer = require('../models/signer');
|
||||
const BigNumber = require('bignumber.js');
|
||||
|
||||
/**
|
||||
* Creates Segwit P2SH Bitcoin address
|
||||
* @param pubkey
|
||||
* @param network
|
||||
* @returns {String}
|
||||
*/
|
||||
function pubkeyToP2shSegwitAddress(pubkey, network) {
|
||||
network = network || bitcoin.networks.bitcoin;
|
||||
const { address } = bitcoin.payments.p2sh({
|
||||
redeem: bitcoin.payments.p2wpkh({ pubkey, network }),
|
||||
network,
|
||||
});
|
||||
return address;
|
||||
}
|
||||
|
||||
export class SegwitP2SHWallet extends LegacyWallet {
|
||||
static type = 'segwitP2SH';
|
||||
static typeReadable = 'SegWit (P2SH)';
|
||||
@ -13,11 +28,7 @@ export class SegwitP2SHWallet extends LegacyWallet {
|
||||
|
||||
static witnessToAddress(witness) {
|
||||
const pubKey = Buffer.from(witness, 'hex');
|
||||
const pubKeyHash = bitcoin.crypto.hash160(pubKey);
|
||||
const redeemScript = bitcoin.script.witnessPubKeyHash.output.encode(pubKeyHash);
|
||||
const redeemScriptHash = bitcoin.crypto.hash160(redeemScript);
|
||||
const scriptPubkey = bitcoin.script.scriptHash.output.encode(redeemScriptHash);
|
||||
return bitcoin.address.fromOutputScript(scriptPubkey, bitcoin.networks.bitcoin);
|
||||
return pubkeyToP2shSegwitAddress(pubKey);
|
||||
}
|
||||
|
||||
getAddress() {
|
||||
@ -25,14 +36,12 @@ export class SegwitP2SHWallet extends LegacyWallet {
|
||||
let address;
|
||||
try {
|
||||
let keyPair = bitcoin.ECPair.fromWIF(this.secret);
|
||||
let pubKey = keyPair.getPublicKeyBuffer();
|
||||
let pubKey = keyPair.publicKey;
|
||||
if (!keyPair.compressed) {
|
||||
console.warn('only compressed public keys are good for segwit');
|
||||
return false;
|
||||
}
|
||||
let witnessScript = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(pubKey));
|
||||
let scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(witnessScript));
|
||||
address = bitcoin.address.fromOutputScript(scriptPubKey);
|
||||
address = pubkeyToP2shSegwitAddress(pubKey);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1155,7 +1155,7 @@
|
||||
PROVISIONING_PROFILE_SPECIFIER = "io.bluewallet.bluewallet AppStore";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "BlueWallet-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
@ -1188,7 +1188,7 @@
|
||||
PRODUCT_NAME = BlueWallet;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "io.bluewallet.bluewallet AppStore";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "BlueWallet-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
|
@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@ -14,26 +14,10 @@
|
||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon" translatesAutoresizingMaskIntoConstraints="NO" id="5GZ-ze-kHb">
|
||||
<rect key="frame" x="154" y="184" width="173" height="112"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="112" id="Zm5-a8-A8d"/>
|
||||
<constraint firstAttribute="width" constant="173" id="t2s-74-qaQ"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="5GZ-ze-kHb" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="UkL-ek-FgS"/>
|
||||
<constraint firstItem="5GZ-ze-kHb" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="mWu-9a-P4V"/>
|
||||
</constraints>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="547.20000000000005" y="454.27286356821594"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="icon" width="512" height="512"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
@ -86,17 +86,17 @@ PODS:
|
||||
- React-jsinspector (0.60.5)
|
||||
- react-native-blur (0.8.0):
|
||||
- React
|
||||
- react-native-camera (2.11.1):
|
||||
- react-native-camera (3.4.0):
|
||||
- React
|
||||
- react-native-camera/RCT (= 2.11.1)
|
||||
- react-native-camera/RN (= 2.11.1)
|
||||
- react-native-camera/RCT (2.11.1):
|
||||
- react-native-camera/RCT (= 3.4.0)
|
||||
- react-native-camera/RN (= 3.4.0)
|
||||
- react-native-camera/RCT (3.4.0):
|
||||
- React
|
||||
- react-native-camera/RN (2.11.1):
|
||||
- react-native-camera/RN (3.4.0):
|
||||
- React
|
||||
- react-native-haptic-feedback (1.7.1):
|
||||
- React
|
||||
- react-native-image-picker (0.28.1):
|
||||
- react-native-image-picker (1.1.0):
|
||||
- React
|
||||
- react-native-randombytes (3.5.3):
|
||||
- React
|
||||
@ -339,9 +339,9 @@ SPEC CHECKSUMS:
|
||||
React-jsiexecutor: 90ad2f9db09513fc763bc757fdc3c4ff8bde2a30
|
||||
React-jsinspector: e08662d1bf5b129a3d556eb9ea343a3f40353ae4
|
||||
react-native-blur: cad4d93b364f91e7b7931b3fa935455487e5c33c
|
||||
react-native-camera: 96a3c81f27da57b816fbb6808dde20dc96d1431e
|
||||
react-native-camera: 203091b4bf99d48b788a0682ad573e8718724893
|
||||
react-native-haptic-feedback: 22c9dc85fd8059f83bf9edd9212ac4bd4ae6074d
|
||||
react-native-image-picker: fd93361c666f397bdf72f9c6c23f13d2685b9173
|
||||
react-native-image-picker: 3637d63fef7e32a230141ab4660d3ceb773c824f
|
||||
react-native-randombytes: 991545e6eaaf700b4ee384c291ef3d572e0b2ca8
|
||||
react-native-slider: 6d83f7b8076a84e965a43fbdcfcf9dac19cea42e
|
||||
react-native-webview: f72ac4078e115dfa741cc588acb1cca25566457d
|
||||
|
@ -28,6 +28,10 @@ dayjs.extend(relativeTime);
|
||||
lang = 'zh-cn';
|
||||
require('dayjs/locale/zh-cn');
|
||||
break;
|
||||
case 'zh_tw':
|
||||
lang = 'zh-tw';
|
||||
require('dayjs/locale/zh-tw');
|
||||
break;
|
||||
case 'ru':
|
||||
require('dayjs/locale/ru');
|
||||
break;
|
||||
@ -113,6 +117,7 @@ strings = new Localization({
|
||||
hu_hu: require('./hu_HU.js'),
|
||||
id_id: require('./id_ID.js'),
|
||||
zh_cn: require('./zh_cn.js'),
|
||||
zh_tw: require('./zh_tw.js'),
|
||||
sv_se: require('./sv_SE.js'),
|
||||
nb_no: require('./nb_NO.js'),
|
||||
tr_tr: require('./tr_TR.js'),
|
||||
|
@ -24,8 +24,8 @@ module.exports = {
|
||||
empty_txs1: 'ธุรกรรมจะปรากฏที่นี่,',
|
||||
empty_txs2: 'ไม่มี ณ ขณะนี้',
|
||||
empty_txs1_lightning:
|
||||
'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: '\nแตะที่ "จัดการเงิน" เพื่อเริ่มใช้งาน และเติมเงิน',
|
||||
tap_here_to_buy: 'กดที่นี่เพื่อซื้อบิตคอยน์',
|
||||
},
|
||||
reorder: {
|
||||
|
235
loc/zh_tw.js
Normal file
235
loc/zh_tw.js
Normal file
@ -0,0 +1,235 @@
|
||||
module.exports = {
|
||||
_: {
|
||||
storage_is_encrypted: '你的資訊已經被加密, 請輸入密碼解密',
|
||||
enter_password: '輸入密碼',
|
||||
bad_password: '密碼無效,請重試',
|
||||
never: '不',
|
||||
continue: '繼續',
|
||||
ok: '好的',
|
||||
},
|
||||
wallets: {
|
||||
select_wallet: '選擇錢包',
|
||||
options: '選項',
|
||||
createBitcoinWallet: '您當前沒有bitcoin錢包. 為了支援閃電錢包, 我們需要建立或者匯入一個比特幣錢包. 是否需要繼續?',
|
||||
list: {
|
||||
app_name: 'BlueWallet',
|
||||
title: '錢包',
|
||||
header: '一個錢包代表一對的私鑰和地址' + '你可以通過分享收款.',
|
||||
add: '新增錢包',
|
||||
create_a_wallet: '建立一個錢包',
|
||||
create_a_wallet1: '建立錢包是免費的,你可以',
|
||||
create_a_wallet2: '想建立多少就建立多少個',
|
||||
latest_transaction: '最近的轉賬',
|
||||
empty_txs1: '你的轉賬資訊將展示在這裡',
|
||||
empty_txs2: '當前無資訊',
|
||||
empty_txs1_lightning:
|
||||
'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.',
|
||||
tap_here_to_buy: '點選購買比特幣',
|
||||
},
|
||||
reorder: {
|
||||
title: '重新排列錢包',
|
||||
},
|
||||
add: {
|
||||
title: '新增錢包',
|
||||
description: '你可以掃描你的紙質備份錢包 (WIF格式), 或者建立一個新錢包. 預設支援隔離見證錢包',
|
||||
scan: '掃描',
|
||||
create: '建立',
|
||||
label_new_segwit: '新隔離見證(Segwit)',
|
||||
label_new_lightning: '新閃電',
|
||||
wallet_name: '錢包名稱',
|
||||
wallet_type: '類型',
|
||||
or: '或',
|
||||
import_wallet: '匯入錢包',
|
||||
imported: '已經匯入',
|
||||
coming_soon: '即將來臨',
|
||||
lightning: '閃電',
|
||||
bitcoin: '比特幣',
|
||||
},
|
||||
details: {
|
||||
title: '錢包',
|
||||
address: '地址',
|
||||
type: '類型',
|
||||
label: '標籤',
|
||||
destination: '目的',
|
||||
description: '描述',
|
||||
are_you_sure: '你確認麼?',
|
||||
yes_delete: '是的,刪除',
|
||||
no_cancel: '不,取消',
|
||||
delete: '刪除',
|
||||
save: '儲存',
|
||||
delete_this_wallet: '刪除這個錢包',
|
||||
export_backup: '匯出備份',
|
||||
buy_bitcoin: '購買比特幣',
|
||||
show_xpub: '展示錢包 XPUB',
|
||||
},
|
||||
export: {
|
||||
title: '錢包匯出',
|
||||
},
|
||||
xpub: {
|
||||
title: '錢包 XPUB',
|
||||
copiedToClipboard: '複製到貼上板.',
|
||||
},
|
||||
import: {
|
||||
title: '匯入',
|
||||
explanation: '輸入你的助記詞,私鑰或者WIF, 或者其他格式的資料. BlueWallet將盡可能的自動識別資料格式並匯入錢包',
|
||||
imported: '已經匯入',
|
||||
error: '匯入失敗,請確認你提供的資訊是有效的',
|
||||
success: '成功',
|
||||
do_import: '匯入',
|
||||
scan_qr: '或掃面二維碼',
|
||||
},
|
||||
scanQrWif: {
|
||||
go_back: '回退',
|
||||
cancel: '取消',
|
||||
decoding: '解碼中',
|
||||
input_password: '輸入密碼',
|
||||
password_explain: '這是一個BIP38加密的私鑰',
|
||||
bad_password: '密碼錯誤',
|
||||
wallet_already_exists: '當前錢包已經存在',
|
||||
bad_wif: 'WIF格式無效',
|
||||
imported_wif: 'WIF已經匯入',
|
||||
with_address: ' 地址為',
|
||||
imported_segwit: 'SegWit已經匯入',
|
||||
imported_legacy: 'Legacy已經匯入',
|
||||
imported_watchonly: '匯入只讀',
|
||||
},
|
||||
},
|
||||
transactions: {
|
||||
list: {
|
||||
tabBarLabel: '轉賬',
|
||||
title: '轉賬',
|
||||
description: '當前所有錢包的轉入和轉出記錄',
|
||||
conf: '配置',
|
||||
},
|
||||
details: {
|
||||
title: '轉賬',
|
||||
from: '輸入',
|
||||
to: '輸出',
|
||||
copy: '複製',
|
||||
transaction_details: '轉賬詳情',
|
||||
show_in_block_explorer: '區塊瀏覽器展示',
|
||||
},
|
||||
},
|
||||
send: {
|
||||
header: '傳送',
|
||||
details: {
|
||||
title: '建立交易',
|
||||
amount_field_is_not_valid: '金額格式無效',
|
||||
fee_field_is_not_valid: '費用格式無效',
|
||||
address_field_is_not_valid: '地址內容無效',
|
||||
total_exceeds_balance: '餘額不足',
|
||||
create_tx_error: '建立交易失敗. 請確認地址格式正確.',
|
||||
address: '地址',
|
||||
amount_placeholder: '傳送金額(in BTC)',
|
||||
fee_placeholder: '手續費用 (in BTC)',
|
||||
note_placeholder: '訊息',
|
||||
cancel: '取消',
|
||||
scan: '掃描',
|
||||
send: '傳送',
|
||||
create: '建立',
|
||||
remaining_balance: '剩餘金額',
|
||||
},
|
||||
confirm: {
|
||||
header: '確認',
|
||||
sendNow: '現在傳送',
|
||||
},
|
||||
success: {
|
||||
done: '完成',
|
||||
},
|
||||
create: {
|
||||
details: '詳情',
|
||||
title: '建立詳情',
|
||||
error: '建立交易失敗. 無效地址或金額?',
|
||||
go_back: '回退',
|
||||
this_is_hex: '這個是交易的十六進位制資料, 簽名並廣播到全網路.',
|
||||
to: '到',
|
||||
amount: '金額',
|
||||
fee: '手續費',
|
||||
tx_size: '交易大小',
|
||||
satoshi_per_byte: '蔥每byte',
|
||||
memo: '訊息',
|
||||
broadcast: '廣播',
|
||||
not_enough_fee: '手續費不夠,請增加手續費',
|
||||
},
|
||||
},
|
||||
receive: {
|
||||
header: '收款',
|
||||
details: {
|
||||
title: '分享這個地址給付款人',
|
||||
share: '分享',
|
||||
copiedToClipboard: '複製到貼上板.',
|
||||
label: '描述',
|
||||
create: '建立',
|
||||
setAmount: '收款金額',
|
||||
},
|
||||
},
|
||||
buyBitcoin: {
|
||||
header: '購買比特幣',
|
||||
tap_your_address: '點選地址複製到貼上板:',
|
||||
copied: '複製到貼上板!',
|
||||
},
|
||||
settings: {
|
||||
header: '設定',
|
||||
plausible_deniability: '可否認性...',
|
||||
storage_not_encrypted: '儲存:未加密',
|
||||
storage_encrypted: '儲存:加密中',
|
||||
password: '密碼',
|
||||
password_explain: '建立你的加密密碼',
|
||||
retype_password: '再次輸入密碼',
|
||||
passwords_do_not_match: '兩次輸入密碼不同',
|
||||
encrypt_storage: '加密儲存',
|
||||
lightning_settings: '閃電網路設定',
|
||||
lightning_settings_explain: '如要要連線你自己的閃電節點請安裝LndHub' + ' 並把url地址輸入到下面. 空白將使用預設的LndHub (lndhub.io)',
|
||||
save: '儲存',
|
||||
about: '關於',
|
||||
language: '語言',
|
||||
currency: '貨幣',
|
||||
advanced_options: 'Advanced Options',
|
||||
enable_advanced_mode: 'Enable advanced mode',
|
||||
},
|
||||
plausibledeniability: {
|
||||
title: '可否認性',
|
||||
help:
|
||||
'在某些情況下, 你不得不暴露 ' +
|
||||
'密碼. 為了讓你的比特幣更加安全, BlueWallet可以建立一些 ' +
|
||||
'加密空間, 用不同的密碼. 在壓力之下, ' +
|
||||
'你可以暴露這個錢包密碼. 再次進入 ' +
|
||||
'BlueWallet, 我們會解鎖一些虛擬空間. 對第三方來說看上去' +
|
||||
'是合理的, 但會偷偷的幫你保證主錢包的安全 ' +
|
||||
'幣也就安全了.',
|
||||
help2: '新的空間具備完整的功能,你可以存在 ' + '少量的金額在裡面.',
|
||||
create_fake_storage: '建立虛擬加密儲存',
|
||||
go_back: '回退',
|
||||
create_password: '建立密碼',
|
||||
create_password_explanation: '虛擬儲存空間密碼不能和主儲存空間密碼相同',
|
||||
password_should_not_match: '虛擬儲存空間密碼不能和主儲存空間密碼相同',
|
||||
retype_password: '重輸密碼',
|
||||
passwords_do_not_match: '兩次輸入密碼不同,請重新輸入',
|
||||
success: '成功',
|
||||
},
|
||||
lnd: {
|
||||
title: '配置資金支援',
|
||||
choose_source_wallet: '選擇一個資金源錢包',
|
||||
refill_lnd_balance: '給閃電錢包充值',
|
||||
refill: '充值',
|
||||
withdraw: '提取',
|
||||
expired: '超時',
|
||||
sameWalletAsInvoiceError: '你不能用建立賬單的錢包去支付該賬單',
|
||||
},
|
||||
pleasebackup: {
|
||||
title: 'Your wallet is created...',
|
||||
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. You can use Electrum wallet on desktop (https://electrum.org/) to restore the same wallet.",
|
||||
ok: 'OK, I wrote this down!',
|
||||
},
|
||||
lndViewInvoice: {
|
||||
wasnt_paid_and_expired: 'This invoice was not paid for and has expired',
|
||||
has_been_paid: 'This invoice has been paid for',
|
||||
please_pay: 'Please pay',
|
||||
sats: 'sats',
|
||||
for: 'For:',
|
||||
additional_info: 'Additional Information',
|
||||
open_direct_channel: 'Open direct channel with this node:',
|
||||
},
|
||||
};
|
166
models/signer.js
166
models/signer.js
@ -6,13 +6,16 @@
|
||||
* https://github.com/Overtorment/Cashier-BTC
|
||||
*
|
||||
**/
|
||||
let bitcoinjs = require('bitcoinjs-lib');
|
||||
const bitcoinjs = require('bitcoinjs-lib');
|
||||
const _p2wpkh = bitcoinjs.payments.p2wpkh;
|
||||
const _p2sh = bitcoinjs.payments.p2sh;
|
||||
const toSatoshi = num => parseInt((num * 100000000).toFixed(0));
|
||||
|
||||
exports.createHDTransaction = function(utxos, toAddress, amount, fixedFee, changeAddress) {
|
||||
let feeInSatoshis = parseInt((fixedFee * 100000000).toFixed(0));
|
||||
let amountToOutputSatoshi = parseInt(((amount - fixedFee) * 100000000).toFixed(0)); // how much payee should get
|
||||
let txb = new bitcoinjs.TransactionBuilder();
|
||||
txb.setVersion(1);
|
||||
let unspentAmountSatoshi = 0;
|
||||
let ourOutputs = {};
|
||||
let outputNum = 0;
|
||||
@ -50,7 +53,11 @@ exports.createHDTransaction = function(utxos, toAddress, amount, fixedFee, chang
|
||||
// now, signing every input with a corresponding key
|
||||
|
||||
for (let c = 0; c <= outputNum; c++) {
|
||||
txb.sign(c, ourOutputs[c].keyPair);
|
||||
txb.sign({
|
||||
prevOutScriptType: 'p2pkh',
|
||||
vin: c,
|
||||
keyPair: ourOutputs[c].keyPair,
|
||||
});
|
||||
}
|
||||
|
||||
let tx = txb.build();
|
||||
@ -60,23 +67,35 @@ exports.createHDTransaction = function(utxos, toAddress, amount, fixedFee, chang
|
||||
exports.createHDSegwitTransaction = function(utxos, toAddress, amount, fixedFee, changeAddress) {
|
||||
let feeInSatoshis = parseInt((fixedFee * 100000000).toFixed(0));
|
||||
let amountToOutputSatoshi = parseInt(((amount - fixedFee) * 100000000).toFixed(0)); // how much payee should get
|
||||
let txb = new bitcoinjs.TransactionBuilder();
|
||||
let psbt = new bitcoinjs.Psbt();
|
||||
psbt.setVersion(1);
|
||||
let unspentAmountSatoshi = 0;
|
||||
let ourOutputs = {};
|
||||
let ourOutputs = [];
|
||||
let outputNum = 0;
|
||||
for (const unspent of utxos) {
|
||||
if (unspent.confirmations < 1) {
|
||||
// using only confirmed outputs
|
||||
continue;
|
||||
}
|
||||
txb.addInput(unspent.txid, unspent.vout);
|
||||
ourOutputs[outputNum] = ourOutputs[outputNum] || {};
|
||||
let keyPair = bitcoinjs.ECPair.fromWIF(unspent.wif);
|
||||
let pubKey = keyPair.getPublicKeyBuffer();
|
||||
let pubKeyHash = bitcoinjs.crypto.hash160(pubKey);
|
||||
let redeemScript = bitcoinjs.script.witnessPubKeyHash.output.encode(pubKeyHash);
|
||||
let p2wpkh = _p2wpkh({
|
||||
pubkey: keyPair.publicKey,
|
||||
});
|
||||
let p2sh = _p2sh({
|
||||
redeem: p2wpkh,
|
||||
});
|
||||
psbt.addInput({
|
||||
hash: unspent.txid,
|
||||
index: unspent.vout,
|
||||
witnessUtxo: {
|
||||
script: p2sh.output,
|
||||
value: unspent.amount,
|
||||
},
|
||||
redeemScript: p2wpkh.output,
|
||||
});
|
||||
ourOutputs[outputNum] = ourOutputs[outputNum] || {};
|
||||
ourOutputs[outputNum].keyPair = keyPair;
|
||||
ourOutputs[outputNum].redeemScript = redeemScript;
|
||||
ourOutputs[outputNum].redeemScript = p2wpkh.output;
|
||||
ourOutputs[outputNum].amount = unspent.amount;
|
||||
unspentAmountSatoshi += unspent.amount;
|
||||
if (unspentAmountSatoshi >= amountToOutputSatoshi + feeInSatoshis) {
|
||||
@ -92,23 +111,29 @@ exports.createHDSegwitTransaction = function(utxos, toAddress, amount, fixedFee,
|
||||
|
||||
// adding outputs
|
||||
|
||||
txb.addOutput(toAddress, amountToOutputSatoshi);
|
||||
psbt.addOutput({
|
||||
address: toAddress,
|
||||
value: amountToOutputSatoshi,
|
||||
});
|
||||
if (amountToOutputSatoshi + feeInSatoshis < unspentAmountSatoshi) {
|
||||
// sending less than we have, so the rest should go back
|
||||
if (unspentAmountSatoshi - amountToOutputSatoshi - feeInSatoshis > 3 * feeInSatoshis) {
|
||||
// to prevent @dust error change transferred amount should be at least 3xfee.
|
||||
// if not - we just dont send change and it wil add to fee
|
||||
txb.addOutput(changeAddress, unspentAmountSatoshi - amountToOutputSatoshi - feeInSatoshis);
|
||||
psbt.addOutput({
|
||||
address: changeAddress,
|
||||
value: unspentAmountSatoshi - amountToOutputSatoshi - feeInSatoshis,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// now, signing every input with a corresponding key
|
||||
|
||||
for (let c = 0; c <= outputNum; c++) {
|
||||
txb.sign(c, ourOutputs[c].keyPair, ourOutputs[c].redeemScript, null, ourOutputs[c].amount);
|
||||
psbt.signInput(c, ourOutputs[c].keyPair);
|
||||
}
|
||||
|
||||
let tx = txb.build();
|
||||
let tx = psbt.finalizeAllInputs().extractTransaction();
|
||||
return tx.toHex();
|
||||
};
|
||||
|
||||
@ -120,37 +145,57 @@ exports.createSegwitTransaction = function(utxos, toAddress, amount, fixedFee, W
|
||||
|
||||
let feeInSatoshis = parseInt((fixedFee * 100000000).toFixed(0));
|
||||
let keyPair = bitcoinjs.ECPair.fromWIF(WIF);
|
||||
let pubKey = keyPair.getPublicKeyBuffer();
|
||||
let pubKeyHash = bitcoinjs.crypto.hash160(pubKey);
|
||||
let redeemScript = bitcoinjs.script.witnessPubKeyHash.output.encode(pubKeyHash);
|
||||
let p2wpkh = _p2wpkh({
|
||||
pubkey: keyPair.publicKey,
|
||||
});
|
||||
let p2sh = _p2sh({
|
||||
redeem: p2wpkh,
|
||||
});
|
||||
|
||||
let txb = new bitcoinjs.TransactionBuilder();
|
||||
let psbt = new bitcoinjs.Psbt();
|
||||
psbt.setVersion(1);
|
||||
let unspentAmount = 0;
|
||||
for (const unspent of utxos) {
|
||||
if (unspent.confirmations < 2) {
|
||||
// using only confirmed outputs
|
||||
continue;
|
||||
}
|
||||
txb.addInput(unspent.txid, unspent.vout, sequence);
|
||||
unspentAmount += parseInt((unspent.amount * 100000000).toFixed(0));
|
||||
const satoshis = parseInt((unspent.amount * 100000000).toFixed(0));
|
||||
psbt.addInput({
|
||||
hash: unspent.txid,
|
||||
index: unspent.vout,
|
||||
sequence,
|
||||
witnessUtxo: {
|
||||
script: p2sh.output,
|
||||
value: satoshis,
|
||||
},
|
||||
redeemScript: p2wpkh.output,
|
||||
});
|
||||
unspentAmount += satoshis;
|
||||
}
|
||||
let amountToOutput = parseInt(((amount - fixedFee) * 100000000).toFixed(0));
|
||||
txb.addOutput(toAddress, amountToOutput);
|
||||
psbt.addOutput({
|
||||
address: toAddress,
|
||||
value: amountToOutput,
|
||||
});
|
||||
if (amountToOutput + feeInSatoshis < unspentAmount) {
|
||||
// sending less than we have, so the rest should go back
|
||||
|
||||
if (unspentAmount - amountToOutput - feeInSatoshis > 3 * feeInSatoshis) {
|
||||
// to prevent @dust error change transferred amount should be at least 3xfee.
|
||||
// if not - we just dont send change and it wil add to fee
|
||||
txb.addOutput(changeAddress, unspentAmount - amountToOutput - feeInSatoshis);
|
||||
psbt.addOutput({
|
||||
address: changeAddress,
|
||||
value: unspentAmount - amountToOutput - feeInSatoshis,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (let c = 0; c < utxos.length; c++) {
|
||||
txb.sign(c, keyPair, redeemScript, null, parseInt((utxos[c].amount * 100000000).toFixed(0)));
|
||||
psbt.signInput(c, keyPair);
|
||||
}
|
||||
|
||||
let tx = txb.build();
|
||||
let tx = psbt.finalizeAllInputs().extractTransaction();
|
||||
return tx.toHex();
|
||||
};
|
||||
|
||||
@ -168,11 +213,33 @@ exports.createRBFSegwitTransaction = function(txhex, addressReplaceMap, feeDelta
|
||||
highestSequence = i.sequence;
|
||||
}
|
||||
}
|
||||
let keyPair = bitcoinjs.ECPair.fromWIF(WIF);
|
||||
let p2wpkh = _p2wpkh({
|
||||
pubkey: keyPair.publicKey,
|
||||
});
|
||||
let p2sh = _p2sh({
|
||||
redeem: p2wpkh,
|
||||
});
|
||||
|
||||
// creating TX
|
||||
let txb = new bitcoinjs.TransactionBuilder();
|
||||
let psbt = new bitcoinjs.Psbt();
|
||||
psbt.setVersion(1);
|
||||
for (let unspent of tx.ins) {
|
||||
txb.addInput(unspent.hash.reverse().toString('hex'), unspent.index, highestSequence + 1);
|
||||
let txid = Buffer.from(unspent.hash)
|
||||
.reverse()
|
||||
.toString('hex');
|
||||
let index = unspent.index;
|
||||
let amount = utxodata[txid][index];
|
||||
psbt.addInput({
|
||||
hash: txid,
|
||||
index,
|
||||
sequence: highestSequence + 1,
|
||||
witnessUtxo: {
|
||||
script: p2sh.output,
|
||||
value: amount,
|
||||
},
|
||||
redeemScript: p2wpkh.output,
|
||||
});
|
||||
}
|
||||
|
||||
for (let o of tx.outs) {
|
||||
@ -180,37 +247,36 @@ exports.createRBFSegwitTransaction = function(txhex, addressReplaceMap, feeDelta
|
||||
if (addressReplaceMap[outAddress]) {
|
||||
// means this is DESTINATION address, not messing with it's amount
|
||||
// but replacing the address itseld
|
||||
txb.addOutput(addressReplaceMap[outAddress], o.value);
|
||||
psbt.addOutput({
|
||||
address: addressReplaceMap[outAddress],
|
||||
value: o.value,
|
||||
});
|
||||
} else {
|
||||
// CHANGE address, so we deduct increased fee from here
|
||||
let feeDeltaInSatoshi = parseInt((feeDelta * 100000000).toFixed(0));
|
||||
txb.addOutput(outAddress, o.value - feeDeltaInSatoshi);
|
||||
psbt.addOutput({
|
||||
address: outAddress,
|
||||
value: o.value - feeDeltaInSatoshi,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// signing
|
||||
let keyPair = bitcoinjs.ECPair.fromWIF(WIF);
|
||||
let pubKey = keyPair.getPublicKeyBuffer();
|
||||
let pubKeyHash = bitcoinjs.crypto.hash160(pubKey);
|
||||
let redeemScript = bitcoinjs.script.witnessPubKeyHash.output.encode(pubKeyHash);
|
||||
for (let c = 0; c < tx.ins.length; c++) {
|
||||
let txid = tx.ins[c].hash.reverse().toString('hex');
|
||||
let index = tx.ins[c].index;
|
||||
let amount = utxodata[txid][index];
|
||||
txb.sign(c, keyPair, redeemScript, null, amount);
|
||||
psbt.signInput(c, keyPair);
|
||||
}
|
||||
|
||||
let newTx = txb.build();
|
||||
let newTx = psbt.finalizeAllInputs().extractTransaction();
|
||||
return newTx.toHex();
|
||||
};
|
||||
|
||||
exports.generateNewSegwitAddress = function() {
|
||||
let keyPair = bitcoinjs.ECPair.makeRandom();
|
||||
let pubKey = keyPair.getPublicKeyBuffer();
|
||||
|
||||
let witnessScript = bitcoinjs.script.witnessPubKeyHash.output.encode(bitcoinjs.crypto.hash160(pubKey));
|
||||
let scriptPubKey = bitcoinjs.script.scriptHash.output.encode(bitcoinjs.crypto.hash160(witnessScript));
|
||||
let address = bitcoinjs.address.fromOutputScript(scriptPubKey);
|
||||
let address = bitcoinjs.payments.p2sh({
|
||||
redeem: bitcoinjs.payments.p2wpkh({
|
||||
pubkey: keyPair.publicKey,
|
||||
}),
|
||||
}).address;
|
||||
|
||||
return {
|
||||
address: address,
|
||||
@ -235,10 +301,11 @@ exports.URI = function(paymentInfo) {
|
||||
|
||||
exports.WIF2segwitAddress = function(WIF) {
|
||||
let keyPair = bitcoinjs.ECPair.fromWIF(WIF);
|
||||
let pubKey = keyPair.getPublicKeyBuffer();
|
||||
let witnessScript = bitcoinjs.script.witnessPubKeyHash.output.encode(bitcoinjs.crypto.hash160(pubKey));
|
||||
let scriptPubKey = bitcoinjs.script.scriptHash.output.encode(bitcoinjs.crypto.hash160(witnessScript));
|
||||
return bitcoinjs.address.fromOutputScript(scriptPubKey);
|
||||
return bitcoinjs.payments.p2sh({
|
||||
redeem: bitcoinjs.payments.p2wpkh({
|
||||
pubkey: keyPair.publicKey,
|
||||
}),
|
||||
}).address;
|
||||
};
|
||||
|
||||
exports.createTransaction = function(utxos, toAddress, _amount, _fixedFee, WIF, fromAddress) {
|
||||
@ -246,6 +313,7 @@ exports.createTransaction = function(utxos, toAddress, _amount, _fixedFee, WIF,
|
||||
let amountToOutput = toSatoshi(_amount - _fixedFee);
|
||||
let pk = bitcoinjs.ECPair.fromWIF(WIF); // eslint-disable-line new-cap
|
||||
let txb = new bitcoinjs.TransactionBuilder();
|
||||
txb.setVersion(1);
|
||||
let unspentAmount = 0;
|
||||
for (const unspent of utxos) {
|
||||
if (unspent.confirmations < 2) {
|
||||
@ -263,7 +331,11 @@ exports.createTransaction = function(utxos, toAddress, _amount, _fixedFee, WIF,
|
||||
}
|
||||
|
||||
for (let c = 0; c < utxos.length; c++) {
|
||||
txb.sign(c, pk);
|
||||
txb.sign({
|
||||
prevOutScriptType: 'p2pkh',
|
||||
vin: c,
|
||||
keyPair: pk,
|
||||
});
|
||||
}
|
||||
|
||||
return txb.build().toHex();
|
||||
|
63
package-lock.json
generated
63
package-lock.json
generated
@ -2663,6 +2663,11 @@
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"bip174": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/bip174/-/bip174-1.0.1.tgz",
|
||||
"integrity": "sha512-Mq2aFs1TdMfxBpYPg7uzjhsiXbAtoVq44TNjEWtvuZBiBgc3m7+n55orYMtTAxdg7jWbL4DtH0MKocJER4xERQ=="
|
||||
},
|
||||
"bip21": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/bip21/-/bip21-2.0.2.tgz",
|
||||
@ -2711,34 +2716,14 @@
|
||||
"integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow=="
|
||||
},
|
||||
"bitcoinjs-lib": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-3.3.2.tgz",
|
||||
"integrity": "sha512-l5qqvbaK8wwtANPf6oEffykycg4383XgEYdia1rI7/JpGf1jfRWlOUCvx5TiTZS7kyIvY4j/UhIQ2urLsvGkzw==",
|
||||
"requires": {
|
||||
"bech32": "^1.1.2",
|
||||
"bigi": "^1.4.0",
|
||||
"bip66": "^1.1.0",
|
||||
"bitcoin-ops": "^1.3.0",
|
||||
"bs58check": "^2.0.0",
|
||||
"create-hash": "^1.1.0",
|
||||
"create-hmac": "^1.1.3",
|
||||
"ecurve": "^1.0.0",
|
||||
"merkle-lib": "^2.0.10",
|
||||
"pushdata-bitcoin": "^1.0.1",
|
||||
"randombytes": "^2.0.1",
|
||||
"safe-buffer": "^5.0.1",
|
||||
"typeforce": "^1.11.3",
|
||||
"varuint-bitcoin": "^1.0.4",
|
||||
"wif": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"bitcoinjs5": {
|
||||
"version": "git+https://github.com/Overtorment/bitcoinjs5.git#846c0185a6693f86540d58a7a5fffe8173dc8b34",
|
||||
"from": "git+https://github.com/Overtorment/bitcoinjs5.git#846c018",
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-5.1.6.tgz",
|
||||
"integrity": "sha512-NgvnA8XXUuzpuBnVs1plzZvVOYsuont4KPzaGcVIwjktYQbCk1hUkXnt4wujIOBscNsXuu+plVbPYvtMosZI/w==",
|
||||
"requires": {
|
||||
"@types/node": "10.12.18",
|
||||
"bech32": "^1.1.2",
|
||||
"bip32": "^2.0.3",
|
||||
"bip174": "^1.0.1",
|
||||
"bip32": "^2.0.4",
|
||||
"bip66": "^1.1.0",
|
||||
"bitcoin-ops": "^1.4.0",
|
||||
"bs58check": "^2.0.0",
|
||||
@ -2751,6 +2736,22 @@
|
||||
"typeforce": "^1.11.3",
|
||||
"varuint-bitcoin": "^1.0.4",
|
||||
"wif": "^2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"bip32": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/bip32/-/bip32-2.0.4.tgz",
|
||||
"integrity": "sha512-ioPytarPDIrWckWMuK4RNUtvwhvWEc2fvuhnO0WEwu732k5OLjUXv4rXi2c/KJHw9ZMNQMkYRJrBw81RujShGQ==",
|
||||
"requires": {
|
||||
"@types/node": "10.12.18",
|
||||
"bs58check": "^2.1.1",
|
||||
"create-hash": "^1.2.0",
|
||||
"create-hmac": "^1.1.7",
|
||||
"tiny-secp256k1": "^1.1.0",
|
||||
"typeforce": "^1.11.5",
|
||||
"wif": "^2.0.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"bl": {
|
||||
@ -10686,9 +10687,9 @@
|
||||
}
|
||||
},
|
||||
"react-native-camera": {
|
||||
"version": "2.11.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-2.11.1.tgz",
|
||||
"integrity": "sha512-ZmPZHcY7UXEf7Z8PoJX/WhFtmLFtdRPBGDwemOLlPRVwTVyu/OXVINDUWCug4daBqV8Fs3X1O6V927+K2u2GfA==",
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-3.4.0.tgz",
|
||||
"integrity": "sha512-EFaixLtQsd3Kjs2AnxPx4Qb1mNSlZRZBVoxXDUdWcSdCEE3CSvdeonTb3vWAT3ZlGMi1RTOggtBpI4StMtFNjw==",
|
||||
"requires": {
|
||||
"prop-types": "^15.6.2"
|
||||
}
|
||||
@ -10769,9 +10770,9 @@
|
||||
"integrity": "sha512-iuXBEZsQbKOe5uOLXuzTEvrvUCV0a4AktAfJHlWK7Jb0t/ABUc4kUfclqx+la+yA1TKrauDp/6MjrP0OUDXA9Q=="
|
||||
},
|
||||
"react-native-image-picker": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-0.28.1.tgz",
|
||||
"integrity": "sha512-CW2dm+cjsdW2fjBW2WD/cSufNG0x0UpljwGHrjSzyB0TckoW+tjYv44UWtckCWxr1JtCg+QrYDO/MzlRyFcjwQ=="
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-1.1.0.tgz",
|
||||
"integrity": "sha512-/KjHf4NNAjl6XM7FQuqvGDz1wB9sRdLf86+2yksLW/QTRR7CitX4TLCM8ZF9CX6Y0MsCTndkZia3zWE+nt/GiA=="
|
||||
},
|
||||
"react-native-level-fs": {
|
||||
"version": "3.0.1",
|
||||
|
10
package.json
10
package.json
@ -24,7 +24,7 @@
|
||||
"rn-nodeify": "github:tradle/rn-nodeify"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "./patches/fix_mangle.sh; git apply patches/minifier.js.patch; git apply patches/minify.js.patch; git apply patches/transaction_builder.js.patch; git apply ./patches/transaction.js.patch",
|
||||
"prepare": "./patches/fix_mangle.sh; git apply patches/minifier.js.patch; git apply patches/minify.js.patch",
|
||||
"clean": "cd android/; ./gradlew clean; cd ..; rm -r -f /tmp/metro-cache/; rm -r -f node_modules/; npm cache clean --force; npm i; npm start -- --reset-cache",
|
||||
"releasenotes2json": "./release-notes.sh > release-notes.txt; node -e 'console.log(JSON.stringify(require(\"fs\").readFileSync(\"release-notes.txt\", \"utf8\")));' > release-notes.json",
|
||||
"podinstall": "./podinstall.sh",
|
||||
@ -58,13 +58,13 @@
|
||||
"bip21": "2.0.2",
|
||||
"bip32": "2.0.3",
|
||||
"bip39": "2.5.0",
|
||||
"bitcoinjs-lib": "3.3.2",
|
||||
"bitcoinjs5": "git+https://github.com/Overtorment/bitcoinjs5.git#846c018",
|
||||
"bitcoinjs-lib": "^5.1.6",
|
||||
"buffer": "5.2.1",
|
||||
"buffer-reverse": "1.0.1",
|
||||
"coinselect": "3.1.11",
|
||||
"crypto-js": "3.1.9-1",
|
||||
"dayjs": "1.8.14",
|
||||
"ecurve": "^1.0.6",
|
||||
"electrum-client": "git+https://github.com/BlueWallet/rn-electrum-client.git",
|
||||
"eslint-config-prettier": "6.0.0",
|
||||
"eslint-config-standard": "12.0.0",
|
||||
@ -84,7 +84,7 @@
|
||||
"react": "16.8.6",
|
||||
"react-localization": "1.0.13",
|
||||
"react-native": "0.60.5",
|
||||
"react-native-camera": "2.11.1",
|
||||
"react-native-camera": "3.4.0",
|
||||
"react-native-device-info": "2.2.2",
|
||||
"react-native-elements": "0.19.0",
|
||||
"react-native-flexi-radio-button": "0.2.2",
|
||||
@ -92,7 +92,7 @@
|
||||
"react-native-gesture-handler": "1.3.0",
|
||||
"react-native-handoff": "git+https://github.com/marcosrdz/react-native-handoff.git",
|
||||
"react-native-haptic-feedback": "1.7.1",
|
||||
"react-native-image-picker": "0.28.1",
|
||||
"react-native-image-picker": "1.1.0",
|
||||
"react-native-level-fs": "3.0.1",
|
||||
"react-native-linear-gradient": "2.5.4",
|
||||
"react-native-modal": "11.1.0",
|
||||
|
@ -1,12 +0,0 @@
|
||||
--- a/node_modules/bitcoinjs-lib/src/transaction.js 2018-07-18 00:17:03.540824839 +0100
|
||||
+++ b/node_modules/bitcoinjs-lib/src/transaction.js 2018-07-18 00:24:55.840803782 +0100
|
||||
@@ -408,7 +408,8 @@
|
||||
|
||||
Transaction.prototype.getId = function () {
|
||||
// transaction hash's are displayed in reverse order
|
||||
- return this.getHash().reverse().toString('hex')
|
||||
+ var bufferReverse = require('buffer-reverse')
|
||||
+ return bufferReverse(this.getHash()).toString('hex')
|
||||
}
|
||||
|
||||
Transaction.prototype.toBuffer = function (buffer, initialOffset) {
|
@ -1,12 +0,0 @@
|
||||
--- a/node_modules/bitcoinjs-lib/src/transaction_builder.js 2018-07-18 00:09:22.924845375 +0100
|
||||
+++ b/node_modules/bitcoinjs-lib/src/transaction_builder.js 2018-07-18 00:14:20.996832086 +0100
|
||||
@@ -536,7 +536,8 @@
|
||||
// is it a hex string?
|
||||
if (typeof txHash === 'string') {
|
||||
// transaction hashs's are displayed in reverse order, un-reverse it
|
||||
- txHash = Buffer.from(txHash, 'hex').reverse()
|
||||
+ var bufferReverse = require('buffer-reverse')
|
||||
+ txHash = bufferReverse(new Buffer(txHash, 'hex'))
|
||||
|
||||
// is it a Transaction object?
|
||||
} else if (txHash instanceof Transaction) {
|
@ -3,9 +3,9 @@ import { ScrollView, View } from 'react-native';
|
||||
import { BlueLoading, BlueSpacing20, SafeBlueArea, BlueCard, BlueText, BlueNavigationStyle } from '../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import { SegwitP2SHWallet, LegacyWallet, HDSegwitP2SHWallet, HDSegwitBech32Wallet } from '../class';
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
let BigNumber = require('bignumber.js');
|
||||
let encryption = require('../encryption');
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
let BlueElectrum = require('../BlueElectrum');
|
||||
|
||||
export default class Selftest extends Component {
|
||||
@ -166,7 +166,7 @@ export default class Selftest extends Component {
|
||||
block_height: 514991,
|
||||
tx_input_n: -1,
|
||||
tx_output_n: 2,
|
||||
value: 546,
|
||||
value: 110000,
|
||||
ref_balance: 546,
|
||||
spent: false,
|
||||
confirmations: 9,
|
||||
@ -185,7 +185,7 @@ export default class Selftest extends Component {
|
||||
}
|
||||
if (
|
||||
tx !==
|
||||
'0100000000010123c3e0950eabb2b5c1a956e9d003c516fc29ff529211bd552be719fb78ea5e0f0200000017160014597ce022baa887799951e0496c769d9cc0c759dc0000000001a0860100000000001976a914ff715fb722cb10646d80709aeac7f2f4ee00278f88ac0247304402202507d6b05ab19c7fdee217e97fddab80d481d7b2a103c00cecfc634bf897188d02205fa62ad413b6e441f99f94d7d8f9cd4ba51a1d928cbdec6873fa915236dd6d92012103aea0dfd576151cb399347aa6732f8fdf027b9ea3ea2e65fb754803f776e0a50900000000'
|
||||
'0100000000010123c3e0950eabb2b5c1a956e9d003c516fc29ff529211bd552be719fb78ea5e0f0200000017160014597ce022baa887799951e0496c769d9cc0c759dc0000000001a0860100000000001976a914ff715fb722cb10646d80709aeac7f2f4ee00278f88ac02473044022075670317a0e5b5d4eef154b03db97396a64cbc6ef3b576d98367e1a83c1c488002206d6df1e8085fd711d6ea264de3803340f80fa2c6e30683879d9ad40f3228c56c012103aea0dfd576151cb399347aa6732f8fdf027b9ea3ea2e65fb754803f776e0a50900000000'
|
||||
) {
|
||||
errorMessage += 'created tx hex doesnt match; ';
|
||||
isOk = false;
|
||||
@ -217,16 +217,17 @@ export default class Selftest extends Component {
|
||||
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';
|
||||
let seed = bip39.mnemonicToSeed(mnemonic);
|
||||
let root = bitcoin.HDNode.fromSeedBuffer(seed);
|
||||
let root = bitcoin.bip32.fromSeed(seed);
|
||||
|
||||
let path = "m/49'/0'/0'/0/0";
|
||||
let child = root.derivePath(path);
|
||||
|
||||
let keyhash = bitcoin.crypto.hash160(child.getPublicKeyBuffer());
|
||||
let scriptSig = bitcoin.script.witnessPubKeyHash.output.encode(keyhash);
|
||||
let addressBytes = bitcoin.crypto.hash160(scriptSig);
|
||||
let outputScript = bitcoin.script.scriptHash.output.encode(addressBytes);
|
||||
let address = bitcoin.address.fromOutputScript(outputScript, bitcoin.networks.bitcoin);
|
||||
let address = bitcoin.payments.p2sh({
|
||||
redeem: bitcoin.payments.p2wpkh({
|
||||
pubkey: child.publicKey,
|
||||
network: bitcoin.networks.bitcoin,
|
||||
}),
|
||||
network: bitcoin.networks.bitcoin,
|
||||
}).address;
|
||||
|
||||
if (address !== '3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK') {
|
||||
errorMessage += 'bip49 is not ok; ';
|
||||
|
@ -37,6 +37,7 @@ import BitcoinBIP70TransactionDecode from '../../bip70/bip70';
|
||||
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
|
||||
import { HDLegacyP2PKHWallet, HDSegwitBech32Wallet, HDSegwitP2SHWallet, LightningCustodianWallet } from '../../class';
|
||||
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
import { BitcoinTransaction } from '../../models/bitcoinTransactionInfo';
|
||||
const bip21 = require('bip21');
|
||||
let BigNumber = require('bignumber.js');
|
||||
@ -44,7 +45,6 @@ const { width } = Dimensions.get('window');
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp');
|
||||
let loc = require('../../loc');
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
|
||||
const btcAddressRx = /^[a-zA-Z0-9]{26,35}$/;
|
||||
|
||||
|
@ -1,25 +1,25 @@
|
||||
/* global alert */
|
||||
import React from 'react';
|
||||
import { Image, TouchableOpacity } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import { RNCamera } from 'react-native-camera';
|
||||
import { SafeBlueArea } from '../../BlueComponents';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import ImagePicker from 'react-native-image-picker';
|
||||
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
|
||||
|
||||
export default class CameraExample extends React.Component {
|
||||
export default class ScanQRCode extends React.Component {
|
||||
static navigationOptions = {
|
||||
header: null,
|
||||
};
|
||||
|
||||
state = {
|
||||
isLoading: false,
|
||||
};
|
||||
cameraRef = null;
|
||||
|
||||
onBarCodeScanned = ret => {
|
||||
if (this.state.isLoading) return;
|
||||
this.setState({ isLoading: true }, () => {
|
||||
const onBarScannedProp = this.props.navigation.getParam('onBarScanned');
|
||||
this.props.navigation.goBack();
|
||||
onBarScannedProp(ret.data);
|
||||
});
|
||||
onBarCodeRead = ret => {
|
||||
if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.pausePreview();
|
||||
const onBarScannedProp = this.props.navigation.getParam('onBarScanned');
|
||||
this.props.navigation.goBack();
|
||||
onBarScannedProp(ret.data);
|
||||
}; // end
|
||||
|
||||
render() {
|
||||
@ -33,8 +33,9 @@ export default class CameraExample extends React.Component {
|
||||
buttonPositive: 'OK',
|
||||
buttonNegative: 'Cancel',
|
||||
}}
|
||||
ref={ref => (this.cameraRef = ref)}
|
||||
style={{ flex: 1, justifyContent: 'space-between' }}
|
||||
onBarCodeRead={this.onBarCodeScanned}
|
||||
onBarCodeRead={this.onBarCodeRead}
|
||||
barCodeTypes={[RNCamera.Constants.BarCodeType.qr]}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
@ -52,12 +53,51 @@ export default class CameraExample extends React.Component {
|
||||
>
|
||||
<Image style={{ alignSelf: 'center' }} source={require('../../img/close-white.png')} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40,
|
||||
backgroundColor: '#FFFFFF',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 20,
|
||||
position: 'absolute',
|
||||
left: 24,
|
||||
bottom: 48,
|
||||
}}
|
||||
onPress={() => {
|
||||
if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.pausePreview();
|
||||
ImagePicker.launchImageLibrary(
|
||||
{
|
||||
title: null,
|
||||
mediaType: 'photo',
|
||||
takePhotoButtonTitle: null,
|
||||
},
|
||||
response => {
|
||||
if (response.uri) {
|
||||
const uri = response.uri.toString().replace('file://', '');
|
||||
LocalQRCode.decode(uri, (error, result) => {
|
||||
if (!error) {
|
||||
this.onBarCodeRead({ data: result });
|
||||
} else {
|
||||
if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.resumePreview();
|
||||
alert('The selected image does not contain a QR Code.');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.resumePreview();
|
||||
}
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Icon name="image" type="font-awesome" color="#0c2550" />
|
||||
</TouchableOpacity>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
CameraExample.propTypes = {
|
||||
ScanQRCode.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.func,
|
||||
dismiss: PropTypes.func,
|
||||
|
@ -19,9 +19,10 @@ export default class Language extends Component {
|
||||
availableLanguages: [
|
||||
{ label: 'English', value: 'en' },
|
||||
{ label: 'Afrikaans (AFR)', value: 'zar_afr' },
|
||||
{ label: 'Česky (CZ)', value: 'cs_cz' },
|
||||
{ label: 'Chinese (ZH)', value: 'zh_cn' },
|
||||
{ label: 'Chinese (TW)', value: 'zh_tw' },
|
||||
{ label: 'Croatian (HR)', value: 'hr_hr' },
|
||||
{ label: 'Česky (CZ)', value: 'cs_cz' },
|
||||
{ label: 'Danish (DK)', value: 'da_dk' },
|
||||
{ label: 'Deutsch (DE)', value: 'de_de' },
|
||||
{ label: 'Español (ES)', value: 'es' },
|
||||
|
@ -14,8 +14,8 @@ import {
|
||||
BlueNavigationStyle,
|
||||
} from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
const bitcoinjs = require('bitcoinjs-lib');
|
||||
let BigNumber = require('bignumber.js');
|
||||
let bitcoinjs = require('bitcoinjs-lib');
|
||||
let BlueApp = require('../../BlueApp');
|
||||
|
||||
export default class SendCreate extends Component {
|
||||
|
@ -21,18 +21,10 @@ export default class ScanQrWif extends React.Component {
|
||||
header: null,
|
||||
};
|
||||
|
||||
state = {
|
||||
isLoading: false,
|
||||
};
|
||||
state = { isLoading: false };
|
||||
|
||||
onBarCodeScanned = async ret => {
|
||||
if (+new Date() - this.lastTimeIveBeenHere < 6000) {
|
||||
this.lastTimeIveBeenHere = +new Date();
|
||||
return;
|
||||
}
|
||||
this.lastTimeIveBeenHere = +new Date();
|
||||
this.setState({ isLoading: true });
|
||||
|
||||
if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.pausePreview();
|
||||
if (ret.data[0] === '6') {
|
||||
// password-encrypted, need to ask for password and decrypt
|
||||
console.log('trying to decrypt...');
|
||||
@ -55,6 +47,7 @@ export default class ScanQrWif extends React.Component {
|
||||
ret.data = wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed);
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.resumePreview();
|
||||
this.setState({ message: false, isLoading: false });
|
||||
return alert(loc.wallets.scanQrWif.bad_password);
|
||||
}
|
||||
@ -66,6 +59,7 @@ export default class ScanQrWif extends React.Component {
|
||||
if (w.getSecret() === ret.data) {
|
||||
// lookig for duplicates
|
||||
this.setState({ isLoading: false });
|
||||
if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.resumePreview();
|
||||
return alert(loc.wallets.scanQrWif.wallet_already_exists); // duplicate, not adding
|
||||
}
|
||||
}
|
||||
@ -78,6 +72,7 @@ export default class ScanQrWif extends React.Component {
|
||||
if (w.getSecret() === hd.getSecret()) {
|
||||
// lookig for duplicates
|
||||
this.setState({ isLoading: false });
|
||||
if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.resumePreview();
|
||||
return alert(loc.wallets.scanQrWif.wallet_already_exists); // duplicate, not adding
|
||||
}
|
||||
}
|
||||
@ -105,6 +100,7 @@ export default class ScanQrWif extends React.Component {
|
||||
if (w.getSecret() === hd.getSecret()) {
|
||||
// lookig for duplicates
|
||||
this.setState({ isLoading: false });
|
||||
if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.resumePreview();
|
||||
return alert(loc.wallets.scanQrWif.wallet_already_exists); // duplicate, not adding
|
||||
}
|
||||
}
|
||||
@ -131,6 +127,7 @@ export default class ScanQrWif extends React.Component {
|
||||
if (w.getSecret() === hd.getSecret()) {
|
||||
// lookig for duplicates
|
||||
this.setState({ isLoading: false });
|
||||
if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.resumePreview();
|
||||
return alert(loc.wallets.scanQrWif.wallet_already_exists); // duplicate, not adding
|
||||
}
|
||||
}
|
||||
@ -169,6 +166,7 @@ export default class ScanQrWif extends React.Component {
|
||||
} catch (Err) {
|
||||
console.log(Err);
|
||||
this.setState({ isLoading: false });
|
||||
if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.resumePreview();
|
||||
alert(Err.message);
|
||||
return;
|
||||
}
|
||||
@ -218,6 +216,7 @@ export default class ScanQrWif extends React.Component {
|
||||
|
||||
if (newWallet.getAddress() === false && newLegacyWallet.getAddress() === false) {
|
||||
alert(loc.wallets.scanQrWif.bad_wif);
|
||||
if (RNCamera.Constants.CameraStatus === RNCamera.Constants.CameraStatus.READY) this.cameraRef.resumePreview();
|
||||
this.setState({ isLoading: false });
|
||||
return;
|
||||
}
|
||||
@ -303,6 +302,7 @@ export default class ScanQrWif extends React.Component {
|
||||
}}
|
||||
style={{ flex: 1, justifyContent: 'space-between' }}
|
||||
onBarCodeRead={this.onBarCodeScanned}
|
||||
ref={ref => (this.cameraRef = ref)}
|
||||
barCodeTypes={[RNCamera.Constants.BarCodeType.qr]}
|
||||
/>
|
||||
<TouchableOpacity
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* global it, describe, afterAll, beforeAll, jasmine */
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
global.net = require('net');
|
||||
let BlueElectrum = require('../../BlueElectrum');
|
||||
let assert = require('assert');
|
||||
let bitcoin = require('bitcoinjs-lib');
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 150 * 1000;
|
||||
|
||||
afterAll(() => {
|
||||
|
@ -1,9 +1,9 @@
|
||||
/* global it, jasmine, afterAll, beforeAll */
|
||||
import { SegwitP2SHWallet, SegwitBech32Wallet, HDSegwitP2SHWallet, HDLegacyBreadwalletWallet, HDLegacyP2PKHWallet } from '../../class';
|
||||
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
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
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 300 * 1000;
|
||||
@ -155,10 +155,8 @@ it('HD (BIP49) can create TX', async () => {
|
||||
assert.strictEqual(tx.outs.length, 2);
|
||||
assert.strictEqual(tx.outs[0].value, 500);
|
||||
assert.strictEqual(tx.outs[1].value, 25400);
|
||||
let chunksIn = bitcoin.script.decompile(tx.outs[0].script);
|
||||
let toAddress = bitcoin.address.fromOutputScript(chunksIn);
|
||||
chunksIn = bitcoin.script.decompile(tx.outs[1].script);
|
||||
let changeAddress = bitcoin.address.fromOutputScript(chunksIn);
|
||||
let toAddress = bitcoin.address.fromOutputScript(tx.outs[0].script);
|
||||
let changeAddress = bitcoin.address.fromOutputScript(tx.outs[1].script);
|
||||
assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress);
|
||||
assert.strictEqual(hd._getInternalAddressByIndex(hd.next_free_change_address_index), changeAddress);
|
||||
|
||||
@ -175,8 +173,7 @@ it('HD (BIP49) can create TX', async () => {
|
||||
tx = bitcoin.Transaction.fromHex(txhex);
|
||||
assert.strictEqual(tx.ins.length, 1);
|
||||
assert.strictEqual(tx.outs.length, 1);
|
||||
chunksIn = bitcoin.script.decompile(tx.outs[0].script);
|
||||
toAddress = bitcoin.address.fromOutputScript(chunksIn);
|
||||
toAddress = bitcoin.address.fromOutputScript(tx.outs[0].script);
|
||||
assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress);
|
||||
|
||||
// testing sendMAX
|
||||
@ -349,10 +346,8 @@ it('Legacy HD (BIP44) can create TX', async () => {
|
||||
assert.strictEqual(tx.outs.length, 2);
|
||||
assert.strictEqual(tx.outs[0].value, 80000); // payee
|
||||
assert.strictEqual(tx.outs[1].value, 19500); // change
|
||||
let chunksIn = bitcoin.script.decompile(tx.outs[0].script);
|
||||
let toAddress = bitcoin.address.fromOutputScript(chunksIn);
|
||||
chunksIn = bitcoin.script.decompile(tx.outs[1].script);
|
||||
let changeAddress = bitcoin.address.fromOutputScript(chunksIn);
|
||||
let toAddress = bitcoin.address.fromOutputScript(tx.outs[0].script);
|
||||
let changeAddress = bitcoin.address.fromOutputScript(tx.outs[1].script);
|
||||
assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress);
|
||||
assert.strictEqual(hd._getInternalAddressByIndex(hd.next_free_change_address_index), changeAddress);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* global it, describe, jasmine, afterAll, beforeAll */
|
||||
import { HDSegwitBech32Wallet, HDSegwitBech32Transaction, SegwitBech32Wallet } from '../../class';
|
||||
const bitcoin = require('bitcoinjs5');
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
global.crypto = require('crypto'); // shall be used by tests under nodejs CLI, but not in RN environment
|
||||
let assert = require('assert');
|
||||
global.net = require('net'); // needed by Electrum client. For RN it is proviced in shim.js
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* global describe, it */
|
||||
let bitcoinjs = require('bitcoinjs-lib')
|
||||
const bitcoinjs = require('bitcoinjs-lib');
|
||||
let assert = require('assert')
|
||||
|
||||
describe('unit - signer', function () {
|
||||
@ -30,8 +30,8 @@ describe('unit - signer', function () {
|
||||
let txhex = '0100000000010115b7e9d1f6b8164a0e95544a94f5b0fbfaadc35f8415acd0ec0e58d5ce8c1a1e0100000017160014f90e5bca5635b84bd828064586bd7eb117fee9a90000000002905f0100000000001976a914f7c6c1f9f6142107ed293c8fbf85fbc49eb5f1b988ace00f97000000000017a9146fbf1cee74734503297e46a0db3e3fbb06f2e9d38702483045022100bd687693e57161282a80affb82f18386cbf319bca72ca2c16320b0f3b087bee802205e22a9a16b86628ea08eab83aebec1348c476e9d0c90cd41aa73c47f50d86aab0121039425479ea581ebc7f55959da8c2e1a1063491768860386335dd4630b5eeacfc500000000'
|
||||
let signer = require('../../models/signer')
|
||||
let dummyUtxodata = {
|
||||
'15b7e9d1f6b8164a0e95544a94f5b0fbfaadc35f8415acd0ec0e58d5ce8c1a1e': { // txid we use output from
|
||||
1: 666 // output index and it's value in satoshi
|
||||
'1e1a8cced5580eecd0ac15845fc3adfafbb0f5944a54950e4a16b8f6d1e9b715': { // txid we use output from
|
||||
1: 10000000 // output index and it's value in satoshi
|
||||
}
|
||||
}
|
||||
let newhex = signer.createRBFSegwitTransaction(txhex, {'1Pb81K1xJnMjUfFgKUbva6gr1HCHXxHVnr': '3BDsBDxDimYgNZzsqszNZobqQq3yeUoJf2'}, 0.0001, 'KyWpryAKPiXXbipxWhtprZjSLVjp22sxbVnJssq2TCNQxs1SuMeD', dummyUtxodata)
|
||||
|
Loading…
Reference in New Issue
Block a user