@pioneer-platform/markets 8.3.13 → 8.3.16
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/lib/index.js +135 -31
- package/package.json +10 -10
package/lib/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
/*
|
|
3
3
|
|
|
4
4
|
https://www.coingecko.com/api/documentations/v3
|
|
5
|
+
https://rest.coincap.io/api-docs.json
|
|
5
6
|
|
|
6
7
|
*/
|
|
7
8
|
var __assign = (this && this.__assign) || function () {
|
|
@@ -59,10 +60,7 @@ var Axios = require('axios');
|
|
|
59
60
|
var https = require('https');
|
|
60
61
|
var axios = Axios.create({
|
|
61
62
|
httpsAgent: new https.Agent({
|
|
62
|
-
rejectUnauthorized: false
|
|
63
|
-
headers: {
|
|
64
|
-
"Authorization": "Bearer " + process.env['COINCAP_API_KEY'],
|
|
65
|
-
}
|
|
63
|
+
rejectUnauthorized: false
|
|
66
64
|
})
|
|
67
65
|
});
|
|
68
66
|
var axiosRetry = require('axios-retry');
|
|
@@ -82,9 +80,17 @@ var ProToken = require("@pioneer-platform/pro-token");
|
|
|
82
80
|
var log = require('@pioneer-platform/loggerdog')();
|
|
83
81
|
var _a = require("@pioneer-platform/pioneer-coins"), getExplorerAddressUrl = _a.getExplorerAddressUrl, needsMemoByNetwork = _a.needsMemoByNetwork, COIN_MAP_LONG = _a.COIN_MAP_LONG;
|
|
84
82
|
var _b = require('@pioneer-platform/default-redis'), subscriber = _b.subscriber, publisher = _b.publisher, redis = _b.redis, redisQueue = _b.redisQueue;
|
|
85
|
-
|
|
83
|
+
// API Documentation URLs
|
|
84
|
+
// https://rest.coincap.io/api-docs.json
|
|
85
|
+
// API Base URLs
|
|
86
|
+
var URL_COINCAP = "https://rest.coincap.io/v3/";
|
|
86
87
|
var URL_COINGECKO = "https://api.coingecko.com/api/v3/";
|
|
88
|
+
// API Keys
|
|
89
|
+
var COINCAP_API_KEY = process.env['COINCAP_API_KEY'];
|
|
87
90
|
var COINGECKO_API_KEY = process.env['COINGECKO_API_KEY'];
|
|
91
|
+
if (!COINCAP_API_KEY) {
|
|
92
|
+
console.warn("COINCAP_API_KEY not found in environment variables. CoinCap API 3.0 requires an API key.");
|
|
93
|
+
}
|
|
88
94
|
var GLOBAL_RATES_COINCAP;
|
|
89
95
|
var GLOBAL_RATES_COINGECKO;
|
|
90
96
|
module.exports = {
|
|
@@ -126,6 +132,11 @@ var update_cache = function () {
|
|
|
126
132
|
_a.label = 1;
|
|
127
133
|
case 1:
|
|
128
134
|
_a.trys.push([1, 16, , 17]);
|
|
135
|
+
// Validate API key is available
|
|
136
|
+
if (!COINCAP_API_KEY) {
|
|
137
|
+
log.error(tag, "COINCAP_API_KEY is required for CoinCap API 3.0");
|
|
138
|
+
return [2 /*return*/, ["COINCAP_API_KEY_MISSING"]];
|
|
139
|
+
}
|
|
129
140
|
entries = Object.entries(pioneer_discovery_1.assetData).map(function (_a) {
|
|
130
141
|
var caip = _a[0], asset = _a[1];
|
|
131
142
|
if (typeof asset === 'object' && asset !== null) {
|
|
@@ -138,11 +149,15 @@ var update_cache = function () {
|
|
|
138
149
|
log.debug(tag, "entries: ", entries);
|
|
139
150
|
log.info(tag, "entries: ", entries[0]);
|
|
140
151
|
log.info(tag, "entries: ", entries.length);
|
|
141
|
-
url = URL_COINCAP
|
|
152
|
+
url = "".concat(URL_COINCAP, "assets?limit=2000");
|
|
142
153
|
log.debug(tag, "url: ", url);
|
|
143
154
|
return [4 /*yield*/, axios({
|
|
144
155
|
url: url,
|
|
145
|
-
method: 'GET'
|
|
156
|
+
method: 'GET',
|
|
157
|
+
headers: {
|
|
158
|
+
'Accept': 'application/json',
|
|
159
|
+
'Authorization': "Bearer ".concat(COINCAP_API_KEY)
|
|
160
|
+
}
|
|
146
161
|
})];
|
|
147
162
|
case 2:
|
|
148
163
|
result = _a.sent();
|
|
@@ -162,10 +177,12 @@ var update_cache = function () {
|
|
|
162
177
|
if (!(j < assetsMatchSymbol.length)) return [3 /*break*/, 4];
|
|
163
178
|
asset = assetsMatchSymbol[j];
|
|
164
179
|
key = "coincap:" + asset.caip;
|
|
165
|
-
|
|
180
|
+
// No expiration - old price is better than no price
|
|
181
|
+
return [4 /*yield*/, redis.set(key, JSON.stringify(entry))];
|
|
166
182
|
case 2:
|
|
183
|
+
// No expiration - old price is better than no price
|
|
167
184
|
_b.sent();
|
|
168
|
-
log.info(tag, "saved: " + key
|
|
185
|
+
log.info(tag, "saved: " + key);
|
|
169
186
|
populatedCaips_1.add(asset.caip);
|
|
170
187
|
_b.label = 3;
|
|
171
188
|
case 3:
|
|
@@ -213,8 +230,10 @@ var update_cache = function () {
|
|
|
213
230
|
if (!(_c < matchingAssets_1.length)) return [3 /*break*/, 4];
|
|
214
231
|
matchingAsset = matchingAssets_1[_c];
|
|
215
232
|
key = "coingecko:".concat(matchingAsset.caip);
|
|
216
|
-
|
|
233
|
+
// No expiration - old price is better than no price
|
|
234
|
+
return [4 /*yield*/, redis.set(key, JSON.stringify(coin))];
|
|
217
235
|
case 2:
|
|
236
|
+
// No expiration - old price is better than no price
|
|
218
237
|
_d.sent();
|
|
219
238
|
log.info(tag, "Saved ".concat(coin.symbol, " under ").concat(key));
|
|
220
239
|
populatedCaips_1.add(matchingAsset.caip);
|
|
@@ -476,18 +495,27 @@ var get_assets_coincap = function () {
|
|
|
476
495
|
return __generator(this, function (_a) {
|
|
477
496
|
switch (_a.label) {
|
|
478
497
|
case 0:
|
|
479
|
-
tag = TAG + ' |
|
|
498
|
+
tag = TAG + ' | get_assets_coincap | ';
|
|
480
499
|
_a.label = 1;
|
|
481
500
|
case 1:
|
|
482
501
|
_a.trys.push([1, 3, , 4]);
|
|
483
502
|
output = {};
|
|
484
|
-
|
|
503
|
+
// API 3.0 requires an API key
|
|
504
|
+
if (!COINCAP_API_KEY) {
|
|
505
|
+
log.error(tag, "COINCAP_API_KEY is required for CoinCap API 3.0");
|
|
506
|
+
return [2 /*return*/, {}];
|
|
507
|
+
}
|
|
508
|
+
url = "".concat(URL_COINCAP, "assets?limit=2000");
|
|
485
509
|
log.debug(tag, "url: ", url);
|
|
486
510
|
return [4 /*yield*/, axios({
|
|
487
511
|
url: url,
|
|
488
|
-
method: 'GET'
|
|
512
|
+
method: 'GET',
|
|
513
|
+
headers: {
|
|
514
|
+
'Accept': 'application/json',
|
|
515
|
+
'Authorization': "Bearer ".concat(COINCAP_API_KEY)
|
|
516
|
+
}
|
|
489
517
|
})
|
|
490
|
-
//
|
|
518
|
+
// Parse into keys array off ticker
|
|
491
519
|
];
|
|
492
520
|
case 2:
|
|
493
521
|
result = _a.sent();
|
|
@@ -502,7 +530,8 @@ var get_assets_coincap = function () {
|
|
|
502
530
|
return [2 /*return*/, output];
|
|
503
531
|
case 3:
|
|
504
532
|
e_3 = _a.sent();
|
|
505
|
-
|
|
533
|
+
log.error(TAG, "Error fetching CoinCap assets: ", e_3);
|
|
534
|
+
// Handle error gracefully
|
|
506
535
|
return [2 /*return*/, {}];
|
|
507
536
|
case 4: return [2 /*return*/];
|
|
508
537
|
}
|
|
@@ -554,30 +583,77 @@ var get_assets_coingecko = function (limit, skip) {
|
|
|
554
583
|
};
|
|
555
584
|
var get_prices_in_quote = function (assets, quote) {
|
|
556
585
|
return __awaiter(this, void 0, void 0, function () {
|
|
557
|
-
var tag, data, e_5;
|
|
586
|
+
var tag, result, _i, assets_1, asset, url, response, assetError_1, coincapError_1, data, e_5;
|
|
558
587
|
return __generator(this, function (_a) {
|
|
559
588
|
switch (_a.label) {
|
|
560
589
|
case 0:
|
|
561
590
|
tag = " | get_prices_in_quote | ";
|
|
562
591
|
_a.label = 1;
|
|
563
592
|
case 1:
|
|
564
|
-
_a.trys.push([1,
|
|
565
|
-
|
|
593
|
+
_a.trys.push([1, 12, , 13]);
|
|
594
|
+
if (!(COINCAP_API_KEY && quote.toLowerCase() === 'usd')) return [3 /*break*/, 10];
|
|
595
|
+
_a.label = 2;
|
|
566
596
|
case 2:
|
|
597
|
+
_a.trys.push([2, 9, , 10]);
|
|
598
|
+
result = {};
|
|
599
|
+
_i = 0, assets_1 = assets;
|
|
600
|
+
_a.label = 3;
|
|
601
|
+
case 3:
|
|
602
|
+
if (!(_i < assets_1.length)) return [3 /*break*/, 8];
|
|
603
|
+
asset = assets_1[_i];
|
|
604
|
+
_a.label = 4;
|
|
605
|
+
case 4:
|
|
606
|
+
_a.trys.push([4, 6, , 7]);
|
|
607
|
+
url = "".concat(URL_COINCAP, "assets/").concat(asset);
|
|
608
|
+
return [4 /*yield*/, axios({
|
|
609
|
+
url: url,
|
|
610
|
+
method: 'GET',
|
|
611
|
+
headers: {
|
|
612
|
+
'Accept': 'application/json',
|
|
613
|
+
'Authorization': "Bearer ".concat(COINCAP_API_KEY)
|
|
614
|
+
}
|
|
615
|
+
})];
|
|
616
|
+
case 5:
|
|
617
|
+
response = _a.sent();
|
|
618
|
+
if (response.data && response.data.data) {
|
|
619
|
+
result[asset] = {
|
|
620
|
+
usd: parseFloat(response.data.data.priceUsd)
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
return [3 /*break*/, 7];
|
|
624
|
+
case 6:
|
|
625
|
+
assetError_1 = _a.sent();
|
|
626
|
+
log.error(tag, "Error fetching price for ".concat(asset, " from CoinCap: "), assetError_1);
|
|
627
|
+
return [3 /*break*/, 7];
|
|
628
|
+
case 7:
|
|
629
|
+
_i++;
|
|
630
|
+
return [3 /*break*/, 3];
|
|
631
|
+
case 8:
|
|
632
|
+
// If we got at least one result, return it
|
|
633
|
+
if (Object.keys(result).length > 0) {
|
|
634
|
+
return [2 /*return*/, result];
|
|
635
|
+
}
|
|
636
|
+
return [3 /*break*/, 10];
|
|
637
|
+
case 9:
|
|
638
|
+
coincapError_1 = _a.sent();
|
|
639
|
+
log.error(tag, "CoinCap API error, falling back to CoinGecko: ", coincapError_1);
|
|
640
|
+
return [3 /*break*/, 10];
|
|
641
|
+
case 10: return [4 /*yield*/, axios.get("".concat(URL_COINGECKO, "/simple/price?ids=").concat(assets.toString(), "&vs_currencies=").concat(quote))];
|
|
642
|
+
case 11:
|
|
567
643
|
data = (_a.sent()).data;
|
|
568
644
|
return [2 /*return*/, data];
|
|
569
|
-
case
|
|
645
|
+
case 12:
|
|
570
646
|
e_5 = _a.sent();
|
|
571
|
-
log.error(tag, "
|
|
572
|
-
return [
|
|
573
|
-
case
|
|
647
|
+
log.error(tag, "Error fetching prices: ", e_5);
|
|
648
|
+
return [2 /*return*/, {}];
|
|
649
|
+
case 13: return [2 /*return*/];
|
|
574
650
|
}
|
|
575
651
|
});
|
|
576
652
|
});
|
|
577
653
|
};
|
|
578
654
|
var get_price = function (asset) {
|
|
579
655
|
return __awaiter(this, void 0, void 0, function () {
|
|
580
|
-
var tag, data, currency, marketData, e_6;
|
|
656
|
+
var tag, url, result, coinInfo, coincapError_2, data, currency, marketData, e_6;
|
|
581
657
|
var _a, _b, _c, _d;
|
|
582
658
|
return __generator(this, function (_e) {
|
|
583
659
|
switch (_e.label) {
|
|
@@ -585,11 +661,39 @@ var get_price = function (asset) {
|
|
|
585
661
|
tag = " | get_price | ";
|
|
586
662
|
_e.label = 1;
|
|
587
663
|
case 1:
|
|
588
|
-
_e.trys.push([1,
|
|
589
|
-
return [
|
|
590
|
-
|
|
591
|
-
];
|
|
664
|
+
_e.trys.push([1, 7, , 8]);
|
|
665
|
+
if (!COINCAP_API_KEY) return [3 /*break*/, 5];
|
|
666
|
+
_e.label = 2;
|
|
592
667
|
case 2:
|
|
668
|
+
_e.trys.push([2, 4, , 5]);
|
|
669
|
+
url = "".concat(URL_COINCAP, "assets/").concat(asset);
|
|
670
|
+
log.debug(tag, "CoinCap URL: ", url);
|
|
671
|
+
return [4 /*yield*/, axios({
|
|
672
|
+
url: url,
|
|
673
|
+
method: 'GET',
|
|
674
|
+
headers: {
|
|
675
|
+
'Accept': 'application/json',
|
|
676
|
+
'Authorization': "Bearer ".concat(COINCAP_API_KEY)
|
|
677
|
+
}
|
|
678
|
+
})];
|
|
679
|
+
case 3:
|
|
680
|
+
result = _e.sent();
|
|
681
|
+
coinInfo = result.data.data;
|
|
682
|
+
return [2 /*return*/, {
|
|
683
|
+
price: parseFloat(coinInfo.priceUsd),
|
|
684
|
+
marketCap: parseFloat(coinInfo.marketCapUsd),
|
|
685
|
+
changePercent24Hr: parseFloat(coinInfo.changePercent24Hr),
|
|
686
|
+
volume: parseFloat(coinInfo.volumeUsd24Hr),
|
|
687
|
+
icon: "https://assets.coincap.io/assets/icons/".concat(coinInfo.symbol.toLowerCase(), "@2x.png")
|
|
688
|
+
}];
|
|
689
|
+
case 4:
|
|
690
|
+
coincapError_2 = _e.sent();
|
|
691
|
+
log.error(tag, "CoinCap API error, falling back to CoinGecko: ", coincapError_2);
|
|
692
|
+
return [3 /*break*/, 5];
|
|
693
|
+
case 5: return [4 /*yield*/, axios.get("".concat(URL_COINGECKO, "/coins/").concat(asset))
|
|
694
|
+
// TODO: get correct localizations
|
|
695
|
+
];
|
|
696
|
+
case 6:
|
|
593
697
|
data = (_e.sent()).data;
|
|
594
698
|
currency = 'usd';
|
|
595
699
|
marketData = data === null || data === void 0 ? void 0 : data.market_data;
|
|
@@ -600,11 +704,11 @@ var get_price = function (asset) {
|
|
|
600
704
|
volume: (_c = marketData === null || marketData === void 0 ? void 0 : marketData.total_volume) === null || _c === void 0 ? void 0 : _c[currency],
|
|
601
705
|
icon: (_d = data === null || data === void 0 ? void 0 : data.image) === null || _d === void 0 ? void 0 : _d.large
|
|
602
706
|
}];
|
|
603
|
-
case
|
|
707
|
+
case 7:
|
|
604
708
|
e_6 = _e.sent();
|
|
605
|
-
log.error(tag, "
|
|
606
|
-
return [
|
|
607
|
-
case
|
|
709
|
+
log.error(tag, "Error fetching price data: ", e_6);
|
|
710
|
+
return [2 /*return*/, null];
|
|
711
|
+
case 8: return [2 /*return*/];
|
|
608
712
|
}
|
|
609
713
|
});
|
|
610
714
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pioneer-platform/markets",
|
|
3
|
-
"version": "8.3.
|
|
3
|
+
"version": "8.3.16",
|
|
4
4
|
"main": "./lib/index.js",
|
|
5
5
|
"types": "./lib/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
@@ -14,14 +14,6 @@
|
|
|
14
14
|
"axios-retry": "^3.2.0",
|
|
15
15
|
"dotenv": "^8.2.0"
|
|
16
16
|
},
|
|
17
|
-
"scripts": {
|
|
18
|
-
"npm": "pnpm i",
|
|
19
|
-
"test": "pnpm run build && node __tests__/test-module.js",
|
|
20
|
-
"build": "tsc -p .",
|
|
21
|
-
"build:watch": "pnpm run build && onchange 'src/**/*.ts' -- pnpm run build",
|
|
22
|
-
"prepublish": "pnpm run build",
|
|
23
|
-
"refresh": "rm -rf ./node_modules ./package-lock.json && pnpm install"
|
|
24
|
-
},
|
|
25
17
|
"devDependencies": {
|
|
26
18
|
"@types/jest": "^25.2.3",
|
|
27
19
|
"@types/node": "^18.16.0",
|
|
@@ -33,5 +25,13 @@
|
|
|
33
25
|
"ts-jest": "^29.0.5",
|
|
34
26
|
"typescript": "^5.0.4"
|
|
35
27
|
},
|
|
36
|
-
"gitHead": "aeae28273014ab69b42f22abec159c6693a56c40"
|
|
28
|
+
"gitHead": "aeae28273014ab69b42f22abec159c6693a56c40",
|
|
29
|
+
"scripts": {
|
|
30
|
+
"npm": "pnpm i",
|
|
31
|
+
"test": "pnpm run build && node __tests__/test-module.js",
|
|
32
|
+
"build": "tsc -p .",
|
|
33
|
+
"build:watch": "pnpm run build && onchange 'src/**/*.ts' -- pnpm run build",
|
|
34
|
+
"prepublish": "pnpm run build",
|
|
35
|
+
"refresh": "rm -rf ./node_modules ./package-lock.json && pnpm install"
|
|
36
|
+
}
|
|
37
37
|
}
|