@pioneer-platform/pioneer-sdk 4.21.1 → 4.21.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,7 +1,7 @@
1
1
  {
2
2
  "author": "highlander",
3
3
  "name": "@pioneer-platform/pioneer-sdk",
4
- "version": "4.21.1",
4
+ "version": "4.21.2",
5
5
  "dependencies": {
6
6
  "@keepkey/keepkey-sdk": "^0.2.62",
7
7
  "@pioneer-platform/loggerdog": "^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
@@ -952,7 +952,7 @@ export class SDK {
952
952
  throw e;
953
953
  }
954
954
  };
955
- this.signTx = async function (unsignedTx: any) {
955
+ this.signTx = async function (caip: string, unsignedTx: any) {
956
956
  let tag = TAG + ' | signTx | ';
957
957
  try {
958
958
  const transactionDependencies = {
@@ -966,7 +966,7 @@ export class SDK {
966
966
  keepKeySdk: this.keepKeySdk,
967
967
  };
968
968
  let txManager = new TransactionManager(transactionDependencies, this.events);
969
- let signedTx = await txManager.sign(unsignedTx);
969
+ let signedTx = await txManager.sign({ caip, unsignedTx });
970
970
  return signedTx;
971
971
  } catch (e) {
972
972
  console.error(e);
@@ -1119,13 +1119,12 @@ export class SDK {
1119
1119
  }
1120
1120
 
1121
1121
  let quote = {
1122
- affiliate: '0x658DE0443259a1027caA976ef9a42E6982037A03',
1123
- sellAsset: this.assetContext,
1122
+ sellAsset: this.assetContext.caip, // Send CAIP string, not object
1124
1123
  sellAmount: inputAmount.toPrecision(8),
1125
- buyAsset: this.outboundAssetContext,
1124
+ buyAsset: this.outboundAssetContext.caip, // Send CAIP string, not object
1126
1125
  recipientAddress, // Fill this based on your logic
1127
1126
  senderAddress, // Fill this based on your logic
1128
- slippage: '3',
1127
+ slippage: swapPayload.slippagePercentage || 3,
1129
1128
  };
1130
1129
 
1131
1130
  let result: any;
@@ -1134,10 +1133,13 @@ export class SDK {
1134
1133
  result = result.data;
1135
1134
  } catch (e) {
1136
1135
  console.error(tag, 'Failed to get quote: ', e);
1136
+ throw Error(
1137
+ 'Quote API failed for path: ' + quote.sellAsset + ' -> ' + quote.buyAsset + '. Error: ' + e,
1138
+ );
1137
1139
  }
1138
- if (result.length === 0)
1140
+ if (!result || result.length === 0)
1139
1141
  throw Error(
1140
- 'No quotes available! path: ' + quote.sellAsset.caip + ' -> ' + quote.buyAsset.caip,
1142
+ 'No quotes available! path: ' + quote.sellAsset + ' -> ' + quote.buyAsset,
1141
1143
  );
1142
1144
  //TODO let user handle selecting quote?
1143
1145
  let selected = result[0];
@@ -1145,12 +1147,14 @@ export class SDK {
1145
1147
  if (!txs) throw Error('invalid quote!');
1146
1148
  for (let i = 0; i < txs.length; i++) {
1147
1149
  let tx = txs[i];
1150
+
1148
1151
  const transactionDependencies = {
1149
1152
  context: this.context,
1150
1153
  assetContext: this.assetContext,
1151
1154
  balances: this.balances,
1152
1155
  pioneer: this.pioneer,
1153
1156
  pubkeys: this.pubkeys,
1157
+ pubkeyContext: this.pubkeyContext,
1154
1158
  nodes: this.nodes,
1155
1159
  keepKeySdk: this.keepKeySdk,
1156
1160
  };
@@ -1161,7 +1165,7 @@ export class SDK {
1161
1165
 
1162
1166
  let unsignedTx;
1163
1167
  if (tx.type === 'deposit') {
1164
- //build deposit tx
1168
+ //build deposit tx (Tendermint chains)
1165
1169
  unsignedTx = await createUnsignedTendermintTx(
1166
1170
  caip,
1167
1171
  tx.type,
@@ -1169,11 +1173,16 @@ export class SDK {
1169
1173
  tx.txParams.memo,
1170
1174
  this.pubkeys,
1171
1175
  this.pioneer,
1172
- this.keepKeySdk,
1176
+ this.pubkeyContext,
1173
1177
  false,
1174
1178
  undefined,
1175
1179
  );
1180
+ } else if (tx.type === 'EVM' || tx.type === 'evm') {
1181
+ //EVM transaction - use the pre-built transaction from integration
1182
+ console.log(tag, 'Using pre-built EVM transaction from integration');
1183
+ unsignedTx = tx.txParams;
1176
1184
  } else {
1185
+ //transfer transaction (UTXO chains) - requires memo
1177
1186
  if (!tx.txParams.memo) throw Error('memo required on swaps!');
1178
1187
  const sendPayload: any = {
1179
1188
  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,