Merge branch 'master' of github.com:Overtorment/BlueWallet

This commit is contained in:
Overtorment 2018-07-08 10:35:24 +01:00
commit 46a5030ee6
46 changed files with 493 additions and 1025 deletions

View File

@ -9,6 +9,7 @@
'warn',
{
singleQuote: true,
printWidth: 140,
trailingComma: 'all'
}
]

10
App.js
View File

@ -23,14 +23,8 @@ const appjson = require('./app.json');
const CustomDrawerContentComponent = props => (
<ScrollView>
<SafeAreaView
style={styles.container}
forceInset={{ top: 'always', horizontal: 'never' }}
>
<Text
onPress={() => props.navigation.navigate('About')}
style={styles.heading}
>
<SafeAreaView style={styles.container} forceInset={{ top: 'always', horizontal: 'never' }}>
<Text onPress={() => props.navigation.navigate('About')} style={styles.heading}>
{' '}
{pkg.name} v{pkg.version} (build {appjson.expo.ios.buildNumber})
</Text>

View File

@ -10,6 +10,7 @@ let assert = require('assert');
jest.mock('react-native-qrcode', () => 'Video');
const AsyncStorage = new MockStorage();
jest.setMock('AsyncStorage', AsyncStorage);
jest.useFakeTimers();
jest.mock('Picker', () => {
// eslint-disable-next-line import/no-unresolved
const React = require('React');
@ -164,9 +165,7 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.equal(Storage2.wallets[1].getLabel(), 'testlabel2');
// next, adding new `fake` storage which should be unlocked with `fake` password
let createFakeStorageResult = await Storage2.createFakeStorage(
'fakePassword',
);
let createFakeStorageResult = await Storage2.createFakeStorage('fakePassword');
assert.ok(createFakeStorageResult);
assert.equal(Storage2.wallets.length, 0);
assert.equal(Storage2.cachedPassword, 'fakePassword');
@ -190,46 +189,6 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.equal(Storage3.wallets[0].getLabel(), 'fakewallet');
});
it('bip38 decodes', async () => {
const bip38 = require('./bip38');
const wif = require('wif');
let encryptedKey =
'6PRVWUbkzq2VVjRuv58jpwVjTeN46MeNmzUHqUjQptBJUHGcBakduhrUNc';
let decryptedKey = await bip38.decrypt(
encryptedKey,
'TestingOneTwoThree',
() => {},
{ N: 1, r: 8, p: 8 }, // using non-default parameters to speed it up (not-bip38 compliant)
);
assert.equal(
wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed),
'5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR',
);
});
it('bip38 decodes slow', async () => {
if (process.env.USER === 'burn') {
// run only on circleCI
return;
}
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;
const bip38 = require('bip38');
const wif = require('wif');
let encryptedKey =
'6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN';
let decryptedKey = await bip38.decrypt(encryptedKey, 'qwerty', status =>
process.stdout.write(parseInt(status.percent) + '%\r'),
);
assert.equal(
wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed),
'KxqRtpd9vFju297ACPKHrGkgXuberTveZPXbRDiQ3MXZycSQYtjc',
);
});
it('Wallet can fetch UTXO', async () => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
let w = new SegwitP2SHWallet();
@ -251,11 +210,20 @@ it('Wallet can fetch balance', async () => {
assert.ok(w._lastBalanceFetch > 0);
});
it.skip('Wallet can fetch TXs', async () => {
let w = new LegacyWallet();
w._address = '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG';
await w.fetchTransactions();
console.log('txs num:', w.getTransactions().length);
assert.equal(w.getTransactions().length, 2);
});
describe('currency', () => {
it.only('fetches exchange rate and saves to AsyncStorage', async () => {
it('fetches exchange rate and saves to AsyncStorage', async () => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 15000;
AsyncStorage.storageCache = {}; // cleanup from other tests
let currency = require('./currency');
await currency.startUpdater(true);
await currency.startUpdater();
let cur = AsyncStorage.storageCache[AppStorage.CURRENCY];
cur = JSON.parse(cur);
assert.ok(Number.isInteger(cur[currency.STRUCT.LAST_UPDATED]));

32
App2.test.js Normal file
View File

@ -0,0 +1,32 @@
/* global it, jasmine */
let assert = require('assert');
it('bip38 decodes', async () => {
const bip38 = require('./bip38');
const wif = require('wif');
let encryptedKey = '6PRVWUbkzq2VVjRuv58jpwVjTeN46MeNmzUHqUjQptBJUHGcBakduhrUNc';
let decryptedKey = await bip38.decrypt(
encryptedKey,
'TestingOneTwoThree',
() => {},
{ N: 1, r: 8, p: 8 }, // using non-default parameters to speed it up (not-bip38 compliant)
);
assert.equal(wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed), '5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR');
});
it('bip38 decodes slow', async () => {
if (process.env.USER === 'burn' || process.env.USER === 'igor') {
// run only on circleCI
return;
}
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;
const bip38 = require('bip38');
const wif = require('wif');
let encryptedKey = '6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN';
let decryptedKey = await bip38.decrypt(encryptedKey, 'qwerty', status => process.stdout.write(parseInt(status.percent) + '%\r'));
assert.equal(wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed), 'KxqRtpd9vFju297ACPKHrGkgXuberTveZPXbRDiQ3MXZycSQYtjc');
});

View File

@ -15,10 +15,7 @@ async function startAndDecrypt(retry) {
let password = false;
if (await BlueApp.storageIsEncrypted()) {
do {
password = await prompt(
(retry && loc._.bad_password) || loc._.enter_password,
loc._.storage_is_encrypted,
);
password = await prompt((retry && loc._.bad_password) || loc._.enter_password, loc._.storage_is_encrypted);
} while (!password);
}
let success = await BlueApp.loadFromDisk(password);
@ -35,10 +32,7 @@ async function startAndDecrypt(retry) {
console.log('time to refresh wallet #0');
let oldBalance = wallets[0].getBalance();
await wallets[0].fetchBalance();
if (
oldBalance !== wallets[0].getBalance() ||
wallets[0].getUnconfirmedBalance() !== 0
) {
if (oldBalance !== wallets[0].getBalance() || wallets[0].getUnconfirmedBalance() !== 0) {
// balance changed, thus txs too
await wallets[0].fetchTransactions();
hadToRefresh = true;

View File

@ -3,25 +3,8 @@ import React, { Component } from 'react';
import { SafeAreaView } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import { LinearGradient } from 'expo';
import {
Icon,
Button,
FormLabel,
FormInput,
Card,
Text,
Header,
List,
ListItem,
} from 'react-native-elements';
import {
TouchableOpacity,
ActivityIndicator,
View,
StyleSheet,
Dimensions,
Image,
} from 'react-native';
import { Icon, Button, FormLabel, FormInput, Card, Text, Header, List, ListItem } from 'react-native-elements';
import { TouchableOpacity, ActivityIndicator, View, StyleSheet, Dimensions, Image } from 'react-native';
import Carousel from 'react-native-snap-carousel';
let loc = require('./loc/');
/** @type {AppStorage} */
@ -91,12 +74,7 @@ export class BlueCard extends Component {
export class BlueText extends Component {
render() {
return (
<Text
{...this.props}
style={{ color: BlueApp.settings.foregroundColor }}
/>
);
return <Text {...this.props} style={{ color: BlueApp.settings.foregroundColor }} />;
}
}
@ -123,12 +101,7 @@ export class BlueListItem extends Component {
export class BlueFormLabel extends Component {
render() {
return (
<FormLabel
{...this.props}
labelStyle={{ color: BlueApp.settings.foregroundColor }}
/>
);
return <FormLabel {...this.props} labelStyle={{ color: BlueApp.settings.foregroundColor }} />;
}
}
@ -215,12 +188,7 @@ export class BlueHeaderDefaultSub extends Component {
>
<View style={stylesBlueIcon.box}>
<View style={stylesBlueIcon.ballTransparrent}>
<Icon
name="times"
size={16}
type="font-awesome"
color={BlueApp.settings.foregroundColor}
/>
<Icon name="times" size={16} type="font-awesome" color={BlueApp.settings.foregroundColor} />
</View>
</View>
</TouchableOpacity>
@ -264,12 +232,7 @@ export class BlueHeaderDefaultMain extends Component {
>
<View style={stylesBlueIcon.box}>
<View style={stylesBlueIcon.ballTransparrent}>
<Icon
name="kebab-horizontal"
size={22}
type="octicon"
color={BlueApp.settings.foregroundColor}
/>
<Icon name="kebab-horizontal" size={22} type="octicon" color={BlueApp.settings.foregroundColor} />
</View>
</View>
</TouchableOpacity>
@ -281,23 +244,13 @@ export class BlueHeaderDefaultMain extends Component {
export class BlueSpacing extends Component {
render() {
return (
<View
{...this.props}
style={{ height: 60, backgroundColor: BlueApp.settings.brandingColor }}
/>
);
return <View {...this.props} style={{ height: 60, backgroundColor: BlueApp.settings.brandingColor }} />;
}
}
export class BlueSpacing40 extends Component {
render() {
return (
<View
{...this.props}
style={{ height: 50, backgroundColor: BlueApp.settings.brandingColor }}
/>
);
return <View {...this.props} style={{ height: 50, backgroundColor: BlueApp.settings.brandingColor }} />;
}
}
@ -463,14 +416,7 @@ export class BlueTransactionIncommingIcon extends Component {
<View {...this.props} style={stylesBlueIcon.container}>
<View style={stylesBlueIcon.boxIncomming}>
<View style={stylesBlueIcon.ballIncomming}>
<Icon
{...this.props}
name="arrow-down"
size={16}
type="font-awesome"
color="#37c0a1"
iconStyle={{ left: 0, top: 8 }}
/>
<Icon {...this.props} name="arrow-down" size={16} type="font-awesome" color="#37c0a1" iconStyle={{ left: 0, top: 8 }} />
</View>
</View>
</View>
@ -505,14 +451,7 @@ export class BlueTransactionOutgoingIcon extends Component {
<View {...this.props} style={stylesBlueIcon.container}>
<View style={stylesBlueIcon.boxIncomming}>
<View style={stylesBlueIcon.ballOutgoing}>
<Icon
{...this.props}
name="arrow-down"
size={16}
type="font-awesome"
color="#d0021b"
iconStyle={{ left: 0, top: 8 }}
/>
<Icon {...this.props} name="arrow-down" size={16} type="font-awesome" color="#d0021b" iconStyle={{ left: 0, top: 8 }} />
</View>
</View>
</View>
@ -556,14 +495,7 @@ export class BlueReceiveButtonIcon extends Component {
transform: [{ rotate: '-45deg' }],
}}
>
<Icon
{...this.props}
name="arrow-down"
size={16}
type="font-awesome"
color="#2f5fb3"
iconStyle={{ left: 0, top: 15 }}
/>
<Icon {...this.props} name="arrow-down" size={16} type="font-awesome" color="#2f5fb3" iconStyle={{ left: 0, top: 15 }} />
</View>
<Text
style={{
@ -620,14 +552,7 @@ export class BlueSendButtonIcon extends Component {
transform: [{ rotate: '225deg' }],
}}
>
<Icon
{...this.props}
name="arrow-down"
size={16}
type="font-awesome"
color="#2f5fb3"
iconStyle={{ left: 0, top: 0 }}
/>
<Icon {...this.props} name="arrow-down" size={16} type="font-awesome" color="#2f5fb3" iconStyle={{ left: 0, top: 0 }} />
</View>
<Text
style={{
@ -773,10 +698,7 @@ export class WalletsCarousel extends Component {
}
}}
>
<LinearGradient
colors={['#65ceef', '#68bbe1']}
style={{ padding: 15, borderRadius: 10, height: 145 }}
>
<LinearGradient colors={['#65ceef', '#68bbe1']} style={{ padding: 15, borderRadius: 10, height: 145 }}>
<Image
source={require('./img/btc-shape.png')}
style={{

View File

@ -4,22 +4,20 @@ import {
SegwitBech32Wallet,
HDSegwitP2SHWallet,
HDLegacyBreadwalletWallet,
HDLegacyP2PKHWallet,
LegacyWallet,
} from './class';
let assert = require('assert');
it('can convert witness to address', () => {
let address = SegwitP2SHWallet.witnessToAddress(
'035c618df829af694cb99e664ce1b34f80ad2c3b49bcd0d9c0b1836c66b2d25fd8',
);
let address = SegwitP2SHWallet.witnessToAddress('035c618df829af694cb99e664ce1b34f80ad2c3b49bcd0d9c0b1836c66b2d25fd8');
assert.equal(address, '34ZVGb3gT8xMLT6fpqC6dNVqJtJmvdjbD7');
address = SegwitBech32Wallet.witnessToAddress(
'035c618df829af694cb99e664ce1b34f80ad2c3b49bcd0d9c0b1836c66b2d25fd8',
);
address = SegwitBech32Wallet.witnessToAddress('035c618df829af694cb99e664ce1b34f80ad2c3b49bcd0d9c0b1836c66b2d25fd8');
assert.equal(address, 'bc1quhnve8q4tk3unhmjts7ymxv8cd6w9xv8wy29uv');
});
it('can create a BIP49', function() {
it('can create a Segwit HD (BIP49)', async function() {
let bip39 = require('bip39');
let bitcoin = require('bitcoinjs-lib');
let mnemonic =
@ -35,10 +33,7 @@ it('can create a BIP49', function() {
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.address.fromOutputScript(outputScript, bitcoin.networks.bitcoin);
assert.equal(address, '3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK');
@ -54,24 +49,65 @@ it('can create a BIP49', function() {
assert.equal(true, hd.validateMnemonic());
assert.equal(child.keyPair.toWIF(), hd._getExternalWIFByIndex(0));
assert.equal(
'ypub6WhHmKBmHNjcrUVNCa3sXduH9yxutMipDcwiKW31vWjcMbfhQHjXdyx4rqXbEtVgzdbhFJ5mZJWmfWwnP4Vjzx97admTUYKQt6b9D7jjSCp',
hd.getXpub(),
);
// checking that internal pointer and async address getter return the same address
let freeAddress = await hd.getAddressAsync();
assert.equal(hd._getExternalAddressByIndex(hd.next_free_address_index), freeAddress);
});
it.only('can create a Legacy HD (BIP44)', async function() {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30 * 1000;
let bip39 = require('bip39');
let bitcoin = require('bitcoinjs-lib');
let mnemonic = 'high relief amount witness try remember adult destroy puppy fox giant peace';
assert.ok(bip39.validateMnemonic(mnemonic));
let seed = bip39.mnemonicToSeed(mnemonic);
let root = bitcoin.HDNode.fromSeedBuffer(seed);
let path = "m/44'/0'/0'/0/0";
let child = root.derivePath(path);
let w = new LegacyWallet();
w.setSecret(child.keyPair.toWIF());
assert.equal('12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG', w.getAddress());
// testing our class
let hd = new HDLegacyP2PKHWallet();
hd.setSecret(mnemonic);
assert.equal(hd.validateMnemonic(), true);
assert.equal(hd._getExternalAddressByIndex(0), '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG');
assert.equal(hd._getInternalAddressByIndex(0), '1KZjqYHm7a1DjhjcdcjfQvYfF2h6PqatjX');
assert.equal(
hd.getXpub(),
'xpub6CQdfC3v9gU86eaSn7AhUFcBVxiGhdtYxdC5Cw2vLmFkfth2KXCMmYcPpvZviA89X6DXDs4PJDk5QVL2G2xaVjv7SM4roWHr1gR4xB3Z7Ps',
);
assert.equal(hd._getExternalWIFByIndex(0), 'L1hqNoJ26YuCdujMBJfWBNfgf4Jo7AcKFvcNcKLoMtoJDdDtRq7Q');
assert.equal(hd._getInternalWIFByIndex(0), 'Kx3QkrfemEEV49Mj5oWfb4bsWymboPdstta7eN3kAzop9apxYEFP');
await hd.fetchBalance();
assert.equal(hd.balance, 0);
await hd.fetchTransactions();
assert.equal(hd.transactions.length, 4);
assert.equal(hd.next_free_address_index, 1);
assert.equal(hd.next_free_change_address_index, 1);
// TODO: rewrite fetchTransactions on Frisbee and uncomment:
// let freeAddress = await hd.getAddressAsync();
// assert.equal(hd._getExternalAddressByIndex(hd.next_free_address_index), freeAddress);
});
it('HD breadwallet works', async function() {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 300 * 1000;
let hdBread = new HDLegacyBreadwalletWallet();
hdBread.setSecret(
'high relief amount witness try remember adult destroy puppy fox giant peace',
);
hdBread.setSecret('high relief amount witness try remember adult destroy puppy fox giant peace');
assert.equal(hdBread.validateMnemonic(), true);
assert.equal(
hdBread._getExternalAddressByIndex(0),
'1ARGkNMdsBE36fJhddSwf8PqBXG3s4d2KU',
);
assert.equal(
hdBread._getInternalAddressByIndex(0),
'1JLvA5D7RpWgChb4A5sFcLNrfxYbyZdw3V',
);
assert.equal(hdBread._getExternalAddressByIndex(0), '1ARGkNMdsBE36fJhddSwf8PqBXG3s4d2KU');
assert.equal(hdBread._getInternalAddressByIndex(0), '1JLvA5D7RpWgChb4A5sFcLNrfxYbyZdw3V');
assert.equal(
hdBread.getXpub(),

View File

@ -14,17 +14,13 @@ export default class MockStorage {
getItem = jest.fn(key => {
return new Promise(resolve => {
return this.storageCache.hasOwnProperty(key)
? resolve(this.storageCache[key])
: resolve(null);
return this.storageCache.hasOwnProperty(key) ? resolve(this.storageCache[key]) : resolve(null);
});
});
removeItem = jest.fn(key => {
return new Promise((resolve, reject) => {
return this.storageCache.hasOwnProperty(key)
? resolve(delete this.storageCache[key])
: reject(new Error('No such key!'));
return this.storageCache.hasOwnProperty(key) ? resolve(delete this.storageCache[key]) : reject(new Error('No such key!'));
});
});
@ -33,8 +29,6 @@ export default class MockStorage {
});
getAllKeys = jest.fn(key => {
return new Promise((resolve, reject) =>
resolve(Object.keys(this.storageCache)),
);
return new Promise((resolve, reject) => resolve(Object.keys(this.storageCache)));
});
}

View File

@ -1,6 +1,7 @@
# BlueWallet - Bitcoin Wallet
[![CircleCI](https://circleci.com/gh/Overtorment/BlueWallet.svg?style=svg)](https://circleci.com/gh/Overtorment/BlueWallet)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
Thin Bitcoin Wallet.
Built with React Native, Expo and BlockCypher API.

View File

@ -197,9 +197,7 @@ export class AppStorage {
} else {
// decrypted ok, this is our bucket
// we serialize our object's data, encrypt it, and add it to buckets
newData.push(
encryption.encrypt(JSON.stringify(data), this.cachedPassword),
);
newData.push(encryption.encrypt(JSON.stringify(data), this.cachedPassword));
await AsyncStorage.setItem(AppStorage.FLAG_ENCRYPTED, '1');
}
}

View File

@ -4,7 +4,7 @@ const bip39 = require('bip39');
/**
* HD Wallet (BIP39).
* In particular, BIP49 (P2SH Segwit) https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki
* In particular, Breadwallet-compatible (Legacy addresses)
*/
export class HDLegacyBreadwalletWallet extends HDSegwitP2SHWallet {
constructor() {
@ -16,10 +16,6 @@ export class HDLegacyBreadwalletWallet extends HDSegwitP2SHWallet {
return 'HD Legacy Breadwallet-compatible (P2PKH)';
}
getAddress() {
// TODO: derive from hierarchy, return next free address
}
/**
* @see https://github.com/bitcoinjs/bitcoinjs-lib/issues/584
* @see https://github.com/bitcoinjs/bitcoinjs-lib/issues/914
@ -59,4 +55,28 @@ export class HDLegacyBreadwalletWallet extends HDSegwitP2SHWallet {
return child.getAddress();
}
_getExternalWIFByIndex(index) {
index = index * 1; // cast to int
let mnemonic = this.secret;
let seed = bip39.mnemonicToSeed(mnemonic);
let root = bitcoin.HDNode.fromSeedBuffer(seed);
let path = "m/0'/1/" + index;
let child = root.derivePath(path);
return child.keyPair.toWIF();
}
_getInternalWIFByIndex(index) {
index = index * 1; // cast to int
let mnemonic = this.secret;
let seed = bip39.mnemonicToSeed(mnemonic);
let root = bitcoin.HDNode.fromSeedBuffer(seed);
let path = "m/0'/1/" + index;
let child = root.derivePath(path);
return child.keyPair.toWIF();
}
getAddressAsync() {
// TODO
}
}

View File

@ -0,0 +1,104 @@
import { LegacyWallet, HDSegwitP2SHWallet } from './';
const bitcoin = require('bitcoinjs-lib');
const bip39 = require('bip39');
/**
* HD Wallet (BIP39).
* In particular, BIP44 (P2PKH legacy addressess)
* @see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
*/
export class HDLegacyP2PKHWallet extends HDSegwitP2SHWallet {
constructor() {
super();
this.type = 'HDlegacyP2PKH';
}
getTypeReadable() {
return 'HD Legacy (BIP44 P2PKH)';
}
getXpub() {
let mnemonic = this.secret;
let seed = bip39.mnemonicToSeed(mnemonic);
let root = bitcoin.HDNode.fromSeedBuffer(seed);
let path = "m/44'/0'/0'";
let child = root.derivePath(path).neutered();
return child.toBase58();
}
_getExternalWIFByIndex(index) {
index = index * 1; // cast to int
let mnemonic = this.secret;
let seed = bip39.mnemonicToSeed(mnemonic);
let root = bitcoin.HDNode.fromSeedBuffer(seed);
let path = "m/44'/0'/0'/0/" + index;
let child = root.derivePath(path);
return child.keyPair.toWIF();
}
_getInternalWIFByIndex(index) {
index = index * 1; // cast to int
let mnemonic = this.secret;
let seed = bip39.mnemonicToSeed(mnemonic);
let root = bitcoin.HDNode.fromSeedBuffer(seed);
let path = "m/44'/0'/0'/1/" + index;
let child = root.derivePath(path);
return child.keyPair.toWIF();
}
_getExternalAddressByIndex(index) {
index = index * 1; // cast to int
let mnemonic = this.secret;
let seed = bip39.mnemonicToSeed(mnemonic);
let root = bitcoin.HDNode.fromSeedBuffer(seed);
let path = "m/44'/0'/0'/0/" + index;
let child = root.derivePath(path);
let w = new LegacyWallet();
w.setSecret(child.keyPair.toWIF());
return w.getAddress();
}
_getInternalAddressByIndex(index) {
index = index * 1; // cast to int
let mnemonic = this.secret;
let seed = bip39.mnemonicToSeed(mnemonic);
let root = bitcoin.HDNode.fromSeedBuffer(seed);
let path = "m/44'/0'/0'/1/" + index;
let child = root.derivePath(path);
let w = new LegacyWallet();
w.setSecret(child.keyPair.toWIF());
return w.getAddress();
}
/**
* @inheritDoc
*/
async getAddressAsync() {
// looking for free external address
let freeAddress = '';
let c;
for (c = -1; c < 5; c++) {
let Legacy = new LegacyWallet();
Legacy.setSecret(this._getExternalWIFByIndex(this.next_free_address_index + c));
await Legacy.fetchTransactions();
if (Legacy.transactions.length === 0) {
// found free address
freeAddress = Legacy.getAddress();
this.next_free_address_index += c + 1; // now points to the one _after_
break;
}
}
if (!freeAddress) {
// could not find in cycle above, give up
freeAddress = this._getExternalAddressByIndex(this.next_free_address_index + c); // we didnt check this one, maybe its free
this.next_free_address_index += c + 1; // now points to the one _after_
}
return freeAddress;
}
}

View File

@ -3,10 +3,12 @@ import { SegwitP2SHWallet } from './segwit-p2sh-wallet';
import Frisbee from 'frisbee';
const bitcoin = require('bitcoinjs-lib');
const bip39 = require('bip39');
const BigNumber = require('bignumber.js');
/**
* HD Wallet (BIP39).
* In particular, BIP49 (P2SH Segwit) https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki
* In particular, BIP49 (P2SH Segwit)
* @see https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki
*/
export class HDSegwitP2SHWallet extends LegacyWallet {
constructor() {
@ -18,18 +20,22 @@ export class HDSegwitP2SHWallet extends LegacyWallet {
this.external_addresses_cache = {}; // index => address
}
allowSend() {
return false; // TODO send from HD
}
validateMnemonic() {
return bip39.validateMnemonic(this.secret);
}
getTypeReadable() {
return 'HD SegWit (P2SH)';
return 'HD SegWit (BIP49 P2SH)';
}
/**
* Derives from hierarchy, returns next free address
* (the one that has no transactions). Looks for several,
* gve ups if none found, and returns the used one
* gives up if none found, and returns the used one
*
* @return {Promise.<string>}
*/
@ -39,9 +45,7 @@ export class HDSegwitP2SHWallet extends LegacyWallet {
let c;
for (c = -1; c < 5; c++) {
let Segwit = new SegwitP2SHWallet();
Segwit.setSecret(
this._getExternalWIFByIndex(this.next_free_address_index + c),
);
Segwit.setSecret(this._getExternalWIFByIndex(this.next_free_address_index + c));
await Segwit.fetchTransactions();
if (Segwit.transactions.length === 0) {
// found free address
@ -53,9 +57,7 @@ export class HDSegwitP2SHWallet extends LegacyWallet {
if (!freeAddress) {
// could not find in cycle above, give up
freeAddress = this._getExternalAddressByIndex(
this.next_free_address_index + c,
); // we didnt check this one, maybe its free
freeAddress = this._getExternalAddressByIndex(this.next_free_address_index + c); // we didnt check this one, maybe its free
this.next_free_address_index += c + 1; // now points to the one _after_
}
@ -94,12 +96,7 @@ export class HDSegwitP2SHWallet extends LegacyWallet {
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,
);
return address;
return bitcoin.address.fromOutputScript(outputScript, bitcoin.networks.bitcoin);
}
_getInternalAddressByIndex(index) {
@ -115,10 +112,17 @@ export class HDSegwitP2SHWallet extends LegacyWallet {
let scriptSig = bitcoin.script.witnessPubKeyHash.output.encode(keyhash);
let addressBytes = bitcoin.crypto.hash160(scriptSig);
let outputScript = bitcoin.script.scriptHash.output.encode(addressBytes);
return bitcoin.address.fromOutputScript(
outputScript,
bitcoin.networks.bitcoin,
);
return bitcoin.address.fromOutputScript(outputScript, bitcoin.networks.bitcoin);
}
getXpub() {
let mnemonic = this.secret;
let seed = bip39.mnemonicToSeed(mnemonic);
let root = bitcoin.HDNode.fromSeedBuffer(seed);
let path = "m/49'/0'/0'";
let child = root.derivePath(path).neutered();
return child.toBase58();
}
async fetchBalance() {
@ -135,15 +139,21 @@ export class HDSegwitP2SHWallet extends LegacyWallet {
}
}
/**
* Async function to fetch all transactions. Use getter to get actual txs.
* Also, sets internals:
* `this.internal_addresses_cache`
* `this.external_addresses_cache`
*
* @returns {Promise<void>}
*/
async fetchTransactions() {
const api = new Frisbee({ baseURI: 'https://blockchain.info' });
this.transactions = [];
let offset = 0;
while (1) {
let response = await api.get(
'/multiaddr?active=' + this.getXpub() + '&n=100&offset=' + offset,
);
let response = await api.get('/multiaddr?active=' + this.getXpub() + '&n=100&offset=' + offset);
if (response && response.body) {
if (response.body.txs && response.body.txs.length === 0) {
@ -165,18 +175,12 @@ export class HDSegwitP2SHWallet extends LegacyWallet {
let path = input.prev_out.xpub.path.split('/');
if (path[path.length - 2] === '1') {
// change address
this.next_free_change_address_index = Math.max(
path[path.length - 1] * 1 + 1,
this.next_free_change_address_index,
);
this.next_free_change_address_index = Math.max(path[path.length - 1] * 1 + 1, this.next_free_change_address_index);
// setting to point to last maximum known change address + 1
}
if (path[path.length - 2] === '0') {
// main (aka external) address
this.next_free_address_index = Math.max(
path[path.length - 1] * 1 + 1,
this.next_free_address_index,
);
this.next_free_address_index = Math.max(path[path.length - 1] * 1 + 1, this.next_free_address_index);
// setting to point to last maximum known main address + 1
}
// done with cache
@ -193,25 +197,19 @@ export class HDSegwitP2SHWallet extends LegacyWallet {
let path = output.xpub.path.split('/');
if (path[path.length - 2] === '1') {
// change address
this.next_free_change_address_index = Math.max(
path[path.length - 1] * 1 + 1,
this.next_free_change_address_index,
);
this.next_free_change_address_index = Math.max(path[path.length - 1] * 1 + 1, this.next_free_change_address_index);
// setting to point to last maximum known change address + 1
}
if (path[path.length - 2] === '0') {
// main (aka external) address
this.next_free_address_index = Math.max(
path[path.length - 1] * 1 + 1,
this.next_free_address_index,
);
this.next_free_address_index = Math.max(path[path.length - 1] * 1 + 1, this.next_free_address_index);
// setting to point to last maximum known main address + 1
}
// done with cache
}
}
tx.value = value / 100000000;
tx.value = new BigNumber(value).div(100000000).toString() * 1;
this.transactions.push(tx);
}
@ -219,7 +217,7 @@ export class HDSegwitP2SHWallet extends LegacyWallet {
break; // error ?
}
} else {
throw new Error('Could not fetch balance from API'); // breaks here
throw new Error('Could not fetch transactions from API'); // breaks here
}
offset += 100;

View File

@ -6,3 +6,4 @@ export * from './segwit-bech-wallet';
export * from './segwit-p2sh-wallet';
export * from './hd-segwit-p2sh-wallet';
export * from './hd-legacy-breadwallet-wallet';
export * from './hd-legacy-p2pkh-wallet';

View File

@ -83,25 +83,17 @@ export class LegacyWallet extends AbstractWallet {
});
let response = await api.get(
this.getAddress() +
'/balance' +
((useBlockcypherTokens &&
'&token=' + this.getRandomBlockcypherToken()) ||
''),
this.getAddress() + '/balance' + ((useBlockcypherTokens && '&token=' + this.getRandomBlockcypherToken()) || ''),
);
let json = response.body;
if (
typeof json === 'undefined' ||
typeof json.final_balance === 'undefined'
) {
if (typeof json === 'undefined' || typeof json.final_balance === 'undefined') {
throw new Error('Could not fetch UTXO from API' + response.err);
}
this.balance = new BigNumber(json.final_balance);
this.balance = this.balance.div(100000000).toString() * 1;
this.unconfirmed_balance = new BigNumber(json.unconfirmed_balance);
this.unconfirmed_balance =
this.unconfirmed_balance.div(100000000).toString() * 1;
this.unconfirmed_balance = this.unconfirmed_balance.div(100000000).toString() * 1;
this._lastBalanceFetch = +new Date();
} catch (err) {
console.warn(err);
@ -129,15 +121,10 @@ export class LegacyWallet extends AbstractWallet {
this.getAddress() +
'?limit=2000&after=' +
maxHeight +
((useBlockcypherTokens &&
'&token=' + this.getRandomBlockcypherToken()) ||
''),
((useBlockcypherTokens && '&token=' + this.getRandomBlockcypherToken()) || ''),
);
json = response.body;
if (
typeof json === 'undefined' ||
typeof json.final_balance === 'undefined'
) {
if (typeof json === 'undefined' || typeof json.final_balance === 'undefined') {
throw new Error('Could not fetch UTXO from API' + response.err);
}
json.txrefs = json.txrefs || []; // case when source address is empty (or maxheight too high, no txs)
@ -169,19 +156,10 @@ export class LegacyWallet extends AbstractWallet {
let url;
if (useBlockcypherTokens) {
response = await fetch(
(url =
'https://api.blockcypher.com/v1/btc/main/addrs/' +
this.getAddress() +
'/full?token=' +
this.getRandomBlockcypherToken()),
(url = 'https://api.blockcypher.com/v1/btc/main/addrs/' + this.getAddress() + '/full?token=' + this.getRandomBlockcypherToken()),
);
} else {
response = await fetch(
(url =
'https://api.blockcypher.com/v1/btc/main/addrs/' +
this.getAddress() +
'/full'),
);
response = await fetch((url = 'https://api.blockcypher.com/v1/btc/main/addrs/' + this.getAddress() + '/full'));
}
console.log(url);
let json = await response.json();
@ -369,25 +347,9 @@ export class LegacyWallet extends AbstractWallet {
u.amount = u.amount.div(100000000);
u.amount = u.amount.toString(10);
}
console.log(
'creating legacy tx ',
amount,
' with fee ',
fee,
'secret=',
this.getSecret(),
'from address',
this.getAddress(),
);
console.log('creating legacy tx ', amount, ' with fee ', fee, 'secret=', this.getSecret(), 'from address', this.getAddress());
let amountPlusFee = parseFloat(new BigNumber(amount).add(fee).toString(10));
return signer.createTransaction(
utxos,
toAddress,
amountPlusFee,
fee,
this.getSecret(),
this.getAddress(),
);
return signer.createTransaction(utxos, toAddress, amountPlusFee, fee, this.getSecret(), this.getAddress());
}
getLatestTransactionTime() {

View File

@ -17,9 +17,7 @@ export class SegwitBech32Wallet extends LegacyWallet {
try {
let keyPair = bitcoin.ECPair.fromWIF(this.secret);
let pubKey = keyPair.getPublicKeyBuffer();
let scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(
bitcoin.crypto.hash160(pubKey),
);
let scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(pubKey));
address = bitcoin.address.fromOutputScript(scriptPubKey);
} catch (err) {
return false;
@ -32,12 +30,7 @@ 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,
);
const scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(pubKeyHash);
return bitcoin.address.fromOutputScript(scriptPubKey, bitcoin.networks.bitcoin);
}
}

View File

@ -16,17 +16,10 @@ 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 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,
);
const scriptPubkey = bitcoin.script.scriptHash.output.encode(redeemScriptHash);
return bitcoin.address.fromOutputScript(scriptPubkey, bitcoin.networks.bitcoin);
}
getAddress() {
@ -35,12 +28,8 @@ export class SegwitP2SHWallet extends LegacyWallet {
try {
let keyPair = bitcoin.ECPair.fromWIF(this.secret);
let pubKey = keyPair.getPublicKeyBuffer();
let witnessScript = bitcoin.script.witnessPubKeyHash.output.encode(
bitcoin.crypto.hash160(pubKey),
);
let scriptPubKey = bitcoin.script.scriptHash.output.encode(
bitcoin.crypto.hash160(witnessScript),
);
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);
} catch (err) {
return false;
@ -76,26 +65,9 @@ export class SegwitP2SHWallet extends LegacyWallet {
u.amount = u.amount.div(100000000);
u.amount = u.amount.toString(10);
}
console.log(
'creating tx ',
amount,
' with fee ',
fee,
'secret=',
this.getSecret(),
'from address',
this.getAddress(),
);
console.log('creating tx ', amount, ' with fee ', fee, 'secret=', this.getSecret(), 'from address', this.getAddress());
let amountPlusFee = parseFloat(new BigNumber(amount).add(fee).toString(10));
// to compensate that module substracts fee from amount
return signer.createSegwitTransaction(
utxos,
address,
amountPlusFee,
fee,
this.getSecret(),
this.getAddress(),
sequence,
);
return signer.createSegwitTransaction(utxos, address, amountPlusFee, fee, this.getSecret(), this.getAddress(), sequence);
}
}

View File

@ -37,7 +37,7 @@ async function updateExchangeRate() {
console.log('updated currency exchange:', lang);
}
async function startUpdater(doNotSetInterval) {
async function startUpdater() {
lang = await AsyncStorage.getItem(AppStorage.CURRENCY);
try {
lang = JSON.parse(lang);
@ -52,9 +52,7 @@ async function startUpdater(doNotSetInterval) {
lang[STRUCT.LAST_UPDATED] = lang[STRUCT.LAST_UPDATED] || 0;
lang[STRUCT.BTC_USD] = lang[STRUCT.BTC_USD] || 6500;
if (!doNotSetInterval) {
setInterval(() => updateExchangeRate(), 2 * 60 * 100);
}
setInterval(() => updateExchangeRate(), 2 * 60 * 100);
return updateExchangeRate();
}

View File

@ -1,11 +1,6 @@
function EV(eventName, arg) {
if (Object.values(EV.enum).indexOf(eventName) === -1) {
return console.warn(
'Unregistered event',
eventName,
'registered events:',
EV.enum,
);
return console.warn('Unregistered event', eventName, 'registered events:', EV.enum);
}
EV.callbacks = EV.callbacks || {}; // static variable
EV.callbacks[eventName] = EV.callbacks[eventName] || [];
@ -27,8 +22,7 @@ function EV(eventName, arg) {
EV.enum = {
WALLETS_COUNT_CHANGED: 'WALLETS_COUNT_CHANGED',
TRANSACTIONS_COUNT_CHANGED: 'TRANSACTIONS_COUNT_CHANGED',
CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS:
'CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS',
CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS: 'CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS',
RECEIVE_ADDRESS_CHANGED: 'RECEIVE_ADDRESS_CHANGED',
};

View File

@ -1,7 +1,6 @@
module.exports = {
_: {
storage_is_encrypted:
'Your storage is encrypted. Password is required to decrypt it',
storage_is_encrypted: 'Your storage is encrypted. Password is required to decrypt it',
enter_password: 'Enter password',
bad_password: 'Bad pasword, try again',
months_ago: 'months ago',
@ -14,9 +13,7 @@ module.exports = {
tabBarLabel: 'Wallets',
app_name: 'Blue Wallet',
title: 'wallets',
header:
'A wallet represents a pair of a secret (private key) and an address' +
'you can share to receive coins.',
header: 'A wallet represents a pair of a secret (private key) and an address' + 'you can share to receive coins.',
add: 'Add Wallet',
create_a_wallet: 'Create a wallet',
create_a_wallet1: "It's free and you can create",
@ -98,8 +95,7 @@ module.exports = {
title: 'Create Transaction',
error: 'Error creating transaction. Invalid address or send amount?',
go_back: 'Go Back',
this_is_hex:
'This is transaction hex, signed and ready to be broadcast to the network. Continue?',
this_is_hex: 'This is transaction hex, signed and ready to be broadcast to the network. Continue?',
to: 'To',
amount: 'Amount',
fee: 'Fee',
@ -141,16 +137,12 @@ module.exports = {
"BlueWallet, it will unlock new 'fake' storage. This will seem " +
'legit to a 3rd party, but will secretly keep your main storage ' +
'with coins safe.',
help2:
'New storage will be fully functional, and you can store some ' +
'minimum amounts there so it looks more believable.',
help2: 'New storage will be fully functional, and you can store some ' + 'minimum amounts there so it looks more believable.',
create_fake_storage: 'Create fake encrypted storage',
go_back: 'Go Back',
create_password: 'Create a password',
create_password_explanation:
'Password for fake storage should not match password for your main storage',
password_should_not_match:
'Password for fake storage should not match password for your main storage',
create_password_explanation: 'Password for fake storage should not match password for your main storage',
password_should_not_match: 'Password for fake storage should not match password for your main storage',
retype_password: 'Retype password',
passwords_do_not_match: 'Passwords do not match, try again',
success: 'Success',

View File

@ -4,9 +4,7 @@ module.exports = {
tabBarLabel: 'Monederos',
app_name: 'Blue Wallet',
title: 'Mi Monederos de Bitcoin',
header:
'Un Monedero esta representado con secreto (clave privada) y una dirección' +
'que puedes compartir para recibir monedas.',
header: 'Un Monedero esta representado con secreto (clave privada) y una dirección' + 'que puedes compartir para recibir monedas.',
add: 'Añadir Monedero',
},
add: {
@ -50,8 +48,7 @@ module.exports = {
list: {
tabBarLabel: 'Transacciónes',
title: 'Mi Transacciónes',
description:
'Una lista de las transacciones entrantes o salientes de sus monederos',
description: 'Una lista de las transacciones entrantes o salientes de sus monederos',
conf: 'conf',
},
details: {
@ -81,11 +78,9 @@ module.exports = {
},
create: {
title: 'Crear una Transaccion',
error:
'Error al crear una transacción. ¿Dirección o cantidad estan invalidas?',
error: 'Error al crear una transacción. ¿Dirección o cantidad estan invalidas?',
go_back: 'Regresar',
this_is_hex:
'Este es representacion hex de transacción, firmado y listo para ser transmitido a la red. ¿Continuar?',
this_is_hex: 'Este es representacion hex de transacción, firmado y listo para ser transmitido a la red. ¿Continuar?',
to: 'A',
amount: 'Cantidad',
fee: 'Tasa',
@ -110,8 +105,7 @@ module.exports = {
plausible_deniability: 'Negación plausible...',
storage_not_encrypted: 'Almacenamiento: no esta encriptado',
password: 'Contraseña',
password_explain:
'Crea la contraseña que usarás para descifrar el almacenamiento',
password_explain: 'Crea la contraseña que usarás para descifrar el almacenamiento',
retype_password: 'Ingresa la contraseña de nuevo',
passwords_do_not_match: 'Contraseñas deben ser iguales',
encrypt_storage: 'Cifrar almacenamiento',

View File

@ -21,13 +21,7 @@ let strings;
locale = locale.split('-');
locale = locale[0];
console.log('current locale:', locale);
if (
locale === 'en' ||
locale === 'ru' ||
locale === 'ua' ||
locale === 'es' ||
locale === 'pt'
) {
if (locale === 'en' || locale === 'ru' || locale === 'ua' || locale === 'es' || locale === 'pt') {
strings.setLanguage(locale);
} else {
strings.setLanguage('en');

View File

@ -1,7 +1,6 @@
module.exports = {
_: {
storage_is_encrypted:
'O armazenamento está encriptado. Uma password é necessaria para desencriptar',
storage_is_encrypted: 'O armazenamento está encriptado. Uma password é necessaria para desencriptar',
enter_password: 'Inserir password',
bad_password: 'pasword errada, tentar novamente',
},
@ -10,9 +9,7 @@ module.exports = {
tabBarLabel: 'Wallets',
app_name: 'Blue Wallet',
title: 'Minhas Bitcoin Wallets',
header:
'Uma wallet representa um par entre um segredo (chave privada) e um endereço' +
'que pode partilhar para receber Bitcoin.',
header: 'Uma wallet representa um par entre um segredo (chave privada) e um endereço' + 'que pode partilhar para receber Bitcoin.',
add: 'Adicionar Wallet',
},
add: {
@ -56,8 +53,7 @@ module.exports = {
list: {
tabBarLabel: 'Transações',
title: 'Minhas Transações',
description:
'Uma lista de transações feitas ou recebidas nas suas wallets',
description: 'Uma lista de transações feitas ou recebidas nas suas wallets',
conf: 'conf',
},
details: {
@ -89,8 +85,7 @@ module.exports = {
title: 'Criar Transacção',
error: 'Erro ao criar transação. Endereço inválido ou quantia?',
go_back: 'Voltar',
this_is_hex:
'Este é o hex da transação, assinado e pronto para ser difundido para a network. Continuar?',
this_is_hex: 'Este é o hex da transação, assinado e pronto para ser difundido para a network. Continuar?',
to: 'Para',
amount: 'Quantia',
fee: 'Taxa',
@ -132,16 +127,12 @@ module.exports = {
'BlueWallet, esta vai abrir um armazenamento "falso". Que vai parecer ' +
'legítimo a um terceiro, mas que secretamente vai manter o seu armazenamento principal ' +
'com as moedas em segurança.',
help2:
'Este novo armazenamento é completamente funcional, e pode guardar ' +
'um valor minímo para parecer mais real.',
help2: 'Este novo armazenamento é completamente funcional, e pode guardar ' + 'um valor minímo para parecer mais real.',
create_fake_storage: 'Criar armazenamento encriptado FALSO',
go_back: 'Voltar',
create_password: 'Criar password',
create_password_explanation:
'Password para armazenamento FALSO não deve coincidir com o principal',
password_should_not_match:
'Password para armazenamento FALSO não deve coincidir com o principal',
create_password_explanation: 'Password para armazenamento FALSO não deve coincidir com o principal',
password_should_not_match: 'Password para armazenamento FALSO não deve coincidir com o principal',
retype_password: 'Inserir password novamente',
passwords_do_not_match: 'Passwords não coincidem, tente novamente',
success: 'Sucesso',

View File

@ -1,7 +1,6 @@
module.exports = {
_: {
storage_is_encrypted:
'O armazenamento está encriptado. Uma password é necessaria para desencriptar',
storage_is_encrypted: 'O armazenamento está encriptado. Uma password é necessaria para desencriptar',
enter_password: 'Inserir password',
bad_password: 'pasword errada, tente novamente',
},
@ -10,9 +9,7 @@ module.exports = {
tabBarLabel: 'Wallets',
app_name: 'Blue Wallet',
title: 'Minhas Bitcoin Wallets',
header:
'Uma wallet representa um par entre um segredo (chave privada) e um endereço' +
'que pode partilhar para receber Bitcoin.',
header: 'Uma wallet representa um par entre um segredo (chave privada) e um endereço' + 'que pode partilhar para receber Bitcoin.',
add: 'Adicionar Wallet',
},
add: {
@ -56,8 +53,7 @@ module.exports = {
list: {
tabBarLabel: 'Transacções',
title: 'Minhas Transacções',
description:
'Uma lista de transações feitas ou recebidas nas suas wallets',
description: 'Uma lista de transações feitas ou recebidas nas suas wallets',
conf: 'conf',
},
details: {
@ -89,8 +85,7 @@ module.exports = {
title: 'Criar Transacção',
error: 'Erro ao criar transacção. Endereço inválido ou quantia?',
go_back: 'Voltar',
this_is_hex:
'Este é o hex da transacção, assinado e pronto para ser difundido para a network. Continuar?',
this_is_hex: 'Este é o hex da transacção, assinado e pronto para ser difundido para a network. Continuar?',
to: 'Para',
amount: 'Quantia',
fee: 'Taxa',
@ -132,16 +127,12 @@ module.exports = {
'BlueWallet, esta vai abrir um armazenamento "falso". Que vai parecer ' +
'legítimo a um terceiro, mas que secretamente vai manter o seu armazenamento principal ' +
'com as moedas em segurança.',
help2:
'Este novo armazenamento é completamente funcional, e pode guardar ' +
'um valor minímo para parecer mais real.',
help2: 'Este novo armazenamento é completamente funcional, e pode guardar ' + 'um valor minímo para parecer mais real.',
create_fake_storage: 'Criar armazenamento encriptado FALSO',
go_back: 'Voltar',
create_password: 'Criar password',
create_password_explanation:
'Password para armazenamento FALSO não deve coincidir com o principal',
password_should_not_match:
'Password para armazenamento FALSO não deve coincidir com o principal',
create_password_explanation: 'Password para armazenamento FALSO não deve coincidir com o principal',
password_should_not_match: 'Password para armazenamento FALSO não deve coincidir com o principal',
retype_password: 'Inserir password novamente',
passwords_do_not_match: 'Passwords não coincidem, tente novamente',
success: 'Sucesso',

View File

@ -1,7 +1,6 @@
module.exports = {
_: {
storage_is_encrypted:
'Ваше хранилище зашифровано. Введите пароль для расшифровки',
storage_is_encrypted: 'Ваше хранилище зашифровано. Введите пароль для расшифровки',
enter_password: 'Введите пароль',
bad_password: 'Неверный пароль, попробуйте еще раз',
months_ago: 'месяцев назад',
@ -14,8 +13,7 @@ module.exports = {
tabBarLabel: 'Кошельки',
app_name: 'BlueWallet',
title: 'Мои Кошельки',
header:
'Кошелек это секретный (приватный) ключ, и соответствующий ему адрес на который можно получать биткоины',
header: 'Кошелек это секретный (приватный) ключ, и соответствующий ему адрес на который можно получать биткоины',
add: 'Добавить Кошелек',
create_a_wallet: 'Создать кошелек',
create_a_wallet1: 'Это бесплатно и вы можете создать',
@ -95,11 +93,9 @@ module.exports = {
},
create: {
title: 'Создать Транзакцию',
error:
'Ошибка при создании транзакции. Неправильный адрес назначения или недостаточно средств?',
error: 'Ошибка при создании транзакции. Неправильный адрес назначения или недостаточно средств?',
go_back: 'Назад',
this_is_hex:
'Это данные транзакции. Транзакция подписана и готова быть транслирована в сеть. Продолжить?',
this_is_hex: 'Это данные транзакции. Транзакция подписана и готова быть транслирована в сеть. Продолжить?',
to: 'Куда',
amount: 'Сколько',
fee: 'Комиссия',
@ -147,10 +143,8 @@ module.exports = {
create_fake_storage: 'Создать фальшивое хранилище',
go_back: 'Назад',
create_password: 'Придумайте пароль',
create_password_explanation:
'Пароль для фальшивого хранилища не должен быть таким же как основной пароль',
password_should_not_match:
'Пароль для фальшивого хранилища не должен быть таким же как основной пароль',
create_password_explanation: 'Пароль для фальшивого хранилища не должен быть таким же как основной пароль',
password_should_not_match: 'Пароль для фальшивого хранилища не должен быть таким же как основной пароль',
retype_password: 'Наберите пароль повторно',
passwords_do_not_match: 'Пароли не совпадают, попробуйте еще раз',
success: 'Операция успешна',

View File

@ -1,7 +1,6 @@
module.exports = {
_: {
storage_is_encrypted:
'Ваше сховище зашифроване. Введіть пароль для розшифровки',
storage_is_encrypted: 'Ваше сховище зашифроване. Введіть пароль для розшифровки',
enter_password: 'Введіть пароль',
bad_password: 'Невірний пароль, спробуйте ще раз',
},
@ -10,8 +9,7 @@ module.exports = {
tabBarLabel: 'Гаманці',
app_name: 'BlueWallet',
title: 'Мої Біткоїн Гаманці',
header:
'Гаманець це секретний (приватний) ключ, і відповідна йому адреса на яку можна отримувати біткоїни',
header: 'Гаманець це секретний (приватний) ключ, і відповідна йому адреса на яку можна отримувати біткоїни',
add: 'Додати Гаманець',
},
add: {
@ -85,11 +83,9 @@ module.exports = {
},
create: {
title: 'Створити Транзакцію',
error:
'Помилка при створенні транзакції. Невiрна адреса призначення або недостатньо коштiв?',
error: 'Помилка при створенні транзакції. Невiрна адреса призначення або недостатньо коштiв?',
go_back: 'Назад',
this_is_hex:
'Це дані транзакції. Транзакція підписана і готова бути трансльована в мережу. Продовжити?',
this_is_hex: 'Це дані транзакції. Транзакція підписана і готова бути трансльована в мережу. Продовжити?',
to: 'Куди',
amount: 'Скільки',
fee: 'Комісія',
@ -137,10 +133,8 @@ module.exports = {
create_fake_storage: 'Створити фальшиве сховище',
go_back: 'Назад',
create_password: 'Придумайте пароль',
create_password_explanation:
'Пароль для фальшивого сховіща не має буті таким же як основній пароль',
password_should_not_match:
'Пароль для фальшивого сховища не має бути таким же як основний пароль',
create_password_explanation: 'Пароль для фальшивого сховіща не має буті таким же як основній пароль',
password_should_not_match: 'Пароль для фальшивого сховища не має бути таким же як основний пароль',
retype_password: 'Наберіть пароль ще раз',
passwords_do_not_match: 'Паролі не збігаються, спробуйте ще раз',
success: 'Операція успішна',

View File

@ -9,15 +9,7 @@
let bitcoinjs = require('bitcoinjs-lib');
const toSatoshi = num => parseInt((num * 100000000).toFixed(0));
exports.createSegwitTransaction = function(
utxos,
toAddress,
amount,
fixedFee,
WIF,
changeAddress,
sequence,
) {
exports.createSegwitTransaction = function(utxos, toAddress, amount, fixedFee, WIF, changeAddress, sequence) {
changeAddress = changeAddress || exports.WIF2segwitAddress(WIF);
if (sequence === undefined) {
sequence = bitcoinjs.Transaction.DEFAULT_SEQUENCE;
@ -27,9 +19,7 @@ exports.createSegwitTransaction = function(
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 redeemScript = bitcoinjs.script.witnessPubKeyHash.output.encode(pubKeyHash);
let txb = new bitcoinjs.TransactionBuilder();
let unspentAmount = 0;
@ -45,33 +35,18 @@ exports.createSegwitTransaction = function(
txb.addOutput(toAddress, amountToOutput);
if (amountToOutput + feeInSatoshis < unspentAmount) {
// sending less than we have, so the rest should go back
txb.addOutput(
changeAddress,
unspentAmount - amountToOutput - feeInSatoshis,
);
txb.addOutput(changeAddress, unspentAmount - amountToOutput - feeInSatoshis);
}
for (let c = 0; c < utxos.length; c++) {
txb.sign(
c,
keyPair,
redeemScript,
null,
parseInt((utxos[c].amount * 100000000).toFixed(0)),
);
txb.sign(c, keyPair, redeemScript, null, parseInt((utxos[c].amount * 100000000).toFixed(0)));
}
let tx = txb.build();
return tx.toHex();
};
exports.createRBFSegwitTransaction = function(
txhex,
addressReplaceMap,
feeDelta,
WIF,
utxodata,
) {
exports.createRBFSegwitTransaction = function(txhex, addressReplaceMap, feeDelta, WIF, utxodata) {
if (feeDelta < 0) {
throw Error('replace-by-fee requires increased fee, not decreased');
}
@ -89,11 +64,7 @@ exports.createRBFSegwitTransaction = function(
// creating TX
let txb = new bitcoinjs.TransactionBuilder();
for (let unspent of tx.ins) {
txb.addInput(
unspent.hash.reverse().toString('hex'),
unspent.index,
highestSequence + 1,
);
txb.addInput(unspent.hash.reverse().toString('hex'), unspent.index, highestSequence + 1);
}
for (let o of tx.outs) {
@ -113,9 +84,7 @@ exports.createRBFSegwitTransaction = function(
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 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;
@ -131,12 +100,8 @@ 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 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);
return {
@ -163,23 +128,12 @@ 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),
);
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);
};
exports.createTransaction = function(
utxos,
toAddress,
_amount,
_fixedFee,
WIF,
fromAddress,
) {
exports.createTransaction = function(utxos, toAddress, _amount, _fixedFee, WIF, fromAddress) {
let fixedFee = toSatoshi(_fixedFee);
let amountToOutput = toSatoshi(_amount - _fixedFee);
let pk = bitcoinjs.ECPair.fromWIF(WIF); // eslint-disable-line new-cap

View File

@ -1,14 +1,6 @@
import React, { Component } from 'react';
import { ScrollView, Linking, Dimensions } from 'react-native';
import {
BlueLoading,
BlueSpacing20,
BlueButton,
SafeBlueArea,
BlueCard,
BlueText,
BlueHeaderDefaultSub,
} from '../BlueComponents';
import { BlueLoading, BlueSpacing20, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueHeaderDefaultSub } from '../BlueComponents';
import PropTypes from 'prop-types';
/** @type {AppStorage} */
let BlueApp = require('../BlueApp');
@ -39,16 +31,11 @@ export default class About extends Component {
return (
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
<BlueHeaderDefaultSub
leftText={'about'}
onClose={() => this.props.navigation.goBack()}
/>
<BlueHeaderDefaultSub leftText={'about'} onClose={() => this.props.navigation.goBack()} />
<BlueCard>
<ScrollView maxHeight={height - 150}>
<BlueText h4>
BlueWallet is free and opensource Bitcoin wallet. Licensed MIT.
</BlueText>
<BlueText h4>BlueWallet is free and opensource Bitcoin wallet. Licensed MIT.</BlueText>
<BlueButton
icon={{
@ -81,9 +68,7 @@ export default class About extends Component {
color: BlueApp.settings.buttonTextColor,
}}
onPress={() => {
Linking.openURL(
'https://itunes.apple.com/us/app/bluewallet-bitcoin-wallet/id1376878040?l=ru&ls=1&mt=8',
);
Linking.openURL('https://itunes.apple.com/us/app/bluewallet-bitcoin-wallet/id1376878040?l=ru&ls=1&mt=8');
}}
title="Leave us a review on Appstore"
/>

View File

@ -2,14 +2,7 @@
import React, { Component } from 'react';
import { ScrollView } from 'react-native';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {
BlueLoading,
BlueButton,
SafeBlueArea,
BlueCard,
BlueText,
BlueHeader,
} from '../BlueComponents';
import { BlueLoading, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueHeader } from '../BlueComponents';
import PropTypes from 'prop-types';
/** @type {AppStorage} */
let BlueApp = require('../BlueApp');
@ -21,11 +14,7 @@ export default class PlausibleDeniability extends Component {
static navigationOptions = {
tabBarLabel: loc.plausibledeniability.title,
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-settings' : 'ios-settings-outline'}
size={26}
style={{ color: tintColor }}
/>
<Ionicons name={focused ? 'ios-settings' : 'ios-settings-outline'} size={26} style={{ color: tintColor }} />
),
};
@ -73,14 +62,9 @@ export default class PlausibleDeniability extends Component {
}}
title={loc.plausibledeniability.create_fake_storage}
onPress={async () => {
let p1 = await prompt(
loc.plausibledeniability.create_password,
loc.plausibledeniability.create_password_explanation,
);
let p1 = await prompt(loc.plausibledeniability.create_password, loc.plausibledeniability.create_password_explanation);
if (p1 === BlueApp.cachedPassword) {
return alert(
loc.plausibledeniability.password_should_not_match,
);
return alert(loc.plausibledeniability.password_should_not_match);
}
if (!p1) {

View File

@ -70,10 +70,7 @@ export default class ReceiveDetails extends Component {
return <BlueSpacing />;
}
})()}
<BlueHeaderDefaultSub
leftText={loc.receive.list.header}
onClose={() => this.props.navigation.goBack()}
/>
<BlueHeaderDefaultSub leftText={loc.receive.list.header} onClose={() => this.props.navigation.goBack()} />
<View
style={{

View File

@ -1,13 +1,7 @@
import React, { Component } from 'react';
import { ListView, Dimensions } from 'react-native';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {
BlueLoading,
SafeBlueArea,
BlueCard,
BlueListItem,
BlueHeader,
} from '../../BlueComponents';
import { BlueLoading, SafeBlueArea, BlueCard, BlueListItem, BlueHeader } from '../../BlueComponents';
import PropTypes from 'prop-types';
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
@ -20,11 +14,7 @@ export default class ReceiveList extends Component {
static navigationOptions = {
tabBarLabel: loc.receive.list.tabBarLabel,
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-cash' : 'ios-cash-outline'}
size={26}
style={{ color: tintColor }}
/>
<Ionicons name={focused ? 'ios-cash' : 'ios-cash-outline'} size={26} style={{ color: tintColor }} />
),
};

View File

@ -1,15 +1,7 @@
import React, { Component } from 'react';
import { ScrollView, View } from 'react-native';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {
BlueLoading,
BlueSpacing20,
SafeBlueArea,
BlueCard,
BlueText,
BlueButton,
BlueHeader,
} from '../BlueComponents';
import { BlueLoading, BlueSpacing20, SafeBlueArea, BlueCard, BlueText, BlueButton, BlueHeader } from '../BlueComponents';
import PropTypes from 'prop-types';
import { SegwitP2SHWallet, LegacyWallet } from '../class';
let BlueApp = require('../BlueApp');
@ -20,11 +12,7 @@ export default class Selftest extends Component {
static navigationOptions = {
tabBarLabel: 'Self test',
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-settings' : 'ios-settings-outline'}
size={26}
style={{ color: tintColor }}
/>
<Ionicons name={focused ? 'ios-settings' : 'ios-settings-outline'} size={26} style={{ color: tintColor }} />
),
};
@ -65,8 +53,7 @@ export default class Selftest extends Component {
// utxos as received from blockcypher
let utxos = [
{
tx_hash:
'2f445cf016fa2772db7d473bff97515355b4e6148e1c980ce351d47cf54c517f',
tx_hash: '2f445cf016fa2772db7d473bff97515355b4e6148e1c980ce351d47cf54c517f',
block_height: 523186,
tx_input_n: -1,
tx_output_n: 1,
@ -101,12 +88,10 @@ export default class Selftest extends Component {
double_spend: false,
ref_balance: 300000,
spent: false,
tx_hash:
'dc3605040a03724bc584ed43bc22a559f5d32a1b0708ca05b20b9018fdd523ef',
tx_hash: 'dc3605040a03724bc584ed43bc22a559f5d32a1b0708ca05b20b9018fdd523ef',
tx_input_n: -1,
tx_output_n: 0,
txid:
'dc3605040a03724bc584ed43bc22a559f5d32a1b0708ca05b20b9018fdd523ef',
txid: 'dc3605040a03724bc584ed43bc22a559f5d32a1b0708ca05b20b9018fdd523ef',
value: 200000,
vout: 0,
},
@ -118,12 +103,10 @@ export default class Selftest extends Component {
double_spend: false,
ref_balance: 100000,
spent: false,
tx_hash:
'c473c104febfe6621804976d1082a1468c1198d0339e35f30a8ba1515d9eb017',
tx_hash: 'c473c104febfe6621804976d1082a1468c1198d0339e35f30a8ba1515d9eb017',
tx_input_n: -1,
tx_output_n: 0,
txid:
'c473c104febfe6621804976d1082a1468c1198d0339e35f30a8ba1515d9eb017',
txid: 'c473c104febfe6621804976d1082a1468c1198d0339e35f30a8ba1515d9eb017',
value: 100000,
vout: 0,
},
@ -160,8 +143,7 @@ export default class Selftest extends Component {
// utxos as received from blockcypher
let utxo = [
{
tx_hash:
'0f5eea78fb19e72b55bd119252ff29fc16c503d0e956a9c1b5b2ab0e95e0c323',
tx_hash: '0f5eea78fb19e72b55bd119252ff29fc16c503d0e956a9c1b5b2ab0e95e0c323',
block_height: 514991,
tx_input_n: -1,
tx_output_n: 2,
@ -174,20 +156,12 @@ export default class Selftest extends Component {
},
];
let tx = l.createTx(
utxo,
0.001,
0.0001,
'1QHf8Gp3wfmFiSdEX4FtrssCGR68diN1cj',
);
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();
if (
txid !==
'110f51d28d585e922adbf701cba802e549b8fe3a53fa5d62426ab42549c9b6de'
) {
if (txid !== '110f51d28d585e922adbf701cba802e549b8fe3a53fa5d62426ab42549c9b6de') {
errorMessage += 'created txid doesnt match; ';
isOk = false;
}
@ -234,10 +208,7 @@ export default class Selftest extends Component {
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.address.fromOutputScript(outputScript, bitcoin.networks.bitcoin);
if (address !== '3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK') {
errorMessage += 'bip49 is not ok; ';

View File

@ -1,15 +1,7 @@
import React, { Component } from 'react';
import { TextInput } from 'react-native';
import { Text, FormValidationMessage } from 'react-native-elements';
import {
BlueLoading,
BlueSpacing20,
BlueButton,
SafeBlueArea,
BlueCard,
BlueText,
BlueSpacing,
} from '../../BlueComponents';
import { BlueLoading, BlueSpacing20, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueSpacing } from '../../BlueComponents';
import PropTypes from 'prop-types';
let BigNumber = require('bignumber.js');
let BlueApp = require('../../BlueApp');
@ -56,13 +48,7 @@ export default class SendCreate extends Component {
utxo = this.state.fromWallet.utxo;
let startTime = Date.now();
tx = this.state.fromWallet.createTx(
utxo,
this.state.amount,
this.state.fee,
this.state.address,
this.state.memo,
);
tx = this.state.fromWallet.createTx(utxo, this.state.amount, this.state.fee, this.state.address, this.state.memo);
let endTime = Date.now();
console.log('create tx ', (endTime - startTime) / 1000, 'sec');
@ -113,8 +99,7 @@ export default class SendCreate extends Component {
} else {
this.setState({ broadcastErrorMessage: '' });
this.setState({
broadcastSuccessMessage:
'Success! TXID: ' + JSON.stringify(result.result),
broadcastSuccessMessage: 'Success! TXID: ' + JSON.stringify(result.result),
});
}
}
@ -124,19 +109,11 @@ export default class SendCreate extends Component {
return (
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
<BlueSpacing />
<BlueCard
title={loc.send.create.title}
style={{ alignItems: 'center', flex: 1 }}
>
<BlueCard title={loc.send.create.title} style={{ alignItems: 'center', flex: 1 }}>
<BlueText>{loc.send.create.error}</BlueText>
<FormValidationMessage>
{this.state.errorMessage}
</FormValidationMessage>
<FormValidationMessage>{this.state.errorMessage}</FormValidationMessage>
</BlueCard>
<BlueButton
onPress={() => this.props.navigation.goBack()}
title={loc.send.create.go_back}
/>
<BlueButton onPress={() => this.props.navigation.goBack()} title={loc.send.create.go_back} />
</SafeBlueArea>
);
}
@ -148,10 +125,7 @@ export default class SendCreate extends Component {
return (
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
<BlueSpacing />
<BlueCard
title={loc.send.create.title}
style={{ alignItems: 'center', flex: 1 }}
>
<BlueCard title={loc.send.create.title} style={{ alignItems: 'center', flex: 1 }}>
<BlueText>{loc.send.create.this_is_hex}</BlueText>
<TextInput
@ -182,8 +156,7 @@ export default class SendCreate extends Component {
{loc.send.create.tx_size}: {this.state.size} Bytes
</BlueText>
<BlueText>
{loc.send.create.satoshi_per_byte}: {this.state.satoshiPerByte}{' '}
Sat/B
{loc.send.create.satoshi_per_byte}: {this.state.satoshiPerByte} Sat/B
</BlueText>
<BlueText>
{loc.send.create.memo}: {this.state.memo}
@ -210,12 +183,8 @@ export default class SendCreate extends Component {
title={loc.send.create.go_back}
/>
<FormValidationMessage>
{this.state.broadcastErrorMessage}
</FormValidationMessage>
<Text style={{ padding: 0, color: '#0f0' }}>
{this.state.broadcastSuccessMessage}
</Text>
<FormValidationMessage>{this.state.broadcastErrorMessage}</FormValidationMessage>
<Text style={{ padding: 0, color: '#0f0' }}>{this.state.broadcastSuccessMessage}</Text>
</SafeBlueArea>
);
}

View File

@ -38,11 +38,9 @@ export default class SendDetails extends Component {
super(props);
let startTime = Date.now();
let address;
if (props.navigation.state.params)
address = props.navigation.state.params.address;
if (props.navigation.state.params) address = props.navigation.state.params.address;
let fromAddress;
if (props.navigation.state.params)
fromAddress = props.navigation.state.params.fromAddress;
if (props.navigation.state.params) fromAddress = props.navigation.state.params.fromAddress;
let fromWallet = {};
let startTime2 = Date.now();
@ -164,9 +162,7 @@ export default class SendDetails extends Component {
if (!this.state.fromWallet.getAddress) {
return (
<View style={{ flex: 1, paddingTop: 20 }}>
<Text>
System error: Source wallet not found (this should never happen)
</Text>
<Text>System error: Source wallet not found (this should never happen)</Text>
</View>
);
}
@ -180,10 +176,7 @@ export default class SendDetails extends Component {
return <BlueSpacing />;
}
})()}
<BlueCard
title={loc.send.details.title}
style={{ alignItems: 'center', flex: 1 }}
>
<BlueCard title={loc.send.details.title} style={{ alignItems: 'center', flex: 1 }}>
<BlueFormInputAddress
style={{ width: 250 }}
onChangeText={text => this.setState({ address: text })}
@ -192,18 +185,14 @@ export default class SendDetails extends Component {
/>
<BlueFormInput
onChangeText={text =>
this.setState({ amount: text.replace(',', '.') })
}
onChangeText={text => this.setState({ amount: text.replace(',', '.') })}
keyboardType={'numeric'}
placeholder={loc.send.details.amount_placeholder}
value={this.state.amount + ''}
/>
<BlueFormInput
onChangeText={text =>
this.setState({ fee: text.replace(',', '.') })
}
onChangeText={text => this.setState({ fee: text.replace(',', '.') })}
keyboardType={'numeric'}
placeholder={loc.send.details.fee_placeholder}
value={this.state.fee + ''}
@ -218,12 +207,7 @@ export default class SendDetails extends Component {
<BlueSpacing20 />
<BlueText>
{loc.send.details.remaining_balance}:{' '}
{this.recalculateAvailableBalance(
this.state.fromWallet.getBalance(),
this.state.amount,
this.state.fee,
)}{' '}
BTC
{this.recalculateAvailableBalance(this.state.fromWallet.getBalance(), this.state.amount, this.state.fee)} BTC
</BlueText>
</BlueCard>
@ -231,10 +215,7 @@ export default class SendDetails extends Component {
<View style={{ flex: 1, flexDirection: 'row' }}>
<View style={{ flex: 0.33 }}>
<BlueButton
onPress={() => this.props.navigation.goBack()}
title={loc.send.details.cancel}
/>
<BlueButton onPress={() => this.props.navigation.goBack()} title={loc.send.details.cancel} />
</View>
<View style={{ flex: 0.33 }}>
<BlueButton
@ -249,10 +230,7 @@ export default class SendDetails extends Component {
/>
</View>
<View style={{ flex: 0.33 }}>
<BlueButton
onPress={() => this.createTransaction()}
title={loc.send.details.create}
/>
<BlueButton onPress={() => this.createTransaction()} title={loc.send.details.create} />
</View>
</View>
</SafeBlueArea>

View File

@ -1,12 +1,7 @@
import React, { Component } from 'react';
import { Dimensions, ActivityIndicator, View, ListView } from 'react-native';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {
SafeBlueArea,
BlueCard,
BlueListItem,
BlueHeader,
} from '../../BlueComponents';
import { SafeBlueArea, BlueCard, BlueListItem, BlueHeader } from '../../BlueComponents';
import PropTypes from 'prop-types';
let EV = require('../../events');
/** @type {AppStorage} */
@ -19,11 +14,7 @@ export default class SendList extends Component {
static navigationOptions = {
tabBarLabel: loc.send.list.tabBarLabel,
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'md-paper-plane' : 'md-paper-plane'}
size={26}
style={{ color: tintColor }}
/>
<Ionicons name={focused ? 'md-paper-plane' : 'md-paper-plane'} size={26} style={{ color: tintColor }} />
),
};

View File

@ -1,12 +1,6 @@
/* global alert */
import React from 'react';
import {
Text,
ActivityIndicator,
Button,
View,
TouchableOpacity,
} from 'react-native';
import { Text, ActivityIndicator, Button, View, TouchableOpacity } from 'react-native';
import { Camera, Permissions } from 'expo';
import PropTypes from 'prop-types';
let EV = require('../../events');
@ -61,11 +55,7 @@ export default class CameraExample extends React.Component {
} else {
return (
<View style={{ flex: 1 }}>
<Camera
style={{ flex: 1 }}
type={this.state.type}
onBarCodeRead={ret => this.onBarCodeRead(ret)}
>
<Camera style={{ flex: 1 }} type={this.state.type} onBarCodeRead={ret => this.onBarCodeRead(ret)}>
<View
style={{
flex: 1,
@ -81,18 +71,11 @@ export default class CameraExample extends React.Component {
}}
onPress={() => {
this.setState({
type:
this.state.type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back,
type: this.state.type === Camera.Constants.Type.back ? Camera.Constants.Type.front : Camera.Constants.Type.back,
});
}}
>
<Button
style={{ fontSize: 18, marginBottom: 10 }}
title="Go back"
onPress={() => this.props.navigation.goBack()}
/>
<Button style={{ fontSize: 18, marginBottom: 10 }} title="Go back" onPress={() => this.props.navigation.goBack()} />
</TouchableOpacity>
</View>
</Camera>

View File

@ -2,14 +2,7 @@
import React, { Component } from 'react';
import { ScrollView, View, Picker } from 'react-native';
import { FormValidationMessage } from 'react-native-elements';
import {
BlueLoading,
BlueButton,
SafeBlueArea,
BlueCard,
BlueText,
BlueHeaderDefaultSub,
} from '../BlueComponents';
import { BlueLoading, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueHeaderDefaultSub } from '../BlueComponents';
import PropTypes from 'prop-types';
/** @type {AppStorage} */
let BlueApp = require('../BlueApp');
@ -43,10 +36,7 @@ export default class Settings extends Component {
return (
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
<BlueHeaderDefaultSub
leftText={loc.settings.header}
onClose={() => this.props.navigation.goBack()}
/>
<BlueHeaderDefaultSub leftText={loc.settings.header} onClose={() => this.props.navigation.goBack()} />
<BlueCard>
<ScrollView maxHeight={450}>
@ -56,9 +46,7 @@ export default class Settings extends Component {
<View>
<BlueText>{loc.settings.storage_encrypted}</BlueText>
<BlueButton
onPress={() =>
this.props.navigation.navigate('PlausibleDeniability')
}
onPress={() => this.props.navigation.navigate('PlausibleDeniability')}
title={loc.settings.plausible_deniability}
/>
</View>
@ -66,9 +54,7 @@ export default class Settings extends Component {
} else {
return (
<View>
<FormValidationMessage>
{loc.settings.storage_not_encrypted}
</FormValidationMessage>
<FormValidationMessage>{loc.settings.storage_not_encrypted}</FormValidationMessage>
<BlueButton
icon={{
name: 'shield',
@ -77,18 +63,12 @@ export default class Settings extends Component {
}}
onPress={async () => {
this.setState({ isLoading: true });
let p1 = await prompt(
loc.settings.password,
loc.settings.password_explain,
);
let p1 = await prompt(loc.settings.password, loc.settings.password_explain);
if (!p1) {
this.setState({ isLoading: false });
return;
}
let p2 = await prompt(
loc.settings.password,
loc.settings.retype_password,
);
let p2 = await prompt(loc.settings.password, loc.settings.retype_password);
if (p1 === p2) {
await BlueApp.encryptStorage(p1);
this.setState({
@ -107,10 +87,7 @@ export default class Settings extends Component {
}
})()}
<BlueButton
onPress={() => this.props.navigation.navigate('About')}
title={loc.settings.about}
/>
<BlueButton onPress={() => this.props.navigation.navigate('About')} title={loc.settings.about} />
</ScrollView>
<Picker
@ -122,31 +99,11 @@ export default class Settings extends Component {
return this.setState({ language: itemValue });
}}
>
<Picker.Item
color={BlueApp.settings.foregroundColor}
label="English"
value="en"
/>
<Picker.Item
color={BlueApp.settings.foregroundColor}
label="Русский"
value="ru"
/>
<Picker.Item
color={BlueApp.settings.foregroundColor}
label="Українська"
value="ua"
/>
<Picker.Item
color={BlueApp.settings.foregroundColor}
label="Spanish"
value="es"
/>
<Picker.Item
color={BlueApp.settings.foregroundColor}
label="Portuguese"
value="pt"
/>
<Picker.Item color={BlueApp.settings.foregroundColor} label="English" value="en" />
<Picker.Item color={BlueApp.settings.foregroundColor} label="Русский" value="ru" />
<Picker.Item color={BlueApp.settings.foregroundColor} label="Українська" value="ua" />
<Picker.Item color={BlueApp.settings.foregroundColor} label="Spanish" value="es" />
<Picker.Item color={BlueApp.settings.foregroundColor} label="Portuguese" value="pt" />
</Picker>
</BlueCard>
</SafeBlueArea>

View File

@ -2,15 +2,7 @@
import React, { Component } from 'react';
import { TextInput } from 'react-native';
import { Text, FormValidationMessage } from 'react-native-elements';
import {
BlueLoading,
BlueSpacing20,
BlueButton,
SafeBlueArea,
BlueCard,
BlueText,
BlueSpacing,
} from '../../BlueComponents';
import { BlueLoading, BlueSpacing20, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueSpacing } from '../../BlueComponents';
import PropTypes from 'prop-types';
let BigNumber = require('bignumber.js');
let bitcoinjs = require('bitcoinjs-lib');
@ -30,8 +22,7 @@ export default class SendCreate extends Component {
this.state = {
isLoading: true,
feeDelta: props.navigation.state.params.feeDelta,
newDestinationAddress:
props.navigation.state.params.newDestinationAddress,
newDestinationAddress: props.navigation.state.params.newDestinationAddress,
txid: props.navigation.state.params.txid,
sourceTx: props.navigation.state.params.sourceTx,
fromWallet: props.navigation.state.params.sourceWallet,
@ -90,9 +81,7 @@ export default class SendCreate extends Component {
transferAmount = transferAmount.div(100000000).toString(10);
}
}
let oldFee = new BigNumber(
totalInputAmountSatoshi - totalOutputAmountSatoshi,
);
let oldFee = new BigNumber(totalInputAmountSatoshi - totalOutputAmountSatoshi);
oldFee = parseFloat(oldFee.div(100000000).toString(10));
console.log('changeAddress = ', changeAddress);
@ -113,14 +102,7 @@ export default class SendCreate extends Component {
// more responsive
let tx;
try {
tx = this.state.fromWallet.createTx(
utxo,
transferAmount,
newFee,
this.state.newDestinationAddress,
false,
lastSequence,
);
tx = this.state.fromWallet.createTx(utxo, transferAmount, newFee, this.state.newDestinationAddress, false, lastSequence);
BlueApp.tx_metadata[this.state.txid] = txMetadata || {};
BlueApp.tx_metadata[this.state.txid]['last_sequence'] = lastSequence;
@ -132,10 +114,7 @@ export default class SendCreate extends Component {
BlueApp.tx_metadata[txid]['txhex'] = tx;
//
BlueApp.saveToDisk();
console.log(
'BlueApp.txMetadata[this.state.txid]',
BlueApp.tx_metadata[this.state.txid],
);
console.log('BlueApp.txMetadata[this.state.txid]', BlueApp.tx_metadata[this.state.txid]);
} catch (err) {
console.log(err);
return this.setState({
@ -173,8 +152,7 @@ export default class SendCreate extends Component {
} else {
this.setState({ broadcastErrorMessage: '' });
this.setState({
broadcastSuccessMessage:
'Success! TXID: ' + JSON.stringify(result.result || result.txid),
broadcastSuccessMessage: 'Success! TXID: ' + JSON.stringify(result.result || result.txid),
});
}
}
@ -184,21 +162,11 @@ export default class SendCreate extends Component {
return (
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
<BlueSpacing />
<BlueCard
title={'Replace Transaction'}
style={{ alignItems: 'center', flex: 1 }}
>
<BlueText>
Error creating transaction. Invalid address or send amount?
</BlueText>
<FormValidationMessage>
{this.state.errorMessage}
</FormValidationMessage>
<BlueCard title={'Replace Transaction'} style={{ alignItems: 'center', flex: 1 }}>
<BlueText>Error creating transaction. Invalid address or send amount?</BlueText>
<FormValidationMessage>{this.state.errorMessage}</FormValidationMessage>
</BlueCard>
<BlueButton
onPress={() => this.props.navigation.goBack()}
title="Go back"
/>
<BlueButton onPress={() => this.props.navigation.goBack()} title="Go back" />
</SafeBlueArea>
);
}
@ -218,10 +186,7 @@ export default class SendCreate extends Component {
<BlueText h4>This transaction is not replaceable</BlueText>
<BlueButton
onPress={() => this.props.navigation.goBack()}
title="Back"
/>
<BlueButton onPress={() => this.props.navigation.goBack()} title="Back" />
</SafeBlueArea>
);
}
@ -229,14 +194,8 @@ export default class SendCreate extends Component {
return (
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
<BlueSpacing />
<BlueCard
title={'Replace Transaction'}
style={{ alignItems: 'center', flex: 1 }}
>
<BlueText>
This is transaction hex, signed and ready to be broadcast to the
network. Continue?
</BlueText>
<BlueCard title={'Replace Transaction'} style={{ alignItems: 'center', flex: 1 }}>
<BlueText>This is transaction hex, signed and ready to be broadcast to the network. Continue?</BlueText>
<TextInput
style={{
@ -253,33 +212,19 @@ export default class SendCreate extends Component {
<BlueSpacing20 />
<BlueText style={{ paddingTop: 20 }}>
To: {this.state.newDestinationAddress}
</BlueText>
<BlueText style={{ paddingTop: 20 }}>To: {this.state.newDestinationAddress}</BlueText>
<BlueText>Amount: {this.state.amount} BTC</BlueText>
<BlueText>Fee: {this.state.fee} BTC</BlueText>
<BlueText>TX size: {this.state.size} Bytes</BlueText>
<BlueText>satoshiPerByte: {this.state.satoshiPerByte} Sat/B</BlueText>
</BlueCard>
<BlueButton
icon={{ name: 'megaphone', type: 'octicon' }}
onPress={() => this.broadcast()}
title="Broadcast"
/>
<BlueButton icon={{ name: 'megaphone', type: 'octicon' }} onPress={() => this.broadcast()} title="Broadcast" />
<BlueButton
icon={{ name: 'arrow-left', type: 'octicon' }}
onPress={() => this.props.navigation.goBack()}
title="Go back"
/>
<BlueButton icon={{ name: 'arrow-left', type: 'octicon' }} onPress={() => this.props.navigation.goBack()} title="Go back" />
<FormValidationMessage>
{this.state.broadcastErrorMessage}
</FormValidationMessage>
<Text style={{ padding: 20, color: '#080' }}>
{this.state.broadcastSuccessMessage}
</Text>
<FormValidationMessage>{this.state.broadcastErrorMessage}</FormValidationMessage>
<Text style={{ padding: 20, color: '#080' }}>{this.state.broadcastSuccessMessage}</Text>
</SafeBlueArea>
);
}

View File

@ -1,14 +1,6 @@
import React, { Component } from 'react';
import { ActivityIndicator, View } from 'react-native';
import {
BlueSpacing20,
BlueButton,
SafeBlueArea,
BlueCard,
BlueText,
BlueFormInput,
BlueSpacing,
} from '../../BlueComponents';
import { BlueSpacing20, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueFormInput, BlueSpacing } from '../../BlueComponents';
import PropTypes from 'prop-types';
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
@ -21,8 +13,7 @@ export default class RBF extends Component {
constructor(props) {
super(props);
let txid;
if (props.navigation.state.params)
txid = props.navigation.state.params.txid;
if (props.navigation.state.params) txid = props.navigation.state.params.txid;
let sourceWallet;
let sourceTx;
@ -108,10 +99,7 @@ export default class RBF extends Component {
<BlueText h4>This transaction is not replaceable</BlueText>
<BlueButton
onPress={() => this.props.navigation.goBack()}
title="Back"
/>
<BlueButton onPress={() => this.props.navigation.goBack()} title="Back" />
</SafeBlueArea>
);
}
@ -119,13 +107,8 @@ export default class RBF extends Component {
if (!this.state.sourceWallet.getAddress) {
return (
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
<BlueText>
System error: Source wallet not found (this should never happen)
</BlueText>
<BlueButton
onPress={() => this.props.navigation.goBack()}
title="Back"
/>
<BlueText>System error: Source wallet not found (this should never happen)</BlueText>
<BlueButton onPress={() => this.props.navigation.goBack()} title="Back" />
</SafeBlueArea>
);
}
@ -133,14 +116,8 @@ export default class RBF extends Component {
return (
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
<BlueSpacing />
<BlueCard
title={'Replace By Fee'}
style={{ alignItems: 'center', flex: 1 }}
>
<BlueText>
RBF allows you to increase fee on already sent but not confirmed
transaction, thus speeding up mining
</BlueText>
<BlueCard title={'Replace By Fee'} style={{ alignItems: 'center', flex: 1 }}>
<BlueText>RBF allows you to increase fee on already sent but not confirmed transaction, thus speeding up mining</BlueText>
<BlueSpacing20 />
<BlueText>
@ -149,9 +126,7 @@ export default class RBF extends Component {
<BlueSpacing20 />
<BlueFormInput
onChangeText={text =>
this.setState({ newDestinationAddress: text })
}
onChangeText={text => this.setState({ newDestinationAddress: text })}
placeholder={'receiver address here'}
value={this.state.newDestinationAddress}
/>
@ -166,17 +141,11 @@ export default class RBF extends Component {
<View style={{ flex: 1, flexDirection: 'row', paddingTop: 20 }}>
<View style={{ flex: 0.33 }}>
<BlueButton
onPress={() => this.props.navigation.goBack()}
title="Cancel"
/>
<BlueButton onPress={() => this.props.navigation.goBack()} title="Cancel" />
</View>
<View style={{ flex: 0.33 }} />
<View style={{ flex: 0.33 }}>
<BlueButton
onPress={() => this.createTransaction()}
title="Create"
/>
<BlueButton onPress={() => this.createTransaction()} title="Create" />
</View>
</View>
</SafeBlueArea>

View File

@ -77,10 +77,7 @@ export default class TransactionsDetails extends Component {
return <BlueSpacing />;
}
})()}
<BlueHeaderDefaultSub
leftText={loc.transactions.details.title}
onClose={() => this.props.navigation.goBack()}
/>
<BlueHeaderDefaultSub leftText={loc.transactions.details.title} onClose={() => this.props.navigation.goBack()} />
<BlueCard>
{(() => {
@ -88,9 +85,7 @@ export default class TransactionsDetails extends Component {
if (BlueApp.tx_metadata[this.state.tx.hash]['memo']) {
return (
<View>
<BlueText h4>
{BlueApp.tx_metadata[this.state.tx.hash]['memo']}
</BlueText>
<BlueText h4>{BlueApp.tx_metadata[this.state.tx.hash]['memo']}</BlueText>
<BlueSpacing20 />
</View>
);
@ -99,14 +94,10 @@ export default class TransactionsDetails extends Component {
})()}
<BlueText h4>{loc.transactions.details.from}:</BlueText>
<BlueText style={{ marginBottom: 10 }}>
{this.state.from.join(', ')}
</BlueText>
<BlueText style={{ marginBottom: 10 }}>{this.state.from.join(', ')}</BlueText>
<BlueText h4>{loc.transactions.details.to}:</BlueText>
<BlueText style={{ marginBottom: 10 }}>
{this.state.to.join(', ')}
</BlueText>
<BlueText style={{ marginBottom: 10 }}>{this.state.to.join(', ')}</BlueText>
<BlueText>Txid: {this.state.tx.hash}</BlueText>
<BlueText>received: {this.state.tx.received}</BlueText>

View File

@ -2,14 +2,7 @@ import React, { Component } from 'react';
import { ListView, Dimensions } from 'react-native';
import Ionicons from 'react-native-vector-icons/Ionicons';
import { Header, Icon } from 'react-native-elements';
import {
BlueLoading,
BlueList,
SafeBlueArea,
BlueCard,
BlueText,
BlueListItem,
} from '../../BlueComponents';
import { BlueLoading, BlueList, SafeBlueArea, BlueCard, BlueText, BlueListItem } from '../../BlueComponents';
import PropTypes from 'prop-types';
let loc = require('../../loc');
let EV = require('../../events');
@ -23,11 +16,7 @@ export default class TransactionsList extends Component {
static navigationOptions = {
tabBarLabel: loc.transactions.list.tabBarLabel,
tabBarIcon: ({ tintColor, focused }) => (
<Ionicons
name={focused ? 'ios-list-box' : 'ios-list-box-outline'}
size={26}
style={{ color: tintColor }}
/>
<Ionicons name={focused ? 'ios-list-box' : 'ios-list-box-outline'} size={26} style={{ color: tintColor }} />
),
};
@ -114,18 +103,10 @@ export default class TransactionsList extends Component {
text: this.state.final_balance + ' BTC',
style: { color: BlueApp.settings.foregroundColor, fontSize: 25 },
}}
rightComponent={
<Icon
name="refresh"
color={BlueApp.settings.foregroundColor}
onPress={() => this.refresh()}
/>
}
rightComponent={<Icon name="refresh" color={BlueApp.settings.foregroundColor} onPress={() => this.refresh()} />}
/>
<BlueCard title={loc.transactions.list.title}>
<BlueText style={{ marginBottom: 10 }}>
{loc.transactions.list.description}
</BlueText>
<BlueText style={{ marginBottom: 10 }}>{loc.transactions.list.description}</BlueText>
<BlueList>
<ListView
@ -138,25 +119,14 @@ export default class TransactionsList extends Component {
avatar={
<Icon
color={(() => {
return (
(rowData.confirmations &&
((rowData.value < 0 && '#900') || '#080')) ||
'#ebebeb'
);
return (rowData.confirmations && ((rowData.value < 0 && '#900') || '#080')) || '#ebebeb';
})()}
name={(() => {
return (
(rowData.value < 0 && 'call-made') ||
'call-received'
);
return (rowData.value < 0 && 'call-made') || 'call-received';
})()}
/>
}
title={
rowData.value / 100000000 +
' BTC' +
this.txMemo(rowData.hash)
}
title={rowData.value / 100000000 + ' BTC' + this.txMemo(rowData.hash)}
subtitle={
rowData.received
.replace(['T'], ' ')

View File

@ -1,15 +1,7 @@
import { SegwitP2SHWallet } from '../../class';
import React, { Component } from 'react';
import { ActivityIndicator, Dimensions, View } from 'react-native';
import {
BlueSpacing,
BlueButton,
SafeBlueArea,
BlueCard,
BlueText,
BlueHeaderDefaultSub,
BlueSpacing40,
} from '../../BlueComponents';
import { BlueSpacing, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueHeaderDefaultSub, BlueSpacing40 } from '../../BlueComponents';
import PropTypes from 'prop-types';
let EV = require('../../events');
let A = require('../../analytics');
@ -53,10 +45,7 @@ export default class WalletsAdd extends Component {
}
return (
<SafeBlueArea
forceInset={{ horizontal: 'always' }}
style={{ flex: 1, paddingTop: 40 }}
>
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1, paddingTop: 40 }}>
{(() => {
if (isIpad) {
return <BlueSpacing40 />;
@ -64,10 +53,7 @@ export default class WalletsAdd extends Component {
return <BlueSpacing />;
}
})()}
<BlueHeaderDefaultSub
leftText={loc.wallets.add.title}
onClose={() => this.props.navigation.goBack()}
/>
<BlueHeaderDefaultSub leftText={loc.wallets.add.title} onClose={() => this.props.navigation.goBack()} />
<BlueCard>
<BlueText>{loc.wallets.add.description}</BlueText>

View File

@ -79,23 +79,14 @@ export default class WalletDetails extends Component {
<SafeBlueArea style={{ flex: 1 }}>
<BlueSpacingVariable />
<BlueHeaderDefaultSub
leftText={loc.wallets.details.title}
onClose={() => this.props.navigation.goBack()}
/>
<BlueHeaderDefaultSub leftText={loc.wallets.details.title} onClose={() => this.props.navigation.goBack()} />
<BlueCard style={{ alignItems: 'center', flex: 1 }}>
<BlueFormLabel>{loc.wallets.details.address}:</BlueFormLabel>
<BlueFormInputAddress
value={this.state.wallet.getAddress()}
editable
/>
<BlueFormInputAddress value={this.state.wallet.getAddress()} editable />
<BlueFormLabel>{loc.wallets.details.type}:</BlueFormLabel>
<BlueFormInput
value={this.state.wallet.getTypeReadable()}
editable={false}
/>
<BlueFormInput value={this.state.wallet.getTypeReadable()} editable={false} />
<BlueFormLabel>{loc.wallets.details.label}:</BlueFormLabel>
<BlueFormInput

View File

@ -1,14 +1,7 @@
import React, { Component } from 'react';
import { Dimensions, ActivityIndicator, View } from 'react-native';
import QRCode from 'react-native-qrcode';
import {
BlueSpacing,
BlueSpacing40,
SafeBlueArea,
BlueCard,
BlueText,
BlueHeaderDefaultSub,
} from '../../BlueComponents';
import { BlueSpacing, BlueSpacing40, SafeBlueArea, BlueCard, BlueText, BlueHeaderDefaultSub } from '../../BlueComponents';
import PropTypes from 'prop-types';
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
@ -80,10 +73,7 @@ export default class WalletExport extends Component {
return <BlueSpacing />;
}
})()}
<BlueHeaderDefaultSub
leftText={loc.wallets.export.title}
onClose={() => this.props.navigation.goBack()}
/>
<BlueHeaderDefaultSub leftText={loc.wallets.export.title} onClose={() => this.props.navigation.goBack()} />
<BlueCard style={{ alignItems: 'center', flex: 1 }}>
<BlueText>{this.state.wallet.getAddress()}</BlueText>
@ -93,9 +83,7 @@ export default class WalletExport extends Component {
bgColor={BlueApp.settings.foregroundColor}
fgColor={BlueApp.settings.brandingColor}
/>
<BlueText>
{this.state.wallet.getSecret()} [Wallet Import Format]
</BlueText>
<BlueText>{this.state.wallet.getSecret()} [Wallet Import Format]</BlueText>
</BlueCard>
</SafeBlueArea>
);

View File

@ -94,9 +94,7 @@ export default class WalletsList extends Component {
showReceiveButton: showReceive,
showSendButton: showSend,
showRereshButton: (BlueApp.getWallets().length > 0 && true) || false,
dataSource: ds.cloneWithRows(
BlueApp.getTransactions(this.lastSnappedTo || 0),
),
dataSource: ds.cloneWithRows(BlueApp.getTransactions(this.lastSnappedTo || 0)),
});
}, 1);
}
@ -179,10 +177,7 @@ export default class WalletsList extends Component {
if (wallets && wallets[index] && wallets[index].timeToRefresh()) {
console.log('snapped to, and now its time to refresh wallet #', index);
await wallets[index].fetchBalance();
if (
oldBalance !== wallets[index].getBalance() ||
wallets[index].getUnconfirmedBalance() !== 0
) {
if (oldBalance !== wallets[index].getBalance() || wallets[index].getUnconfirmedBalance() !== 0) {
console.log('balance changed, thus txs too');
// balance changed, thus txs too
await wallets[index].fetchTransactions();
@ -211,10 +206,7 @@ export default class WalletsList extends Component {
return (
<SafeBlueArea>
<BlueHeaderDefaultMain
leftText={loc.wallets.list.title}
onClose={() => navigate('Settings')}
/>
<BlueHeaderDefaultMain leftText={loc.wallets.list.title} onClose={() => navigate('Settings')} />
<WalletsCarousel
data={BlueApp.getWallets().concat(false)}
@ -246,11 +238,7 @@ export default class WalletsList extends Component {
</Text>
{(() => {
if (this.state.showRereshButton) {
return (
<BlueRefreshIcon
onPress={() => this.refreshTransactions()}
/>
);
return <BlueRefreshIcon onPress={() => this.refreshTransactions()} />;
}
})()}
</View>
@ -263,10 +251,7 @@ export default class WalletsList extends Component {
}}
>
{(() => {
if (
BlueApp.getTransactions(this.lastSnappedTo || 0)
.length === 0
) {
if (BlueApp.getTransactions(this.lastSnappedTo || 0).length === 0) {
return (
<View>
<Text
@ -325,16 +310,10 @@ export default class WalletsList extends Component {
);
}
})()}
title={loc.transactionTimeToReadable(
rowData.received,
)}
title={loc.transactionTimeToReadable(rowData.received)}
subtitle={
(rowData.confirmations < 200
? loc.transactions.list.conf +
': ' +
rowData.confirmations +
' '
: '') + this.txMemo(rowData.hash)
(rowData.confirmations < 200 ? loc.transactions.list.conf + ': ' + rowData.confirmations + ' ' : '') +
this.txMemo(rowData.hash)
}
onPress={() => {
navigate('TransactionDetails', {
@ -355,10 +334,7 @@ export default class WalletsList extends Component {
top: -7,
fontWeight: '600',
fontSize: 16,
color:
rowData.value / 100000000 < 0
? BlueApp.settings.foregroundColor
: '#37c0a1',
color: rowData.value / 100000000 < 0 ? BlueApp.settings.foregroundColor : '#37c0a1',
}}
/>
);

View File

@ -1,12 +1,6 @@
/* global alert */
import React from 'react';
import {
Text,
ActivityIndicator,
Button,
View,
TouchableOpacity,
} from 'react-native';
import { Text, ActivityIndicator, Button, View, TouchableOpacity } from 'react-native';
import { BlueText, SafeBlueArea, BlueButton } from '../../BlueComponents';
import { Camera, Permissions } from 'expo';
import { SegwitP2SHWallet, LegacyWallet } from '../../class';
@ -46,31 +40,18 @@ export default class ScanQrWif extends React.Component {
message: loc.wallets.scanQrWif.decoding,
});
shold_stop_bip38 = undefined; // eslint-disable-line
let password = await prompt(
loc.wallets.scanQrWif.input_password,
loc.wallets.scanQrWif.password_explain,
);
let password = await prompt(loc.wallets.scanQrWif.input_password, loc.wallets.scanQrWif.password_explain);
if (!password) {
return;
}
let that = this;
try {
let decryptedKey = await bip38.decrypt(ret.data, password, function(
status,
) {
let decryptedKey = await bip38.decrypt(ret.data, password, function(status) {
that.setState({
message:
loc.wallets.scanQrWif.decoding +
'... ' +
status.percent.toString().substr(0, 4) +
' %',
message: loc.wallets.scanQrWif.decoding + '... ' + status.percent.toString().substr(0, 4) + ' %',
});
});
ret.data = wif.encode(
0x80,
decryptedKey.privateKey,
decryptedKey.compressed,
);
ret.data = wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed);
} catch (e) {
console.log(e.message);
this.setState({ message: false });
@ -93,10 +74,7 @@ export default class ScanQrWif extends React.Component {
let newLegacyWallet = new LegacyWallet();
newLegacyWallet.setSecret(ret.data);
if (
newWallet.getAddress() === false ||
newLegacyWallet.getAddress() === false
) {
if (newWallet.getAddress() === false || newLegacyWallet.getAddress() === false) {
alert(loc.wallets.scanQrWif.bad_wif);
return;
}
@ -108,23 +86,13 @@ export default class ScanQrWif extends React.Component {
if (newLegacyWallet.getBalance()) {
newLegacyWallet.setLabel(loc.wallets.scanQrWif.imported_legacy);
BlueApp.wallets.push(newLegacyWallet);
alert(
loc.wallets.scanQrWif.imported_wif +
ret.data +
loc.wallets.scanQrWif.with_address +
newLegacyWallet.getAddress(),
);
alert(loc.wallets.scanQrWif.imported_wif + ret.data + loc.wallets.scanQrWif.with_address + newLegacyWallet.getAddress());
} else {
await newWallet.fetchBalance();
await newWallet.fetchTransactions();
newWallet.setLabel(loc.wallets.scanQrWif.imported_segwit);
BlueApp.wallets.push(newWallet);
alert(
loc.wallets.scanQrWif.imported_wif +
ret.data +
loc.wallets.scanQrWif.with_address +
newWallet.getAddress(),
);
alert(loc.wallets.scanQrWif.imported_wif + ret.data + loc.wallets.scanQrWif.with_address + newWallet.getAddress());
}
await BlueApp.saveToDisk();
this.props.navigation.popToTop();
@ -185,11 +153,7 @@ export default class ScanQrWif extends React.Component {
);
} else {
return (
<Camera
style={{ flex: 1 }}
type={this.state.type}
onBarCodeRead={ret => this.onBarCodeRead(ret)}
>
<Camera style={{ flex: 1 }} type={this.state.type} onBarCodeRead={ret => this.onBarCodeRead(ret)}>
<View
style={{
flex: 1,
@ -205,10 +169,7 @@ export default class ScanQrWif extends React.Component {
}}
onPress={() => {
this.setState({
type:
this.state.type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back,
type: this.state.type === Camera.Constants.Type.back ? Camera.Constants.Type.front : Camera.Constants.Type.back,
});
}}
>