@pioneer-platform/pioneer-sdk 0.0.82 → 4.14.0
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 +5358 -0
- package/dist/index.es.js +5537 -0
- package/dist/index.js +5537 -0
- package/package.json +55 -37
- package/src/TransactionManager.ts +333 -0
- package/src/charts/cosmos-staking.ts +171 -0
- package/src/charts/evm.ts +199 -0
- package/src/charts/index.ts +46 -0
- package/src/charts/maya.ts +110 -0
- package/src/charts/types.ts +77 -0
- package/src/charts/utils.ts +24 -0
- package/src/fees/index.ts +620 -0
- package/src/getPubkey.ts +151 -0
- package/src/index.ts +2250 -0
- package/src/kkapi-batch-client.ts +191 -0
- package/src/offline-client.ts +287 -0
- package/src/supportedCaips.ts +36 -0
- package/src/txbuilder/createUnsignedEvmTx.ts +532 -0
- package/src/txbuilder/createUnsignedRippleTx.ts +122 -0
- package/src/txbuilder/createUnsignedStakingTx.ts +188 -0
- package/src/txbuilder/createUnsignedTendermintTx.ts +249 -0
- package/src/txbuilder/createUnsignedUxtoTx.ts +450 -0
- package/src/txbuilder/templates/cosmos-staking.ts +157 -0
- package/src/txbuilder/templates/cosmos.ts +30 -0
- package/src/txbuilder/templates/mayachain.ts +60 -0
- package/src/txbuilder/templates/osmosis.ts +30 -0
- package/src/txbuilder/templates/thorchain.ts +60 -0
- package/src/utils/build-dashboard.ts +181 -0
- package/src/utils/format-time.ts +12 -0
- package/src/utils/kkapi-detection.ts +64 -0
- package/src/utils/pubkey-helpers.ts +75 -0
- package/lib/index.d.ts +0 -66
- package/lib/index.js +0 -493
- package/tsconfig.json +0 -13
@@ -0,0 +1,620 @@
|
|
1
|
+
/**
|
2
|
+
* Fee Management Module for Pioneer SDK
|
3
|
+
*
|
4
|
+
* Handles all fee-related complexity, normalization, and provides
|
5
|
+
* a clean, consistent interface for the frontend.
|
6
|
+
*/
|
7
|
+
|
8
|
+
const TAG = ' | Pioneer-sdk | fees | ';
|
9
|
+
|
10
|
+
export interface FeeLevel {
|
11
|
+
label: string;
|
12
|
+
value: string;
|
13
|
+
unit: string;
|
14
|
+
description: string;
|
15
|
+
estimatedTime?: string;
|
16
|
+
priority: 'low' | 'medium' | 'high';
|
17
|
+
}
|
18
|
+
|
19
|
+
export interface NormalizedFeeRates {
|
20
|
+
slow: FeeLevel;
|
21
|
+
average: FeeLevel;
|
22
|
+
fastest: FeeLevel;
|
23
|
+
networkId: string;
|
24
|
+
networkType: 'UTXO' | 'EVM' | 'COSMOS' | 'RIPPLE' | 'OTHER';
|
25
|
+
raw: any; // Original API response for debugging
|
26
|
+
}
|
27
|
+
|
28
|
+
export interface FeeEstimate {
|
29
|
+
amount: string;
|
30
|
+
unit: string;
|
31
|
+
usdValue?: string;
|
32
|
+
}
|
33
|
+
|
34
|
+
// Network type detection
|
35
|
+
function getNetworkType(networkId: string): 'UTXO' | 'EVM' | 'COSMOS' | 'RIPPLE' | 'OTHER' {
|
36
|
+
if (networkId.startsWith('bip122:')) return 'UTXO';
|
37
|
+
if (networkId.startsWith('eip155:')) return 'EVM';
|
38
|
+
if (networkId.startsWith('cosmos:')) return 'COSMOS';
|
39
|
+
if (networkId.startsWith('ripple:')) return 'RIPPLE';
|
40
|
+
return 'OTHER';
|
41
|
+
}
|
42
|
+
|
43
|
+
// Get human-readable network name
|
44
|
+
function getNetworkName(networkId: string): string {
|
45
|
+
const networkNames: Record<string, string> = {
|
46
|
+
'bip122:000000000019d6689c085ae165831e93': 'Bitcoin',
|
47
|
+
'bip122:12a765e31ffd4059bada1e25190f6e98': 'Litecoin',
|
48
|
+
'bip122:00000000001a91e3dace36e2be3bf030': 'Dogecoin',
|
49
|
+
'bip122:000000000000000000651ef99cb9fcbe': 'Bitcoin Cash',
|
50
|
+
'bip122:000007d91d1254d60e2dd1ae58038307': 'Dash',
|
51
|
+
'eip155:1': 'Ethereum',
|
52
|
+
'eip155:56': 'BNB Smart Chain',
|
53
|
+
'eip155:137': 'Polygon',
|
54
|
+
'eip155:43114': 'Avalanche',
|
55
|
+
'eip155:8453': 'Base',
|
56
|
+
'eip155:10': 'Optimism',
|
57
|
+
'cosmos:cosmoshub-4': 'Cosmos Hub',
|
58
|
+
'cosmos:osmosis-1': 'Osmosis',
|
59
|
+
'cosmos:thorchain-mainnet-v1': 'THORChain',
|
60
|
+
'cosmos:mayachain-mainnet-v1': 'Maya',
|
61
|
+
'ripple:4109c6f2045fc7eff4cde8f9905d19c2': 'Ripple',
|
62
|
+
};
|
63
|
+
return networkNames[networkId] || networkId;
|
64
|
+
}
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Main fee fetching and normalization function
|
68
|
+
* Handles all the complexity of different API formats and returns
|
69
|
+
* a clean, normalized structure for the UI
|
70
|
+
*/
|
71
|
+
export async function getFees(
|
72
|
+
pioneer: any,
|
73
|
+
networkId: string
|
74
|
+
): Promise<NormalizedFeeRates> {
|
75
|
+
const tag = TAG + ' | getFees | ';
|
76
|
+
|
77
|
+
try {
|
78
|
+
console.log(tag, `Fetching fees for network: ${networkId}`);
|
79
|
+
|
80
|
+
// For Cosmos chains, always use hardcoded fees
|
81
|
+
const networkType = getNetworkType(networkId);
|
82
|
+
if (networkType === 'COSMOS') {
|
83
|
+
console.log(tag, 'Using hardcoded fees for Cosmos network:', networkId);
|
84
|
+
return getCosmosFees(networkId);
|
85
|
+
}
|
86
|
+
|
87
|
+
// For Ripple, always use hardcoded fees (API doesn't support it)
|
88
|
+
if (networkType === 'RIPPLE') {
|
89
|
+
console.log(tag, 'Using hardcoded fees for Ripple:', networkId);
|
90
|
+
return getRippleFees(networkId);
|
91
|
+
}
|
92
|
+
|
93
|
+
// Hardcode DOGE fees at 10 sat/byte (API and Blockbook often unreliable for DOGE)
|
94
|
+
if (networkId === 'bip122:00000000001a91e3dace36e2be3bf030') {
|
95
|
+
console.log(tag, 'Using hardcoded fees for Dogecoin: 10 sat/byte');
|
96
|
+
return {
|
97
|
+
slow: {
|
98
|
+
label: 'Slow',
|
99
|
+
value: '10',
|
100
|
+
unit: 'sat/byte',
|
101
|
+
description: 'Low priority - 30+ minutes',
|
102
|
+
estimatedTime: '~30 minutes',
|
103
|
+
priority: 'low'
|
104
|
+
},
|
105
|
+
average: {
|
106
|
+
label: 'Average',
|
107
|
+
value: '10',
|
108
|
+
unit: 'sat/byte',
|
109
|
+
description: 'Normal priority - 10-30 minutes',
|
110
|
+
estimatedTime: '~15 minutes',
|
111
|
+
priority: 'medium'
|
112
|
+
},
|
113
|
+
fastest: {
|
114
|
+
label: 'Fast',
|
115
|
+
value: '10',
|
116
|
+
unit: 'sat/byte',
|
117
|
+
description: 'High priority - next block',
|
118
|
+
estimatedTime: '~5 minutes',
|
119
|
+
priority: 'high'
|
120
|
+
},
|
121
|
+
networkId,
|
122
|
+
networkType: 'UTXO',
|
123
|
+
raw: { hardcoded: true, reason: 'DOGE fee estimation unreliable' }
|
124
|
+
};
|
125
|
+
}
|
126
|
+
|
127
|
+
// Get raw fee data from API
|
128
|
+
const feeResponse = await (pioneer.GetFeeRateByNetwork
|
129
|
+
? pioneer.GetFeeRateByNetwork({ networkId })
|
130
|
+
: pioneer.GetFeeRate({ networkId }));
|
131
|
+
|
132
|
+
if (!feeResponse || !feeResponse.data) {
|
133
|
+
throw new Error(`No fee data returned for ${networkId}`);
|
134
|
+
}
|
135
|
+
|
136
|
+
const feeData = feeResponse.data;
|
137
|
+
console.log(tag, 'Raw fee data:', feeData);
|
138
|
+
|
139
|
+
// Check if API returned an error response
|
140
|
+
if (feeData.success === false || feeData.error) {
|
141
|
+
throw new Error(feeData.error || `API error for ${networkId}`);
|
142
|
+
}
|
143
|
+
|
144
|
+
// Network type already detected above, just get network name
|
145
|
+
const networkName = getNetworkName(networkId);
|
146
|
+
|
147
|
+
// Normalize the fee data based on format (pass networkId for sanity checks)
|
148
|
+
let normalizedFees = normalizeFeeData(feeData, networkType, networkName, networkId);
|
149
|
+
|
150
|
+
// Ensure fees are differentiated for better UX
|
151
|
+
normalizedFees = ensureFeeDifferentiation(normalizedFees, networkType);
|
152
|
+
|
153
|
+
// Add network metadata
|
154
|
+
normalizedFees.networkId = networkId;
|
155
|
+
normalizedFees.networkType = networkType;
|
156
|
+
normalizedFees.raw = feeData;
|
157
|
+
|
158
|
+
console.log(tag, 'Normalized fees:', normalizedFees);
|
159
|
+
return normalizedFees;
|
160
|
+
|
161
|
+
} catch (error: any) {
|
162
|
+
console.error(tag, 'Failed to fetch fees:', error);
|
163
|
+
|
164
|
+
// Return sensible defaults on error
|
165
|
+
return getFallbackFees(networkId);
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
/**
|
170
|
+
* Normalize fee data from various API formats to consistent UI format
|
171
|
+
*/
|
172
|
+
function normalizeFeeData(
|
173
|
+
feeData: any,
|
174
|
+
networkType: string,
|
175
|
+
networkName: string,
|
176
|
+
networkId?: string
|
177
|
+
): NormalizedFeeRates {
|
178
|
+
// Check which format the API returned
|
179
|
+
const hasSlowAverageFastest = feeData.slow !== undefined &&
|
180
|
+
feeData.average !== undefined &&
|
181
|
+
feeData.fastest !== undefined;
|
182
|
+
|
183
|
+
const hasAverageFastFastest = feeData.average !== undefined &&
|
184
|
+
feeData.fast !== undefined &&
|
185
|
+
feeData.fastest !== undefined;
|
186
|
+
|
187
|
+
let slowValue: string, averageValue: string, fastestValue: string;
|
188
|
+
|
189
|
+
if (hasSlowAverageFastest) {
|
190
|
+
// Already in UI format
|
191
|
+
slowValue = feeData.slow.toString();
|
192
|
+
averageValue = feeData.average.toString();
|
193
|
+
fastestValue = feeData.fastest.toString();
|
194
|
+
} else if (hasAverageFastFastest) {
|
195
|
+
// Map API format to UI format
|
196
|
+
slowValue = feeData.average.toString();
|
197
|
+
averageValue = feeData.fast.toString();
|
198
|
+
fastestValue = feeData.fastest.toString();
|
199
|
+
} else {
|
200
|
+
throw new Error('Unknown fee data format');
|
201
|
+
}
|
202
|
+
|
203
|
+
// UNIT CONVERSION: Detect if API returned sat/kB instead of sat/byte
|
204
|
+
// If values are unreasonably high, they're likely in sat/kB and need to be divided by 1000
|
205
|
+
if (networkType === 'UTXO') {
|
206
|
+
const slowNum = parseFloat(slowValue);
|
207
|
+
const avgNum = parseFloat(averageValue);
|
208
|
+
const fastestNum = parseFloat(fastestValue);
|
209
|
+
|
210
|
+
// Detection threshold: if ANY value > 500, likely in wrong units (sat/kB instead of sat/byte)
|
211
|
+
// This is safe because even BTC rarely exceeds 500 sat/byte
|
212
|
+
const conversionThreshold = 500;
|
213
|
+
|
214
|
+
if (slowNum > conversionThreshold || avgNum > conversionThreshold || fastestNum > conversionThreshold) {
|
215
|
+
console.warn(`[FEES] Detected wrong units for ${networkName}: values appear to be in sat/kB instead of sat/byte`);
|
216
|
+
console.warn(`[FEES] Original values: slow=${slowNum}, avg=${avgNum}, fastest=${fastestNum}`);
|
217
|
+
|
218
|
+
// Convert from sat/kB to sat/byte
|
219
|
+
slowValue = (slowNum / 1000).toFixed(3);
|
220
|
+
averageValue = (avgNum / 1000).toFixed(3);
|
221
|
+
fastestValue = (fastestNum / 1000).toFixed(3);
|
222
|
+
|
223
|
+
console.warn(`[FEES] Converted to sat/byte: slow=${slowValue}, avg=${averageValue}, fastest=${fastestValue}`);
|
224
|
+
}
|
225
|
+
}
|
226
|
+
|
227
|
+
// Apply sanity checks for UTXO networks to prevent absurdly high fees
|
228
|
+
// The API sometimes returns stale or incorrect data (e.g., DOGE returning 50000 sat/byte instead of 50)
|
229
|
+
if (networkType === 'UTXO') {
|
230
|
+
const sanityLimits: Record<string, number> = {
|
231
|
+
'bip122:00000000001a91e3dace36e2be3bf030': 100, // DOGE max 100 sat/byte (typical: 1-10)
|
232
|
+
'bip122:12a765e31ffd4059bada1e25190f6e98': 500, // LTC max 500 sat/byte
|
233
|
+
'bip122:000000000000000000651ef99cb9fcbe': 50, // BCH max 50 sat/byte (low fee chain)
|
234
|
+
'bip122:000007d91d1254d60e2dd1ae58038307': 50, // DASH max 50 sat/byte (low fee chain)
|
235
|
+
'bip122:000000000019d6689c085ae165831e93': 5000, // BTC max 5000 sat/byte (can spike during congestion)
|
236
|
+
};
|
237
|
+
|
238
|
+
const matchedNetworkId = networkId && sanityLimits[networkId] ? networkId :
|
239
|
+
Object.keys(sanityLimits).find(id => networkName.toLowerCase().includes(id.split(':')[1]?.substring(0, 8)));
|
240
|
+
|
241
|
+
if (matchedNetworkId && sanityLimits[matchedNetworkId]) {
|
242
|
+
const limit = sanityLimits[matchedNetworkId];
|
243
|
+
const slowNum = parseFloat(slowValue);
|
244
|
+
const avgNum = parseFloat(averageValue);
|
245
|
+
const fastestNum = parseFloat(fastestValue);
|
246
|
+
|
247
|
+
if (slowNum > limit || avgNum > limit || fastestNum > limit) {
|
248
|
+
console.warn(`[FEES] Detected absurdly high fees for ${networkName}: slow=${slowNum}, avg=${avgNum}, fastest=${fastestNum}`);
|
249
|
+
console.warn(`[FEES] Capping fees to reasonable limits (max: ${limit} sat/byte)`);
|
250
|
+
|
251
|
+
// Cap to reasonable values - use 10% of limit as conservative default
|
252
|
+
const safeFee = (limit * 0.1).toFixed(2);
|
253
|
+
const mediumFee = (limit * 0.15).toFixed(2);
|
254
|
+
const fastFee = (limit * 0.2).toFixed(2);
|
255
|
+
|
256
|
+
slowValue = safeFee;
|
257
|
+
averageValue = mediumFee;
|
258
|
+
fastestValue = fastFee;
|
259
|
+
|
260
|
+
console.warn(`[FEES] Adjusted to: slow=${slowValue}, avg=${averageValue}, fastest=${fastestValue}`);
|
261
|
+
}
|
262
|
+
}
|
263
|
+
}
|
264
|
+
|
265
|
+
// Get unit and descriptions based on network type
|
266
|
+
const unit = feeData.unit || getDefaultUnit(networkType);
|
267
|
+
const baseDescription = feeData.description || getDefaultDescription(networkType, networkName);
|
268
|
+
|
269
|
+
return {
|
270
|
+
slow: {
|
271
|
+
label: 'Economy',
|
272
|
+
value: slowValue,
|
273
|
+
unit,
|
274
|
+
description: `${baseDescription} - Lower priority, may take longer to confirm.`,
|
275
|
+
estimatedTime: getEstimatedTime(networkType, 'low'),
|
276
|
+
priority: 'low',
|
277
|
+
},
|
278
|
+
average: {
|
279
|
+
label: 'Standard',
|
280
|
+
value: averageValue,
|
281
|
+
unit,
|
282
|
+
description: `${baseDescription} - Normal priority, typical confirmation time.`,
|
283
|
+
estimatedTime: getEstimatedTime(networkType, 'medium'),
|
284
|
+
priority: 'medium',
|
285
|
+
},
|
286
|
+
fastest: {
|
287
|
+
label: 'Priority',
|
288
|
+
value: fastestValue,
|
289
|
+
unit,
|
290
|
+
description: `${baseDescription} - High priority, fastest confirmation.`,
|
291
|
+
estimatedTime: getEstimatedTime(networkType, 'high'),
|
292
|
+
priority: 'high',
|
293
|
+
},
|
294
|
+
networkId: '',
|
295
|
+
networkType: networkType as any,
|
296
|
+
raw: feeData,
|
297
|
+
};
|
298
|
+
}
|
299
|
+
|
300
|
+
/**
|
301
|
+
* Ensure fees are differentiated for better UX
|
302
|
+
*/
|
303
|
+
function ensureFeeDifferentiation(
|
304
|
+
fees: NormalizedFeeRates,
|
305
|
+
networkType: string
|
306
|
+
): NormalizedFeeRates {
|
307
|
+
const slowVal = parseFloat(fees.slow.value) || 0;
|
308
|
+
const avgVal = parseFloat(fees.average.value) || 0;
|
309
|
+
const fastestVal = parseFloat(fees.fastest.value) || 0;
|
310
|
+
|
311
|
+
// Check if all values are zero
|
312
|
+
if (slowVal === 0 && avgVal === 0 && fastestVal === 0) {
|
313
|
+
console.warn('All fee values are 0 - using fallback values');
|
314
|
+
// Return sensible defaults based on network type
|
315
|
+
if (networkType === 'UTXO') {
|
316
|
+
return {
|
317
|
+
...fees,
|
318
|
+
slow: { ...fees.slow, value: '1' },
|
319
|
+
average: { ...fees.average, value: '2' },
|
320
|
+
fastest: { ...fees.fastest, value: '3' },
|
321
|
+
};
|
322
|
+
} else {
|
323
|
+
return {
|
324
|
+
...fees,
|
325
|
+
slow: { ...fees.slow, value: '1' },
|
326
|
+
average: { ...fees.average, value: '1.5' },
|
327
|
+
fastest: { ...fees.fastest, value: '2' },
|
328
|
+
};
|
329
|
+
}
|
330
|
+
}
|
331
|
+
|
332
|
+
// For UTXO networks with very similar values (like 1, 1, 1.01)
|
333
|
+
if (networkType === 'UTXO') {
|
334
|
+
const diff = fastestVal - slowVal;
|
335
|
+
if (diff < 0.5) {
|
336
|
+
console.warn('UTXO fees too similar, adjusting for better UX');
|
337
|
+
return {
|
338
|
+
...fees,
|
339
|
+
slow: { ...fees.slow, value: slowVal.toString() },
|
340
|
+
average: { ...fees.average, value: (slowVal + 1).toString() },
|
341
|
+
fastest: { ...fees.fastest, value: (slowVal + 2).toString() },
|
342
|
+
};
|
343
|
+
}
|
344
|
+
}
|
345
|
+
|
346
|
+
// For EVM networks, check if values are already well differentiated
|
347
|
+
// Don't adjust if there's already good separation
|
348
|
+
const slowToAvgRatio = avgVal / slowVal;
|
349
|
+
const avgToFastRatio = fastestVal / avgVal;
|
350
|
+
|
351
|
+
// If ratios show good differentiation (at least 10% difference), keep original
|
352
|
+
if (slowToAvgRatio >= 1.1 && avgToFastRatio >= 1.1) {
|
353
|
+
return fees; // Already well differentiated
|
354
|
+
}
|
355
|
+
|
356
|
+
// Only adjust if fees are too similar
|
357
|
+
console.warn('Fees not well differentiated, adjusting slightly');
|
358
|
+
return {
|
359
|
+
...fees,
|
360
|
+
slow: { ...fees.slow, value: slowVal.toString() },
|
361
|
+
average: { ...fees.average, value: (slowVal * 1.2).toFixed(6) },
|
362
|
+
fastest: { ...fees.fastest, value: (slowVal * 1.5).toFixed(6) },
|
363
|
+
};
|
364
|
+
}
|
365
|
+
|
366
|
+
/**
|
367
|
+
* Get default unit based on network type
|
368
|
+
*/
|
369
|
+
function getDefaultUnit(networkType: string): string {
|
370
|
+
switch (networkType) {
|
371
|
+
case 'UTXO':
|
372
|
+
return 'sat/vB';
|
373
|
+
case 'EVM':
|
374
|
+
return 'gwei';
|
375
|
+
case 'COSMOS':
|
376
|
+
return 'uatom';
|
377
|
+
case 'RIPPLE':
|
378
|
+
return 'XRP';
|
379
|
+
default:
|
380
|
+
return 'units';
|
381
|
+
}
|
382
|
+
}
|
383
|
+
|
384
|
+
/**
|
385
|
+
* Get default description based on network type
|
386
|
+
*/
|
387
|
+
function getDefaultDescription(networkType: string, networkName: string): string {
|
388
|
+
switch (networkType) {
|
389
|
+
case 'UTXO':
|
390
|
+
return `Fee rate in satoshis per virtual byte for ${networkName}`;
|
391
|
+
case 'EVM':
|
392
|
+
return `Gas price in Gwei for ${networkName} (1 Gwei = 0.000000001 ETH)`;
|
393
|
+
case 'COSMOS':
|
394
|
+
return `Transaction fee for ${networkName}`;
|
395
|
+
case 'RIPPLE':
|
396
|
+
return `Fixed transaction fee for ${networkName}`;
|
397
|
+
default:
|
398
|
+
return `Transaction fee for ${networkName}`;
|
399
|
+
}
|
400
|
+
}
|
401
|
+
|
402
|
+
/**
|
403
|
+
* Get estimated confirmation time
|
404
|
+
*/
|
405
|
+
function getEstimatedTime(networkType: string, priority: string): string {
|
406
|
+
const times: Record<string, Record<string, string>> = {
|
407
|
+
UTXO: {
|
408
|
+
low: '~60+ minutes',
|
409
|
+
medium: '~30 minutes',
|
410
|
+
high: '~10 minutes',
|
411
|
+
},
|
412
|
+
EVM: {
|
413
|
+
low: '~5 minutes',
|
414
|
+
medium: '~2 minutes',
|
415
|
+
high: '~30 seconds',
|
416
|
+
},
|
417
|
+
COSMOS: {
|
418
|
+
low: '~10 seconds',
|
419
|
+
medium: '~7 seconds',
|
420
|
+
high: '~5 seconds',
|
421
|
+
},
|
422
|
+
RIPPLE: {
|
423
|
+
low: '~4 seconds',
|
424
|
+
medium: '~4 seconds',
|
425
|
+
high: '~4 seconds',
|
426
|
+
},
|
427
|
+
};
|
428
|
+
|
429
|
+
return times[networkType]?.[priority] || '~varies';
|
430
|
+
}
|
431
|
+
|
432
|
+
/**
|
433
|
+
* Get hardcoded Cosmos fees based on network
|
434
|
+
*/
|
435
|
+
function getCosmosFees(networkId: string): NormalizedFeeRates {
|
436
|
+
const networkName = getNetworkName(networkId);
|
437
|
+
|
438
|
+
// These match the fees in txbuilder/createUnsignedTendermintTx.ts
|
439
|
+
const cosmosFeesMap: Record<string, { base: number; unit: string; denom: string }> = {
|
440
|
+
'cosmos:thorchain-mainnet-v1': { base: 0.02, unit: 'RUNE', denom: 'rune' },
|
441
|
+
'cosmos:mayachain-mainnet-v1': { base: 0.2, unit: 'MAYA', denom: 'maya' },
|
442
|
+
'cosmos:cosmoshub-4': { base: 0.005, unit: 'ATOM', denom: 'uatom' },
|
443
|
+
'cosmos:osmosis-1': { base: 0.035, unit: 'OSMO', denom: 'uosmo' },
|
444
|
+
};
|
445
|
+
|
446
|
+
const feeConfig = cosmosFeesMap[networkId] || { base: 0.025, unit: 'units', denom: 'units' };
|
447
|
+
|
448
|
+
// For Cosmos, we provide the base fee with different priority multipliers
|
449
|
+
const slowFee = feeConfig.base.toString();
|
450
|
+
const avgFee = (feeConfig.base * 1.5).toFixed(4);
|
451
|
+
const fastFee = (feeConfig.base * 2).toFixed(4);
|
452
|
+
|
453
|
+
return {
|
454
|
+
slow: {
|
455
|
+
label: 'Economy',
|
456
|
+
value: slowFee,
|
457
|
+
unit: feeConfig.unit,
|
458
|
+
description: `Standard fee for ${networkName}. Gas is automatically calculated.`,
|
459
|
+
estimatedTime: '~10 seconds',
|
460
|
+
priority: 'low',
|
461
|
+
},
|
462
|
+
average: {
|
463
|
+
label: 'Standard',
|
464
|
+
value: avgFee,
|
465
|
+
unit: feeConfig.unit,
|
466
|
+
description: `Priority fee for ${networkName}. Slightly higher for faster processing.`,
|
467
|
+
estimatedTime: '~7 seconds',
|
468
|
+
priority: 'medium',
|
469
|
+
},
|
470
|
+
fastest: {
|
471
|
+
label: 'Priority',
|
472
|
+
value: fastFee,
|
473
|
+
unit: feeConfig.unit,
|
474
|
+
description: `Maximum priority for ${networkName}. Fastest possible confirmation.`,
|
475
|
+
estimatedTime: '~5 seconds',
|
476
|
+
priority: 'high',
|
477
|
+
},
|
478
|
+
networkId,
|
479
|
+
networkType: 'COSMOS',
|
480
|
+
raw: { hardcoded: true, base: feeConfig.base, unit: feeConfig.unit, denom: feeConfig.denom },
|
481
|
+
};
|
482
|
+
}
|
483
|
+
|
484
|
+
/**
|
485
|
+
* Get hardcoded Ripple fees
|
486
|
+
*/
|
487
|
+
function getRippleFees(networkId: string): NormalizedFeeRates {
|
488
|
+
const networkName = getNetworkName(networkId);
|
489
|
+
|
490
|
+
// XRP has a fixed minimum fee of 0.00001 XRP (10 drops)
|
491
|
+
// This is hardcoded in the network protocol
|
492
|
+
const baseFee = '0.00001';
|
493
|
+
|
494
|
+
return {
|
495
|
+
slow: {
|
496
|
+
label: 'Standard',
|
497
|
+
value: baseFee,
|
498
|
+
unit: 'XRP',
|
499
|
+
description: `Fixed network fee for ${networkName}. All transactions use the same fee.`,
|
500
|
+
estimatedTime: '~4 seconds',
|
501
|
+
priority: 'low',
|
502
|
+
},
|
503
|
+
average: {
|
504
|
+
label: 'Standard',
|
505
|
+
value: baseFee,
|
506
|
+
unit: 'XRP',
|
507
|
+
description: `Fixed network fee for ${networkName}. All transactions use the same fee.`,
|
508
|
+
estimatedTime: '~4 seconds',
|
509
|
+
priority: 'medium',
|
510
|
+
},
|
511
|
+
fastest: {
|
512
|
+
label: 'Standard',
|
513
|
+
value: baseFee,
|
514
|
+
unit: 'XRP',
|
515
|
+
description: `Fixed network fee for ${networkName}. All transactions use the same fee.`,
|
516
|
+
estimatedTime: '~4 seconds',
|
517
|
+
priority: 'high',
|
518
|
+
},
|
519
|
+
networkId,
|
520
|
+
networkType: 'RIPPLE',
|
521
|
+
raw: { hardcoded: true, baseFee, reason: 'Ripple uses fixed network fees' },
|
522
|
+
};
|
523
|
+
}
|
524
|
+
|
525
|
+
/**
|
526
|
+
* Get fallback fees when API fails
|
527
|
+
*/
|
528
|
+
function getFallbackFees(networkId: string): NormalizedFeeRates {
|
529
|
+
const networkType = getNetworkType(networkId);
|
530
|
+
const networkName = getNetworkName(networkId);
|
531
|
+
|
532
|
+
// For Cosmos chains, use hardcoded fees
|
533
|
+
if (networkType === 'COSMOS') {
|
534
|
+
return getCosmosFees(networkId);
|
535
|
+
}
|
536
|
+
|
537
|
+
// Default fallback values by network type
|
538
|
+
const fallbacks: Record<string, { slow: string; average: string; fastest: string; unit: string }> = {
|
539
|
+
UTXO: { slow: '1', average: '2', fastest: '3', unit: 'sat/vB' },
|
540
|
+
EVM: { slow: '1', average: '1.5', fastest: '2', unit: 'gwei' },
|
541
|
+
RIPPLE: { slow: '0.00001', average: '0.00001', fastest: '0.00001', unit: 'XRP' },
|
542
|
+
};
|
543
|
+
|
544
|
+
const fallback = fallbacks[networkType] || fallbacks.UTXO;
|
545
|
+
|
546
|
+
return {
|
547
|
+
slow: {
|
548
|
+
label: 'Economy',
|
549
|
+
value: fallback.slow,
|
550
|
+
unit: fallback.unit,
|
551
|
+
description: `Default fee for ${networkName} (API unavailable)`,
|
552
|
+
estimatedTime: getEstimatedTime(networkType, 'low'),
|
553
|
+
priority: 'low',
|
554
|
+
},
|
555
|
+
average: {
|
556
|
+
label: 'Standard',
|
557
|
+
value: fallback.average,
|
558
|
+
unit: fallback.unit,
|
559
|
+
description: `Default fee for ${networkName} (API unavailable)`,
|
560
|
+
estimatedTime: getEstimatedTime(networkType, 'medium'),
|
561
|
+
priority: 'medium',
|
562
|
+
},
|
563
|
+
fastest: {
|
564
|
+
label: 'Priority',
|
565
|
+
value: fallback.fastest,
|
566
|
+
unit: fallback.unit,
|
567
|
+
description: `Default fee for ${networkName} (API unavailable)`,
|
568
|
+
estimatedTime: getEstimatedTime(networkType, 'high'),
|
569
|
+
priority: 'high',
|
570
|
+
},
|
571
|
+
networkId,
|
572
|
+
networkType: networkType as any,
|
573
|
+
raw: null,
|
574
|
+
};
|
575
|
+
}
|
576
|
+
|
577
|
+
/**
|
578
|
+
* Calculate estimated transaction fee based on fee rate and transaction size
|
579
|
+
*/
|
580
|
+
export function estimateTransactionFee(
|
581
|
+
feeRate: string,
|
582
|
+
unit: string,
|
583
|
+
networkType: string,
|
584
|
+
txSize?: number
|
585
|
+
): FeeEstimate {
|
586
|
+
switch (networkType) {
|
587
|
+
case 'UTXO':
|
588
|
+
// For UTXO chains, multiply fee rate by transaction size
|
589
|
+
const sizeInBytes = txSize || 250; // Default estimate
|
590
|
+
const feeInSatoshis = parseFloat(feeRate) * sizeInBytes;
|
591
|
+
const feeInBTC = feeInSatoshis / 100000000;
|
592
|
+
return {
|
593
|
+
amount: feeInBTC.toFixed(8),
|
594
|
+
unit: 'BTC',
|
595
|
+
};
|
596
|
+
|
597
|
+
case 'EVM':
|
598
|
+
// For EVM chains, multiply gas price by gas limit
|
599
|
+
const gasLimit = 21000; // Standard transfer
|
600
|
+
const feeInGwei = parseFloat(feeRate) * gasLimit;
|
601
|
+
const feeInEth = feeInGwei / 1000000000;
|
602
|
+
return {
|
603
|
+
amount: feeInEth.toFixed(9),
|
604
|
+
unit: 'ETH',
|
605
|
+
};
|
606
|
+
|
607
|
+
case 'RIPPLE':
|
608
|
+
// Ripple has fixed fees
|
609
|
+
return {
|
610
|
+
amount: feeRate,
|
611
|
+
unit: 'XRP',
|
612
|
+
};
|
613
|
+
|
614
|
+
default:
|
615
|
+
return {
|
616
|
+
amount: feeRate,
|
617
|
+
unit: unit,
|
618
|
+
};
|
619
|
+
}
|
620
|
+
}
|