|
|
@ -542,6 +542,9 @@ shepherd.verifyMerkle = function(txid, height, serverList, mainServer) { |
|
|
|
ecl.connect(); |
|
|
|
ecl.blockchainTransactionGetMerkle(txid, height) |
|
|
|
.then((merkleData) => { |
|
|
|
if (merkleData && |
|
|
|
merkleData.merkle && |
|
|
|
merkleData.pos) { |
|
|
|
console.log('electrum getmerkle =>'); |
|
|
|
console.log(merkleData); |
|
|
|
ecl.close(); |
|
|
@ -553,6 +556,8 @@ shepherd.verifyMerkle = function(txid, height, serverList, mainServer) { |
|
|
|
ecl.connect(); |
|
|
|
ecl.blockchainBlockGetHeader(height) |
|
|
|
.then((blockInfo) => { |
|
|
|
if (blockInfo && |
|
|
|
blockInfo['merkle_root']) { |
|
|
|
ecl.close(); |
|
|
|
console.log('blockinfo =>'); |
|
|
|
console.log(blockInfo); |
|
|
@ -568,7 +573,13 @@ shepherd.verifyMerkle = function(txid, height, serverList, mainServer) { |
|
|
|
} else { |
|
|
|
resolve(CONNECTION_ERROR_OR_INCOMPLETE_DATA); |
|
|
|
} |
|
|
|
} else { |
|
|
|
resolve(f); |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
resolve(CONNECTION_ERROR_OR_INCOMPLETE_DATA); |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
@ -736,17 +747,8 @@ shepherd.kdmCalcInterest = function(locktime, value) { // value in sats |
|
|
|
|
|
|
|
console.log(`minutes if statement ${timestampDiffMinutes}`); |
|
|
|
|
|
|
|
let denominator = (365 * 24 * 60) / timestampDiffMinutes; |
|
|
|
|
|
|
|
if (denominator === 0) { |
|
|
|
denominator = 1; // max KOMODO_INTEREST per transfer, do it at least annually!
|
|
|
|
} |
|
|
|
|
|
|
|
console.log(`denominator ${denominator}`); |
|
|
|
|
|
|
|
// TODO: check if interest is > 5% yr
|
|
|
|
// calc ytd and 5% for 1 yr
|
|
|
|
const numerator = Number(value) * 0.00000001 / 20; // assumes 5%!
|
|
|
|
// const hoursInOneYear = 365 * 24;
|
|
|
|
// const hoursDiff = hoursInOneYear - hoursPassed;
|
|
|
|
|
|
|
@ -764,6 +766,9 @@ shepherd.get('/electrum/getbalance', function(req, res, next) { |
|
|
|
ecl.connect(); |
|
|
|
ecl.blockchainAddressGetBalance(req.query.address) |
|
|
|
.then((json) => { |
|
|
|
if (json && |
|
|
|
json.hasOwnProperty('confirmed') && |
|
|
|
json.hasOwnProperty('unconfirmed')) { |
|
|
|
if (network === 'komodo') { |
|
|
|
ecl.connect(); |
|
|
|
ecl.blockchainAddressListunspent(req.query.address) |
|
|
@ -788,25 +793,34 @@ shepherd.get('/electrum/getbalance', function(req, res, next) { |
|
|
|
_utxo.length) { |
|
|
|
let interestTotal = 0; |
|
|
|
|
|
|
|
for (let i = 0; i < _utxo.length; i++) { |
|
|
|
ecl.blockchainTransactionGet(_utxo[i]['tx_hash']) |
|
|
|
Promise.all(_utxo.map((_utxoItem, index) => { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
ecl.blockchainTransactionGet(_utxoItem['tx_hash']) |
|
|
|
.then((_rawtxJSON) => { |
|
|
|
console.log('electrum gettransaction ==>'); |
|
|
|
console.log(i + ' | ' + (_rawtxJSON.length - 1)); |
|
|
|
console.log(index + ' | ' + (_rawtxJSON.length - 1)); |
|
|
|
console.log(_rawtxJSON); |
|
|
|
|
|
|
|
// decode tx
|
|
|
|
const _network = shepherd.getNetworkData(network); |
|
|
|
const decodedTx = electrumJSTxDecoder(_rawtxJSON, _network); |
|
|
|
|
|
|
|
if (decodedTx.format.locktime > 0) { |
|
|
|
interestTotal += shepherd.kdmCalcInterest(decodedTx.format.locktime, _utxo[i].value); |
|
|
|
if (decodedTx && |
|
|
|
decodedTx.format && |
|
|
|
decodedTx.format.locktime > 0) { |
|
|
|
interestTotal += shepherd.kdmCalcInterest(decodedTx.format.locktime, _utxoItem.value); |
|
|
|
} |
|
|
|
|
|
|
|
console.log('decoded tx =>'); |
|
|
|
console.log(decodedTx); |
|
|
|
console.log(decodedTx.format.locktime); |
|
|
|
|
|
|
|
if (i === _utxo.length -1) { |
|
|
|
resolve(true); |
|
|
|
}); |
|
|
|
}); |
|
|
|
})) |
|
|
|
.then(promiseResult => { |
|
|
|
ecl.close(); |
|
|
|
|
|
|
|
const successObj = { |
|
|
|
msg: 'success', |
|
|
|
result: { |
|
|
@ -822,9 +836,7 @@ shepherd.get('/electrum/getbalance', function(req, res, next) { |
|
|
|
}; |
|
|
|
|
|
|
|
res.end(JSON.stringify(successObj)); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
} else { |
|
|
|
const successObj = { |
|
|
|
msg: 'success', |
|
|
@ -851,6 +863,9 @@ shepherd.get('/electrum/getbalance', function(req, res, next) { |
|
|
|
unconfirmedSats: json.unconfirmed, |
|
|
|
balanceSats: json.confirmed, |
|
|
|
interest: 0, |
|
|
|
interestSats: 0, |
|
|
|
total: 0, |
|
|
|
totalSats: 0, |
|
|
|
}, |
|
|
|
}; |
|
|
|
|
|
|
@ -865,12 +880,21 @@ shepherd.get('/electrum/getbalance', function(req, res, next) { |
|
|
|
const successObj = { |
|
|
|
msg: 'success', |
|
|
|
result: { |
|
|
|
balance: 0.00000001 * json.confirmed, |
|
|
|
unconfirmed: json.unconfirmed, |
|
|
|
sats: json.confirmed, |
|
|
|
balance: Number((0.00000001 * json.confirmed).toFixed(8)), |
|
|
|
unconfirmed: Number((0.00000001 * json.unconfirmed).toFixed(8)), |
|
|
|
unconfirmedSats: json.unconfirmed, |
|
|
|
balanceSats: json.confirmed, |
|
|
|
}, |
|
|
|
}; |
|
|
|
|
|
|
|
res.end(JSON.stringify(successObj)); |
|
|
|
} |
|
|
|
} else { |
|
|
|
const successObj = { |
|
|
|
msg: 'error', |
|
|
|
result: CONNECTION_ERROR_OR_INCOMPLETE_DATA, |
|
|
|
}; |
|
|
|
|
|
|
|
res.end(JSON.stringify(successObj)); |
|
|
|
} |
|
|
|
}); |
|
|
@ -920,7 +944,9 @@ shepherd.get('/electrum/listtransactions', function(req, res, next) { |
|
|
|
ecl.connect(); |
|
|
|
|
|
|
|
ecl.blockchainNumblocksSubscribe() |
|
|
|
.then(function(currentHeight) { |
|
|
|
.then((currentHeight) => { |
|
|
|
if (currentHeight && |
|
|
|
Number(currentHeight) > 0) { |
|
|
|
ecl.blockchainAddressGetHistory(req.query.address) |
|
|
|
.then((json) => { |
|
|
|
if (json && |
|
|
@ -930,14 +956,16 @@ shepherd.get('/electrum/listtransactions', function(req, res, next) { |
|
|
|
console.log(json.length); |
|
|
|
let _rawtx = []; |
|
|
|
|
|
|
|
// get raw tx
|
|
|
|
for (let i = 0; i < json.length; i++) { |
|
|
|
ecl.blockchainBlockGetHeader(json[i].height) |
|
|
|
Promise.all(json.map((transaction, index) => { |
|
|
|
return new Promise((resolve, reject) => { |
|
|
|
ecl.blockchainBlockGetHeader(transaction.height) |
|
|
|
.then((blockInfo) => { |
|
|
|
ecl.blockchainTransactionGet(json[i]['tx_hash']) |
|
|
|
if (blockInfo && |
|
|
|
blockInfo.timestamp) { |
|
|
|
ecl.blockchainTransactionGet(transaction['tx_hash']) |
|
|
|
.then((_rawtxJSON) => { |
|
|
|
console.log('electrum gettransaction ==>'); |
|
|
|
console.log(i + ' | ' + (_rawtxJSON.length - 1)); |
|
|
|
console.log(index + ' | ' + (_rawtxJSON.length - 1)); |
|
|
|
console.log(_rawtxJSON); |
|
|
|
|
|
|
|
// decode tx
|
|
|
@ -949,25 +977,36 @@ shepherd.get('/electrum/listtransactions', function(req, res, next) { |
|
|
|
console.log('decodedtx =>'); |
|
|
|
console.log(decodedTx.outputs); |
|
|
|
|
|
|
|
if (decodedTx.inputs) { |
|
|
|
for (let j = 0; j < decodedTx.inputs.length; j++) { |
|
|
|
if (decodedTx.inputs[j].txid !== '0000000000000000000000000000000000000000000000000000000000000000') { |
|
|
|
ecl.blockchainTransactionGet(decodedTx.inputs[j].txid) |
|
|
|
if (decodedTx && |
|
|
|
decodedTx.inputs) { |
|
|
|
Promise.all(decodedTx.inputs.map((_decodedInput, index) => { |
|
|
|
return new Promise((_resolve, _reject) => { |
|
|
|
if (_decodedInput.txid !== '0000000000000000000000000000000000000000000000000000000000000000') { |
|
|
|
ecl.blockchainTransactionGet(_decodedInput.txid) |
|
|
|
.then((rawInput) => { |
|
|
|
console.log('electrum raw input tx ==>'); |
|
|
|
const decodedVinVout = electrumJSTxDecoder(rawInput, _network); |
|
|
|
console.log(decodedVinVout.outputs[decodedTx.inputs[j].n]); |
|
|
|
txInputs.push(decodedVinVout.outputs[decodedTx.inputs[j].n]); |
|
|
|
|
|
|
|
if (j === decodedTx.inputs.length - 1) { |
|
|
|
if (decodedVinVout) { |
|
|
|
console.log(decodedVinVout.outputs[_decodedInput.n]); |
|
|
|
txInputs.push(decodedVinVout.outputs[_decodedInput.n]); |
|
|
|
_resolve(true); |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
_resolve(true); |
|
|
|
} |
|
|
|
}); |
|
|
|
})) |
|
|
|
.then(promiseResult => { |
|
|
|
const _parsedTx = { |
|
|
|
network: decodedTx.network, |
|
|
|
format: decodedTx.format, |
|
|
|
inputs: txInputs, |
|
|
|
outputs: decodedTx.outputs, |
|
|
|
height: json[i].height, |
|
|
|
height: transaction.height, |
|
|
|
timestamp: blockInfo.timestamp, |
|
|
|
confirmations: currentHeight - json[i].height, |
|
|
|
confirmations: currentHeight - transaction.height, |
|
|
|
}; |
|
|
|
|
|
|
|
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, req.query.address, network); |
|
|
@ -978,104 +1017,68 @@ shepherd.get('/electrum/listtransactions', function(req, res, next) { |
|
|
|
_rawtx.push(formattedTx[0]); |
|
|
|
_rawtx.push(formattedTx[1]); |
|
|
|
} |
|
|
|
|
|
|
|
if (i === json.length - 1) { |
|
|
|
ecl.close(); |
|
|
|
console.log('electrum gettransaction array ==>'); |
|
|
|
console.log(_rawtx); |
|
|
|
|
|
|
|
const successObj = { |
|
|
|
msg: 'success', |
|
|
|
result: { |
|
|
|
listtransactions: _rawtx, |
|
|
|
}, |
|
|
|
}; |
|
|
|
|
|
|
|
res.end(JSON.stringify(successObj)); |
|
|
|
} |
|
|
|
} |
|
|
|
resolve(true); |
|
|
|
}); |
|
|
|
} else { |
|
|
|
if (j === decodedTx.inputs.length - 1) { |
|
|
|
const _parsedTx = { |
|
|
|
network: decodedTx.network, |
|
|
|
format: decodedTx.format, |
|
|
|
inputs: txInputs, |
|
|
|
outputs: decodedTx.outputs, |
|
|
|
height: json[i].height, |
|
|
|
format: 'cant parse', |
|
|
|
inputs: 'cant parse', |
|
|
|
outputs: 'cant parse', |
|
|
|
height: transaction.height, |
|
|
|
timestamp: blockInfo.timestamp, |
|
|
|
confirmations: currentHeight - json[i].height, |
|
|
|
confirmations: currentHeight - transaction.height, |
|
|
|
}; |
|
|
|
|
|
|
|
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, req.query.address, network); |
|
|
|
|
|
|
|
if (formattedTx.type) { |
|
|
|
_rawtx.push(formattedTx); |
|
|
|
} else { |
|
|
|
_rawtx.push(formattedTx[0]); |
|
|
|
_rawtx.push(formattedTx[1]); |
|
|
|
} |
|
|
|
|
|
|
|
if (i === json.length - 1) { |
|
|
|
ecl.close(); |
|
|
|
console.log('electrum gettransaction array ==>'); |
|
|
|
console.log(_rawtx); |
|
|
|
|
|
|
|
const successObj = { |
|
|
|
msg: 'success', |
|
|
|
result: { |
|
|
|
listtransactions: _rawtx, |
|
|
|
}, |
|
|
|
}; |
|
|
|
|
|
|
|
res.end(JSON.stringify(successObj)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
resolve(true); |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
const _parsedTx = { |
|
|
|
network: decodedTx.network, |
|
|
|
network: 'cant parse', |
|
|
|
format: 'cant parse', |
|
|
|
inputs: 'cant parse', |
|
|
|
outputs: 'cant parse', |
|
|
|
height: json[i].height, |
|
|
|
timestamp: blockInfo.timestamp, |
|
|
|
confirmations: currentHeight - json[i].height, |
|
|
|
height: transaction.height, |
|
|
|
timestamp: 'cant get block info', |
|
|
|
confirmations: currentHeight - transaction.height, |
|
|
|
}; |
|
|
|
|
|
|
|
const formattedTx = shepherd.parseTransactionAddresses(_parsedTx, req.query.address, network); |
|
|
|
_rawtx.push(formattedTx); |
|
|
|
|
|
|
|
if (i === json.length - 1) { |
|
|
|
resolve(true); |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
})) |
|
|
|
.then(promiseResult => { |
|
|
|
ecl.close(); |
|
|
|
console.log('electrum gettransaction array ==>'); |
|
|
|
console.log(_rawtx); |
|
|
|
|
|
|
|
const successObj = { |
|
|
|
msg: 'success', |
|
|
|
result: { |
|
|
|
listtransactions: _rawtx, |
|
|
|
}, |
|
|
|
result: _rawtx, |
|
|
|
}; |
|
|
|
|
|
|
|
res.end(JSON.stringify(successObj)); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} else { |
|
|
|
const successObj = { |
|
|
|
msg: 'success', |
|
|
|
result: { |
|
|
|
listtransactions: [], |
|
|
|
}, |
|
|
|
result: [], |
|
|
|
}; |
|
|
|
|
|
|
|
res.end(JSON.stringify(successObj)); |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
const successObj = { |
|
|
|
msg: 'error', |
|
|
|
result: 'cant get current height', |
|
|
|
}; |
|
|
|
|
|
|
|
res.end(JSON.stringify(successObj)); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
}); |
|
|
@ -1388,7 +1391,7 @@ shepherd.buildSignedTx = function(sendTo, changeAddress, wif, network, utxo, cha |
|
|
|
let key = bitcoinJS.ECPair.fromWIF(wif, shepherd.getNetworkData(network)); |
|
|
|
let tx = new bitcoinJS.TransactionBuilder(shepherd.getNetworkData(network)); |
|
|
|
|
|
|
|
console.log(`buildSignedTx priv key ${wif}`); |
|
|
|
// console.log(`buildSignedTx priv key ${wif}`);
|
|
|
|
console.log(`buildSignedTx pub key ${key.getAddress().toString()}`); |
|
|
|
// console.log('buildSignedTx std tx fee ' + electrumServers[network].txfee);
|
|
|
|
|
|
|
@ -1701,6 +1704,8 @@ shepherd.listunspent = function(ecl, address, network, full, verify) { |
|
|
|
|
|
|
|
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) { |
|
|
@ -1755,6 +1760,10 @@ shepherd.listunspent = function(ecl, address, network, full, verify) { |
|
|
|
if (verify) { |
|
|
|
shepherd.verifyMerkleByCoin(shepherd.findCoinName(network), _utxoItem['tx_hash'], _utxoItem.height) |
|
|
|
.then((verifyMerkleRes) => { |
|
|
|
if (verifyMerkleRes && verifyMerkleRes === CONNECTION_ERROR_OR_INCOMPLETE_DATA) { |
|
|
|
verifyMerkleRes = false; |
|
|
|
} |
|
|
|
|
|
|
|
_resolveObj.verified = verifyMerkleRes; |
|
|
|
resolve(_resolveObj); |
|
|
|
}); |
|
|
@ -1777,6 +1786,10 @@ shepherd.listunspent = function(ecl, address, network, full, verify) { |
|
|
|
if (verify) { |
|
|
|
shepherd.verifyMerkleByCoin(shepherd.findCoinName(network), _utxoItem['tx_hash'], _utxoItem.height) |
|
|
|
.then((verifyMerkleRes) => { |
|
|
|
if (verifyMerkleRes && verifyMerkleRes === CONNECTION_ERROR_OR_INCOMPLETE_DATA) { |
|
|
|
verifyMerkleRes = false; |
|
|
|
} |
|
|
|
|
|
|
|
_resolveObj.verified = verifyMerkleRes; |
|
|
|
resolve(_resolveObj); |
|
|
|
}); |
|
|
@ -1800,6 +1813,9 @@ shepherd.listunspent = function(ecl, address, network, full, verify) { |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
} else { |
|
|
|
resolve('cant get current height'); |
|
|
|
} |
|
|
|
}); |
|
|
|
} else { |
|
|
|
ecl.close(); |
|
|
|