mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-03-26 08:55:56 +01:00
REF: hd wallet classes
This commit is contained in:
parent
afae64a32c
commit
777c9e6de7
5 changed files with 111 additions and 187 deletions
|
@ -2,6 +2,8 @@ import { LegacyWallet } from './legacy-wallet';
|
||||||
import Frisbee from 'frisbee';
|
import Frisbee from 'frisbee';
|
||||||
import { WatchOnlyWallet } from './watch-only-wallet';
|
import { WatchOnlyWallet } from './watch-only-wallet';
|
||||||
const bip39 = require('bip39');
|
const bip39 = require('bip39');
|
||||||
|
const BigNumber = require('bignumber.js');
|
||||||
|
const bitcoin = require('bitcoinjs-lib');
|
||||||
|
|
||||||
export class AbstractHDWallet extends LegacyWallet {
|
export class AbstractHDWallet extends LegacyWallet {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -195,28 +197,6 @@ export class AbstractHDWallet extends LegacyWallet {
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
async fetchBalance() {
|
|
||||||
try {
|
|
||||||
const api = new Frisbee({ baseURI: 'https://blockchain.info' });
|
|
||||||
|
|
||||||
let response = await api.get('/balance?active=' + this.getXpub());
|
|
||||||
|
|
||||||
if (response && response.body) {
|
|
||||||
for (let xpub of Object.keys(response.body)) {
|
|
||||||
this.balance = response.body[xpub].final_balance / 100000000;
|
|
||||||
}
|
|
||||||
this._lastBalanceFetch = +new Date();
|
|
||||||
} else {
|
|
||||||
throw new Error('Could not fetch balance from API: ' + response.err);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Async function to fetch all transactions. Use getter to get actual txs.
|
* Async function to fetch all transactions. Use getter to get actual txs.
|
||||||
* Also, sets internals:
|
* Also, sets internals:
|
||||||
|
@ -365,4 +345,84 @@ export class AbstractHDWallet extends LegacyWallet {
|
||||||
createTx() {
|
createTx() {
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fetchBalance() {
|
||||||
|
try {
|
||||||
|
const api = new Frisbee({ baseURI: 'https://www.blockonomics.co' });
|
||||||
|
let response = await api.post('/api/balance', { body: JSON.stringify({ addr: this.getXpub() }) });
|
||||||
|
|
||||||
|
if (response && response.body && response.body.response) {
|
||||||
|
this.balance = 0;
|
||||||
|
this.unconfirmed_balance = 0;
|
||||||
|
this.usedAddresses = [];
|
||||||
|
for (let addr of response.body.response) {
|
||||||
|
this.balance += addr.confirmed;
|
||||||
|
this.unconfirmed_balance += addr.unconfirmed;
|
||||||
|
this.usedAddresses.push(addr.addr);
|
||||||
|
}
|
||||||
|
this.balance = new BigNumber(this.balance).dividedBy(100000000).toString() * 1;
|
||||||
|
this.unconfirmed_balance = new BigNumber(this.unconfirmed_balance).dividedBy(100000000).toString() * 1;
|
||||||
|
this._lastBalanceFetch = +new Date();
|
||||||
|
} else {
|
||||||
|
throw new Error('Could not fetch balance from API: ' + response.err);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
async fetchUtxo() {
|
||||||
|
const api = new Frisbee({
|
||||||
|
baseURI: 'https://blockchain.info',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.usedAddresses.length === 0) {
|
||||||
|
// just for any case, refresh balance (it refreshes internal `this.usedAddresses`)
|
||||||
|
await this.fetchBalance();
|
||||||
|
}
|
||||||
|
|
||||||
|
let addresses = this.usedAddresses.join('|');
|
||||||
|
addresses += '|' + this._getExternalAddressByIndex(this.next_free_address_index);
|
||||||
|
addresses += '|' + this._getInternalAddressByIndex(this.next_free_change_address_index);
|
||||||
|
|
||||||
|
let utxos = [];
|
||||||
|
|
||||||
|
let response;
|
||||||
|
try {
|
||||||
|
response = await api.get('/unspent?active=' + addresses + '&limit=1000');
|
||||||
|
// this endpoint does not support offset of some kind o_O
|
||||||
|
// so doing only one call
|
||||||
|
let json = response.body;
|
||||||
|
if (typeof json === 'undefined' || typeof json.unspent_outputs === 'undefined') {
|
||||||
|
throw new Error('Could not fetch UTXO from API ' + response.err);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let unspent of json.unspent_outputs) {
|
||||||
|
// a lil transform for signer module
|
||||||
|
unspent.txid = unspent.tx_hash_big_endian;
|
||||||
|
unspent.vout = unspent.tx_output_n;
|
||||||
|
unspent.amount = unspent.value;
|
||||||
|
|
||||||
|
let chunksIn = bitcoin.script.decompile(Buffer.from(unspent.script, 'hex'));
|
||||||
|
unspent.address = bitcoin.address.fromOutputScript(chunksIn);
|
||||||
|
utxos.push(unspent);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.utxo = utxos;
|
||||||
|
}
|
||||||
|
|
||||||
|
weOwnAddress(addr) {
|
||||||
|
let hashmap = {};
|
||||||
|
for (let a of this.usedAddresses) {
|
||||||
|
hashmap[a] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashmap[addr] === 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { AbstractHDWallet } from './abstract-hd-wallet';
|
import { AbstractHDWallet } from './abstract-hd-wallet';
|
||||||
|
import Frisbee from 'frisbee';
|
||||||
const bitcoin = require('bitcoinjs-lib');
|
const bitcoin = require('bitcoinjs-lib');
|
||||||
const bip39 = require('bip39');
|
const bip39 = require('bip39');
|
||||||
|
|
||||||
|
@ -80,4 +81,26 @@ export class HDLegacyBreadwalletWallet extends AbstractHDWallet {
|
||||||
let child = root.derivePath(path);
|
let child = root.derivePath(path);
|
||||||
return child.keyPair.toWIF();
|
return child.keyPair.toWIF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
async fetchBalance() {
|
||||||
|
try {
|
||||||
|
const api = new Frisbee({ baseURI: 'https://blockchain.info' });
|
||||||
|
|
||||||
|
let response = await api.get('/balance?active=' + this.getXpub());
|
||||||
|
|
||||||
|
if (response && response.body) {
|
||||||
|
for (let xpub of Object.keys(response.body)) {
|
||||||
|
this.balance = response.body[xpub].final_balance / 100000000;
|
||||||
|
}
|
||||||
|
this._lastBalanceFetch = +new Date();
|
||||||
|
} else {
|
||||||
|
throw new Error('Could not fetch balance from API: ' + response.err);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { LegacyWallet } from './';
|
import { LegacyWallet } from './';
|
||||||
import { AbstractHDWallet } from './abstract-hd-wallet';
|
import { AbstractHDWallet } from './abstract-hd-wallet';
|
||||||
import Frisbee from 'frisbee';
|
|
||||||
const bitcoin = require('bitcoinjs-lib');
|
const bitcoin = require('bitcoinjs-lib');
|
||||||
const bip39 = require('bip39');
|
const bip39 = require('bip39');
|
||||||
const BigNumber = require('bignumber.js');
|
const BigNumber = require('bignumber.js');
|
||||||
|
@ -107,87 +106,6 @@ export class HDLegacyP2PKHWallet extends AbstractHDWallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchBalance() {
|
|
||||||
try {
|
|
||||||
const api = new Frisbee({ baseURI: 'https://www.blockonomics.co' });
|
|
||||||
let response = await api.post('/api/balance', { body: JSON.stringify({ addr: this.getXpub() }) });
|
|
||||||
// console.log(response);
|
|
||||||
|
|
||||||
if (response && response.body && response.body.response) {
|
|
||||||
this.balance = 0;
|
|
||||||
this.unconfirmed_balance = 0;
|
|
||||||
this.usedAddresses = [];
|
|
||||||
for (let addr of response.body.response) {
|
|
||||||
this.balance += addr.confirmed;
|
|
||||||
this.unconfirmed_balance += addr.unconfirmed;
|
|
||||||
this.usedAddresses.push(addr.addr);
|
|
||||||
}
|
|
||||||
this.balance = new BigNumber(this.balance).dividedBy(100000000).toString() * 1;
|
|
||||||
this.unconfirmed_balance = new BigNumber(this.unconfirmed_balance).dividedBy(100000000).toString() * 1;
|
|
||||||
this._lastBalanceFetch = +new Date();
|
|
||||||
} else {
|
|
||||||
throw new Error('Could not fetch balance from API: ' + response.err);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
async fetchUtxo() {
|
|
||||||
const api = new Frisbee({
|
|
||||||
baseURI: 'https://blockchain.info',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.usedAddresses.length === 0) {
|
|
||||||
// just for any case, refresh balance (it refreshes internal `this.usedAddresses`)
|
|
||||||
await this.fetchBalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
let addresses = this.usedAddresses.join('|');
|
|
||||||
addresses += '|' + this._getExternalAddressByIndex(this.next_free_address_index);
|
|
||||||
addresses += '|' + this._getInternalAddressByIndex(this.next_free_change_address_index);
|
|
||||||
|
|
||||||
let utxos = [];
|
|
||||||
|
|
||||||
let response;
|
|
||||||
try {
|
|
||||||
response = await api.get('/unspent?active=' + addresses + '&limit=1000');
|
|
||||||
// this endpoint does not support offset of some kind o_O
|
|
||||||
// so doing only one call
|
|
||||||
let json = response.body;
|
|
||||||
if (typeof json === 'undefined' || typeof json.unspent_outputs === 'undefined') {
|
|
||||||
throw new Error('Could not fetch UTXO from API ' + response.err);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let unspent of json.unspent_outputs) {
|
|
||||||
// a lil transform for signer module
|
|
||||||
unspent.txid = unspent.tx_hash_big_endian;
|
|
||||||
unspent.vout = unspent.tx_output_n;
|
|
||||||
unspent.amount = unspent.value;
|
|
||||||
|
|
||||||
let chunksIn = bitcoin.script.decompile(Buffer.from(unspent.script, 'hex'));
|
|
||||||
unspent.address = bitcoin.address.fromOutputScript(chunksIn);
|
|
||||||
utxos.push(unspent);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.utxo = utxos;
|
|
||||||
}
|
|
||||||
|
|
||||||
weOwnAddress(addr) {
|
|
||||||
let hashmap = {};
|
|
||||||
for (let a of this.usedAddresses) {
|
|
||||||
hashmap[a] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hashmap[addr] === 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
createTx(utxos, amount, fee, address) {
|
createTx(utxos, amount, fee, address) {
|
||||||
for (let utxo of utxos) {
|
for (let utxo of utxos) {
|
||||||
utxo.wif = this._getWifForAddress(utxo.address);
|
utxo.wif = this._getWifForAddress(utxo.address);
|
||||||
|
|
|
@ -50,32 +50,6 @@ export class HDSegwitP2SHWallet extends AbstractHDWallet {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchBalance() {
|
|
||||||
try {
|
|
||||||
const api = new Frisbee({ baseURI: 'https://www.blockonomics.co' });
|
|
||||||
let response = await api.post('/api/balance', { body: JSON.stringify({ addr: this.getXpub() }) });
|
|
||||||
// console.log(response);
|
|
||||||
|
|
||||||
if (response && response.body && response.body.response) {
|
|
||||||
this.balance = 0;
|
|
||||||
this.unconfirmed_balance = 0;
|
|
||||||
this.usedAddresses = [];
|
|
||||||
for (let addr of response.body.response) {
|
|
||||||
this.balance += addr.confirmed;
|
|
||||||
this.unconfirmed_balance += addr.unconfirmed;
|
|
||||||
this.usedAddresses.push(addr.addr);
|
|
||||||
}
|
|
||||||
this.balance = new BigNumber(this.balance).dividedBy(100000000).toString() * 1;
|
|
||||||
this.unconfirmed_balance = new BigNumber(this.unconfirmed_balance).dividedBy(100000000).toString() * 1;
|
|
||||||
this._lastBalanceFetch = +new Date();
|
|
||||||
} else {
|
|
||||||
throw new Error('Could not fetch balance from API: ' + response.err);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_getExternalWIFByIndex(index) {
|
_getExternalWIFByIndex(index) {
|
||||||
index = index * 1; // cast to int
|
index = index * 1; // cast to int
|
||||||
let mnemonic = this.secret;
|
let mnemonic = this.secret;
|
||||||
|
@ -290,61 +264,6 @@ export class HDSegwitP2SHWallet extends AbstractHDWallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
async fetchUtxo() {
|
|
||||||
const api = new Frisbee({
|
|
||||||
baseURI: 'https://blockchain.info',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.usedAddresses.length === 0) {
|
|
||||||
// just for any case, refresh balance (it refreshes internal `this.usedAddresses`)
|
|
||||||
await this.fetchBalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
let addresses = this.usedAddresses.join('|');
|
|
||||||
addresses += '|' + this._getExternalAddressByIndex(this.next_free_address_index);
|
|
||||||
addresses += '|' + this._getInternalAddressByIndex(this.next_free_change_address_index);
|
|
||||||
|
|
||||||
let utxos = [];
|
|
||||||
|
|
||||||
let response;
|
|
||||||
try {
|
|
||||||
response = await api.get('/unspent?active=' + addresses + '&limit=1000');
|
|
||||||
// this endpoint does not support offset of some kind o_O
|
|
||||||
// so doing only one call
|
|
||||||
let json = response.body;
|
|
||||||
if (typeof json === 'undefined' || typeof json.unspent_outputs === 'undefined') {
|
|
||||||
throw new Error('Could not fetch UTXO from API ' + response.err);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let unspent of json.unspent_outputs) {
|
|
||||||
// a lil transform for signer module
|
|
||||||
unspent.txid = unspent.tx_hash_big_endian;
|
|
||||||
unspent.vout = unspent.tx_output_n;
|
|
||||||
unspent.amount = unspent.value;
|
|
||||||
|
|
||||||
let chunksIn = bitcoin.script.decompile(Buffer.from(unspent.script, 'hex'));
|
|
||||||
unspent.address = bitcoin.address.fromOutputScript(chunksIn);
|
|
||||||
utxos.push(unspent);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.utxo = utxos;
|
|
||||||
}
|
|
||||||
|
|
||||||
weOwnAddress(addr) {
|
|
||||||
let hashmap = {};
|
|
||||||
for (let a of this.usedAddresses) {
|
|
||||||
hashmap[a] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hashmap[addr] === 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
createTx(utxos, amount, fee, address) {
|
createTx(utxos, amount, fee, address) {
|
||||||
for (let utxo of utxos) {
|
for (let utxo of utxos) {
|
||||||
utxo.wif = this._getWifForAddress(utxo.address);
|
utxo.wif = this._getWifForAddress(utxo.address);
|
||||||
|
|
|
@ -19,7 +19,7 @@ import Modal from 'react-native-modal';
|
||||||
import NetworkTransactionFees, { NetworkTransactionFee } from '../../models/networkTransactionFees';
|
import NetworkTransactionFees, { NetworkTransactionFee } from '../../models/networkTransactionFees';
|
||||||
import BitcoinBIP70TransactionDecode from '../../bip70/bip70';
|
import BitcoinBIP70TransactionDecode from '../../bip70/bip70';
|
||||||
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
||||||
import { HDSegwitP2SHWallet } from '../../class';
|
import { HDLegacyP2PKHWallet, HDSegwitP2SHWallet } from '../../class';
|
||||||
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
||||||
const bip21 = require('bip21');
|
const bip21 = require('bip21');
|
||||||
let EV = require('../../events');
|
let EV = require('../../events');
|
||||||
|
@ -304,7 +304,11 @@ export default class SendDetails extends Component {
|
||||||
this.props.navigation.navigate('Confirm', {
|
this.props.navigation.navigate('Confirm', {
|
||||||
amount: this.state.amount,
|
amount: this.state.amount,
|
||||||
// HD wallet's utxo is in sats, classic segwit wallet utxos are in btc
|
// HD wallet's utxo is in sats, classic segwit wallet utxos are in btc
|
||||||
fee: this.calculateFee(utxo, tx, this.state.fromWallet.type === new HDSegwitP2SHWallet().type),
|
fee: this.calculateFee(
|
||||||
|
utxo,
|
||||||
|
tx,
|
||||||
|
this.state.fromWallet.type === new HDSegwitP2SHWallet().type || this.state.fromWallet.type === new HDLegacyP2PKHWallet().type,
|
||||||
|
),
|
||||||
address: this.state.address,
|
address: this.state.address,
|
||||||
memo: this.state.memo,
|
memo: this.state.memo,
|
||||||
fromWallet: this.state.fromWallet,
|
fromWallet: this.state.fromWallet,
|
||||||
|
|
Loading…
Add table
Reference in a new issue