module . exports = ( shepherd ) => {
shepherd . listunspent = ( ecl , address , network , full , verify ) => {
let _ atLeastOneDecodeTxFailed = false ;
if ( full ) {
return new shepherd . Promise ( ( resolve , reject ) => {
ecl . connect ( ) ;
ecl . blockchainAddressListunspent ( address )
. then ( ( _ utxoJSON ) => {
if ( _ utxoJSON &&
_ utxoJSON . length ) {
let formattedUtxoList = [ ] ;
let _ utxo = [ ] ;
ecl . blockchainNumblocksSubscribe ( )
. then ( ( currentHeight ) => {
if ( currentHeight &&
Number ( currentHeight ) > 0 ) {
// filter out unconfirmed utxos
for ( let i = 0 ; i < _ utxoJSON . length ; i ++ ) {
if ( Number ( currentHeight ) - Number ( _ utxoJSON [ i ] . height ) !== 0 ) {
_ utxo . push ( _ utxoJSON [ i ] ) ;
}
}
if ( ! _ utxo . length ) { // no confirmed utxo
resolve ( 'no valid utxo' ) ;
} else {
shepherd . Promise . all ( _ utxo . map ( ( _ utxoItem , index ) => {
return new shepherd . Promise ( ( resolve , reject ) => {
ecl . blockchainTransactionGet ( _ utxoItem [ 'tx_hash' ] )
. then ( ( _ rawtxJSON ) => {
shepherd . log ( 'electrum gettransaction ==>' , true ) ;
shepherd . log ( index + ' | ' + ( _ rawtxJSON . length - 1 ) , true ) ;
shepherd . log ( _ rawtxJSON , true ) ;
// decode tx
const _ network = shepherd . getNetworkData ( network ) ;
const decodedTx = shepherd . electrumJSTxDecoder ( _ rawtxJSON , network , _ network ) ;
shepherd . log ( 'decoded tx =>' , true ) ;
shepherd . log ( decodedTx , true ) ;
if ( ! decodedTx ) {
_ atLeastOneDecodeTxFailed = true ;
resolve ( 'cant decode tx' ) ;
} else {
if ( network === 'komodo' ) {
let interest = 0 ;
if ( Number ( _ utxoItem . value ) * 0.00000001 >= 10 &&
decodedTx . format . locktime > 0 ) {
interest = shepherd . kmdCalcInterest ( decodedTx . format . locktime , _ utxoItem . value ) ;
}
let _ resolveObj = {
txid : _ utxoItem [ 'tx_hash' ] ,
vout : _ utxoItem [ 'tx_pos' ] ,
address ,
amount : Number ( _ utxoItem . value ) * 0.00000001 ,
amountSats : _ utxoItem . value ,
locktime : decodedTx . format . locktime ,
interest : Number ( interest . toFixed ( 8 ) ) ,
interestSats : Math . floor ( interest * 100000000 ) ,
confirmations : Number ( _ utxoItem . height ) === 0 ? 0 : currentHeight - _ utxoItem . height ,
spendable : true ,
verified : false ,
} ;
// merkle root verification agains another electrum server
if ( verify ) {
shepherd . verifyMerkleByCoin ( shepherd . findCoinName ( network ) , _ utxoItem [ 'tx_hash' ] , _ utxoItem . height )
. then ( ( verifyMerkleRes ) => {
if ( verifyMerkleRes &&
verifyMerkleRes === shepherd . CONNECTION_ERROR_OR_INCOMPLETE_DATA ) {
verifyMerkleRes = false ;
}
_ resolveObj . verified = verifyMerkleRes ;
resolve ( _ resolveObj ) ;
} ) ;
} else {
resolve ( _ resolveObj ) ;
}
} else {
let _ resolveObj = {
txid : _ utxoItem [ 'tx_hash' ] ,
vout : _ utxoItem [ 'tx_pos' ] ,
address ,
amount : Number ( _ utxoItem . value ) * 0.00000001 ,
amountSats : _ utxoItem . value ,
confirmations : Number ( _ utxoItem . height ) === 0 ? 0 : currentHeight - _ utxoItem . height ,
spendable : true ,
verified : false ,
} ;
// merkle root verification agains another electrum server
if ( verify ) {
shepherd . verifyMerkleByCoin ( shepherd . findCoinName ( network ) , _ utxoItem [ 'tx_hash' ] , _ utxoItem . height )
. then ( ( verifyMerkleRes ) => {
if ( verifyMerkleRes &&
verifyMerkleRes === shepherd . CONNECTION_ERROR_OR_INCOMPLETE_DATA ) {
verifyMerkleRes = false ;
}
_ resolveObj . verified = verifyMerkleRes ;
resolve ( _ resolveObj ) ;
} ) ;
} else {
resolve ( _ resolveObj ) ;
}
}
}
} ) ;
} ) ;
} ) )
. then ( promiseResult => {
ecl . close ( ) ;
if ( ! _ atLeastOneDecodeTxFailed ) {
shepherd . log ( promiseResult , true ) ;
resolve ( promiseResult ) ;
} else {
shepherd . log ( 'listunspent error, cant decode tx(s)' , true ) ;
resolve ( 'decode error' ) ;
}
} ) ;
}
} else {
resolve ( 'cant get current height' ) ;
}
} ) ;
} else {
ecl . close ( ) ;
resolve ( shepherd . CONNECTION_ERROR_OR_INCOMPLETE_DATA ) ;
}
} ) ;
} ) ;
} else {
return new shepherd . Promise ( ( resolve , reject ) => {
ecl . connect ( ) ;
ecl . blockchainAddressListunspent ( address )
. then ( ( json ) => {
ecl . close ( ) ;
if ( json &&
json . length ) {
resolve ( json ) ;
} else {
resolve ( shepherd . CONNECTION_ERROR_OR_INCOMPLETE_DATA ) ;
}
} ) ;
} ) ;
}
}
shepherd . get ( '/electrum/listunspent' , ( req , res , next ) => {
const network = req . query . network || shepherd . findNetworkObj ( req . query . coin ) ;
const ecl = new shepherd . electrumJSCore ( shepherd . electrumServers [ network ] . port , shepherd . electrumServers [ network ] . address , shepherd . electrumServers [ network ] . proto ) ; // tcp or tls
if ( req . query . full &&
req . query . full === 'true' ) {
shepherd . listunspent (
ecl ,
req . query . address ,
network ,
true ,
req . query . verify
) . then ( ( listunspent ) => {
shepherd . log ( 'electrum listunspent ==>' , true ) ;
const successObj = {
msg : 'success' ,
result : listunspent ,
} ;
res . end ( JSON . stringify ( successObj ) ) ;
} ) ;
} else {
shepherd . listunspent ( ecl , req . query . address , network )
. then ( ( listunspent ) => {
ecl . close ( ) ;
shepherd . log ( 'electrum listunspent ==>' , true ) ;
const successObj = {
msg : 'success' ,
result : listunspent ,
} ;
res . end ( JSON . stringify ( successObj ) ) ;
} ) ;
}
} ) ;
return shepherd ;
} ;