REF: hd wallet classes

This commit is contained in:
Overtorment 2018-12-22 02:46:35 +00:00
parent afae64a32c
commit 777c9e6de7
5 changed files with 111 additions and 187 deletions

View File

@ -2,6 +2,8 @@ import { LegacyWallet } from './legacy-wallet';
import Frisbee from 'frisbee';
import { WatchOnlyWallet } from './watch-only-wallet';
const bip39 = require('bip39');
const BigNumber = require('bignumber.js');
const bitcoin = require('bitcoinjs-lib');
export class AbstractHDWallet extends LegacyWallet {
constructor() {
@ -195,28 +197,6 @@ export class AbstractHDWallet extends LegacyWallet {
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.
* Also, sets internals:
@ -365,4 +345,84 @@ export class AbstractHDWallet extends LegacyWallet {
createTx() {
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;
}
}

View File

@ -1,4 +1,5 @@
import { AbstractHDWallet } from './abstract-hd-wallet';
import Frisbee from 'frisbee';
const bitcoin = require('bitcoinjs-lib');
const bip39 = require('bip39');
@ -80,4 +81,26 @@ export class HDLegacyBreadwalletWallet extends AbstractHDWallet {
let child = root.derivePath(path);
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);
}
}
}

View File

@ -1,6 +1,5 @@
import { LegacyWallet } from './';
import { AbstractHDWallet } from './abstract-hd-wallet';
import Frisbee from 'frisbee';
const bitcoin = require('bitcoinjs-lib');
const bip39 = require('bip39');
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) {
for (let utxo of utxos) {
utxo.wif = this._getWifForAddress(utxo.address);

View File

@ -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) {
index = index * 1; // cast to int
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) {
for (let utxo of utxos) {
utxo.wif = this._getWifForAddress(utxo.address);

View File

@ -19,7 +19,7 @@ import Modal from 'react-native-modal';
import NetworkTransactionFees, { NetworkTransactionFee } from '../../models/networkTransactionFees';
import BitcoinBIP70TransactionDecode from '../../bip70/bip70';
import { BitcoinUnit } from '../../models/bitcoinUnits';
import { HDSegwitP2SHWallet } from '../../class';
import { HDLegacyP2PKHWallet, HDSegwitP2SHWallet } from '../../class';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
const bip21 = require('bip21');
let EV = require('../../events');
@ -304,7 +304,11 @@ export default class SendDetails extends Component {
this.props.navigation.navigate('Confirm', {
amount: this.state.amount,
// 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,
memo: this.state.memo,
fromWallet: this.state.fromWallet,