Files
js/examples/address-tx-list.js
2021-02-15 12:16:14 +01:00

212 lines
8.1 KiB
JavaScript

if (process.argv.length <= 2) {
console.log("Fetch interactions of address\nUsage node TODO.js [address]");
process.exit();
}
const FloweeServices = require('../');
var Flowee = new FloweeServices();
function printDate(timeInSeconds) {
let date = new Date(timeInSeconds * 1000); // JS wants milliseconds.
var answer = date.getUTCDate() + "/" + (date.getUTCMonth() + 1);
while (answer.length < 5)
answer = " " + answer;
// JS misses 'getUTCYear' :(
let y = date.getUTCFullYear() - 2000;
answer += "/" + y;
return answer;
}
function listInteractions(address) {
// search request passes an object literal
var promise = Flowee.search({
jobs: [
{ // Get all transactions based on the following address
value: address,
type: Flowee.Job.LookupByAddress,
}
],
// don't fetch items twice, remember which ones we created jobs for
requests: {
headers: {},
tx: {}
},
// private method to avoid fetching blockheaders multiple times.
fetchHeader: function(blockHeight) {
if (typeof this.requests.headers[`${blockHeight}`] === 'undefined') {
this.requests.headers[`${blockHeight}`] = true;
this.addJob({
type: Flowee.Job.FetchBlockHeader,
value: blockHeight,
});
}
},
fetchTxOutputs: function(txid) {
if (typeof this.requests.tx[`${txid}`] === 'undefined') {
this.requests.tx[`${txid}`] = true;
this.addJob({
type: Flowee.Job.FetchTx,
value: txid,
txFilter: [
Flowee.IncludeOutputAmounts,
Flowee.IncludeOutputAddresses
]
});
}
},
onAddressUsedInOutput: function(blockHeight, offsetInBlock, outIndex) {
this.fetchHeader(blockHeight);
this.addJob({
type: Flowee.Job.FetchTx,
value: blockHeight,
value2: offsetInBlock,
txFilter: [
Flowee.IncludeTxid,
Flowee.IncludeOutputAmounts,
Flowee.IncludeOutputAddresses,
Flowee.IncludeInputs
],
// the next one is for myself, not the framework.
outIndex: outIndex
});
},
onTxAdded: function(transaction) {
let jobId = transaction.jobId;
let job = this.jobs[jobId];
// If outIndex was defined this is one of the tx's we got from the
// address-search because we added it in onAddressUsedInOutput()
if (typeof job.outIndex !== 'undefined') {
transaction.isMain = true;
transaction.outIndex = job.outIndex;
for (let i = 0; i < transaction.inputs.length; ++i) {
if (i == 6) break; // no need to show more inputs.
// input is really just a link to another Tx, fetch its outputs.
this.fetchTxOutputs(transaction.inputs[i].previousTxid);
}
for (let i = 0; i < transaction.outputs.length; ++i) {
if (i >= 6) {
if (job.outIndex >= i)
i = job.outIndex;
else
break;
}
this.addJob({
type: Flowee.Job.LookupSpentTx,
value: transaction.txid,
value2: i
});
}
} else {
// anything not from the address search should be made easy to find.
this[`${transaction.txid}`] = transaction;
this.fetchHeader(transaction.blockHeight);
}
},
onSpentOutputResolved: function(jobId, blockHeight, offsetInBlock) {
if (blockHeight != -1) { // it was spent.
let job = this.jobs[jobId];
this[`out${job.value}${job.value2}`] = blockHeight;
this.fetchHeader(blockHeight);
}
},
onFinished: function() {
console.log("Transactions that interacted with address: " + address);
for (num in this.transactions) {
let tx = this.transactions[num];
if (tx.isMain) {
let header = this[`block${tx.blockHeight}`];
console.log();
console.log(printDate(header.time) + " (block: " + tx.blockHeight
+ ") txid: " + tx.txid);
for (let i = 0; i < tx.inputs.length; ++i) {
if (i == 6) {
console.log(" " + (tx.inputs.length - i)
+ " more inputs not shown");
break;
}
if (tx.isCoinbase) {
let header = this[`block${tx.blockHeight}`];
let amount = 0;
for (let o = 0; o < tx.outputs.length; ++o) {
amount += tx.outputs[o].amount;
}
console.log(printDate(header.time)
+ " " + amount / 100000000 + " BCH [coinbase]");
break;
}
else {
// input is really just a link.
let prev = this[`${tx.inputs[i].previousTxid}`];
let prevOut = prev.outputs[tx.inputs[i].outputIndex];
let header = this[`block${prev.blockHeight}`];
console.log(printDate(header.time)
+ " " + prevOut.amount / 100000000 + " BCH => "
+ prevOut.address);
}
}
for (let i = 0; i < tx.outputs.length; ++i) {
if (i >= 6) {
if (tx.outIndex > i) {
console.log(" skipping " + (tx.outIndex - i) + " outputs");
i = tx.outIndex;
}
else if (tx.outIndex < i) {
console.log(" " + (tx.outputs.length - i)
+ " more outputs not shown");
break;
}
}
let str = tx.outIndex === i ? "\t* " : "\t ";
let spentHeight = this[`out${tx.txid}${i}`];
if (spentHeight) {
let header = this[`block${spentHeight}`];
var spent = printDate(header.time);
} else {
var spent = "unspent";
}
console.log(str + tx.outputs[i].amount / 100000000 + " BCH => "
+ tx.outputs[i].address + " (spent: " + spent +")");
}
}
}
/*
console.log("Address balance fetched: " + address);
if (this.total != 0 || this.outputs != 0) {
console.log(" UTXOs: " + this.unspent + "/" + this.outputs);
console.log(" Balance: " + this.total / 100000000);
} else {
console.log(" empty");
}
*/
}
});
return promise;
}
Flowee.connect().then(async function() {
try {
for (arg in process.argv) {
if (arg > 1) { // nodejs, skip first two args.
let result = await listInteractions(process.argv[arg])
}
}
} catch (error) {
console.log("Error detected: " + error);
}
process.exit();
})