@scure/btc-signer 1.8.0 → 2.0.0-beta.1
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/README.md +15 -12
- package/_type_test.js +10 -12
- package/_type_test.js.map +1 -1
- package/index.js +17 -61
- package/index.js.map +1 -1
- package/musig2.d.ts +2 -2
- package/musig2.d.ts.map +1 -1
- package/musig2.js +93 -91
- package/musig2.js.map +1 -1
- package/p2p.d.ts +7 -8
- package/p2p.d.ts.map +1 -1
- package/p2p.js +32 -38
- package/p2p.js.map +1 -1
- package/package.json +33 -70
- package/payment.js +73 -96
- package/payment.js.map +1 -1
- package/psbt.d.ts +224 -224
- package/psbt.d.ts.map +1 -1
- package/psbt.js +58 -63
- package/psbt.js.map +1 -1
- package/script.d.ts +125 -120
- package/script.d.ts.map +1 -1
- package/script.js +46 -146
- package/script.js.map +1 -1
- package/src/_type_test.ts +2 -2
- package/src/musig2.ts +45 -53
- package/src/p2p.ts +31 -43
- package/src/psbt.ts +7 -7
- package/src/script.ts +29 -26
- package/src/transaction.ts +31 -24
- package/src/utils.ts +45 -26
- package/src/utxo.ts +1 -1
- package/transaction.d.ts +23 -28
- package/transaction.d.ts.map +1 -1
- package/transaction.js +140 -154
- package/transaction.js.map +1 -1
- package/utils.d.ts +13 -7
- package/utils.d.ts.map +1 -1
- package/utils.js +60 -62
- package/utils.js.map +1 -1
- package/utxo.d.ts +45 -45
- package/utxo.d.ts.map +1 -1
- package/utxo.js +63 -59
- package/utxo.js.map +1 -1
- package/esm/_type_test.d.ts +0 -2
- package/esm/_type_test.d.ts.map +0 -1
- package/esm/_type_test.js +0 -57
- package/esm/_type_test.js.map +0 -1
- package/esm/index.d.ts +0 -22
- package/esm/index.d.ts.map +0 -1
- package/esm/index.js +0 -22
- package/esm/index.js.map +0 -1
- package/esm/musig2.d.ts +0 -148
- package/esm/musig2.d.ts.map +0 -1
- package/esm/musig2.js +0 -405
- package/esm/musig2.js.map +0 -1
- package/esm/p2p.d.ts +0 -38
- package/esm/p2p.d.ts.map +0 -1
- package/esm/p2p.js +0 -156
- package/esm/p2p.js.map +0 -1
- package/esm/package.json +0 -1
- package/esm/payment.d.ts +0 -200
- package/esm/payment.d.ts.map +0 -1
- package/esm/payment.js +0 -697
- package/esm/payment.js.map +0 -1
- package/esm/psbt.d.ts +0 -820
- package/esm/psbt.d.ts.map +0 -1
- package/esm/psbt.js +0 -409
- package/esm/psbt.js.map +0 -1
- package/esm/script.d.ts +0 -170
- package/esm/script.d.ts.map +0 -1
- package/esm/script.js +0 -356
- package/esm/script.js.map +0 -1
- package/esm/transaction.d.ts +0 -171
- package/esm/transaction.d.ts.map +0 -1
- package/esm/transaction.js +0 -1182
- package/esm/transaction.js.map +0 -1
- package/esm/utils.d.ts +0 -35
- package/esm/utils.d.ts.map +0 -1
- package/esm/utils.js +0 -118
- package/esm/utils.js.map +0 -1
- package/esm/utxo.d.ts +0 -198
- package/esm/utxo.d.ts.map +0 -1
- package/esm/utxo.js +0 -461
- package/esm/utxo.js.map +0 -1
- package/src/package.json +0 -3
package/transaction.js
CHANGED
|
@@ -1,40 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
exports.getInputType = getInputType;
|
|
9
|
-
exports.PSBTCombine = PSBTCombine;
|
|
10
|
-
exports.bip32Path = bip32Path;
|
|
11
|
-
const base_1 = require("@scure/base");
|
|
12
|
-
const P = require("micro-packed");
|
|
13
|
-
const payment_ts_1 = require("./payment.js");
|
|
14
|
-
const psbt = require("./psbt.js");
|
|
15
|
-
const script_ts_1 = require("./script.js");
|
|
16
|
-
const u = require("./utils.js");
|
|
17
|
-
const utils_ts_1 = require("./utils.js");
|
|
1
|
+
import { hex } from '@scure/base';
|
|
2
|
+
import * as P from 'micro-packed';
|
|
3
|
+
import { Address, OutScript, checkScript, tapLeafHash } from "./payment.js";
|
|
4
|
+
import * as psbt from "./psbt.js";
|
|
5
|
+
import { CompactSizeLen, RawOldTx, RawOutput, RawTx, RawWitness, Script, VarBytes, } from "./script.js";
|
|
6
|
+
import * as u from "./utils.js";
|
|
7
|
+
import { NETWORK, concatBytes, equalBytes, isBytes } from "./utils.js";
|
|
18
8
|
const EMPTY32 = new Uint8Array(32);
|
|
19
9
|
const EMPTY_OUTPUT = {
|
|
20
10
|
amount: 0xffffffffffffffffn,
|
|
21
11
|
script: P.EMPTY,
|
|
22
12
|
};
|
|
23
|
-
const toVsize = (weight) => Math.ceil(weight / 4);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
exports.Decimal = P.coders.decimal(exports.PRECISION);
|
|
13
|
+
export const toVsize = (weight) => Math.ceil(weight / 4);
|
|
14
|
+
export const PRECISION = 8;
|
|
15
|
+
export const DEFAULT_VERSION = 2;
|
|
16
|
+
export const DEFAULT_LOCKTIME = 0;
|
|
17
|
+
export const DEFAULT_SEQUENCE = 4294967295;
|
|
18
|
+
export const Decimal = P.coders.decimal(PRECISION);
|
|
30
19
|
// Same as value || def, but doesn't overwrites zero ('0', 0, 0n, etc)
|
|
31
|
-
const def = (value, def) => (value === undefined ? def : value);
|
|
32
|
-
|
|
33
|
-
function cloneDeep(obj) {
|
|
20
|
+
export const def = (value, def) => (value === undefined ? def : value);
|
|
21
|
+
export function cloneDeep(obj) {
|
|
34
22
|
if (Array.isArray(obj))
|
|
35
23
|
return obj.map((i) => cloneDeep(i));
|
|
36
24
|
// slice of nodejs Buffer doesn't copy
|
|
37
|
-
else if (
|
|
25
|
+
else if (isBytes(obj))
|
|
38
26
|
return Uint8Array.from(obj);
|
|
39
27
|
// immutable
|
|
40
28
|
else if (['number', 'bigint', 'boolean', 'string', 'undefined'].includes(typeof obj))
|
|
@@ -52,27 +40,26 @@ function cloneDeep(obj) {
|
|
|
52
40
|
* Internal, exported only for backwards-compat. Use `SigHash` instead.
|
|
53
41
|
* @deprecated
|
|
54
42
|
*/
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
})(SigHash || (exports.SigHash = SigHash = {}));
|
|
43
|
+
export const SignatureHash = {
|
|
44
|
+
DEFAULT: 0,
|
|
45
|
+
ALL: 1,
|
|
46
|
+
NONE: 2,
|
|
47
|
+
SINGLE: 3,
|
|
48
|
+
ANYONECANPAY: 0x80,
|
|
49
|
+
};
|
|
50
|
+
export const SigHash = {
|
|
51
|
+
DEFAULT: SignatureHash.DEFAULT,
|
|
52
|
+
ALL: SignatureHash.ALL,
|
|
53
|
+
NONE: SignatureHash.NONE,
|
|
54
|
+
SINGLE: SignatureHash.SINGLE,
|
|
55
|
+
DEFAULT_ANYONECANPAY: SignatureHash.DEFAULT | SignatureHash.ANYONECANPAY,
|
|
56
|
+
ALL_ANYONECANPAY: SignatureHash.ALL | SignatureHash.ANYONECANPAY,
|
|
57
|
+
NONE_ANYONECANPAY: SignatureHash.NONE | SignatureHash.ANYONECANPAY,
|
|
58
|
+
SINGLE_ANYONECANPAY: SignatureHash.SINGLE | SignatureHash.ANYONECANPAY,
|
|
59
|
+
};
|
|
60
|
+
export const SigHashNames = u.reverseObject(SigHash);
|
|
74
61
|
function getTaprootKeys(privKey, pubKey, internalKey, merkleRoot = P.EMPTY) {
|
|
75
|
-
if (
|
|
62
|
+
if (equalBytes(internalKey, pubKey)) {
|
|
76
63
|
privKey = u.taprootTweakPrivKey(privKey, merkleRoot);
|
|
77
64
|
pubKey = u.pubSchnorr(privKey);
|
|
78
65
|
}
|
|
@@ -85,14 +72,14 @@ function outputBeforeSign(i) {
|
|
|
85
72
|
return { script: i.script, amount: i.amount };
|
|
86
73
|
}
|
|
87
74
|
// Force check index/txid/sequence
|
|
88
|
-
function inputBeforeSign(i) {
|
|
75
|
+
export function inputBeforeSign(i) {
|
|
89
76
|
if (i.txid === undefined || i.index === undefined)
|
|
90
77
|
throw new Error('Transaction/input: txid and index required');
|
|
91
78
|
return {
|
|
92
79
|
txid: i.txid,
|
|
93
80
|
index: i.index,
|
|
94
|
-
sequence:
|
|
95
|
-
finalScriptSig:
|
|
81
|
+
sequence: def(i.sequence, DEFAULT_SEQUENCE),
|
|
82
|
+
finalScriptSig: def(i.finalScriptSig, P.EMPTY),
|
|
96
83
|
};
|
|
97
84
|
}
|
|
98
85
|
function cleanFinalInput(i) {
|
|
@@ -105,7 +92,7 @@ function cleanFinalInput(i) {
|
|
|
105
92
|
// (TxHash, Idx)
|
|
106
93
|
const TxHashIdx = P.struct({ txid: P.bytes(32, true), index: P.U32LE });
|
|
107
94
|
function validateSigHash(s) {
|
|
108
|
-
if (typeof s !== 'number' || typeof
|
|
95
|
+
if (typeof s !== 'number' || typeof SigHashNames[s] !== 'string')
|
|
109
96
|
throw new Error(`Invalid SigHash=${s}`);
|
|
110
97
|
return s;
|
|
111
98
|
}
|
|
@@ -123,17 +110,14 @@ function validateOpts(opts) {
|
|
|
123
110
|
const _opts = {
|
|
124
111
|
...opts,
|
|
125
112
|
// Defaults
|
|
126
|
-
version:
|
|
127
|
-
lockTime:
|
|
128
|
-
PSBTVersion:
|
|
113
|
+
version: def(opts.version, DEFAULT_VERSION),
|
|
114
|
+
lockTime: def(opts.lockTime, 0),
|
|
115
|
+
PSBTVersion: def(opts.PSBTVersion, 0),
|
|
129
116
|
};
|
|
130
117
|
if (typeof _opts.allowUnknowInput !== 'undefined')
|
|
131
118
|
opts.allowUnknownInputs = _opts.allowUnknowInput;
|
|
132
119
|
if (typeof _opts.allowUnknowOutput !== 'undefined')
|
|
133
120
|
opts.allowUnknownOutputs = _opts.allowUnknowOutput;
|
|
134
|
-
// 0 and -1 happens in tests
|
|
135
|
-
if (![-1, 0, 1, 2, 3].includes(_opts.version))
|
|
136
|
-
throw new Error(`Unknown version: ${_opts.version}`);
|
|
137
121
|
if (typeof _opts.lockTime !== 'number')
|
|
138
122
|
throw new Error('Transaction lock time should be number');
|
|
139
123
|
P.U32LE.encode(_opts.lockTime); // Additional range checks that lockTime
|
|
@@ -143,6 +127,7 @@ function validateOpts(opts) {
|
|
|
143
127
|
throw new Error(`Unknown PSBT version ${_opts.PSBTVersion}`);
|
|
144
128
|
// Flags
|
|
145
129
|
for (const k of [
|
|
130
|
+
'allowUnknownVersion',
|
|
146
131
|
'allowUnknownOutputs',
|
|
147
132
|
'allowUnknownInputs',
|
|
148
133
|
'disableScriptCheck',
|
|
@@ -156,6 +141,11 @@ function validateOpts(opts) {
|
|
|
156
141
|
if (typeof v !== 'boolean')
|
|
157
142
|
throw new Error(`Transation options wrong type: ${k}=${v} (${typeof v})`);
|
|
158
143
|
}
|
|
144
|
+
// 0 and -1 happens in tests
|
|
145
|
+
if (_opts.allowUnknownVersion
|
|
146
|
+
? typeof _opts.version === 'number'
|
|
147
|
+
: ![-1, 0, 1, 2, 3].includes(_opts.version))
|
|
148
|
+
throw new Error(`Unknown version: ${_opts.version}`);
|
|
159
149
|
if (_opts.customScripts !== undefined) {
|
|
160
150
|
const cs = _opts.customScripts;
|
|
161
151
|
if (!Array.isArray(cs)) {
|
|
@@ -178,7 +168,7 @@ function validateInput(i) {
|
|
|
178
168
|
throw new Error(`validateInput: index(${i.index}) not in nonWitnessUtxo`);
|
|
179
169
|
const prevOut = i.nonWitnessUtxo.outputs[i.index];
|
|
180
170
|
if (i.witnessUtxo &&
|
|
181
|
-
(!
|
|
171
|
+
(!equalBytes(i.witnessUtxo.script, prevOut.script) || i.witnessUtxo.amount !== prevOut.amount))
|
|
182
172
|
throw new Error('validateInput: witnessUtxo different from nonWitnessUtxo');
|
|
183
173
|
if (i.txid) {
|
|
184
174
|
const outputs = i.nonWitnessUtxo.outputs;
|
|
@@ -192,12 +182,12 @@ function validateInput(i) {
|
|
|
192
182
|
// in case user wants to use wrong input by mistake
|
|
193
183
|
// - Worst case: tx will be rejected by nodes. Still better than disallowing user
|
|
194
184
|
// to spend real input, no matter how broken it looks
|
|
195
|
-
const tx = Transaction.fromRaw(
|
|
185
|
+
const tx = Transaction.fromRaw(RawTx.encode(i.nonWitnessUtxo), {
|
|
196
186
|
allowUnknownOutputs: true,
|
|
197
187
|
disableScriptCheck: true,
|
|
198
188
|
allowUnknownInputs: true,
|
|
199
189
|
});
|
|
200
|
-
const txid =
|
|
190
|
+
const txid = hex.encode(i.txid);
|
|
201
191
|
// PSBTv2 vectors have non-final tx in inputs
|
|
202
192
|
if (tx.isFinal && tx.id !== txid)
|
|
203
193
|
throw new Error(`nonWitnessUtxo: wrong txid, exp=${txid} got=${tx.id}`);
|
|
@@ -206,7 +196,7 @@ function validateInput(i) {
|
|
|
206
196
|
return i;
|
|
207
197
|
}
|
|
208
198
|
// Normalizes input
|
|
209
|
-
function getPrevOut(input) {
|
|
199
|
+
export function getPrevOut(input) {
|
|
210
200
|
if (input.nonWitnessUtxo) {
|
|
211
201
|
if (input.index === undefined)
|
|
212
202
|
throw new Error('Unknown input index');
|
|
@@ -217,20 +207,20 @@ function getPrevOut(input) {
|
|
|
217
207
|
else
|
|
218
208
|
throw new Error('Cannot find previous output info');
|
|
219
209
|
}
|
|
220
|
-
function normalizeInput(i, cur, allowedFields, disableScriptCheck = false, allowUnknown = false) {
|
|
210
|
+
export function normalizeInput(i, cur, allowedFields, disableScriptCheck = false, allowUnknown = false) {
|
|
221
211
|
let { nonWitnessUtxo, txid } = i;
|
|
222
212
|
// String support for common fields. We usually prefer Uint8Array to avoid errors
|
|
223
213
|
// like hex looking string accidentally passed, however, in case of nonWitnessUtxo
|
|
224
214
|
// it is better to expect string, since constructing this complex object will be
|
|
225
215
|
// difficult for user
|
|
226
216
|
if (typeof nonWitnessUtxo === 'string')
|
|
227
|
-
nonWitnessUtxo =
|
|
228
|
-
if (
|
|
229
|
-
nonWitnessUtxo =
|
|
217
|
+
nonWitnessUtxo = hex.decode(nonWitnessUtxo);
|
|
218
|
+
if (isBytes(nonWitnessUtxo))
|
|
219
|
+
nonWitnessUtxo = RawTx.decode(nonWitnessUtxo);
|
|
230
220
|
if (!('nonWitnessUtxo' in i) && nonWitnessUtxo === undefined)
|
|
231
221
|
nonWitnessUtxo = cur?.nonWitnessUtxo;
|
|
232
222
|
if (typeof txid === 'string')
|
|
233
|
-
txid =
|
|
223
|
+
txid = hex.decode(txid);
|
|
234
224
|
// TODO: if we have nonWitnessUtxo, we can extract txId from here
|
|
235
225
|
if (txid === undefined)
|
|
236
226
|
txid = cur?.txid;
|
|
@@ -238,7 +228,7 @@ function normalizeInput(i, cur, allowedFields, disableScriptCheck = false, allow
|
|
|
238
228
|
if (!('nonWitnessUtxo' in i) && res.nonWitnessUtxo === undefined)
|
|
239
229
|
delete res.nonWitnessUtxo;
|
|
240
230
|
if (res.sequence === undefined)
|
|
241
|
-
res.sequence =
|
|
231
|
+
res.sequence = DEFAULT_SEQUENCE;
|
|
242
232
|
if (res.tapMerkleRoot === null)
|
|
243
233
|
delete res.tapMerkleRoot;
|
|
244
234
|
res = psbt.mergeKeyMap(psbt.PSBTInput, res, cur, allowedFields, allowUnknown);
|
|
@@ -249,14 +239,14 @@ function normalizeInput(i, cur, allowedFields, disableScriptCheck = false, allow
|
|
|
249
239
|
else if (res.witnessUtxo)
|
|
250
240
|
prevOut = res.witnessUtxo;
|
|
251
241
|
if (prevOut && !disableScriptCheck)
|
|
252
|
-
|
|
242
|
+
checkScript(prevOut && prevOut.script, res.redeemScript, res.witnessScript);
|
|
253
243
|
return res;
|
|
254
244
|
}
|
|
255
|
-
function getInputType(input, allowLegacyWitnessUtxo = false) {
|
|
245
|
+
export function getInputType(input, allowLegacyWitnessUtxo = false) {
|
|
256
246
|
let txType = 'legacy';
|
|
257
247
|
let defaultSighash = SignatureHash.ALL;
|
|
258
248
|
const prevOut = getPrevOut(input);
|
|
259
|
-
const first =
|
|
249
|
+
const first = OutScript.decode(prevOut.script);
|
|
260
250
|
let type = first.type;
|
|
261
251
|
let cur = first;
|
|
262
252
|
const stack = [first];
|
|
@@ -277,7 +267,7 @@ function getInputType(input, allowLegacyWitnessUtxo = false) {
|
|
|
277
267
|
if (first.type === 'sh') {
|
|
278
268
|
if (!input.redeemScript)
|
|
279
269
|
throw new Error('inputType: sh without redeemScript');
|
|
280
|
-
let child =
|
|
270
|
+
let child = OutScript.decode(input.redeemScript);
|
|
281
271
|
if (child.type === 'wpkh' || child.type === 'wsh')
|
|
282
272
|
txType = 'segwit';
|
|
283
273
|
stack.push(child);
|
|
@@ -288,7 +278,7 @@ function getInputType(input, allowLegacyWitnessUtxo = false) {
|
|
|
288
278
|
if (cur.type === 'wsh') {
|
|
289
279
|
if (!input.witnessScript)
|
|
290
280
|
throw new Error('inputType: wsh without witnessScript');
|
|
291
|
-
let child =
|
|
281
|
+
let child = OutScript.decode(input.witnessScript);
|
|
292
282
|
if (child.type === 'wsh')
|
|
293
283
|
txType = 'segwit';
|
|
294
284
|
stack.push(child);
|
|
@@ -298,7 +288,7 @@ function getInputType(input, allowLegacyWitnessUtxo = false) {
|
|
|
298
288
|
const last = stack[stack.length - 1];
|
|
299
289
|
if (last.type === 'sh' || last.type === 'wsh')
|
|
300
290
|
throw new Error('inputType: sh/wsh cannot be terminal type');
|
|
301
|
-
const lastScript =
|
|
291
|
+
const lastScript = OutScript.encode(last);
|
|
302
292
|
const res = {
|
|
303
293
|
type,
|
|
304
294
|
txType,
|
|
@@ -313,20 +303,21 @@ function getInputType(input, allowLegacyWitnessUtxo = false) {
|
|
|
313
303
|
return res;
|
|
314
304
|
}
|
|
315
305
|
}
|
|
316
|
-
class Transaction {
|
|
306
|
+
export class Transaction {
|
|
307
|
+
global = {};
|
|
308
|
+
inputs = []; // use getInput()
|
|
309
|
+
outputs = []; // use getOutput()
|
|
310
|
+
opts;
|
|
317
311
|
constructor(opts = {}) {
|
|
318
|
-
this.global = {};
|
|
319
|
-
this.inputs = []; // use getInput()
|
|
320
|
-
this.outputs = []; // use getOutput()
|
|
321
312
|
const _opts = (this.opts = validateOpts(opts));
|
|
322
313
|
// Merge with global structure of PSBTv2
|
|
323
|
-
if (_opts.lockTime !==
|
|
314
|
+
if (_opts.lockTime !== DEFAULT_LOCKTIME)
|
|
324
315
|
this.global.fallbackLocktime = _opts.lockTime;
|
|
325
316
|
this.global.txVersion = _opts.version;
|
|
326
317
|
}
|
|
327
318
|
// Import
|
|
328
319
|
static fromRaw(raw, opts = {}) {
|
|
329
|
-
const parsed =
|
|
320
|
+
const parsed = RawTx.decode(raw);
|
|
330
321
|
const tx = new Transaction({ ...opts, version: parsed.version, lockTime: parsed.lockTime });
|
|
331
322
|
for (const o of parsed.outputs)
|
|
332
323
|
tx.addOutput(o);
|
|
@@ -373,7 +364,7 @@ class Transaction {
|
|
|
373
364
|
...parsed.global.unsignedTx?.outputs[j],
|
|
374
365
|
}));
|
|
375
366
|
tx.global = { ...parsed.global, txVersion: version }; // just in case proprietary/unknown fields
|
|
376
|
-
if (lockTime !==
|
|
367
|
+
if (lockTime !== DEFAULT_LOCKTIME)
|
|
377
368
|
tx.global.fallbackLocktime = lockTime;
|
|
378
369
|
return tx;
|
|
379
370
|
}
|
|
@@ -404,7 +395,7 @@ class Transaction {
|
|
|
404
395
|
- Parsing of PSBTv0 depends on unsignedTx (it looks for input count here)
|
|
405
396
|
- BIP-174 requires old serialization format (without witnesses) inside global, which solves this
|
|
406
397
|
*/
|
|
407
|
-
global.unsignedTx =
|
|
398
|
+
global.unsignedTx = RawOldTx.decode(RawOldTx.encode({
|
|
408
399
|
version: this.version,
|
|
409
400
|
lockTime: this.lockTime,
|
|
410
401
|
inputs: this.inputs.map(inputBeforeSign).map((i) => ({
|
|
@@ -421,7 +412,7 @@ class Transaction {
|
|
|
421
412
|
global.txVersion = this.version;
|
|
422
413
|
global.inputCount = this.inputs.length;
|
|
423
414
|
global.outputCount = this.outputs.length;
|
|
424
|
-
if (global.fallbackLocktime && global.fallbackLocktime ===
|
|
415
|
+
if (global.fallbackLocktime && global.fallbackLocktime === DEFAULT_LOCKTIME)
|
|
425
416
|
delete global.fallbackLocktime;
|
|
426
417
|
}
|
|
427
418
|
if (this.opts.bip174jsCompat) {
|
|
@@ -438,9 +429,9 @@ class Transaction {
|
|
|
438
429
|
}
|
|
439
430
|
// BIP370 lockTime (https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki#determining-lock-time)
|
|
440
431
|
get lockTime() {
|
|
441
|
-
let height =
|
|
432
|
+
let height = DEFAULT_LOCKTIME;
|
|
442
433
|
let heightCnt = 0;
|
|
443
|
-
let time =
|
|
434
|
+
let time = DEFAULT_LOCKTIME;
|
|
444
435
|
let timeCnt = 0;
|
|
445
436
|
for (const i of this.inputs) {
|
|
446
437
|
if (i.requiredHeightLocktime) {
|
|
@@ -454,9 +445,9 @@ class Transaction {
|
|
|
454
445
|
}
|
|
455
446
|
if (heightCnt && heightCnt >= timeCnt)
|
|
456
447
|
return height;
|
|
457
|
-
if (time !==
|
|
448
|
+
if (time !== DEFAULT_LOCKTIME)
|
|
458
449
|
return time;
|
|
459
|
-
return this.global.fallbackLocktime ||
|
|
450
|
+
return this.global.fallbackLocktime || DEFAULT_LOCKTIME;
|
|
460
451
|
}
|
|
461
452
|
get version() {
|
|
462
453
|
// Should be not possible
|
|
@@ -549,25 +540,25 @@ class Transaction {
|
|
|
549
540
|
let out = 32;
|
|
550
541
|
// Outputs
|
|
551
542
|
const outputs = this.outputs.map(outputBeforeSign);
|
|
552
|
-
out += 4 *
|
|
543
|
+
out += 4 * CompactSizeLen.encode(this.outputs.length).length;
|
|
553
544
|
for (const o of outputs)
|
|
554
|
-
out += 32 + 4 *
|
|
545
|
+
out += 32 + 4 * VarBytes.encode(o.script).length;
|
|
555
546
|
// Inputs
|
|
556
547
|
if (this.hasWitnesses)
|
|
557
548
|
out += 2;
|
|
558
|
-
out += 4 *
|
|
549
|
+
out += 4 * CompactSizeLen.encode(this.inputs.length).length;
|
|
559
550
|
for (const i of this.inputs) {
|
|
560
|
-
out += 160 + 4 *
|
|
551
|
+
out += 160 + 4 * VarBytes.encode(i.finalScriptSig || P.EMPTY).length;
|
|
561
552
|
if (this.hasWitnesses && i.finalScriptWitness)
|
|
562
|
-
out +=
|
|
553
|
+
out += RawWitness.encode(i.finalScriptWitness).length;
|
|
563
554
|
}
|
|
564
555
|
return out;
|
|
565
556
|
}
|
|
566
557
|
get vsize() {
|
|
567
|
-
return
|
|
558
|
+
return toVsize(this.weight);
|
|
568
559
|
}
|
|
569
560
|
toBytes(withScriptSig = false, withWitness = false) {
|
|
570
|
-
return
|
|
561
|
+
return RawTx.encode({
|
|
571
562
|
version: this.version,
|
|
572
563
|
lockTime: this.lockTime,
|
|
573
564
|
inputs: this.inputs.map(inputBeforeSign).map((i) => ({
|
|
@@ -583,17 +574,13 @@ class Transaction {
|
|
|
583
574
|
return this.toBytes(false, false);
|
|
584
575
|
}
|
|
585
576
|
get hex() {
|
|
586
|
-
return
|
|
577
|
+
return hex.encode(this.toBytes(true, this.hasWitnesses));
|
|
587
578
|
}
|
|
588
579
|
get hash() {
|
|
589
|
-
|
|
590
|
-
throw new Error('Transaction is not finalized');
|
|
591
|
-
return base_1.hex.encode(u.sha256x2(this.toBytes(true)));
|
|
580
|
+
return hex.encode(u.sha256x2(this.toBytes(true)));
|
|
592
581
|
}
|
|
593
582
|
get id() {
|
|
594
|
-
|
|
595
|
-
throw new Error('Transaction is not finalized');
|
|
596
|
-
return base_1.hex.encode(u.sha256x2(this.toBytes(true)).reverse());
|
|
583
|
+
return hex.encode(u.sha256x2(this.toBytes(true)).reverse());
|
|
597
584
|
}
|
|
598
585
|
// Input stuff
|
|
599
586
|
checkInputIdx(idx) {
|
|
@@ -633,11 +620,11 @@ class Transaction {
|
|
|
633
620
|
this.checkOutputIdx(idx);
|
|
634
621
|
return cloneDeep(this.outputs[idx]);
|
|
635
622
|
}
|
|
636
|
-
getOutputAddress(idx, network =
|
|
623
|
+
getOutputAddress(idx, network = NETWORK) {
|
|
637
624
|
const out = this.getOutput(idx);
|
|
638
625
|
if (!out.script)
|
|
639
626
|
return;
|
|
640
|
-
return
|
|
627
|
+
return Address(network).encode(OutScript.decode(out.script));
|
|
641
628
|
}
|
|
642
629
|
get outputsLength() {
|
|
643
630
|
return this.outputs.length;
|
|
@@ -649,7 +636,7 @@ class Transaction {
|
|
|
649
636
|
if (typeof amount !== 'bigint')
|
|
650
637
|
throw new Error(`Wrong amount type, should be of type bigint in sats, but got ${amount} of type ${typeof amount}`);
|
|
651
638
|
if (typeof script === 'string')
|
|
652
|
-
script =
|
|
639
|
+
script = hex.decode(script);
|
|
653
640
|
if (script === undefined)
|
|
654
641
|
script = cur?.script;
|
|
655
642
|
let res = { ...cur, ...o, amount, script };
|
|
@@ -659,11 +646,11 @@ class Transaction {
|
|
|
659
646
|
psbt.PSBTOutputCoder.encode(res);
|
|
660
647
|
if (res.script &&
|
|
661
648
|
!this.opts.allowUnknownOutputs &&
|
|
662
|
-
|
|
649
|
+
OutScript.decode(res.script).type === 'unknown') {
|
|
663
650
|
throw new Error('Transaction/output: unknown output script type, there is a chance that input is unspendable. Pass allowUnknownOutputs=true, if you sure');
|
|
664
651
|
}
|
|
665
652
|
if (!this.opts.disableScriptCheck)
|
|
666
|
-
|
|
653
|
+
checkScript(res.script, res.redeemScript, res.witnessScript);
|
|
667
654
|
return res;
|
|
668
655
|
}
|
|
669
656
|
addOutput(o, _ignoreSignStatus = false) {
|
|
@@ -682,8 +669,8 @@ class Transaction {
|
|
|
682
669
|
}
|
|
683
670
|
this.outputs[idx] = this.normalizeOutput(output, this.outputs[idx], allowedFields);
|
|
684
671
|
}
|
|
685
|
-
addOutputAddress(address, amount, network =
|
|
686
|
-
return this.addOutput({ script:
|
|
672
|
+
addOutputAddress(address, amount, network = NETWORK) {
|
|
673
|
+
return this.addOutput({ script: OutScript.encode(Address(network).decode(address)), amount });
|
|
687
674
|
}
|
|
688
675
|
// Utils
|
|
689
676
|
get fee() {
|
|
@@ -709,7 +696,7 @@ class Transaction {
|
|
|
709
696
|
throw new Error(`Invalid input idx=${idx}`);
|
|
710
697
|
if ((isSingle && idx >= this.outputs.length) || idx >= this.inputs.length)
|
|
711
698
|
return P.U256BE.encode(1n);
|
|
712
|
-
prevOutScript =
|
|
699
|
+
prevOutScript = Script.encode(Script.decode(prevOutScript).filter((i) => i !== 'CODESEPARATOR'));
|
|
713
700
|
let inputs = this.inputs
|
|
714
701
|
.map(inputBeforeSign)
|
|
715
702
|
.map((input, inputIdx) => ({
|
|
@@ -730,7 +717,7 @@ class Transaction {
|
|
|
730
717
|
else if (isSingle) {
|
|
731
718
|
outputs = outputs.slice(0, idx).fill(EMPTY_OUTPUT).concat([outputs[idx]]);
|
|
732
719
|
}
|
|
733
|
-
const tmpTx =
|
|
720
|
+
const tmpTx = RawTx.encode({
|
|
734
721
|
lockTime: this.lockTime,
|
|
735
722
|
version: this.version,
|
|
736
723
|
segwitFlag: false,
|
|
@@ -751,12 +738,12 @@ class Transaction {
|
|
|
751
738
|
if (!isAny && !isSingle && !isNone)
|
|
752
739
|
sequenceHash = u.sha256x2(...inputs.map((i) => P.U32LE.encode(i.sequence)));
|
|
753
740
|
if (!isSingle && !isNone) {
|
|
754
|
-
outputHash = u.sha256x2(...outputs.map(
|
|
741
|
+
outputHash = u.sha256x2(...outputs.map(RawOutput.encode));
|
|
755
742
|
}
|
|
756
743
|
else if (isSingle && idx < outputs.length)
|
|
757
|
-
outputHash = u.sha256x2(
|
|
744
|
+
outputHash = u.sha256x2(RawOutput.encode(outputs[idx]));
|
|
758
745
|
const input = inputs[idx];
|
|
759
|
-
return u.sha256x2(P.I32LE.encode(this.version), inputHash, sequenceHash, P.bytes(32, true).encode(input.txid), P.U32LE.encode(input.index),
|
|
746
|
+
return u.sha256x2(P.I32LE.encode(this.version), inputHash, sequenceHash, P.bytes(32, true).encode(input.txid), P.U32LE.encode(input.index), VarBytes.encode(prevOutScript), P.U64LE.encode(amount), P.U32LE.encode(input.sequence), outputHash, P.U32LE.encode(this.lockTime), P.U32LE.encode(hashType));
|
|
760
747
|
}
|
|
761
748
|
preimageWitnessV1(idx, prevOutScript, hashType, amount, codeSeparator = -1, leafScript, leafVer = 0xc0, annex) {
|
|
762
749
|
if (!Array.isArray(amount) || this.inputs.length !== amount.length)
|
|
@@ -777,27 +764,27 @@ class Transaction {
|
|
|
777
764
|
out.push(...[
|
|
778
765
|
inputs.map(TxHashIdx.encode),
|
|
779
766
|
amount.map(P.U64LE.encode),
|
|
780
|
-
prevOutScript.map(
|
|
767
|
+
prevOutScript.map(VarBytes.encode),
|
|
781
768
|
inputs.map((i) => P.U32LE.encode(i.sequence)),
|
|
782
|
-
].map((i) => u.sha256(
|
|
769
|
+
].map((i) => u.sha256(concatBytes(...i))));
|
|
783
770
|
}
|
|
784
771
|
if (outType === SignatureHash.ALL) {
|
|
785
|
-
out.push(u.sha256(
|
|
772
|
+
out.push(u.sha256(concatBytes(...outputs.map(RawOutput.encode))));
|
|
786
773
|
}
|
|
787
774
|
const spendType = (annex ? 1 : 0) | (leafScript ? 2 : 0);
|
|
788
775
|
out.push(new Uint8Array([spendType]));
|
|
789
776
|
if (inType === SignatureHash.ANYONECANPAY) {
|
|
790
777
|
const inp = inputs[idx];
|
|
791
|
-
out.push(TxHashIdx.encode(inp), P.U64LE.encode(amount[idx]),
|
|
778
|
+
out.push(TxHashIdx.encode(inp), P.U64LE.encode(amount[idx]), VarBytes.encode(prevOutScript[idx]), P.U32LE.encode(inp.sequence));
|
|
792
779
|
}
|
|
793
780
|
else
|
|
794
781
|
out.push(P.U32LE.encode(idx));
|
|
795
782
|
if (spendType & 1)
|
|
796
|
-
out.push(u.sha256(
|
|
783
|
+
out.push(u.sha256(VarBytes.encode(annex || P.EMPTY)));
|
|
797
784
|
if (outType === SignatureHash.SINGLE)
|
|
798
|
-
out.push(idx < outputs.length ? u.sha256(
|
|
785
|
+
out.push(idx < outputs.length ? u.sha256(RawOutput.encode(outputs[idx])) : EMPTY32);
|
|
799
786
|
if (leafScript)
|
|
800
|
-
out.push(
|
|
787
|
+
out.push(tapLeafHash(leafScript, leafVer), P.U8.encode(0), P.I32LE.encode(codeSeparator));
|
|
801
788
|
return u.tagSchnorr('TapSighash', ...out);
|
|
802
789
|
}
|
|
803
790
|
// Signer can be privateKey OR instance of bip32 HD stuff
|
|
@@ -806,7 +793,7 @@ class Transaction {
|
|
|
806
793
|
const input = this.inputs[idx];
|
|
807
794
|
const inputType = getInputType(input, this.opts.allowLegacyWitnessUtxo);
|
|
808
795
|
// Handle BIP32 HDKey
|
|
809
|
-
if (!
|
|
796
|
+
if (!isBytes(privateKey)) {
|
|
810
797
|
if (!input.bip32Derivation || !input.bip32Derivation.length)
|
|
811
798
|
throw new Error('bip32Derivation: empty');
|
|
812
799
|
const signers = input.bip32Derivation
|
|
@@ -815,7 +802,7 @@ class Transaction {
|
|
|
815
802
|
let s = privateKey;
|
|
816
803
|
for (const i of path)
|
|
817
804
|
s = s.deriveChild(i);
|
|
818
|
-
if (!
|
|
805
|
+
if (!equalBytes(s.publicKey, pubKey))
|
|
819
806
|
throw new Error('bip32Derivation: wrong pubKey');
|
|
820
807
|
if (!s.privateKey)
|
|
821
808
|
throw new Error('bip32Derivation: no privateKey');
|
|
@@ -864,9 +851,9 @@ class Transaction {
|
|
|
864
851
|
// priv key to be provided
|
|
865
852
|
const { pubKey, privKey } = getTaprootKeys(privateKey, schnorrPub, input.tapInternalKey, merkleRoot);
|
|
866
853
|
const [taprootPubKey, _] = u.taprootTweakPubkey(input.tapInternalKey, merkleRoot);
|
|
867
|
-
if (
|
|
854
|
+
if (equalBytes(taprootPubKey, pubKey)) {
|
|
868
855
|
const hash = this.preimageWitnessV1(idx, prevOutScript, sighash, amount);
|
|
869
|
-
const sig =
|
|
856
|
+
const sig = concatBytes(u.signSchnorr(hash, privKey, _auxRand), sighash !== SignatureHash.DEFAULT ? new Uint8Array([sighash]) : P.EMPTY);
|
|
870
857
|
this.updateInput(idx, { tapKeySig: sig }, true);
|
|
871
858
|
signed = true;
|
|
872
859
|
}
|
|
@@ -875,16 +862,16 @@ class Transaction {
|
|
|
875
862
|
input.tapScriptSig = input.tapScriptSig || [];
|
|
876
863
|
for (const [_, _script] of input.tapLeafScript) {
|
|
877
864
|
const script = _script.subarray(0, -1);
|
|
878
|
-
const scriptDecoded =
|
|
865
|
+
const scriptDecoded = Script.decode(script);
|
|
879
866
|
const ver = _script[_script.length - 1];
|
|
880
|
-
const hash =
|
|
867
|
+
const hash = tapLeafHash(script, ver);
|
|
881
868
|
// NOTE: no need to tweak internal key here, since we don't support nested p2tr
|
|
882
|
-
const pos = scriptDecoded.findIndex((i) =>
|
|
869
|
+
const pos = scriptDecoded.findIndex((i) => isBytes(i) && equalBytes(i, schnorrPub));
|
|
883
870
|
// Skip if there is no public key in tapLeafScript
|
|
884
871
|
if (pos === -1)
|
|
885
872
|
continue;
|
|
886
873
|
const msg = this.preimageWitnessV1(idx, prevOutScript, sighash, amount, undefined, script, ver);
|
|
887
|
-
const sig =
|
|
874
|
+
const sig = concatBytes(u.signSchnorr(msg, privateKey, _auxRand), sighash !== SignatureHash.DEFAULT ? new Uint8Array([sighash]) : P.EMPTY);
|
|
888
875
|
this.updateInput(idx, { tapScriptSig: [[{ pubKey: schnorrPub, leafHash: hash }, sig]] }, true);
|
|
889
876
|
signed = true;
|
|
890
877
|
}
|
|
@@ -900,8 +887,8 @@ class Transaction {
|
|
|
900
887
|
// Check if script has public key or its has inside
|
|
901
888
|
let hasPubkey = false;
|
|
902
889
|
const pubKeyHash = u.hash160(pubKey);
|
|
903
|
-
for (const i of
|
|
904
|
-
if (
|
|
890
|
+
for (const i of Script.decode(inputType.lastScript)) {
|
|
891
|
+
if (isBytes(i) && (equalBytes(i, pubKey) || equalBytes(i, pubKeyHash)))
|
|
905
892
|
hasPubkey = true;
|
|
906
893
|
}
|
|
907
894
|
if (!hasPubkey)
|
|
@@ -914,14 +901,14 @@ class Transaction {
|
|
|
914
901
|
let script = inputType.lastScript;
|
|
915
902
|
// If wpkh OR sh-wpkh, wsh-wpkh is impossible, so looks ok
|
|
916
903
|
if (inputType.last.type === 'wpkh')
|
|
917
|
-
script =
|
|
904
|
+
script = OutScript.encode({ type: 'pkh', hash: inputType.last.hash });
|
|
918
905
|
hash = this.preimageWitnessV0(idx, script, sighash, prevOut.amount);
|
|
919
906
|
}
|
|
920
907
|
else
|
|
921
908
|
throw new Error(`Transaction/sign: unknown tx type: ${inputType.txType}`);
|
|
922
909
|
const sig = u.signECDSA(hash, privateKey, this.opts.lowR);
|
|
923
910
|
this.updateInput(idx, {
|
|
924
|
-
partialSig: [[pubKey,
|
|
911
|
+
partialSig: [[pubKey, concatBytes(sig, new Uint8Array([sighash]))]],
|
|
925
912
|
}, true);
|
|
926
913
|
}
|
|
927
914
|
return true;
|
|
@@ -964,16 +951,16 @@ class Transaction {
|
|
|
964
951
|
// Last byte is version
|
|
965
952
|
const script = _script.slice(0, -1);
|
|
966
953
|
const ver = _script[_script.length - 1];
|
|
967
|
-
const outScript =
|
|
968
|
-
const hash =
|
|
969
|
-
const scriptSig = input.tapScriptSig.filter((i) =>
|
|
954
|
+
const outScript = OutScript.decode(script);
|
|
955
|
+
const hash = tapLeafHash(script, ver);
|
|
956
|
+
const scriptSig = input.tapScriptSig.filter((i) => equalBytes(i[0].leafHash, hash));
|
|
970
957
|
let signatures = [];
|
|
971
958
|
if (outScript.type === 'tr_ms') {
|
|
972
959
|
const m = outScript.m;
|
|
973
960
|
const pubkeys = outScript.pubkeys;
|
|
974
961
|
let added = 0;
|
|
975
962
|
for (const pub of pubkeys) {
|
|
976
|
-
const sigIdx = scriptSig.findIndex((i) =>
|
|
963
|
+
const sigIdx = scriptSig.findIndex((i) => equalBytes(i[0].pubKey, pub));
|
|
977
964
|
// Should have exact amount of signatures (more -- will fail)
|
|
978
965
|
if (added === m || sigIdx === -1) {
|
|
979
966
|
signatures.push(P.EMPTY);
|
|
@@ -988,7 +975,7 @@ class Transaction {
|
|
|
988
975
|
}
|
|
989
976
|
else if (outScript.type === 'tr_ns') {
|
|
990
977
|
for (const pub of outScript.pubkeys) {
|
|
991
|
-
const sigIdx = scriptSig.findIndex((i) =>
|
|
978
|
+
const sigIdx = scriptSig.findIndex((i) => equalBytes(i[0].pubKey, pub));
|
|
992
979
|
if (sigIdx === -1)
|
|
993
980
|
continue;
|
|
994
981
|
signatures.push(scriptSig[sigIdx][1]);
|
|
@@ -998,10 +985,10 @@ class Transaction {
|
|
|
998
985
|
}
|
|
999
986
|
else if (outScript.type === 'unknown' && this.opts.allowUnknownInputs) {
|
|
1000
987
|
// Trying our best to sign what we can
|
|
1001
|
-
const scriptDecoded =
|
|
988
|
+
const scriptDecoded = Script.decode(script);
|
|
1002
989
|
signatures = scriptSig
|
|
1003
990
|
.map(([{ pubKey }, signature]) => {
|
|
1004
|
-
const pos = scriptDecoded.findIndex((i) =>
|
|
991
|
+
const pos = scriptDecoded.findIndex((i) => isBytes(i) && equalBytes(i, pubKey));
|
|
1005
992
|
if (pos === -1)
|
|
1006
993
|
throw new Error('finalize/taproot: cannot find position of pubkey in script');
|
|
1007
994
|
return { signature, pos };
|
|
@@ -1018,7 +1005,7 @@ class Transaction {
|
|
|
1018
1005
|
for (const c of custom) {
|
|
1019
1006
|
if (!c.finalizeTaproot)
|
|
1020
1007
|
continue;
|
|
1021
|
-
const scriptDecoded =
|
|
1008
|
+
const scriptDecoded = Script.decode(script);
|
|
1022
1009
|
const csEncoded = c.encode(scriptDecoded);
|
|
1023
1010
|
if (csEncoded === undefined)
|
|
1024
1011
|
continue;
|
|
@@ -1060,7 +1047,7 @@ class Transaction {
|
|
|
1060
1047
|
let signatures = [];
|
|
1061
1048
|
// partial: [pubkey, sign]
|
|
1062
1049
|
for (const pub of pubkeys) {
|
|
1063
|
-
const sign = input.partialSig.find((s) =>
|
|
1050
|
+
const sign = input.partialSig.find((s) => equalBytes(pub, s[0]));
|
|
1064
1051
|
if (!sign)
|
|
1065
1052
|
continue;
|
|
1066
1053
|
signatures.push(sign[1]);
|
|
@@ -1069,13 +1056,13 @@ class Transaction {
|
|
|
1069
1056
|
if (signatures.length !== m) {
|
|
1070
1057
|
throw new Error(`Multisig: wrong signatures count, m=${m} n=${pubkeys.length} signatures=${signatures.length}`);
|
|
1071
1058
|
}
|
|
1072
|
-
inputScript =
|
|
1059
|
+
inputScript = Script.encode([0, ...signatures]);
|
|
1073
1060
|
}
|
|
1074
1061
|
else if (inputType.last.type === 'pk') {
|
|
1075
|
-
inputScript =
|
|
1062
|
+
inputScript = Script.encode([input.partialSig[0][1]]);
|
|
1076
1063
|
}
|
|
1077
1064
|
else if (inputType.last.type === 'pkh') {
|
|
1078
|
-
inputScript =
|
|
1065
|
+
inputScript = Script.encode([input.partialSig[0][1], input.partialSig[0][0]]);
|
|
1079
1066
|
}
|
|
1080
1067
|
else if (inputType.last.type === 'wpkh') {
|
|
1081
1068
|
inputScript = P.EMPTY;
|
|
@@ -1088,10 +1075,10 @@ class Transaction {
|
|
|
1088
1075
|
if (inputType.type.includes('wsh-')) {
|
|
1089
1076
|
// P2WSH
|
|
1090
1077
|
if (inputScript.length && inputType.lastScript.length) {
|
|
1091
|
-
witness =
|
|
1078
|
+
witness = Script.decode(inputScript).map((i) => {
|
|
1092
1079
|
if (i === 0)
|
|
1093
1080
|
return P.EMPTY;
|
|
1094
|
-
if (
|
|
1081
|
+
if (isBytes(i))
|
|
1095
1082
|
return i;
|
|
1096
1083
|
throw new Error(`Wrong witness op=${i}`);
|
|
1097
1084
|
});
|
|
@@ -1101,10 +1088,10 @@ class Transaction {
|
|
|
1101
1088
|
if (inputType.txType === 'segwit')
|
|
1102
1089
|
finalScriptWitness = witness;
|
|
1103
1090
|
if (inputType.type.startsWith('sh-wsh-')) {
|
|
1104
|
-
finalScriptSig =
|
|
1091
|
+
finalScriptSig = Script.encode([Script.encode([0, u.sha256(inputType.lastScript)])]);
|
|
1105
1092
|
}
|
|
1106
1093
|
else if (inputType.type.startsWith('sh-')) {
|
|
1107
|
-
finalScriptSig =
|
|
1094
|
+
finalScriptSig = Script.encode([...Script.decode(inputScript), inputType.lastScript]);
|
|
1108
1095
|
}
|
|
1109
1096
|
else if (inputType.type.startsWith('wsh-')) {
|
|
1110
1097
|
}
|
|
@@ -1142,11 +1129,11 @@ class Transaction {
|
|
|
1142
1129
|
throw new Error(`Transaction/combine: different ${k} length this=${this[k].length} other=${other[k].length}`);
|
|
1143
1130
|
}
|
|
1144
1131
|
}
|
|
1145
|
-
const thisUnsigned = this.global.unsignedTx ?
|
|
1132
|
+
const thisUnsigned = this.global.unsignedTx ? RawOldTx.encode(this.global.unsignedTx) : P.EMPTY;
|
|
1146
1133
|
const otherUnsigned = other.global.unsignedTx
|
|
1147
|
-
?
|
|
1134
|
+
? RawOldTx.encode(other.global.unsignedTx)
|
|
1148
1135
|
: P.EMPTY;
|
|
1149
|
-
if (!
|
|
1136
|
+
if (!equalBytes(thisUnsigned, otherUnsigned))
|
|
1150
1137
|
throw new Error(`Transaction/combine: different unsigned tx`);
|
|
1151
1138
|
this.global = psbt.mergeKeyMap(psbt.PSBTGlobal, this.global, other.global, undefined, this.opts.allowUnknown);
|
|
1152
1139
|
for (let i = 0; i < this.inputs.length; i++)
|
|
@@ -1160,8 +1147,7 @@ class Transaction {
|
|
|
1160
1147
|
return Transaction.fromPSBT(this.toPSBT(this.opts.PSBTVersion), this.opts);
|
|
1161
1148
|
}
|
|
1162
1149
|
}
|
|
1163
|
-
|
|
1164
|
-
function PSBTCombine(psbts) {
|
|
1150
|
+
export function PSBTCombine(psbts) {
|
|
1165
1151
|
if (!psbts || !Array.isArray(psbts) || !psbts.length)
|
|
1166
1152
|
throw new Error('PSBTCombine: wrong PSBT list');
|
|
1167
1153
|
const tx = Transaction.fromPSBT(psbts[0]);
|
|
@@ -1171,7 +1157,7 @@ function PSBTCombine(psbts) {
|
|
|
1171
1157
|
}
|
|
1172
1158
|
// Copy-pasted from bip32 derive, maybe do something like 'bip32.parsePath'?
|
|
1173
1159
|
const HARDENED_OFFSET = 0x80000000;
|
|
1174
|
-
function bip32Path(path) {
|
|
1160
|
+
export function bip32Path(path) {
|
|
1175
1161
|
const out = [];
|
|
1176
1162
|
if (!/^[mM]'?/.test(path))
|
|
1177
1163
|
throw new Error('Path must start with "m" or "M"');
|