@teleportdao/bitcoin 2.2.4 → 2.3.0-alpha.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/bitcoin-interface-utils.d.ts +4 -0
- package/dist/bitcoin-interface-utils.d.ts.map +1 -1
- package/dist/bitcoin-interface-utils.js +4 -0
- package/dist/bitcoin-interface-utils.js.map +1 -1
- package/dist/bitcoin-utils.d.ts +5 -1
- package/dist/bitcoin-utils.d.ts.map +1 -1
- package/dist/bitcoin-utils.js +44 -2
- package/dist/bitcoin-utils.js.map +1 -1
- package/dist/bitcoin-wallet-base copy.d.ts +122 -0
- package/dist/bitcoin-wallet-base copy.d.ts.map +1 -0
- package/dist/bitcoin-wallet-base copy.js +279 -0
- package/dist/bitcoin-wallet-base copy.js.map +1 -0
- package/dist/bitcoin-wallet-base.d.ts +18 -8
- package/dist/bitcoin-wallet-base.d.ts.map +1 -1
- package/dist/bitcoin-wallet-base.js +33 -13
- package/dist/bitcoin-wallet-base.js.map +1 -1
- package/dist/multisig-coordinator-wallet.d.ts +2 -0
- package/dist/multisig-coordinator-wallet.d.ts.map +1 -0
- package/dist/multisig-coordinator-wallet.js +6 -0
- package/dist/multisig-coordinator-wallet.js.map +1 -0
- package/dist/sign/sign-transaction.d.ts +5 -1
- package/dist/sign/sign-transaction.d.ts.map +1 -1
- package/dist/sign/sign-transaction.js +5 -2
- package/dist/sign/sign-transaction.js.map +1 -1
- package/dist/transaction-builder/transaction-builder.d.ts +26 -1
- package/dist/transaction-builder/transaction-builder.d.ts.map +1 -1
- package/dist/transaction-builder/transaction-builder.js +192 -110
- package/dist/transaction-builder/transaction-builder.js.map +1 -1
- package/package.json +3 -3
- package/src/bitcoin-interface-utils.ts +12 -0
- package/src/bitcoin-utils.ts +51 -2
- package/src/bitcoin-wallet-base.ts +62 -22
- package/src/multisig-coordinator-wallet.ts +9 -0
- package/src/sign/sign-transaction.ts +5 -7
- package/src/transaction-builder/transaction-builder.ts +264 -124
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
/* eslint-disable no-underscore-dangle */
|
|
3
3
|
import * as bitcoin from "bitcoinjs-lib"
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
createAddressObjectByPublicKey,
|
|
7
|
+
getAddressType,
|
|
8
|
+
createMultisigAddressObjectByPublicKeys,
|
|
9
|
+
} from "../bitcoin-utils"
|
|
6
10
|
|
|
7
11
|
const coinselect = require("coinselect")
|
|
8
12
|
const coinselectSplit = require("coinselect/split")
|
|
@@ -22,24 +26,30 @@ const coinselectAccumulative = require("coinselect/accumulative")
|
|
|
22
26
|
// p2wpkh: 35, // 31
|
|
23
27
|
// p2sh: 35, // 32
|
|
24
28
|
// p2tr: 45, // 43
|
|
29
|
+
// p2tr: 45, // 43
|
|
25
30
|
// default: 35,
|
|
26
31
|
// },
|
|
27
32
|
//
|
|
28
33
|
// }
|
|
34
|
+
|
|
35
|
+
const SINGLESIG_TYPES = ["p2pkh", "p2wpkh", "p2sh-p2wpkh", "p2tr"]
|
|
36
|
+
const MULTISIG_TYPES = ["p2sh", "p2wsh", "p2sh-p2wsh"]
|
|
37
|
+
|
|
29
38
|
export const componentBytes = {
|
|
30
39
|
bytePerInput: {
|
|
31
|
-
p2pkh:
|
|
32
|
-
p2wpkh:
|
|
33
|
-
"p2sh-p2wpkh": 91
|
|
34
|
-
p2tr:
|
|
40
|
+
p2pkh: 152, // 149
|
|
41
|
+
p2wpkh: 72, // 68
|
|
42
|
+
"p2sh-p2wpkh": 96, // 91
|
|
43
|
+
p2tr: 62, // 58
|
|
35
44
|
default: 100,
|
|
36
45
|
},
|
|
37
46
|
baseTxBytes: 10 + 5, // +5 extra bytes to be sure
|
|
38
47
|
bytePerOutput: {
|
|
39
|
-
p2pkh: 34, //
|
|
40
|
-
p2wpkh: 31, //
|
|
41
|
-
p2sh: 32, //
|
|
42
|
-
p2tr: 43, //
|
|
48
|
+
p2pkh: 34, // 33
|
|
49
|
+
p2wpkh: 31, // 30
|
|
50
|
+
p2sh: 32, // 31
|
|
51
|
+
p2tr: 43, // 42
|
|
52
|
+
p2wsh: 44, // 43
|
|
43
53
|
default: 35,
|
|
44
54
|
max: 45,
|
|
45
55
|
},
|
|
@@ -50,6 +60,76 @@ export const componentBytes = {
|
|
|
50
60
|
},
|
|
51
61
|
}
|
|
52
62
|
|
|
63
|
+
// P2SH | 46 + 74n + 34m
|
|
64
|
+
// P2SH-P2WSH | (306 + 76n + 34m) / 4
|
|
65
|
+
// P2WSH | (166 + 76n + 34m) / 4
|
|
66
|
+
|
|
67
|
+
export function getInputSize(
|
|
68
|
+
addressType: string,
|
|
69
|
+
details?: {
|
|
70
|
+
// op return or other script
|
|
71
|
+
script?: string
|
|
72
|
+
// n of m multisig
|
|
73
|
+
n?: number
|
|
74
|
+
m?: number
|
|
75
|
+
},
|
|
76
|
+
) {
|
|
77
|
+
let { m = 3 } = details || {}
|
|
78
|
+
const n = details?.n || m || 2
|
|
79
|
+
if (addressType === "p2sh") {
|
|
80
|
+
return 46 + 74 * n + 34 * m
|
|
81
|
+
}
|
|
82
|
+
if (addressType === "p2sh-p2wsh") {
|
|
83
|
+
return +((306 + 76 * n + 34 * m) / 4).toFixed()
|
|
84
|
+
}
|
|
85
|
+
if (addressType === "p2wsh") {
|
|
86
|
+
return +((166 + 76 * n + 34 * m) / 4).toFixed()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
componentBytes.bytePerInput[addressType as keyof typeof componentBytes.bytePerInput] ||
|
|
91
|
+
componentBytes.bytePerInput.default
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function getOutputSize(
|
|
96
|
+
output: {
|
|
97
|
+
addressType?: string
|
|
98
|
+
address?: string
|
|
99
|
+
script?: Buffer
|
|
100
|
+
},
|
|
101
|
+
// use network to decode address
|
|
102
|
+
network: bitcoin.Network = bitcoin.networks.bitcoin,
|
|
103
|
+
) {
|
|
104
|
+
if (output.addressType) {
|
|
105
|
+
return (
|
|
106
|
+
componentBytes.bytePerOutput[
|
|
107
|
+
output.addressType as keyof typeof componentBytes.bytePerOutput
|
|
108
|
+
] || componentBytes.bytePerOutput.default
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
if (output.address) {
|
|
112
|
+
let addressType = "max"
|
|
113
|
+
try {
|
|
114
|
+
addressType = getAddressType(output.address, network)
|
|
115
|
+
} catch {
|
|
116
|
+
addressType = "max"
|
|
117
|
+
}
|
|
118
|
+
return (
|
|
119
|
+
componentBytes.bytePerOutput[addressType as keyof typeof componentBytes.bytePerOutput] ||
|
|
120
|
+
componentBytes.bytePerOutput.max
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (output.script) {
|
|
125
|
+
if (output.script.byteLength < 255) {
|
|
126
|
+
return output.script.byteLength + componentBytes.scriptExtraBytes.lessThan255
|
|
127
|
+
}
|
|
128
|
+
return output.script.byteLength + componentBytes.scriptExtraBytes.moreThan255
|
|
129
|
+
}
|
|
130
|
+
throw new Error("invalid output")
|
|
131
|
+
}
|
|
132
|
+
|
|
53
133
|
export const DUST = 1000
|
|
54
134
|
|
|
55
135
|
export type Utxo = {
|
|
@@ -57,14 +137,21 @@ export type Utxo = {
|
|
|
57
137
|
value: number
|
|
58
138
|
index: number
|
|
59
139
|
}
|
|
140
|
+
|
|
60
141
|
export type SignerInfo = {
|
|
61
142
|
address: string
|
|
62
143
|
publicKey: string
|
|
63
144
|
addressType: string
|
|
145
|
+
|
|
146
|
+
//
|
|
147
|
+
publicKeys?: string[]
|
|
148
|
+
numberOfSigners?: number
|
|
149
|
+
|
|
64
150
|
derivationPath?: string
|
|
65
151
|
masterFingerprint?: string
|
|
66
152
|
includeHex?: boolean
|
|
67
153
|
}
|
|
154
|
+
|
|
68
155
|
export type ExtendedUtxo = {
|
|
69
156
|
signerInfo: SignerInfo
|
|
70
157
|
hash: string
|
|
@@ -102,6 +189,7 @@ export type BitcoinJSInputInfo = ExtendedUtxo & {
|
|
|
102
189
|
value: number
|
|
103
190
|
}
|
|
104
191
|
redeemScript?: Buffer
|
|
192
|
+
witnessScript?: Buffer
|
|
105
193
|
tapInternalKey?: Buffer
|
|
106
194
|
}
|
|
107
195
|
|
|
@@ -135,6 +223,8 @@ function coinSelectInOrder(
|
|
|
135
223
|
}
|
|
136
224
|
|
|
137
225
|
export abstract class BaseTransactionBuilder {
|
|
226
|
+
MULTISIG_TYPES = MULTISIG_TYPES
|
|
227
|
+
|
|
138
228
|
testnet: boolean
|
|
139
229
|
network: bitcoin.Network
|
|
140
230
|
maximumNumberOfOutputsInTransaction: number
|
|
@@ -161,11 +251,25 @@ export abstract class BaseTransactionBuilder {
|
|
|
161
251
|
this.dustLimit = dustLimit || 1 * 2 * componentBytes.bytePerInput.p2pkh
|
|
162
252
|
}
|
|
163
253
|
|
|
254
|
+
isMultiSig(addressType: string) {
|
|
255
|
+
return this.MULTISIG_TYPES.includes(addressType)
|
|
256
|
+
}
|
|
257
|
+
|
|
164
258
|
// eslint-disable-next-line no-unused-vars, class-methods-use-this
|
|
165
259
|
abstract _getTransactionHex(transactionId: string): Promise<string>
|
|
166
260
|
|
|
167
261
|
// eslint-disable-next-line no-unused-vars, class-methods-use-this
|
|
168
|
-
createAddressObject(input: {
|
|
262
|
+
createAddressObject(input: {
|
|
263
|
+
addressType: string
|
|
264
|
+
publicKey: Buffer
|
|
265
|
+
publicKeys?: Buffer[]
|
|
266
|
+
numberOfSigners?: number
|
|
267
|
+
}) {
|
|
268
|
+
if (this.MULTISIG_TYPES.includes(input.addressType))
|
|
269
|
+
return createMultisigAddressObjectByPublicKeys(input.addressType, {
|
|
270
|
+
publicKeys: input.publicKeys!,
|
|
271
|
+
numberOfSigners: input.numberOfSigners,
|
|
272
|
+
})
|
|
169
273
|
return createAddressObjectByPublicKey(input, this.network)
|
|
170
274
|
}
|
|
171
275
|
|
|
@@ -192,7 +296,12 @@ export abstract class BaseTransactionBuilder {
|
|
|
192
296
|
}
|
|
193
297
|
|
|
194
298
|
calculateTxSize(
|
|
195
|
-
inputTypes:
|
|
299
|
+
inputTypes: {
|
|
300
|
+
addressType: string
|
|
301
|
+
n?: number
|
|
302
|
+
m?: number
|
|
303
|
+
script?: string
|
|
304
|
+
}[],
|
|
196
305
|
outputs: {
|
|
197
306
|
script?: Buffer
|
|
198
307
|
address?: string
|
|
@@ -200,33 +309,19 @@ export abstract class BaseTransactionBuilder {
|
|
|
200
309
|
}[],
|
|
201
310
|
changeAddressType = "default",
|
|
202
311
|
) {
|
|
203
|
-
const inputsSizes = inputTypes.map(
|
|
204
|
-
(addressType)
|
|
205
|
-
componentBytes.bytePerInput[addressType as keyof typeof componentBytes.bytePerInput],
|
|
312
|
+
const inputsSizes = inputTypes.map(({ addressType, n, m }) =>
|
|
313
|
+
getInputSize(addressType, { n, m }),
|
|
206
314
|
)
|
|
207
315
|
const outputSizes = outputs.map((outP: any) => {
|
|
208
|
-
if (outP.address) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
return componentBytes.bytePerOutput[
|
|
216
|
-
addressType as keyof typeof componentBytes.bytePerOutput
|
|
217
|
-
]
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (outP.script) {
|
|
221
|
-
if (outP.script.byteLength < 255) {
|
|
222
|
-
return outP.script.byteLength + componentBytes.scriptExtraBytes.lessThan255
|
|
223
|
-
}
|
|
224
|
-
return outP.script.byteLength + componentBytes.scriptExtraBytes.moreThan255
|
|
316
|
+
if (!outP.address && !outP.script) {
|
|
317
|
+
return getOutputSize(
|
|
318
|
+
{
|
|
319
|
+
addressType: changeAddressType,
|
|
320
|
+
},
|
|
321
|
+
this.network,
|
|
322
|
+
)
|
|
225
323
|
}
|
|
226
|
-
|
|
227
|
-
return componentBytes.bytePerOutput[
|
|
228
|
-
changeAddressType as keyof typeof componentBytes.bytePerOutput
|
|
229
|
-
]
|
|
324
|
+
return getOutputSize(outP, this.network)
|
|
230
325
|
})
|
|
231
326
|
|
|
232
327
|
const txSize: number =
|
|
@@ -260,9 +355,10 @@ export abstract class BaseTransactionBuilder {
|
|
|
260
355
|
(u) =>
|
|
261
356
|
u.value >
|
|
262
357
|
+feeRate *
|
|
263
|
-
|
|
264
|
-
u.signerInfo.
|
|
265
|
-
|
|
358
|
+
getInputSize(u.signerInfo.addressType, {
|
|
359
|
+
m: u.signerInfo.publicKeys?.length,
|
|
360
|
+
n: u.signerInfo.numberOfSigners,
|
|
361
|
+
}),
|
|
266
362
|
)
|
|
267
363
|
let selectResponse
|
|
268
364
|
switch (selectType) {
|
|
@@ -316,13 +412,17 @@ export abstract class BaseTransactionBuilder {
|
|
|
316
412
|
changeAddressType = "default"
|
|
317
413
|
}
|
|
318
414
|
|
|
319
|
-
const txSize =
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
)
|
|
415
|
+
const txSize = this.calculateTxSize(
|
|
416
|
+
inputs.map((i) => ({
|
|
417
|
+
addressType: i.signerInfo.addressType,
|
|
418
|
+
m: i.signerInfo.publicKeys?.length,
|
|
419
|
+
n: i.signerInfo.numberOfSigners,
|
|
420
|
+
})),
|
|
421
|
+
outputs,
|
|
422
|
+
changeAddressType,
|
|
423
|
+
)
|
|
325
424
|
|
|
425
|
+
let extraChangeFee = Math.round(componentBytes.bytePerOutput.default * feeRate)
|
|
326
426
|
let txFee = Math.round(txSize * feeRate)
|
|
327
427
|
if (Math.round(feeRate) === 1) {
|
|
328
428
|
txFee = Math.round(txFee + txFee * 0.1)
|
|
@@ -330,7 +430,8 @@ export abstract class BaseTransactionBuilder {
|
|
|
330
430
|
if (
|
|
331
431
|
inputs.reduce((a, b) => a + b.value, 0) -
|
|
332
432
|
outputs.filter((o) => o.address || o.script).reduce((a, b) => a + b.value, 0) -
|
|
333
|
-
txFee
|
|
433
|
+
txFee -
|
|
434
|
+
extraChangeFee <
|
|
334
435
|
0
|
|
335
436
|
) {
|
|
336
437
|
let spendableBalance = inputs.reduce((a, b) => a + b.value, 0)
|
|
@@ -346,35 +447,58 @@ export abstract class BaseTransactionBuilder {
|
|
|
346
447
|
)}`,
|
|
347
448
|
)
|
|
348
449
|
}
|
|
450
|
+
|
|
349
451
|
let diff = fee - txFee
|
|
350
452
|
let changeIndex = outputs.findIndex((x) => !x?.address && !x.script && (x.value || 0) > 0)
|
|
351
453
|
let change: ChangeTarget | undefined
|
|
352
|
-
if (changeIndex >= 0 || diff > DUST) {
|
|
353
|
-
if (changeIndex >= 0) {
|
|
354
|
-
diff = diff + componentBytes.bytePerOutput.default * Math.round(feeRate)
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (diff < 0) {
|
|
358
|
-
diff = 0
|
|
359
|
-
}
|
|
360
454
|
|
|
455
|
+
if (diff > 0) {
|
|
361
456
|
if (selectType === "full") {
|
|
362
457
|
outputs[0].value = outputs[0].value + diff
|
|
363
458
|
fee = fee - diff
|
|
364
|
-
} else {
|
|
459
|
+
} else if (changeIndex >= 0) {
|
|
365
460
|
if (!changeObject) throw new Error("change not exist")
|
|
366
461
|
change = {
|
|
367
462
|
address: changeObject.address,
|
|
368
|
-
value:
|
|
463
|
+
value: outputs[changeIndex].value + diff,
|
|
369
464
|
}
|
|
370
465
|
fee = fee - diff
|
|
466
|
+
} else if (diff - extraChangeFee > DUST) {
|
|
467
|
+
if (!changeObject) throw new Error("change not exist")
|
|
468
|
+
change = {
|
|
469
|
+
address: changeObject.address,
|
|
470
|
+
value: diff - extraChangeFee,
|
|
471
|
+
}
|
|
472
|
+
fee = fee - diff + extraChangeFee
|
|
371
473
|
}
|
|
474
|
+
} else if (-1 * diff > 0) {
|
|
475
|
+
const positiveDiff = -1 * diff
|
|
372
476
|
|
|
373
|
-
if
|
|
374
|
-
|
|
477
|
+
// if we don't have change we should consider extra ChangeFee
|
|
478
|
+
let currentChangeValue = changeIndex > 0 ? outputs[changeIndex].value : -1 * extraChangeFee
|
|
479
|
+
if (currentChangeValue - positiveDiff < -1 * DUST) {
|
|
480
|
+
throw new Error(`not enough balance.`) // it should no happen
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (changeIndex > 0) {
|
|
484
|
+
if (!changeObject) throw new Error("change not exist")
|
|
485
|
+
change =
|
|
486
|
+
outputs[changeIndex].value - positiveDiff > DUST
|
|
487
|
+
? {
|
|
488
|
+
address: changeObject.address,
|
|
489
|
+
value: outputs[changeIndex].value - positiveDiff,
|
|
490
|
+
}
|
|
491
|
+
: undefined
|
|
492
|
+
fee = fee + positiveDiff
|
|
375
493
|
}
|
|
376
494
|
}
|
|
377
495
|
|
|
496
|
+
if (changeIndex >= 0) {
|
|
497
|
+
outputs.splice(changeIndex, 1)
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
console.log(fee, outputs, change)
|
|
501
|
+
|
|
378
502
|
return {
|
|
379
503
|
inputs,
|
|
380
504
|
fee,
|
|
@@ -433,11 +557,21 @@ export abstract class BaseTransactionBuilder {
|
|
|
433
557
|
})[] = baseInputs
|
|
434
558
|
const transactionHex: { [key: string]: string } = {}
|
|
435
559
|
for (let i in inputs) {
|
|
436
|
-
let {
|
|
437
|
-
|
|
560
|
+
let {
|
|
561
|
+
address,
|
|
562
|
+
publicKey,
|
|
563
|
+
derivationPath,
|
|
564
|
+
masterFingerprint,
|
|
565
|
+
addressType,
|
|
566
|
+
publicKeys,
|
|
567
|
+
numberOfSigners,
|
|
568
|
+
} = inputs[i].signerInfo
|
|
438
569
|
// todo : support without publicKey
|
|
570
|
+
|
|
439
571
|
let addressObject = this.createAddressObject({
|
|
440
572
|
publicKey: Buffer.from(publicKey, "hex"),
|
|
573
|
+
publicKeys: publicKeys?.map((p) => Buffer.from(p, "hex")),
|
|
574
|
+
numberOfSigners,
|
|
441
575
|
addressType,
|
|
442
576
|
})
|
|
443
577
|
if (derivationPath && masterFingerprint && addressObject.pubkey) {
|
|
@@ -475,7 +609,8 @@ export abstract class BaseTransactionBuilder {
|
|
|
475
609
|
script: addressObject.output,
|
|
476
610
|
value: inputs[i].value,
|
|
477
611
|
}
|
|
478
|
-
if (!addressObject?.redeem?.output)
|
|
612
|
+
if (!addressObject?.redeem?.output)
|
|
613
|
+
throw new Error("invalid signer info for p2sh-p2wpkh address")
|
|
479
614
|
inputs[i].redeemScript = addressObject.redeem.output
|
|
480
615
|
|
|
481
616
|
if (inputs[i].signerInfo.includeHex) {
|
|
@@ -493,6 +628,51 @@ export abstract class BaseTransactionBuilder {
|
|
|
493
628
|
if (!addressObject.pubkey) throw new Error("invalid signer info for p2tr address (pubkey)")
|
|
494
629
|
inputs[i].tapInternalKey = addressObject.internalPubkey
|
|
495
630
|
|
|
631
|
+
if (inputs[i].signerInfo.includeHex) {
|
|
632
|
+
const txHex =
|
|
633
|
+
transactionHex[inputs[i].hash] || (await this._getTransactionHex(inputs[i].hash))
|
|
634
|
+
transactionHex[inputs[i].hash] = txHex
|
|
635
|
+
inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex")
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
// multisig
|
|
639
|
+
else if (addressType === "p2sh") {
|
|
640
|
+
const txHex =
|
|
641
|
+
transactionHex[inputs[i].hash] || (await this._getTransactionHex(inputs[i].hash))
|
|
642
|
+
transactionHex[inputs[i].hash] = txHex
|
|
643
|
+
inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex")
|
|
644
|
+
|
|
645
|
+
if (!addressObject.output) throw new Error("invalid signer info")
|
|
646
|
+
if (!addressObject?.redeem?.output) throw new Error("invalid signer info for p2sh address")
|
|
647
|
+
inputs[i].redeemScript = addressObject.redeem.output
|
|
648
|
+
} else if (addressType === "p2wsh") {
|
|
649
|
+
if (!addressObject.output) throw new Error("invalid signer info")
|
|
650
|
+
inputs[i].witnessUtxo = {
|
|
651
|
+
script: addressObject.output,
|
|
652
|
+
value: inputs[i].value,
|
|
653
|
+
}
|
|
654
|
+
if (!addressObject?.redeem?.output) throw new Error("invalid signer info for p2wsh address")
|
|
655
|
+
inputs[i].witnessScript = addressObject.redeem?.output
|
|
656
|
+
|
|
657
|
+
if (inputs[i].signerInfo.includeHex) {
|
|
658
|
+
const txHex =
|
|
659
|
+
transactionHex[inputs[i].hash] || (await this._getTransactionHex(inputs[i].hash))
|
|
660
|
+
transactionHex[inputs[i].hash] = txHex
|
|
661
|
+
inputs[i].nonWitnessUtxo = Buffer.from(txHex, "hex")
|
|
662
|
+
}
|
|
663
|
+
} else if (addressType === "p2sh-p2wsh") {
|
|
664
|
+
if (!addressObject.output) throw new Error("invalid signer info")
|
|
665
|
+
inputs[i].witnessUtxo = {
|
|
666
|
+
script: addressObject.output,
|
|
667
|
+
value: inputs[i].value,
|
|
668
|
+
}
|
|
669
|
+
if (!addressObject?.redeem?.output) throw new Error("invalid signer info for p2sh address")
|
|
670
|
+
inputs[i].redeemScript = addressObject.redeem.output
|
|
671
|
+
|
|
672
|
+
if (!addressObject?.redeem?.redeem?.output)
|
|
673
|
+
throw new Error("invalid signer info for p2sh-p2wsh address")
|
|
674
|
+
inputs[i].witnessScript = addressObject.redeem.redeem.output
|
|
675
|
+
|
|
496
676
|
if (inputs[i].signerInfo.includeHex) {
|
|
497
677
|
const txHex =
|
|
498
678
|
transactionHex[inputs[i].hash] || (await this._getTransactionHex(inputs[i].hash))
|
|
@@ -525,70 +705,29 @@ export abstract class BaseTransactionBuilder {
|
|
|
525
705
|
newPsbt.setMaximumFeeRate(+(feeRate + feeRate / 100).toFixed())
|
|
526
706
|
// add input
|
|
527
707
|
for (const input of inputs) {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
break
|
|
541
|
-
}
|
|
542
|
-
case "p2wpkh": {
|
|
543
|
-
let i = {
|
|
544
|
-
hash: input.hash,
|
|
545
|
-
index: Number(input.index),
|
|
546
|
-
witnessUtxo: input.witnessUtxo,
|
|
547
|
-
// we dont need nonWitnessUtxo. bud some application force nonWitnessUtxo
|
|
548
|
-
nonWitnessUtxo: input.nonWitnessUtxo,
|
|
549
|
-
sequence,
|
|
550
|
-
bip32Derivation: input.bip32Derivation,
|
|
551
|
-
}
|
|
552
|
-
if (!i.bip32Derivation) delete i.bip32Derivation
|
|
553
|
-
if (!i.nonWitnessUtxo) delete i.nonWitnessUtxo
|
|
554
|
-
newPsbt.addInput(i)
|
|
555
|
-
break
|
|
556
|
-
}
|
|
557
|
-
case "p2sh-p2wpkh": {
|
|
558
|
-
let i = {
|
|
559
|
-
hash: input.hash,
|
|
560
|
-
index: Number(input.index),
|
|
561
|
-
witnessUtxo: input.witnessUtxo,
|
|
562
|
-
// we dont need nonWitnessUtxo. bud some application force nonWitnessUtxo
|
|
563
|
-
nonWitnessUtxo: input.nonWitnessUtxo,
|
|
564
|
-
redeemScript: input.redeemScript,
|
|
565
|
-
sequence,
|
|
566
|
-
bip32Derivation: input.bip32Derivation,
|
|
567
|
-
}
|
|
568
|
-
if (!i.bip32Derivation) delete i.bip32Derivation
|
|
569
|
-
if (!i.nonWitnessUtxo) delete i.nonWitnessUtxo
|
|
570
|
-
newPsbt.addInput(i)
|
|
571
|
-
break
|
|
572
|
-
}
|
|
573
|
-
case "p2tr": {
|
|
574
|
-
let i = {
|
|
575
|
-
hash: input.hash,
|
|
576
|
-
index: Number(input.index),
|
|
577
|
-
witnessUtxo: input.witnessUtxo,
|
|
578
|
-
// we dont need nonWitnessUtxo. bud some application force nonWitnessUtxo
|
|
579
|
-
nonWitnessUtxo: input.nonWitnessUtxo,
|
|
580
|
-
tapInternalKey: input.tapInternalKey,
|
|
581
|
-
sequence,
|
|
582
|
-
bip32Derivation: input.bip32Derivation,
|
|
583
|
-
}
|
|
584
|
-
if (!i.bip32Derivation) delete i.bip32Derivation
|
|
585
|
-
if (!i.nonWitnessUtxo) delete i.nonWitnessUtxo
|
|
586
|
-
newPsbt.addInput(i)
|
|
587
|
-
break
|
|
588
|
-
}
|
|
589
|
-
default:
|
|
590
|
-
throw new Error("address type is incorrect")
|
|
708
|
+
const i = {
|
|
709
|
+
hash: input.hash,
|
|
710
|
+
index: +input.index,
|
|
711
|
+
witnessUtxo: input.witnessUtxo,
|
|
712
|
+
nonWitnessUtxo: input.nonWitnessUtxo,
|
|
713
|
+
redeemScript: input.redeemScript,
|
|
714
|
+
sequence,
|
|
715
|
+
bip32Derivation: input.bip32Derivation,
|
|
716
|
+
// multisig
|
|
717
|
+
witnessScript: input.witnessScript,
|
|
718
|
+
// taproot
|
|
719
|
+
tapInternalKey: input.tapInternalKey,
|
|
591
720
|
}
|
|
721
|
+
|
|
722
|
+
if (!i.bip32Derivation) delete i.bip32Derivation
|
|
723
|
+
if (!i.nonWitnessUtxo) delete i.nonWitnessUtxo
|
|
724
|
+
if (!i.witnessUtxo) delete i.witnessUtxo
|
|
725
|
+
if (!i.redeemScript) delete i.redeemScript
|
|
726
|
+
if (!i.witnessScript) delete i.witnessScript
|
|
727
|
+
if (!i.tapInternalKey) delete i.tapInternalKey
|
|
728
|
+
|
|
729
|
+
newPsbt.addInput(i)
|
|
730
|
+
// console.log(i)
|
|
592
731
|
}
|
|
593
732
|
|
|
594
733
|
// add outputs
|
|
@@ -613,7 +752,7 @@ export abstract class BaseTransactionBuilder {
|
|
|
613
752
|
|
|
614
753
|
const unsignedPsbtBaseText = newPsbt.toBase64()
|
|
615
754
|
|
|
616
|
-
const safeAddressTypeForPossibleTxId = ["p2wpkh", "p2tr"]
|
|
755
|
+
const safeAddressTypeForPossibleTxId = ["p2wpkh", "p2tr", "p2wsh"]
|
|
617
756
|
const isPossibleTxId = inputs.reduce(
|
|
618
757
|
(a, b) => a && safeAddressTypeForPossibleTxId.includes(b.signerInfo.addressType),
|
|
619
758
|
true,
|
|
@@ -681,6 +820,7 @@ export abstract class BaseTransactionBuilder {
|
|
|
681
820
|
let psbt = bitcoin.Psbt.fromBase64(unsignedPsbt, {
|
|
682
821
|
network: this.network,
|
|
683
822
|
})
|
|
823
|
+
|
|
684
824
|
return (psbt as any).__CACHE.__TX.getId()
|
|
685
825
|
}
|
|
686
826
|
}
|