@pioneer-platform/pioneer-sdk 8.14.0 → 8.15.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.
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "author": "highlander",
3
3
  "name": "@pioneer-platform/pioneer-sdk",
4
- "version": "8.14.0",
4
+ "version": "8.15.2",
5
5
  "dependencies": {
6
6
  "@keepkey/keepkey-sdk": "^0.2.62",
7
7
  "@pioneer-platform/loggerdog": "^8.11.0",
8
8
  "@pioneer-platform/pioneer-caip": "^9.10.0",
9
9
  "@pioneer-platform/pioneer-client": "^9.10.10",
10
10
  "@pioneer-platform/pioneer-coins": "^9.11.0",
11
- "@pioneer-platform/pioneer-discovery": "^8.12.0",
11
+ "@pioneer-platform/pioneer-discovery": "^8.14.1",
12
12
  "@pioneer-platform/pioneer-events": "^8.12.0",
13
13
  "coinselect": "^3.1.13",
14
14
  "eventemitter3": "^5.0.1",
package/src/fees/index.ts CHANGED
@@ -89,13 +89,19 @@ export async function getFees(
89
89
  try {
90
90
  console.log(tag, `Fetching fees for network: ${networkId}`);
91
91
 
92
- // For Cosmos chains, always use hardcoded fees
92
+ // For Cosmos chains, always use hardcoded fees (multiple Cosmos chains)
93
93
  const networkType = getNetworkType(networkId);
94
94
  if (networkType === 'COSMOS') {
95
95
  console.log(tag, 'Using hardcoded fees for Cosmos network:', networkId);
96
96
  return getCosmosFees(networkId);
97
97
  }
98
98
 
99
+ // Hardcode XRP fees (fixed fee model)
100
+ if (networkId === 'ripple:4109c6f2045fc7eff4cde8f9905d19c2') {
101
+ console.log(tag, 'Using hardcoded fees for Ripple: 0.00001 XRP');
102
+ return getRippleFees(networkId);
103
+ }
104
+
99
105
  // Hardcode DOGE fees at 10 sat/byte (API and Blockbook often unreliable for DOGE)
100
106
  if (networkId === 'bip122:00000000001a91e3dace36e2be3bf030') {
101
107
  console.log(tag, 'Using hardcoded fees for Dogecoin: 10 sat/byte');
@@ -535,6 +541,48 @@ function getCosmosFees(networkId: string): NormalizedFeeRates {
535
541
  };
536
542
  }
537
543
 
544
+ /**
545
+ * Get hardcoded Ripple fees
546
+ * XRP uses a fixed fee model with very low transaction costs
547
+ */
548
+ function getRippleFees(networkId: string): NormalizedFeeRates {
549
+ const networkName = getNetworkName(networkId);
550
+
551
+ // XRP standard fee is 0.00001 XRP (10 drops)
552
+ // This is sufficient for most transactions and is the network minimum
553
+ const standardFee = '0.00001';
554
+
555
+ return {
556
+ slow: {
557
+ label: 'Standard',
558
+ value: standardFee,
559
+ unit: 'XRP',
560
+ description: `Fixed fee for ${networkName}. XRP uses a deterministic fee model.`,
561
+ estimatedTime: '~4 seconds',
562
+ priority: 'low',
563
+ },
564
+ average: {
565
+ label: 'Standard',
566
+ value: standardFee,
567
+ unit: 'XRP',
568
+ description: `Fixed fee for ${networkName}. XRP uses a deterministic fee model.`,
569
+ estimatedTime: '~4 seconds',
570
+ priority: 'medium',
571
+ },
572
+ fastest: {
573
+ label: 'Standard',
574
+ value: standardFee,
575
+ unit: 'XRP',
576
+ description: `Fixed fee for ${networkName}. XRP uses a deterministic fee model.`,
577
+ estimatedTime: '~4 seconds',
578
+ priority: 'high',
579
+ },
580
+ networkId,
581
+ networkType: 'RIPPLE',
582
+ raw: { hardcoded: true, fee: standardFee, unit: 'XRP' },
583
+ };
584
+ }
585
+
538
586
  /**
539
587
  * Get fallback fees when API fails
540
588
  */
package/src/index.ts CHANGED
@@ -782,6 +782,13 @@ export class SDK {
782
782
  this.buildDashboardFromBalances = function () {
783
783
  return buildDashboardFromBalances(this.balances, this.blockchains, this.assetsMap);
784
784
  };
785
+ // ✅ PHASE 3: Infer asset type from CAIP structure (fallback helper)
786
+ this.inferTypeFromCaip = function (caip: string): string {
787
+ if (caip.includes('/slip44:')) return 'native';
788
+ if (caip.includes('/erc20:') || caip.includes('/bep20:') || caip.includes('/spl:')) return 'token';
789
+ if (caip.includes('/denom:')) return 'native'; // Cosmos denoms
790
+ return 'unknown';
791
+ };
785
792
  this.syncMarket = async function () {
786
793
  return syncMarket(this.balances, this.pioneer);
787
794
  };
@@ -1880,7 +1887,7 @@ export class SDK {
1880
1887
  throw error;
1881
1888
  }
1882
1889
  };
1883
- this.getBalancesForNetworks = async function (networkIds: string[]) {
1890
+ this.getBalancesForNetworks = async function (networkIds: string[], forceRefresh?: boolean) {
1884
1891
  const tag = `${TAG} | getBalancesForNetworks | `;
1885
1892
  try {
1886
1893
  // Add defensive check for pioneer initialization
@@ -1893,6 +1900,11 @@ export class SDK {
1893
1900
  throw new Error('Pioneer client not initialized. Call init() first.');
1894
1901
  }
1895
1902
 
1903
+ // Log force refresh request
1904
+ if (forceRefresh) {
1905
+ console.log(tag, '🔄 Force refresh requested - bypassing balance cache');
1906
+ }
1907
+
1896
1908
  // DIAGNOSTIC: Log input
1897
1909
  console.log('🔍 [DIAGNOSTIC] Input networks:', networkIds);
1898
1910
  console.log('🔍 [DIAGNOSTIC] Total pubkeys:', this.pubkeys.length);
@@ -1987,7 +1999,11 @@ export class SDK {
1987
1999
 
1988
2000
  try {
1989
2001
  // Wrap assetQuery in object with pubkeys field (API expects { pubkeys: [...] })
1990
- let marketInfo = await this.pioneer.GetPortfolioBalances({ pubkeys: assetQuery });
2002
+ // Pass forceRefresh as query parameter if provided
2003
+ let marketInfo = await this.pioneer.GetPortfolioBalances(
2004
+ { pubkeys: assetQuery },
2005
+ forceRefresh ? { forceRefresh: true } : undefined
2006
+ );
1991
2007
  const apiCallTime = performance.now() - apiCallStart;
1992
2008
  console.timeEnd('GetPortfolioBalances Response Time');
1993
2009
  console.log(`⏱️ [PERF] API call completed in ${apiCallTime.toFixed(0)}ms`);
@@ -2000,12 +2016,30 @@ export class SDK {
2000
2016
  console.log(`⏱️ [PERF] Starting balance enrichment...`);
2001
2017
  for (let balance of balances) {
2002
2018
  const assetInfo = this.assetsMap.get(balance.caip.toLowerCase()) || this.assetsMap.get(balance.caip);
2003
- if (!assetInfo) continue;
2019
+
2020
+ // ✅ PHASE 3: Add fallback for missing asset metadata
2021
+ if (!assetInfo) {
2022
+ console.warn(`⚠️ [ENRICHMENT] Asset metadata missing for ${balance.caip}, using fallback enrichment`);
2023
+
2024
+ // Fallback: Use API-provided values or infer from CAIP
2025
+ const inferredType = this.inferTypeFromCaip(balance.caip);
2026
+ Object.assign(balance, {
2027
+ type: balance.type || inferredType,
2028
+ isNative: balance.isNative ?? (inferredType === 'native'),
2029
+ networkId: caipToNetworkId(balance.caip),
2030
+ icon: 'https://pioneers.dev/coins/unknown.png',
2031
+ identifier: `${balance.caip}:${balance.pubkey}`,
2032
+ updated: Date.now(),
2033
+ });
2034
+ continue;
2035
+ }
2004
2036
 
2005
2037
  // Get color from mapping (fallback to assetInfo.color if it exists)
2006
2038
  const color = ASSET_COLORS[balance.caip] || assetInfo.color;
2007
2039
 
2008
2040
  Object.assign(balance, assetInfo, {
2041
+ type: balance.type || assetInfo.type, // ✅ PHASE 3: Prefer API type, fallback to assetInfo
2042
+ isNative: balance.isNative ?? assetInfo.isNative, // ✅ PHASE 3: Prefer API isNative
2009
2043
  networkId: caipToNetworkId(balance.caip),
2010
2044
  icon: assetInfo.icon || 'https://pioneers.dev/coins/etherum.png',
2011
2045
  identifier: `${balance.caip}:${balance.pubkey}`,
@@ -2041,11 +2075,11 @@ export class SDK {
2041
2075
  throw e;
2042
2076
  }
2043
2077
  };
2044
- this.getBalances = async function () {
2078
+ this.getBalances = async function (forceRefresh?: boolean) {
2045
2079
  const tag = `${TAG} | getBalances | `;
2046
2080
  try {
2047
2081
  // Simply call the shared function with all blockchains
2048
- return await this.getBalancesForNetworks(this.blockchains);
2082
+ return await this.getBalancesForNetworks(this.blockchains, forceRefresh);
2049
2083
  } catch (e) {
2050
2084
  console.error(tag, 'Error in getBalances: ', e);
2051
2085
  throw e;
@@ -2110,57 +2144,21 @@ export class SDK {
2110
2144
  this.getCharts = async function () {
2111
2145
  const tag = `${TAG} | getCharts | `;
2112
2146
  try {
2113
- console.log(tag, 'Fetching charts from batch endpoint');
2114
-
2115
- // Build pubkeys array for batch request
2116
- const pubkeysForBatch: { pubkey: string; caip: string }[] = [];
2117
-
2118
- for (const pubkey of this.pubkeys) {
2119
- const address = pubkey.address || pubkey.master || pubkey.pubkey;
2120
- if (!address) continue;
2121
-
2122
- // Get networks this pubkey supports
2123
- const supportedNetworks = pubkey.networks || [];
2124
-
2125
- // For each blockchain we're processing
2126
- for (const blockchain of this.blockchains) {
2127
- // Check if this pubkey supports this blockchain
2128
- const supportsNetwork = supportedNetworks.some((net: string) =>
2129
- net === blockchain ||
2130
- (net.endsWith(':*') && blockchain.startsWith(net.replace(':*', ':')))
2131
- );
2132
-
2133
- if (supportsNetwork) {
2134
- // Build the CAIP for this combination
2135
- let caip: string;
2136
- if (blockchain.startsWith('eip155:')) {
2137
- caip = `${blockchain}/slip44:60`;
2138
- } else {
2139
- caip = `${blockchain}/slip44:0`; // Fallback for non-EVM
2140
- }
2141
-
2142
- pubkeysForBatch.push({
2143
- pubkey: address,
2144
- caip: caip
2145
- });
2146
- }
2147
- }
2148
- }
2149
-
2150
- console.log(tag, `Calling batch GetCharts with ${pubkeysForBatch.length} pubkeys`);
2151
-
2152
- // Single batch call to get ALL charts data
2153
- let newBalances = [];
2154
- try {
2155
- const chartsResponse = await this.pioneer.GetCharts({
2156
- pubkeys: pubkeysForBatch
2157
- });
2158
- newBalances = chartsResponse?.data?.balances || [];
2159
- console.log(tag, `Received ${newBalances.length} balances from batch endpoint`);
2160
- } catch (chartsError: any) {
2161
- // GetCharts API may not be available - gracefully continue without charts data
2162
- console.warn(tag, `GetCharts API not available (${chartsError.message}), continuing without charts data`);
2163
- }
2147
+ console.log(tag, 'Fetching charts (portfolio + tokens + staking)...');
2148
+
2149
+ // Use the NEW modular chart implementation
2150
+ // This calls /charts/portfolio (BLOCKING) which fetches tokens from Zapper/Unchained
2151
+ const { getCharts: getChartsModular } = await import('./charts');
2152
+
2153
+ // Call new implementation with all required parameters
2154
+ const newBalances = await getChartsModular(
2155
+ this.blockchains,
2156
+ this.pioneer,
2157
+ this.pubkeys,
2158
+ this.context
2159
+ );
2160
+
2161
+ console.log(tag, `Modular charts returned ${newBalances.length} balances (native + tokens + staking)`);
2164
2162
 
2165
2163
  // Deduplicate balances using a Map with `identifier` as the key
2166
2164
  const uniqueBalances = new Map(
@@ -2172,11 +2170,15 @@ export class SDK {
2172
2170
  },
2173
2171
  ]),
2174
2172
  );
2175
- console.log(tag, 'uniqueBalances: ', uniqueBalances.size);
2173
+ console.log(tag, 'Deduplicated to:', uniqueBalances.size, 'unique balances');
2176
2174
 
2177
2175
  // Convert Map back to array and set this.balances
2178
2176
  this.balances = Array.from(uniqueBalances.values());
2179
- console.log(tag, 'Updated this.balances: ', this.balances.length);
2177
+
2178
+ // Log breakdown of balance types
2179
+ const tokens = this.balances.filter((b: any) => b.token === true);
2180
+ const native = this.balances.filter((b: any) => b.token !== true);
2181
+ console.log(tag, `Balance breakdown: ${native.length} native + ${tokens.length} tokens = ${this.balances.length} total`);
2180
2182
 
2181
2183
  return this.balances;
2182
2184
  } catch (e) {
@@ -2208,10 +2210,15 @@ export class SDK {
2208
2210
  return { success: false };
2209
2211
  }
2210
2212
  };
2211
- this.refresh = async (): Promise<any> => {
2213
+ this.refresh = async (forceRefresh?: boolean): Promise<any> => {
2212
2214
  const tag = `${TAG} | refresh | `;
2213
2215
  try {
2214
- await this.sync();
2216
+ if (forceRefresh) {
2217
+ console.log(tag, '🔄 Force refresh - fetching fresh balances from blockchain');
2218
+ await this.getBalances(true);
2219
+ } else {
2220
+ await this.sync();
2221
+ }
2215
2222
  return this.balances;
2216
2223
  } catch (e) {
2217
2224
  console.error(tag, 'e: ', e);