@pioneer-platform/markets 8.11.0 → 8.11.2

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/lib/index.js +320 -16
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @pioneer-platform/markets
2
2
 
3
+ ## 8.11.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Update pioneer-discovery dependency to latest version
8
+
9
+ ## 8.11.1
10
+
11
+ ### Patch Changes
12
+
13
+ - Fix markets integration and update pioneer-sdk with latest changes
14
+
3
15
  ## 8.11.0
4
16
 
5
17
  ### Minor Changes
package/lib/index.js CHANGED
@@ -86,14 +86,20 @@ var _b = require('@pioneer-platform/default-redis'), subscriber = _b.subscriber,
86
86
  // API Base URLs
87
87
  var URL_COINCAP = "https://rest.coincap.io/v3/";
88
88
  var URL_COINGECKO = "https://api.coingecko.com/api/v3/";
89
+ var URL_COINMARKETCAP = "https://pro-api.coinmarketcap.com/v1/";
89
90
  // API Keys
90
91
  var COINCAP_API_KEY = process.env['COINCAP_API_KEY'];
91
92
  var COINGECKO_API_KEY = process.env['COINGECKO_API_KEY'];
93
+ var CMC_PRO_API_KEY = process.env['CMC_PRO_API_KEY'];
92
94
  if (!COINCAP_API_KEY) {
93
95
  console.warn("COINCAP_API_KEY not found in environment variables. CoinCap API 3.0 requires an API key.");
94
96
  }
97
+ if (CMC_PRO_API_KEY) {
98
+ log.info(TAG, "✅ CoinMarketCap API key found - CMC will be used as fallback source");
99
+ }
95
100
  var GLOBAL_RATES_COINCAP;
96
101
  var GLOBAL_RATES_COINGECKO;
102
+ var GLOBAL_RATES_CMC;
97
103
  module.exports = {
98
104
  init: function (settings) {
99
105
  if (settings === null || settings === void 0 ? void 0 : settings.apiKey) {
@@ -101,12 +107,20 @@ module.exports = {
101
107
  }
102
108
  //if(!COINGECKO_API_KEY) throw Error("api key required! set env COINGECKO_API_KEY")
103
109
  },
110
+ // NEW: CAIP-first individual asset price lookup
111
+ getAssetPriceByCaip: function (caip) {
112
+ return get_asset_price_by_caip(caip);
113
+ },
114
+ // Legacy bulk fetch functions
104
115
  getAssetsCoinCap: function () {
105
116
  return get_assets_coincap();
106
117
  },
107
118
  getAssetsCoingecko: function (limit, skip) {
108
119
  return get_assets_coingecko(limit, skip);
109
120
  },
121
+ // getAssetsCoinMarketCap: function (limit:number,start:number){
122
+ // return get_assets_coinmarketcap(limit,start);
123
+ // },
110
124
  getRatePro: function () {
111
125
  return ProToken.getRateProUsd();
112
126
  },
@@ -488,14 +502,15 @@ var build_balances = function (marketInfoCoinCap, marketInfoCoinGecko, pubkeys)
488
502
  };
489
503
  var get_assets_coincap = function () {
490
504
  return __awaiter(this, void 0, void 0, function () {
491
- var tag, output, url, result, allCoinsArray, i, coinInfo, e_3;
492
- return __generator(this, function (_a) {
493
- switch (_a.label) {
505
+ var tag, output, url, result, allCoinsArray, i, coinInfo, e_3, status_1, isRateLimit, message;
506
+ var _a;
507
+ return __generator(this, function (_b) {
508
+ switch (_b.label) {
494
509
  case 0:
495
510
  tag = TAG + ' | get_assets_coincap | ';
496
- _a.label = 1;
511
+ _b.label = 1;
497
512
  case 1:
498
- _a.trys.push([1, 3, , 4]);
513
+ _b.trys.push([1, 3, , 4]);
499
514
  output = {};
500
515
  // API 3.0 requires an API key
501
516
  if (!COINCAP_API_KEY) {
@@ -515,7 +530,7 @@ var get_assets_coincap = function () {
515
530
  // Parse into keys array off ticker
516
531
  ];
517
532
  case 2:
518
- result = _a.sent();
533
+ result = _b.sent();
519
534
  allCoinsArray = result.data.data;
520
535
  log.debug(tag, "allCoinsArray: ", allCoinsArray.length);
521
536
  for (i = 0; i < allCoinsArray.length; i++) {
@@ -526,8 +541,16 @@ var get_assets_coincap = function () {
526
541
  log.debug('result: ', output);
527
542
  return [2 /*return*/, output];
528
543
  case 3:
529
- e_3 = _a.sent();
530
- log.error(TAG, "Error fetching CoinCap assets: ", e_3);
544
+ e_3 = _b.sent();
545
+ status_1 = ((_a = e_3.response) === null || _a === void 0 ? void 0 : _a.status) || e_3.status;
546
+ isRateLimit = status_1 === 429 || status_1 === 403;
547
+ message = e_3.message || '';
548
+ if (isRateLimit || message.includes('rate limit') || message.includes('usage limit')) {
549
+ log.warn(TAG, "CoinCap API rate limit (".concat(status_1, "): pausing requests"));
550
+ }
551
+ else {
552
+ log.debug(TAG, "Error fetching CoinCap assets: ".concat(e_3.message || 'Unknown error'));
553
+ }
531
554
  // Handle error gracefully
532
555
  return [2 /*return*/, {}];
533
556
  case 4: return [2 /*return*/];
@@ -537,14 +560,15 @@ var get_assets_coincap = function () {
537
560
  };
538
561
  var get_assets_coingecko = function (limit, skip) {
539
562
  return __awaiter(this, void 0, void 0, function () {
540
- var tag, output, url, result, allCoinsArray, i, coinInfo, e_4;
541
- return __generator(this, function (_a) {
542
- switch (_a.label) {
563
+ var tag, output, url, result, allCoinsArray, i, coinInfo, e_4, status_2, isRateLimit, message;
564
+ var _a;
565
+ return __generator(this, function (_b) {
566
+ switch (_b.label) {
543
567
  case 0:
544
568
  tag = TAG + ' | get_assets_coingecko | ';
545
- _a.label = 1;
569
+ _b.label = 1;
546
570
  case 1:
547
- _a.trys.push([1, 3, , 4]);
571
+ _b.trys.push([1, 3, , 4]);
548
572
  output = {};
549
573
  if (!limit)
550
574
  limit = 250;
@@ -557,7 +581,7 @@ var get_assets_coingecko = function (limit, skip) {
557
581
  method: 'GET'
558
582
  })];
559
583
  case 2:
560
- result = _a.sent();
584
+ result = _b.sent();
561
585
  log.debug(tag, "result: ", result.data);
562
586
  allCoinsArray = result.data;
563
587
  log.debug(tag, "allCoinsArray: ", allCoinsArray.length);
@@ -570,14 +594,294 @@ var get_assets_coingecko = function (limit, skip) {
570
594
  log.debug('result: ', output);
571
595
  return [2 /*return*/, output];
572
596
  case 3:
573
- e_4 = _a.sent();
574
- //handle error gracefully
597
+ e_4 = _b.sent();
598
+ status_2 = ((_a = e_4.response) === null || _a === void 0 ? void 0 : _a.status) || e_4.status;
599
+ isRateLimit = status_2 === 429 || status_2 === 403;
600
+ message = e_4.message || '';
601
+ if (isRateLimit || message.includes('rate limit') || message.includes('usage limit')) {
602
+ log.warn(tag, "CoinGecko API rate limit (".concat(status_2, "): pausing requests"));
603
+ }
604
+ else {
605
+ log.debug(tag, "Error fetching CoinGecko assets: ".concat(e_4.message || 'Unknown error'));
606
+ }
607
+ // Handle error gracefully
575
608
  return [2 /*return*/, {}];
576
609
  case 4: return [2 /*return*/];
577
610
  }
578
611
  });
579
612
  });
580
613
  };
614
+ /*
615
+ NEW CAIP-FIRST INDIVIDUAL ASSET FUNCTIONS
616
+ All CAIP-to-identifier translation logic lives here
617
+ */
618
+ /**
619
+ * Translate CAIP to API-specific identifiers
620
+ * @param caip - CAIP identifier (e.g., "eip155:1/slip44:60" for ETH)
621
+ * @returns Object with identifiers for each API
622
+ */
623
+ var caip_to_identifiers = function (caip) {
624
+ var tag = TAG + ' | caip_to_identifiers | ';
625
+ // Get asset data from discovery module
626
+ var asset = pioneer_discovery_1.assetData[caip] || pioneer_discovery_1.assetData[caip.toUpperCase()] || pioneer_discovery_1.assetData[caip.toLowerCase()];
627
+ if (!asset || !asset.symbol) {
628
+ log.debug(tag, "No asset mapping found for CAIP: ".concat(caip));
629
+ return null;
630
+ }
631
+ var symbol = asset.symbol.toUpperCase();
632
+ // TODO: Build comprehensive mapping table
633
+ // For now, use symbol-based mapping with known exceptions
634
+ var coinGeckoIdMap = {
635
+ 'BTC': 'bitcoin',
636
+ 'ETH': 'ethereum',
637
+ 'ATOM': 'cosmos',
638
+ 'OSMO': 'osmosis',
639
+ 'RUNE': 'thorchain',
640
+ 'CACAO': 'cacao', // MayaChain
641
+ 'MAYA': 'maya-protocol',
642
+ 'XRP': 'ripple',
643
+ 'LTC': 'litecoin',
644
+ 'DOGE': 'dogecoin',
645
+ 'BCH': 'bitcoin-cash'
646
+ };
647
+ return {
648
+ symbol: symbol,
649
+ coingeckoId: coinGeckoIdMap[symbol] || symbol.toLowerCase(),
650
+ cmcSymbol: symbol,
651
+ coincapSymbol: symbol.toLowerCase()
652
+ };
653
+ };
654
+ /**
655
+ * Get price from CoinGecko by coin ID
656
+ */
657
+ var get_price_from_coingecko = function (coingeckoId) {
658
+ return __awaiter(this, void 0, void 0, function () {
659
+ var tag, url, response, price, error_1, status_3;
660
+ var _a;
661
+ return __generator(this, function (_b) {
662
+ switch (_b.label) {
663
+ case 0:
664
+ tag = TAG + ' | get_price_from_coingecko | ';
665
+ _b.label = 1;
666
+ case 1:
667
+ _b.trys.push([1, 3, , 4]);
668
+ url = "".concat(URL_COINGECKO, "simple/price?ids=").concat(coingeckoId, "&vs_currencies=usd");
669
+ log.debug(tag, "Fetching from CoinGecko: ".concat(url));
670
+ return [4 /*yield*/, axios.get(url)];
671
+ case 2:
672
+ response = _b.sent();
673
+ if (response.data && response.data[coingeckoId] && response.data[coingeckoId].usd) {
674
+ price = parseFloat(response.data[coingeckoId].usd);
675
+ log.debug(tag, "\u2705 CoinGecko price for ".concat(coingeckoId, ": $").concat(price));
676
+ return [2 /*return*/, price];
677
+ }
678
+ log.debug(tag, "No price data from CoinGecko for ".concat(coingeckoId));
679
+ return [2 /*return*/, 0];
680
+ case 3:
681
+ error_1 = _b.sent();
682
+ status_3 = ((_a = error_1.response) === null || _a === void 0 ? void 0 : _a.status) || error_1.status;
683
+ if (status_3 === 429 || status_3 === 403) {
684
+ log.warn(tag, "CoinGecko rate limit (".concat(status_3, ") for ").concat(coingeckoId));
685
+ }
686
+ else {
687
+ log.debug(tag, "CoinGecko error for ".concat(coingeckoId, ": ").concat(error_1.message));
688
+ }
689
+ return [2 /*return*/, 0];
690
+ case 4: return [2 /*return*/];
691
+ }
692
+ });
693
+ });
694
+ };
695
+ /**
696
+ * Get price from CoinMarketCap by symbol
697
+ */
698
+ var get_price_from_coinmarketcap = function (symbol) {
699
+ return __awaiter(this, void 0, void 0, function () {
700
+ var tag, url, response, price, error_2, status_4;
701
+ var _a;
702
+ return __generator(this, function (_b) {
703
+ switch (_b.label) {
704
+ case 0:
705
+ tag = TAG + ' | get_price_from_coinmarketcap | ';
706
+ if (!CMC_PRO_API_KEY) {
707
+ log.debug(tag, 'CMC_PRO_API_KEY not set, skipping CoinMarketCap');
708
+ return [2 /*return*/, 0];
709
+ }
710
+ _b.label = 1;
711
+ case 1:
712
+ _b.trys.push([1, 3, , 4]);
713
+ url = "".concat(URL_COINMARKETCAP, "cryptocurrency/quotes/latest?symbol=").concat(symbol, "&convert=USD");
714
+ log.debug(tag, "Fetching from CoinMarketCap: ".concat(url));
715
+ return [4 /*yield*/, axios.get(url, {
716
+ headers: {
717
+ 'X-CMC_PRO_API_KEY': CMC_PRO_API_KEY,
718
+ 'Accept': 'application/json'
719
+ }
720
+ })];
721
+ case 2:
722
+ response = _b.sent();
723
+ if (response.data && response.data.data && response.data.data[symbol]) {
724
+ price = parseFloat(response.data.data[symbol].quote.USD.price);
725
+ log.debug(tag, "\u2705 CoinMarketCap price for ".concat(symbol, ": $").concat(price));
726
+ return [2 /*return*/, price];
727
+ }
728
+ log.debug(tag, "No price data from CoinMarketCap for ".concat(symbol));
729
+ return [2 /*return*/, 0];
730
+ case 3:
731
+ error_2 = _b.sent();
732
+ status_4 = ((_a = error_2.response) === null || _a === void 0 ? void 0 : _a.status) || error_2.status;
733
+ if (status_4 === 429 || status_4 === 403) {
734
+ log.warn(tag, "CoinMarketCap rate limit (".concat(status_4, ") for ").concat(symbol));
735
+ }
736
+ else {
737
+ log.debug(tag, "CoinMarketCap error for ".concat(symbol, ": ").concat(error_2.message));
738
+ }
739
+ return [2 /*return*/, 0];
740
+ case 4: return [2 /*return*/];
741
+ }
742
+ });
743
+ });
744
+ };
745
+ /**
746
+ * Get price from CoinCap by symbol
747
+ */
748
+ var get_price_from_coincap = function (symbol) {
749
+ return __awaiter(this, void 0, void 0, function () {
750
+ var tag, url, response, price, error_3, status_5;
751
+ var _a;
752
+ return __generator(this, function (_b) {
753
+ switch (_b.label) {
754
+ case 0:
755
+ tag = TAG + ' | get_price_from_coincap | ';
756
+ if (!COINCAP_API_KEY) {
757
+ log.debug(tag, 'COINCAP_API_KEY not set, skipping CoinCap');
758
+ return [2 /*return*/, 0];
759
+ }
760
+ _b.label = 1;
761
+ case 1:
762
+ _b.trys.push([1, 3, , 4]);
763
+ url = "".concat(URL_COINCAP, "assets/").concat(symbol);
764
+ log.debug(tag, "Fetching from CoinCap: ".concat(url));
765
+ return [4 /*yield*/, axios.get(url, {
766
+ headers: {
767
+ 'Accept': 'application/json',
768
+ 'Authorization': "Bearer ".concat(COINCAP_API_KEY)
769
+ }
770
+ })];
771
+ case 2:
772
+ response = _b.sent();
773
+ if (response.data && response.data.data && response.data.data.priceUsd) {
774
+ price = parseFloat(response.data.data.priceUsd);
775
+ log.debug(tag, "\u2705 CoinCap price for ".concat(symbol, ": $").concat(price));
776
+ return [2 /*return*/, price];
777
+ }
778
+ log.debug(tag, "No price data from CoinCap for ".concat(symbol));
779
+ return [2 /*return*/, 0];
780
+ case 3:
781
+ error_3 = _b.sent();
782
+ status_5 = ((_a = error_3.response) === null || _a === void 0 ? void 0 : _a.status) || error_3.status;
783
+ if (status_5 === 429 || status_5 === 403) {
784
+ log.warn(tag, "CoinCap rate limit (".concat(status_5, ") for ").concat(symbol));
785
+ }
786
+ else {
787
+ log.debug(tag, "CoinCap error for ".concat(symbol, ": ").concat(error_3.message));
788
+ }
789
+ return [2 /*return*/, 0];
790
+ case 4: return [2 /*return*/];
791
+ }
792
+ });
793
+ });
794
+ };
795
+ /**
796
+ * Get price from MayaScan for MAYA token
797
+ * MAYA token is different from CACAO (the gas token)
798
+ */
799
+ var get_price_from_mayascan = function () {
800
+ return __awaiter(this, void 0, void 0, function () {
801
+ var tag, url, response, price, error_4;
802
+ return __generator(this, function (_a) {
803
+ switch (_a.label) {
804
+ case 0:
805
+ tag = TAG + ' | get_price_from_mayascan | ';
806
+ _a.label = 1;
807
+ case 1:
808
+ _a.trys.push([1, 3, , 4]);
809
+ url = 'https://www.mayascan.org/api/maya/price?days=1';
810
+ log.debug(tag, "Fetching MAYA token price from MayaScan: ".concat(url));
811
+ return [4 /*yield*/, axios.get(url)];
812
+ case 2:
813
+ response = _a.sent();
814
+ if (response.data && response.data.mayaPriceInUsd) {
815
+ price = parseFloat(response.data.mayaPriceInUsd);
816
+ log.debug(tag, "\u2705 MayaScan price for MAYA token: $".concat(price));
817
+ return [2 /*return*/, price];
818
+ }
819
+ log.debug(tag, 'No MAYA price data from MayaScan');
820
+ return [2 /*return*/, 0];
821
+ case 3:
822
+ error_4 = _a.sent();
823
+ log.debug(tag, "MayaScan error: ".concat(error_4.message));
824
+ return [2 /*return*/, 0];
825
+ case 4: return [2 /*return*/];
826
+ }
827
+ });
828
+ });
829
+ };
830
+ /**
831
+ * Main function: Get asset price by CAIP
832
+ * Tries all APIs in order: CoinGecko → CoinMarketCap → CoinCap
833
+ */
834
+ var get_asset_price_by_caip = function (caip) {
835
+ return __awaiter(this, void 0, void 0, function () {
836
+ var tag, mayaPrice, identifiers, price;
837
+ return __generator(this, function (_a) {
838
+ switch (_a.label) {
839
+ case 0:
840
+ tag = TAG + ' | get_asset_price_by_caip | ';
841
+ log.debug(tag, "Looking up price for: ".concat(caip));
842
+ if (!(caip === 'cosmos:mayachain-mainnet-v1/denom:maya' || caip.toLowerCase().includes('denom:maya'))) return [3 /*break*/, 2];
843
+ log.debug(tag, 'MAYA token detected, using MayaScan API');
844
+ return [4 /*yield*/, get_price_from_mayascan()];
845
+ case 1:
846
+ mayaPrice = _a.sent();
847
+ if (mayaPrice > 0) {
848
+ return [2 /*return*/, mayaPrice];
849
+ }
850
+ log.warn(tag, '❌ Failed to get MAYA price from MayaScan, trying standard APIs');
851
+ _a.label = 2;
852
+ case 2:
853
+ identifiers = caip_to_identifiers(caip);
854
+ if (!identifiers) {
855
+ log.warn(tag, "No identifier mapping found for CAIP: ".concat(caip));
856
+ return [2 /*return*/, 0];
857
+ }
858
+ log.debug(tag, "Identifiers for ".concat(caip, ":"), identifiers);
859
+ return [4 /*yield*/, get_price_from_coingecko(identifiers.coingeckoId)];
860
+ case 3:
861
+ price = _a.sent();
862
+ if (price > 0) {
863
+ return [2 /*return*/, price];
864
+ }
865
+ return [4 /*yield*/, get_price_from_coinmarketcap(identifiers.cmcSymbol)];
866
+ case 4:
867
+ // Try CoinMarketCap second (requires API key, very comprehensive)
868
+ price = _a.sent();
869
+ if (price > 0) {
870
+ return [2 /*return*/, price];
871
+ }
872
+ return [4 /*yield*/, get_price_from_coincap(identifiers.coincapSymbol)];
873
+ case 5:
874
+ // Try CoinCap last (requires API key, currently rate limited)
875
+ price = _a.sent();
876
+ if (price > 0) {
877
+ return [2 /*return*/, price];
878
+ }
879
+ log.warn(tag, "\u274C No price found from any API for: ".concat(caip));
880
+ return [2 /*return*/, 0];
881
+ }
882
+ });
883
+ });
884
+ };
581
885
  var get_prices_in_quote = function (assets, quote) {
582
886
  return __awaiter(this, void 0, void 0, function () {
583
887
  var tag, result, _i, assets_1, asset, url, response, assetError_1, coincapError_1, data, e_5;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pioneer-platform/markets",
3
- "version": "8.11.0",
3
+ "version": "8.11.2",
4
4
  "main": "./lib/index.js",
5
5
  "types": "./lib/index.d.ts",
6
6
  "dependencies": {