-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
152 lines (126 loc) · 4.37 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
* Copyright © 2021 Neel Yadav
* All rights reserved.
*
* Tool to handle/export Handshake tx history
* from the wallet client (hsw) and exchanges
* (only Bittrex currently), along with other
* Bitcoin wallet transactions, for portfolio
* tracking purposes.
*
* Authors: Neel Yadav <mail@neelyadav.com>
* Created: August 26th, 2021
* Website: https://github.com/nlydv/handcount
*
*/
const { buildExchangeHistory, DECIMALS } = require("./lib/exchange.js");
const { toCSV } = require("./lib/util");
const build = {
bitcoin: require("./lib/wallets/bitcoin.js"),
handshake: require("./lib/wallets/handshake.js"),
};
class Account {
constructor() {
this.balance = 0;
this.income = 0;
this.expend = 0;
this.burned = 0;
this.sumFee = 0;
this.numTxs = 0;
}
}
const bank = {
// HNS: {
// balance: 0,
// income: 0,
// expend: 0,
// burned: 0,
// sumFee: 0
// }
};
let numTxs = 0;
let ledger = [];
function reconcile(wallet, exchange) {
const transfers = [];
let newWallet = wallet.ledger;
let newExchange = exchange.ledger;
exchange.ledger.forEach(tx => {
if ( tx.type === "DEPOSIT" || tx.type === "WITHDRAW" ) transfers.push(tx);
});
for ( const tx of transfers ) {
const hash = tx.id;
const match = wallet.ledger.findIndex(wt => wt.id === hash);
const wt = wallet.ledger[match];
if ( match === -1 ) continue;
const newTx = {
id: hash,
type: "TRANSFER",
time: wt.time,
block: wt.block,
route: {
from: ( tx.type === "DEPOSIT" ? "WALLET" : tx.origin ),
to: ( tx.type === "DEPOSIT" ? tx.origin : "WALLET" )
},
txFee: wt.txFee + tx.txFee,
delta: wt.net - (wt.txFee + tx.txFee),
net: wt.net
};
newWallet[match] = newTx;
newExchange = newExchange.filter(e => e !== tx);
}
return [ newWallet, newExchange ];
}
/* ————————————————————————————————————————————————————————————— */
async function buildPortfolio() {
const wallets = {
BTC: await build.bitcoin(),
HNS: await build.handshake()
};
let exchange = await buildExchangeHistory();
for ( const [money, acct] of Object.entries(wallets) ) {
let wallet = acct;
bank[money] = bank?.[money] ?? new Account();
// merge matching deposit/withdrawal txs between wallet & exchange
const merged = reconcile(wallet, exchange);
wallet.ledger = merged[0];
exchange.ledger = merged[1];
// initate filling bank metrics by first copying hsw values (wallet.js)
wallet = Object.entries(wallet);
ledger = ledger.concat(wallet.pop()[1]);
numTxs += wallet.pop()[1];
wallet.forEach(value => { bank[money][value[0]] += value[1]; });
}
// then extract off & merge the meta/non-iterative metrics from exchange values (exchange.js)
exchange = Object.entries(exchange);
ledger = ledger.concat(exchange.pop()[1]);
numTxs += exchange.pop()[1];
const monies = exchange.shift()[1];
// iterate and add numerical exchange metrics to respective bank values
for ( const item of exchange ) {
const metric = item[0];
const values = item[1];
for ( let money of monies ) {
const i = monies.indexOf(money);
// bank[money] = bank?.[money] ?? { balance: 0, income: 0, expend: 0, sumFee: 0 };
bank[money] = bank?.[money] ?? new Account();
bank[money][metric] += values[i];
}
}
// limit numerical values to max precision of associated coin
Object.keys(bank).forEach(money => {
Object.keys(bank[money]).forEach(metric => {
const fixed = Number.parseFloat(bank[money][metric].toFixed(DECIMALS[money]));
bank[money][metric] = fixed;
});
});
// re-sort ledger txs in chronological order
ledger.sort((a, b) => new Date(a.time) - new Date(b.time));
bank.numTxs = ledger.length;
bank.ledger = ledger;
return bank;
}
(async () => {
const bank = await buildPortfolio();
// console.log(JSON.stringify(bank));
toCSV(bank);
})();