@pioneer-platform/pioneer-history 0.2.0 → 0.4.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/CHANGELOG.md +19 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +70 -21
- package/lib/schemas/history-response.d.ts +91 -0
- package/lib/schemas/history-response.js +21 -1
- package/lib/services/swap-detector.d.ts +54 -0
- package/lib/services/swap-detector.js +353 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @pioneer-platform/pioneer-history
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- chore: feat(pioneer-sdk): Add ERC-20/BEP-20 token table to portfolio dashboard
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
- @pioneer-platform/cosmos-network@8.27.0
|
|
13
|
+
- @pioneer-platform/eth-network@8.31.0
|
|
14
|
+
- @pioneer-platform/utxo-network@8.28.0
|
|
15
|
+
|
|
16
|
+
## 0.3.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- feat(pioneer-sdk): Add ERC-20/BEP-20 token table to portfolio dashboard
|
|
21
|
+
|
|
3
22
|
## 0.2.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -71,6 +71,8 @@ exports.History = exports.SUPPORTED_CAIPS = exports.OTHER_SUPPORT = exports.TEND
|
|
|
71
71
|
var TAG = " | pioneer-history | ";
|
|
72
72
|
var log = require('@pioneer-platform/loggerdog')();
|
|
73
73
|
var caipToNetworkId = require('@pioneer-platform/pioneer-caip').caipToNetworkId;
|
|
74
|
+
// Swap detection
|
|
75
|
+
var swap_detector_1 = require("./services/swap-detector");
|
|
74
76
|
// CAIP support constants (reuse from pioneer-balance)
|
|
75
77
|
exports.UTXO_SUPPORT = [
|
|
76
78
|
'bip122:000000000019d6689c085ae165831e93/slip44:0', // BTC
|
|
@@ -99,9 +101,19 @@ exports.SUPPORTED_CAIPS = {
|
|
|
99
101
|
__exportStar(require("./schemas/history-response"), exports);
|
|
100
102
|
var History = /** @class */ (function () {
|
|
101
103
|
function History(config) {
|
|
104
|
+
this.swapDetector = null;
|
|
102
105
|
log.debug(TAG, "🏗️ History constructor called");
|
|
103
106
|
this.blockchains = config.wss || [];
|
|
104
107
|
this.nodes = config.nodes || [];
|
|
108
|
+
this.pendingSwapsService = config.pendingSwapsService || null;
|
|
109
|
+
// Initialize swap detector with pendingSwapsService (enables Layer 1 DB lookup)
|
|
110
|
+
this.swapDetector = new swap_detector_1.SwapDetector(this.pendingSwapsService, log);
|
|
111
|
+
if (this.pendingSwapsService) {
|
|
112
|
+
log.info(TAG, "✅ SwapDetector initialized with DB service (Layer 1 enabled)");
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
log.warn(TAG, "⚠️ SwapDetector initialized without DB service (Layer 1 disabled - only memo/contract detection active)");
|
|
116
|
+
}
|
|
105
117
|
// CRITICAL: Use globally initialized networks if available (server environment)
|
|
106
118
|
var globalNetworks = global.pioneerNetworks;
|
|
107
119
|
if (globalNetworks) {
|
|
@@ -373,9 +385,9 @@ var History = /** @class */ (function () {
|
|
|
373
385
|
};
|
|
374
386
|
History.prototype.getHistory = function (query, options) {
|
|
375
387
|
return __awaiter(this, void 0, void 0, function () {
|
|
376
|
-
var tag, queries, results, _i, queries_1, q, networkId, type, asset, pubkey, _a, networkIdToSymbol, coin, rawTxs, rawTxs, rawTxs, rawTxs, error_1;
|
|
377
|
-
return __generator(this, function (
|
|
378
|
-
switch (
|
|
388
|
+
var tag, queries, results, _i, queries_1, q, networkId, type, asset, pubkey, _a, networkIdToSymbol, coin, rawTxs, rawTxs, rawTxs, rawTxs, error_1, allTransactions, _b, results_1, result, swapMetadata, _c, results_2, result, _d, _e, tx, metadata, error_2;
|
|
389
|
+
return __generator(this, function (_f) {
|
|
390
|
+
switch (_f.label) {
|
|
379
391
|
case 0:
|
|
380
392
|
tag = TAG + " | getHistory | ";
|
|
381
393
|
log.debug(tag, "🔍 HISTORY QUERY START");
|
|
@@ -383,7 +395,7 @@ var History = /** @class */ (function () {
|
|
|
383
395
|
log.debug(tag, "Processing ".concat(queries.length, " ").concat(queries.length === 1 ? 'query' : 'queries'));
|
|
384
396
|
results = [];
|
|
385
397
|
_i = 0, queries_1 = queries;
|
|
386
|
-
|
|
398
|
+
_f.label = 1;
|
|
387
399
|
case 1:
|
|
388
400
|
if (!(_i < queries_1.length)) return [3 /*break*/, 30];
|
|
389
401
|
q = queries_1[_i];
|
|
@@ -396,13 +408,13 @@ var History = /** @class */ (function () {
|
|
|
396
408
|
networkId = caipToNetworkId(q.caip);
|
|
397
409
|
return [4 /*yield*/, this.classifyCaip(q.caip)];
|
|
398
410
|
case 2:
|
|
399
|
-
type =
|
|
411
|
+
type = _f.sent();
|
|
400
412
|
log.debug(tag, "🎯 Classified CAIP type:", type);
|
|
401
413
|
asset = { caip: q.caip };
|
|
402
414
|
pubkey = { pubkey: q.pubkey };
|
|
403
|
-
|
|
415
|
+
_f.label = 3;
|
|
404
416
|
case 3:
|
|
405
|
-
|
|
417
|
+
_f.trys.push([3, 28, , 29]);
|
|
406
418
|
_a = type;
|
|
407
419
|
switch (_a) {
|
|
408
420
|
case 'UTXO': return [3 /*break*/, 4];
|
|
@@ -428,7 +440,7 @@ var History = /** @class */ (function () {
|
|
|
428
440
|
log.debug(tag, 'Fetching UTXO transactions for', coin);
|
|
429
441
|
return [4 /*yield*/, this.networks.networks.utxo.txsByXpub(coin, pubkey.pubkey)];
|
|
430
442
|
case 5:
|
|
431
|
-
rawTxs =
|
|
443
|
+
rawTxs = _f.sent();
|
|
432
444
|
log.debug(tag, "Received ".concat((rawTxs === null || rawTxs === void 0 ? void 0 : rawTxs.length) || 0, " UTXO transactions"));
|
|
433
445
|
asset.transactions = this.normalizeUtxoTransactions(rawTxs || [], pubkey.pubkey, q.caip);
|
|
434
446
|
results.push(asset);
|
|
@@ -438,14 +450,14 @@ var History = /** @class */ (function () {
|
|
|
438
450
|
if (!this.networks.networks.ethereum.getTransactionsByNetwork) return [3 /*break*/, 8];
|
|
439
451
|
return [4 /*yield*/, this.networks.networks.ethereum.getTransactionsByNetwork(networkId, pubkey.pubkey, options)];
|
|
440
452
|
case 7:
|
|
441
|
-
rawTxs =
|
|
453
|
+
rawTxs = _f.sent();
|
|
442
454
|
log.debug(tag, "Received ".concat((rawTxs === null || rawTxs === void 0 ? void 0 : rawTxs.length) || 0, " EVM transactions"));
|
|
443
455
|
asset.transactions = this.normalizeEvmTransactions(rawTxs || [], pubkey.pubkey, q.caip);
|
|
444
456
|
return [3 /*break*/, 9];
|
|
445
457
|
case 8:
|
|
446
458
|
log.warn(tag, 'EVM transaction history not available - method not found');
|
|
447
459
|
asset.transactions = [];
|
|
448
|
-
|
|
460
|
+
_f.label = 9;
|
|
449
461
|
case 9:
|
|
450
462
|
results.push(asset);
|
|
451
463
|
return [3 /*break*/, 27];
|
|
@@ -456,32 +468,32 @@ var History = /** @class */ (function () {
|
|
|
456
468
|
if (!this.networks.networks.mayachain.getTransactions) return [3 /*break*/, 12];
|
|
457
469
|
return [4 /*yield*/, this.networks.networks.mayachain.getTransactions(pubkey.pubkey)];
|
|
458
470
|
case 11:
|
|
459
|
-
rawTxs =
|
|
460
|
-
|
|
471
|
+
rawTxs = _f.sent();
|
|
472
|
+
_f.label = 12;
|
|
461
473
|
case 12: return [3 /*break*/, 21];
|
|
462
474
|
case 13:
|
|
463
475
|
if (!q.caip.startsWith('cosmos:osmosis-1')) return [3 /*break*/, 16];
|
|
464
476
|
if (!this.networks.networks.osmosis.getTransactions) return [3 /*break*/, 15];
|
|
465
477
|
return [4 /*yield*/, this.networks.networks.osmosis.getTransactions(pubkey.pubkey)];
|
|
466
478
|
case 14:
|
|
467
|
-
rawTxs =
|
|
468
|
-
|
|
479
|
+
rawTxs = _f.sent();
|
|
480
|
+
_f.label = 15;
|
|
469
481
|
case 15: return [3 /*break*/, 21];
|
|
470
482
|
case 16:
|
|
471
483
|
if (!q.caip.startsWith('cosmos:thorchain-mainnet-v1')) return [3 /*break*/, 19];
|
|
472
484
|
if (!this.networks.networks.thorchain.getTransactions) return [3 /*break*/, 18];
|
|
473
485
|
return [4 /*yield*/, this.networks.networks.thorchain.getTransactions(pubkey.pubkey)];
|
|
474
486
|
case 17:
|
|
475
|
-
rawTxs =
|
|
476
|
-
|
|
487
|
+
rawTxs = _f.sent();
|
|
488
|
+
_f.label = 18;
|
|
477
489
|
case 18: return [3 /*break*/, 21];
|
|
478
490
|
case 19:
|
|
479
491
|
if (!q.caip.startsWith('cosmos:cosmoshub-4')) return [3 /*break*/, 21];
|
|
480
492
|
if (!this.networks.networks.cosmos.getTransactions) return [3 /*break*/, 21];
|
|
481
493
|
return [4 /*yield*/, this.networks.networks.cosmos.getTransactions(pubkey.pubkey)];
|
|
482
494
|
case 20:
|
|
483
|
-
rawTxs =
|
|
484
|
-
|
|
495
|
+
rawTxs = _f.sent();
|
|
496
|
+
_f.label = 21;
|
|
485
497
|
case 21:
|
|
486
498
|
log.debug(tag, "Received ".concat((rawTxs === null || rawTxs === void 0 ? void 0 : rawTxs.length) || 0, " Tendermint transactions"));
|
|
487
499
|
asset.transactions = this.normalizeTendermintTransactions(rawTxs || [], pubkey.pubkey, q.caip);
|
|
@@ -493,21 +505,21 @@ var History = /** @class */ (function () {
|
|
|
493
505
|
if (!this.networks.networks.ripple.getTransactions) return [3 /*break*/, 24];
|
|
494
506
|
return [4 /*yield*/, this.networks.networks.ripple.getTransactions(pubkey.pubkey)];
|
|
495
507
|
case 23:
|
|
496
|
-
rawTxs =
|
|
508
|
+
rawTxs = _f.sent();
|
|
497
509
|
log.debug(tag, "Received ".concat((rawTxs === null || rawTxs === void 0 ? void 0 : rawTxs.length) || 0, " Ripple transactions"));
|
|
498
510
|
asset.transactions = this.normalizeRippleTransactions(rawTxs || [], pubkey.pubkey, q.caip);
|
|
499
511
|
return [3 /*break*/, 25];
|
|
500
512
|
case 24:
|
|
501
513
|
log.warn(tag, 'Ripple transaction history not available');
|
|
502
514
|
asset.transactions = [];
|
|
503
|
-
|
|
515
|
+
_f.label = 25;
|
|
504
516
|
case 25:
|
|
505
517
|
results.push(asset);
|
|
506
518
|
return [3 /*break*/, 27];
|
|
507
519
|
case 26: throw new Error("FAIL FAST: Unsupported chain type: ".concat(type));
|
|
508
520
|
case 27: return [3 /*break*/, 29];
|
|
509
521
|
case 28:
|
|
510
|
-
error_1 =
|
|
522
|
+
error_1 = _f.sent();
|
|
511
523
|
log.error(tag, "Error fetching history for ".concat(q.caip, ":"), error_1);
|
|
512
524
|
// Add empty result so batch processing continues
|
|
513
525
|
asset.transactions = [];
|
|
@@ -518,6 +530,43 @@ var History = /** @class */ (function () {
|
|
|
518
530
|
_i++;
|
|
519
531
|
return [3 /*break*/, 1];
|
|
520
532
|
case 30:
|
|
533
|
+
if (!(this.swapDetector && results.length > 0)) return [3 /*break*/, 35];
|
|
534
|
+
_f.label = 31;
|
|
535
|
+
case 31:
|
|
536
|
+
_f.trys.push([31, 34, , 35]);
|
|
537
|
+
allTransactions = [];
|
|
538
|
+
for (_b = 0, results_1 = results; _b < results_1.length; _b++) {
|
|
539
|
+
result = results_1[_b];
|
|
540
|
+
if (result.transactions && Array.isArray(result.transactions)) {
|
|
541
|
+
allTransactions.push.apply(allTransactions, result.transactions);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
if (!(allTransactions.length > 0)) return [3 /*break*/, 33];
|
|
545
|
+
log.debug(tag, "Running swap detection on ".concat(allTransactions.length, " transactions"));
|
|
546
|
+
return [4 /*yield*/, this.swapDetector.detectSwaps(allTransactions)];
|
|
547
|
+
case 32:
|
|
548
|
+
swapMetadata = _f.sent();
|
|
549
|
+
// Enrich each transaction with swap metadata
|
|
550
|
+
for (_c = 0, results_2 = results; _c < results_2.length; _c++) {
|
|
551
|
+
result = results_2[_c];
|
|
552
|
+
if (result.transactions && Array.isArray(result.transactions)) {
|
|
553
|
+
for (_d = 0, _e = result.transactions; _d < _e.length; _d++) {
|
|
554
|
+
tx = _e[_d];
|
|
555
|
+
metadata = swapMetadata.get(tx.txid);
|
|
556
|
+
if (metadata && metadata.isSwap) {
|
|
557
|
+
tx.swapMetadata = metadata;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
log.debug(tag, "Enriched ".concat(swapMetadata.size, " swap transactions"));
|
|
563
|
+
_f.label = 33;
|
|
564
|
+
case 33: return [3 /*break*/, 35];
|
|
565
|
+
case 34:
|
|
566
|
+
error_2 = _f.sent();
|
|
567
|
+
log.error(tag, 'Swap detection failed (non-critical):', error_2.message);
|
|
568
|
+
return [3 /*break*/, 35];
|
|
569
|
+
case 35:
|
|
521
570
|
log.debug(tag, "✅ HISTORY QUERY COMPLETE");
|
|
522
571
|
// Return single result if single query, array if batch
|
|
523
572
|
return [2 /*return*/, Array.isArray(query) ? results : results[0]];
|
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Swap metadata schema
|
|
4
|
+
*/
|
|
5
|
+
export declare const SwapMetadataSchema: z.ZodObject<{
|
|
6
|
+
isSwap: z.ZodBoolean;
|
|
7
|
+
swapId: z.ZodOptional<z.ZodString>;
|
|
8
|
+
protocol: z.ZodOptional<z.ZodString>;
|
|
9
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
10
|
+
PENDING: "PENDING";
|
|
11
|
+
CONFIRMING: "CONFIRMING";
|
|
12
|
+
COMPLETED: "COMPLETED";
|
|
13
|
+
FAILED: "FAILED";
|
|
14
|
+
REFUNDED: "REFUNDED";
|
|
15
|
+
}>>;
|
|
16
|
+
fromAsset: z.ZodOptional<z.ZodString>;
|
|
17
|
+
toAsset: z.ZodOptional<z.ZodString>;
|
|
18
|
+
fromAmount: z.ZodOptional<z.ZodString>;
|
|
19
|
+
toAmount: z.ZodOptional<z.ZodString>;
|
|
20
|
+
destinationAddress: z.ZodOptional<z.ZodString>;
|
|
21
|
+
minimumReceived: z.ZodOptional<z.ZodString>;
|
|
22
|
+
userMessage: z.ZodOptional<z.ZodString>;
|
|
23
|
+
estimatedCompletionTime: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
inboundTxHash: z.ZodOptional<z.ZodString>;
|
|
25
|
+
outboundTxHash: z.ZodOptional<z.ZodString>;
|
|
26
|
+
}, z.core.$strip>;
|
|
2
27
|
/**
|
|
3
28
|
* Transaction schema for API responses
|
|
4
29
|
*/
|
|
@@ -34,6 +59,28 @@ export declare const TransactionSchema: z.ZodObject<{
|
|
|
34
59
|
fee: z.ZodOptional<z.ZodString>;
|
|
35
60
|
memo: z.ZodOptional<z.ZodString>;
|
|
36
61
|
raw: z.ZodOptional<z.ZodAny>;
|
|
62
|
+
swapMetadata: z.ZodOptional<z.ZodObject<{
|
|
63
|
+
isSwap: z.ZodBoolean;
|
|
64
|
+
swapId: z.ZodOptional<z.ZodString>;
|
|
65
|
+
protocol: z.ZodOptional<z.ZodString>;
|
|
66
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
67
|
+
PENDING: "PENDING";
|
|
68
|
+
CONFIRMING: "CONFIRMING";
|
|
69
|
+
COMPLETED: "COMPLETED";
|
|
70
|
+
FAILED: "FAILED";
|
|
71
|
+
REFUNDED: "REFUNDED";
|
|
72
|
+
}>>;
|
|
73
|
+
fromAsset: z.ZodOptional<z.ZodString>;
|
|
74
|
+
toAsset: z.ZodOptional<z.ZodString>;
|
|
75
|
+
fromAmount: z.ZodOptional<z.ZodString>;
|
|
76
|
+
toAmount: z.ZodOptional<z.ZodString>;
|
|
77
|
+
destinationAddress: z.ZodOptional<z.ZodString>;
|
|
78
|
+
minimumReceived: z.ZodOptional<z.ZodString>;
|
|
79
|
+
userMessage: z.ZodOptional<z.ZodString>;
|
|
80
|
+
estimatedCompletionTime: z.ZodOptional<z.ZodNumber>;
|
|
81
|
+
inboundTxHash: z.ZodOptional<z.ZodString>;
|
|
82
|
+
outboundTxHash: z.ZodOptional<z.ZodString>;
|
|
83
|
+
}, z.core.$strip>>;
|
|
37
84
|
}, z.core.$strip>;
|
|
38
85
|
/**
|
|
39
86
|
* Individual history result schema
|
|
@@ -73,6 +120,28 @@ export declare const HistoryResultSchema: z.ZodObject<{
|
|
|
73
120
|
fee: z.ZodOptional<z.ZodString>;
|
|
74
121
|
memo: z.ZodOptional<z.ZodString>;
|
|
75
122
|
raw: z.ZodOptional<z.ZodAny>;
|
|
123
|
+
swapMetadata: z.ZodOptional<z.ZodObject<{
|
|
124
|
+
isSwap: z.ZodBoolean;
|
|
125
|
+
swapId: z.ZodOptional<z.ZodString>;
|
|
126
|
+
protocol: z.ZodOptional<z.ZodString>;
|
|
127
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
128
|
+
PENDING: "PENDING";
|
|
129
|
+
CONFIRMING: "CONFIRMING";
|
|
130
|
+
COMPLETED: "COMPLETED";
|
|
131
|
+
FAILED: "FAILED";
|
|
132
|
+
REFUNDED: "REFUNDED";
|
|
133
|
+
}>>;
|
|
134
|
+
fromAsset: z.ZodOptional<z.ZodString>;
|
|
135
|
+
toAsset: z.ZodOptional<z.ZodString>;
|
|
136
|
+
fromAmount: z.ZodOptional<z.ZodString>;
|
|
137
|
+
toAmount: z.ZodOptional<z.ZodString>;
|
|
138
|
+
destinationAddress: z.ZodOptional<z.ZodString>;
|
|
139
|
+
minimumReceived: z.ZodOptional<z.ZodString>;
|
|
140
|
+
userMessage: z.ZodOptional<z.ZodString>;
|
|
141
|
+
estimatedCompletionTime: z.ZodOptional<z.ZodNumber>;
|
|
142
|
+
inboundTxHash: z.ZodOptional<z.ZodString>;
|
|
143
|
+
outboundTxHash: z.ZodOptional<z.ZodString>;
|
|
144
|
+
}, z.core.$strip>>;
|
|
76
145
|
}, z.core.$strip>>;
|
|
77
146
|
fetchedAt: z.ZodNumber;
|
|
78
147
|
fetchedAtISO: z.ZodString;
|
|
@@ -120,6 +189,28 @@ export declare const TransactionHistoryResponseSchema: z.ZodObject<{
|
|
|
120
189
|
fee: z.ZodOptional<z.ZodString>;
|
|
121
190
|
memo: z.ZodOptional<z.ZodString>;
|
|
122
191
|
raw: z.ZodOptional<z.ZodAny>;
|
|
192
|
+
swapMetadata: z.ZodOptional<z.ZodObject<{
|
|
193
|
+
isSwap: z.ZodBoolean;
|
|
194
|
+
swapId: z.ZodOptional<z.ZodString>;
|
|
195
|
+
protocol: z.ZodOptional<z.ZodString>;
|
|
196
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
197
|
+
PENDING: "PENDING";
|
|
198
|
+
CONFIRMING: "CONFIRMING";
|
|
199
|
+
COMPLETED: "COMPLETED";
|
|
200
|
+
FAILED: "FAILED";
|
|
201
|
+
REFUNDED: "REFUNDED";
|
|
202
|
+
}>>;
|
|
203
|
+
fromAsset: z.ZodOptional<z.ZodString>;
|
|
204
|
+
toAsset: z.ZodOptional<z.ZodString>;
|
|
205
|
+
fromAmount: z.ZodOptional<z.ZodString>;
|
|
206
|
+
toAmount: z.ZodOptional<z.ZodString>;
|
|
207
|
+
destinationAddress: z.ZodOptional<z.ZodString>;
|
|
208
|
+
minimumReceived: z.ZodOptional<z.ZodString>;
|
|
209
|
+
userMessage: z.ZodOptional<z.ZodString>;
|
|
210
|
+
estimatedCompletionTime: z.ZodOptional<z.ZodNumber>;
|
|
211
|
+
inboundTxHash: z.ZodOptional<z.ZodString>;
|
|
212
|
+
outboundTxHash: z.ZodOptional<z.ZodString>;
|
|
213
|
+
}, z.core.$strip>>;
|
|
123
214
|
}, z.core.$strip>>;
|
|
124
215
|
fetchedAt: z.ZodNumber;
|
|
125
216
|
fetchedAtISO: z.ZodString;
|
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TransactionHistoryResponseSchema = exports.HistoryResultSchema = exports.TransactionSchema = void 0;
|
|
3
|
+
exports.TransactionHistoryResponseSchema = exports.HistoryResultSchema = exports.TransactionSchema = exports.SwapMetadataSchema = void 0;
|
|
4
4
|
var zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* Swap metadata schema
|
|
7
|
+
*/
|
|
8
|
+
exports.SwapMetadataSchema = zod_1.z.object({
|
|
9
|
+
isSwap: zod_1.z.boolean(),
|
|
10
|
+
swapId: zod_1.z.string().optional(),
|
|
11
|
+
protocol: zod_1.z.string().optional(),
|
|
12
|
+
status: zod_1.z.enum(['PENDING', 'CONFIRMING', 'COMPLETED', 'FAILED', 'REFUNDED']).optional(),
|
|
13
|
+
fromAsset: zod_1.z.string().optional(),
|
|
14
|
+
toAsset: zod_1.z.string().optional(),
|
|
15
|
+
fromAmount: zod_1.z.string().optional(),
|
|
16
|
+
toAmount: zod_1.z.string().optional(),
|
|
17
|
+
destinationAddress: zod_1.z.string().optional(),
|
|
18
|
+
minimumReceived: zod_1.z.string().optional(),
|
|
19
|
+
userMessage: zod_1.z.string().optional(),
|
|
20
|
+
estimatedCompletionTime: zod_1.z.number().optional(),
|
|
21
|
+
inboundTxHash: zod_1.z.string().optional(),
|
|
22
|
+
outboundTxHash: zod_1.z.string().optional(),
|
|
23
|
+
});
|
|
5
24
|
/**
|
|
6
25
|
* Transaction schema for API responses
|
|
7
26
|
*/
|
|
@@ -21,6 +40,7 @@ exports.TransactionSchema = zod_1.z.object({
|
|
|
21
40
|
fee: zod_1.z.string().optional(),
|
|
22
41
|
memo: zod_1.z.string().optional(),
|
|
23
42
|
raw: zod_1.z.any().optional(),
|
|
43
|
+
swapMetadata: exports.SwapMetadataSchema.optional(),
|
|
24
44
|
});
|
|
25
45
|
/**
|
|
26
46
|
* Individual history result schema
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Transaction } from '../index';
|
|
2
|
+
/**
|
|
3
|
+
* Swap metadata attached to transactions
|
|
4
|
+
*/
|
|
5
|
+
export interface SwapMetadata {
|
|
6
|
+
isSwap: boolean;
|
|
7
|
+
swapId?: string;
|
|
8
|
+
protocol?: string;
|
|
9
|
+
status?: 'PENDING' | 'CONFIRMING' | 'COMPLETED' | 'FAILED' | 'REFUNDED';
|
|
10
|
+
fromAsset?: string;
|
|
11
|
+
toAsset?: string;
|
|
12
|
+
fromAmount?: string;
|
|
13
|
+
toAmount?: string;
|
|
14
|
+
destinationAddress?: string;
|
|
15
|
+
minimumReceived?: string;
|
|
16
|
+
inboundTxHash?: string;
|
|
17
|
+
outboundTxHash?: string;
|
|
18
|
+
userMessage?: string;
|
|
19
|
+
estimatedCompletionTime?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Detect if transaction is a swap and enrich with metadata
|
|
23
|
+
*/
|
|
24
|
+
export declare class SwapDetector {
|
|
25
|
+
private pendingSwapsService;
|
|
26
|
+
private log;
|
|
27
|
+
constructor(pendingSwapsService: any, log: any);
|
|
28
|
+
/**
|
|
29
|
+
* Detect swaps in batch of transactions
|
|
30
|
+
*/
|
|
31
|
+
detectSwaps(transactions: Transaction[]): Promise<Map<string, SwapMetadata>>;
|
|
32
|
+
/**
|
|
33
|
+
* Parse Thorchain/Maya memo format using pioneer-coins parseMemo
|
|
34
|
+
* Handles both verbose (SWAP:asset:address) and shorthand (=:asset:address) formats
|
|
35
|
+
*/
|
|
36
|
+
private parseMemo;
|
|
37
|
+
/**
|
|
38
|
+
* Detect DEX contract addresses
|
|
39
|
+
*/
|
|
40
|
+
private detectDexContract;
|
|
41
|
+
/**
|
|
42
|
+
* Generate user-friendly status message
|
|
43
|
+
*/
|
|
44
|
+
private generateUserMessage;
|
|
45
|
+
/**
|
|
46
|
+
* Estimate completion time based on swap status
|
|
47
|
+
*/
|
|
48
|
+
private estimateCompletionTime;
|
|
49
|
+
/**
|
|
50
|
+
* Query Midgard API for outbound transaction hash
|
|
51
|
+
* Queries both THORChain and Maya Midgard endpoints
|
|
52
|
+
*/
|
|
53
|
+
private queryMidgardForOutbound;
|
|
54
|
+
}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Swap Detection Service
|
|
4
|
+
|
|
5
|
+
Multi-layered detection strategy for identifying swap transactions:
|
|
6
|
+
1. Pending Swaps DB Lookup (PRIMARY - highest accuracy)
|
|
7
|
+
2. Memo Parsing (FALLBACK - Thorchain/Maya format detection)
|
|
8
|
+
3. Contract Address Detection (EVM ONLY - DEX router matching)
|
|
9
|
+
*/
|
|
10
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
11
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
12
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
13
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
14
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
15
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
16
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
20
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
21
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
22
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
23
|
+
function step(op) {
|
|
24
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
25
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
26
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
27
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
28
|
+
switch (op[0]) {
|
|
29
|
+
case 0: case 1: t = op; break;
|
|
30
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
31
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
32
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
33
|
+
default:
|
|
34
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
35
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
36
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
37
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
38
|
+
if (t[2]) _.ops.pop();
|
|
39
|
+
_.trys.pop(); continue;
|
|
40
|
+
}
|
|
41
|
+
op = body.call(thisArg, _);
|
|
42
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
43
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
exports.SwapDetector = void 0;
|
|
48
|
+
var TAG = ' | swap-detector | ';
|
|
49
|
+
/**
|
|
50
|
+
* Detect if transaction is a swap and enrich with metadata
|
|
51
|
+
*/
|
|
52
|
+
var SwapDetector = /** @class */ (function () {
|
|
53
|
+
function SwapDetector(pendingSwapsService, log) {
|
|
54
|
+
this.pendingSwapsService = pendingSwapsService;
|
|
55
|
+
this.log = log;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Detect swaps in batch of transactions
|
|
59
|
+
*/
|
|
60
|
+
SwapDetector.prototype.detectSwaps = function (transactions) {
|
|
61
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
62
|
+
var tag, swapMetadata, txids, pendingSwaps, _i, pendingSwaps_1, swap, metadata, error_1, _a, transactions_1, tx, memoMetadata, swapsNeedingOutbound, outboundPromises, _b, transactions_2, tx, contractMetadata;
|
|
63
|
+
var _this = this;
|
|
64
|
+
var _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
65
|
+
return __generator(this, function (_s) {
|
|
66
|
+
switch (_s.label) {
|
|
67
|
+
case 0:
|
|
68
|
+
tag = TAG + ' | detectSwaps | ';
|
|
69
|
+
swapMetadata = new Map();
|
|
70
|
+
txids = transactions.map(function (tx) { return tx.txid; });
|
|
71
|
+
if (!this.pendingSwapsService) return [3 /*break*/, 4];
|
|
72
|
+
_s.label = 1;
|
|
73
|
+
case 1:
|
|
74
|
+
_s.trys.push([1, 3, , 4]);
|
|
75
|
+
console.log(tag, "\uD83D\uDD0D Running swap detection on ".concat(txids.length, " transactions"));
|
|
76
|
+
return [4 /*yield*/, this.pendingSwapsService.findByTxids(txids)];
|
|
77
|
+
case 2:
|
|
78
|
+
pendingSwaps = _s.sent();
|
|
79
|
+
console.log(tag, "\u2705 DB lookup found ".concat(pendingSwaps.length, " swaps"));
|
|
80
|
+
for (_i = 0, pendingSwaps_1 = pendingSwaps; _i < pendingSwaps_1.length; _i++) {
|
|
81
|
+
swap = pendingSwaps_1[_i];
|
|
82
|
+
metadata = {
|
|
83
|
+
isSwap: true,
|
|
84
|
+
swapId: ((_c = swap._id) === null || _c === void 0 ? void 0 : _c.toString()) || swap._id,
|
|
85
|
+
protocol: swap.integration,
|
|
86
|
+
status: swap.status.toUpperCase(),
|
|
87
|
+
// Use CAIPs directly - more exact than symbols
|
|
88
|
+
fromAsset: ((_d = swap.sellAsset) === null || _d === void 0 ? void 0 : _d.caip) || ((_e = swap.sellAsset) === null || _e === void 0 ? void 0 : _e.symbol),
|
|
89
|
+
toAsset: ((_f = swap.buyAsset) === null || _f === void 0 ? void 0 : _f.caip) || ((_g = swap.buyAsset) === null || _g === void 0 ? void 0 : _g.symbol),
|
|
90
|
+
fromAmount: (_h = swap.sellAsset) === null || _h === void 0 ? void 0 : _h.amount,
|
|
91
|
+
toAmount: ((_j = swap.buyAsset) === null || _j === void 0 ? void 0 : _j.amount) || ((_k = swap.quote) === null || _k === void 0 ? void 0 : _k.expectedAmountOut),
|
|
92
|
+
destinationAddress: (_l = swap.buyAsset) === null || _l === void 0 ? void 0 : _l.address,
|
|
93
|
+
minimumReceived: (_m = swap.quote) === null || _m === void 0 ? void 0 : _m.minimumAmountOut,
|
|
94
|
+
userMessage: this.generateUserMessage(swap),
|
|
95
|
+
estimatedCompletionTime: this.estimateCompletionTime(swap),
|
|
96
|
+
inboundTxHash: ((_o = swap.thorchainData) === null || _o === void 0 ? void 0 : _o.inboundTxHash) || swap.txHash,
|
|
97
|
+
outboundTxHash: (_p = swap.thorchainData) === null || _p === void 0 ? void 0 : _p.outboundTxHash
|
|
98
|
+
};
|
|
99
|
+
// Map swap to all related transaction hashes
|
|
100
|
+
// Inbound transaction
|
|
101
|
+
if (swap.txHash) {
|
|
102
|
+
swapMetadata.set(swap.txHash, metadata);
|
|
103
|
+
}
|
|
104
|
+
// Thorchain inbound (if different)
|
|
105
|
+
if (((_q = swap.thorchainData) === null || _q === void 0 ? void 0 : _q.inboundTxHash) && swap.thorchainData.inboundTxHash !== swap.txHash) {
|
|
106
|
+
swapMetadata.set(swap.thorchainData.inboundTxHash, metadata);
|
|
107
|
+
}
|
|
108
|
+
// Thorchain outbound
|
|
109
|
+
if ((_r = swap.thorchainData) === null || _r === void 0 ? void 0 : _r.outboundTxHash) {
|
|
110
|
+
swapMetadata.set(swap.thorchainData.outboundTxHash, metadata);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
this.log.info(tag, "DB lookup found ".concat(pendingSwaps.length, " swaps"));
|
|
114
|
+
return [3 /*break*/, 4];
|
|
115
|
+
case 3:
|
|
116
|
+
error_1 = _s.sent();
|
|
117
|
+
this.log.error(tag, 'DB lookup failed (non-critical):', error_1.message);
|
|
118
|
+
return [3 /*break*/, 4];
|
|
119
|
+
case 4:
|
|
120
|
+
// Layer 2: Memo Parsing (FALLBACK for Thorchain/Maya)
|
|
121
|
+
for (_a = 0, transactions_1 = transactions; _a < transactions_1.length; _a++) {
|
|
122
|
+
tx = transactions_1[_a];
|
|
123
|
+
// Skip if already detected from DB
|
|
124
|
+
if (swapMetadata.has(tx.txid))
|
|
125
|
+
continue;
|
|
126
|
+
if (tx.memo) {
|
|
127
|
+
memoMetadata = this.parseMemo(tx.memo);
|
|
128
|
+
if (memoMetadata.isSwap) {
|
|
129
|
+
// Set inbound txHash
|
|
130
|
+
memoMetadata.inboundTxHash = tx.txid;
|
|
131
|
+
swapMetadata.set(tx.txid, memoMetadata);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Layer 2.5: Recursive Outbound Lookup for Memo-Detected Swaps
|
|
136
|
+
// Query Midgard for outbound transactions for all memo-detected swaps
|
|
137
|
+
console.log(tag, "\uD83D\uDD0D Running recursive outbound lookup for ".concat(swapMetadata.size, " detected swaps"));
|
|
138
|
+
swapsNeedingOutbound = Array.from(swapMetadata.entries()).filter(function (_a) {
|
|
139
|
+
var txid = _a[0], metadata = _a[1];
|
|
140
|
+
return metadata.isSwap && !metadata.outboundTxHash;
|
|
141
|
+
});
|
|
142
|
+
if (!(swapsNeedingOutbound.length > 0)) return [3 /*break*/, 6];
|
|
143
|
+
console.log(tag, "\uD83D\uDCE1 Querying Midgard for ".concat(swapsNeedingOutbound.length, " swaps"));
|
|
144
|
+
outboundPromises = swapsNeedingOutbound.map(function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
|
|
145
|
+
var outboundTxHash, error_2;
|
|
146
|
+
var txid = _b[0], metadata = _b[1];
|
|
147
|
+
return __generator(this, function (_c) {
|
|
148
|
+
switch (_c.label) {
|
|
149
|
+
case 0:
|
|
150
|
+
_c.trys.push([0, 2, , 3]);
|
|
151
|
+
return [4 /*yield*/, this.queryMidgardForOutbound(txid)];
|
|
152
|
+
case 1:
|
|
153
|
+
outboundTxHash = _c.sent();
|
|
154
|
+
if (outboundTxHash) {
|
|
155
|
+
console.log(tag, "\u2705 Found outbound tx for ".concat(txid.substring(0, 10), "...: ").concat(outboundTxHash.substring(0, 10), "..."));
|
|
156
|
+
// Update metadata with outbound txHash
|
|
157
|
+
metadata.outboundTxHash = outboundTxHash;
|
|
158
|
+
metadata.status = 'COMPLETED';
|
|
159
|
+
metadata.userMessage = 'Swap completed successfully';
|
|
160
|
+
}
|
|
161
|
+
return [3 /*break*/, 3];
|
|
162
|
+
case 2:
|
|
163
|
+
error_2 = _c.sent();
|
|
164
|
+
console.log(tag, "\u26A0\uFE0F Midgard lookup failed for ".concat(txid.substring(0, 10), "...: ").concat(error_2.message));
|
|
165
|
+
return [3 /*break*/, 3];
|
|
166
|
+
case 3: return [2 /*return*/];
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}); });
|
|
170
|
+
return [4 /*yield*/, Promise.all(outboundPromises)];
|
|
171
|
+
case 5:
|
|
172
|
+
_s.sent();
|
|
173
|
+
console.log(tag, "\u2705 Recursive outbound lookup complete");
|
|
174
|
+
_s.label = 6;
|
|
175
|
+
case 6:
|
|
176
|
+
// Layer 3: Contract Address Detection (EVM ONLY)
|
|
177
|
+
for (_b = 0, transactions_2 = transactions; _b < transactions_2.length; _b++) {
|
|
178
|
+
tx = transactions_2[_b];
|
|
179
|
+
// Skip if already detected
|
|
180
|
+
if (swapMetadata.has(tx.txid))
|
|
181
|
+
continue;
|
|
182
|
+
// Only for EVM chains
|
|
183
|
+
if (tx.networkId && tx.networkId.startsWith('eip155:')) {
|
|
184
|
+
contractMetadata = this.detectDexContract(tx);
|
|
185
|
+
if (contractMetadata.isSwap) {
|
|
186
|
+
swapMetadata.set(tx.txid, contractMetadata);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
console.log(tag, "\u2705 Total swaps detected: ".concat(swapMetadata.size));
|
|
191
|
+
this.log.info(tag, "Total swaps detected: ".concat(swapMetadata.size));
|
|
192
|
+
return [2 /*return*/, swapMetadata];
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* Parse Thorchain/Maya memo format using pioneer-coins parseMemo
|
|
199
|
+
* Handles both verbose (SWAP:asset:address) and shorthand (=:asset:address) formats
|
|
200
|
+
*/
|
|
201
|
+
SwapDetector.prototype.parseMemo = function (memo) {
|
|
202
|
+
// TODO: Use parseMemo from @pioneer-platform/pioneer-coins instead of custom implementation
|
|
203
|
+
// For now, keep basic pattern matching until we can import it properly
|
|
204
|
+
// Try verbose format: SWAP:asset:address
|
|
205
|
+
var verbosePattern = /^SWAP:([^:]+):([^:]+)(?::(\d+))?/i;
|
|
206
|
+
var match = memo.match(verbosePattern);
|
|
207
|
+
// Try shorthand format: =:asset:address
|
|
208
|
+
if (!match) {
|
|
209
|
+
var shorthandPattern = /^=:([^:]+):([^:]+)(?::(\d+))?/;
|
|
210
|
+
match = memo.match(shorthandPattern);
|
|
211
|
+
}
|
|
212
|
+
if (match) {
|
|
213
|
+
// Return raw asset code/CAIP - let display layer handle conversion
|
|
214
|
+
var toAsset = match[1]; // Could be 'e', 'ETH', or full CAIP
|
|
215
|
+
return {
|
|
216
|
+
isSwap: true,
|
|
217
|
+
protocol: 'thorchain',
|
|
218
|
+
toAsset: toAsset, // Return raw value
|
|
219
|
+
destinationAddress: match[2],
|
|
220
|
+
minimumReceived: match[3],
|
|
221
|
+
userMessage: 'Swap detected from transaction memo'
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return { isSwap: false };
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* Detect DEX contract addresses
|
|
228
|
+
*/
|
|
229
|
+
SwapDetector.prototype.detectDexContract = function (tx) {
|
|
230
|
+
var _a;
|
|
231
|
+
var knownDexContracts = [
|
|
232
|
+
'0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'.toLowerCase(), // Uniswap V2 Router
|
|
233
|
+
'0xE592427A0AEce92De3Edee1F18E0157C05861564'.toLowerCase(), // Uniswap V3 Router
|
|
234
|
+
'0xD37BbE5744D730a1d98d8DC97c42F0Ca46aD7146'.toLowerCase(), // Thorchain Router
|
|
235
|
+
];
|
|
236
|
+
var toAddress = (_a = tx.to[0]) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
237
|
+
if (toAddress && knownDexContracts.includes(toAddress)) {
|
|
238
|
+
return {
|
|
239
|
+
isSwap: true,
|
|
240
|
+
protocol: 'uniswap', // Simplified - would need more logic
|
|
241
|
+
userMessage: 'DEX swap detected'
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return { isSwap: false };
|
|
245
|
+
};
|
|
246
|
+
/**
|
|
247
|
+
* Generate user-friendly status message
|
|
248
|
+
*/
|
|
249
|
+
SwapDetector.prototype.generateUserMessage = function (swap) {
|
|
250
|
+
switch (swap.status) {
|
|
251
|
+
case 'PENDING':
|
|
252
|
+
return "Swap pending - waiting for network confirmations";
|
|
253
|
+
case 'CONFIRMING':
|
|
254
|
+
var confirmations = swap.confirmations || 0;
|
|
255
|
+
var required = swap.requiredConfirmations || 6;
|
|
256
|
+
return "Confirming swap (".concat(confirmations, "/").concat(required, " confirmations)");
|
|
257
|
+
case 'COMPLETED':
|
|
258
|
+
return "Swap completed successfully";
|
|
259
|
+
case 'FAILED':
|
|
260
|
+
return "Swap failed - funds may be refunded";
|
|
261
|
+
case 'REFUNDED':
|
|
262
|
+
return "Swap refunded to your wallet";
|
|
263
|
+
default:
|
|
264
|
+
return 'Swap status unknown';
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
/**
|
|
268
|
+
* Estimate completion time based on swap status
|
|
269
|
+
*/
|
|
270
|
+
SwapDetector.prototype.estimateCompletionTime = function (swap) {
|
|
271
|
+
if (swap.status === 'COMPLETED' || swap.status === 'FAILED') {
|
|
272
|
+
return undefined; // Already finished
|
|
273
|
+
}
|
|
274
|
+
// Rough estimates (would be more sophisticated in production)
|
|
275
|
+
var now = Date.now();
|
|
276
|
+
var avgBlockTime = 12000; // 12 seconds for Ethereum
|
|
277
|
+
var remainingConfirmations = (swap.requiredConfirmations || 6) - (swap.confirmations || 0);
|
|
278
|
+
return now + (remainingConfirmations * avgBlockTime);
|
|
279
|
+
};
|
|
280
|
+
/**
|
|
281
|
+
* Query Midgard API for outbound transaction hash
|
|
282
|
+
* Queries both THORChain and Maya Midgard endpoints
|
|
283
|
+
*/
|
|
284
|
+
SwapDetector.prototype.queryMidgardForOutbound = function (inboundTxHash) {
|
|
285
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
286
|
+
var tag, thorUrl, response, data, action, outboundTxid, thorError_1, mayaUrl, response, data, action, outboundTxid, mayaError_1;
|
|
287
|
+
return __generator(this, function (_a) {
|
|
288
|
+
switch (_a.label) {
|
|
289
|
+
case 0:
|
|
290
|
+
tag = TAG + ' | queryMidgardForOutbound | ';
|
|
291
|
+
_a.label = 1;
|
|
292
|
+
case 1:
|
|
293
|
+
_a.trys.push([1, 5, , 6]);
|
|
294
|
+
thorUrl = "https://midgard.ninerealms.com/v2/actions?txid=".concat(inboundTxHash);
|
|
295
|
+
console.log(tag, "Querying THORChain Midgard: ".concat(thorUrl));
|
|
296
|
+
return [4 /*yield*/, fetch(thorUrl)];
|
|
297
|
+
case 2:
|
|
298
|
+
response = _a.sent();
|
|
299
|
+
if (!response.ok) return [3 /*break*/, 4];
|
|
300
|
+
return [4 /*yield*/, response.json()];
|
|
301
|
+
case 3:
|
|
302
|
+
data = _a.sent();
|
|
303
|
+
if (data.actions && data.actions.length > 0) {
|
|
304
|
+
action = data.actions[0];
|
|
305
|
+
// Check for outbound transaction
|
|
306
|
+
if (action.out && action.out.length > 0 && action.out[0].txID) {
|
|
307
|
+
outboundTxid = action.out[0].txID;
|
|
308
|
+
console.log(tag, "\u2705 Found outbound from THORChain: ".concat(outboundTxid));
|
|
309
|
+
return [2 /*return*/, outboundTxid];
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
_a.label = 4;
|
|
313
|
+
case 4: return [3 /*break*/, 6];
|
|
314
|
+
case 5:
|
|
315
|
+
thorError_1 = _a.sent();
|
|
316
|
+
console.log(tag, "THORChain Midgard failed: ".concat(thorError_1.message));
|
|
317
|
+
return [3 /*break*/, 6];
|
|
318
|
+
case 6:
|
|
319
|
+
_a.trys.push([6, 10, , 11]);
|
|
320
|
+
mayaUrl = "https://midgard.mayachain.info/v2/actions?txid=".concat(inboundTxHash);
|
|
321
|
+
console.log(tag, "Querying Maya Midgard: ".concat(mayaUrl));
|
|
322
|
+
return [4 /*yield*/, fetch(mayaUrl)];
|
|
323
|
+
case 7:
|
|
324
|
+
response = _a.sent();
|
|
325
|
+
if (!response.ok) return [3 /*break*/, 9];
|
|
326
|
+
return [4 /*yield*/, response.json()];
|
|
327
|
+
case 8:
|
|
328
|
+
data = _a.sent();
|
|
329
|
+
if (data.actions && data.actions.length > 0) {
|
|
330
|
+
action = data.actions[0];
|
|
331
|
+
// Check for outbound transaction
|
|
332
|
+
if (action.out && action.out.length > 0 && action.out[0].txID) {
|
|
333
|
+
outboundTxid = action.out[0].txID;
|
|
334
|
+
console.log(tag, "\u2705 Found outbound from Maya: ".concat(outboundTxid));
|
|
335
|
+
return [2 /*return*/, outboundTxid];
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
_a.label = 9;
|
|
339
|
+
case 9: return [3 /*break*/, 11];
|
|
340
|
+
case 10:
|
|
341
|
+
mayaError_1 = _a.sent();
|
|
342
|
+
console.log(tag, "Maya Midgard failed: ".concat(mayaError_1.message));
|
|
343
|
+
return [3 /*break*/, 11];
|
|
344
|
+
case 11:
|
|
345
|
+
console.log(tag, "No outbound tx found for ".concat(inboundTxHash));
|
|
346
|
+
return [2 /*return*/, null];
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
};
|
|
351
|
+
return SwapDetector;
|
|
352
|
+
}());
|
|
353
|
+
exports.SwapDetector = SwapDetector;
|