@exodus/bitcoin-api 2.10.1 → 2.12.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/package.json +3 -2
- package/src/index.js +1 -0
- package/src/insight-api-client/ws.js +6 -1
- package/src/sign-message.js +11 -0
- package/src/tx-send/index.js +207 -49
- package/src/tx-sign/create-get-key-and-purpose.js +3 -5
- package/src/tx-sign/create-sign-with-wallet.js +6 -8
- package/src/tx-sign/default-create-tx.js +1 -3
- package/src/tx-sign/taproot.js +7 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/bitcoin-api",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"description": "Exodus bitcoin-api",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@exodus/asset-lib": "^4.1.0",
|
|
22
22
|
"@exodus/basic-utils": "^2.1.0",
|
|
23
|
+
"@exodus/bip322-js": "^1.1.0-exodus.4",
|
|
23
24
|
"@exodus/bip44-constants": "^195.0.0",
|
|
24
25
|
"@exodus/bitcoin-lib": "2.3.0",
|
|
25
26
|
"@exodus/bitcoinjs-lib": "^6.1.5-exodus.1",
|
|
@@ -57,5 +58,5 @@
|
|
|
57
58
|
"jest-when": "^3.5.1",
|
|
58
59
|
"safe-buffer": "^5.2.1"
|
|
59
60
|
},
|
|
60
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "49a0b40b825c556ea08538c5cedf64754dd35369"
|
|
61
62
|
}
|
package/src/index.js
CHANGED
|
@@ -11,7 +11,12 @@ export default class InsightWSClient extends EventEmitter {
|
|
|
11
11
|
|
|
12
12
|
connect(addresses, opts) {
|
|
13
13
|
const options = Object.assign(
|
|
14
|
-
{
|
|
14
|
+
{
|
|
15
|
+
transports: ['websocket'],
|
|
16
|
+
reconnectionDelayMax: 30_000,
|
|
17
|
+
reconnectionDelay: 10_000,
|
|
18
|
+
extraHeaders: { 'User-Agent': 'exodus' },
|
|
19
|
+
},
|
|
15
20
|
opts
|
|
16
21
|
)
|
|
17
22
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Signer } from '@exodus/bip322-js'
|
|
2
|
+
import assert from 'minimalistic-assert'
|
|
3
|
+
|
|
4
|
+
export const signMessage = async ({ privateKey, message: _message }) => {
|
|
5
|
+
assert(_message?.bip322Message, `expected bip322Message`)
|
|
6
|
+
|
|
7
|
+
const { address, message } = _message.bip322Message
|
|
8
|
+
const signedMessage = Signer.sign(Buffer.from(privateKey), address, message)
|
|
9
|
+
|
|
10
|
+
return Buffer.isBuffer(signedMessage) ? signedMessage : Buffer.from(signedMessage, 'base64')
|
|
11
|
+
}
|
package/src/tx-send/index.js
CHANGED
|
@@ -128,16 +128,99 @@ export const getSizeAndChangeScriptFactory =
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Signs a transaction using the provided asset client interface.
|
|
133
|
+
*
|
|
134
|
+
* @async
|
|
135
|
+
* @function signTransaction
|
|
136
|
+
* @param {Object} assetClientInterface - The asset client interface to use for signing the transaction.
|
|
137
|
+
* @param {string} assetName - The name of the asset.
|
|
138
|
+
* @param {Object} unsignedTx - The unsigned transaction to sign.
|
|
139
|
+
* @param {Object} walletAccount - The wallet account to use for signing.
|
|
140
|
+
* @returns {Promise<Object>} An object containing the signed raw transaction, transaction ID, and the signed transaction.
|
|
141
|
+
* @throws {Error} Throws an error if signing the transaction fails.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* // Example usage:
|
|
145
|
+
* const { rawTx, txId, tx } = await signTransaction({assetClientInterface, assetName, unsignedTx, walletAccount});
|
|
146
|
+
* // rawTx: Buffer data representing the signed raw transaction
|
|
147
|
+
* // txId: The ID of the signed transaction
|
|
148
|
+
* // tx: An object representing the signed transaction, containing virtualSize and outs
|
|
149
|
+
* // Example returned object:
|
|
150
|
+
* {
|
|
151
|
+
* rawTx: {
|
|
152
|
+
* type: "Buffer",
|
|
153
|
+
* data: [
|
|
154
|
+
* 2,
|
|
155
|
+
* ...
|
|
156
|
+
* ]
|
|
157
|
+
* },
|
|
158
|
+
* txId: "35244fba5cc46d6f3773689dce11ddba3f341149ef627c051e1a0bacd9458a1c",
|
|
159
|
+
* tx: {
|
|
160
|
+
* virtualSize: 110,
|
|
161
|
+
* outs: [
|
|
162
|
+
* {
|
|
163
|
+
* script: "0014c06da7c31e24ba4e7a0656443e17c00572a3e9f7"
|
|
164
|
+
* }
|
|
165
|
+
* ]
|
|
166
|
+
* }
|
|
167
|
+
* }
|
|
168
|
+
*/
|
|
169
|
+
export async function signTransaction({
|
|
170
|
+
assetClientInterface,
|
|
171
|
+
assetName,
|
|
172
|
+
unsignedTx,
|
|
173
|
+
walletAccount,
|
|
174
|
+
}) {
|
|
175
|
+
const { rawTx, txId, tx } = await assetClientInterface.signTransaction({
|
|
176
|
+
assetName,
|
|
177
|
+
unsignedTx,
|
|
178
|
+
walletAccount,
|
|
179
|
+
})
|
|
180
|
+
return { rawTx, txId, tx }
|
|
181
|
+
}
|
|
133
182
|
|
|
134
|
-
|
|
183
|
+
async function createUnsignedTx({
|
|
184
|
+
inputs,
|
|
185
|
+
outputs,
|
|
186
|
+
useCashAddress,
|
|
187
|
+
addressPathsMap,
|
|
188
|
+
blockHeight,
|
|
189
|
+
asset,
|
|
190
|
+
selectedUtxos,
|
|
191
|
+
insightClient,
|
|
192
|
+
}) {
|
|
193
|
+
const unsignedTx = {
|
|
194
|
+
txData: {
|
|
195
|
+
inputs,
|
|
196
|
+
outputs,
|
|
197
|
+
},
|
|
198
|
+
txMeta: {
|
|
199
|
+
useCashAddress, // for trezor to show the receiver cash address
|
|
200
|
+
addressPathsMap,
|
|
201
|
+
blockHeight,
|
|
202
|
+
},
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const nonWitnessTxs = await getNonWitnessTxs(asset, selectedUtxos, insightClient)
|
|
206
|
+
Object.assign(unsignedTx.txMeta, { rawTxs: nonWitnessTxs })
|
|
207
|
+
return unsignedTx
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async function getBlockHeight({ assetName, insightClient }) {
|
|
211
|
+
return ['zcash', 'bitcoin', 'bitcoinregtest', 'bitcointestnet'].includes(assetName)
|
|
212
|
+
? insightClient.fetchBlockHeight()
|
|
213
|
+
: 0
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export const getPrepareSendTransaction =
|
|
135
217
|
({
|
|
218
|
+
blockHeight: providedBlockHeight,
|
|
219
|
+
ordinalsEnabled,
|
|
136
220
|
getFeeEstimator,
|
|
137
|
-
getSizeAndChangeScript = getSizeAndChangeScriptFactory(), // for decred customizations
|
|
138
221
|
allowUnconfirmedRbfEnabledUtxos,
|
|
139
|
-
ordinalsEnabled = false,
|
|
140
222
|
utxosDescendingOrder,
|
|
223
|
+
rbfEnabled: providedRbfEnabled,
|
|
141
224
|
}) =>
|
|
142
225
|
async (
|
|
143
226
|
{ asset: maybeToken, walletAccount, address, amount: tokenAmount, options },
|
|
@@ -148,30 +231,33 @@ export const createAndBroadcastTXFactory =
|
|
|
148
231
|
feePerKB,
|
|
149
232
|
customFee,
|
|
150
233
|
isSendAll,
|
|
151
|
-
isExchange,
|
|
152
|
-
isBip70,
|
|
153
234
|
bumpTxId,
|
|
154
|
-
isRbfAllowed = true,
|
|
155
235
|
nft,
|
|
156
236
|
feeOpts,
|
|
237
|
+
isExchange,
|
|
238
|
+
isBip70,
|
|
239
|
+
isRbfAllowed,
|
|
157
240
|
} = options
|
|
158
241
|
|
|
242
|
+
const asset = maybeToken.baseAsset
|
|
243
|
+
const assetName = asset.name
|
|
244
|
+
const accountState = await assetClientInterface.getAccountState({ assetName, walletAccount })
|
|
245
|
+
const feeData = await assetClientInterface.getFeeConfig({ assetName })
|
|
246
|
+
const insightClient = asset.baseAsset.insightClient
|
|
247
|
+
|
|
248
|
+
const blockHeight = providedBlockHeight || (await getBlockHeight({ assetName, insightClient }))
|
|
159
249
|
const brc20 = options.brc20 || feeOpts?.brc20 // feeOpts is the only way I've found atm to pass brc20 param without changing the tx-send hydra module
|
|
160
250
|
|
|
161
|
-
const
|
|
251
|
+
const rbfEnabled =
|
|
252
|
+
providedRbfEnabled ||
|
|
253
|
+
(feeData.rbfEnabled && !isExchange && !isBip70 && isRbfAllowed && !nft && !brc20)
|
|
162
254
|
|
|
163
255
|
const isToken = maybeToken.name !== asset.name
|
|
164
|
-
|
|
165
256
|
if (isToken) {
|
|
166
257
|
assert(brc20, 'brc20 is required when sending bitcoin token')
|
|
167
258
|
}
|
|
168
259
|
|
|
169
260
|
const amount = isToken ? asset.currency.ZERO : tokenAmount
|
|
170
|
-
|
|
171
|
-
const assetName = asset.name
|
|
172
|
-
|
|
173
|
-
const accountState = await assetClientInterface.getAccountState({ assetName, walletAccount })
|
|
174
|
-
|
|
175
261
|
const inscriptionIds = nft?.tokenId ? [nft?.tokenId] : brc20 ? brc20.inscriptionIds : undefined
|
|
176
262
|
|
|
177
263
|
assert(
|
|
@@ -210,9 +296,8 @@ export const createAndBroadcastTXFactory =
|
|
|
210
296
|
? getTransferOrdinalsUtxos({ inscriptionIds, ordinalsUtxos: currentOrdinalsUtxos })
|
|
211
297
|
: undefined
|
|
212
298
|
|
|
213
|
-
const insightClient = asset.baseAsset.insightClient
|
|
214
299
|
const currency = asset.currency
|
|
215
|
-
|
|
300
|
+
|
|
216
301
|
const unconfirmedTxAncestor = getUnconfirmedTxAncestorMap({ accountState })
|
|
217
302
|
const usableUtxos = getUsableUtxos({
|
|
218
303
|
asset,
|
|
@@ -232,9 +317,6 @@ export const createAndBroadcastTXFactory =
|
|
|
232
317
|
address = asset.address.P2SH2ToP2SH(address)
|
|
233
318
|
}
|
|
234
319
|
|
|
235
|
-
const rbfEnabled =
|
|
236
|
-
feeData.rbfEnabled && !isExchange && !isBip70 && isRbfAllowed && !nft && !brc20
|
|
237
|
-
|
|
238
320
|
let utxosToBump
|
|
239
321
|
if (bumpTxId) {
|
|
240
322
|
const bumpTx = replaceableTxs.find(({ txId }) => txId === bumpTxId)
|
|
@@ -250,7 +332,7 @@ export const createAndBroadcastTXFactory =
|
|
|
250
332
|
}
|
|
251
333
|
}
|
|
252
334
|
|
|
253
|
-
const sendAmount = bumpTxId || transferOrdinalsUtxos ? asset.currency.ZERO : amount
|
|
335
|
+
const sendAmount = bumpTxId || transferOrdinalsUtxos ? asset.currency.ZERO : amount
|
|
254
336
|
const receiveAddress = bumpTxId ? (replaceableTxs.length > 0 ? null : 'P2WPKH') : address
|
|
255
337
|
const feeRate = feeData.feePerKB
|
|
256
338
|
const resolvedIsSendAll = (!rbfEnabled && feePerKB) || transferOrdinalsUtxos ? false : isSendAll
|
|
@@ -301,18 +383,13 @@ export const createAndBroadcastTXFactory =
|
|
|
301
383
|
|
|
302
384
|
const addressPathsMap = selectedUtxos.getAddressPathsMap()
|
|
303
385
|
|
|
304
|
-
//
|
|
386
|
+
// Inputs and Outputs
|
|
305
387
|
const inputs = shuffle(createInputs(assetName, selectedUtxos.toArray(), rbfEnabled))
|
|
388
|
+
let outputs = replaceTx
|
|
389
|
+
? replaceTx.data.sent.map(({ address, amount }) => createOutput(assetName, address, amount))
|
|
390
|
+
: []
|
|
306
391
|
|
|
307
|
-
|
|
308
|
-
if (replaceTx) {
|
|
309
|
-
outputs = replaceTx.data.sent.map(({ address, amount }) =>
|
|
310
|
-
createOutput(assetName, address, amount)
|
|
311
|
-
)
|
|
312
|
-
} else {
|
|
313
|
-
outputs = []
|
|
314
|
-
}
|
|
315
|
-
|
|
392
|
+
// Send output
|
|
316
393
|
let sendOutput
|
|
317
394
|
if (address) {
|
|
318
395
|
if (transferOrdinalsUtxos) {
|
|
@@ -342,6 +419,7 @@ export const createAndBroadcastTXFactory =
|
|
|
342
419
|
ourAddress = Address.create(legacyAddress, ourAddress.meta)
|
|
343
420
|
}
|
|
344
421
|
|
|
422
|
+
// Change Output
|
|
345
423
|
let changeOutput
|
|
346
424
|
if (change.gte(dust)) {
|
|
347
425
|
changeOutput = createOutput(assetName, ourAddress.address ?? ourAddress.toString(), change)
|
|
@@ -355,31 +433,111 @@ export const createAndBroadcastTXFactory =
|
|
|
355
433
|
}
|
|
356
434
|
|
|
357
435
|
outputs = replaceTx ? outputs : shuffle(outputs)
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
436
|
+
|
|
437
|
+
const unsignedTx = await createUnsignedTx({
|
|
438
|
+
inputs,
|
|
439
|
+
outputs,
|
|
440
|
+
useCashAddress,
|
|
441
|
+
addressPathsMap,
|
|
442
|
+
blockHeight,
|
|
443
|
+
asset,
|
|
444
|
+
selectedUtxos,
|
|
445
|
+
insightClient,
|
|
446
|
+
})
|
|
447
|
+
return {
|
|
448
|
+
amount,
|
|
449
|
+
change,
|
|
450
|
+
totalAmount,
|
|
451
|
+
currentOrdinalsUtxos,
|
|
452
|
+
inscriptionIds,
|
|
453
|
+
address,
|
|
454
|
+
ourAddress,
|
|
455
|
+
receiveAddress,
|
|
456
|
+
sendAmount,
|
|
457
|
+
fee,
|
|
458
|
+
usableUtxos,
|
|
459
|
+
selectedUtxos,
|
|
460
|
+
transferOrdinalsUtxos,
|
|
461
|
+
replaceTx,
|
|
462
|
+
sendOutput,
|
|
463
|
+
changeOutput,
|
|
464
|
+
unsignedTx,
|
|
373
465
|
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// not ported from Exodus; but this demos signing / broadcasting
|
|
469
|
+
// NOTE: this will be ripped out in the coming weeks
|
|
470
|
+
export const createAndBroadcastTXFactory =
|
|
471
|
+
({
|
|
472
|
+
getFeeEstimator,
|
|
473
|
+
getSizeAndChangeScript = getSizeAndChangeScriptFactory(), // for decred customizations
|
|
474
|
+
allowUnconfirmedRbfEnabledUtxos,
|
|
475
|
+
ordinalsEnabled = false,
|
|
476
|
+
utxosDescendingOrder,
|
|
477
|
+
}) =>
|
|
478
|
+
async (
|
|
479
|
+
{ asset: maybeToken, walletAccount, address, amount: tokenAmount, options },
|
|
480
|
+
{ assetClientInterface }
|
|
481
|
+
) => {
|
|
482
|
+
// Prepare transaction
|
|
483
|
+
const { bumpTxId, nft, isExchange, isBip70, isRbfAllowed = true, feeOpts } = options
|
|
374
484
|
|
|
375
|
-
const
|
|
376
|
-
|
|
377
|
-
const
|
|
485
|
+
const asset = maybeToken.baseAsset
|
|
486
|
+
const assetName = asset.name
|
|
487
|
+
const feeData = await assetClientInterface.getFeeConfig({ assetName })
|
|
488
|
+
const accountState = await assetClientInterface.getAccountState({ assetName, walletAccount })
|
|
489
|
+
const insightClient = asset.baseAsset.insightClient
|
|
490
|
+
const isToken = maybeToken.name !== asset.name
|
|
491
|
+
const brc20 = options.brc20 || feeOpts?.brc20
|
|
492
|
+
|
|
493
|
+
const rbfEnabled =
|
|
494
|
+
feeData.rbfEnabled && !isExchange && !isBip70 && isRbfAllowed && !nft && !brc20
|
|
495
|
+
|
|
496
|
+
// blockHeight
|
|
497
|
+
const blockHeight = await getBlockHeight({ assetName, insightClient })
|
|
498
|
+
|
|
499
|
+
const transactionDescriptor = await getPrepareSendTransaction({
|
|
500
|
+
blockHeight,
|
|
501
|
+
ordinalsEnabled,
|
|
502
|
+
getFeeEstimator,
|
|
503
|
+
allowUnconfirmedRbfEnabledUtxos,
|
|
504
|
+
utxosDescendingOrder,
|
|
505
|
+
rbfEnabled,
|
|
506
|
+
})(
|
|
507
|
+
{ asset: maybeToken, walletAccount, address, amount: tokenAmount, options },
|
|
508
|
+
{ assetClientInterface }
|
|
509
|
+
)
|
|
510
|
+
const {
|
|
511
|
+
amount,
|
|
512
|
+
change,
|
|
513
|
+
totalAmount,
|
|
514
|
+
currentOrdinalsUtxos,
|
|
515
|
+
inscriptionIds,
|
|
516
|
+
ourAddress,
|
|
517
|
+
receiveAddress,
|
|
518
|
+
sendAmount,
|
|
519
|
+
fee,
|
|
520
|
+
usableUtxos,
|
|
521
|
+
selectedUtxos,
|
|
522
|
+
transferOrdinalsUtxos,
|
|
523
|
+
replaceTx,
|
|
524
|
+
sendOutput,
|
|
525
|
+
changeOutput,
|
|
526
|
+
unsignedTx,
|
|
527
|
+
} = transactionDescriptor
|
|
528
|
+
const outputs = unsignedTx.txData.outputs
|
|
529
|
+
|
|
530
|
+
address = transactionDescriptor.address
|
|
531
|
+
|
|
532
|
+
// Sign transaction
|
|
533
|
+
const { rawTx, txId, tx } = await signTransaction({
|
|
534
|
+
assetClientInterface,
|
|
378
535
|
assetName,
|
|
379
536
|
unsignedTx,
|
|
380
537
|
walletAccount,
|
|
381
538
|
})
|
|
382
539
|
|
|
540
|
+
// Broadcast transaction
|
|
383
541
|
const broadcastTxWithRetry = retry(
|
|
384
542
|
async (rawTx) => {
|
|
385
543
|
try {
|
|
@@ -8,7 +8,6 @@ import secp256k1 from 'secp256k1'
|
|
|
8
8
|
const ECPair = getECPair()
|
|
9
9
|
|
|
10
10
|
export const createGetKeyAndPurpose = ({
|
|
11
|
-
keys,
|
|
12
11
|
hdkeys,
|
|
13
12
|
resolvePurpose,
|
|
14
13
|
addressPathsMap,
|
|
@@ -22,7 +21,7 @@ export const createGetKeyAndPurpose = ({
|
|
|
22
21
|
return getPrivateKeyFromMap(privateKeysAddressMap, networkInfo, purpose, address)
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
return getPrivateKeyFromHDKeys(hdkeys, addressPathsMap,
|
|
24
|
+
return getPrivateKeyFromHDKeys(hdkeys, addressPathsMap, networkInfo, purpose, address)
|
|
26
25
|
})
|
|
27
26
|
|
|
28
27
|
function getPrivateKeyFromMap(privateKeysAddressMap, networkInfo, purpose, address) {
|
|
@@ -33,15 +32,14 @@ function getPrivateKeyFromMap(privateKeysAddressMap, networkInfo, purpose, addre
|
|
|
33
32
|
return { key, purpose, publicKey }
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
function getPrivateKeyFromHDKeys(hdkeys, addressPathsMap,
|
|
35
|
+
function getPrivateKeyFromHDKeys(hdkeys, addressPathsMap, networkInfo, purpose, address) {
|
|
37
36
|
const path = getOwnProperty(addressPathsMap, address, 'string')
|
|
38
37
|
assert(hdkeys, 'hdkeys must be provided')
|
|
39
38
|
assert(purpose, `purpose for address ${address} could not be resolved`)
|
|
40
39
|
const hdkey = hdkeys[purpose]
|
|
41
40
|
assert(hdkey, `hdkey for purpose for ${purpose} and address ${address} could not be resolved`)
|
|
42
41
|
const derivedhdkey = hdkey.derive(path)
|
|
43
|
-
const
|
|
44
|
-
const key = ECPair.fromWIF(privateEncoded, networkInfo)
|
|
42
|
+
const key = ECPair.fromPrivateKey(derivedhdkey.privateKey, { network: networkInfo })
|
|
45
43
|
const publicKey = derivedhdkey.publicKey
|
|
46
44
|
return { key, publicKey, purpose }
|
|
47
45
|
}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import { Transaction, payments } from '@exodus/bitcoinjs-lib'
|
|
2
2
|
|
|
3
|
-
import { getECPair } from '../bitcoinjs-lib'
|
|
4
3
|
import { toXOnly } from '../bitcoinjs-lib/ecc-utils'
|
|
5
4
|
import { createGetKeyAndPurpose } from './create-get-key-and-purpose'
|
|
6
|
-
import { toAsyncSigner
|
|
7
|
-
|
|
8
|
-
const ECPair = getECPair()
|
|
5
|
+
import { toAsyncSigner } from './taproot'
|
|
9
6
|
|
|
10
7
|
export function createSignWithWallet({
|
|
11
|
-
keys,
|
|
12
8
|
hdkeys,
|
|
13
9
|
resolvePurpose,
|
|
14
10
|
privateKeysAddressMap,
|
|
@@ -17,7 +13,6 @@ export function createSignWithWallet({
|
|
|
17
13
|
network,
|
|
18
14
|
}) {
|
|
19
15
|
const getKeyAndPurpose = createGetKeyAndPurpose({
|
|
20
|
-
keys,
|
|
21
16
|
hdkeys,
|
|
22
17
|
resolvePurpose,
|
|
23
18
|
privateKeysAddressMap,
|
|
@@ -70,8 +65,11 @@ export function createSignWithWallet({
|
|
|
70
65
|
}
|
|
71
66
|
|
|
72
67
|
// desktop / BE / mobile with bip-schnorr signing
|
|
73
|
-
|
|
74
|
-
|
|
68
|
+
await psbt.signInputAsync(
|
|
69
|
+
index,
|
|
70
|
+
toAsyncSigner({ keyPair: key, isTaprootAddress, network }),
|
|
71
|
+
allowedSigHashTypes
|
|
72
|
+
)
|
|
75
73
|
}
|
|
76
74
|
}
|
|
77
75
|
}
|
|
@@ -4,10 +4,9 @@ import { createPrepareForSigning } from './default-prepare-for-signing'
|
|
|
4
4
|
import { createSignWithWallet } from './create-sign-with-wallet'
|
|
5
5
|
import { extractTransaction } from './common'
|
|
6
6
|
|
|
7
|
-
export const signTxFactory = ({ assetName, resolvePurpose,
|
|
7
|
+
export const signTxFactory = ({ assetName, resolvePurpose, coinInfo, network }) => {
|
|
8
8
|
assert(assetName, 'assetName is required')
|
|
9
9
|
assert(resolvePurpose, 'resolvePurpose is required')
|
|
10
|
-
assert(keys, 'keys is required')
|
|
11
10
|
assert(coinInfo, 'coinInfo is required')
|
|
12
11
|
|
|
13
12
|
const prepareForSigning = createPrepareForSigning({
|
|
@@ -26,7 +25,6 @@ export const signTxFactory = ({ assetName, resolvePurpose, keys, coinInfo, netwo
|
|
|
26
25
|
|
|
27
26
|
const inputsToSign = unsignedTx.txMeta.inputsToSign || unsignedTx.txData.inputs
|
|
28
27
|
const signWithWallet = createSignWithWallet({
|
|
29
|
-
keys,
|
|
30
28
|
hdkeys,
|
|
31
29
|
resolvePurpose,
|
|
32
30
|
privateKeysAddressMap,
|
package/src/tx-sign/taproot.js
CHANGED
|
@@ -8,7 +8,7 @@ import { getECPair } from '../bitcoinjs-lib'
|
|
|
8
8
|
const ecc = eccFactory()
|
|
9
9
|
const ECPair = getECPair()
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
function tweakSigner({ signer, tweakHash, network }) {
|
|
12
12
|
assert(signer, 'signer is required')
|
|
13
13
|
|
|
14
14
|
let privateKey = signer.privateKey
|
|
@@ -40,8 +40,13 @@ function tapTweakHash(pubKey, h) {
|
|
|
40
40
|
/**
|
|
41
41
|
* Take a sync signer and make it async.
|
|
42
42
|
*/
|
|
43
|
-
export function toAsyncSigner({ keyPair }) {
|
|
43
|
+
export function toAsyncSigner({ keyPair, isTaprootAddress, network }) {
|
|
44
44
|
assert(keyPair, 'keyPair is required')
|
|
45
|
+
|
|
46
|
+
if (isTaprootAddress) {
|
|
47
|
+
keyPair = tweakSigner({ signer: keyPair, ECPair, network })
|
|
48
|
+
}
|
|
49
|
+
|
|
45
50
|
// eslint-disable-next-line @exodus/mutable/no-param-reassign-prop-only
|
|
46
51
|
keyPair.sign = async (h) => {
|
|
47
52
|
const sig = await ecc.signAsync(h, keyPair.privateKey)
|