@pioneer-platform/markets 8.11.13 → 8.11.23
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 +9 -0
- package/lib/index.js +304 -70
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
package/lib/index.js
CHANGED
|
@@ -57,6 +57,7 @@ var TAG = " | market-module | ";
|
|
|
57
57
|
// @ts-ignore
|
|
58
58
|
var pioneer_discovery_1 = require("@pioneer-platform/pioneer-discovery");
|
|
59
59
|
var caip_1 = require("@shapeshiftoss/caip");
|
|
60
|
+
var Bottleneck = require('bottleneck');
|
|
60
61
|
var axiosLib = require('axios');
|
|
61
62
|
var Axios = axiosLib.default || axiosLib;
|
|
62
63
|
var https = require('https');
|
|
@@ -68,15 +69,22 @@ var axios = Axios.create({
|
|
|
68
69
|
});
|
|
69
70
|
var axiosRetry = require('axios-retry');
|
|
70
71
|
axiosRetry(axios, {
|
|
71
|
-
retries:
|
|
72
|
+
retries: 3, // Reduced from 5 to 3
|
|
72
73
|
retryDelay: function (retryCount) {
|
|
73
74
|
console.log("retry attempt: ".concat(retryCount));
|
|
74
|
-
return retryCount *
|
|
75
|
+
return retryCount * 2000; // Increased from 1s to 2s backoff
|
|
75
76
|
},
|
|
76
77
|
retryCondition: function (error) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
var _a;
|
|
79
|
+
var status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
|
|
80
|
+
// CRITICAL FIX: Never retry rate limits (429) - respect the API!
|
|
81
|
+
// Also never retry 4xx client errors (except 503 service unavailable)
|
|
82
|
+
if (status === 429 || status === 403) {
|
|
83
|
+
console.warn("Rate limit or forbidden (".concat(status, "), not retrying"));
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
// Only retry on actual service unavailability
|
|
87
|
+
return status === 503 || status === 502 || status === 504;
|
|
80
88
|
},
|
|
81
89
|
});
|
|
82
90
|
var ProToken = require("@pioneer-platform/pro-token");
|
|
@@ -102,6 +110,30 @@ if (CMC_PRO_API_KEY) {
|
|
|
102
110
|
var GLOBAL_RATES_COINCAP;
|
|
103
111
|
var GLOBAL_RATES_COINGECKO;
|
|
104
112
|
var GLOBAL_RATES_CMC;
|
|
113
|
+
// FIX: Request coalescing to prevent thundering herd
|
|
114
|
+
// Tracks in-flight API requests to prevent duplicate calls for same asset
|
|
115
|
+
var pendingPriceRequests = new Map();
|
|
116
|
+
var pendingPriceRequestsWithSource = new Map();
|
|
117
|
+
// FIX: Rate limiters for external APIs
|
|
118
|
+
// CoinGecko free tier: 50 calls/minute = 1.2s between calls (we use 1.5s for safety)
|
|
119
|
+
var coingeckoLimiter = new Bottleneck({
|
|
120
|
+
minTime: 1500, // 1.5 seconds between calls (40 calls/minute)
|
|
121
|
+
maxConcurrent: 1
|
|
122
|
+
});
|
|
123
|
+
// CoinMarketCap: Varies by plan, using conservative limits
|
|
124
|
+
// Basic plan: 333 calls/day ≈ 1 call every 4 minutes, but allow bursts
|
|
125
|
+
var coinmarketcapLimiter = new Bottleneck({
|
|
126
|
+
reservoir: 10, // Allow 10 calls initially
|
|
127
|
+
reservoirRefreshAmount: 10,
|
|
128
|
+
reservoirRefreshInterval: 60 * 1000, // Refresh 10 calls every minute
|
|
129
|
+
minTime: 2000, // 2 seconds between calls
|
|
130
|
+
maxConcurrent: 1
|
|
131
|
+
});
|
|
132
|
+
// CoinCap API 3.0: Similar to CoinGecko
|
|
133
|
+
var coincapLimiter = new Bottleneck({
|
|
134
|
+
minTime: 1500, // 1.5 seconds between calls
|
|
135
|
+
maxConcurrent: 1
|
|
136
|
+
});
|
|
105
137
|
module.exports = {
|
|
106
138
|
init: function (settings) {
|
|
107
139
|
if (settings === null || settings === void 0 ? void 0 : settings.apiKey) {
|
|
@@ -113,6 +145,10 @@ module.exports = {
|
|
|
113
145
|
getAssetPriceByCaip: function (caip, returnSource) {
|
|
114
146
|
return get_asset_price_by_caip(caip, returnSource);
|
|
115
147
|
},
|
|
148
|
+
// NEW: Batch price lookup (significantly reduces API calls)
|
|
149
|
+
getBatchPricesByCaip: function (caips, returnSource) {
|
|
150
|
+
return get_batch_prices_by_caip(caips, returnSource);
|
|
151
|
+
},
|
|
116
152
|
// Legacy bulk fetch functions
|
|
117
153
|
getAssetsCoinCap: function () {
|
|
118
154
|
return get_assets_coincap();
|
|
@@ -684,10 +720,12 @@ var caip_to_identifiers = function (caip) {
|
|
|
684
720
|
};
|
|
685
721
|
/**
|
|
686
722
|
* Get price from CoinGecko by coin ID
|
|
723
|
+
* Now with rate limiting to prevent API spam
|
|
687
724
|
*/
|
|
688
725
|
var get_price_from_coingecko = function (coingeckoId) {
|
|
689
726
|
return __awaiter(this, void 0, void 0, function () {
|
|
690
|
-
var tag,
|
|
727
|
+
var tag, error_1, status_3;
|
|
728
|
+
var _this = this;
|
|
691
729
|
var _a;
|
|
692
730
|
return __generator(this, function (_b) {
|
|
693
731
|
switch (_b.label) {
|
|
@@ -696,18 +734,29 @@ var get_price_from_coingecko = function (coingeckoId) {
|
|
|
696
734
|
_b.label = 1;
|
|
697
735
|
case 1:
|
|
698
736
|
_b.trys.push([1, 3, , 4]);
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
737
|
+
return [4 /*yield*/, coingeckoLimiter.schedule(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
738
|
+
var url, response, price;
|
|
739
|
+
return __generator(this, function (_a) {
|
|
740
|
+
switch (_a.label) {
|
|
741
|
+
case 0:
|
|
742
|
+
url = "".concat(URL_COINGECKO, "simple/price?ids=").concat(coingeckoId, "&vs_currencies=usd");
|
|
743
|
+
log.debug(tag, "Fetching from CoinGecko: ".concat(url));
|
|
744
|
+
return [4 /*yield*/, axios.get(url)];
|
|
745
|
+
case 1:
|
|
746
|
+
response = _a.sent();
|
|
747
|
+
if (response.data && response.data[coingeckoId] && response.data[coingeckoId].usd) {
|
|
748
|
+
price = parseFloat(response.data[coingeckoId].usd);
|
|
749
|
+
log.debug(tag, "\u2705 CoinGecko price for ".concat(coingeckoId, ": $").concat(price));
|
|
750
|
+
return [2 /*return*/, price];
|
|
751
|
+
}
|
|
752
|
+
log.debug(tag, "No price data from CoinGecko for ".concat(coingeckoId));
|
|
753
|
+
return [2 /*return*/, 0];
|
|
754
|
+
}
|
|
755
|
+
});
|
|
756
|
+
}); })];
|
|
757
|
+
case 2:
|
|
758
|
+
// Apply rate limiting
|
|
759
|
+
return [2 /*return*/, _b.sent()];
|
|
711
760
|
case 3:
|
|
712
761
|
error_1 = _b.sent();
|
|
713
762
|
status_3 = ((_a = error_1.response) === null || _a === void 0 ? void 0 : _a.status) || error_1.status;
|
|
@@ -725,49 +774,63 @@ var get_price_from_coingecko = function (coingeckoId) {
|
|
|
725
774
|
};
|
|
726
775
|
/**
|
|
727
776
|
* Get price from CoinMarketCap by symbol
|
|
777
|
+
* Now with rate limiting to prevent API spam
|
|
728
778
|
*/
|
|
729
779
|
var get_price_from_coinmarketcap = function (symbol) {
|
|
730
780
|
return __awaiter(this, void 0, void 0, function () {
|
|
731
|
-
var tag,
|
|
732
|
-
var
|
|
733
|
-
|
|
734
|
-
|
|
781
|
+
var tag, error_2, status_4;
|
|
782
|
+
var _this = this;
|
|
783
|
+
var _a;
|
|
784
|
+
return __generator(this, function (_b) {
|
|
785
|
+
switch (_b.label) {
|
|
735
786
|
case 0:
|
|
736
787
|
tag = TAG + ' | get_price_from_coinmarketcap | ';
|
|
737
788
|
if (!CMC_PRO_API_KEY) {
|
|
738
789
|
log.debug(tag, 'CMC_PRO_API_KEY not set, skipping CoinMarketCap');
|
|
739
790
|
return [2 /*return*/, 0];
|
|
740
791
|
}
|
|
741
|
-
|
|
792
|
+
_b.label = 1;
|
|
742
793
|
case 1:
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
794
|
+
_b.trys.push([1, 3, , 4]);
|
|
795
|
+
return [4 /*yield*/, coinmarketcapLimiter.schedule(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
796
|
+
var url, response, coinData, priceData, price;
|
|
797
|
+
var _a, _b;
|
|
798
|
+
return __generator(this, function (_c) {
|
|
799
|
+
switch (_c.label) {
|
|
800
|
+
case 0:
|
|
801
|
+
url = "".concat(URL_COINMARKETCAP, "cryptocurrency/quotes/latest?symbol=").concat(symbol, "&convert=USD");
|
|
802
|
+
log.debug(tag, "Fetching from CoinMarketCap: ".concat(url));
|
|
803
|
+
return [4 /*yield*/, axios.get(url, {
|
|
804
|
+
headers: {
|
|
805
|
+
'X-CMC_PRO_API_KEY': CMC_PRO_API_KEY,
|
|
806
|
+
'Accept': 'application/json'
|
|
807
|
+
}
|
|
808
|
+
})];
|
|
809
|
+
case 1:
|
|
810
|
+
response = _c.sent();
|
|
811
|
+
if (response.data && response.data.data && response.data.data[symbol]) {
|
|
812
|
+
coinData = response.data.data[symbol];
|
|
813
|
+
priceData = (_b = (_a = coinData.quote) === null || _a === void 0 ? void 0 : _a.USD) === null || _b === void 0 ? void 0 : _b.price;
|
|
814
|
+
if (!priceData || isNaN(parseFloat(priceData))) {
|
|
815
|
+
log.warn(tag, "\u26A0\uFE0F CoinMarketCap returned invalid price for ".concat(symbol));
|
|
816
|
+
log.warn(tag, "Symbol: ".concat(coinData.symbol, ", Slug: ").concat(coinData.slug, ", Quote keys:"), Object.keys(coinData.quote || {}));
|
|
817
|
+
return [2 /*return*/, 0];
|
|
818
|
+
}
|
|
819
|
+
price = parseFloat(priceData);
|
|
820
|
+
log.debug(tag, "\u2705 CoinMarketCap price for ".concat(symbol, ": $").concat(price));
|
|
821
|
+
return [2 /*return*/, price];
|
|
822
|
+
}
|
|
823
|
+
log.debug(tag, "No price data from CoinMarketCap for ".concat(symbol));
|
|
824
|
+
return [2 /*return*/, 0];
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
}); })];
|
|
828
|
+
case 2:
|
|
829
|
+
// Apply rate limiting
|
|
830
|
+
return [2 /*return*/, _b.sent()];
|
|
768
831
|
case 3:
|
|
769
|
-
error_2 =
|
|
770
|
-
status_4 = ((
|
|
832
|
+
error_2 = _b.sent();
|
|
833
|
+
status_4 = ((_a = error_2.response) === null || _a === void 0 ? void 0 : _a.status) || error_2.status;
|
|
771
834
|
if (status_4 === 429 || status_4 === 403) {
|
|
772
835
|
log.warn(tag, "CoinMarketCap rate limit (".concat(status_4, ") for ").concat(symbol));
|
|
773
836
|
}
|
|
@@ -782,10 +845,12 @@ var get_price_from_coinmarketcap = function (symbol) {
|
|
|
782
845
|
};
|
|
783
846
|
/**
|
|
784
847
|
* Get price from CoinCap by symbol
|
|
848
|
+
* Now with rate limiting to prevent API spam
|
|
785
849
|
*/
|
|
786
850
|
var get_price_from_coincap = function (symbol) {
|
|
787
851
|
return __awaiter(this, void 0, void 0, function () {
|
|
788
|
-
var tag,
|
|
852
|
+
var tag, error_3, status_5;
|
|
853
|
+
var _this = this;
|
|
789
854
|
var _a;
|
|
790
855
|
return __generator(this, function (_b) {
|
|
791
856
|
switch (_b.label) {
|
|
@@ -798,23 +863,34 @@ var get_price_from_coincap = function (symbol) {
|
|
|
798
863
|
_b.label = 1;
|
|
799
864
|
case 1:
|
|
800
865
|
_b.trys.push([1, 3, , 4]);
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
866
|
+
return [4 /*yield*/, coincapLimiter.schedule(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
867
|
+
var url, response, price;
|
|
868
|
+
return __generator(this, function (_a) {
|
|
869
|
+
switch (_a.label) {
|
|
870
|
+
case 0:
|
|
871
|
+
url = "".concat(URL_COINCAP, "assets/").concat(symbol);
|
|
872
|
+
log.debug(tag, "Fetching from CoinCap: ".concat(url));
|
|
873
|
+
return [4 /*yield*/, axios.get(url, {
|
|
874
|
+
headers: {
|
|
875
|
+
'Accept': 'application/json',
|
|
876
|
+
'Authorization': "Bearer ".concat(COINCAP_API_KEY)
|
|
877
|
+
}
|
|
878
|
+
})];
|
|
879
|
+
case 1:
|
|
880
|
+
response = _a.sent();
|
|
881
|
+
if (response.data && response.data.data && response.data.data.priceUsd) {
|
|
882
|
+
price = parseFloat(response.data.data.priceUsd);
|
|
883
|
+
log.debug(tag, "\u2705 CoinCap price for ".concat(symbol, ": $").concat(price));
|
|
884
|
+
return [2 /*return*/, price];
|
|
885
|
+
}
|
|
886
|
+
log.debug(tag, "No price data from CoinCap for ".concat(symbol));
|
|
887
|
+
return [2 /*return*/, 0];
|
|
888
|
+
}
|
|
889
|
+
});
|
|
890
|
+
}); })];
|
|
891
|
+
case 2:
|
|
892
|
+
// Apply rate limiting
|
|
893
|
+
return [2 /*return*/, _b.sent()];
|
|
818
894
|
case 3:
|
|
819
895
|
error_3 = _b.sent();
|
|
820
896
|
status_5 = ((_a = error_3.response) === null || _a === void 0 ? void 0 : _a.status) || error_3.status;
|
|
@@ -881,14 +957,41 @@ var get_price_from_mayascan = function () {
|
|
|
881
957
|
* Returns: { price: number, source: string } or backwards compatible number
|
|
882
958
|
*/
|
|
883
959
|
var get_asset_price_by_caip = function (caip_2) {
|
|
960
|
+
return __awaiter(this, arguments, void 0, function (caip, returnSource) {
|
|
961
|
+
var tag, pendingMap, existingRequest, pricePromise;
|
|
962
|
+
if (returnSource === void 0) { returnSource = false; }
|
|
963
|
+
return __generator(this, function (_a) {
|
|
964
|
+
tag = TAG + ' | get_asset_price_by_caip | ';
|
|
965
|
+
log.debug(tag, "Looking up price for: ".concat(caip));
|
|
966
|
+
pendingMap = returnSource ? pendingPriceRequestsWithSource : pendingPriceRequests;
|
|
967
|
+
existingRequest = pendingMap.get(caip);
|
|
968
|
+
if (existingRequest) {
|
|
969
|
+
log.debug(tag, "Coalescing duplicate request for: ".concat(caip));
|
|
970
|
+
return [2 /*return*/, existingRequest];
|
|
971
|
+
}
|
|
972
|
+
pricePromise = get_asset_price_by_caip_internal(caip, returnSource);
|
|
973
|
+
// Store promise for request coalescing
|
|
974
|
+
pendingMap.set(caip, pricePromise);
|
|
975
|
+
// Cleanup after completion (success or failure)
|
|
976
|
+
pricePromise.finally(function () {
|
|
977
|
+
pendingMap.delete(caip);
|
|
978
|
+
});
|
|
979
|
+
return [2 /*return*/, pricePromise];
|
|
980
|
+
});
|
|
981
|
+
});
|
|
982
|
+
};
|
|
983
|
+
/**
|
|
984
|
+
* Internal implementation (separated for request coalescing)
|
|
985
|
+
*/
|
|
986
|
+
var get_asset_price_by_caip_internal = function (caip_2) {
|
|
884
987
|
return __awaiter(this, arguments, void 0, function (caip, returnSource) {
|
|
885
988
|
var tag, mayaPrice, isCacao, identifiers, price, cacaoPrice;
|
|
886
989
|
if (returnSource === void 0) { returnSource = false; }
|
|
887
990
|
return __generator(this, function (_a) {
|
|
888
991
|
switch (_a.label) {
|
|
889
992
|
case 0:
|
|
890
|
-
tag = TAG + ' |
|
|
891
|
-
log.debug(tag, "
|
|
993
|
+
tag = TAG + ' | get_asset_price_by_caip_internal | ';
|
|
994
|
+
log.debug(tag, "Fetching price for: ".concat(caip));
|
|
892
995
|
if (!(caip === 'cosmos:mayachain-mainnet-v1/denom:maya' || caip.toLowerCase().includes('denom:maya'))) return [3 /*break*/, 2];
|
|
893
996
|
log.debug(tag, 'MAYA token detected, using MayaScan API');
|
|
894
997
|
return [4 /*yield*/, get_price_from_mayascan('maya')];
|
|
@@ -1082,3 +1185,134 @@ var get_price = function (asset) {
|
|
|
1082
1185
|
});
|
|
1083
1186
|
});
|
|
1084
1187
|
};
|
|
1188
|
+
/**
|
|
1189
|
+
* NEW: Batch price lookup by CAIP
|
|
1190
|
+
* Fetches multiple asset prices in a single API call (up to 250 assets)
|
|
1191
|
+
* Reduces API calls by 95%+ for portfolio operations
|
|
1192
|
+
*/
|
|
1193
|
+
var get_batch_prices_by_caip = function (caips_1) {
|
|
1194
|
+
return __awaiter(this, arguments, void 0, function (caips, returnSource) {
|
|
1195
|
+
var tag, results, caipToIdMap, specialCaips, _i, caips_2, caip, identifiers, coingeckoIds, batchSize, i, batch, idsParam, url, response, _a, batch_1, coingeckoId, mapping, price, error_5, _b, specialCaips_1, caip, price, error_6, missingCaips, _c, missingCaips_1, caip, _d, _e, error_7;
|
|
1196
|
+
var _f;
|
|
1197
|
+
if (returnSource === void 0) { returnSource = false; }
|
|
1198
|
+
return __generator(this, function (_g) {
|
|
1199
|
+
switch (_g.label) {
|
|
1200
|
+
case 0:
|
|
1201
|
+
tag = TAG + ' | get_batch_prices_by_caip | ';
|
|
1202
|
+
log.info(tag, "Fetching batch prices for ".concat(caips.length, " assets"));
|
|
1203
|
+
results = {};
|
|
1204
|
+
caipToIdMap = {};
|
|
1205
|
+
specialCaips = [];
|
|
1206
|
+
for (_i = 0, caips_2 = caips; _i < caips_2.length; _i++) {
|
|
1207
|
+
caip = caips_2[_i];
|
|
1208
|
+
// Handle special cases (MAYA, CACAO)
|
|
1209
|
+
if (caip === 'cosmos:mayachain-mainnet-v1/denom:maya' || caip.toLowerCase().includes('denom:maya')) {
|
|
1210
|
+
specialCaips.push(caip);
|
|
1211
|
+
continue;
|
|
1212
|
+
}
|
|
1213
|
+
if (caip === 'cosmos:mayachain-mainnet-v1/slip44:931') {
|
|
1214
|
+
specialCaips.push(caip);
|
|
1215
|
+
continue;
|
|
1216
|
+
}
|
|
1217
|
+
identifiers = caip_to_identifiers(caip);
|
|
1218
|
+
if (identifiers === null || identifiers === void 0 ? void 0 : identifiers.coingeckoId) {
|
|
1219
|
+
caipToIdMap[identifiers.coingeckoId] = { caip: caip, coingeckoId: identifiers.coingeckoId };
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
coingeckoIds = Object.keys(caipToIdMap);
|
|
1223
|
+
if (!(coingeckoIds.length > 0)) return [3 /*break*/, 8];
|
|
1224
|
+
_g.label = 1;
|
|
1225
|
+
case 1:
|
|
1226
|
+
_g.trys.push([1, 7, , 8]);
|
|
1227
|
+
batchSize = 250;
|
|
1228
|
+
i = 0;
|
|
1229
|
+
_g.label = 2;
|
|
1230
|
+
case 2:
|
|
1231
|
+
if (!(i < coingeckoIds.length)) return [3 /*break*/, 6];
|
|
1232
|
+
batch = coingeckoIds.slice(i, i + batchSize);
|
|
1233
|
+
idsParam = batch.join(',');
|
|
1234
|
+
url = "".concat(URL_COINGECKO, "simple/price?ids=").concat(idsParam, "&vs_currencies=usd");
|
|
1235
|
+
log.debug(tag, "Fetching batch ".concat(i / batchSize + 1, ": ").concat(batch.length, " assets"));
|
|
1236
|
+
return [4 /*yield*/, axios.get(url)];
|
|
1237
|
+
case 3:
|
|
1238
|
+
response = _g.sent();
|
|
1239
|
+
// Map results back to CAIPs
|
|
1240
|
+
for (_a = 0, batch_1 = batch; _a < batch_1.length; _a++) {
|
|
1241
|
+
coingeckoId = batch_1[_a];
|
|
1242
|
+
mapping = caipToIdMap[coingeckoId];
|
|
1243
|
+
if ((_f = response.data[coingeckoId]) === null || _f === void 0 ? void 0 : _f.usd) {
|
|
1244
|
+
price = parseFloat(response.data[coingeckoId].usd);
|
|
1245
|
+
results[mapping.caip] = returnSource
|
|
1246
|
+
? { price: price, source: 'coingecko' }
|
|
1247
|
+
: price;
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
if (!(i + batchSize < coingeckoIds.length)) return [3 /*break*/, 5];
|
|
1251
|
+
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 1500); })];
|
|
1252
|
+
case 4:
|
|
1253
|
+
_g.sent();
|
|
1254
|
+
_g.label = 5;
|
|
1255
|
+
case 5:
|
|
1256
|
+
i += batchSize;
|
|
1257
|
+
return [3 /*break*/, 2];
|
|
1258
|
+
case 6:
|
|
1259
|
+
log.info(tag, "\u2705 Batch fetched ".concat(Object.keys(results).length, " prices from CoinGecko"));
|
|
1260
|
+
return [3 /*break*/, 8];
|
|
1261
|
+
case 7:
|
|
1262
|
+
error_5 = _g.sent();
|
|
1263
|
+
log.error(tag, "CoinGecko batch fetch failed:", error_5.message);
|
|
1264
|
+
return [3 /*break*/, 8];
|
|
1265
|
+
case 8:
|
|
1266
|
+
_b = 0, specialCaips_1 = specialCaips;
|
|
1267
|
+
_g.label = 9;
|
|
1268
|
+
case 9:
|
|
1269
|
+
if (!(_b < specialCaips_1.length)) return [3 /*break*/, 14];
|
|
1270
|
+
caip = specialCaips_1[_b];
|
|
1271
|
+
_g.label = 10;
|
|
1272
|
+
case 10:
|
|
1273
|
+
_g.trys.push([10, 12, , 13]);
|
|
1274
|
+
return [4 /*yield*/, get_asset_price_by_caip(caip, returnSource)];
|
|
1275
|
+
case 11:
|
|
1276
|
+
price = _g.sent();
|
|
1277
|
+
results[caip] = price;
|
|
1278
|
+
return [3 /*break*/, 13];
|
|
1279
|
+
case 12:
|
|
1280
|
+
error_6 = _g.sent();
|
|
1281
|
+
log.warn(tag, "Failed to fetch special case: ".concat(caip));
|
|
1282
|
+
return [3 /*break*/, 13];
|
|
1283
|
+
case 13:
|
|
1284
|
+
_b++;
|
|
1285
|
+
return [3 /*break*/, 9];
|
|
1286
|
+
case 14:
|
|
1287
|
+
missingCaips = caips.filter(function (caip) { return !results[caip]; });
|
|
1288
|
+
if (!(missingCaips.length > 0)) return [3 /*break*/, 20];
|
|
1289
|
+
log.info(tag, "Falling back to individual fetch for ".concat(missingCaips.length, " missing prices"));
|
|
1290
|
+
_c = 0, missingCaips_1 = missingCaips;
|
|
1291
|
+
_g.label = 15;
|
|
1292
|
+
case 15:
|
|
1293
|
+
if (!(_c < missingCaips_1.length)) return [3 /*break*/, 20];
|
|
1294
|
+
caip = missingCaips_1[_c];
|
|
1295
|
+
_g.label = 16;
|
|
1296
|
+
case 16:
|
|
1297
|
+
_g.trys.push([16, 18, , 19]);
|
|
1298
|
+
_d = results;
|
|
1299
|
+
_e = caip;
|
|
1300
|
+
return [4 /*yield*/, get_asset_price_by_caip(caip, returnSource)];
|
|
1301
|
+
case 17:
|
|
1302
|
+
_d[_e] = _g.sent();
|
|
1303
|
+
return [3 /*break*/, 19];
|
|
1304
|
+
case 18:
|
|
1305
|
+
error_7 = _g.sent();
|
|
1306
|
+
log.warn(tag, "Failed to fetch fallback price for ".concat(caip));
|
|
1307
|
+
results[caip] = returnSource ? { price: 0, source: 'none' } : 0;
|
|
1308
|
+
return [3 /*break*/, 19];
|
|
1309
|
+
case 19:
|
|
1310
|
+
_c++;
|
|
1311
|
+
return [3 /*break*/, 15];
|
|
1312
|
+
case 20:
|
|
1313
|
+
log.info(tag, "\u2705 Batch complete: ".concat(Object.keys(results).length, "/").concat(caips.length, " prices fetched"));
|
|
1314
|
+
return [2 /*return*/, results];
|
|
1315
|
+
}
|
|
1316
|
+
});
|
|
1317
|
+
});
|
|
1318
|
+
};
|
package/package.json
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pioneer-platform/markets",
|
|
3
|
-
"version": "8.11.
|
|
3
|
+
"version": "8.11.23",
|
|
4
4
|
"main": "./lib/index.js",
|
|
5
5
|
"types": "./lib/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@pioneer-platform/default-redis": "^8.11.
|
|
7
|
+
"@pioneer-platform/default-redis": "^8.11.7",
|
|
8
8
|
"@pioneer-platform/loggerdog": "^8.11.0",
|
|
9
9
|
"@pioneer-platform/pioneer-coins": "^9.11.0",
|
|
10
|
-
"@pioneer-platform/pioneer-discovery": "^8.11.
|
|
10
|
+
"@pioneer-platform/pioneer-discovery": "^8.11.23",
|
|
11
11
|
"@pioneer-platform/pioneer-types": "^8.11.0",
|
|
12
|
-
"@pioneer-platform/pro-token": "^0.8.
|
|
12
|
+
"@pioneer-platform/pro-token": "^0.8.1",
|
|
13
13
|
"@shapeshiftoss/caip": "^9.0.0-alpha.0",
|
|
14
14
|
"axios": "^1.6.0",
|
|
15
15
|
"axios-retry": "^3.2.0",
|
|
16
|
+
"bottleneck": "^2.19.5",
|
|
16
17
|
"dotenv": "^8.2.0"
|
|
17
18
|
},
|
|
18
19
|
"scripts": {
|