You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

187 lines
4.6 KiB

/*!
* lib/wallet/hd-account-info.js
* Copyright © 2019 – Katana Cryptographic Ltd. All Rights Reserved.
*/
'use strict'
const errors = require('../errors')
const db = require('../db/mysql-db-wrapper')
const hdaHelper = require('../bitcoin/hd-accounts-helper')
const hdaService = require('../bitcoin/hd-accounts-service')
const rpcLatestBlock = require('../bitcoind-rpc/latest-block')
/**
* A class storing information about the actibity of a hd account
*/
class HdAccountInfo {
/**
* Constructor
* @param {object} xpub - xpub
*/
constructor(xpub) {
// Initializes properties
this.xpub = xpub
this.address = xpub
this.account = 0
this.depth = 0
this.finalBalance = 0
this.accountIndex = 0
this.changeIndex = 0
this.accountDerivedIndex = 0
this.changeDerivedIndex = 0
this.nTx = 0
this.unspentOutputs = []
this.derivation = null
this.created = null
this.tracked = false
}
/**
* Ensure the hd account exists in database
* Otherwise, tries to import it with BIP44 derivation
* @returns {Promise - integer} return the internal id of the hd account
* or null if it doesn't exist
*/
async ensureHdAccount() {
try {
const id = await db.getHDAccountId(this.xpub)
return id
} catch(e) {
if (e == errors.db.ERROR_NO_HD_ACCOUNT) {
try {
// Default to BIP44 import
return hdaService.restoreHdAccount(this.xpub, hdaHelper.BIP44)
} catch(e) {
return null
}
}
return null
}
}
/**
* Load information about the hd account
* @returns {Promise}
*/
async loadInfo() {
try {
const id = await db.getHDAccountId(this.xpub)
//if (id == null) return false
const account = await db.getHDAccount(this.xpub)
this.created = account.hdCreated
this.derivation = hdaHelper.typeString(account.hdType)
this.tracked = true
this.finalBalance = await db.getHDAccountBalance(this.xpub)
const unusedIdx = await db.getHDAccountNextUnusedIndices(this.xpub)
this.accountIndex = unusedIdx[0]
this.changeIndex = unusedIdx[1]
const derivedIdx = await db.getHDAccountDerivedIndices(this.xpub)
this.accountDerivedIndex = derivedIdx[0]
this.changeDerivedIndex = derivedIdx[1]
this.nTx = await db.getHDAccountNbTransactions(this.xpub)
const node = hdaHelper.getNode(this.xpub)
const index = node[2].index
const threshold = Math.pow(2,31)
const hardened = (index >= threshold)
this.account = hardened ? (index - threshold) : index
this.depth = node[2].depth
return true
} catch(e) {
return false
}
}
/**
* Load the utxos associated to the hd account
* @returns {Promise - object[]}
*/
async loadUtxos() {
this.unspentOutputs = []
const utxos = await db.getHDAccountUnspentOutputs(this.xpub)
for (let utxo of utxos) {
const conf =
(utxo.blockHeight == null)
? 0
: (rpcLatestBlock.height - utxo.blockHeight + 1)
const entry = {
tx_hash: utxo.txnTxid,
tx_output_n: utxo.outIndex,
tx_version: utxo.txnVersion,
tx_locktime: utxo.txnLocktime,
value: utxo.outAmount,
script: utxo.outScript,
addr: utxo.addrAddress,
confirmations: conf,
xpub: {
m: this.xpub,
path: ['M', utxo.hdAddrChain, utxo.hdAddrIndex].join('/')
}
}
this.unspentOutputs.push(entry)
}
// Order the utxos
this.unspentOutputs.sort((a,b) => b.confirmations - a.confirmations)
return this.unspentOutputs
}
/**
* Return a plain old js object with hd account properties
* @returns {object}
*/
toPojo() {
return {
address: this.address,
final_balance: this.finalBalance,
account_index: this.accountIndex,
change_index: this.changeIndex,
n_tx: this.nTx,
derivation: this.derivation,
created: this.created
}
}
/**
* Return a plain old js object with hd account properties
* (extended version)
* @returns {object}
*/
toPojoExtended() {
return {
xpub: this.xpub,
tracked: this.tracked,
balance: this.finalBalance,
unused: {
external: this.accountIndex,
internal: this.changeIndex,
},
derived: {
external: this.accountDerivedIndex,
internal: this.changeDerivedIndex,
},
n_tx: this.nTx,
derivation: this.derivation,
account: this.account,
depth: this.depth,
created: (new Date(this.created * 1000)).toGMTString()
}
}
}
module.exports = HdAccountInfo