@pioneer-platform/pioneer-sdk 0.0.81 → 4.13.30
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,450 @@
|
|
1
|
+
import { caipToNetworkId, NetworkIdToChain } from '@pioneer-platform/pioneer-caip';
|
2
|
+
import { bip32ToAddressNList } from '@pioneer-platform/pioneer-coins';
|
3
|
+
|
4
|
+
export async function createUnsignedUxtoTx(
|
5
|
+
caip: string,
|
6
|
+
to: string,
|
7
|
+
amount: number,
|
8
|
+
memo: string,
|
9
|
+
pubkeys: any,
|
10
|
+
pioneer: any,
|
11
|
+
keepKeySdk: any,
|
12
|
+
isMax: boolean, // Added isMax parameter
|
13
|
+
feeLevel: number = 5, // Added feeLevel parameter with default of 5 (average)
|
14
|
+
changeScriptType?: string, // Added changeScriptType parameter for user preference
|
15
|
+
): Promise<any> {
|
16
|
+
let tag = ' | createUnsignedUxtoTx | ';
|
17
|
+
|
18
|
+
try {
|
19
|
+
if (!pioneer) throw Error('Failed to init! pioneer');
|
20
|
+
|
21
|
+
const networkId = caipToNetworkId(caip);
|
22
|
+
|
23
|
+
// Auto-correct context if wrong network
|
24
|
+
if (!keepKeySdk.pubkeyContext?.networks?.includes(networkId)) {
|
25
|
+
keepKeySdk.pubkeyContext = pubkeys.find((pk) => pk.networks?.includes(networkId));
|
26
|
+
}
|
27
|
+
|
28
|
+
// For UTXO, we still need all relevant pubkeys to aggregate UTXOs
|
29
|
+
const relevantPubkeys = pubkeys.filter(
|
30
|
+
(e) => e.networks && Array.isArray(e.networks) && e.networks.includes(networkId),
|
31
|
+
);
|
32
|
+
|
33
|
+
const segwitNetworks = [
|
34
|
+
'bip122:000000000019d6689c085ae165831e93', // Bitcoin Mainnet
|
35
|
+
// 'bip122:12a765e31ffd4059bada1e25190f6e98', // LTC
|
36
|
+
];
|
37
|
+
|
38
|
+
// Check if the current networkId is in the SegWit networks array
|
39
|
+
const isSegwit = segwitNetworks.includes(networkId);
|
40
|
+
|
41
|
+
let chain = NetworkIdToChain[networkId];
|
42
|
+
|
43
|
+
// Determine the change script type - use preference or default to p2wpkh for lower fees
|
44
|
+
const actualChangeScriptType =
|
45
|
+
changeScriptType ||
|
46
|
+
relevantPubkeys.find((pk) => pk.scriptType === 'p2wpkh')?.scriptType || // Prefer native segwit if available
|
47
|
+
relevantPubkeys[0].scriptType || // Fall back to first available
|
48
|
+
'p2wpkh'; // Ultimate default
|
49
|
+
console.log(`${tag}: Using change script type: ${actualChangeScriptType}`);
|
50
|
+
|
51
|
+
// Find the xpub that matches the desired script type
|
52
|
+
const changeXpub =
|
53
|
+
relevantPubkeys.find((pk) => pk.scriptType === actualChangeScriptType)?.pubkey ||
|
54
|
+
relevantPubkeys.find((pk) => pk.scriptType === 'p2wpkh')?.pubkey || // Fall back to native segwit
|
55
|
+
relevantPubkeys[0].pubkey; // Last resort: use first available
|
56
|
+
|
57
|
+
console.log(
|
58
|
+
`${tag}: Change xpub selected for ${actualChangeScriptType}:`,
|
59
|
+
changeXpub?.substring(0, 10) + '...',
|
60
|
+
);
|
61
|
+
|
62
|
+
let changeAddressIndex = await pioneer.GetChangeAddress({
|
63
|
+
network: chain,
|
64
|
+
xpub: changeXpub,
|
65
|
+
});
|
66
|
+
changeAddressIndex = changeAddressIndex.data.changeIndex;
|
67
|
+
|
68
|
+
// Determine BIP path based on script type
|
69
|
+
let bipPath: string;
|
70
|
+
switch (actualChangeScriptType) {
|
71
|
+
case 'p2pkh':
|
72
|
+
bipPath = `m/44'/0'/0'/1/${changeAddressIndex}`; // BIP44 for legacy
|
73
|
+
break;
|
74
|
+
case 'p2sh-p2wpkh':
|
75
|
+
bipPath = `m/49'/0'/0'/1/${changeAddressIndex}`; // BIP49 for wrapped segwit
|
76
|
+
break;
|
77
|
+
case 'p2wpkh':
|
78
|
+
default:
|
79
|
+
bipPath = `m/84'/0'/0'/1/${changeAddressIndex}`; // BIP84 for native segwit
|
80
|
+
break;
|
81
|
+
}
|
82
|
+
|
83
|
+
const path = bipPath;
|
84
|
+
console.log(`${tag}: Change address path: ${path} (index: ${changeAddressIndex})`);
|
85
|
+
|
86
|
+
const changeAddress = {
|
87
|
+
path: path,
|
88
|
+
isChange: true,
|
89
|
+
index: changeAddressIndex,
|
90
|
+
addressNList: bip32ToAddressNList(path),
|
91
|
+
scriptType: actualChangeScriptType, // Store the script type with the change address
|
92
|
+
};
|
93
|
+
|
94
|
+
const utxos: any[] = [];
|
95
|
+
for (const pubkey of relevantPubkeys) {
|
96
|
+
//console.log('pubkey: ',pubkey)
|
97
|
+
try {
|
98
|
+
let utxosResp = await pioneer.ListUnspent({ network: chain, xpub: pubkey.pubkey });
|
99
|
+
utxosResp = utxosResp.data;
|
100
|
+
console.log(
|
101
|
+
`${tag}: ListUnspent response for ${pubkey.scriptType}:`,
|
102
|
+
utxosResp?.length || 0,
|
103
|
+
'UTXOs',
|
104
|
+
);
|
105
|
+
|
106
|
+
// Validate the response
|
107
|
+
if (!utxosResp || !Array.isArray(utxosResp)) {
|
108
|
+
console.warn(`${tag}: Invalid or empty UTXO response for ${pubkey.pubkey}`);
|
109
|
+
continue;
|
110
|
+
}
|
111
|
+
|
112
|
+
//classify scriptType
|
113
|
+
let scriptType = pubkey.scriptType;
|
114
|
+
// Assign the scriptType to each UTXO in the array
|
115
|
+
for (const u of utxosResp) {
|
116
|
+
u.scriptType = scriptType;
|
117
|
+
}
|
118
|
+
utxos.push(...utxosResp);
|
119
|
+
} catch (error) {
|
120
|
+
console.error(`${tag}: Failed to fetch UTXOs for ${pubkey.pubkey}:`, error);
|
121
|
+
// Continue to next pubkey instead of failing entirely
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
console.log(`${tag}: Total UTXOs collected:`, utxos.length);
|
126
|
+
if (!utxos || utxos.length === 0) throw Error('No UTXOs found across all addresses');
|
127
|
+
|
128
|
+
for (const utxo of utxos) {
|
129
|
+
utxo.value = Number(utxo.value);
|
130
|
+
}
|
131
|
+
|
132
|
+
let feeRateFromNode: any;
|
133
|
+
|
134
|
+
// HARDCODE DOGE FEES - API is unreliable for DOGE
|
135
|
+
if (networkId === 'bip122:00000000001a91e3dace36e2be3bf030') {
|
136
|
+
console.log(`${tag}: Using hardcoded fees for DOGE (10 sat/byte)`);
|
137
|
+
feeRateFromNode = {
|
138
|
+
slow: 10,
|
139
|
+
average: 10,
|
140
|
+
fast: 10,
|
141
|
+
fastest: 10,
|
142
|
+
unit: 'sat/byte',
|
143
|
+
description: 'Hardcoded DOGE fees - API unreliable'
|
144
|
+
};
|
145
|
+
} else {
|
146
|
+
try {
|
147
|
+
// Try GetFeeRateByNetwork first (newer API), then fallback to GetFeeRate
|
148
|
+
let feeResponse;
|
149
|
+
if (pioneer.GetFeeRateByNetwork) {
|
150
|
+
console.log(`${tag}: Trying GetFeeRateByNetwork for ${networkId}`);
|
151
|
+
feeResponse = await pioneer.GetFeeRateByNetwork({ networkId });
|
152
|
+
} else {
|
153
|
+
console.log(`${tag}: Using GetFeeRate for ${networkId}`);
|
154
|
+
feeResponse = await pioneer.GetFeeRate({ networkId });
|
155
|
+
}
|
156
|
+
|
157
|
+
feeRateFromNode = feeResponse.data;
|
158
|
+
console.log(`${tag}: Got fee rates from API:`, JSON.stringify(feeRateFromNode, null, 2));
|
159
|
+
|
160
|
+
// UNIT CONVERSION: Detect if API returned sat/kB instead of sat/byte
|
161
|
+
// If values are unreasonably high (>500), they're likely in sat/kB
|
162
|
+
const conversionThreshold = 500;
|
163
|
+
const needsConversion =
|
164
|
+
(feeRateFromNode.slow && feeRateFromNode.slow > conversionThreshold) ||
|
165
|
+
(feeRateFromNode.average && feeRateFromNode.average > conversionThreshold) ||
|
166
|
+
(feeRateFromNode.fast && feeRateFromNode.fast > conversionThreshold) ||
|
167
|
+
(feeRateFromNode.fastest && feeRateFromNode.fastest > conversionThreshold);
|
168
|
+
|
169
|
+
if (needsConversion) {
|
170
|
+
console.warn(`${tag}: Detected wrong units - values appear to be in sat/kB instead of sat/byte`);
|
171
|
+
console.warn(`${tag}: Original values:`, {
|
172
|
+
slow: feeRateFromNode.slow,
|
173
|
+
average: feeRateFromNode.average,
|
174
|
+
fast: feeRateFromNode.fast,
|
175
|
+
fastest: feeRateFromNode.fastest,
|
176
|
+
});
|
177
|
+
|
178
|
+
// Convert from sat/kB to sat/byte by dividing by 1000
|
179
|
+
if (feeRateFromNode.slow) feeRateFromNode.slow = feeRateFromNode.slow / 1000;
|
180
|
+
if (feeRateFromNode.average) feeRateFromNode.average = feeRateFromNode.average / 1000;
|
181
|
+
if (feeRateFromNode.fast) feeRateFromNode.fast = feeRateFromNode.fast / 1000;
|
182
|
+
if (feeRateFromNode.fastest) feeRateFromNode.fastest = feeRateFromNode.fastest / 1000;
|
183
|
+
|
184
|
+
console.warn(`${tag}: Converted to sat/byte:`, feeRateFromNode);
|
185
|
+
}
|
186
|
+
|
187
|
+
// Validate the response has the expected structure
|
188
|
+
if (!feeRateFromNode || typeof feeRateFromNode !== 'object') {
|
189
|
+
throw new Error(`Invalid fee rate response from API: ${JSON.stringify(feeRateFromNode)}`);
|
190
|
+
}
|
191
|
+
|
192
|
+
// Log all available fee rates for debugging
|
193
|
+
console.log(`${tag}: Available fee rates:`, {
|
194
|
+
slow: feeRateFromNode.slow,
|
195
|
+
average: feeRateFromNode.average,
|
196
|
+
fast: feeRateFromNode.fast,
|
197
|
+
fastest: feeRateFromNode.fastest,
|
198
|
+
});
|
199
|
+
|
200
|
+
// Check that we have at least one fee rate
|
201
|
+
if (
|
202
|
+
!feeRateFromNode.slow &&
|
203
|
+
!feeRateFromNode.average &&
|
204
|
+
!feeRateFromNode.fast &&
|
205
|
+
!feeRateFromNode.fastest
|
206
|
+
) {
|
207
|
+
throw new Error(`No valid fee rates in API response: ${JSON.stringify(feeRateFromNode)}`);
|
208
|
+
}
|
209
|
+
} catch (error: any) {
|
210
|
+
console.error(`${tag}: Failed to get fee rates from Pioneer API:`, error.message || error);
|
211
|
+
throw new Error(
|
212
|
+
`Unable to get fee rate for network ${networkId}: ${error.message || 'API unavailable'}`,
|
213
|
+
);
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
217
|
+
// Map fee level to fee rate (1-2 = slow, 3-4 = average, 5 = fastest)
|
218
|
+
// Frontend typically sends: slow=1, average=3, fastest=5
|
219
|
+
let effectiveFeeRate;
|
220
|
+
console.log(`${tag}: Using fee level ${feeLevel}`);
|
221
|
+
|
222
|
+
switch (feeLevel) {
|
223
|
+
case 1:
|
224
|
+
case 2:
|
225
|
+
effectiveFeeRate = feeRateFromNode.slow || feeRateFromNode.average;
|
226
|
+
console.log(`${tag}: Using SLOW fee rate: ${effectiveFeeRate} sat/vB`);
|
227
|
+
break;
|
228
|
+
case 3:
|
229
|
+
case 4:
|
230
|
+
effectiveFeeRate = feeRateFromNode.average || feeRateFromNode.fast;
|
231
|
+
console.log(`${tag}: Using AVERAGE fee rate: ${effectiveFeeRate} sat/vB`);
|
232
|
+
break;
|
233
|
+
case 5:
|
234
|
+
effectiveFeeRate = feeRateFromNode.fastest || feeRateFromNode.fast;
|
235
|
+
console.log(`${tag}: Using FASTEST fee rate: ${effectiveFeeRate} sat/vB`);
|
236
|
+
break;
|
237
|
+
default:
|
238
|
+
throw new Error(`Invalid fee level: ${feeLevel}. Must be 1-5`);
|
239
|
+
}
|
240
|
+
|
241
|
+
if (!effectiveFeeRate) throw new Error('Unable to get fee rate for network');
|
242
|
+
|
243
|
+
// Log what we're using
|
244
|
+
console.log(`${tag}: Using fee rate from API:`, {
|
245
|
+
feeLevel,
|
246
|
+
selectedRate: effectiveFeeRate,
|
247
|
+
description: feeLevel <= 2 ? 'slow' : feeLevel <= 4 ? 'average' : 'fast',
|
248
|
+
});
|
249
|
+
|
250
|
+
// Only enforce minimum for safety if fee is 0 or negative
|
251
|
+
if (effectiveFeeRate <= 0) throw Error('Failed to build valid fee! Must be > 0');
|
252
|
+
|
253
|
+
// CRITICAL: coinselect library requires WHOLE NUMBER fee rates, not decimals
|
254
|
+
// Round up to ensure we don't underpay on fees
|
255
|
+
effectiveFeeRate = Math.ceil(effectiveFeeRate);
|
256
|
+
|
257
|
+
// Enforce Bitcoin network minimum relay fee (3 sat/vB minimum for BTC mainnet)
|
258
|
+
// This prevents "min relay fee not met" errors from nodes
|
259
|
+
const MIN_RELAY_FEE_RATE = 3;
|
260
|
+
if (effectiveFeeRate < MIN_RELAY_FEE_RATE) {
|
261
|
+
console.log(`${tag}: Fee rate ${effectiveFeeRate} is below minimum relay fee, increasing to ${MIN_RELAY_FEE_RATE} sat/vB`);
|
262
|
+
effectiveFeeRate = MIN_RELAY_FEE_RATE;
|
263
|
+
}
|
264
|
+
|
265
|
+
// The effectiveFeeRate is now the actual sat/vB from the API
|
266
|
+
console.log(`${tag}: Final fee rate to use (rounded, with minimums): ${effectiveFeeRate} sat/vB`);
|
267
|
+
|
268
|
+
amount = parseInt(String(amount * 1e8));
|
269
|
+
if (amount <= 0 && !isMax) throw Error('Invalid amount! 0');
|
270
|
+
|
271
|
+
// Log UTXOs before coin selection for debugging
|
272
|
+
const totalBalance = utxos.reduce((sum, utxo) => sum + utxo.value, 0);
|
273
|
+
console.log(`${tag}: Coin selection inputs:`, {
|
274
|
+
utxoCount: utxos.length,
|
275
|
+
totalBalance: totalBalance / 1e8,
|
276
|
+
requestedAmount: amount / 1e8,
|
277
|
+
isMax,
|
278
|
+
feeRate: effectiveFeeRate,
|
279
|
+
});
|
280
|
+
|
281
|
+
// DEBUG: Log actual UTXO structure to see what coinselect receives
|
282
|
+
console.log(`${tag}: UTXO details for coin selection:`,
|
283
|
+
utxos.map(u => ({
|
284
|
+
value: u.value,
|
285
|
+
txid: u.txid?.substring(0, 10) + '...',
|
286
|
+
vout: u.vout,
|
287
|
+
scriptType: u.scriptType,
|
288
|
+
hasPath: !!u.path,
|
289
|
+
hasTxHex: !!u.txHex
|
290
|
+
}))
|
291
|
+
);
|
292
|
+
|
293
|
+
let result;
|
294
|
+
if (isMax) {
|
295
|
+
//console.log(tag, 'isMax:', isMax);
|
296
|
+
// For max send, use coinSelectSplit
|
297
|
+
const { default: coinSelectSplit } = await import('coinselect/split');
|
298
|
+
result = coinSelectSplit(utxos, [{ address: to }], effectiveFeeRate);
|
299
|
+
} else {
|
300
|
+
//console.log(tag, 'isMax:', isMax)
|
301
|
+
// Regular send
|
302
|
+
const { default: coinSelect } = await import('coinselect');
|
303
|
+
result = coinSelect(utxos, [{ address: to, value: amount }], effectiveFeeRate);
|
304
|
+
}
|
305
|
+
|
306
|
+
console.log(tag, 'coinSelect result object:', result);
|
307
|
+
console.log(tag, 'coinSelect result.inputs:', result?.inputs);
|
308
|
+
|
309
|
+
if (!result || !result.inputs) {
|
310
|
+
// Provide detailed error information
|
311
|
+
const errorDetails = {
|
312
|
+
utxoCount: utxos.length,
|
313
|
+
totalBalance: totalBalance / 1e8,
|
314
|
+
requestedAmount: amount / 1e8,
|
315
|
+
feeRate: effectiveFeeRate,
|
316
|
+
insufficientFunds: totalBalance < amount,
|
317
|
+
};
|
318
|
+
console.error(`${tag}: Coin selection failed:`, errorDetails);
|
319
|
+
|
320
|
+
if (utxos.length === 0) {
|
321
|
+
throw Error('No UTXOs available for coin selection');
|
322
|
+
} else if (totalBalance < amount) {
|
323
|
+
throw Error(`Insufficient funds: Have ${totalBalance / 1e8} BTC, need ${amount / 1e8} BTC`);
|
324
|
+
} else {
|
325
|
+
throw Error(
|
326
|
+
'Failed to create transaction: Coin selection failed (possibly due to high fees)',
|
327
|
+
);
|
328
|
+
}
|
329
|
+
}
|
330
|
+
|
331
|
+
let { inputs, outputs, fee } = result;
|
332
|
+
if (!inputs) throw Error('Failed to create transaction: Missing inputs');
|
333
|
+
if (!outputs) throw Error('Failed to create transaction: Missing outputs');
|
334
|
+
if (fee === undefined) throw Error('Failed to calculate transaction fee');
|
335
|
+
|
336
|
+
console.log(`${tag}: Transaction built with:`, {
|
337
|
+
feeLevel,
|
338
|
+
effectiveFeeRate: `${effectiveFeeRate} sat/vB`,
|
339
|
+
calculatedFee: `${fee} satoshis`,
|
340
|
+
inputCount: inputs.length,
|
341
|
+
outputCount: outputs.length,
|
342
|
+
});
|
343
|
+
|
344
|
+
const uniqueInputSet = new Set();
|
345
|
+
console.log(tag, 'inputs:', inputs);
|
346
|
+
console.log(tag, 'inputs:', inputs[0]);
|
347
|
+
const preparedInputs = inputs
|
348
|
+
.map(transformInput)
|
349
|
+
.filter(({ hash, index }) =>
|
350
|
+
uniqueInputSet.has(`${hash}:${index}`) ? false : uniqueInputSet.add(`${hash}:${index}`),
|
351
|
+
)
|
352
|
+
.map(({ value, index, hash, txHex, path, scriptType }) => ({
|
353
|
+
addressNList: bip32ToAddressNList(path),
|
354
|
+
//TODO this is PER INPUT not per asset, we need to detect what pubkeys are segwit what are not
|
355
|
+
scriptType,
|
356
|
+
amount: value.toString(),
|
357
|
+
vout: index,
|
358
|
+
txid: hash,
|
359
|
+
hex: txHex || '',
|
360
|
+
}));
|
361
|
+
|
362
|
+
// Remove hardcoded script type - use the one from changeAddress
|
363
|
+
|
364
|
+
const preparedOutputs = outputs
|
365
|
+
.map(({ value, address }) => {
|
366
|
+
if (address) {
|
367
|
+
return { address, amount: value.toString(), addressType: 'spend' };
|
368
|
+
} else if (!isMax) {
|
369
|
+
return {
|
370
|
+
addressNList: changeAddress.addressNList,
|
371
|
+
scriptType: changeAddress.scriptType, // Use the correct script type from change address
|
372
|
+
isChange: true,
|
373
|
+
amount: value.toString(),
|
374
|
+
addressType: 'change',
|
375
|
+
};
|
376
|
+
}
|
377
|
+
return null; // No change output when isMax is true
|
378
|
+
})
|
379
|
+
.filter((output) => output !== null);
|
380
|
+
|
381
|
+
if (!fee) {
|
382
|
+
fee =
|
383
|
+
inputs.reduce((acc, input) => acc + input.value, 0) -
|
384
|
+
outputs.reduce((acc, output) => acc + parseInt(output.amount), 0);
|
385
|
+
}
|
386
|
+
|
387
|
+
// Include the fee in the transaction object for the vault to use
|
388
|
+
let unsignedTx = {
|
389
|
+
inputs: preparedInputs,
|
390
|
+
outputs: preparedOutputs,
|
391
|
+
memo,
|
392
|
+
fee: fee.toString(), // Add the calculated fee to the returned object
|
393
|
+
};
|
394
|
+
//console.log(tag, 'unsignedTx:', unsignedTx);
|
395
|
+
|
396
|
+
return unsignedTx;
|
397
|
+
} catch (error) {
|
398
|
+
//console.log(tag, 'Error:', error);
|
399
|
+
throw error;
|
400
|
+
}
|
401
|
+
}
|
402
|
+
|
403
|
+
function transformInput(input) {
|
404
|
+
const {
|
405
|
+
txid,
|
406
|
+
vout,
|
407
|
+
value,
|
408
|
+
address,
|
409
|
+
height,
|
410
|
+
confirmations,
|
411
|
+
path,
|
412
|
+
scriptType,
|
413
|
+
hex: txHex,
|
414
|
+
tx,
|
415
|
+
coin,
|
416
|
+
network,
|
417
|
+
} = input;
|
418
|
+
|
419
|
+
return {
|
420
|
+
address,
|
421
|
+
hash: txid,
|
422
|
+
index: vout,
|
423
|
+
value: parseInt(value),
|
424
|
+
height,
|
425
|
+
scriptType,
|
426
|
+
confirmations,
|
427
|
+
path,
|
428
|
+
txHex,
|
429
|
+
tx,
|
430
|
+
coin,
|
431
|
+
network,
|
432
|
+
witnessUtxo: {
|
433
|
+
value: parseInt(tx.vout[0].value),
|
434
|
+
script: Buffer.from(tx.vout[0].scriptPubKey.hex, 'hex'),
|
435
|
+
},
|
436
|
+
};
|
437
|
+
}
|
438
|
+
|
439
|
+
function getScriptTypeFromXpub(xpub: string): string {
|
440
|
+
if (xpub.startsWith('xpub')) {
|
441
|
+
return 'p2pkh'; // Legacy
|
442
|
+
} else if (xpub.startsWith('ypub')) {
|
443
|
+
return 'p2sh'; // P2WPKH nested in P2SH
|
444
|
+
} else if (xpub.startsWith('zpub')) {
|
445
|
+
return 'p2wpkh'; // Native SegWit
|
446
|
+
} else {
|
447
|
+
// Default fallback
|
448
|
+
return 'p2pkh';
|
449
|
+
}
|
450
|
+
}
|
@@ -0,0 +1,157 @@
|
|
1
|
+
export const cosmosDelegateTemplate = (params: {
|
2
|
+
account_number: string;
|
3
|
+
chain_id: string;
|
4
|
+
fee: { gas: string; amount: any[] };
|
5
|
+
from_address: string;
|
6
|
+
validator_address: string;
|
7
|
+
amount: string;
|
8
|
+
denom: string;
|
9
|
+
memo: string;
|
10
|
+
sequence: string;
|
11
|
+
}) => ({
|
12
|
+
signerAddress: params.from_address,
|
13
|
+
signDoc: {
|
14
|
+
account_number: params.account_number,
|
15
|
+
chain_id: params.chain_id,
|
16
|
+
fee: params.fee,
|
17
|
+
msgs: [
|
18
|
+
{
|
19
|
+
value: {
|
20
|
+
delegator_address: params.from_address,
|
21
|
+
validator_address: params.validator_address,
|
22
|
+
amount: {
|
23
|
+
denom: params.denom,
|
24
|
+
amount: params.amount,
|
25
|
+
},
|
26
|
+
},
|
27
|
+
type: 'cosmos-sdk/MsgDelegate',
|
28
|
+
},
|
29
|
+
],
|
30
|
+
memo: params.memo,
|
31
|
+
sequence: params.sequence,
|
32
|
+
},
|
33
|
+
});
|
34
|
+
|
35
|
+
export const cosmosUndelegateTemplate = (params: {
|
36
|
+
account_number: string;
|
37
|
+
chain_id: string;
|
38
|
+
fee: { gas: string; amount: any[] };
|
39
|
+
from_address: string;
|
40
|
+
validator_address: string;
|
41
|
+
amount: string;
|
42
|
+
denom: string;
|
43
|
+
memo: string;
|
44
|
+
sequence: string;
|
45
|
+
}) => ({
|
46
|
+
signerAddress: params.from_address,
|
47
|
+
signDoc: {
|
48
|
+
account_number: params.account_number,
|
49
|
+
chain_id: params.chain_id,
|
50
|
+
fee: params.fee,
|
51
|
+
msgs: [
|
52
|
+
{
|
53
|
+
value: {
|
54
|
+
delegator_address: params.from_address,
|
55
|
+
validator_address: params.validator_address,
|
56
|
+
amount: {
|
57
|
+
denom: params.denom,
|
58
|
+
amount: params.amount,
|
59
|
+
},
|
60
|
+
},
|
61
|
+
type: 'cosmos-sdk/MsgUndelegate',
|
62
|
+
},
|
63
|
+
],
|
64
|
+
memo: params.memo,
|
65
|
+
sequence: params.sequence,
|
66
|
+
},
|
67
|
+
});
|
68
|
+
|
69
|
+
export const cosmosRedelegateTemplate = (params: {
|
70
|
+
account_number: string;
|
71
|
+
chain_id: string;
|
72
|
+
fee: { gas: string; amount: any[] };
|
73
|
+
from_address: string;
|
74
|
+
validator_src_address: string;
|
75
|
+
validator_dst_address: string;
|
76
|
+
amount: string;
|
77
|
+
denom: string;
|
78
|
+
memo: string;
|
79
|
+
sequence: string;
|
80
|
+
}) => ({
|
81
|
+
signerAddress: params.from_address,
|
82
|
+
signDoc: {
|
83
|
+
account_number: params.account_number,
|
84
|
+
chain_id: params.chain_id,
|
85
|
+
fee: params.fee,
|
86
|
+
msgs: [
|
87
|
+
{
|
88
|
+
value: {
|
89
|
+
delegator_address: params.from_address,
|
90
|
+
validator_src_address: params.validator_src_address,
|
91
|
+
validator_dst_address: params.validator_dst_address,
|
92
|
+
amount: {
|
93
|
+
denom: params.denom,
|
94
|
+
amount: params.amount,
|
95
|
+
},
|
96
|
+
},
|
97
|
+
type: 'cosmos-sdk/MsgBeginRedelegate',
|
98
|
+
},
|
99
|
+
],
|
100
|
+
memo: params.memo,
|
101
|
+
sequence: params.sequence,
|
102
|
+
},
|
103
|
+
});
|
104
|
+
|
105
|
+
export const cosmosClaimRewardsTemplate = (params: {
|
106
|
+
account_number: string;
|
107
|
+
chain_id: string;
|
108
|
+
fee: { gas: string; amount: any[] };
|
109
|
+
from_address: string;
|
110
|
+
validator_address: string;
|
111
|
+
memo: string;
|
112
|
+
sequence: string;
|
113
|
+
}) => ({
|
114
|
+
signerAddress: params.from_address,
|
115
|
+
signDoc: {
|
116
|
+
account_number: params.account_number,
|
117
|
+
chain_id: params.chain_id,
|
118
|
+
fee: params.fee,
|
119
|
+
msgs: [
|
120
|
+
{
|
121
|
+
value: {
|
122
|
+
delegator_address: params.from_address,
|
123
|
+
validator_address: params.validator_address,
|
124
|
+
},
|
125
|
+
type: 'cosmos-sdk/MsgWithdrawDelegatorReward',
|
126
|
+
},
|
127
|
+
],
|
128
|
+
memo: params.memo,
|
129
|
+
sequence: params.sequence,
|
130
|
+
},
|
131
|
+
});
|
132
|
+
|
133
|
+
export const cosmosClaimAllRewardsTemplate = (params: {
|
134
|
+
account_number: string;
|
135
|
+
chain_id: string;
|
136
|
+
fee: { gas: string; amount: any[] };
|
137
|
+
from_address: string;
|
138
|
+
validator_addresses: string[];
|
139
|
+
memo: string;
|
140
|
+
sequence: string;
|
141
|
+
}) => ({
|
142
|
+
signerAddress: params.from_address,
|
143
|
+
signDoc: {
|
144
|
+
account_number: params.account_number,
|
145
|
+
chain_id: params.chain_id,
|
146
|
+
fee: params.fee,
|
147
|
+
msgs: params.validator_addresses.map((validator_address) => ({
|
148
|
+
value: {
|
149
|
+
delegator_address: params.from_address,
|
150
|
+
validator_address,
|
151
|
+
},
|
152
|
+
type: 'cosmos-sdk/MsgWithdrawDelegatorReward',
|
153
|
+
})),
|
154
|
+
memo: params.memo,
|
155
|
+
sequence: params.sequence,
|
156
|
+
},
|
157
|
+
});
|
@@ -0,0 +1,30 @@
|
|
1
|
+
export const cosmosTransferTemplate = (params: {
|
2
|
+
account_number: string;
|
3
|
+
chain_id: string;
|
4
|
+
fee: { gas: string; amount: any[] };
|
5
|
+
from_address: string;
|
6
|
+
to_address: string;
|
7
|
+
asset: string;
|
8
|
+
amount: string;
|
9
|
+
memo: string;
|
10
|
+
sequence: string;
|
11
|
+
}) => ({
|
12
|
+
signerAddress: params.from_address,
|
13
|
+
signDoc: {
|
14
|
+
account_number: params.account_number,
|
15
|
+
chain_id: params.chain_id,
|
16
|
+
fee: params.fee,
|
17
|
+
msgs: [
|
18
|
+
{
|
19
|
+
value: {
|
20
|
+
amount: [{ denom: params.asset, amount: params.amount }],
|
21
|
+
to_address: params.to_address,
|
22
|
+
from_address: params.from_address,
|
23
|
+
},
|
24
|
+
type: 'cosmos-sdk/MsgSend',
|
25
|
+
},
|
26
|
+
],
|
27
|
+
memo: params.memo || '',
|
28
|
+
sequence: params.sequence,
|
29
|
+
},
|
30
|
+
});
|
@@ -0,0 +1,60 @@
|
|
1
|
+
export const mayachainTransferTemplate = (params: {
|
2
|
+
account_number: string;
|
3
|
+
chain_id: string;
|
4
|
+
fee: { gas: string; amount: any[] };
|
5
|
+
from_address: string;
|
6
|
+
to_address: string;
|
7
|
+
asset: string;
|
8
|
+
amount: string;
|
9
|
+
memo: string;
|
10
|
+
sequence: string;
|
11
|
+
}) => ({
|
12
|
+
signerAddress: params.from_address,
|
13
|
+
signDoc: {
|
14
|
+
account_number: params.account_number,
|
15
|
+
chain_id: params.chain_id,
|
16
|
+
fee: params.fee,
|
17
|
+
msgs: [
|
18
|
+
{
|
19
|
+
value: {
|
20
|
+
amount: [{ denom: params.asset, amount: params.amount }],
|
21
|
+
to_address: params.to_address,
|
22
|
+
from_address: params.from_address,
|
23
|
+
},
|
24
|
+
type: 'mayachain/MsgSend' as const,
|
25
|
+
},
|
26
|
+
],
|
27
|
+
memo: params.memo,
|
28
|
+
sequence: params.sequence,
|
29
|
+
},
|
30
|
+
});
|
31
|
+
|
32
|
+
export const mayachainDepositTemplate = (params: {
|
33
|
+
account_number: string;
|
34
|
+
chain_id: string;
|
35
|
+
fee: { gas: string; amount: any[] };
|
36
|
+
from_address: string;
|
37
|
+
asset: string;
|
38
|
+
amount: string;
|
39
|
+
memo: string;
|
40
|
+
sequence: string;
|
41
|
+
}) => ({
|
42
|
+
signerAddress: params.from_address,
|
43
|
+
signDoc: {
|
44
|
+
account_number: params.account_number,
|
45
|
+
chain_id: params.chain_id,
|
46
|
+
fee: params.fee,
|
47
|
+
msgs: [
|
48
|
+
{
|
49
|
+
value: {
|
50
|
+
coins: [{ asset: params.asset, amount: params.amount }],
|
51
|
+
memo: params.memo,
|
52
|
+
signer: params.from_address,
|
53
|
+
},
|
54
|
+
type: 'mayachain/MsgDeposit',
|
55
|
+
},
|
56
|
+
],
|
57
|
+
memo: params.memo,
|
58
|
+
sequence: params.sequence,
|
59
|
+
},
|
60
|
+
});
|