@pioneer-platform/pioneer-sdk 4.21.7 → 4.21.9

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/dist/index.cjs CHANGED
@@ -3350,7 +3350,13 @@ async function getFees(pioneer, networkId) {
3350
3350
  };
3351
3351
  }
3352
3352
  } else {
3353
- feeResponse = await (pioneer.GetFeeRateByNetwork ? pioneer.GetFeeRateByNetwork({ networkId }) : pioneer.GetFeeRate({ networkId }));
3353
+ if (networkType === "EVM") {
3354
+ console.log(tag6, "Using GetGasPriceByNetwork for EVM network:", networkId);
3355
+ feeResponse = await (pioneer.GetGasPriceByNetwork ? pioneer.GetGasPriceByNetwork({ networkId }) : Promise.reject(new Error("GetGasPriceByNetwork not available")));
3356
+ } else {
3357
+ console.log(tag6, "Using GetFeeRateByNetwork for UTXO network:", networkId);
3358
+ feeResponse = await (pioneer.GetFeeRateByNetwork ? pioneer.GetFeeRateByNetwork({ networkId }) : pioneer.GetFeeRate({ networkId }));
3359
+ }
3354
3360
  }
3355
3361
  if (!feeResponse || !feeResponse.data) {
3356
3362
  throw new Error(`No fee data returned for ${networkId}`);
package/dist/index.es.js CHANGED
@@ -3526,7 +3526,13 @@ async function getFees(pioneer, networkId) {
3526
3526
  };
3527
3527
  }
3528
3528
  } else {
3529
- feeResponse = await (pioneer.GetFeeRateByNetwork ? pioneer.GetFeeRateByNetwork({ networkId }) : pioneer.GetFeeRate({ networkId }));
3529
+ if (networkType === "EVM") {
3530
+ console.log(tag6, "Using GetGasPriceByNetwork for EVM network:", networkId);
3531
+ feeResponse = await (pioneer.GetGasPriceByNetwork ? pioneer.GetGasPriceByNetwork({ networkId }) : Promise.reject(new Error("GetGasPriceByNetwork not available")));
3532
+ } else {
3533
+ console.log(tag6, "Using GetFeeRateByNetwork for UTXO network:", networkId);
3534
+ feeResponse = await (pioneer.GetFeeRateByNetwork ? pioneer.GetFeeRateByNetwork({ networkId }) : pioneer.GetFeeRate({ networkId }));
3535
+ }
3530
3536
  }
3531
3537
  if (!feeResponse || !feeResponse.data) {
3532
3538
  throw new Error(`No fee data returned for ${networkId}`);
package/dist/index.js CHANGED
@@ -3526,7 +3526,13 @@ async function getFees(pioneer, networkId) {
3526
3526
  };
3527
3527
  }
3528
3528
  } else {
3529
- feeResponse = await (pioneer.GetFeeRateByNetwork ? pioneer.GetFeeRateByNetwork({ networkId }) : pioneer.GetFeeRate({ networkId }));
3529
+ if (networkType === "EVM") {
3530
+ console.log(tag6, "Using GetGasPriceByNetwork for EVM network:", networkId);
3531
+ feeResponse = await (pioneer.GetGasPriceByNetwork ? pioneer.GetGasPriceByNetwork({ networkId }) : Promise.reject(new Error("GetGasPriceByNetwork not available")));
3532
+ } else {
3533
+ console.log(tag6, "Using GetFeeRateByNetwork for UTXO network:", networkId);
3534
+ feeResponse = await (pioneer.GetFeeRateByNetwork ? pioneer.GetFeeRateByNetwork({ networkId }) : pioneer.GetFeeRate({ networkId }));
3535
+ }
3530
3536
  }
3531
3537
  if (!feeResponse || !feeResponse.data) {
3532
3538
  throw new Error(`No fee data returned for ${networkId}`);
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.7",
4
+ "version": "4.21.9",
5
5
  "dependencies": {
6
6
  "@keepkey/keepkey-sdk": "^0.2.62",
7
7
  "@pioneer-platform/loggerdog": "^8.11.0",
@@ -48,8 +48,6 @@
48
48
  },
49
49
  "react-native": "./src/index.ts",
50
50
  "repository": "https://github.com/thorswap/SwapKit.git",
51
- "type": "module",
52
- "types": "./dist/index.d.ts",
53
51
  "scripts": {
54
52
  "build": "bash scripts/build.sh",
55
53
  "build:watch": "nodemon --watch src --exec 'bun run build'",
@@ -57,5 +55,7 @@
57
55
  "lint": "eslint ./ --ext .ts,.tsx --fix; tsc --noEmit",
58
56
  "test": "echo 'vitest --run'",
59
57
  "test:coverage": "echo 'vitest run --coverage'"
60
- }
61
- }
58
+ },
59
+ "type": "module",
60
+ "types": "./dist/index.d.ts"
61
+ }
package/src/fees/index.ts CHANGED
@@ -172,10 +172,20 @@ export async function getFees(
172
172
  };
173
173
  }
174
174
  } else {
175
- // Normal API call for other networks
176
- feeResponse = await (pioneer.GetFeeRateByNetwork
177
- ? pioneer.GetFeeRateByNetwork({ networkId })
178
- : pioneer.GetFeeRate({ networkId }));
175
+ // Route to correct API endpoint based on network type
176
+ if (networkType === 'EVM') {
177
+ // For EVM networks, use GetGasPriceByNetwork endpoint
178
+ console.log(tag, 'Using GetGasPriceByNetwork for EVM network:', networkId);
179
+ feeResponse = await (pioneer.GetGasPriceByNetwork
180
+ ? pioneer.GetGasPriceByNetwork({ networkId })
181
+ : Promise.reject(new Error('GetGasPriceByNetwork not available')));
182
+ } else {
183
+ // For UTXO networks, use GetFeeRateByNetwork endpoint
184
+ console.log(tag, 'Using GetFeeRateByNetwork for UTXO network:', networkId);
185
+ feeResponse = await (pioneer.GetFeeRateByNetwork
186
+ ? pioneer.GetFeeRateByNetwork({ networkId })
187
+ : pioneer.GetFeeRate({ networkId }));
188
+ }
179
189
  }
180
190
 
181
191
  if (!feeResponse || !feeResponse.data) {
@@ -1,384 +0,0 @@
1
- import { caipToNetworkId, NetworkIdToChain } from '@pioneer-platform/pioneer-caip';
2
- import { bip32ToAddressNList } from '@pioneer-platform/pioneer-coins';
3
- import coinSelect from 'coinselect';
4
- import coinSelectSplit from 'coinselect/split';
5
-
6
- export async function createUnsignedUxtoTx(
7
- caip: string,
8
- to: string,
9
- amount: number,
10
- memo: string,
11
- pubkeys: any,
12
- pioneer: any,
13
- keepKeySdk: any,
14
- isMax: boolean, // Added isMax parameter
15
- feeLevel: number = 5, // Added feeLevel parameter with default of 5 (average)
16
- changeScriptType?: string, // Added changeScriptType parameter for user preference
17
- ): Promise<any> {
18
- let tag = ' | createUnsignedUxtoTx | ';
19
-
20
- try {
21
- if (!pioneer) throw Error('Failed to init! pioneer');
22
-
23
- const networkId = caipToNetworkId(caip);
24
-
25
- // Auto-correct context if wrong network
26
- if (!keepKeySdk.pubkeyContext?.networks?.includes(networkId)) {
27
- keepKeySdk.pubkeyContext = pubkeys.find((pk) => pk.networks?.includes(networkId));
28
- }
29
-
30
- // For UTXO, we still need all relevant pubkeys to aggregate UTXOs
31
- const relevantPubkeys = pubkeys.filter(
32
- (e) => e.networks && Array.isArray(e.networks) && e.networks.includes(networkId),
33
- );
34
-
35
- const segwitNetworks = [
36
- 'bip122:000000000019d6689c085ae165831e93', // Bitcoin Mainnet
37
- // 'bip122:12a765e31ffd4059bada1e25190f6e98', // LTC
38
- ];
39
-
40
- // Check if the current networkId is in the SegWit networks array
41
- const isSegwit = segwitNetworks.includes(networkId);
42
-
43
- let chain = NetworkIdToChain[networkId];
44
-
45
- // Determine the change script type - use preference or default to p2wpkh for lower fees
46
- const actualChangeScriptType =
47
- changeScriptType ||
48
- relevantPubkeys.find((pk) => pk.scriptType === 'p2wpkh')?.scriptType || // Prefer native segwit if available
49
- relevantPubkeys[0].scriptType || // Fall back to first available
50
- 'p2wpkh'; // Ultimate default
51
- console.log(`${tag}: Using change script type: ${actualChangeScriptType}`);
52
-
53
- // Find the xpub that matches the desired script type
54
- const changeXpub =
55
- relevantPubkeys.find((pk) => pk.scriptType === actualChangeScriptType)?.pubkey ||
56
- relevantPubkeys.find((pk) => pk.scriptType === 'p2wpkh')?.pubkey || // Fall back to native segwit
57
- relevantPubkeys[0].pubkey; // Last resort: use first available
58
-
59
- console.log(
60
- `${tag}: Change xpub selected for ${actualChangeScriptType}:`,
61
- changeXpub?.substring(0, 10) + '...',
62
- );
63
-
64
- let changeAddressIndex = await pioneer.GetChangeAddress({
65
- network: chain,
66
- xpub: changeXpub,
67
- });
68
- changeAddressIndex = changeAddressIndex.data.changeIndex;
69
-
70
- // Determine BIP path based on script type
71
- let bipPath: string;
72
- switch (actualChangeScriptType) {
73
- case 'p2pkh':
74
- bipPath = `m/44'/0'/0'/1/${changeAddressIndex}`; // BIP44 for legacy
75
- break;
76
- case 'p2sh-p2wpkh':
77
- bipPath = `m/49'/0'/0'/1/${changeAddressIndex}`; // BIP49 for wrapped segwit
78
- break;
79
- case 'p2wpkh':
80
- default:
81
- bipPath = `m/84'/0'/0'/1/${changeAddressIndex}`; // BIP84 for native segwit
82
- break;
83
- }
84
-
85
- const path = bipPath;
86
- console.log(`${tag}: Change address path: ${path} (index: ${changeAddressIndex})`);
87
-
88
- const changeAddress = {
89
- path: path,
90
- isChange: true,
91
- index: changeAddressIndex,
92
- addressNList: bip32ToAddressNList(path),
93
- scriptType: actualChangeScriptType, // Store the script type with the change address
94
- };
95
-
96
- const utxos: any[] = [];
97
- for (const pubkey of relevantPubkeys) {
98
- //console.log('pubkey: ',pubkey)
99
- try {
100
- let utxosResp = await pioneer.ListUnspent({ network: chain, xpub: pubkey.pubkey });
101
- utxosResp = utxosResp.data;
102
- console.log(
103
- `${tag}: ListUnspent response for ${pubkey.scriptType}:`,
104
- utxosResp?.length || 0,
105
- 'UTXOs',
106
- );
107
-
108
- // Validate the response
109
- if (!utxosResp || !Array.isArray(utxosResp)) {
110
- console.warn(`${tag}: Invalid or empty UTXO response for ${pubkey.pubkey}`);
111
- continue;
112
- }
113
-
114
- //classify scriptType
115
- let scriptType = pubkey.scriptType;
116
- // Assign the scriptType to each UTXO in the array
117
- for (const u of utxosResp) {
118
- u.scriptType = scriptType;
119
- }
120
- utxos.push(...utxosResp);
121
- } catch (error) {
122
- console.error(`${tag}: Failed to fetch UTXOs for ${pubkey.pubkey}:`, error);
123
- // Continue to next pubkey instead of failing entirely
124
- }
125
- }
126
-
127
- console.log(`${tag}: Total UTXOs collected:`, utxos.length);
128
- if (!utxos || utxos.length === 0) throw Error('No UTXOs found across all addresses');
129
-
130
- for (const utxo of utxos) {
131
- utxo.value = Number(utxo.value);
132
- }
133
-
134
- let feeRateFromNode: any;
135
- try {
136
- // Try GetFeeRateByNetwork first (newer API), then fallback to GetFeeRate
137
- let feeResponse;
138
- if (pioneer.GetFeeRateByNetwork) {
139
- console.log(`${tag}: Trying GetFeeRateByNetwork for ${networkId}`);
140
- feeResponse = await pioneer.GetFeeRateByNetwork({ networkId });
141
- } else {
142
- console.log(`${tag}: Using GetFeeRate for ${networkId}`);
143
- feeResponse = await pioneer.GetFeeRate({ networkId });
144
- }
145
-
146
- feeRateFromNode = feeResponse.data;
147
- console.log(`${tag}: Got fee rates from API:`, JSON.stringify(feeRateFromNode, null, 2));
148
-
149
- // Validate the response has the expected structure
150
- if (!feeRateFromNode || typeof feeRateFromNode !== 'object') {
151
- throw new Error(`Invalid fee rate response from API: ${JSON.stringify(feeRateFromNode)}`);
152
- }
153
-
154
- // Log all available fee rates for debugging
155
- console.log(`${tag}: Available fee rates:`, {
156
- slow: feeRateFromNode.slow,
157
- average: feeRateFromNode.average,
158
- fast: feeRateFromNode.fast,
159
- fastest: feeRateFromNode.fastest,
160
- });
161
-
162
- // Check that we have at least one fee rate
163
- if (
164
- !feeRateFromNode.slow &&
165
- !feeRateFromNode.average &&
166
- !feeRateFromNode.fast &&
167
- !feeRateFromNode.fastest
168
- ) {
169
- throw new Error(`No valid fee rates in API response: ${JSON.stringify(feeRateFromNode)}`);
170
- }
171
- } catch (error: any) {
172
- console.error(`${tag}: Failed to get fee rates from Pioneer API:`, error.message || error);
173
- throw new Error(
174
- `Unable to get fee rate for network ${networkId}: ${error.message || 'API unavailable'}`,
175
- );
176
- }
177
-
178
- // Map fee level to fee rate (1-2 = slow, 3-4 = average, 5 = fastest)
179
- // Frontend typically sends: slow=1, average=3, fastest=5
180
- let effectiveFeeRate;
181
- console.log(`${tag}: Using fee level ${feeLevel}`);
182
-
183
- switch (feeLevel) {
184
- case 1:
185
- case 2:
186
- effectiveFeeRate = feeRateFromNode.slow || feeRateFromNode.average;
187
- console.log(`${tag}: Using SLOW fee rate: ${effectiveFeeRate} sat/vB`);
188
- break;
189
- case 3:
190
- case 4:
191
- effectiveFeeRate = feeRateFromNode.average || feeRateFromNode.fast;
192
- console.log(`${tag}: Using AVERAGE fee rate: ${effectiveFeeRate} sat/vB`);
193
- break;
194
- case 5:
195
- effectiveFeeRate = feeRateFromNode.fastest || feeRateFromNode.fast;
196
- console.log(`${tag}: Using FASTEST fee rate: ${effectiveFeeRate} sat/vB`);
197
- break;
198
- default:
199
- throw new Error(`Invalid fee level: ${feeLevel}. Must be 1-5`);
200
- }
201
-
202
- if (!effectiveFeeRate) throw new Error('Unable to get fee rate for network');
203
-
204
- // Log what we're using
205
- console.log(`${tag}: Using fee rate from API:`, {
206
- feeLevel,
207
- selectedRate: effectiveFeeRate,
208
- description: feeLevel <= 2 ? 'slow' : feeLevel <= 4 ? 'average' : 'fast',
209
- });
210
-
211
- // Only enforce minimum for safety if fee is 0 or negative
212
- if (effectiveFeeRate <= 0) throw Error('Failed to build valid fee! Must be > 0');
213
-
214
- // The effectiveFeeRate is now the actual sat/vB from the API
215
- console.log(`${tag}: Final fee rate to use: ${effectiveFeeRate} sat/vB`);
216
-
217
- amount = parseInt(String(amount * 1e8));
218
- if (amount <= 0 && !isMax) throw Error('Invalid amount! 0');
219
-
220
- // Log UTXOs before coin selection for debugging
221
- const totalBalance = utxos.reduce((sum, utxo) => sum + utxo.value, 0);
222
- console.log(`${tag}: Coin selection inputs:`, {
223
- utxoCount: utxos.length,
224
- totalBalance: totalBalance / 1e8,
225
- requestedAmount: amount / 1e8,
226
- isMax,
227
- feeRate: effectiveFeeRate,
228
- });
229
-
230
- let result;
231
- if (isMax) {
232
- //console.log(tag, 'isMax:', isMax);
233
- // For max send, use coinSelectSplit
234
- result = coinSelectSplit(utxos, [{ address: to }], effectiveFeeRate);
235
- } else {
236
- //console.log(tag, 'isMax:', isMax)
237
- // Regular send
238
- result = coinSelect(utxos, [{ address: to, value: amount }], effectiveFeeRate);
239
- }
240
-
241
- console.log(tag, 'coinSelect result:', result ? 'Success' : 'Failed');
242
-
243
- if (!result || !result.inputs) {
244
- // Provide detailed error information
245
- const errorDetails = {
246
- utxoCount: utxos.length,
247
- totalBalance: totalBalance / 1e8,
248
- requestedAmount: amount / 1e8,
249
- feeRate: effectiveFeeRate,
250
- insufficientFunds: totalBalance < amount,
251
- };
252
- console.error(`${tag}: Coin selection failed:`, errorDetails);
253
-
254
- if (utxos.length === 0) {
255
- throw Error('No UTXOs available for coin selection');
256
- } else if (totalBalance < amount) {
257
- throw Error(`Insufficient funds: Have ${totalBalance / 1e8} BTC, need ${amount / 1e8} BTC`);
258
- } else {
259
- throw Error(
260
- 'Failed to create transaction: Coin selection failed (possibly due to high fees)',
261
- );
262
- }
263
- }
264
-
265
- let { inputs, outputs, fee } = result;
266
- if (!inputs) throw Error('Failed to create transaction: Missing inputs');
267
- if (!outputs) throw Error('Failed to create transaction: Missing outputs');
268
- if (fee === undefined) throw Error('Failed to calculate transaction fee');
269
-
270
- console.log(`${tag}: Transaction built with:`, {
271
- feeLevel,
272
- effectiveFeeRate: `${effectiveFeeRate} sat/vB`,
273
- calculatedFee: `${fee} satoshis`,
274
- inputCount: inputs.length,
275
- outputCount: outputs.length,
276
- });
277
-
278
- const uniqueInputSet = new Set();
279
- console.log(tag, 'inputs:', inputs);
280
- console.log(tag, 'inputs:', inputs[0]);
281
- const preparedInputs = inputs
282
- .map(transformInput)
283
- .filter(({ hash, index }) =>
284
- uniqueInputSet.has(`${hash}:${index}`) ? false : uniqueInputSet.add(`${hash}:${index}`),
285
- )
286
- .map(({ value, index, hash, txHex, path, scriptType }) => ({
287
- addressNList: bip32ToAddressNList(path),
288
- //TODO this is PER INPUT not per asset, we need to detect what pubkeys are segwit what are not
289
- scriptType,
290
- amount: value.toString(),
291
- vout: index,
292
- txid: hash,
293
- hex: txHex || '',
294
- }));
295
-
296
- // Remove hardcoded script type - use the one from changeAddress
297
-
298
- const preparedOutputs = outputs
299
- .map(({ value, address }) => {
300
- if (address) {
301
- return { address, amount: value.toString(), addressType: 'spend' };
302
- } else if (!isMax) {
303
- return {
304
- addressNList: changeAddress.addressNList,
305
- scriptType: changeAddress.scriptType, // Use the correct script type from change address
306
- isChange: true,
307
- amount: value.toString(),
308
- addressType: 'change',
309
- };
310
- }
311
- return null; // No change output when isMax is true
312
- })
313
- .filter((output) => output !== null);
314
-
315
- if (!fee) {
316
- fee =
317
- inputs.reduce((acc, input) => acc + input.value, 0) -
318
- outputs.reduce((acc, output) => acc + parseInt(output.amount), 0);
319
- }
320
-
321
- // Include the fee in the transaction object for the vault to use
322
- let unsignedTx = {
323
- inputs: preparedInputs,
324
- outputs: preparedOutputs,
325
- memo,
326
- fee: fee.toString(), // Add the calculated fee to the returned object
327
- };
328
- //console.log(tag, 'unsignedTx:', unsignedTx);
329
-
330
- return unsignedTx;
331
- } catch (error) {
332
- //console.log(tag, 'Error:', error);
333
- throw error;
334
- }
335
- }
336
-
337
- function transformInput(input) {
338
- const {
339
- txid,
340
- vout,
341
- value,
342
- address,
343
- height,
344
- confirmations,
345
- path,
346
- scriptType,
347
- hex: txHex,
348
- tx,
349
- coin,
350
- network,
351
- } = input;
352
-
353
- return {
354
- address,
355
- hash: txid,
356
- index: vout,
357
- value: parseInt(value),
358
- height,
359
- scriptType,
360
- confirmations,
361
- path,
362
- txHex,
363
- tx,
364
- coin,
365
- network,
366
- witnessUtxo: {
367
- value: parseInt(tx.vout[0].value),
368
- script: Buffer.from(tx.vout[0].scriptPubKey.hex, 'hex'),
369
- },
370
- };
371
- }
372
-
373
- function getScriptTypeFromXpub(xpub: string): string {
374
- if (xpub.startsWith('xpub')) {
375
- return 'p2pkh'; // Legacy
376
- } else if (xpub.startsWith('ypub')) {
377
- return 'p2sh'; // P2WPKH nested in P2SH
378
- } else if (xpub.startsWith('zpub')) {
379
- return 'p2wpkh'; // Native SegWit
380
- } else {
381
- // Default fallback
382
- return 'p2pkh';
383
- }
384
- }