Browse Source

ADD: refill lightning wallet with bank card

receivehooks
Overtorment 5 years ago
parent
commit
4baa1f38a6
  1. 4
      class/abstract-hd-wallet.js
  2. 3
      class/lightning-custodian-wallet.js
  3. 18
      class/watch-only-wallet.js
  4. 66
      screen/wallets/buyBitcoin.js
  5. 3
      screen/wallets/details.js
  6. 16
      screen/wallets/transactions.js
  7. 3
      tests/integration/hd-segwit-bech32-wallet.test.js
  8. 4
      tests/integration/hd-segwit-p2sh-wallet.test.js

4
class/abstract-hd-wallet.js

@ -23,6 +23,10 @@ export class AbstractHDWallet extends LegacyWallet {
this.gap_limit = 20;
}
getNextFreeAddressIndex() {
return this.next_free_address_index;
}
prepareForSerialization() {
// deleting structures that cant be serialized
delete this._node0;

3
class/lightning-custodian-wallet.js

@ -368,7 +368,8 @@ export class LightningCustodianWallet extends LegacyWallet {
}
async getAddressAsync() {
return this.fetchBtcAddress();
await this.fetchBtcAddress();
return this.getAddress();
}
async allowOnchainAddress() {

18
class/watch-only-wallet.js

@ -35,7 +35,9 @@ export class WatchOnlyWallet extends LegacyWallet {
}
getAddress() {
return this.secret;
if (this.isAddressValid(this.secret)) return this.secret; // handling case when there is an XPUB there
if (this._hdWalletInstance) throw new Error('Should not be used in watch-only HD wallets');
throw new Error('Not initialized');
}
createTx(utxos, amount, fee, toAddress, memo) {
@ -119,6 +121,11 @@ export class WatchOnlyWallet extends LegacyWallet {
throw new Error('Not initialized');
}
getNextFreeAddressIndex() {
if (this._hdWalletInstance) return this._hdWalletInstance.next_free_address_index;
throw new Error('Not initialized');
}
async getChangeAddressAsync() {
if (this._hdWalletInstance) return this._hdWalletInstance.getChangeAddressAsync();
throw new Error('Not initialized');
@ -183,6 +190,15 @@ export class WatchOnlyWallet extends LegacyWallet {
return this.secret.startsWith('xpub') || this.secret.startsWith('ypub') || this.secret.startsWith('zpub');
}
weOwnAddress(address) {
if (this.isHd()) {
if (this._hdWalletInstance) return this._hdWalletInstance.weOwnAddress(address);
throw new Error('Not initialized');
}
return this.getAddress() === address;
}
allowHodlHodlTrading() {
return this.isHd();
}

66
screen/wallets/buyBitcoin.js

@ -2,8 +2,8 @@ import React, { Component } from 'react';
import { BlueNavigationStyle, BlueLoading } from '../../BlueComponents';
import PropTypes from 'prop-types';
import { WebView } from 'react-native-webview';
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
import { AppStorage, LightningCustodianWallet, WatchOnlyWallet } from '../../class';
let BlueApp: AppStorage = require('../../BlueApp');
let loc = require('../../loc');
export default class BuyBitcoin extends Component {
@ -15,47 +15,54 @@ export default class BuyBitcoin extends Component {
constructor(props) {
super(props);
let address = props.navigation.state.params.address;
let secret = props.navigation.state.params.secret;
let wallet = props.navigation.state.params.wallet;
this.state = {
isLoading: true,
address: address,
secret: secret,
addressText: '',
wallet,
address: '',
};
}
async componentDidMount() {
console.log('buyBitcoin - componentDidMount');
/** @type {AbstractWallet} */
let wallet;
let address = this.state.address;
for (let w of BlueApp.getWallets()) {
if ((address && w.getAddress() === this.state.address) || w.getSecret() === this.state.secret) {
// found our wallet
wallet = w;
}
}
/** @type {AbstractHDWallet|WatchOnlyWallet|LightningCustodianWallet} */
let wallet = this.state.wallet;
let address = '';
if (wallet && wallet.getAddressAsync) {
setTimeout(async () => {
address = await wallet.getAddressAsync();
BlueApp.saveToDisk(); // caching whatever getAddressAsync() generated internally
this.setState({
address: address,
addressText: address,
isLoading: false,
});
}, 1);
} else {
if (WatchOnlyWallet.type === wallet.type && !wallet.isHd()) {
// plain watchonly - just get the address
address = wallet.getAddress();
this.setState({
isLoading: false,
address,
addressText: address,
});
return;
}
// otherwise, lets call widely-used getAddressAsync()
try {
address = await Promise.race([wallet.getAddressAsync(), BlueApp.sleep(2000)]);
} catch (_) {}
if (!address) {
// either sleep expired or getAddressAsync threw an exception
if (LightningCustodianWallet.type === wallet.type) {
// not much we can do, lets hope refill address was cached previously
address = wallet.getAddress() || '';
} else {
// plain hd wallet (either HD or watchonly-wrapped). trying next free address
address = wallet._getExternalAddressByIndex(wallet.getNextFreeAddressIndex());
}
}
this.setState({
isLoading: false,
address,
});
}
render() {
@ -86,8 +93,7 @@ BuyBitcoin.propTypes = {
goBack: PropTypes.func,
state: PropTypes.shape({
params: PropTypes.shape({
address: PropTypes.string,
secret: PropTypes.string,
wallet: PropTypes.object,
safelloStateToken: PropTypes.string,
}),
}),

3
screen/wallets/details.js

@ -253,8 +253,7 @@ export default class WalletDetails extends Component {
}}
onPress={() =>
this.props.navigation.navigate('BuyBitcoin', {
address: this.state.wallet.getAddress(),
secret: this.state.wallet.getSecret(),
wallet: this.state.wallet,
})
}
title={loc.wallets.details.buy_bitcoin}

16
screen/wallets/transactions.js

@ -288,6 +288,19 @@ export default class WalletTransactions extends Component {
title={'Refill with External Wallet'}
/>
<BlueListItem
hideChevron
component={TouchableOpacity}
onPress={a => {
this.setState({ isManageFundsModalVisible: false }, async () => {
this.props.navigation.navigate('BuyBitcoin', {
wallet: this.state.wallet,
});
});
}}
title={'Refill with bank card'}
/>
<BlueListItem
title={loc.lnd.withdraw}
hideChevron
@ -650,8 +663,7 @@ export default class WalletTransactions extends Component {
}}
onPress={() =>
this.props.navigation.navigate('BuyBitcoin', {
address: this.state.wallet.getAddress(),
secret: this.state.wallet.getSecret(),
wallet: this.state.wallet,
})
}
>

3
tests/integration/hd-segwit-bech32-wallet.test.js

@ -49,6 +49,7 @@ describe('Bech32 Segwit HD (BIP84)', () => {
assert.strictEqual(await hd.getAddressAsync(), hd._getExternalAddressByIndex(2));
assert.strictEqual(await hd.getChangeAddressAsync(), hd._getInternalAddressByIndex(2));
assert.strictEqual(hd.next_free_address_index, 2);
assert.strictEqual(hd.getNextFreeAddressIndex(), 2);
assert.strictEqual(hd.next_free_change_address_index, 2);
// now fetch txs
@ -81,6 +82,7 @@ describe('Bech32 Segwit HD (BIP84)', () => {
assert.strictEqual(await hd.getAddressAsync(), hd._getExternalAddressByIndex(2));
assert.strictEqual(await hd.getChangeAddressAsync(), hd._getInternalAddressByIndex(2));
assert.strictEqual(hd.next_free_address_index, 2);
assert.strictEqual(hd.getNextFreeAddressIndex(), 2);
assert.strictEqual(hd.next_free_change_address_index, 2);
});
@ -153,6 +155,7 @@ describe('Bech32 Segwit HD (BIP84)', () => {
assert.ok(hd.next_free_change_address_index > 0);
assert.ok(hd.next_free_address_index > 0);
assert.ok(hd.getNextFreeAddressIndex() > 0);
start = +new Date();
await hd.fetchTransactions();

4
tests/integration/hd-segwit-p2sh-wallet.test.js

@ -187,6 +187,7 @@ it('can create a Legacy HD (BIP44)', async function() {
assert.ok(hd._lastTxFetch > 0);
assert.strictEqual(hd.getTransactions().length, 4);
assert.strictEqual(hd.next_free_address_index, 1);
assert.strictEqual(hd.getNextFreeAddressIndex(), 1);
assert.strictEqual(hd.next_free_change_address_index, 1);
for (let tx of hd.getTransactions()) {
@ -196,6 +197,7 @@ 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.strictEqual(hd._getExternalAddressByIndex(hd.next_free_address_index), freeAddress);
assert.strictEqual(hd._getExternalAddressByIndex(hd.getNextFreeAddressIndex()), freeAddress);
});
it('Legacy HD (BIP44) can create TX', async () => {
@ -257,9 +259,11 @@ it('HD breadwallet works', async function() {
assert.strictEqual(hdBread.getBalance(), 123456);
assert.strictEqual(hdBread.next_free_address_index, 11);
assert.strictEqual(hdBread.getNextFreeAddressIndex(), 11);
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.strictEqual(hdBread._getExternalAddressByIndex(hdBread.next_free_address_index), freeAddress);
assert.strictEqual(hdBread._getExternalAddressByIndex(hdBread.getNextFreeAddressIndex()), freeAddress);
});

Loading…
Cancel
Save