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]+" []");
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=.08;
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; itimeLimitUtc) {
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);
}
});
});
}