Due to Hive Engine outages, I had to research which transactions were not completed or refunded. Since I keep trading while waiting for the counterparty, and my code is a little bugged, there were many transactions to check.
I already wrote a simple page to research a transaction by its hash, but this time it was insufficient. I would have to do many searches with it.
So I wrote a NodeJS script for finding stuck deposits/withdrawals. It is rudimentary but it suits my needs.
Usage
To call the program:
node transactions-report.js your-account
You can specify a number of days (default 7):
node transactions-report.js your-account 30
Output
$ ./transactions-report.js arbitra 20
20 days
2 SWAP.HIVE transfers out, 15 transfers in
25 SWAP.HBD transfers out, 7 transfers in
155 native transfers out, 150 transfers in
182 transfers out
0771a2c4cd9c224ee8aea199a28ec2346ae1ae77 Sent: to hiveswap 0.669 HIVE at 2025-10-11T23:11:45.000Z, Received: 0.669 HIVE in 0m
...
0d097478a72ccd10d0a0176b60785248f61cdff2 Sent: to hiveswap 881.074 HIVE at 2025-10-11T13:52:45.000Z, NOTHING RECEIVED
...
54183fbf7d439c3e4a0e1b88a9d6108381b569c2 Sent: to hiveswap 1054.775 HIVE at 2025-09-29T21:16:48.000Z, Received: 1050.0285125 SWAP.HIVE in 0m
Sums: { hiveswap: { HIVE: 4167.956 }, 'honey-swap': { HIVE: 1977.421 } }
Installation
Save the Javascript code at http://droida.ch/hive/transactions-report.js in the directory of your choice.
Open a terminal (CTRL+ALT+T), and enter the directory:
cd /path/to/folder
The script runs with Node.js
Install libraries:
npm install https steem
Source Code
You are free to use, modify and distribute it. No attribution is required. There is no garantee.
#!/usr/bin/node
const swapServices=["sw4p", "hiveswap", "graphene-swap", "honey-swap"];
let days=7;
let account;
if (process.argv.length>2) {
account=process.argv[2];
if (process.argv.length>3) {
days=parseFloat(process.argv[3]);
}
} else {
console.log("Usage: "+process.argv[0]+" "+process.argv[1]+" <ACCOUNT> [<DAYS>]");
process.exit(1);
}
const https = require('https');
const chain=require("steem");
chain.api.setOptions({ url: 'https://api.hive.blog' });
chain.config.set('address_prefix','STM');
chain.config.set('chain_id','beeab0de00000000000000000000000000000000000000000000000000000000');
chain.config.set('alternative_api_endpoints', ['https://api.openhive.network', 'https://rpc.esteem.app']);
chain.config.set('rebranded_api', true);
const historyCount=100;
const engineHistoryCount=30;
const minFees=-.05;
const maxFees=.8;
const utcOffset=-new Date().getTimezoneOffset()/60;
const searchToTimestampMsUtc=(Date.now()+utcOffset*1000)-days*86400000;
main();
async function main() {
console.log(days+" days");
let swaps=[];
let engineHiveTransfersOut=[];
let engineHiveTransfersIn=[];
const engineHiveTransfers=await requestEngineHistory("SWAP.HIVE", searchToTimestampMsUtc);
for (let transfer of engineHiveTransfers) {
if (transfer.from==account) {
engineHiveTransfersOut.push(transfer);
swaps.push(transfer);
} else {
engineHiveTransfersIn.push(transfer);
}
}
console.log(engineHiveTransfersOut.length+" SWAP.HIVE transfers out, "+engineHiveTransfersIn.length+" transfers in");
let engineHbdTransfersOut=[];
let engineHbdTransfersIn=[];
const engineHbdTransfers=await requestEngineHistory("SWAP.HBD", searchToTimestampMsUtc);
for (let transfer of engineHbdTransfers) {
if (transfer.from==account) {
engineHbdTransfersOut.push(transfer);
swaps.push(transfer);
} else {
engineHbdTransfersIn.push(transfer);
}
}
console.log(engineHbdTransfersOut.length+" SWAP.HBD transfers out, "+engineHbdTransfersIn.length+" transfers in");
const nativeTransfers=await requestHiveHistory(searchToTimestampMsUtc);
let nativeTransfersOut=[];
let nativeTransfersIn=[];
for (let transfer of nativeTransfers) {
if (transfer.from==account) {
nativeTransfersOut.push(transfer);
swaps.push(transfer);
} else {
nativeTransfersIn.push(transfer);
}
}
console.log(nativeTransfersOut.length+" native transfers out, "+nativeTransfersIn.length+" transfers in");
console.log(swaps.length+" transfers out");
const handledTransfersIn=[];
swap=swaps.sort(function(a, b) {
return b.date-a.date;
});
for (let swap of swaps) {
let id=swap.id;
let to=swap.to;
let quantity=swap.quantity;
let symbol=swap.symbol;
let memo=swap.memo;
if (symbol=='HIVE' || symbol=='HBD') {
// searching for a swap
if (symbol=='HIVE') {
for (let transfer of engineHiveTransfersIn) {
if (handledTransfersIn.indexOf(transfer.id)==-1 && transfer.from==to) {
let ratio=transfer.quantity/quantity;
let timeDiff=transfer.date-swap.date;
if (timeDiff>0 && ratio>=1-maxFees && ratio<=1-minFees) {
swap.receivedTransaction=transfer.id;
swap.receivedQuantity=transfer.quantity;
swap.receivedSymbol=transfer.symbol;
swap.receivedDate=transfer.date;
swap.receivedMemo=transfer.memo;
swap.delay=timeDiff;
handledTransfersIn.push(transfer.id);
break;
}
}
}
} else {
for (let transfer of engineHbdTransfersIn) {
if (handledTransfersIn.indexOf(transfer.id)==-1 && transfer.from==to) {
let ratio=transfer.quantity/quantity;
let timeDiff=transfer.date-swap.date;
if (timeDiff>0 && ratio>=1-maxFees && ratio<=1-minFees) {
swap.receivedTransaction=transfer.id;
swap.receivedQuantity=transfer.quantity;
swap.receivedSymbol=transfer.symbol;
swap.receivedDate=transfer.date;
swap.receivedMemo=transfer.memo;
swap.delay=timeDiff;
handledTransfersIn.push(transfer.id);
break;
}
}
}
}
// searching for a refund
for (let transfer of nativeTransfersIn) {
if (transfer.from==to) {
let timeDiff=transfer.date-swap.date;
if (handledTransfersIn.indexOf(transfer.id)==-1 && transfer.quantity==quantity && transfer.symbol==symbol && timeDiff>0) {
swap.receivedTransaction=transfer.id;
swap.receivedQuantity=transfer.quantity;
swap.receivedSymbol=transfer.symbol;
swap.receivedDate=transfer.date;
swap.receivedMemo=transfer.memo;
swap.delay=timeDiff;
handledTransfersIn.push(transfer.id);
break;
}
}
}
} else if (symbol=='SWAP.HIVE' || symbol=='SWAP.HBD') {
// searching for a swap
for (let transfer of nativeTransfersIn) {
if (transfer.from==to) {
let counterSymbol=symbol=='SWAP.HIVE' ? 'HIVE' : 'HBD';
let ratio=transfer.quantity/quantity;
let timeDiff=transfer.date-swap.date;
if (handledTransfersIn.indexOf(transfer.id)==-1 && ratio>=1-maxFees && ratio<=1-minFees && transfer.symbol==counterSymbol && timeDiff>0) {
swap.receivedTransaction=transfer.id;
swap.receivedQuantity=transfer.quantity;
swap.receivedSymbol=transfer.symbol;
swap.receivedDate=transfer.date;
swap.receivedMemo=transfer.memo;
swap.delay=timeDiff;
handledTransfersIn.push(transfer.id);
break;
}
}
}
// searching for a refund
if (symbol=='HIVE') {
for (let transfer of engineHiveTransfersIn) {
if (handledTransfersIn.indexOf(transfer.id)==-1 && transfer.from==to) {
let timeDiff=transfer.date-swap.date;
if (timeDiff>0 && transfer.quantity==quantity) {
swap.receivedTransaction=transfer.id;
swap.receivedQuantity=transfer.quantity;
swap.receivedSymbol=transfer.symbol;
swap.receivedDate=transfer.date;
swap.receivedMemo=transfer.memo;
swap.delay=timeDiff;
handledTransfersIn.push(transfer.id);
break;
}
}
}
} else {
for (let transfer of engineHbdTransfersIn) {
if (handledTransfersIn.indexOf(transfer.id)==-1 && transfer.from==to) {
let timeDiff=transfer.date-swap.date;
if (timeDiff>0 && transfer.quantity==quantity) {
swap.receivedTransaction=transfer.id;
swap.receivedQuantity=transfer.quantity;
swap.receivedSymbol=transfer.symbol;
swap.receivedDate=transfer.date;
swap.receivedMemo=transfer.memo;
swap.delay=timeDiff;
handledTransfersIn.push(transfer.id);
break;
}
}
}
}
}
}
let sums;
for (let swap of swaps) {
let id=swap.id;
let to=swap.to;
let quantity=swap.quantity;
let symbol=swap.symbol;
let date=swap.date;
if (swapServices.indexOf(to)>=0) {
if (swap.receivedTransaction) {
console.log(id+" Sent: to "+to+" "+quantity+" "+symbol+" at "+new Date(date).toISOString()+", Received: "+swap.receivedQuantity+" "+swap.receivedSymbol+" in "+(swap.delay/60000).toFixed(0)+"m");
} else {
console.log(id+" Sent: to "+to+" "+quantity+" "+symbol+" at "+new Date(date).toISOString()+", NOTHING RECEIVED");
if (!sums) {
sums={};
}
if (!sums[to] || sums[to].length==0) {
sums[to]={};
}
sums[to][symbol]=sums[to][symbol] ? sums[to][symbol]+quantity : quantity;
}
}
}
if (sums) {
console.log("Missed swaps:", sums);
}
}
async function requestEngineHistory(symbol, timeLimitUtc, offset=0) {
return new Promise(async function(resolve) {
let options = {
hostname: "history.hive-engine.com",
port: 443,
path: "/accountHistory?account="+account+"&limit="+engineHistoryCount+"&offset="+offset+"&symbol="+symbol,
method: 'GET',
};
let request=https.request(options, function(resp) {
let data = '';
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end', async () => {
let result=JSON.parse(data);
let transfers=[];
let timestampMsUtc;
for (let i=0; i<result.length; i++) {
let timestampMs=result[i].timestamp*1000;
timestampMsUtc=timestampMs-utcOffset*3600000; // NOT UTC TIMESTAMPS !
if (timestampMsUtc>timeLimitUtc) {
if (result[i].operation=="tokens_transfer") {
let from=result[i].from;
let to=result[i].to;
let quantity=parseFloat(result[i].quantity);
let memo=result[i].memo;
if (timestampMsUtc>timeLimitUtc) {
transfers.push({
id: result[i].transactionId,
block: result[i].blockNumber,
date: timestampMsUtc,
from: from,
to: to,
quantity: quantity,
symbol: result[i].symbol,
memo: memo,
});
}
}
} else {
break;
}
}
if (timestampMsUtc>=timeLimitUtc) {
let nextItems=await requestEngineHistory(symbol, timeLimitUtc, offset+engineHistoryCount);
transfers.push(...nextItems);
}
resolve(transfers);
});
}).on("error", (err) => {
console.log(err);
resolve(false);
});
request.end();
});
}
async function requestHiveHistory(timeLimitUtc, startNumber=-1) {
return new Promise(async function(resolve) {
let limit=historyCount;
if (startNumber!=-1 && startNumber<=limit) {
limit=startNumber;
}
chain.api.getAccountHistory(account, startNumber, limit, async function(err, result) {
if (result && result.length>0) {
let transfers=[];
let dateUtc;
for (let i=result.length-1; i>=0; i--) {
dateUtc=Date.parse(result[i][1].timestamp);
if (dateUtc>=timeLimitUtc) {
let block=result[i][1].block;
let id=result[i][1].trx_id;
let opType=result[i][1].op[0];
let opData=result[i][1].op[1];
if (opType=="transfer" && dateUtc>=timeLimitUtc) {
let from=opData.from;
let to=opData.to;
let quantity=parseFloat(opData.amount.split(" ")[0]);
let symbol=opData.amount.split(" ")[1];
let memo=opData.memo;
transfers.push({
id: id,
block: block,
date: dateUtc,
from: from,
to: to,
quantity: quantity,
symbol: symbol,
memo: memo,
});
}
} else {
break;
}
}
let number=0;
if (result.length>0) {
number=result[0][0];
}
if (number>0 && dateUtc>=timeLimitUtc) {
let nextItems=await requestHiveHistory(timeLimitUtc, number-1);
transfers.push(...nextItems);
}
resolve(transfers);
} else {
console.log(err);
resolve(null);
}
});
});
}
Congratulations @arbitra! You have completed the following achievement on the Hive blockchain And have been rewarded with New badge(s)
Your next target is to reach 50 upvotes.
Your next target is to reach 50 upvotes.
You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word
STOP