@hackerhouse/xpub-scan 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +8 -0
- package/CONTRIBUTING.md +130 -0
- package/LICENSE +23 -0
- package/README.md +215 -0
- package/__tests__/checkAddresses/checkBitcoinAddressesNegative.test.ts +75 -0
- package/__tests__/checkAddresses/checkBitcoinAddressesPositive.test.ts +87 -0
- package/__tests__/checkAddresses/checkDogeAddressesPositive.test.ts +43 -0
- package/__tests__/checkAddresses/checkLitecoinAddressesNegative.test.ts +75 -0
- package/__tests__/checkAddresses/checkLitecoinAddressesPositive.test.ts +87 -0
- package/__tests__/checkModels/address.test.ts +183 -0
- package/__tests__/checkModels/fakeRawTransactions.json +182 -0
- package/__tests__/deriveAddresses/deriveBitcoinAddresses.test.ts +207 -0
- package/__tests__/deriveAddresses/deriveBitcoinCashAddresses.test copy.ts +79 -0
- package/__tests__/deriveAddresses/deriveDogecoinAddresses.test.ts +43 -0
- package/__tests__/deriveAddresses/deriveEthereumAddresses.test.ts +26 -0
- package/__tests__/deriveAddresses/deriveLitecoinAddresses.test.ts +110 -0
- package/__tests__/helpers.test.ts +274 -0
- package/__tests__/test-utils.ts +3 -0
- package/babel.config.js +6 -0
- package/jest.config.ts +5 -0
- package/ledgerhq-xpub-scan-1.0.4.tgz +0 -0
- package/lib/actions/checkAddress.d.ts +29 -0
- package/lib/actions/checkAddress.js +122 -0
- package/lib/actions/checkBalance.d.ts +20 -0
- package/lib/actions/checkBalance.js +300 -0
- package/lib/actions/deriveAddresses.d.ts +17 -0
- package/lib/actions/deriveAddresses.js +239 -0
- package/lib/actions/processTransactions.d.ts +29 -0
- package/lib/actions/processTransactions.js +289 -0
- package/lib/actions/saveAnalysis.d.ts +2 -0
- package/lib/actions/saveAnalysis.js +800 -0
- package/lib/actions/scanner.d.ts +15 -0
- package/lib/actions/scanner.js +152 -0
- package/lib/api/customProvider.d.ts +19 -0
- package/lib/api/customProvider.js +434 -0
- package/lib/api/defaultProvider.d.ts +23 -0
- package/lib/api/defaultProvider.js +275 -0
- package/lib/comparison/compareOperations.d.ts +13 -0
- package/lib/comparison/compareOperations.js +500 -0
- package/lib/comparison/diffs.d.ts +18 -0
- package/lib/comparison/diffs.js +70 -0
- package/lib/configuration/currencies.d.ts +55 -0
- package/lib/configuration/currencies.js +72 -0
- package/lib/configuration/settings.d.ts +51 -0
- package/lib/configuration/settings.js +113 -0
- package/lib/display.d.ts +12 -0
- package/lib/display.js +251 -0
- package/lib/helpers.d.ts +27 -0
- package/lib/helpers.js +255 -0
- package/lib/input/args.d.ts +6 -0
- package/lib/input/args.js +129 -0
- package/lib/input/check.d.ts +6 -0
- package/lib/input/check.js +217 -0
- package/lib/input/importOperations.d.ts +11 -0
- package/lib/input/importOperations.js +406 -0
- package/lib/models/address.d.ts +40 -0
- package/lib/models/address.js +101 -0
- package/lib/models/comparison.d.ts +8 -0
- package/lib/models/comparison.js +6 -0
- package/lib/models/currency.d.ts +11 -0
- package/lib/models/currency.js +6 -0
- package/lib/models/operation.d.ts +33 -0
- package/lib/models/operation.js +80 -0
- package/lib/models/ownAddresses.d.ts +11 -0
- package/lib/models/ownAddresses.js +31 -0
- package/lib/models/scanLimits.d.ts +7 -0
- package/lib/models/scanLimits.js +6 -0
- package/lib/models/stats.d.ts +7 -0
- package/lib/models/stats.js +6 -0
- package/lib/models/transaction.d.ts +10 -0
- package/lib/models/transaction.js +13 -0
- package/lib/scan.d.ts +2 -0
- package/lib/scan.js +31 -0
- package/lib/templates/logos.base64.d.ts +2 -0
- package/lib/templates/logos.base64.js +9 -0
- package/lib/templates/report.html.d.ts +1 -0
- package/lib/templates/report.html.js +393 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/lib/types.d.ts +55 -0
- package/lib/types.js +2 -0
- package/npm-shrinkwrap.json +12323 -0
- package/package.json +81 -0
- package/sonar-project.properties +15 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.importOperations = void 0;
|
|
30
|
+
const fs_1 = __importDefault(require("fs"));
|
|
31
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
32
|
+
const operation_1 = require("../models/operation");
|
|
33
|
+
const settings_1 = require("../configuration/settings");
|
|
34
|
+
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
35
|
+
const helpers = __importStar(require("../helpers"));
|
|
36
|
+
const currencies_1 = require("../configuration/currencies");
|
|
37
|
+
/**
|
|
38
|
+
* Remove forbidden chars from address(es)
|
|
39
|
+
* note that comma (,) are allowed to render concatenated
|
|
40
|
+
* addresses
|
|
41
|
+
* @param {string} address
|
|
42
|
+
* An inputed address or an aggregated list of inputed addresses
|
|
43
|
+
* @returns string
|
|
44
|
+
* A sanitized address or a sanitized aggregated list of addresses
|
|
45
|
+
*/
|
|
46
|
+
const sanitizeInputedAddress = (address) => {
|
|
47
|
+
return address.replace(/[^0-9a-zA-Z,]/gi, "");
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Get contents from file to import
|
|
51
|
+
* @param {string} path
|
|
52
|
+
* Path of file to import
|
|
53
|
+
* @returns string
|
|
54
|
+
* Imported contents
|
|
55
|
+
*/
|
|
56
|
+
const getFileContents = (path) => {
|
|
57
|
+
if (!fs_1.default.existsSync(path)) {
|
|
58
|
+
throw new Error("Imported file " + path + " does not exist");
|
|
59
|
+
}
|
|
60
|
+
return fs_1.default.readFileSync(path, "utf-8");
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Import transactions from a Custom G CSV
|
|
64
|
+
* @param {string} contents
|
|
65
|
+
* Contents from file to import
|
|
66
|
+
* @returns Operation
|
|
67
|
+
* Imported operations
|
|
68
|
+
*/
|
|
69
|
+
const importFromCustomGCSV = (contents) => {
|
|
70
|
+
const operations = [];
|
|
71
|
+
// temporary fix: offset if CSV refers to storageLimit
|
|
72
|
+
// (only columns with index > 14 have to be offsetted in this situation)
|
|
73
|
+
const offset = contents.includes("storageLimit") ? 2 : 1;
|
|
74
|
+
contents
|
|
75
|
+
.split(/\r?\n/)
|
|
76
|
+
.slice(1)
|
|
77
|
+
.forEach((line) => {
|
|
78
|
+
// split using delimiter ',' except when between double quotes
|
|
79
|
+
// as a Custom G CSV can have several addresses in the same field:
|
|
80
|
+
// ...,'<address1>,<address2>,<address3',...
|
|
81
|
+
const tokens = line.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/);
|
|
82
|
+
if (tokens.length < 20) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// expected date format: yyyy-MM-dd HH:mm:ss
|
|
86
|
+
const date = /(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/gi.exec(tokens[0]) || "";
|
|
87
|
+
const type = String(tokens[2]); // CREDIT || DEBIT
|
|
88
|
+
const status = String(tokens[4]); // CONFIRMED || ABORTED
|
|
89
|
+
const amount = tokens[8]; // in unit of account
|
|
90
|
+
const txid = tokens[16 + offset];
|
|
91
|
+
const sender = tokens[17 + offset];
|
|
92
|
+
const recipient = tokens[18 + offset];
|
|
93
|
+
// process only confirmed transactions
|
|
94
|
+
if (status === "CONFIRMED") {
|
|
95
|
+
if (type === "CREDIT") {
|
|
96
|
+
const op = new operation_1.Operation(date[0], amount);
|
|
97
|
+
op.setTxid(txid);
|
|
98
|
+
// recipient: one address or several concatenated addresses
|
|
99
|
+
// ! for this type of CSV, this field is required and should
|
|
100
|
+
// default to a non-empty string (here: `(no address)`) to
|
|
101
|
+
// ensure that an operation without address results in a mismatch
|
|
102
|
+
op.setAddress(sanitizeInputedAddress(recipient));
|
|
103
|
+
op.setOperationType("Received");
|
|
104
|
+
operations.push(op);
|
|
105
|
+
}
|
|
106
|
+
else if (type === "DEBIT") {
|
|
107
|
+
const op = new operation_1.Operation(date[0], amount);
|
|
108
|
+
op.setTxid(txid);
|
|
109
|
+
// sender: one address or several concatenated addresses
|
|
110
|
+
// ! for this type of CSV, this field is required and should
|
|
111
|
+
// default to a non-empty string (here: `(no address)`) to
|
|
112
|
+
// ensure that an operation without address results in a mismatch
|
|
113
|
+
op.setAddress(sanitizeInputedAddress(sender));
|
|
114
|
+
op.setOperationType("Sent");
|
|
115
|
+
operations.push(op);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return operations;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Import transactions from a Live Desktop CSV
|
|
123
|
+
* @param {string} contents
|
|
124
|
+
* Contents from file to import
|
|
125
|
+
* @returns Operation
|
|
126
|
+
* Imported operations
|
|
127
|
+
*/
|
|
128
|
+
const importFromLiveDesktopCSV = (contents) => {
|
|
129
|
+
const operations = [];
|
|
130
|
+
contents
|
|
131
|
+
.split(/\r?\n/)
|
|
132
|
+
.slice(1)
|
|
133
|
+
.forEach((line) => {
|
|
134
|
+
const tokens = line.split(/,/);
|
|
135
|
+
if (tokens.length < 8) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// expected date format: yyyy-MM-dd HH:mm:ss
|
|
139
|
+
const date = /(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/gi.exec(tokens[0]) || "";
|
|
140
|
+
const currency = tokens[1];
|
|
141
|
+
// skip currencies not relevant to the comparison
|
|
142
|
+
if (currency.toUpperCase() !== settings_1.configuration.currency.symbol.toUpperCase()) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const type = String(tokens[2]); // IN | OUT
|
|
146
|
+
const fees = tokens[4] !== "" ? tokens[4] : 0; // in unit of account
|
|
147
|
+
const txid = tokens[5];
|
|
148
|
+
let amount = tokens[3]; // in unit of account
|
|
149
|
+
// note: type B CSV does not refer to addresses
|
|
150
|
+
if (type === "IN") {
|
|
151
|
+
// if ETH, use fixed-point notation
|
|
152
|
+
amount =
|
|
153
|
+
settings_1.configuration.currency.symbol === currencies_1.currencies.eth.symbol
|
|
154
|
+
? new bignumber_js_1.default(tokens[3]).toFixed(settings_1.ETH_FIXED_PRECISION)
|
|
155
|
+
: new bignumber_js_1.default(tokens[3]).toFixed();
|
|
156
|
+
const op = new operation_1.Operation(date[0], amount);
|
|
157
|
+
op.setTxid(txid);
|
|
158
|
+
op.setOperationType("Received");
|
|
159
|
+
operations.push(op);
|
|
160
|
+
}
|
|
161
|
+
else if (type === "OUT") {
|
|
162
|
+
// out transactions: substract fees from amount (in base unit)...
|
|
163
|
+
// and if ETH, use fixed-point notation
|
|
164
|
+
amount =
|
|
165
|
+
settings_1.configuration.currency.symbol === currencies_1.currencies.eth.symbol
|
|
166
|
+
? new bignumber_js_1.default(amount)
|
|
167
|
+
.minus(new bignumber_js_1.default(fees))
|
|
168
|
+
.toFixed(settings_1.ETH_FIXED_PRECISION)
|
|
169
|
+
: new bignumber_js_1.default(amount).minus(new bignumber_js_1.default(fees)).toFixed();
|
|
170
|
+
// ... and convert the total back to unit of account
|
|
171
|
+
// (otherwise, there would be floating number issues)
|
|
172
|
+
const op = new operation_1.Operation(date[0], amount);
|
|
173
|
+
op.setTxid(txid);
|
|
174
|
+
op.setOperationType("Sent");
|
|
175
|
+
operations.push(op);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
return operations;
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* Import transactions from a type A JSON
|
|
182
|
+
* @param {string} contents
|
|
183
|
+
* Contents from file to import
|
|
184
|
+
* @returns Operation
|
|
185
|
+
* Imported operations
|
|
186
|
+
*/
|
|
187
|
+
const importFromJSONTypeA = (contents) => {
|
|
188
|
+
const operations = [];
|
|
189
|
+
let ops;
|
|
190
|
+
try {
|
|
191
|
+
ops = JSON.parse(contents).operations;
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
throw new Error("JSON parsing error");
|
|
195
|
+
}
|
|
196
|
+
for (const operation of ops) {
|
|
197
|
+
const type = operation.operation_type;
|
|
198
|
+
const date = /(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/gi.exec(operation.transaction.received_at) || "";
|
|
199
|
+
const txid = operation.hash;
|
|
200
|
+
const valueInBaseUnit = new bignumber_js_1.default(operation.amount); // in base unit
|
|
201
|
+
const feesInBaseUnit = new bignumber_js_1.default(operation.fees); // in base unit
|
|
202
|
+
if (type === "receive") {
|
|
203
|
+
const op = new operation_1.Operation(date[0], helpers.toAccountUnit(valueInBaseUnit));
|
|
204
|
+
op.setTxid(txid);
|
|
205
|
+
op.setOperationType("Received");
|
|
206
|
+
const addresses = [];
|
|
207
|
+
for (const output of operation.transaction.outputs) {
|
|
208
|
+
if (output.derivation !== null) {
|
|
209
|
+
addresses.push(output.address);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
op.setAddress(sanitizeInputedAddress(addresses.join(",")));
|
|
213
|
+
operations.push(op);
|
|
214
|
+
}
|
|
215
|
+
else if (type === "send") {
|
|
216
|
+
// out transactions: substract fees from amount (in base unit)...
|
|
217
|
+
const amountInBaseUnit = valueInBaseUnit.minus(feesInBaseUnit);
|
|
218
|
+
// ... and convert the total back to unit of account
|
|
219
|
+
// (otherwise, there would be floating number issues)
|
|
220
|
+
const op = new operation_1.Operation(date[0], helpers.toAccountUnit(amountInBaseUnit));
|
|
221
|
+
op.setTxid(txid);
|
|
222
|
+
op.setOperationType("Sent");
|
|
223
|
+
const addresses = [];
|
|
224
|
+
for (const input of operation.transaction.inputs) {
|
|
225
|
+
if (input.derivation !== null) {
|
|
226
|
+
addresses.push(input.address);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
op.setAddress(sanitizeInputedAddress(addresses.join(",")));
|
|
230
|
+
operations.push(op);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return operations;
|
|
234
|
+
};
|
|
235
|
+
/**
|
|
236
|
+
* Import transactions from a Live Common JSON
|
|
237
|
+
* @param {string} contents
|
|
238
|
+
* Contents from file to import
|
|
239
|
+
* @returns Operation
|
|
240
|
+
* Imported operations
|
|
241
|
+
*/
|
|
242
|
+
const importFromLiveCommonJSON = (contents) => {
|
|
243
|
+
const operations = [];
|
|
244
|
+
let ops;
|
|
245
|
+
try {
|
|
246
|
+
ops = JSON.parse(contents).operations;
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
throw new Error("JSON parsing error");
|
|
250
|
+
}
|
|
251
|
+
for (const operation of ops) {
|
|
252
|
+
const type = operation.type;
|
|
253
|
+
const date = /(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/gi.exec(operation.date) || "";
|
|
254
|
+
const txid = operation.hash;
|
|
255
|
+
const valueInBaseUnit = new bignumber_js_1.default(operation.value); // in base unit
|
|
256
|
+
const feesInBaseUnit = new bignumber_js_1.default(operation.fee); // in base unit
|
|
257
|
+
const recipient = operation.recipients.join(",");
|
|
258
|
+
const sender = operation.senders.join(",");
|
|
259
|
+
if (type === "IN") {
|
|
260
|
+
const op = new operation_1.Operation(date[0], helpers.toAccountUnit(valueInBaseUnit));
|
|
261
|
+
op.setTxid(txid);
|
|
262
|
+
op.setOperationType("Received");
|
|
263
|
+
if (settings_1.configuration.currency.symbol === currencies_1.currencies.bch.symbol) {
|
|
264
|
+
// BCH: Live-common returns the cash address format
|
|
265
|
+
op.setCashAddress(sanitizeInputedAddress(recipient));
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
op.setAddress(sanitizeInputedAddress(recipient));
|
|
269
|
+
}
|
|
270
|
+
operations.push(op);
|
|
271
|
+
}
|
|
272
|
+
else if (type === "OUT") {
|
|
273
|
+
// out transactions: substract fees from amount (in base unit)...
|
|
274
|
+
const amountInBaseUnit = valueInBaseUnit.minus(feesInBaseUnit);
|
|
275
|
+
// ... and convert the total back to unit of account
|
|
276
|
+
// (otherwise, there would be floating number issues)
|
|
277
|
+
const op = new operation_1.Operation(date[0], helpers.toAccountUnit(amountInBaseUnit));
|
|
278
|
+
op.setTxid(txid);
|
|
279
|
+
op.setOperationType("Sent");
|
|
280
|
+
if (settings_1.configuration.currency.symbol === currencies_1.currencies.bch.symbol) {
|
|
281
|
+
// BCH: Live-common returns the cash address format
|
|
282
|
+
op.setCashAddress(sanitizeInputedAddress(sender));
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
op.setAddress(sanitizeInputedAddress(sender));
|
|
286
|
+
}
|
|
287
|
+
operations.push(op);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return operations;
|
|
291
|
+
};
|
|
292
|
+
/**
|
|
293
|
+
* Import transactions from a Custom W JSON
|
|
294
|
+
* @param {string} contents
|
|
295
|
+
* Contents from file to import
|
|
296
|
+
* @returns Operation
|
|
297
|
+
* Imported operations
|
|
298
|
+
*/
|
|
299
|
+
const importFromCustomWJSON = (contents) => {
|
|
300
|
+
const operations = [];
|
|
301
|
+
let ops;
|
|
302
|
+
try {
|
|
303
|
+
ops = JSON.parse(contents).operations;
|
|
304
|
+
}
|
|
305
|
+
catch (err) {
|
|
306
|
+
throw new Error("JSON parsing error");
|
|
307
|
+
}
|
|
308
|
+
for (const operation of ops) {
|
|
309
|
+
const type = operation.type;
|
|
310
|
+
const amount = helpers.toAccountUnit(new bignumber_js_1.default(operation.amount));
|
|
311
|
+
const txid = operation.transaction.hash;
|
|
312
|
+
const date = /(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/gi.exec(operation.time) || "";
|
|
313
|
+
const token = operation.token;
|
|
314
|
+
let op = new operation_1.Operation();
|
|
315
|
+
if (type === "RECEIVE") {
|
|
316
|
+
op = new operation_1.Operation(date[0], amount);
|
|
317
|
+
op.setOperationType("Received");
|
|
318
|
+
op.setTxid(txid);
|
|
319
|
+
const addresses = [];
|
|
320
|
+
for (const output of operation.recipients) {
|
|
321
|
+
addresses.push(output);
|
|
322
|
+
}
|
|
323
|
+
op.setAddress(sanitizeInputedAddress(addresses.join(",")));
|
|
324
|
+
}
|
|
325
|
+
else if (type === "SEND") {
|
|
326
|
+
op = new operation_1.Operation(date[0], amount);
|
|
327
|
+
op.setOperationType("Sent");
|
|
328
|
+
op.setTxid(txid);
|
|
329
|
+
const addresses = [];
|
|
330
|
+
for (const input of operation.senders) {
|
|
331
|
+
addresses.push(input);
|
|
332
|
+
}
|
|
333
|
+
op.setAddress(sanitizeInputedAddress(addresses.join(",")));
|
|
334
|
+
}
|
|
335
|
+
else if (type === "NONE") {
|
|
336
|
+
op = new operation_1.Operation(date[0], new bignumber_js_1.default(0));
|
|
337
|
+
op.setOperationType("SCI (recipient)");
|
|
338
|
+
op.setTxid(txid);
|
|
339
|
+
}
|
|
340
|
+
if (typeof token !== "undefined") {
|
|
341
|
+
settings_1.configuration.augmentedImport = true;
|
|
342
|
+
const tokenAmount = new bignumber_js_1.default(token.amount).dividedBy(Math.pow(10, token.magnitude));
|
|
343
|
+
op.addToken(token.symbol, token.name, new bignumber_js_1.default(tokenAmount));
|
|
344
|
+
}
|
|
345
|
+
// TODO: enable Dapps import when this object will contain
|
|
346
|
+
// more information
|
|
347
|
+
//
|
|
348
|
+
// const dapp = operation.dapp;
|
|
349
|
+
// if (typeof dapp !== "undefined") {
|
|
350
|
+
// configuration.augmentedImport = true;
|
|
351
|
+
// op.addDapp(dapp.contract_name);
|
|
352
|
+
// }
|
|
353
|
+
operations.push(op);
|
|
354
|
+
}
|
|
355
|
+
return operations;
|
|
356
|
+
};
|
|
357
|
+
/**
|
|
358
|
+
* Dispatcher: detect the type of the imported file
|
|
359
|
+
* based on its contents
|
|
360
|
+
* @param {string} path
|
|
361
|
+
* Path of file to import
|
|
362
|
+
* @returns Operation
|
|
363
|
+
* Imported transactions
|
|
364
|
+
*/
|
|
365
|
+
const importOperations = (path) => {
|
|
366
|
+
const contents = getFileContents(path);
|
|
367
|
+
const firstLine = contents.split(/\r?\n/)[0].replace('"', "");
|
|
368
|
+
let operations = [];
|
|
369
|
+
// CSV FILES
|
|
370
|
+
if (firstLine.substring(0, 8) === "Creation") {
|
|
371
|
+
// Custom G CSV: 'Creation' is the first token
|
|
372
|
+
operations = importFromCustomGCSV(contents);
|
|
373
|
+
}
|
|
374
|
+
else if (firstLine.substring(0, 9) === "Operation") {
|
|
375
|
+
// Live Desktop CSV: 'Operation' is the first token
|
|
376
|
+
operations = importFromLiveDesktopCSV(contents);
|
|
377
|
+
}
|
|
378
|
+
// JSON FILES
|
|
379
|
+
else if (firstLine.startsWith("{") || firstLine.startsWith("[")) {
|
|
380
|
+
if (contents.includes("cursor")) {
|
|
381
|
+
// type A JSON: contains a reference to 'cursor',
|
|
382
|
+
// an ambiguous term, but sufficient to
|
|
383
|
+
// distinguish it from type Live Common JSON files
|
|
384
|
+
operations = importFromJSONTypeA(contents);
|
|
385
|
+
}
|
|
386
|
+
else if (contents.includes("seedIdentifier")) {
|
|
387
|
+
// Live Common JSON: contains an explicit reference to 'seedIdentifier'
|
|
388
|
+
operations = importFromLiveCommonJSON(contents);
|
|
389
|
+
}
|
|
390
|
+
else if (contents.includes("uid")) {
|
|
391
|
+
// Custom W JSON: contains an explicit reference to 'uid'
|
|
392
|
+
operations = importFromCustomWJSON(contents);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
throw new Error("Format not recognized.");
|
|
397
|
+
}
|
|
398
|
+
if (!settings_1.configuration.silent) {
|
|
399
|
+
console.log(chalk_1.default.grey(String(operations.length).concat(" operations have been imported")));
|
|
400
|
+
}
|
|
401
|
+
// TODO: at this point, generate a warning/error
|
|
402
|
+
// message if no operation has been imported
|
|
403
|
+
// (file parsing issue?)
|
|
404
|
+
return operations;
|
|
405
|
+
};
|
|
406
|
+
exports.importOperations = importOperations;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DerivationMode } from "../configuration/currencies";
|
|
2
|
+
import { Transaction } from "./transaction";
|
|
3
|
+
import { Operation } from "./operation";
|
|
4
|
+
import { Stats } from "./stats";
|
|
5
|
+
import BigNumber from "bignumber.js";
|
|
6
|
+
declare class Address {
|
|
7
|
+
address: string;
|
|
8
|
+
derivationMode: DerivationMode;
|
|
9
|
+
account: number;
|
|
10
|
+
index: number;
|
|
11
|
+
balance: BigNumber;
|
|
12
|
+
transactions: Array<Transaction>;
|
|
13
|
+
rawTransactions: Array<any>;
|
|
14
|
+
stats: Stats;
|
|
15
|
+
ins: Array<Operation>;
|
|
16
|
+
outs: Array<Operation>;
|
|
17
|
+
utxo: boolean;
|
|
18
|
+
constructor(itemToScan: string, derivationMode?: DerivationMode, account?: number, index?: number);
|
|
19
|
+
setTransactions(transactions: Array<Transaction>): void;
|
|
20
|
+
setRawTransactions(rawTransactions: Array<any>): void;
|
|
21
|
+
setBalance(balance: string | number): void;
|
|
22
|
+
setStats(txsCount: string | number, fundedSum: string | number, spentSum: string | number): void;
|
|
23
|
+
addFundedOperation(funded: Operation): void;
|
|
24
|
+
getFundedOperations(): Operation[];
|
|
25
|
+
addSentOperation(sent: Operation): void;
|
|
26
|
+
getSentOperations(): Operation[];
|
|
27
|
+
toString(): string;
|
|
28
|
+
asCashAddress(): string | undefined;
|
|
29
|
+
getDerivationMode(): DerivationMode;
|
|
30
|
+
getDerivation(): {
|
|
31
|
+
account: number;
|
|
32
|
+
index: number;
|
|
33
|
+
};
|
|
34
|
+
getBalance(): string;
|
|
35
|
+
getStats(): Stats;
|
|
36
|
+
getTransactions(): Transaction[];
|
|
37
|
+
getRawTransactions(): any[];
|
|
38
|
+
isUTXO(): boolean;
|
|
39
|
+
}
|
|
40
|
+
export { Address };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Address = void 0;
|
|
7
|
+
const currencies_1 = require("../configuration/currencies");
|
|
8
|
+
const stats_1 = require("./stats");
|
|
9
|
+
const deriveAddresses_1 = require("../actions/deriveAddresses");
|
|
10
|
+
const helpers_1 = require("../helpers");
|
|
11
|
+
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
12
|
+
class Address {
|
|
13
|
+
constructor(itemToScan, derivationMode, account, index) {
|
|
14
|
+
if (derivationMode) {
|
|
15
|
+
this.address = (0, deriveAddresses_1.deriveAddress)(derivationMode, itemToScan, account, index);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
this.address = itemToScan;
|
|
19
|
+
}
|
|
20
|
+
this.derivationMode = derivationMode;
|
|
21
|
+
this.account = account;
|
|
22
|
+
this.index = index;
|
|
23
|
+
this.ins = [];
|
|
24
|
+
this.outs = [];
|
|
25
|
+
this.utxo = false;
|
|
26
|
+
}
|
|
27
|
+
setTransactions(transactions) {
|
|
28
|
+
this.transactions = transactions;
|
|
29
|
+
}
|
|
30
|
+
setRawTransactions(rawTransactions) {
|
|
31
|
+
this.rawTransactions = rawTransactions;
|
|
32
|
+
}
|
|
33
|
+
setBalance(balance) {
|
|
34
|
+
this.balance = new bignumber_js_1.default(balance);
|
|
35
|
+
if (!this.balance.isZero()) {
|
|
36
|
+
this.utxo = true;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.utxo = false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
setStats(txsCount, fundedSum, spentSum) {
|
|
43
|
+
this.stats = new stats_1.Stats();
|
|
44
|
+
this.stats.txsCount = new bignumber_js_1.default(txsCount);
|
|
45
|
+
this.stats.funded = new bignumber_js_1.default(fundedSum);
|
|
46
|
+
this.stats.spent = new bignumber_js_1.default(spentSum);
|
|
47
|
+
}
|
|
48
|
+
addFundedOperation(funded) {
|
|
49
|
+
this.ins.push(funded);
|
|
50
|
+
}
|
|
51
|
+
getFundedOperations() {
|
|
52
|
+
return this.ins;
|
|
53
|
+
}
|
|
54
|
+
addSentOperation(sent) {
|
|
55
|
+
this.outs.push(sent);
|
|
56
|
+
}
|
|
57
|
+
getSentOperations() {
|
|
58
|
+
return this.outs;
|
|
59
|
+
}
|
|
60
|
+
toString() {
|
|
61
|
+
return this.address;
|
|
62
|
+
}
|
|
63
|
+
// render as Cash Address (Bitcoin Cash)
|
|
64
|
+
asCashAddress() {
|
|
65
|
+
if (this.derivationMode === currencies_1.DerivationMode.BCH) {
|
|
66
|
+
return (0, helpers_1.toUnprefixedCashAddress)(this.address);
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
getDerivationMode() {
|
|
71
|
+
return this.derivationMode;
|
|
72
|
+
}
|
|
73
|
+
getDerivation() {
|
|
74
|
+
return {
|
|
75
|
+
account: this.account,
|
|
76
|
+
index: this.index,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
getBalance() {
|
|
80
|
+
return this.balance.toFixed();
|
|
81
|
+
}
|
|
82
|
+
getStats() {
|
|
83
|
+
return this.stats;
|
|
84
|
+
}
|
|
85
|
+
getTransactions() {
|
|
86
|
+
return this.transactions;
|
|
87
|
+
}
|
|
88
|
+
getRawTransactions() {
|
|
89
|
+
const rawTransactions = this.rawTransactions;
|
|
90
|
+
if (typeof rawTransactions === "undefined") {
|
|
91
|
+
return []; // if no transaction, return an empty array
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
return rawTransactions;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
isUTXO() {
|
|
98
|
+
return this.utxo;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
exports.Address = Address;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Operation } from "./operation";
|
|
2
|
+
type ComparisonStatus = "Match" | "Match (aggregated)" | "Missing (aggregated)" | "Mismatch: addresses" | "Mismatch: amounts" | "Mismatch: token amounts" | "Mismatch: token tickers" | "Mismatch: Dapp" | "Missing Operation" | "Extra Operation" | "Skipped";
|
|
3
|
+
declare class Comparison {
|
|
4
|
+
imported: Operation | undefined;
|
|
5
|
+
actual: Operation | undefined;
|
|
6
|
+
status: ComparisonStatus;
|
|
7
|
+
}
|
|
8
|
+
export { Comparison, ComparisonStatus };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as bjs from "bitcoinjs-lib";
|
|
2
|
+
import { DerivationMode } from "../configuration/currencies";
|
|
3
|
+
declare class Currency {
|
|
4
|
+
name: string;
|
|
5
|
+
symbol: string;
|
|
6
|
+
network?: bjs.networks.Network;
|
|
7
|
+
derivationModes?: Array<DerivationMode>;
|
|
8
|
+
precision: number;
|
|
9
|
+
utxo_based: boolean;
|
|
10
|
+
}
|
|
11
|
+
export { Currency };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import BigNumber from "bignumber.js";
|
|
2
|
+
type OperationType = "Received" | "Received (non-sibling to change)" | "Received (token)" | "Sent" | "Sent (token)" | "Sent to self" | "Sent to sibling" | "Failed to send" | "SCI (caller)" | "SCI (recipient)" | "Swapped";
|
|
3
|
+
declare class Operation {
|
|
4
|
+
operationType: OperationType;
|
|
5
|
+
txid: string;
|
|
6
|
+
date: string;
|
|
7
|
+
block: number;
|
|
8
|
+
address: string;
|
|
9
|
+
cashAddress?: string;
|
|
10
|
+
amount: BigNumber;
|
|
11
|
+
token: {
|
|
12
|
+
name: string;
|
|
13
|
+
symbol: string;
|
|
14
|
+
amount: BigNumber;
|
|
15
|
+
};
|
|
16
|
+
dapp: {
|
|
17
|
+
contract_name: string;
|
|
18
|
+
};
|
|
19
|
+
constructor(date?: string, amount?: BigNumber | string);
|
|
20
|
+
setTxid(txid: string): void;
|
|
21
|
+
getTxid(): string;
|
|
22
|
+
setBlockNumber(blockNumber: number): void;
|
|
23
|
+
getBlockNumber(): number;
|
|
24
|
+
setAddress(address?: string): void;
|
|
25
|
+
setCashAddress(cashAddress: string | undefined): void;
|
|
26
|
+
getAddress(): string;
|
|
27
|
+
getCashAddress(): string | undefined;
|
|
28
|
+
setOperationType(operationType: OperationType): void;
|
|
29
|
+
getOperationType(): OperationType;
|
|
30
|
+
addToken(symbol: string, name: string, amount: BigNumber): void;
|
|
31
|
+
addDapp(contract_name: string): void;
|
|
32
|
+
}
|
|
33
|
+
export { Operation, OperationType };
|