@pioneer-platform/pioneer-sdk 4.21.1 → 4.21.3

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,12 +1,12 @@
1
1
  {
2
2
  "author": "highlander",
3
3
  "name": "@pioneer-platform/pioneer-sdk",
4
- "version": "4.21.1",
4
+ "version": "4.21.3",
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
- "@pioneer-platform/pioneer-client": "^9.10.5",
9
+ "@pioneer-platform/pioneer-client": "^9.10.7",
10
10
  "@pioneer-platform/pioneer-coins": "^9.11.0",
11
11
  "@pioneer-platform/pioneer-discovery": "^0.8.0",
12
12
  "@pioneer-platform/pioneer-events": "^8.11.0",
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Custom Tokens Chart Module
3
+ *
4
+ * Fetches user-defined custom token balances from MongoDB-backed server endpoint
5
+ * Follows the stablecoin chart pattern for network-specific token discovery
6
+ */
7
+
8
+ import { ChartBalance, ChartParams, PortfolioToken } from './types';
9
+ import { hydrateAssetData, checkDuplicateBalance, createBalanceIdentifier } from './utils';
10
+
11
+ const tag = '| charts-custom-tokens |';
12
+
13
+ /**
14
+ * Fetch custom tokens for a user address across all EVM networks
15
+ *
16
+ * This function queries the server for user-defined custom tokens and fetches their balances.
17
+ * Custom tokens are stored in MongoDB per user address with network-specific configuration.
18
+ *
19
+ * @param params Chart parameters including pioneer client, pubkeys, and blockchains
20
+ * @param balances Existing balances array (to check for duplicates)
21
+ * @returns Promise that resolves when custom tokens are added to balances array
22
+ */
23
+ export async function fetchCustomTokens(
24
+ params: ChartParams,
25
+ balances: ChartBalance[]
26
+ ): Promise<void> {
27
+ const { pioneer, pubkeys, blockchains, context } = params;
28
+
29
+ console.log(tag, 'Fetching custom tokens...');
30
+
31
+ // Find the primary EVM address
32
+ const evmPubkey = pubkeys.find(
33
+ (e: any) => e.networks && Array.isArray(e.networks) && e.networks.includes('eip155:*')
34
+ );
35
+ const primaryAddress = evmPubkey?.address || evmPubkey?.master;
36
+
37
+ if (!primaryAddress) {
38
+ console.log(tag, 'No EVM address found, skipping custom tokens');
39
+ return;
40
+ }
41
+
42
+ console.log(tag, 'Using EVM address for custom tokens:', primaryAddress);
43
+
44
+ // Networks that support custom tokens endpoint (all EVM networks)
45
+ const supportedNetworks = blockchains.filter((net: string) => net.startsWith('eip155:'));
46
+
47
+ if (supportedNetworks.length === 0) {
48
+ console.log(tag, 'No EVM networks for custom tokens');
49
+ return;
50
+ }
51
+
52
+ console.log(tag, `Checking custom tokens on ${supportedNetworks.length} networks`);
53
+
54
+ // Fetch custom tokens for each network
55
+ for (const networkId of supportedNetworks) {
56
+ try {
57
+ const response = await pioneer.GetCustomTokens({ networkId, address: primaryAddress });
58
+ const customTokens = response?.data?.tokens || [];
59
+
60
+ console.log(tag, `Found ${customTokens.length} custom tokens on ${networkId}`);
61
+
62
+ // Process each custom token
63
+ for (const token of customTokens) {
64
+ // Convert to ChartBalance format
65
+ const chartBalance = processCustomToken(token, primaryAddress, context, blockchains);
66
+
67
+ // Add if not already in balances (avoid duplicates)
68
+ if (chartBalance && !checkDuplicateBalance(balances, chartBalance.caip, chartBalance.pubkey)) {
69
+ balances.push(chartBalance);
70
+ console.log(tag, `Added custom token: ${chartBalance.symbol} = ${chartBalance.balance}`);
71
+ }
72
+ }
73
+ } catch (error: any) {
74
+ console.error(tag, `Error fetching custom tokens for ${networkId}:`, error.message);
75
+ // Continue with other networks even if one fails
76
+ }
77
+ }
78
+
79
+ console.log(tag, `Custom tokens complete. Total balances: ${balances.length}`);
80
+ }
81
+
82
+ /**
83
+ * Process a custom token into ChartBalance format
84
+ * Follows the same pattern as processPortfolioToken in evm.ts
85
+ */
86
+ function processCustomToken(
87
+ token: PortfolioToken,
88
+ primaryAddress: string,
89
+ context: string,
90
+ blockchains: string[]
91
+ ): ChartBalance | null {
92
+ if (!token.assetCaip || !token.networkId) {
93
+ return null;
94
+ }
95
+
96
+ // Extract the networkId from the assetCaip
97
+ let extractedNetworkId = token.networkId;
98
+
99
+ // For tokens with special formats, extract network part
100
+ if (token.assetCaip.includes('/denom:')) {
101
+ const parts = token.assetCaip.split('/denom:');
102
+ if (parts.length > 0) {
103
+ extractedNetworkId = parts[0];
104
+ }
105
+ } else if (token.networkId && token.networkId.includes('/')) {
106
+ extractedNetworkId = token.networkId.split('/')[0];
107
+ }
108
+
109
+ // Accept ALL EIP155 chains (since we have eip155:* pubkey)
110
+ const isEip155 = extractedNetworkId.startsWith('eip155:');
111
+ if (!isEip155 && !blockchains.includes(extractedNetworkId)) {
112
+ return null;
113
+ }
114
+
115
+ // Hydrate token with assetData
116
+ const tokenAssetInfo = hydrateAssetData(token.assetCaip);
117
+
118
+ // Use consistent pubkey
119
+ const tokenPubkey = token.pubkey || primaryAddress;
120
+
121
+ const chartBalance: ChartBalance = {
122
+ context,
123
+ chart: 'pioneer',
124
+ contextType: context.split(':')[0],
125
+ name: tokenAssetInfo?.name || token.token?.name || 'Unknown Custom Token',
126
+ caip: token.assetCaip,
127
+ icon: tokenAssetInfo?.icon || token.token?.icon || '',
128
+ pubkey: tokenPubkey,
129
+ ticker: tokenAssetInfo?.symbol || token.token?.symbol || 'UNK',
130
+ ref: `${context}${token.assetCaip}`,
131
+ identifier: createBalanceIdentifier(token.assetCaip, tokenPubkey),
132
+ networkId: extractedNetworkId,
133
+ symbol: tokenAssetInfo?.symbol || token.token?.symbol || 'UNK',
134
+ type: tokenAssetInfo?.type || 'erc20',
135
+ token: true, // Custom tokens are always tokens
136
+ decimal: tokenAssetInfo?.decimal || token.token?.decimal,
137
+ balance: token.token?.balance?.toString() || '0',
138
+ priceUsd: token.token?.price || 0,
139
+ valueUsd: token.token?.balanceUSD || 0,
140
+ updated: new Date().getTime(),
141
+ };
142
+
143
+ return chartBalance;
144
+ }
package/src/charts/evm.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { ChartBalance, ChartParams, PortfolioBalance, PortfolioToken } from './types';
2
2
  import { hydrateAssetData, checkDuplicateBalance, createBalanceIdentifier } from './utils';
3
+ import { fetchCustomTokens } from './custom-tokens';
3
4
 
4
5
  const tag = '| charts-evm |';
5
6
 
@@ -32,6 +33,10 @@ export async function getEvmCharts(params: ChartParams): Promise<ChartBalance[]>
32
33
  // This ensures USDC/USDT balances are always available even if Zapper fails
33
34
  await fetchStableCoins(pioneer, primaryAddress, blockchains, balances, context);
34
35
 
36
+ // CUSTOM TOKENS: Fetch user-defined custom tokens from MongoDB-backed endpoint
37
+ // This ensures user's custom tokens are always included in their portfolio
38
+ await fetchCustomTokens({ blockchains, pioneer, pubkeys, context }, balances);
39
+
35
40
  try {
36
41
  // NOTE: Zapper API returns portfolio data across ALL networks for a given address
37
42
  // We use eip155:1 as the networkId parameter, but Zapper will return data for all EVM chains
package/src/index.ts CHANGED
@@ -188,14 +188,6 @@ export class SDK {
188
188
  if (config.blockchains && config.blockchains.length !== this.blockchains.length) {
189
189
  }
190
190
 
191
- // Initialize pubkeys with deduplication if provided in config
192
- if (config.pubkeys && config.pubkeys.length > 0) {
193
- this.setPubkeys(config.pubkeys);
194
- } else {
195
- this.pubkeys = [];
196
- this.pubkeySet.clear();
197
- }
198
-
199
191
  this.balances = config.balances || [];
200
192
  this.nodes = config.nodes || [];
201
193
  this.charts = ['covalent', 'zapper'];
@@ -288,6 +280,15 @@ export class SDK {
288
280
  }
289
281
  };
290
282
 
283
+ // Initialize pubkeys with deduplication if provided in config
284
+ // IMPORTANT: This must come AFTER setPubkeys is defined above
285
+ if (config.pubkeys && config.pubkeys.length > 0) {
286
+ this.setPubkeys(config.pubkeys);
287
+ } else {
288
+ this.pubkeys = [];
289
+ this.pubkeySet.clear();
290
+ }
291
+
291
292
  // Fast portfolio loading from kkapi:// cache
292
293
  this.getUnifiedPortfolio = async function () {
293
294
  const tag = `${TAG} | getUnifiedPortfolio | `;
@@ -952,7 +953,7 @@ export class SDK {
952
953
  throw e;
953
954
  }
954
955
  };
955
- this.signTx = async function (unsignedTx: any) {
956
+ this.signTx = async function (caip: string, unsignedTx: any) {
956
957
  let tag = TAG + ' | signTx | ';
957
958
  try {
958
959
  const transactionDependencies = {
@@ -966,7 +967,7 @@ export class SDK {
966
967
  keepKeySdk: this.keepKeySdk,
967
968
  };
968
969
  let txManager = new TransactionManager(transactionDependencies, this.events);
969
- let signedTx = await txManager.sign(unsignedTx);
970
+ let signedTx = await txManager.sign({ caip, unsignedTx });
970
971
  return signedTx;
971
972
  } catch (e) {
972
973
  console.error(e);
@@ -1119,13 +1120,12 @@ export class SDK {
1119
1120
  }
1120
1121
 
1121
1122
  let quote = {
1122
- affiliate: '0x658DE0443259a1027caA976ef9a42E6982037A03',
1123
- sellAsset: this.assetContext,
1123
+ sellAsset: this.assetContext.caip, // Send CAIP string, not object
1124
1124
  sellAmount: inputAmount.toPrecision(8),
1125
- buyAsset: this.outboundAssetContext,
1125
+ buyAsset: this.outboundAssetContext.caip, // Send CAIP string, not object
1126
1126
  recipientAddress, // Fill this based on your logic
1127
1127
  senderAddress, // Fill this based on your logic
1128
- slippage: '3',
1128
+ slippage: swapPayload.slippagePercentage || 3,
1129
1129
  };
1130
1130
 
1131
1131
  let result: any;
@@ -1134,10 +1134,13 @@ export class SDK {
1134
1134
  result = result.data;
1135
1135
  } catch (e) {
1136
1136
  console.error(tag, 'Failed to get quote: ', e);
1137
+ throw Error(
1138
+ 'Quote API failed for path: ' + quote.sellAsset + ' -> ' + quote.buyAsset + '. Error: ' + e,
1139
+ );
1137
1140
  }
1138
- if (result.length === 0)
1141
+ if (!result || result.length === 0)
1139
1142
  throw Error(
1140
- 'No quotes available! path: ' + quote.sellAsset.caip + ' -> ' + quote.buyAsset.caip,
1143
+ 'No quotes available! path: ' + quote.sellAsset + ' -> ' + quote.buyAsset,
1141
1144
  );
1142
1145
  //TODO let user handle selecting quote?
1143
1146
  let selected = result[0];
@@ -1145,12 +1148,14 @@ export class SDK {
1145
1148
  if (!txs) throw Error('invalid quote!');
1146
1149
  for (let i = 0; i < txs.length; i++) {
1147
1150
  let tx = txs[i];
1151
+
1148
1152
  const transactionDependencies = {
1149
1153
  context: this.context,
1150
1154
  assetContext: this.assetContext,
1151
1155
  balances: this.balances,
1152
1156
  pioneer: this.pioneer,
1153
1157
  pubkeys: this.pubkeys,
1158
+ pubkeyContext: this.pubkeyContext,
1154
1159
  nodes: this.nodes,
1155
1160
  keepKeySdk: this.keepKeySdk,
1156
1161
  };
@@ -1161,7 +1166,7 @@ export class SDK {
1161
1166
 
1162
1167
  let unsignedTx;
1163
1168
  if (tx.type === 'deposit') {
1164
- //build deposit tx
1169
+ //build deposit tx (Tendermint chains)
1165
1170
  unsignedTx = await createUnsignedTendermintTx(
1166
1171
  caip,
1167
1172
  tx.type,
@@ -1169,11 +1174,16 @@ export class SDK {
1169
1174
  tx.txParams.memo,
1170
1175
  this.pubkeys,
1171
1176
  this.pioneer,
1172
- this.keepKeySdk,
1177
+ this.pubkeyContext,
1173
1178
  false,
1174
1179
  undefined,
1175
1180
  );
1181
+ } else if (tx.type === 'EVM' || tx.type === 'evm') {
1182
+ //EVM transaction - use the pre-built transaction from integration
1183
+ console.log(tag, 'Using pre-built EVM transaction from integration');
1184
+ unsignedTx = tx.txParams;
1176
1185
  } else {
1186
+ //transfer transaction (UTXO chains) - requires memo
1177
1187
  if (!tx.txParams.memo) throw Error('memo required on swaps!');
1178
1188
  const sendPayload: any = {
1179
1189
  caip,
@@ -146,6 +146,13 @@ export function buildDashboardFromBalances(balances: any[], blockchains: string[
146
146
  // Get colors from assetMap since balances don't have them
147
147
  const assetInfo = nativeAssetCaip ? assetsMap.get(nativeAssetCaip) : null;
148
148
 
149
+ // Debug logging
150
+ console.log(TAG, `[DEBUG] Network: ${blockchain}`);
151
+ console.log(TAG, `[DEBUG] nativeAssetCaip: ${nativeAssetCaip}`);
152
+ console.log(TAG, `[DEBUG] assetInfo:`, assetInfo);
153
+ console.log(TAG, `[DEBUG] gasAsset:`, gasAsset);
154
+ console.log(TAG, `[DEBUG] Resolved name: ${gasAsset?.name || assetInfo?.name || 'NO NAME'}`);
155
+
149
156
  networksTemp.push({
150
157
  networkId: blockchain,
151
158
  totalValueUsd: networkTotal,