mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-22 06:52:41 +01:00
Merge branch 'experimental' of github.com:BlueWallet/BlueWallet into experimental
# Conflicts: # android/app/app.iml # android/app/build.gradle # android/app/src/main/AndroidManifest.xml # android/app/src/main/java/io/bluewallet/bluewallet/MainApplication.java # android/gradle/wrapper/gradle-wrapper.properties # android/settings.gradle # ios/BlueWallet.xcodeproj/project.pbxproj # ios/BlueWallet/Info.plist # package-lock.json # package.json
This commit is contained in:
commit
3c603b6543
24 changed files with 897 additions and 587 deletions
46
App.test.js
46
App.test.js
|
@ -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);
|
||||
});
|
||||
|
|
16
App2.test.js
16
App2.test.js
|
@ -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 () => {
|
||||
|
|
|
@ -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 (
|
||||
|
|
144
HDWallet.test.js
144
HDWallet.test.js
|
@ -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', () => {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -102,7 +102,7 @@ android {
|
|||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "3.6.2"
|
||||
versionName "3.6.3"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = "27.0.3"
|
||||
buildToolsVersion = "28.0.3"
|
||||
minSdkVersion = 16
|
||||
compileSdkVersion = 27
|
||||
targetSdkVersion = 26
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.6.2</string>
|
||||
<string>3.6.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
@ -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'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>
|
||||
|
|
52
loc/hr_HR.js
52
loc/hr_HR.js
|
@ -4,8 +4,8 @@ module.exports = {
|
|||
enter_password: 'Unesi lozinku',
|
||||
bad_password: 'Kriva lozinka, pokušaj ponovo',
|
||||
never: 'nikad',
|
||||
continue: 'Continue',
|
||||
ok: 'OK',
|
||||
continue: 'Nastavi',
|
||||
ok: 'U redu',
|
||||
},
|
||||
wallets: {
|
||||
select_wallet: 'Odaberi volet',
|
||||
|
@ -13,7 +13,7 @@ module.exports = {
|
|||
list: {
|
||||
app_name: 'Blue Wallet',
|
||||
title: 'Voleti',
|
||||
header: 'Volet je par privatnog ključa (tajna!) i javne adrese' + 'koju slobodno možete dijeliti kada primate novce.',
|
||||
header: 'Volet je par privatnog ključa (tajna!) i javne adrese ' + 'koju slobodno možete dijeliti kada primate novce.',
|
||||
add: 'Dodaj volet',
|
||||
create_a_wallet: 'Stvori novi volet',
|
||||
create_a_wallet1: 'Ne košta ništa i možete',
|
||||
|
@ -33,10 +33,10 @@ module.exports = {
|
|||
create: 'Stvori',
|
||||
label_new_segwit: 'Novi SegWit',
|
||||
label_new_lightning: 'Novi Lightning',
|
||||
wallet_name: 'ime voleta',
|
||||
wallet_type: 'tip',
|
||||
wallet_name: 'ime voleta:',
|
||||
wallet_type: 'tip:',
|
||||
or: 'ili',
|
||||
import_wallet: 'Unesi volet',
|
||||
import_wallet: 'Unesi vanjski volet',
|
||||
imported: 'Unešeno',
|
||||
coming_soon: 'Dolazi uskoro',
|
||||
lightning: 'Lightning',
|
||||
|
@ -53,10 +53,10 @@ module.exports = {
|
|||
yes_delete: 'Da, briši',
|
||||
no_cancel: 'Ne, otiaži',
|
||||
delete: 'Obriši',
|
||||
save: 'Pohrani',
|
||||
save: 'Spremi',
|
||||
delete_this_wallet: 'Obriši ovaj volet',
|
||||
export_backup: 'Izvoz / bekap',
|
||||
buy_bitcoin: 'Kupi Bitcoin',
|
||||
buy_bitcoin: 'Kupovina Bitcoina',
|
||||
show_xpub: 'Prikaži voletov XPUB',
|
||||
},
|
||||
export: {
|
||||
|
@ -147,22 +147,22 @@ module.exports = {
|
|||
satoshi_per_byte: 'Satoshi / byte',
|
||||
memo: 'Bilješka',
|
||||
broadcast: 'Objavi',
|
||||
not_enough_fee: 'Trošak slanja je premal. Povećaj ga.',
|
||||
not_enough_fee: 'Trošak slanja je premalen. Povećaj ga.',
|
||||
},
|
||||
},
|
||||
receive: {
|
||||
header: 'Primanje',
|
||||
header: 'Primi',
|
||||
details: {
|
||||
title: 'Pokaži ovu adresu platitelju',
|
||||
share: 'pokaži',
|
||||
share: 'podijeli',
|
||||
copiedToClipboard: 'Kopirano u međuspremnik.',
|
||||
label: 'Opis',
|
||||
create: 'Create',
|
||||
create: 'Stvori',
|
||||
setAmount: 'Odredi iznos za primiti',
|
||||
},
|
||||
},
|
||||
buyBitcoin: {
|
||||
header: 'Kupi Bitcoin',
|
||||
header: 'Kupovina Bitcoina',
|
||||
tap_your_address: 'Klikni na adresu za spremanje u međuspremnik:',
|
||||
copied: 'Spremljeno u međuspremnik!',
|
||||
},
|
||||
|
@ -176,26 +176,26 @@ module.exports = {
|
|||
retype_password: 'Ponovi lozinku',
|
||||
passwords_do_not_match: 'Lozinke su različite',
|
||||
encrypt_storage: 'Kriptiraj spremnik',
|
||||
lightning_settings: 'Lightning settings',
|
||||
lightning_settings: 'Lightning postavke',
|
||||
lightning_settings_explain:
|
||||
'To connect to your own LND node please install LndHub' +
|
||||
' and put its URL here in settings. Leave blank to use default ' +
|
||||
'Za spajanje na tvoj vlastiti LND čvor trebaš instalirati LndHub' +
|
||||
' i upisati njegov URL ovdje. Ostavi prazno za standardni ' +
|
||||
'ndHub\n (lndhub.io)',
|
||||
save: 'save',
|
||||
about: 'Iznos',
|
||||
save: 'Spremi',
|
||||
about: 'Informacije',
|
||||
language: 'Jezik',
|
||||
currency: 'Valuta',
|
||||
},
|
||||
plausibledeniability: {
|
||||
title: 'Fejk volet',
|
||||
help:
|
||||
'U iznimnim okolnostima netko gadan (pa još ako drži oklagiju) te' +
|
||||
'može neljubazno pritisnuti da mu otkriješ lozinku za ovaj volet.' +
|
||||
'BlueWallet ti čuva leđa buraz. Nemaš brige. Gledaj.' +
|
||||
'Stvoriti ćemo dupli volet sa drugačijom lozinkom. Haha, žišku?' +
|
||||
'Pa kad se ovaj počne pjeniti a ti vidiš da je vrag odnio šalu' +
|
||||
'ti mu podvali ovaj drugi volet. Eto mu ga. Nek si cucla.',
|
||||
help2: 'Novi spremnik će biti posve funkcionalan, možeš pohraniti koliko' + 'misliš da je potrebno da izgleda uvjerljivo.',
|
||||
'Pazi. Netko gadan te može u iznimnim okolnostima (pljačka, prijevremeni izbori, itd.) ' +
|
||||
'brutalno pritisnuti da mu otkriješ lozinku za svoj volet. ' +
|
||||
'BlueWallet ti čuva leđa buraz. Nemaš brige. Gledaj, ' +
|
||||
'stvoriti ćemo fejk volet sa drugačijom lozinkom. Haha, žišku? ' +
|
||||
'Pa kad se ovaj počne pjeniti, a ti vidiš da je vrag odnio šalu, ' +
|
||||
'samo mu podvali lozinku za ovaj drugi volet. Eto mu ga. Nek si cucla. ',
|
||||
help2: 'Novi spremnik će biti posve funkcionalan, možeš pohraniti koliko ' + 'misliš da je potrebno da izgleda uvjerljivo.',
|
||||
create_fake_storage: 'Stvori fejk enkriptirani spremnik',
|
||||
go_back: 'Povratak',
|
||||
create_password: 'Unesi lozinku',
|
||||
|
@ -212,6 +212,6 @@ module.exports = {
|
|||
refill: 'Dopuni',
|
||||
withdraw: 'Isprazni',
|
||||
expired: 'Isteklo',
|
||||
sameWalletAsInvoiceError: 'Ne možeš platiti račun s istim voletom s kojim si račun stvorio, ono.',
|
||||
sameWalletAsInvoiceError: 'Buraz! Ne možeš platiti račun s istim voletom s kojim si račun stvorio, ono.',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export const FiatUnit = Object.freeze({
|
||||
USD: { endPointKey: 'USD', symbol: '$', locale: 'en-US' },
|
||||
AUD: { endPointKey: 'AUD', symbol: '$', locale: 'en-AU' },
|
||||
BRL: { endPointKey: 'BRL', symbol: 'R$', locale: 'pt-BR' },
|
||||
CAD: { endPointKey: 'CAD', symbol: '$', locale: 'en-CA' },
|
||||
CZK: { endPointKey: 'CZK', symbol: 'Kč', locale: 'cs-CZ' },
|
||||
CNY: { endPointKey: 'CNY', symbol: '¥', locale: 'zh-CN' },
|
||||
|
@ -9,6 +10,7 @@ export const FiatUnit = Object.freeze({
|
|||
HRK: { endPointKey: 'HRK', symbol: 'HRK', locale: 'hr-HR' },
|
||||
INR: { endPointKey: 'INR', symbol: '₹', locale: 'hi-HN' },
|
||||
JPY: { endPointKey: 'JPY', symbol: '¥', locale: 'ja-JP' },
|
||||
MXN: { endPointKey: 'MXN', symbol: '$', locale: 'es-MX' },
|
||||
PLN: { endPointKey: 'PLN', symbol: 'zł', locale: 'pl-PL' },
|
||||
RUB: { endPointKey: 'RUB', symbol: '₽', locale: 'ru-RU' },
|
||||
SGD: { endPointKey: 'SGD', symbol: 'S$', locale: 'zh-SG' },
|
||||
|
|
812
package-lock.json
generated
812
package-lock.json
generated
File diff suppressed because it is too large
Load diff
33
package.json
33
package.json
|
@ -1,17 +1,17 @@
|
|||
{
|
||||
"name": "BlueWallet",
|
||||
"version": "3.6.2",
|
||||
"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": {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -85,6 +85,12 @@ export default class ScanLndInvoice extends React.Component {
|
|||
return this.props.navigation.goBack();
|
||||
}
|
||||
|
||||
// handling BIP21 w/BOLT11 support
|
||||
let ind = data.indexOf('lightning=');
|
||||
if (ind !== -1) {
|
||||
data = data.substring(ind + 10).split('&')[0];
|
||||
}
|
||||
|
||||
data = data.replace('LIGHTNING:', '').replace('lightning:', '');
|
||||
console.log(data);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
});
|
||||
|
|
|
@ -109,7 +109,7 @@ export default class About extends Component {
|
|||
};
|
||||
Rate.rate(options, success => {
|
||||
if (success) {
|
||||
console.warn('User Rated.');
|
||||
console.log('User Rated.');
|
||||
}
|
||||
});
|
||||
}}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
Loading…
Add table
Reference in a new issue