Experimental (#268)

* OPS: build maitenance
* ADD: Created BlueCopyTextToClipboard
* ADD: NSMicrophoneUsageDescription in info.plist
This commit is contained in:
Igor Korsakov 2019-01-22 16:17:45 +00:00 committed by GitHub
parent 352f691a2d
commit b64c4d7dcd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 885 additions and 563 deletions

View file

@ -57,7 +57,7 @@ describe('unit - LegacyWallet', function() {
let b = LegacyWallet.fromJson(key);
assert(key === JSON.stringify(b));
assert.equal(key, JSON.stringify(b));
assert.strictEqual(key, JSON.stringify(b));
});
it('can validate addresses', () => {
@ -118,8 +118,8 @@ it('Appstorage - loadFromDisk works', async () => {
let Storage2 = new AppStorage();
await Storage2.loadFromDisk();
assert.equal(Storage2.wallets.length, 1);
assert.equal(Storage2.wallets[0].getLabel(), 'testlabel');
assert.strictEqual(Storage2.wallets.length, 1);
assert.strictEqual(Storage2.wallets[0].getLabel(), 'testlabel');
let isEncrypted = await Storage2.storageIsEncrypted();
assert.ok(!isEncrypted);
@ -146,7 +146,7 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.ok(!isEncrypted);
await Storage.encryptStorage('password');
isEncrypted = await Storage.storageIsEncrypted();
assert.equal(Storage.cachedPassword, 'password');
assert.strictEqual(Storage.cachedPassword, 'password');
assert.ok(isEncrypted);
// saved, now trying to load, using good password
@ -156,8 +156,8 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.ok(isEncrypted);
let loadResult = await Storage2.loadFromDisk('password');
assert.ok(loadResult);
assert.equal(Storage2.wallets.length, 1);
assert.equal(Storage2.wallets[0].getLabel(), 'testlabel');
assert.strictEqual(Storage2.wallets.length, 1);
assert.strictEqual(Storage2.wallets[0].getLabel(), 'testlabel');
// now trying to load, using bad password
@ -166,7 +166,7 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.ok(isEncrypted);
loadResult = await Storage2.loadFromDisk('passwordBAD');
assert.ok(!loadResult);
assert.equal(Storage2.wallets.length, 0);
assert.strictEqual(Storage2.wallets.length, 0);
// now, trying case with adding data after decrypt.
// saveToDisk should be handled correctly
@ -176,14 +176,14 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.ok(isEncrypted);
loadResult = await Storage2.loadFromDisk('password');
assert.ok(loadResult);
assert.equal(Storage2.wallets.length, 1);
assert.equal(Storage2.wallets[0].getLabel(), 'testlabel');
assert.strictEqual(Storage2.wallets.length, 1);
assert.strictEqual(Storage2.wallets[0].getLabel(), 'testlabel');
w = new SegwitP2SHWallet();
w.setLabel('testlabel2');
await w.generate();
Storage2.wallets.push(w);
assert.equal(Storage2.wallets.length, 2);
assert.equal(Storage2.wallets[1].getLabel(), 'testlabel2');
assert.strictEqual(Storage2.wallets.length, 2);
assert.strictEqual(Storage2.wallets[1].getLabel(), 'testlabel2');
await Storage2.saveToDisk();
// saved to encrypted storage after load. next load should be successfull
Storage2 = new AppStorage();
@ -191,15 +191,15 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.ok(isEncrypted);
loadResult = await Storage2.loadFromDisk('password');
assert.ok(loadResult);
assert.equal(Storage2.wallets.length, 2);
assert.equal(Storage2.wallets[0].getLabel(), 'testlabel');
assert.equal(Storage2.wallets[1].getLabel(), 'testlabel2');
assert.strictEqual(Storage2.wallets.length, 2);
assert.strictEqual(Storage2.wallets[0].getLabel(), 'testlabel');
assert.strictEqual(Storage2.wallets[1].getLabel(), 'testlabel2');
// next, adding new `fake` storage which should be unlocked with `fake` password
let createFakeStorageResult = await Storage2.createFakeStorage('fakePassword');
assert.ok(createFakeStorageResult);
assert.equal(Storage2.wallets.length, 0);
assert.equal(Storage2.cachedPassword, 'fakePassword');
assert.strictEqual(Storage2.wallets.length, 0);
assert.strictEqual(Storage2.cachedPassword, 'fakePassword');
w = new SegwitP2SHWallet();
w.setLabel('fakewallet');
await w.generate();
@ -210,14 +210,14 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
let Storage3 = new AppStorage();
loadResult = await Storage3.loadFromDisk('password');
assert.ok(loadResult);
assert.equal(Storage3.wallets.length, 2);
assert.equal(Storage3.wallets[0].getLabel(), 'testlabel');
assert.strictEqual(Storage3.wallets.length, 2);
assert.strictEqual(Storage3.wallets[0].getLabel(), 'testlabel');
// fake:
Storage3 = new AppStorage();
loadResult = await Storage3.loadFromDisk('fakePassword');
assert.ok(loadResult);
assert.equal(Storage3.wallets.length, 1);
assert.equal(Storage3.wallets[0].getLabel(), 'fakewallet');
assert.strictEqual(Storage3.wallets.length, 1);
assert.strictEqual(Storage3.wallets[0].getLabel(), 'fakewallet');
});
it('Wallet can fetch UTXO', async () => {
@ -245,7 +245,7 @@ it('Wallet can fetch TXs', async () => {
let w = new LegacyWallet();
w._address = '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG';
await w.fetchTransactions();
assert.equal(w.getTransactions().length, 2);
assert.strictEqual(w.getTransactions().length, 2);
let tx0 = w.getTransactions()[0];
let txExpected = {
@ -296,7 +296,7 @@ it('Wallet can fetch TXs', async () => {
delete txExpected.confirmations;
delete tx0.preference; // that bs is not always the same
delete txExpected.preference;
assert.deepEqual(tx0, txExpected);
assert.deepStrictEqual(tx0, txExpected);
});
describe('currency', () => {
@ -321,7 +321,7 @@ describe('currency', () => {
await currency.setPrefferedCurrency(FiatUnit.EUR);
await currency.startUpdater();
let preferred = await currency.getPreferredCurrency();
assert.equal(preferred.endPointKey, 'EUR');
assert.strictEqual(preferred.endPointKey, 'EUR');
cur = JSON.parse(AsyncStorage.storageCache[AppStorage.EXCHANGE_RATES]);
assert.ok(cur['BTC_EUR'] > 0);
});

View file

@ -14,7 +14,10 @@ it('bip38 decodes', async () => {
{ 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');
assert.strictEqual(
wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed),
'5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR',
);
});
it('bip38 decodes slow', async () => {
@ -29,7 +32,10 @@ it('bip38 decodes slow', async () => {
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');
assert.strictEqual(
wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed),
'KxqRtpd9vFju297ACPKHrGkgXuberTveZPXbRDiQ3MXZycSQYtjc',
);
});
describe('Watch only wallet', () => {
@ -46,16 +52,16 @@ describe('Watch only wallet', () => {
w.setSecret('167zK5iZrs1U6piDqubD3FjRqUTM2CZnb8');
await w.fetchTransactions();
assert.equal(w.getTransactions().length, 233);
assert.strictEqual(w.getTransactions().length, 233);
w = new WatchOnlyWallet();
w.setSecret('1BiJW1jyUaxcJp2JWwbPLPzB1toPNWTFJV');
await w.fetchTransactions();
assert.equal(w.getTransactions().length, 2);
assert.strictEqual(w.getTransactions().length, 2);
// fetch again and make sure no duplicates
await w.fetchTransactions();
assert.equal(w.getTransactions().length, 2);
assert.strictEqual(w.getTransactions().length, 2);
});
it('can fetch complex TXs', async () => {

View file

@ -10,12 +10,14 @@ import {
Animated,
ActivityIndicator,
View,
UIManager,
StyleSheet,
Dimensions,
Image,
SafeAreaView,
Clipboard,
Platform,
LayoutAnimation,
TextInput,
} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
@ -193,6 +195,60 @@ export const BlueCopyToClipboardButton = ({ stringToCopy }) => {
);
};
export class BlueCopyTextToClipboard extends Component {
static propTypes = {
text: PropTypes.string,
};
static defaultProps = {
text: '',
};
state = { hasTappedText: false };
constructor() {
super();
UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
}
copyToClipboard = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring, () => {
Clipboard.setString(this.props.text);
setTimeout(() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
this.setState({ hasTappedText: false });
}, 1000);
});
this.setState({ hasTappedText: true });
};
render() {
return (
<View style={{ justifyContent: 'center', alignItems: 'center', paddingHorizontal: 16 }}>
<TouchableOpacity onPress={this.copyToClipboard} disabled={this.state.hasTappedText}>
<Text style={styleCopyTextToClipboard.address} numberOfLines={0}>
{this.props.text}
</Text>
{this.state.hasTappedText && (
<Text style={styleCopyTextToClipboard.address} numberOfLines={0}>
{loc.wallets.xpub.copiedToClipboard}
</Text>
)}
</TouchableOpacity>
</View>
);
}
}
const styleCopyTextToClipboard = StyleSheet.create({
address: {
marginVertical: 32,
fontSize: 15,
color: '#9aa0aa',
textAlign: 'center',
},
});
export class SafeBlueArea extends Component {
render() {
return (

View file

@ -6,13 +6,13 @@ let bitcoin = require('bitcoinjs-lib');
it('can convert witness to address', () => {
let address = SegwitP2SHWallet.witnessToAddress('035c618df829af694cb99e664ce1b34f80ad2c3b49bcd0d9c0b1836c66b2d25fd8');
assert.equal(address, '34ZVGb3gT8xMLT6fpqC6dNVqJtJmvdjbD7');
assert.strictEqual(address, '34ZVGb3gT8xMLT6fpqC6dNVqJtJmvdjbD7');
address = SegwitBech32Wallet.witnessToAddress('035c618df829af694cb99e664ce1b34f80ad2c3b49bcd0d9c0b1836c66b2d25fd8');
assert.equal(address, 'bc1quhnve8q4tk3unhmjts7ymxv8cd6w9xv8wy29uv');
assert.strictEqual(address, 'bc1quhnve8q4tk3unhmjts7ymxv8cd6w9xv8wy29uv');
address = SegwitBech32Wallet.scriptPubKeyToAddress('00144d757460da5fcaf84cc22f3847faaa1078e84f6a');
assert.equal(address, 'bc1qf46hgcx6tl90snxz9uuy0742zpuwsnm27ysdh7');
assert.strictEqual(address, 'bc1qf46hgcx6tl90snxz9uuy0742zpuwsnm27ysdh7');
});
it('can create a Segwit HD (BIP49)', async function() {
@ -21,39 +21,39 @@ it('can create a Segwit HD (BIP49)', async function() {
'honey risk juice trip orient galaxy win situate shoot anchor bounce remind horse traffic exotic since escape mimic ramp skin judge owner topple erode';
let hd = new HDSegwitP2SHWallet();
hd.setSecret(mnemonic);
assert.equal('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', hd._getExternalAddressByIndex(0));
assert.equal('35p5LwCAE7mH2css7onyQ1VuS1jgWtQ4U3', hd._getExternalAddressByIndex(1));
assert.equal('32yn5CdevZQLk3ckuZuA8fEKBco8mEkLei', hd._getInternalAddressByIndex(0));
assert.equal(true, hd.validateMnemonic());
assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', hd._getExternalAddressByIndex(0));
assert.strictEqual('35p5LwCAE7mH2css7onyQ1VuS1jgWtQ4U3', hd._getExternalAddressByIndex(1));
assert.strictEqual('32yn5CdevZQLk3ckuZuA8fEKBco8mEkLei', hd._getInternalAddressByIndex(0));
assert.strictEqual(true, hd.validateMnemonic());
await hd.fetchBalance();
assert.equal(hd.getBalance(), 0);
assert.strictEqual(hd.getBalance(), 0);
assert.ok(hd._lastTxFetch === 0);
await hd.fetchTransactions();
assert.ok(hd._lastTxFetch > 0);
assert.equal(hd.transactions.length, 4);
assert.strictEqual(hd.transactions.length, 4);
assert.equal('L4MqtwJm6hkbACLG4ho5DF8GhcXdLEbbvpJnbzA9abfD6RDpbr2m', hd._getExternalWIFByIndex(0));
assert.equal(
assert.strictEqual('L4MqtwJm6hkbACLG4ho5DF8GhcXdLEbbvpJnbzA9abfD6RDpbr2m', hd._getExternalWIFByIndex(0));
assert.strictEqual(
'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);
assert.strictEqual(hd._getExternalAddressByIndex(hd.next_free_address_index), freeAddress);
let freeChangeAddress = await hd.getChangeAddressAsync();
assert.equal(hd._getInternalAddressByIndex(hd.next_free_change_address_index), freeChangeAddress);
assert.strictEqual(hd._getInternalAddressByIndex(hd.next_free_change_address_index), freeChangeAddress);
});
it('Segwit HD (BIP49) can generate addressess only via ypub', async function() {
let ypub = 'ypub6WhHmKBmHNjcrUVNCa3sXduH9yxutMipDcwiKW31vWjcMbfhQHjXdyx4rqXbEtVgzdbhFJ5mZJWmfWwnP4Vjzx97admTUYKQt6b9D7jjSCp';
let hd = new HDSegwitP2SHWallet();
hd._xpub = ypub;
assert.equal('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', hd._getExternalAddressByIndex(0));
assert.equal('35p5LwCAE7mH2css7onyQ1VuS1jgWtQ4U3', hd._getExternalAddressByIndex(1));
assert.equal('32yn5CdevZQLk3ckuZuA8fEKBco8mEkLei', hd._getInternalAddressByIndex(0));
assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', hd._getExternalAddressByIndex(0));
assert.strictEqual('35p5LwCAE7mH2css7onyQ1VuS1jgWtQ4U3', hd._getExternalAddressByIndex(1));
assert.strictEqual('32yn5CdevZQLk3ckuZuA8fEKBco8mEkLei', hd._getInternalAddressByIndex(0));
});
it('can generate Segwit HD (BIP49)', async () => {
@ -88,56 +88,56 @@ it('HD (BIP49) can create TX', async () => {
await hd.getChangeAddressAsync(); // to refresh internal pointer to next free address
await hd.getAddressAsync(); // to refresh internal pointer to next free address
let txhex = hd.createTx(hd.utxo, 0.000014, 0.000001, '3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK');
assert.equal(
assert.strictEqual(
txhex,
'010000000001029d98d81fe2b596fd79e845fa9f38d7e0b6fb73303c40fac604d04df1fa137aee00000000171600142f18e8406c9d210f30c901b24e5feeae78784eb7ffffffff67fb86f310df24e508d40fce9511c7fde4dd4ee91305fd08a074279a70e2cd22000000001716001468dde644410cc789d91a7f36b823f38369755a1cffffffff02780500000000000017a914a3a65daca3064280ae072b9d6773c027b30abace87dc0500000000000017a914850f4dbc255654de2c12c6f6d79cf9cb756cad038702483045022100dc8390a9fd34c31259fa47f9fc182f20d991110ecfd5b58af1cf542fe8de257a022004c2d110da7b8c4127675beccc63b46fd65c706951f090fd381fa3b21d3c5c08012102edd141c5a27a726dda66be10a38b0fd3ccbb40e7c380034aaa43a1656d5f4dd60247304402207c0aef8313d55e72474247daad955979f62e56d1cbac5f2d14b8b022c6ce112602205d9aa3804f04624b12ab8a5ab0214b529c531c2f71c27c6f18aba6502a6ea0a80121030db3c49461a5e539e97bab62ab2b8f88151d1c2376493cf73ef1d02ef60637fd00000000',
);
txhex = hd.createTx(hd.utxo, 0.000005, 0.000001, '3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK');
var tx = bitcoin.Transaction.fromHex(txhex);
assert.equal(tx.ins.length, 1);
assert.equal(tx.outs.length, 2);
assert.equal(tx.outs[0].value, 500);
assert.equal(tx.outs[1].value, 400);
assert.strictEqual(tx.ins.length, 1);
assert.strictEqual(tx.outs.length, 2);
assert.strictEqual(tx.outs[0].value, 500);
assert.strictEqual(tx.outs[1].value, 400);
let chunksIn = bitcoin.script.decompile(tx.outs[0].script);
let toAddress = bitcoin.address.fromOutputScript(chunksIn);
chunksIn = bitcoin.script.decompile(tx.outs[1].script);
let changeAddress = bitcoin.address.fromOutputScript(chunksIn);
assert.equal('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress);
assert.equal(hd._getInternalAddressByIndex(hd.next_free_change_address_index), changeAddress);
assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress);
assert.strictEqual(hd._getInternalAddressByIndex(hd.next_free_change_address_index), changeAddress);
//
txhex = hd.createTx(hd.utxo, 0.000015, 0.000001, '3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK');
tx = bitcoin.Transaction.fromHex(txhex);
assert.equal(tx.ins.length, 2);
assert.equal(tx.outs.length, 2);
assert.strictEqual(tx.ins.length, 2);
assert.strictEqual(tx.outs.length, 2);
//
txhex = hd.createTx(hd.utxo, 0.00025, 0.00001, '3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK');
tx = bitcoin.Transaction.fromHex(txhex);
assert.equal(tx.ins.length, 7);
assert.equal(tx.outs.length, 1);
assert.strictEqual(tx.ins.length, 7);
assert.strictEqual(tx.outs.length, 1);
chunksIn = bitcoin.script.decompile(tx.outs[0].script);
toAddress = bitcoin.address.fromOutputScript(chunksIn);
assert.equal('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress);
assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress);
// checking that change amount is at least 3x of fee, otherwise screw the change, just add it to fee.
// theres 0.00003 on UTXOs, lets transfer (0.00003 - 100sat), soo fee is equal to change (100 sat)
// which throws @dust error if broadcasted
txhex = hd.createTx(hd.utxo, 0.000028, 0.000001, '3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK');
tx = bitcoin.Transaction.fromHex(txhex);
assert.equal(tx.ins.length, 2);
assert.equal(tx.outs.length, 1); // only 1 output, which means change is neglected
assert.equal(tx.outs[0].value, 2800);
assert.strictEqual(tx.ins.length, 2);
assert.strictEqual(tx.outs.length, 1); // only 1 output, which means change is neglected
assert.strictEqual(tx.outs[0].value, 2800);
});
it('Segwit HD (BIP49) can fetch UTXO', async function() {
let hd = new HDSegwitP2SHWallet();
hd.usedAddresses = ['1Ez69SnzzmePmZX3WpEzMKTrcBF2gpNQ55', '1BiTCHeYzJNMxBLFCMkwYXNdFEdPJP53ZV']; // hacking internals
await hd.fetchUtxo();
assert.equal(hd.utxo.length, 11);
assert.strictEqual(hd.utxo.length, 11);
assert.ok(typeof hd.utxo[0].confirmations === 'number');
assert.ok(hd.utxo[0].txid);
assert.ok(hd.utxo[0].vout);
@ -168,7 +168,7 @@ it('can work with malformed mnemonic', () => {
hd = new HDSegwitP2SHWallet();
hd.setSecret(mnemonic);
let seed2 = hd.getMnemonicToSeedHex();
assert.equal(seed1, seed2);
assert.strictEqual(seed1, seed2);
assert.ok(hd.validateMnemonic());
});
@ -182,28 +182,28 @@ it('can create a Legacy HD (BIP44)', async function() {
let mnemonic = process.env.HD_MNEMONIC_BREAD;
let hd = new HDLegacyP2PKHWallet();
hd.setSecret(mnemonic);
assert.equal(hd.validateMnemonic(), true);
assert.equal(hd._getExternalAddressByIndex(0), '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG');
assert.equal(hd._getExternalAddressByIndex(1), '1QDCFcpnrZ4yrAQxmbvSgeUC9iZZ8ehcR5');
assert.equal(hd._getInternalAddressByIndex(0), '1KZjqYHm7a1DjhjcdcjfQvYfF2h6PqatjX');
assert.equal(hd._getInternalAddressByIndex(1), '13CW9WWBsWpDUvLtbFqYziWBWTYUoQb4nU');
assert.equal(
assert.strictEqual(hd.validateMnemonic(), true);
assert.strictEqual(hd._getExternalAddressByIndex(0), '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG');
assert.strictEqual(hd._getExternalAddressByIndex(1), '1QDCFcpnrZ4yrAQxmbvSgeUC9iZZ8ehcR5');
assert.strictEqual(hd._getInternalAddressByIndex(0), '1KZjqYHm7a1DjhjcdcjfQvYfF2h6PqatjX');
assert.strictEqual(hd._getInternalAddressByIndex(1), '13CW9WWBsWpDUvLtbFqYziWBWTYUoQb4nU');
assert.strictEqual(
hd.getXpub(),
'xpub6CQdfC3v9gU86eaSn7AhUFcBVxiGhdtYxdC5Cw2vLmFkfth2KXCMmYcPpvZviA89X6DXDs4PJDk5QVL2G2xaVjv7SM4roWHr1gR4xB3Z7Ps',
);
assert.equal(hd._getExternalWIFByIndex(0), 'L1hqNoJ26YuCdujMBJfWBNfgf4Jo7AcKFvcNcKLoMtoJDdDtRq7Q');
assert.equal(hd._getExternalWIFByIndex(1), 'KyyH4h59iatJWwFfiYPnYkw39SP7cBwydC3xzszsBBXHpfwz9cKb');
assert.equal(hd._getInternalWIFByIndex(0), 'Kx3QkrfemEEV49Mj5oWfb4bsWymboPdstta7eN3kAzop9apxYEFP');
assert.equal(hd._getInternalWIFByIndex(1), 'Kwfg1EDjFapN9hgwafdNPEH22z3vkd4gtG785vXXjJ6uvVWAJGtr');
assert.strictEqual(hd._getExternalWIFByIndex(0), 'L1hqNoJ26YuCdujMBJfWBNfgf4Jo7AcKFvcNcKLoMtoJDdDtRq7Q');
assert.strictEqual(hd._getExternalWIFByIndex(1), 'KyyH4h59iatJWwFfiYPnYkw39SP7cBwydC3xzszsBBXHpfwz9cKb');
assert.strictEqual(hd._getInternalWIFByIndex(0), 'Kx3QkrfemEEV49Mj5oWfb4bsWymboPdstta7eN3kAzop9apxYEFP');
assert.strictEqual(hd._getInternalWIFByIndex(1), 'Kwfg1EDjFapN9hgwafdNPEH22z3vkd4gtG785vXXjJ6uvVWAJGtr');
await hd.fetchBalance();
assert.equal(hd.balance, 0);
assert.strictEqual(hd.balance, 0);
assert.ok(hd._lastTxFetch === 0);
await hd.fetchTransactions();
assert.ok(hd._lastTxFetch > 0);
assert.equal(hd.transactions.length, 4);
assert.equal(hd.next_free_address_index, 1);
assert.equal(hd.next_free_change_address_index, 1);
assert.strictEqual(hd.transactions.length, 4);
assert.strictEqual(hd.next_free_address_index, 1);
assert.strictEqual(hd.next_free_change_address_index, 1);
for (let tx of hd.getTransactions()) {
assert.ok(tx.value === 1000 || tx.value === 1377 || tx.value === -1377 || tx.value === -1000);
@ -211,17 +211,17 @@ it('can create a Legacy HD (BIP44)', async function() {
// 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);
assert.strictEqual(hd._getExternalAddressByIndex(hd.next_free_address_index), freeAddress);
});
it('Legacy HD (BIP44) can generate addressess based on xpub', async function() {
let xpub = 'xpub6CQdfC3v9gU86eaSn7AhUFcBVxiGhdtYxdC5Cw2vLmFkfth2KXCMmYcPpvZviA89X6DXDs4PJDk5QVL2G2xaVjv7SM4roWHr1gR4xB3Z7Ps';
let hd = new HDLegacyP2PKHWallet();
hd._xpub = xpub;
assert.equal(hd._getExternalAddressByIndex(0), '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG');
assert.equal(hd._getInternalAddressByIndex(0), '1KZjqYHm7a1DjhjcdcjfQvYfF2h6PqatjX');
assert.equal(hd._getExternalAddressByIndex(1), '1QDCFcpnrZ4yrAQxmbvSgeUC9iZZ8ehcR5');
assert.equal(hd._getInternalAddressByIndex(1), '13CW9WWBsWpDUvLtbFqYziWBWTYUoQb4nU');
assert.strictEqual(hd._getExternalAddressByIndex(0), '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG');
assert.strictEqual(hd._getInternalAddressByIndex(0), '1KZjqYHm7a1DjhjcdcjfQvYfF2h6PqatjX');
assert.strictEqual(hd._getExternalAddressByIndex(1), '1QDCFcpnrZ4yrAQxmbvSgeUC9iZZ8ehcR5');
assert.strictEqual(hd._getInternalAddressByIndex(1), '13CW9WWBsWpDUvLtbFqYziWBWTYUoQb4nU');
});
it('Legacy HD (BIP44) can create TX', async () => {
@ -239,38 +239,38 @@ it('Legacy HD (BIP44) can create TX', async () => {
await hd.getAddressAsync(); // to refresh internal pointer to next free address
let txhex = hd.createTx(hd.utxo, 0.0008, 0.000005, '3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK');
assert.equal(
assert.strictEqual(
txhex,
'01000000045fbc74110c2d6fcf4d1161a59913fbcd2b6ab3c5a9eb4d0dc0859515cbc8654f030000006b4830450221009be5dbe37db5a8409ddce3570140c95d162a07651b1e48cf39a6a741892adc53022061a25b8024d8f3cb1b94f264245de0c6e9a103ea557ddeb66245b40ec8e9384b012102ad7b2216f3a2b38d56db8a7ee5c540fd12c4bbb7013106eff78cc2ace65aa002ffffffff5fbc74110c2d6fcf4d1161a59913fbcd2b6ab3c5a9eb4d0dc0859515cbc8654f000000006a47304402207106e9fa4e2e35d351fbccc9c0fad3356d85d0cd35a9d7e9cbcefce5440da1e5022073c1905b5927447378c0f660e62900c1d4b2691730799458889fb87d86f5159101210316e84a2556f30a199541633f5dda6787710ccab26771b7084f4c9e1104f47667ffffffff5fbc74110c2d6fcf4d1161a59913fbcd2b6ab3c5a9eb4d0dc0859515cbc8654f020000006a4730440220250b15094096c4d4fe6793da8e45fa118ed057cc2759a480c115e76e23590791022079cdbdc9e630d713395602071e2837ecc1d192a36a24d8ec71bc51d5e62b203b01210316e84a2556f30a199541633f5dda6787710ccab26771b7084f4c9e1104f47667ffffffff5fbc74110c2d6fcf4d1161a59913fbcd2b6ab3c5a9eb4d0dc0859515cbc8654f010000006b483045022100879da610e6ed12c84d55f12baf3bf6222d59b5282502b3c7f4db1d22152c16900220759a1c88583cbdaf7fde21c273ad985dfdf94a2fa85e42ee41dcea2fd69136fd012102ad7b2216f3a2b38d56db8a7ee5c540fd12c4bbb7013106eff78cc2ace65aa002ffffffff02803801000000000017a914a3a65daca3064280ae072b9d6773c027b30abace872c4c0000000000001976a9146ee5e3e66dc73587a3a2d77a1a6c8554fae21b8a88ac00000000',
);
var tx = bitcoin.Transaction.fromHex(txhex);
assert.equal(tx.ins.length, 4);
assert.equal(tx.outs.length, 2);
assert.equal(tx.outs[0].value, 80000); // payee
assert.equal(tx.outs[1].value, 19500); // change
assert.strictEqual(tx.ins.length, 4);
assert.strictEqual(tx.outs.length, 2);
assert.strictEqual(tx.outs[0].value, 80000); // payee
assert.strictEqual(tx.outs[1].value, 19500); // change
let chunksIn = bitcoin.script.decompile(tx.outs[0].script);
let toAddress = bitcoin.address.fromOutputScript(chunksIn);
chunksIn = bitcoin.script.decompile(tx.outs[1].script);
let changeAddress = bitcoin.address.fromOutputScript(chunksIn);
assert.equal('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress);
assert.equal(hd._getInternalAddressByIndex(hd.next_free_change_address_index), changeAddress);
assert.strictEqual('3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK', toAddress);
assert.strictEqual(hd._getInternalAddressByIndex(hd.next_free_change_address_index), changeAddress);
// checking that change amount is at least 3x of fee, otherwise screw the change, just add it to fee.
// theres 0.001 on UTXOs, lets transfer (0.001 - 100sat), soo fee is equal to change (100 sat)
// which throws @dust error if broadcasted
txhex = hd.createTx(hd.utxo, 0.000998, 0.000001, '3GcKN7q7gZuZ8eHygAhHrvPa5zZbG5Q1rK');
tx = bitcoin.Transaction.fromHex(txhex);
assert.equal(tx.ins.length, 4);
assert.equal(tx.outs.length, 1); // only 1 output, which means change is neglected
assert.equal(tx.outs[0].value, 99800);
assert.strictEqual(tx.ins.length, 4);
assert.strictEqual(tx.outs.length, 1); // only 1 output, which means change is neglected
assert.strictEqual(tx.outs[0].value, 99800);
});
it('Legacy HD (BIP44) can fetch UTXO', async function() {
let hd = new HDLegacyP2PKHWallet();
hd.usedAddresses = ['1Ez69SnzzmePmZX3WpEzMKTrcBF2gpNQ55', '1BiTCHeYzJNMxBLFCMkwYXNdFEdPJP53ZV']; // hacking internals
await hd.fetchUtxo();
assert.equal(hd.utxo.length, 11);
assert.strictEqual(hd.utxo.length, 11);
assert.ok(typeof hd.utxo[0].confirmations === 'number');
assert.ok(hd.utxo[0].txid);
assert.ok(hd.utxo[0].vout);
@ -290,31 +290,31 @@ it('HD breadwallet works', async function() {
let hdBread = new HDLegacyBreadwalletWallet();
hdBread.setSecret(process.env.HD_MNEMONIC_BREAD);
assert.equal(hdBread.validateMnemonic(), true);
assert.equal(hdBread._getExternalAddressByIndex(0), '1ARGkNMdsBE36fJhddSwf8PqBXG3s4d2KU');
assert.equal(hdBread._getInternalAddressByIndex(0), '1JLvA5D7RpWgChb4A5sFcLNrfxYbyZdw3V');
assert.strictEqual(hdBread.validateMnemonic(), true);
assert.strictEqual(hdBread._getExternalAddressByIndex(0), '1ARGkNMdsBE36fJhddSwf8PqBXG3s4d2KU');
assert.strictEqual(hdBread._getInternalAddressByIndex(0), '1JLvA5D7RpWgChb4A5sFcLNrfxYbyZdw3V');
assert.equal(
assert.strictEqual(
hdBread.getXpub(),
'xpub68nLLEi3KERQY7jyznC9PQSpSjmekrEmN8324YRCXayMXaavbdEJsK4gEcX2bNf9vGzT4xRks9utZ7ot1CTHLtdyCn9udvv1NWvtY7HXroh',
);
await hdBread.fetchBalance();
assert.equal(hdBread.balance, 0);
assert.strictEqual(hdBread.balance, 0);
assert.ok(hdBread._lastTxFetch === 0);
await hdBread.fetchTransactions();
assert.ok(hdBread._lastTxFetch > 0);
assert.equal(hdBread.transactions.length, 177);
assert.strictEqual(hdBread.transactions.length, 177);
for (let tx of hdBread.getTransactions()) {
assert.ok(tx.confirmations);
}
assert.equal(hdBread.next_free_address_index, 10);
assert.equal(hdBread.next_free_change_address_index, 118);
assert.strictEqual(hdBread.next_free_address_index, 10);
assert.strictEqual(hdBread.next_free_change_address_index, 118);
// checking that internal pointer and async address getter return the same address
let freeAddress = await hdBread.getAddressAsync();
assert.equal(hdBread._getExternalAddressByIndex(hdBread.next_free_address_index), freeAddress);
assert.strictEqual(hdBread._getExternalAddressByIndex(hdBread.next_free_address_index), freeAddress);
});
it('can convert blockchain.info TX to blockcypher TX format', () => {

View file

@ -152,7 +152,7 @@ describe('LightningCustodianWallet', () => {
}
await l2.fetchTransactions();
assert.equal(l2.transactions_raw.length, txLen + 1);
assert.strictEqual(l2.transactions_raw.length, txLen + 1);
// transactions became more after paying an invoice
// now, trying to pay duplicate invoice
@ -165,7 +165,7 @@ describe('LightningCustodianWallet', () => {
}
assert.ok(caughtError);
await l2.fetchTransactions();
assert.equal(l2.transactions_raw.length, txLen + 1);
assert.strictEqual(l2.transactions_raw.length, txLen + 1);
// havent changed since last time
end = +new Date();
if ((end - start) / 1000 > 9) {
@ -191,21 +191,21 @@ describe('LightningCustodianWallet', () => {
await lNew.createAccount(true);
await lNew.authorize();
await lNew.fetchBalance();
assert.equal(lNew.balance, 0);
assert.strictEqual(lNew.balance, 0);
let invoices = await lNew.getUserInvoices();
let invoice = await lNew.addInvoice(1, 'test memo');
let invoices2 = await lNew.getUserInvoices();
assert.equal(invoices2.length, invoices.length + 1);
assert.strictEqual(invoices2.length, invoices.length + 1);
assert.ok(invoices2[0].ispaid === false);
assert.ok(invoices2[0].description);
assert.equal(invoices2[0].description, 'test memo');
assert.strictEqual(invoices2[0].description, 'test memo');
assert.ok(invoices2[0].payment_request);
assert.ok(invoices2[0].timestamp);
assert.ok(invoices2[0].expire_time);
assert.equal(invoices2[0].amt, 1);
assert.strictEqual(invoices2[0].amt, 1);
for (let inv of invoices2) {
assert.equal(inv.type, 'user_invoice');
assert.strictEqual(inv.type, 'user_invoice');
}
await lOld.fetchBalance();
@ -225,11 +225,11 @@ describe('LightningCustodianWallet', () => {
await lOld.fetchBalance();
await lNew.fetchBalance();
assert.equal(oldBalance - lOld.balance, 1);
assert.equal(lNew.balance, 1);
assert.strictEqual(oldBalance - lOld.balance, 1);
assert.strictEqual(lNew.balance, 1);
await lOld.fetchTransactions();
assert.equal(lOld.transactions_raw.length, txLen + 1, 'internal invoice should also produce record in payer`s tx list');
assert.strictEqual(lOld.transactions_raw.length, txLen + 1, 'internal invoice should also produce record in payer`s tx list');
let newTx = lOld.transactions_raw.slice().pop();
assert.ok(typeof newTx.fee !== 'undefined');
assert.ok(newTx.value);
@ -244,8 +244,8 @@ describe('LightningCustodianWallet', () => {
await lNew.payInvoice(invoice);
await lOld.fetchBalance();
await lNew.fetchBalance();
assert.equal(lOld.balance - oldBalance, 1);
assert.equal(lNew.balance, 0);
assert.strictEqual(lOld.balance - oldBalance, 1);
assert.strictEqual(lNew.balance, 0);
// now, paying same internal invoice. should fail:
@ -261,16 +261,16 @@ describe('LightningCustodianWallet', () => {
assert.ok(coughtError);
await lOld.fetchTransactions();
assert.equal(txLen, lOld.transactions_raw.length, 'tx count should not be changed');
assert.equal(invLen, (await lNew.getUserInvoices()).length, 'invoices count should not be changed');
assert.strictEqual(txLen, lOld.transactions_raw.length, 'tx count should not be changed');
assert.strictEqual(invLen, (await lNew.getUserInvoices()).length, 'invoices count should not be changed');
// testing how limiting works:
assert.equal(lNew.user_invoices_raw.length, 1);
assert.strictEqual(lNew.user_invoices_raw.length, 1);
await lNew.addInvoice(666, 'test memo 2');
invoices = await lNew.getUserInvoices(1);
assert.equal(invoices.length, 2);
assert.equal(invoices[0].amt, 1);
assert.equal(invoices[1].amt, 666);
assert.strictEqual(invoices.length, 2);
assert.strictEqual(invoices[0].amt, 1);
assert.strictEqual(invoices[1].amt, 666);
});
it('can pay free amount (tip) invoice', async function() {
@ -319,7 +319,7 @@ describe('LightningCustodianWallet', () => {
let decoded = await l2.decodeInvoice(invoice);
assert.ok(decoded.payment_hash);
assert.ok(decoded.description);
assert.equal(+decoded.num_satoshis, 0);
assert.strictEqual(+decoded.num_satoshis, 0);
await l2.checkRouteInvoice(invoice);
@ -342,10 +342,10 @@ describe('LightningCustodianWallet', () => {
}
await l2.fetchTransactions();
assert.equal(l2.transactions_raw.length, txLen + 1);
assert.strictEqual(l2.transactions_raw.length, txLen + 1);
// transactions became more after paying an invoice
await l2.fetchBalance();
assert.equal(oldBalance - l2.balance, 3);
assert.strictEqual(oldBalance - l2.balance, 3);
});
});

View file

@ -89,6 +89,8 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/apk_list" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/build-info" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/builds" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-libraries" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/checkDebugClasspath" />
@ -96,21 +98,31 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/compatible_screen_manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-apk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_main_apk_resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_merged_manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_split_apk_resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaPrecompile" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javac" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/linked_res_for_bundle" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifest-checker" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/module_bundle" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/prebuild" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/processed_res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shader_assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split-apk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split_list" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/splits-support" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />

View file

@ -3,6 +3,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.CAMERA"/>
<application
android:name=".MainApplication"

View file

@ -3,19 +3,14 @@ package io.bluewallet.bluewallet;
import android.app.Application;
import com.facebook.react.ReactApplication;
import com.reactnativecommunity.webview.RNCWebViewPackage;
import com.oblador.vectoricons.VectorIconsPackage;
import org.reactnative.camera.RNCameraPackage;
import io.sentry.RNSentryPackage;
import com.bitgo.randombytes.RandomBytesPackage;
import im.shimo.react.prompt.RNPromptPackage;
import com.BV.LinearGradient.LinearGradientPackage;
import com.mkuczera.RNReactNativeHapticFeedbackPackage;
import com.idehub.GoogleAnalyticsBridge.GoogleAnalyticsBridgePackage;
import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
import com.rnfs.RNFSPackage;
import com.learnium.RNDeviceInfo.RNDeviceInfo;
import org.reactnative.camera.RNCameraPackage;
import com.reactnativecommunity.webview.RNCWebViewPackage;
import com.oblador.vectoricons.VectorIconsPackage;
import com.horcrux.svg.SvgPackage;
import io.sentry.RNSentryPackage;
import com.bitgo.randombytes.RandomBytesPackage;
@ -28,6 +23,7 @@ import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import org.reactnative.camera.RNCameraPackage;
import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
import com.rnfs.RNFSPackage;
@ -46,18 +42,19 @@ public class MainApplication extends Application implements ReactApplication {
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new RNCWebViewPackage(),
new SvgPackage(),
new RNCameraPackage(),
new RNSentryPackage(),
new RandomBytesPackage(),
new GoogleAnalyticsBridgePackage(),
new RNFSPackage(),
new RNDeviceInfo(),
new VectorIconsPackage(),
new RNPromptPackage(),
new LinearGradientPackage(),
new RNReactNativeHapticFeedbackPackage(),
new GoogleAnalyticsBridgePackage(),
new RNCWebViewPackage(),
new RNFSPackage() ,
new VectorIconsPackage(),
new SvgPackage(),
new LinearGradientPackage(),
new RNDeviceInfo(),
new RNCameraPackage(),
new RNGestureHandlerPackage()
);
}

View file

@ -2,7 +2,7 @@
buildscript {
ext {
buildToolsVersion = "27.0.3"
buildToolsVersion = "28.0.3"
minSdkVersion = 16
compileSdkVersion = 27
targetSdkVersion = 26

View file

@ -1,4 +1,4 @@
#Sat Jan 19 02:29:20 GMT 2019
#Wed Jan 16 14:12:19 EST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

View file

@ -1,4 +1,26 @@
rootProject.name = 'BlueWallet'
include ':react-native-sentry'
project(':react-native-sentry').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sentry/android')
include ':react-native-randombytes'
project(':react-native-randombytes').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-randombytes/android')
include ':react-native-prompt-android'
project(':react-native-prompt-android').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-prompt-android/android')
include ':react-native-linear-gradient'
project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android')
include ':react-native-haptic-feedback'
project(':react-native-haptic-feedback').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-haptic-feedback/android')
include ':react-native-google-analytics-bridge'
project(':react-native-google-analytics-bridge').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-google-analytics-bridge/android')
include ':react-native-gesture-handler'
project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
include ':react-native-fs'
project(':react-native-fs').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fs/android')
include ':react-native-webview'
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
include ':react-native-device-info'
project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
include ':react-native-camera'
project(':react-native-camera').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-camera/android')
include ':react-native-webview'
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
include ':react-native-svg'

View file

@ -499,6 +499,13 @@
remoteGlobalIDString = 0974579A1D2A440A000D9368;
remoteInfo = RCTWKWebView;
};
B4DA894521F6056C00A3CB6C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5F3DCC24027F4B1EAACBAE3C /* RNCWebView.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RNCWebView;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
@ -1032,6 +1039,14 @@
name = Products;
sourceTree = "<group>";
};
B4DA891821F6056C00A3CB6C /* Products */ = {
isa = PBXGroup;
children = (
B4DA894621F6056C00A3CB6C /* libRNCWebView.a */,
);
name = Products;
sourceTree = "<group>";
};
FC7D399B1A1043C49023DC79 /* Resources */ = {
isa = PBXGroup;
children = (
@ -1081,8 +1096,8 @@
buildPhases = (
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
13B07F8E1A680F5B00A75B9A /* Resources */,
B9B0C844E4364469A20FB477 /* Upload Debug Symbols to Sentry */,
);
buildRules = (
@ -1237,6 +1252,10 @@
ProductGroup = B4C5B8E121F2DF3000A845C4 /* Products */;
ProjectRef = 3853DFD4C6D44BB8B17AEDF0 /* RNCamera.xcodeproj */;
},
{
ProductGroup = B4DA891821F6056C00A3CB6C /* Products */;
ProjectRef = 5F3DCC24027F4B1EAACBAE3C /* RNCWebView.xcodeproj */;
},
{
ProductGroup = B4C5B8E521F2DF3000A845C4 /* Products */;
ProjectRef = 03D541ACCDD2451D9971158E /* RNDeviceInfo.xcodeproj */;
@ -1691,6 +1710,13 @@
remoteRef = B4C5BAB521F3708C00A845C4 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
B4DA894621F6056C00A3CB6C /* libRNCWebView.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRNCWebView.a;
remoteRef = B4DA894521F6056C00A3CB6C /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
@ -1755,7 +1781,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export SENTRY_PROPERTIES=sentry.properties\nexport NODE_BINARY=node\n../node_modules/@sentry/cli/bin/sentry-cli react-native xcode ../node_modules/react-native/scripts/react-native-xcode.sh";
shellScript = "export SENTRY_PROPERTIES=sentry.properties\nexport NODE_BINARY=node\n../node_modules/@sentry/cli/bin/sentry-cli react-native xcode ../node_modules/react-native/scripts/react-native-xcode.sh\n";
};
2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */ = {
isa = PBXShellScriptBuildPhase;

View file

@ -56,7 +56,7 @@
<key>NSCalendarsUsageDescription</key>
<string>This alert should not show up as we do not require this data</string>
<key>NSCameraUsageDescription</key>
<string>In order to quickly scan the recipient's address, we need your permission to use the camera to scan their QR Code.</string>
<string>In order to quickly scan the recipient&apos;s address, we need your permission to use the camera to scan their QR Code.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This alert should not show up as we do not require this data</string>
<key>NSMotionUsageDescription</key>
@ -67,6 +67,8 @@
<string>This alert should not show up as we do not require this data</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>This alert should not show up as we do not require this data</string>
<key>NSMicrophoneUsageDescription</key>
<string>This alert should not show up as we do not require this data</string>
<key>UIAppFonts</key>
<array>
<string>AntDesign.ttf</string>

816
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,17 +1,17 @@
{
"name": "BlueWallet",
"version": "3.6.3",
"version": "3.6.0",
"devDependencies": {
"babel-eslint": "^8.2.6",
"babel-eslint": "^10.0.1",
"babel-jest": "23.6.0",
"eslint": "^4.19.1",
"eslint-plugin-babel": "^4.1.2",
"eslint": "^5.12.1",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^6.0.1",
"eslint-plugin-promise": "^3.8.0",
"eslint-plugin-node": "^8.0.1",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-react": "^7.12.3",
"jest": "23.6.0",
"metro-react-native-babel-preset": "^0.49.1",
"metro-react-native-babel-preset": "^0.51.1",
"prettier-eslint-cli": "^4.7.1",
"react-test-renderer": "^16.7.0",
"rn-nodeify": "github:tradle/rn-nodeify"
@ -36,7 +36,7 @@
},
"dependencies": {
"@babel/preset-env": "^7.2.3",
"bignumber.js": "^7.0.0",
"bignumber.js": "^8.0.2",
"bip21": "^2.0.2",
"bip39": "^2.5.0",
"bitcoinjs-lib": "^3.3.2",
@ -44,30 +44,30 @@
"buffer-reverse": "^1.0.1",
"crypto-js": "^3.1.9-1",
"dayjs": "^1.8.0",
"eslint-config-prettier": "^2.10.0",
"eslint-config-prettier": "^3.6.0",
"eslint-config-standard": "^12.0.0",
"eslint-config-standard-react": "^7.0.2",
"eslint-plugin-prettier": "^2.6.2",
"eslint-plugin-prettier": "^3.0.1",
"eslint-plugin-standard": "^4.0.0",
"frisbee": "^1.6.4",
"intl": "^1.2.5",
"mocha": "^5.2.0",
"node-libs-react-native": "^1.0.1",
"path-browserify": "0.0.0",
"prettier": "^1.14.2",
"prettier": "^1.16.0",
"process": "^0.11.10",
"prop-types": "^15.6.2",
"react": "^16.7.0",
"react-localization": "^1.0.10",
"react-native": "^0.57.8",
"react-native-camera": "^1.8.0",
"react-native-camera": "^1.9.0",
"react-native-custom-qr-codes": "^2.0.0",
"react-native-device-info": "^0.25.0",
"react-native-device-info": "^0.25.1",
"react-native-elements": "^0.19.0",
"react-native-flexi-radio-button": "^0.2.2",
"react-native-fs": "^2.13.3",
"react-native-gesture-handler": "^1.0.12",
"react-native-google-analytics-bridge": "^6.1.2",
"react-native-google-analytics-bridge": "^7.0.0",
"react-native-haptic-feedback": "^1.4.2",
"react-native-level-fs": "^3.0.1",
"react-native-linear-gradient": "^2.5.3",
@ -80,8 +80,8 @@
"react-native-sentry": "^0.40.2",
"react-native-snap-carousel": "^3.7.4",
"react-native-sortable-list": "0.0.22",
"react-native-svg": "^8.0.10",
"react-native-vector-icons": "^6.0.2",
"react-native-svg": "^9.0.0",
"react-native-vector-icons": "^6.2.0",
"react-native-webview": "2.8.0",
"react-native-wkwebview-reborn": "^2.0.0",
"react-navigation": "^3.0.9",
@ -90,6 +90,7 @@
"request-promise-native": "^1.0.5",
"secure-random": "^1.1.1",
"stream-browserify": "^1.0.0",
"util": "^0.11.1",
"wif": "^2.0.1"
},
"react-native": {

View file

@ -1,7 +1,15 @@
/* global alert */
import React, { Component } from 'react';
import { Animated, StyleSheet, View, TouchableOpacity, Clipboard, Share } from 'react-native';
import { BlueLoading, SafeBlueArea, BlueButton, BlueNavigationStyle, BlueText, BlueSpacing20 } from '../../BlueComponents';
import { View, Share } from 'react-native';
import {
BlueLoading,
BlueCopyTextToClipboard,
SafeBlueArea,
BlueButton,
BlueNavigationStyle,
BlueText,
BlueSpacing20,
} from '../../BlueComponents';
import PropTypes from 'prop-types';
import { QRCode } from 'react-native-custom-qr-codes';
/** @type {AppStorage} */
@ -16,13 +24,6 @@ export default class LNDViewAdditionalInvoiceInformation extends Component {
state = { walletInfo: undefined };
copyToClipboard = () => {
this.setState({ addressText: loc.receive.details.copiedToClipboard }, () => {
Clipboard.setString(this.state.walletInfo.uris[0]);
setTimeout(() => this.setState({ addressText: this.state.walletInfo.uris[0] }), 1000);
});
};
async componentDidMount() {
const fromWallet = this.props.navigation.getParam('fromWallet');
try {
@ -56,11 +57,7 @@ export default class LNDViewAdditionalInvoiceInformation extends Component {
/>
<BlueSpacing20 />
<BlueText>Open direct channel with this node:</BlueText>
<TouchableOpacity onPress={this.copyToClipboard}>
<Animated.Text style={styles.address} numberOfLines={0}>
{this.state.addressText}
</Animated.Text>
</TouchableOpacity>
<BlueCopyTextToClipboard text={this.state.walletInfo.uris[0]} />
</View>
<View style={{ marginBottom: 24 }}>
<BlueButton
@ -83,15 +80,6 @@ export default class LNDViewAdditionalInvoiceInformation extends Component {
}
}
const styles = StyleSheet.create({
address: {
marginVertical: 32,
fontSize: 15,
color: '#9aa0aa',
textAlign: 'center',
},
});
LNDViewAdditionalInvoiceInformation.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.function,

View file

@ -1,6 +1,14 @@
import React, { Component } from 'react';
import { Animated, StyleSheet, View, TouchableOpacity, Clipboard, Dimensions, Share, ScrollView, BackHandler } from 'react-native';
import { BlueLoading, BlueText, SafeBlueArea, BlueButton, BlueNavigationStyle, BlueSpacing20 } from '../../BlueComponents';
import { View, Dimensions, Share, ScrollView, BackHandler } from 'react-native';
import {
BlueLoading,
BlueText,
SafeBlueArea,
BlueButton,
BlueCopyTextToClipboard,
BlueNavigationStyle,
BlueSpacing20,
} from '../../BlueComponents';
import PropTypes from 'prop-types';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { Icon } from 'react-native-elements';
@ -88,16 +96,10 @@ export default class LNDViewInvoice extends Component {
}
handleBackButton() {
this.props.navigation.dismiss();
return true;
}
copyToClipboard = () => {
this.setState({ addressText: loc.receive.details.copiedToClipboard }, () => {
Clipboard.setString(this.state.invoice.payment_request);
setTimeout(() => this.setState({ addressText: this.state.invoice.payment_request }), 1000);
});
};
onLayout = () => {
const { height } = Dimensions.get('window');
this.setState({ qrCodeHeight: height > width ? width - 20 : width / 2 });
@ -181,12 +183,11 @@ export default class LNDViewInvoice extends Component {
flex: 1,
alignItems: 'center',
marginTop: 8,
paddingHorizontal: 16,
justifyContent: 'space-between',
}}
onLayout={this.onLayout}
>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 16 }}>
<QRFast
value={typeof this.state.invoice === 'object' ? invoice.payment_request : invoice}
fgColor={BlueApp.settings.brandingColor}
@ -198,11 +199,7 @@ export default class LNDViewInvoice extends Component {
<BlueSpacing20 />
{invoice && invoice.amt && <BlueText>Please pay {invoice.amt} sats</BlueText>}
{invoice && invoice.description && <BlueText>For: {invoice.description}</BlueText>}
<TouchableOpacity onPress={this.copyToClipboard}>
<Animated.Text style={styles.address} numberOfLines={0}>
{this.state.addressText}
</Animated.Text>
</TouchableOpacity>
<BlueCopyTextToClipboard text={this.state.invoice.payment_request} />
<BlueButton
icon={{
@ -235,15 +232,6 @@ export default class LNDViewInvoice extends Component {
}
}
const styles = StyleSheet.create({
address: {
marginVertical: 32,
fontSize: 15,
color: '#9aa0aa',
textAlign: 'center',
},
});
LNDViewInvoice.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.function,

View file

@ -1,8 +1,16 @@
import React, { Component } from 'react';
import { Animated, StyleSheet, View, TouchableOpacity, Clipboard, Share } from 'react-native';
import { View, Share } from 'react-native';
import { QRCode } from 'react-native-custom-qr-codes';
import bip21 from 'bip21';
import { BlueLoading, SafeBlueArea, BlueButton, BlueButtonLink, BlueNavigationStyle, is } from '../../BlueComponents';
import {
BlueLoading,
SafeBlueArea,
BlueCopyTextToClipboard,
BlueButton,
BlueButtonLink,
BlueNavigationStyle,
is,
} from '../../BlueComponents';
import PropTypes from 'prop-types';
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
@ -70,13 +78,6 @@ export default class ReceiveDetails extends Component {
}
}
copyToClipboard = () => {
this.setState({ addressText: loc.receive.details.copiedToClipboard }, () => {
Clipboard.setString(this.state.address);
setTimeout(() => this.setState({ addressText: this.state.address }), 1000);
});
};
render() {
console.log('render() receive/details, address,secret=', this.state.address, ',', this.state.secret);
if (this.state.isLoading) {
@ -94,11 +95,7 @@ export default class ReceiveDetails extends Component {
backgroundColor={BlueApp.settings.brandingColor}
logo={require('../../img/qr-code.png')}
/>
<TouchableOpacity onPress={this.copyToClipboard}>
<Animated.Text style={styles.address} numberOfLines={0}>
{this.state.addressText}
</Animated.Text>
</TouchableOpacity>
<BlueCopyTextToClipboard text={this.state.addressText} />
</View>
<View style={{ marginBottom: 24, alignItems: 'center' }}>
<BlueButtonLink
@ -129,15 +126,6 @@ export default class ReceiveDetails extends Component {
}
}
const styles = StyleSheet.create({
address: {
marginVertical: 32,
fontSize: 15,
color: '#9aa0aa',
textAlign: 'center',
},
});
ReceiveDetails.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.function,

View file

@ -1,21 +1,9 @@
import React, { Component } from 'react';
import {
StyleSheet,
View,
Share,
TextInput,
KeyboardAvoidingView,
Clipboard,
Animated,
TouchableOpacity,
Platform,
Dimensions,
ScrollView,
} from 'react-native';
import { View, Share, TextInput, KeyboardAvoidingView, Platform, Dimensions, ScrollView } from 'react-native';
import { QRCode as QRSlow } from 'react-native-custom-qr-codes';
import QRFast from 'react-native-qrcode';
import bip21 from 'bip21';
import { SafeBlueArea, BlueButton, BlueNavigationStyle, BlueBitcoinAmount, BlueText } from '../../BlueComponents';
import { SafeBlueArea, BlueButton, BlueNavigationStyle, BlueBitcoinAmount, BlueText, BlueCopyTextToClipboard } from '../../BlueComponents';
import PropTypes from 'prop-types';
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
@ -52,13 +40,6 @@ export default class ReceiveAmount extends Component {
};
}
copyToClipboard = () => {
this.setState({ addressText: loc.receive.details.copiedToClipboard }, () => {
Clipboard.setString(this.state.bip21);
setTimeout(() => this.setState({ addressText: this.state.address }), 1000);
});
};
determineSize = () => {
if (width > 312) {
return width - 48;
@ -133,11 +114,7 @@ export default class ReceiveAmount extends Component {
)}
</View>
<View style={{ marginBottom: 24, alignItems: 'center', justifyContent: 'space-between' }}>
<TouchableOpacity onPress={this.copyToClipboard}>
<Animated.Text style={styles.address} numberOfLines={0}>
{this.state.bip21}
</Animated.Text>
</TouchableOpacity>
<BlueCopyTextToClipboard text={this.state.bip21} />
</View>
</View>
);
@ -181,12 +158,3 @@ export default class ReceiveAmount extends Component {
);
}
}
const styles = StyleSheet.create({
address: {
marginVertical: 32,
fontSize: 15,
color: '#9aa0aa',
textAlign: 'center',
},
});

View file

@ -109,7 +109,7 @@ export default class About extends Component {
};
Rate.rate(options, success => {
if (success) {
console.warn('User Rated.');
console.log('User Rated.');
}
});
}}

View file

@ -1,6 +1,14 @@
import React, { Component } from 'react';
import { Animated, Linking, StyleSheet, View, TouchableOpacity, Clipboard } from 'react-native';
import { BlueNavigationStyle, BlueLoading, SafeBlueArea, BlueButton, BlueText, BlueSpacing40 } from '../../BlueComponents';
import { Linking, View } from 'react-native';
import {
BlueNavigationStyle,
BlueCopyTextToClipboard,
BlueLoading,
SafeBlueArea,
BlueButton,
BlueText,
BlueSpacing40,
} from '../../BlueComponents';
import PropTypes from 'prop-types';
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
@ -58,13 +66,6 @@ export default class BuyBitcoin extends Component {
}
}
copyToClipboard = () => {
this.setState({ addressText: loc.buyBitcoin.copied }, () => {
Clipboard.setString(this.state.address);
setTimeout(() => this.setState({ addressText: this.state.address }), 1000);
});
};
render() {
console.log('render() receive/details, address,secret=', this.state.address, ',', this.state.secret);
if (this.state.isLoading) {
@ -77,11 +78,7 @@ export default class BuyBitcoin extends Component {
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 16 }}>
<BlueText>{loc.buyBitcoin.tap_your_address}</BlueText>
<TouchableOpacity onPress={this.copyToClipboard}>
<Animated.Text style={styles.address} numberOfLines={0}>
{this.state.addressText}
</Animated.Text>
</TouchableOpacity>
<BlueCopyTextToClipboard text={this.state.addressText} />
<BlueButton
icon={{
@ -108,15 +105,6 @@ export default class BuyBitcoin extends Component {
}
}
const styles = StyleSheet.create({
address: {
marginVertical: 32,
fontSize: 15,
color: '#9aa0aa',
textAlign: 'center',
},
});
BuyBitcoin.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.function,

View file

@ -1,7 +1,7 @@
import React, { Component } from 'react';
import { Dimensions, Platform, ActivityIndicator, View, Clipboard, Animated, TouchableOpacity } from 'react-native';
import { Dimensions, Platform, ActivityIndicator, View } from 'react-native';
import { QRCode as QRSlow } from 'react-native-custom-qr-codes';
import { BlueSpacing20, SafeBlueArea, BlueText, BlueNavigationStyle } from '../../BlueComponents';
import { BlueSpacing20, SafeBlueArea, BlueText, BlueNavigationStyle, BlueCopyTextToClipboard } from '../../BlueComponents';
import PropTypes from 'prop-types';
const QRFast = require('react-native-qrcode');
/** @type {AppStorage} */
@ -49,13 +49,6 @@ export default class WalletXpub extends Component {
}, 1000);
}
copyToClipboard = () => {
this.setState({ xpubText: loc.wallets.xpub.copiedToClipboard }, () => {
Clipboard.setString(this.state.xpub);
setTimeout(() => this.setState({ xpubText: this.state.xpub }), 1000);
});
};
onLayout = () => {
const { height } = Dimensions.get('window');
this.setState({ qrCodeHeight: height > width ? width - 40 : width / 2 });
@ -110,11 +103,7 @@ export default class WalletXpub extends Component {
}
})()}
<BlueSpacing20 />
<TouchableOpacity onPress={this.copyToClipboard}>
<Animated.Text style={{ paddingHorizontal: 8, textAlign: 'center' }} numberOfLines={0}>
{this.state.xpubText}
</Animated.Text>
</TouchableOpacity>
<BlueCopyTextToClipboard text={this.state.xpubText} />
</View>
</SafeBlueArea>
);