ADD: Created BlueCopyTextToClipboard

This commit is contained in:
Marcos Rodriguez Vélez 2019-01-21 08:55:39 -05:00
parent a94f571cf6
commit 3237c8c2c3
13 changed files with 758 additions and 533 deletions

View File

@ -57,7 +57,7 @@ describe('unit - LegacyWallet', function() {
let b = LegacyWallet.fromJson(key); let b = LegacyWallet.fromJson(key);
assert(key === JSON.stringify(b)); assert(key === JSON.stringify(b));
assert.equal(key, JSON.stringify(b)); assert.strictEqual(key, JSON.stringify(b));
}); });
it('can validate addresses', () => { it('can validate addresses', () => {
@ -118,8 +118,8 @@ it('Appstorage - loadFromDisk works', async () => {
let Storage2 = new AppStorage(); let Storage2 = new AppStorage();
await Storage2.loadFromDisk(); await Storage2.loadFromDisk();
assert.equal(Storage2.wallets.length, 1); assert.strictEqual(Storage2.wallets.length, 1);
assert.equal(Storage2.wallets[0].getLabel(), 'testlabel'); assert.strictEqual(Storage2.wallets[0].getLabel(), 'testlabel');
let isEncrypted = await Storage2.storageIsEncrypted(); let isEncrypted = await Storage2.storageIsEncrypted();
assert.ok(!isEncrypted); assert.ok(!isEncrypted);
@ -146,7 +146,7 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.ok(!isEncrypted); assert.ok(!isEncrypted);
await Storage.encryptStorage('password'); await Storage.encryptStorage('password');
isEncrypted = await Storage.storageIsEncrypted(); isEncrypted = await Storage.storageIsEncrypted();
assert.equal(Storage.cachedPassword, 'password'); assert.strictEqual(Storage.cachedPassword, 'password');
assert.ok(isEncrypted); assert.ok(isEncrypted);
// saved, now trying to load, using good password // saved, now trying to load, using good password
@ -156,8 +156,8 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.ok(isEncrypted); assert.ok(isEncrypted);
let loadResult = await Storage2.loadFromDisk('password'); let loadResult = await Storage2.loadFromDisk('password');
assert.ok(loadResult); assert.ok(loadResult);
assert.equal(Storage2.wallets.length, 1); assert.strictEqual(Storage2.wallets.length, 1);
assert.equal(Storage2.wallets[0].getLabel(), 'testlabel'); assert.strictEqual(Storage2.wallets[0].getLabel(), 'testlabel');
// now trying to load, using bad password // now trying to load, using bad password
@ -166,7 +166,7 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.ok(isEncrypted); assert.ok(isEncrypted);
loadResult = await Storage2.loadFromDisk('passwordBAD'); loadResult = await Storage2.loadFromDisk('passwordBAD');
assert.ok(!loadResult); assert.ok(!loadResult);
assert.equal(Storage2.wallets.length, 0); assert.strictEqual(Storage2.wallets.length, 0);
// now, trying case with adding data after decrypt. // now, trying case with adding data after decrypt.
// saveToDisk should be handled correctly // saveToDisk should be handled correctly
@ -176,14 +176,14 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.ok(isEncrypted); assert.ok(isEncrypted);
loadResult = await Storage2.loadFromDisk('password'); loadResult = await Storage2.loadFromDisk('password');
assert.ok(loadResult); assert.ok(loadResult);
assert.equal(Storage2.wallets.length, 1); assert.strictEqual(Storage2.wallets.length, 1);
assert.equal(Storage2.wallets[0].getLabel(), 'testlabel'); assert.strictEqual(Storage2.wallets[0].getLabel(), 'testlabel');
w = new SegwitP2SHWallet(); w = new SegwitP2SHWallet();
w.setLabel('testlabel2'); w.setLabel('testlabel2');
await w.generate(); await w.generate();
Storage2.wallets.push(w); Storage2.wallets.push(w);
assert.equal(Storage2.wallets.length, 2); assert.strictEqual(Storage2.wallets.length, 2);
assert.equal(Storage2.wallets[1].getLabel(), 'testlabel2'); assert.strictEqual(Storage2.wallets[1].getLabel(), 'testlabel2');
await Storage2.saveToDisk(); await Storage2.saveToDisk();
// saved to encrypted storage after load. next load should be successfull // saved to encrypted storage after load. next load should be successfull
Storage2 = new AppStorage(); Storage2 = new AppStorage();
@ -191,15 +191,15 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
assert.ok(isEncrypted); assert.ok(isEncrypted);
loadResult = await Storage2.loadFromDisk('password'); loadResult = await Storage2.loadFromDisk('password');
assert.ok(loadResult); assert.ok(loadResult);
assert.equal(Storage2.wallets.length, 2); assert.strictEqual(Storage2.wallets.length, 2);
assert.equal(Storage2.wallets[0].getLabel(), 'testlabel'); assert.strictEqual(Storage2.wallets[0].getLabel(), 'testlabel');
assert.equal(Storage2.wallets[1].getLabel(), 'testlabel2'); assert.strictEqual(Storage2.wallets[1].getLabel(), 'testlabel2');
// next, adding new `fake` storage which should be unlocked with `fake` password // next, adding new `fake` storage which should be unlocked with `fake` password
let createFakeStorageResult = await Storage2.createFakeStorage('fakePassword'); let createFakeStorageResult = await Storage2.createFakeStorage('fakePassword');
assert.ok(createFakeStorageResult); assert.ok(createFakeStorageResult);
assert.equal(Storage2.wallets.length, 0); assert.strictEqual(Storage2.wallets.length, 0);
assert.equal(Storage2.cachedPassword, 'fakePassword'); assert.strictEqual(Storage2.cachedPassword, 'fakePassword');
w = new SegwitP2SHWallet(); w = new SegwitP2SHWallet();
w.setLabel('fakewallet'); w.setLabel('fakewallet');
await w.generate(); await w.generate();
@ -210,14 +210,14 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
let Storage3 = new AppStorage(); let Storage3 = new AppStorage();
loadResult = await Storage3.loadFromDisk('password'); loadResult = await Storage3.loadFromDisk('password');
assert.ok(loadResult); assert.ok(loadResult);
assert.equal(Storage3.wallets.length, 2); assert.strictEqual(Storage3.wallets.length, 2);
assert.equal(Storage3.wallets[0].getLabel(), 'testlabel'); assert.strictEqual(Storage3.wallets[0].getLabel(), 'testlabel');
// fake: // fake:
Storage3 = new AppStorage(); Storage3 = new AppStorage();
loadResult = await Storage3.loadFromDisk('fakePassword'); loadResult = await Storage3.loadFromDisk('fakePassword');
assert.ok(loadResult); assert.ok(loadResult);
assert.equal(Storage3.wallets.length, 1); assert.strictEqual(Storage3.wallets.length, 1);
assert.equal(Storage3.wallets[0].getLabel(), 'fakewallet'); assert.strictEqual(Storage3.wallets[0].getLabel(), 'fakewallet');
}); });
it('Wallet can fetch UTXO', async () => { it('Wallet can fetch UTXO', async () => {
@ -245,7 +245,7 @@ it('Wallet can fetch TXs', async () => {
let w = new LegacyWallet(); let w = new LegacyWallet();
w._address = '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG'; w._address = '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG';
await w.fetchTransactions(); await w.fetchTransactions();
assert.equal(w.getTransactions().length, 2); assert.strictEqual(w.getTransactions().length, 2);
let tx0 = w.getTransactions()[0]; let tx0 = w.getTransactions()[0];
let txExpected = { let txExpected = {
@ -296,7 +296,7 @@ it('Wallet can fetch TXs', async () => {
delete txExpected.confirmations; delete txExpected.confirmations;
delete tx0.preference; // that bs is not always the same delete tx0.preference; // that bs is not always the same
delete txExpected.preference; delete txExpected.preference;
assert.deepEqual(tx0, txExpected); assert.deepStrictEqual(tx0, txExpected);
}); });
describe('currency', () => { describe('currency', () => {
@ -321,7 +321,7 @@ describe('currency', () => {
await currency.setPrefferedCurrency(FiatUnit.EUR); await currency.setPrefferedCurrency(FiatUnit.EUR);
await currency.startUpdater(); await currency.startUpdater();
let preferred = await currency.getPreferredCurrency(); let preferred = await currency.getPreferredCurrency();
assert.equal(preferred.endPointKey, 'EUR'); assert.strictEqual(preferred.endPointKey, 'EUR');
cur = JSON.parse(AsyncStorage.storageCache[AppStorage.EXCHANGE_RATES]); cur = JSON.parse(AsyncStorage.storageCache[AppStorage.EXCHANGE_RATES]);
assert.ok(cur['BTC_EUR'] > 0); 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) { 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 () => { it('bip38 decodes slow', async () => {
@ -29,7 +32,10 @@ it('bip38 decodes slow', async () => {
let encryptedKey = '6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN'; let encryptedKey = '6PnU5voARjBBykwSddwCdcn6Eu9EcsK24Gs5zWxbJbPZYW7eiYQP8XgKbN';
let decryptedKey = await bip38.decrypt(encryptedKey, 'qwerty', status => process.stdout.write(parseInt(status.percent) + '%\r')); 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', () => { describe('Watch only wallet', () => {
@ -46,16 +52,16 @@ describe('Watch only wallet', () => {
w.setSecret('167zK5iZrs1U6piDqubD3FjRqUTM2CZnb8'); w.setSecret('167zK5iZrs1U6piDqubD3FjRqUTM2CZnb8');
await w.fetchTransactions(); await w.fetchTransactions();
assert.equal(w.getTransactions().length, 233); assert.strictEqual(w.getTransactions().length, 233);
w = new WatchOnlyWallet(); w = new WatchOnlyWallet();
w.setSecret('1BiJW1jyUaxcJp2JWwbPLPzB1toPNWTFJV'); w.setSecret('1BiJW1jyUaxcJp2JWwbPLPzB1toPNWTFJV');
await w.fetchTransactions(); await w.fetchTransactions();
assert.equal(w.getTransactions().length, 2); assert.strictEqual(w.getTransactions().length, 2);
// fetch again and make sure no duplicates // fetch again and make sure no duplicates
await w.fetchTransactions(); await w.fetchTransactions();
assert.equal(w.getTransactions().length, 2); assert.strictEqual(w.getTransactions().length, 2);
}); });
it('can fetch complex TXs', async () => { it('can fetch complex TXs', async () => {

View File

@ -16,6 +16,7 @@ import {
SafeAreaView, SafeAreaView,
Clipboard, Clipboard,
Platform, Platform,
LayoutAnimation,
TextInput, TextInput,
} from 'react-native'; } from 'react-native';
import LinearGradient from 'react-native-linear-gradient'; import LinearGradient from 'react-native-linear-gradient';
@ -193,6 +194,55 @@ export const BlueCopyToClipboardButton = ({ stringToCopy }) => {
); );
}; };
export class BlueCopyTextToClipboard extends Component {
static propTypes = {
text: PropTypes.string,
};
static defaultProps = {
text: '',
};
state = { hasTappedText: false };
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 { export class SafeBlueArea extends Component {
render() { render() {
return ( return (

View File

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

View File

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

774
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,17 @@
{ {
"name": "BlueWallet", "name": "BlueWallet",
"version": "3.6.2", "version": "3.6.0",
"devDependencies": { "devDependencies": {
"babel-eslint": "^8.2.6", "babel-eslint": "^10.0.1",
"babel-jest": "23.6.0", "babel-jest": "23.6.0",
"eslint": "^4.19.1", "eslint": "^5.12.1",
"eslint-plugin-babel": "^4.1.2", "eslint-plugin-babel": "^5.3.0",
"eslint-plugin-import": "^2.14.0", "eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^6.0.1", "eslint-plugin-node": "^8.0.1",
"eslint-plugin-promise": "^3.8.0", "eslint-plugin-promise": "^4.0.1",
"eslint-plugin-react": "^7.12.3", "eslint-plugin-react": "^7.12.3",
"jest": "23.6.0", "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", "prettier-eslint-cli": "^4.7.1",
"react-test-renderer": "^16.7.0", "react-test-renderer": "^16.7.0",
"rn-nodeify": "github:tradle/rn-nodeify" "rn-nodeify": "github:tradle/rn-nodeify"
@ -54,20 +54,20 @@
"mocha": "^5.2.0", "mocha": "^5.2.0",
"node-libs-react-native": "^1.0.1", "node-libs-react-native": "^1.0.1",
"path-browserify": "0.0.0", "path-browserify": "0.0.0",
"prettier": "^1.14.2", "prettier": "^1.16.0",
"process": "^0.11.10", "process": "^0.11.10",
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"react": "^16.7.0", "react": "^16.7.0",
"react-localization": "^1.0.10", "react-localization": "^1.0.10",
"react-native": "^0.57.8", "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-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-elements": "^0.19.0",
"react-native-flexi-radio-button": "^0.2.2", "react-native-flexi-radio-button": "^0.2.2",
"react-native-fs": "^2.13.3", "react-native-fs": "^2.13.3",
"react-native-gesture-handler": "^1.0.12", "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-haptic-feedback": "^1.4.2",
"react-native-level-fs": "^3.0.1", "react-native-level-fs": "^3.0.1",
"react-native-linear-gradient": "^2.5.3", "react-native-linear-gradient": "^2.5.3",
@ -83,13 +83,13 @@
"react-native-svg": "^9.0.0", "react-native-svg": "^9.0.0",
"react-native-vector-icons": "^6.0.2", "react-native-vector-icons": "^6.0.2",
"react-native-webview": "2.8.0", "react-native-webview": "2.8.0",
"react-native-wkwebview-reborn": "^2.0.0",
"react-navigation": "^3.0.9", "react-navigation": "^3.0.9",
"react-test-render": "^1.1.1", "react-test-render": "^1.1.1",
"readable-stream": "^1.1.14", "readable-stream": "^1.1.14",
"request-promise-native": "^1.0.5", "request-promise-native": "^1.0.5",
"secure-random": "^1.1.1", "secure-random": "^1.1.1",
"stream-browserify": "^1.0.0", "stream-browserify": "^1.0.0",
"util": "^0.11.1",
"wif": "^2.0.1" "wif": "^2.0.1"
}, },
"react-native": { "react-native": {

View File

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

View File

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

View File

@ -1,8 +1,16 @@
import React, { Component } from 'react'; 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 { QRCode } from 'react-native-custom-qr-codes';
import bip21 from 'bip21'; 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'; import PropTypes from 'prop-types';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); 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() { render() {
console.log('render() receive/details, address,secret=', this.state.address, ',', this.state.secret); console.log('render() receive/details, address,secret=', this.state.address, ',', this.state.secret);
if (this.state.isLoading) { if (this.state.isLoading) {
@ -94,11 +95,7 @@ export default class ReceiveDetails extends Component {
backgroundColor={BlueApp.settings.brandingColor} backgroundColor={BlueApp.settings.brandingColor}
logo={require('../../img/qr-code.png')} logo={require('../../img/qr-code.png')}
/> />
<TouchableOpacity onPress={this.copyToClipboard}> <BlueCopyTextToClipboard text={this.state.addressText} />
<Animated.Text style={styles.address} numberOfLines={0}>
{this.state.addressText}
</Animated.Text>
</TouchableOpacity>
</View> </View>
<View style={{ marginBottom: 24, alignItems: 'center' }}> <View style={{ marginBottom: 24, alignItems: 'center' }}>
<BlueButtonLink <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 = { ReceiveDetails.propTypes = {
navigation: PropTypes.shape({ navigation: PropTypes.shape({
goBack: PropTypes.function, goBack: PropTypes.function,

View File

@ -1,21 +1,9 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { import { View, Share, TextInput, KeyboardAvoidingView, Platform, Dimensions, ScrollView } from 'react-native';
StyleSheet,
View,
Share,
TextInput,
KeyboardAvoidingView,
Clipboard,
Animated,
TouchableOpacity,
Platform,
Dimensions,
ScrollView,
} from 'react-native';
import { QRCode as QRSlow } from 'react-native-custom-qr-codes'; import { QRCode as QRSlow } from 'react-native-custom-qr-codes';
import QRFast from 'react-native-qrcode'; import QRFast from 'react-native-qrcode';
import bip21 from 'bip21'; 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'; import PropTypes from 'prop-types';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); 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 = () => { determineSize = () => {
if (width > 312) { if (width > 312) {
return width - 48; return width - 48;
@ -133,11 +114,7 @@ export default class ReceiveAmount extends Component {
)} )}
</View> </View>
<View style={{ marginBottom: 24, alignItems: 'center', justifyContent: 'space-between' }}> <View style={{ marginBottom: 24, alignItems: 'center', justifyContent: 'space-between' }}>
<TouchableOpacity onPress={this.copyToClipboard}> <BlueCopyTextToClipboard text={this.state.bip21} />
<Animated.Text style={styles.address} numberOfLines={0}>
{this.state.bip21}
</Animated.Text>
</TouchableOpacity>
</View> </View>
</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

@ -1,6 +1,14 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Animated, Linking, StyleSheet, View, TouchableOpacity, Clipboard } from 'react-native'; import { Linking, View } from 'react-native';
import { BlueNavigationStyle, BlueLoading, SafeBlueArea, BlueButton, BlueText, BlueSpacing40 } from '../../BlueComponents'; import {
BlueNavigationStyle,
BlueCopyTextToClipboard,
BlueLoading,
SafeBlueArea,
BlueButton,
BlueText,
BlueSpacing40,
} from '../../BlueComponents';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
/** @type {AppStorage} */ /** @type {AppStorage} */
let BlueApp = require('../../BlueApp'); 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() { render() {
console.log('render() receive/details, address,secret=', this.state.address, ',', this.state.secret); console.log('render() receive/details, address,secret=', this.state.address, ',', this.state.secret);
if (this.state.isLoading) { if (this.state.isLoading) {
@ -77,11 +78,7 @@ export default class BuyBitcoin extends Component {
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 16 }}> <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 16 }}>
<BlueText>{loc.buyBitcoin.tap_your_address}</BlueText> <BlueText>{loc.buyBitcoin.tap_your_address}</BlueText>
<TouchableOpacity onPress={this.copyToClipboard}> <BlueCopyTextToClipboard text={this.state.addressText} />
<Animated.Text style={styles.address} numberOfLines={0}>
{this.state.addressText}
</Animated.Text>
</TouchableOpacity>
<BlueButton <BlueButton
icon={{ 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 = { BuyBitcoin.propTypes = {
navigation: PropTypes.shape({ navigation: PropTypes.shape({
goBack: PropTypes.function, goBack: PropTypes.function,

View File

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