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
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
|
|
|