@scure/btc-signer 1.3.2 → 1.5.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/README.md +2 -5
- package/_type_test.d.ts.map +1 -0
- package/_type_test.js.map +1 -0
- package/esm/_type_test.d.ts +2 -0
- package/esm/_type_test.js.map +1 -0
- package/{lib → esm}/index.d.ts +2 -2
- package/esm/index.d.ts.map +1 -0
- package/{lib/esm → esm}/index.js +1 -1
- package/esm/index.js.map +1 -0
- package/{lib → esm}/payment.d.ts.map +1 -1
- package/{lib/esm → esm}/payment.js +1 -1
- package/esm/payment.js.map +1 -0
- package/{lib → esm}/psbt.d.ts +0 -14
- package/esm/psbt.d.ts.map +1 -0
- package/{lib/esm → esm}/psbt.js +4 -5
- package/esm/psbt.js.map +1 -0
- package/{lib → esm}/script.d.ts +14 -0
- package/{lib → esm}/script.d.ts.map +1 -1
- package/{lib/esm → esm}/script.js +7 -0
- package/esm/script.js.map +1 -0
- package/{lib → esm}/transaction.d.ts +15 -9
- package/esm/transaction.d.ts.map +1 -0
- package/{lib/esm → esm}/transaction.js +36 -9
- package/esm/transaction.js.map +1 -0
- package/{lib → esm}/utils.d.ts +3 -3
- package/esm/utils.d.ts.map +1 -0
- package/esm/utils.js.map +1 -0
- package/{lib → esm}/utxo.d.ts +16 -19
- package/esm/utxo.d.ts.map +1 -0
- package/{lib/esm → esm}/utxo.js +66 -28
- package/esm/utxo.js.map +1 -0
- package/index.d.ts +20 -0
- package/index.d.ts.map +1 -0
- package/{lib/index.js → index.js} +2 -1
- package/index.js.map +1 -0
- package/package.json +43 -43
- package/payment.d.ts +177 -0
- package/payment.d.ts.map +1 -0
- package/{lib/payment.js → payment.js} +12 -12
- package/payment.js.map +1 -0
- package/psbt.d.ts +820 -0
- package/psbt.d.ts.map +1 -0
- package/{lib/psbt.js → psbt.js} +10 -11
- package/psbt.js.map +1 -0
- package/script.d.ts +168 -0
- package/script.d.ts.map +1 -0
- package/{lib/script.js → script.js} +10 -3
- package/script.js.map +1 -0
- package/src/index.ts +1 -1
- package/src/payment.ts +3 -3
- package/src/psbt.ts +4 -5
- package/src/script.ts +7 -0
- package/src/transaction.ts +41 -9
- package/src/utxo.ts +81 -24
- package/transaction.d.ts +229 -0
- package/transaction.d.ts.map +1 -0
- package/{lib/transaction.js → transaction.js} +48 -21
- package/transaction.js.map +1 -0
- package/utils.d.ts +30 -0
- package/utils.d.ts.map +1 -0
- package/{lib/utils.js → utils.js} +7 -7
- package/utils.js.map +1 -0
- package/utxo.d.ts +248 -0
- package/utxo.d.ts.map +1 -0
- package/{lib/utxo.js → utxo.js} +71 -33
- package/utxo.js.map +1 -0
- package/lib/_type_test.js.map +0 -1
- package/lib/esm/_type_test.js.map +0 -1
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/payment.js.map +0 -1
- package/lib/esm/psbt.js.map +0 -1
- package/lib/esm/script.js.map +0 -1
- package/lib/esm/transaction.js.map +0 -1
- package/lib/esm/utils.js.map +0 -1
- package/lib/esm/utxo.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/payment.js.map +0 -1
- package/lib/psbt.d.ts.map +0 -1
- package/lib/psbt.js.map +0 -1
- package/lib/script.js.map +0 -1
- package/lib/transaction.d.ts.map +0 -1
- package/lib/transaction.js.map +0 -1
- package/lib/utils.d.ts.map +0 -1
- package/lib/utils.js.map +0 -1
- package/lib/utxo.d.ts.map +0 -1
- package/lib/utxo.js.map +0 -1
- /package/{lib/_type_test.d.ts → _type_test.d.ts} +0 -0
- /package/{lib/_type_test.js → _type_test.js} +0 -0
- /package/{lib → esm}/_type_test.d.ts.map +0 -0
- /package/{lib/esm → esm}/_type_test.js +0 -0
- /package/{lib/esm → esm}/package.json +0 -0
- /package/{lib → esm}/payment.d.ts +0 -0
- /package/{lib/esm → esm}/utils.js +0 -0
package/src/utxo.ts
CHANGED
|
@@ -268,12 +268,15 @@ export type EstimatorOpts = TxOpts & {
|
|
|
268
268
|
bip69?: boolean; // https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki
|
|
269
269
|
network?: typeof NETWORK;
|
|
270
270
|
dust?: number; // how much vbytes considered dust?
|
|
271
|
+
dustRelayFeeRate?: bigint; // fee per dust byte (DUST_RELAY_TX_FEE)
|
|
271
272
|
createTx?: boolean; // Create tx inside selection
|
|
273
|
+
requiredInputs?: psbt.TransactionInputUpdate[]; // these inputs always will be used
|
|
274
|
+
allowSameUtxo?: boolean; // allow using UTXO multiple times (for test purposes)
|
|
272
275
|
};
|
|
273
276
|
|
|
274
277
|
function getScript(o: Output, opts: TxOpts = {}, network = NETWORK) {
|
|
275
278
|
let script;
|
|
276
|
-
if ('script' in o && o.script
|
|
279
|
+
if ('script' in o && isBytes(o.script)) {
|
|
277
280
|
script = o.script;
|
|
278
281
|
}
|
|
279
282
|
if ('address' in o) {
|
|
@@ -282,7 +285,12 @@ function getScript(o: Output, opts: TxOpts = {}, network = NETWORK) {
|
|
|
282
285
|
script = OutScript.encode(Address(network).decode(o.address));
|
|
283
286
|
}
|
|
284
287
|
if (!script) throw new Error('Estimator: wrong output script');
|
|
285
|
-
if (typeof o.amount !== 'bigint')
|
|
288
|
+
if (typeof o.amount !== 'bigint')
|
|
289
|
+
throw new Error(
|
|
290
|
+
`Estimator: wrong output amount=${
|
|
291
|
+
o.amount
|
|
292
|
+
}, should be of type bigint but got ${typeof o.amount}.`
|
|
293
|
+
);
|
|
286
294
|
if (script && !opts.allowUnknownOutputs && OutScript.decode(script).type === 'unknown') {
|
|
287
295
|
throw new Error(
|
|
288
296
|
'Estimator: unknown output script type, there is a chance that input is unspendable. Pass allowUnknownOutputs=true, if you sure'
|
|
@@ -310,6 +318,7 @@ export class _Estimator {
|
|
|
310
318
|
private baseWeight: number;
|
|
311
319
|
private changeWeight: number;
|
|
312
320
|
private amount: bigint;
|
|
321
|
+
private requiredIndices: number[] = [];
|
|
313
322
|
private normalizedInputs: {
|
|
314
323
|
inputType: ReturnType<typeof getInputType>;
|
|
315
324
|
normalized: ReturnType<typeof normalizeInput>;
|
|
@@ -317,24 +326,51 @@ export class _Estimator {
|
|
|
317
326
|
value: bigint;
|
|
318
327
|
estimate: { weight: number; hasWitnesses: boolean };
|
|
319
328
|
}[];
|
|
320
|
-
// https://github.com/bitcoin/bitcoin/blob/f90603ac6d24f5263649675d51233f1fce8b2ecd/src/policy/policy.cpp#L44
|
|
321
|
-
// 32 + 4 + 1 + 107 + 4
|
|
322
329
|
// Dust used in accumExact + change address algo
|
|
323
330
|
// - change address: can be smaller for segwit
|
|
324
331
|
// - accumExact: ???
|
|
325
|
-
private dust
|
|
326
|
-
|
|
332
|
+
private dust: bigint; // total dust limit (3||opts.dustRelayFeeRate * 182||opts.dust). Default: 546
|
|
327
333
|
constructor(
|
|
328
|
-
|
|
334
|
+
inputs: psbt.TransactionInputUpdate[],
|
|
329
335
|
private outputs: Output[],
|
|
330
336
|
private opts: EstimatorOpts
|
|
331
337
|
) {
|
|
332
338
|
if (typeof opts.feePerByte !== 'bigint')
|
|
333
|
-
throw new Error(
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
339
|
+
throw new Error(
|
|
340
|
+
`Estimator: wrong feePerByte=${
|
|
341
|
+
opts.feePerByte
|
|
342
|
+
}, should be of type bigint but got ${typeof opts.feePerByte}.`
|
|
343
|
+
);
|
|
344
|
+
// Dust stuff
|
|
345
|
+
// TODO: think about this more:
|
|
346
|
+
// - current dust filters tx which cannot be relayed by core
|
|
347
|
+
// - but actual dust meaning is 'can be this amount spent?'
|
|
348
|
+
// - dust contains full tx size. but we can use other inputs to pay for outputDust (and parially inputsDust)?
|
|
349
|
+
// - not sure if we can spent anything with feePerByte: 3. It will be relayed, but will it be mined?
|
|
350
|
+
// - for now it works exactly as bitcoin-core. But will create change/outputs which cannot be spent (reasonable).
|
|
351
|
+
// Number of bytes needed to create and spend a UTXO.
|
|
352
|
+
// https://github.com/bitcoin/bitcoin/blob/27a770b34b8f1dbb84760f442edb3e23a0c2420b/src/policy/policy.cpp#L28-L41
|
|
353
|
+
const inputsDust = 32 + 4 + 1 + 107 + 4; // NOTE: can be smaller for segwit tx?
|
|
354
|
+
const outputDust = 34; // NOTE: 'nSize = GetSerializeSize(txout)'
|
|
355
|
+
const dustBytes = opts.dust === undefined ? BigInt(inputsDust + outputDust) : opts.dust;
|
|
356
|
+
if (typeof dustBytes !== 'bigint') {
|
|
357
|
+
throw new Error(
|
|
358
|
+
`Estimator: wrong dust=${opts.dust}, should be of type bigint but got ${typeof opts.dust}.`
|
|
359
|
+
);
|
|
337
360
|
}
|
|
361
|
+
// 3 sat/vb is the default minimum fee rate used to calculate dust thresholds by bitcoin core.
|
|
362
|
+
// 3000 sat/kvb -> 3 sat/vb.
|
|
363
|
+
// https://github.com/bitcoin/bitcoin/blob/27a770b34b8f1dbb84760f442edb3e23a0c2420b/src/policy/policy.h#L55
|
|
364
|
+
const dustFee = opts.dustRelayFeeRate === undefined ? 3n : opts.dustRelayFeeRate;
|
|
365
|
+
if (typeof dustFee !== 'bigint') {
|
|
366
|
+
throw new Error(
|
|
367
|
+
`Estimator: wrong dustRelayFeeRate=${opts.dustRelayFeeRate}, should be of type bigint but got ${typeof opts.dustRelayFeeRate}.`
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
// Dust uses feePerbyte by default, but we allow separate dust fee if needed
|
|
371
|
+
this.dust = dustBytes * dustFee;
|
|
372
|
+
if (opts.requiredInputs !== undefined && !Array.isArray(opts.requiredInputs))
|
|
373
|
+
throw new Error(`Estimator: wrong required inputs=${opts.requiredInputs}`);
|
|
338
374
|
const network = opts.network || NETWORK;
|
|
339
375
|
let amount = 0n;
|
|
340
376
|
// Base weight: tx with outputs, no inputs
|
|
@@ -356,9 +392,19 @@ export class _Estimator {
|
|
|
356
392
|
this.baseWeight = baseWeight;
|
|
357
393
|
this.changeWeight = changeWeight;
|
|
358
394
|
this.amount = amount;
|
|
359
|
-
|
|
395
|
+
const allInputs = Array.from(inputs);
|
|
396
|
+
if (opts.requiredInputs) {
|
|
397
|
+
for (let i = 0; i < opts.requiredInputs.length; i++)
|
|
398
|
+
this.requiredIndices.push(allInputs.push(opts.requiredInputs[i]) - 1);
|
|
399
|
+
}
|
|
400
|
+
const inputKeys = new Set();
|
|
401
|
+
this.normalizedInputs = allInputs.map((i) => {
|
|
360
402
|
const normalized = normalizeInput(i, undefined, undefined, opts.disableScriptCheck);
|
|
361
403
|
inputBeforeSign(normalized); // check fields
|
|
404
|
+
const key = `${hex.encode(normalized.txid!)}:${normalized.index}`;
|
|
405
|
+
if (!opts.allowSameUtxo && inputKeys.has(key))
|
|
406
|
+
throw new Error(`Estimator: same input passed multiple times: ${key}`);
|
|
407
|
+
inputKeys.add(key);
|
|
362
408
|
const inputType = getInputType(normalized, opts.allowLegacyWitnessUtxo);
|
|
363
409
|
const prev = getPrevOut(normalized);
|
|
364
410
|
const estimate = estimateInput(inputType, normalized, this.opts);
|
|
@@ -367,7 +413,7 @@ export class _Estimator {
|
|
|
367
413
|
});
|
|
368
414
|
}
|
|
369
415
|
private checkInputIdx(idx: number) {
|
|
370
|
-
if (!Number.isSafeInteger(idx) || 0 > idx || idx >= this.
|
|
416
|
+
if (!Number.isSafeInteger(idx) || 0 > idx || idx >= this.normalizedInputs.length)
|
|
371
417
|
throw new Error(`Wrong input index=${idx}`);
|
|
372
418
|
return idx;
|
|
373
419
|
}
|
|
@@ -397,7 +443,7 @@ export class _Estimator {
|
|
|
397
443
|
|
|
398
444
|
// Sort by value instead of amount
|
|
399
445
|
get biggest() {
|
|
400
|
-
return this.
|
|
446
|
+
return this.normalizedInputs
|
|
401
447
|
.map((_i, j) => j)
|
|
402
448
|
.sort((a, b) => _cmpBig(this.normalizedInputs[b].value, this.normalizedInputs[a].value));
|
|
403
449
|
}
|
|
@@ -408,7 +454,7 @@ export class _Estimator {
|
|
|
408
454
|
// Otherwise, we have no way to know which tx is oldest
|
|
409
455
|
// Explorers usually give UTXO in this order.
|
|
410
456
|
get oldest() {
|
|
411
|
-
return this.
|
|
457
|
+
return this.normalizedInputs.map((_i, j) => j);
|
|
412
458
|
}
|
|
413
459
|
get newest() {
|
|
414
460
|
return this.oldest.reverse();
|
|
@@ -417,7 +463,6 @@ export class _Estimator {
|
|
|
417
463
|
// exact(biggest) will select one big utxo which is closer to targetValue+dust, if possible.
|
|
418
464
|
// If not, it will accumulate largest utxo until value is close to targetValue+dust.
|
|
419
465
|
accumulate(indices: number[], exact = false, skipNegative = true, all = false) {
|
|
420
|
-
const { feePerByte } = this.opts;
|
|
421
466
|
// TODO: how to handle change addresses?
|
|
422
467
|
// - cost of input
|
|
423
468
|
// - cost of change output (if input requires change)
|
|
@@ -433,6 +478,22 @@ export class _Estimator {
|
|
|
433
478
|
const targetAmount = this.amount;
|
|
434
479
|
const res = [];
|
|
435
480
|
let fee;
|
|
481
|
+
for (const idx of this.requiredIndices) {
|
|
482
|
+
this.checkInputIdx(idx);
|
|
483
|
+
const { estimate, amount } = this.normalizedInputs[idx];
|
|
484
|
+
let newWeight = weight + estimate.weight;
|
|
485
|
+
if (!hasWitnesses && estimate.hasWitnesses) newWeight += 2; // enable witness if needed
|
|
486
|
+
const totalWeight = newWeight + 4 * CompactSizeLen.encode(num).length; // number of outputs can change weight
|
|
487
|
+
fee = this.getSatoshi(totalWeight);
|
|
488
|
+
weight = newWeight;
|
|
489
|
+
if (estimate.hasWitnesses) hasWitnesses = true;
|
|
490
|
+
num++;
|
|
491
|
+
inputsAmount += amount;
|
|
492
|
+
res.push(idx);
|
|
493
|
+
// inputsAmount is enough to cover cost of tx
|
|
494
|
+
if (!all && targetAmount + fee <= inputsAmount)
|
|
495
|
+
return { indices: res, fee, weight: totalWeight, total: inputsAmount };
|
|
496
|
+
}
|
|
436
497
|
for (const idx of indices) {
|
|
437
498
|
this.checkInputIdx(idx);
|
|
438
499
|
const { estimate, amount, value } = this.normalizedInputs[idx];
|
|
@@ -441,11 +502,7 @@ export class _Estimator {
|
|
|
441
502
|
const totalWeight = newWeight + 4 * CompactSizeLen.encode(num).length; // number of outputs can change weight
|
|
442
503
|
fee = this.getSatoshi(totalWeight);
|
|
443
504
|
// Best case scenario exact(biggest) -> we find biggest output, less than target+threshold
|
|
444
|
-
if (exact)
|
|
445
|
-
const dust = this.dust * feePerByte;
|
|
446
|
-
// skip if added value is bigger than dust
|
|
447
|
-
if (amount + inputsAmount > targetAmount + fee + dust) continue;
|
|
448
|
-
}
|
|
505
|
+
if (exact && amount + inputsAmount > targetAmount + fee + this.dust) continue; // skip if added value is bigger than dust
|
|
449
506
|
// Negative: cost of using input is more than value provided (negative)
|
|
450
507
|
// By default 'blackjack' mode in coinselect doesn't use that, which means
|
|
451
508
|
// it will use negative output if sorted by 'smallest'
|
|
@@ -456,7 +513,7 @@ export class _Estimator {
|
|
|
456
513
|
inputsAmount += amount;
|
|
457
514
|
res.push(idx);
|
|
458
515
|
// inputsAmount is enough to cover cost of tx
|
|
459
|
-
if (!all && targetAmount + fee
|
|
516
|
+
if (!all && targetAmount + fee <= inputsAmount)
|
|
460
517
|
return { indices: res, fee, weight: totalWeight, total: inputsAmount };
|
|
461
518
|
}
|
|
462
519
|
if (all) {
|
|
@@ -477,7 +534,7 @@ export class _Estimator {
|
|
|
477
534
|
private select(strategy: SelectionStrategy) {
|
|
478
535
|
if (strategy === 'all') {
|
|
479
536
|
return this.accumulate(
|
|
480
|
-
this.
|
|
537
|
+
this.normalizedInputs.map((_, j) => j),
|
|
481
538
|
false,
|
|
482
539
|
true,
|
|
483
540
|
true
|
|
@@ -531,7 +588,7 @@ export class _Estimator {
|
|
|
531
588
|
outputs = this.sortOutputs(outputs).map((i) => outputs[i]);
|
|
532
589
|
}
|
|
533
590
|
const res = {
|
|
534
|
-
inputs: inputs.map((i) => this.
|
|
591
|
+
inputs: inputs.map((i) => this.normalizedInputs[i].normalized),
|
|
535
592
|
outputs,
|
|
536
593
|
fee,
|
|
537
594
|
weight: this.opts.alwaysChange ? s.weight : changeWeight,
|
package/transaction.d.ts
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import * as P from 'micro-packed';
|
|
2
|
+
import { CustomScript } from './payment.js';
|
|
3
|
+
import * as psbt from './psbt.js';
|
|
4
|
+
import { Bytes } from './utils.js';
|
|
5
|
+
interface HDKey {
|
|
6
|
+
publicKey: Bytes;
|
|
7
|
+
privateKey: Bytes;
|
|
8
|
+
fingerprint: number;
|
|
9
|
+
derive(path: string): HDKey;
|
|
10
|
+
deriveChild(index: number): HDKey;
|
|
11
|
+
sign(hash: Bytes): Bytes;
|
|
12
|
+
}
|
|
13
|
+
export type Signer = Bytes | HDKey;
|
|
14
|
+
export declare const PRECISION = 8;
|
|
15
|
+
export declare const DEFAULT_VERSION = 2;
|
|
16
|
+
export declare const DEFAULT_LOCKTIME = 0;
|
|
17
|
+
export declare const DEFAULT_SEQUENCE = 4294967295;
|
|
18
|
+
export declare const Decimal: {
|
|
19
|
+
encode: (from: bigint) => string;
|
|
20
|
+
decode: (to: string) => bigint;
|
|
21
|
+
};
|
|
22
|
+
export declare const def: <T>(value: T | undefined, def: T) => T;
|
|
23
|
+
export declare function cloneDeep<T>(obj: T): T;
|
|
24
|
+
export type TxOpts = {
|
|
25
|
+
version?: number;
|
|
26
|
+
lockTime?: number;
|
|
27
|
+
PSBTVersion?: number;
|
|
28
|
+
/** @deprecated Use `allowUnknownOutputs` */
|
|
29
|
+
allowUnknowOutput?: boolean;
|
|
30
|
+
allowUnknownOutputs?: boolean;
|
|
31
|
+
/** @deprecated Use `allowUnknownInputs` */
|
|
32
|
+
allowUnknowInput?: boolean;
|
|
33
|
+
allowUnknownInputs?: boolean;
|
|
34
|
+
disableScriptCheck?: boolean;
|
|
35
|
+
bip174jsCompat?: boolean;
|
|
36
|
+
allowLegacyWitnessUtxo?: boolean;
|
|
37
|
+
lowR?: boolean;
|
|
38
|
+
customScripts?: CustomScript[];
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Internal, exported only for backwards-compat. Use `SigHash` instead.
|
|
42
|
+
* @deprecated
|
|
43
|
+
*/
|
|
44
|
+
export declare enum SignatureHash {
|
|
45
|
+
DEFAULT = 0,
|
|
46
|
+
ALL = 1,
|
|
47
|
+
NONE = 2,
|
|
48
|
+
SINGLE = 3,
|
|
49
|
+
ANYONECANPAY = 128
|
|
50
|
+
}
|
|
51
|
+
export declare enum SigHash {
|
|
52
|
+
DEFAULT = 0,
|
|
53
|
+
ALL = 1,
|
|
54
|
+
NONE = 2,
|
|
55
|
+
SINGLE = 3,
|
|
56
|
+
DEFAULT_ANYONECANPAY = 128,
|
|
57
|
+
ALL_ANYONECANPAY = 129,
|
|
58
|
+
NONE_ANYONECANPAY = 130,
|
|
59
|
+
SINGLE_ANYONECANPAY = 131
|
|
60
|
+
}
|
|
61
|
+
export type TransactionInputRequired = {
|
|
62
|
+
txid: Bytes;
|
|
63
|
+
index: number;
|
|
64
|
+
sequence: number;
|
|
65
|
+
finalScriptSig: Bytes;
|
|
66
|
+
};
|
|
67
|
+
export declare function inputBeforeSign(i: psbt.TransactionInput): TransactionInputRequired;
|
|
68
|
+
declare function validateOpts(opts: TxOpts): Readonly<{
|
|
69
|
+
version: number;
|
|
70
|
+
lockTime: number;
|
|
71
|
+
PSBTVersion: number;
|
|
72
|
+
/** @deprecated Use `allowUnknownOutputs` */
|
|
73
|
+
allowUnknowOutput?: boolean;
|
|
74
|
+
allowUnknownOutputs?: boolean;
|
|
75
|
+
/** @deprecated Use `allowUnknownInputs` */
|
|
76
|
+
allowUnknowInput?: boolean;
|
|
77
|
+
allowUnknownInputs?: boolean;
|
|
78
|
+
disableScriptCheck?: boolean;
|
|
79
|
+
bip174jsCompat?: boolean;
|
|
80
|
+
allowLegacyWitnessUtxo?: boolean;
|
|
81
|
+
lowR?: boolean;
|
|
82
|
+
customScripts?: CustomScript[];
|
|
83
|
+
}>;
|
|
84
|
+
export declare class Transaction {
|
|
85
|
+
private global;
|
|
86
|
+
private inputs;
|
|
87
|
+
private outputs;
|
|
88
|
+
readonly opts: ReturnType<typeof validateOpts>;
|
|
89
|
+
constructor(opts?: TxOpts);
|
|
90
|
+
static fromRaw(raw: Bytes, opts?: TxOpts): Transaction;
|
|
91
|
+
static fromPSBT(psbt_: Bytes, opts?: TxOpts): Transaction;
|
|
92
|
+
toPSBT(PSBTVersion?: number): Uint8Array;
|
|
93
|
+
get lockTime(): number;
|
|
94
|
+
get version(): number;
|
|
95
|
+
private inputStatus;
|
|
96
|
+
private inputSighash;
|
|
97
|
+
private signStatus;
|
|
98
|
+
get isFinal(): boolean;
|
|
99
|
+
get hasWitnesses(): boolean;
|
|
100
|
+
get weight(): number;
|
|
101
|
+
get vsize(): number;
|
|
102
|
+
toBytes(withScriptSig?: boolean, withWitness?: boolean): Uint8Array;
|
|
103
|
+
get unsignedTx(): Bytes;
|
|
104
|
+
get hex(): string;
|
|
105
|
+
get hash(): string;
|
|
106
|
+
get id(): string;
|
|
107
|
+
private checkInputIdx;
|
|
108
|
+
getInput(idx: number): psbt.PSBTKeyMapKeys<{
|
|
109
|
+
readonly nonWitnessUtxo: readonly [0, false, P.CoderType<P.StructInput<{
|
|
110
|
+
version: number;
|
|
111
|
+
segwitFlag: boolean | undefined;
|
|
112
|
+
inputs: P.StructInput<{
|
|
113
|
+
txid: any;
|
|
114
|
+
index: any;
|
|
115
|
+
finalScriptSig: any;
|
|
116
|
+
sequence: any;
|
|
117
|
+
}>[];
|
|
118
|
+
outputs: P.StructInput<{
|
|
119
|
+
amount: any;
|
|
120
|
+
script: any;
|
|
121
|
+
}>[];
|
|
122
|
+
witnesses: P.Option<Uint8Array[][]>;
|
|
123
|
+
lockTime: number;
|
|
124
|
+
}>>, readonly [], readonly [0, 2], false];
|
|
125
|
+
readonly witnessUtxo: readonly [1, false, P.CoderType<P.StructInput<{
|
|
126
|
+
amount: bigint;
|
|
127
|
+
script: Uint8Array;
|
|
128
|
+
}>>, readonly [], readonly [0, 2], false];
|
|
129
|
+
readonly partialSig: readonly [2, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
130
|
+
readonly sighashType: readonly [3, false, P.CoderType<number>, readonly [], readonly [0, 2], false];
|
|
131
|
+
readonly redeemScript: readonly [4, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
132
|
+
readonly witnessScript: readonly [5, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
133
|
+
readonly bip32Derivation: readonly [6, P.CoderType<Uint8Array>, P.CoderType<P.StructInput<{
|
|
134
|
+
fingerprint: number;
|
|
135
|
+
path: number[];
|
|
136
|
+
}>>, readonly [], readonly [0, 2], false];
|
|
137
|
+
readonly finalScriptSig: readonly [7, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
138
|
+
readonly finalScriptWitness: readonly [8, false, P.CoderType<Uint8Array[]>, readonly [], readonly [0, 2], false];
|
|
139
|
+
readonly porCommitment: readonly [9, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
140
|
+
readonly ripemd160: readonly [10, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
141
|
+
readonly sha256: readonly [11, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
142
|
+
readonly hash160: readonly [12, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
143
|
+
readonly hash256: readonly [13, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
144
|
+
readonly txid: readonly [14, false, P.CoderType<Uint8Array>, readonly [2], readonly [2], true];
|
|
145
|
+
readonly index: readonly [15, false, P.CoderType<number>, readonly [2], readonly [2], true];
|
|
146
|
+
readonly sequence: readonly [16, false, P.CoderType<number>, readonly [], readonly [2], true];
|
|
147
|
+
readonly requiredTimeLocktime: readonly [17, false, P.CoderType<number>, readonly [], readonly [2], false];
|
|
148
|
+
readonly requiredHeightLocktime: readonly [18, false, P.CoderType<number>, readonly [], readonly [2], false];
|
|
149
|
+
readonly tapKeySig: readonly [19, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
150
|
+
readonly tapScriptSig: readonly [20, P.CoderType<P.StructInput<{
|
|
151
|
+
pubKey: Uint8Array;
|
|
152
|
+
leafHash: Uint8Array;
|
|
153
|
+
}>>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
154
|
+
readonly tapLeafScript: readonly [21, P.CoderType<P.StructInput<{
|
|
155
|
+
version: number;
|
|
156
|
+
internalKey: Uint8Array;
|
|
157
|
+
merklePath: Uint8Array[];
|
|
158
|
+
}>>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
159
|
+
readonly tapBip32Derivation: readonly [22, P.CoderType<Uint8Array>, P.CoderType<P.StructInput<{
|
|
160
|
+
hashes: Uint8Array[];
|
|
161
|
+
der: P.StructInput<{
|
|
162
|
+
fingerprint: any;
|
|
163
|
+
path: any;
|
|
164
|
+
}>;
|
|
165
|
+
}>>, readonly [], readonly [0, 2], false];
|
|
166
|
+
readonly tapInternalKey: readonly [23, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
167
|
+
readonly tapMerkleRoot: readonly [24, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
168
|
+
readonly proprietary: readonly [252, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
169
|
+
}>;
|
|
170
|
+
get inputsLength(): number;
|
|
171
|
+
addInput(input: psbt.TransactionInputUpdate, _ignoreSignStatus?: boolean): number;
|
|
172
|
+
updateInput(idx: number, input: psbt.TransactionInputUpdate, _ignoreSignStatus?: boolean): void;
|
|
173
|
+
private checkOutputIdx;
|
|
174
|
+
getOutput(idx: number): psbt.PSBTKeyMapKeys<{
|
|
175
|
+
readonly redeemScript: readonly [0, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
176
|
+
readonly witnessScript: readonly [1, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
177
|
+
readonly bip32Derivation: readonly [2, P.CoderType<Uint8Array>, P.CoderType<P.StructInput<{
|
|
178
|
+
fingerprint: number;
|
|
179
|
+
path: number[];
|
|
180
|
+
}>>, readonly [], readonly [0, 2], false];
|
|
181
|
+
readonly amount: readonly [3, false, P.CoderType<bigint>, readonly [2], readonly [2], true];
|
|
182
|
+
readonly script: readonly [4, false, P.CoderType<Uint8Array>, readonly [2], readonly [2], true];
|
|
183
|
+
readonly tapInternalKey: readonly [5, false, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
184
|
+
readonly tapTree: readonly [6, false, P.CoderType<P.StructInput<{
|
|
185
|
+
depth: number;
|
|
186
|
+
version: number;
|
|
187
|
+
script: Uint8Array;
|
|
188
|
+
}>[]>, readonly [], readonly [0, 2], false];
|
|
189
|
+
readonly tapBip32Derivation: readonly [7, P.CoderType<Uint8Array>, P.CoderType<P.StructInput<{
|
|
190
|
+
hashes: Uint8Array[];
|
|
191
|
+
der: P.StructInput<{
|
|
192
|
+
fingerprint: any;
|
|
193
|
+
path: any;
|
|
194
|
+
}>;
|
|
195
|
+
}>>, readonly [], readonly [0, 2], false];
|
|
196
|
+
readonly proprietary: readonly [252, P.CoderType<Uint8Array>, P.CoderType<Uint8Array>, readonly [], readonly [0, 2], false];
|
|
197
|
+
}>;
|
|
198
|
+
getOutputAddress(idx: number, network?: {
|
|
199
|
+
bech32: string;
|
|
200
|
+
pubKeyHash: number;
|
|
201
|
+
scriptHash: number;
|
|
202
|
+
wif: number;
|
|
203
|
+
}): string | undefined;
|
|
204
|
+
get outputsLength(): number;
|
|
205
|
+
private normalizeOutput;
|
|
206
|
+
addOutput(o: psbt.TransactionOutputUpdate, _ignoreSignStatus?: boolean): number;
|
|
207
|
+
updateOutput(idx: number, output: psbt.TransactionOutputUpdate, _ignoreSignStatus?: boolean): void;
|
|
208
|
+
addOutputAddress(address: string, amount: bigint, network?: {
|
|
209
|
+
bech32: string;
|
|
210
|
+
pubKeyHash: number;
|
|
211
|
+
scriptHash: number;
|
|
212
|
+
wif: number;
|
|
213
|
+
}): number;
|
|
214
|
+
get fee(): bigint;
|
|
215
|
+
private preimageLegacy;
|
|
216
|
+
preimageWitnessV0(idx: number, prevOutScript: Bytes, hashType: number, amount: bigint): Uint8Array;
|
|
217
|
+
preimageWitnessV1(idx: number, prevOutScript: Bytes[], hashType: number, amount: bigint[], codeSeparator?: number, leafScript?: Bytes, leafVer?: number, annex?: Bytes): Uint8Array;
|
|
218
|
+
signIdx(privateKey: Signer, idx: number, allowedSighash?: SigHash[], _auxRand?: Bytes): boolean;
|
|
219
|
+
sign(privateKey: Signer, allowedSighash?: number[], _auxRand?: Bytes): number;
|
|
220
|
+
finalizeIdx(idx: number): void;
|
|
221
|
+
finalize(): void;
|
|
222
|
+
extract(): Uint8Array;
|
|
223
|
+
combine(other: Transaction): this;
|
|
224
|
+
clone(): Transaction;
|
|
225
|
+
}
|
|
226
|
+
export declare function PSBTCombine(psbts: Bytes[]): Bytes;
|
|
227
|
+
export declare function bip32Path(path: string): number[];
|
|
228
|
+
export {};
|
|
229
|
+
//# sourceMappingURL=transaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["src/transaction.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.Transaction = exports.SigHash = exports.SignatureHash = exports.def = exports.Decimal = exports.DEFAULT_SEQUENCE = exports.DEFAULT_LOCKTIME = exports.DEFAULT_VERSION = exports.PRECISION = void 0;
|
|
4
|
+
exports.cloneDeep = cloneDeep;
|
|
5
|
+
exports.inputBeforeSign = inputBeforeSign;
|
|
6
|
+
exports.PSBTCombine = PSBTCombine;
|
|
7
|
+
exports.bip32Path = bip32Path;
|
|
4
8
|
const P = require("micro-packed");
|
|
5
9
|
const base_1 = require("@scure/base");
|
|
6
10
|
const payment_js_1 = require("./payment.js");
|
|
7
11
|
const psbt = require("./psbt.js"); // circular
|
|
8
12
|
const script_js_1 = require("./script.js");
|
|
13
|
+
const script_js_2 = require("./script.js");
|
|
9
14
|
const utils_js_1 = require("./utils.js");
|
|
10
15
|
const u = require("./utils.js");
|
|
11
16
|
const utxo_js_1 = require("./utxo.js"); // circular
|
|
@@ -26,7 +31,7 @@ function cloneDeep(obj) {
|
|
|
26
31
|
if (Array.isArray(obj))
|
|
27
32
|
return obj.map((i) => cloneDeep(i));
|
|
28
33
|
// slice of nodejs Buffer doesn't copy
|
|
29
|
-
else if (
|
|
34
|
+
else if ((0, utils_js_1.isBytes)(obj))
|
|
30
35
|
return Uint8Array.from(obj);
|
|
31
36
|
// immutable
|
|
32
37
|
else if (['number', 'bigint', 'boolean', 'string', 'undefined'].includes(typeof obj))
|
|
@@ -40,7 +45,6 @@ function cloneDeep(obj) {
|
|
|
40
45
|
}
|
|
41
46
|
throw new Error(`cloneDeep: unknown type=${obj} (${typeof obj})`);
|
|
42
47
|
}
|
|
43
|
-
exports.cloneDeep = cloneDeep;
|
|
44
48
|
/**
|
|
45
49
|
* Internal, exported only for backwards-compat. Use `SigHash` instead.
|
|
46
50
|
* @deprecated
|
|
@@ -88,7 +92,6 @@ function inputBeforeSign(i) {
|
|
|
88
92
|
finalScriptSig: (0, exports.def)(i.finalScriptSig, P.EMPTY),
|
|
89
93
|
};
|
|
90
94
|
}
|
|
91
|
-
exports.inputBeforeSign = inputBeforeSign;
|
|
92
95
|
function cleanFinalInput(i) {
|
|
93
96
|
for (const _k in i) {
|
|
94
97
|
const k = _k;
|
|
@@ -177,7 +180,7 @@ class Transaction {
|
|
|
177
180
|
}
|
|
178
181
|
// Import
|
|
179
182
|
static fromRaw(raw, opts = {}) {
|
|
180
|
-
const parsed =
|
|
183
|
+
const parsed = script_js_2.RawTx.decode(raw);
|
|
181
184
|
const tx = new Transaction({ ...opts, version: parsed.version, lockTime: parsed.lockTime });
|
|
182
185
|
for (const o of parsed.outputs)
|
|
183
186
|
tx.addOutput(o);
|
|
@@ -231,6 +234,11 @@ class Transaction {
|
|
|
231
234
|
toPSBT(PSBTVersion = this.opts.PSBTVersion) {
|
|
232
235
|
if (PSBTVersion !== 0 && PSBTVersion !== 2)
|
|
233
236
|
throw new Error(`Wrong PSBT version=${PSBTVersion}`);
|
|
237
|
+
// if (PSBTVersion === 0 && this.inputs.length === 0) {
|
|
238
|
+
// throw new Error(
|
|
239
|
+
// 'PSBT version=0 export for transaction without inputs disabled, please use version=2. Please check `toPSBT` method for explanation.'
|
|
240
|
+
// );
|
|
241
|
+
// }
|
|
234
242
|
const inputs = this.inputs.map((i) => psbt.cleanPSBTFields(PSBTVersion, psbt.PSBTInput, i));
|
|
235
243
|
for (const inp of inputs) {
|
|
236
244
|
// Don't serialize empty fields
|
|
@@ -244,7 +252,21 @@ class Transaction {
|
|
|
244
252
|
const outputs = this.outputs.map((i) => psbt.cleanPSBTFields(PSBTVersion, psbt.PSBTOutput, i));
|
|
245
253
|
const global = { ...this.global };
|
|
246
254
|
if (PSBTVersion === 0) {
|
|
247
|
-
|
|
255
|
+
/*
|
|
256
|
+
- Bitcoin raw transaction expects to have at least 1 input because it uses case with zero inputs as marker for SegWit
|
|
257
|
+
- this means we cannot serialize raw tx with zero inputs since it will be parsed as SegWit tx
|
|
258
|
+
- Parsing of PSBTv0 depends on unsignedTx (it looks for input count here)
|
|
259
|
+
- BIP-174 requires old serialization format (without witnesses) inside global, which solves this
|
|
260
|
+
*/
|
|
261
|
+
global.unsignedTx = script_js_2.RawOldTx.decode(script_js_2.RawOldTx.encode({
|
|
262
|
+
version: this.version,
|
|
263
|
+
lockTime: this.lockTime,
|
|
264
|
+
inputs: this.inputs.map(inputBeforeSign).map((i) => ({
|
|
265
|
+
...i,
|
|
266
|
+
finalScriptSig: P.EMPTY,
|
|
267
|
+
})),
|
|
268
|
+
outputs: this.outputs.map(outputBeforeSign),
|
|
269
|
+
}));
|
|
248
270
|
delete global.fallbackLocktime;
|
|
249
271
|
delete global.txVersion;
|
|
250
272
|
}
|
|
@@ -318,7 +340,8 @@ class Transaction {
|
|
|
318
340
|
// We will lose some vectors -> smaller test coverage of preimages (very important!)
|
|
319
341
|
inputSighash(idx) {
|
|
320
342
|
this.checkInputIdx(idx);
|
|
321
|
-
const
|
|
343
|
+
const inputSighash = this.inputs[idx].sighashType;
|
|
344
|
+
const sighash = inputSighash === undefined ? SignatureHash.DEFAULT : inputSighash;
|
|
322
345
|
// ALL or DEFAULT -- everything signed
|
|
323
346
|
// NONE -- all inputs + no outputs
|
|
324
347
|
// SINGLE -- all inputs + output with same index
|
|
@@ -390,7 +413,7 @@ class Transaction {
|
|
|
390
413
|
for (const i of this.inputs) {
|
|
391
414
|
out += 160 + 4 * script_js_1.VarBytes.encode(i.finalScriptSig || P.EMPTY).length;
|
|
392
415
|
if (this.hasWitnesses && i.finalScriptWitness)
|
|
393
|
-
out +=
|
|
416
|
+
out += script_js_2.RawWitness.encode(i.finalScriptWitness).length;
|
|
394
417
|
}
|
|
395
418
|
return out;
|
|
396
419
|
}
|
|
@@ -398,7 +421,7 @@ class Transaction {
|
|
|
398
421
|
return (0, utxo_js_1.toVsize)(this.weight);
|
|
399
422
|
}
|
|
400
423
|
toBytes(withScriptSig = false, withWitness = false) {
|
|
401
|
-
return
|
|
424
|
+
return script_js_2.RawTx.encode({
|
|
402
425
|
version: this.version,
|
|
403
426
|
lockTime: this.lockTime,
|
|
404
427
|
inputs: this.inputs.map(inputBeforeSign).map((i) => ({
|
|
@@ -464,6 +487,12 @@ class Transaction {
|
|
|
464
487
|
this.checkOutputIdx(idx);
|
|
465
488
|
return cloneDeep(this.outputs[idx]);
|
|
466
489
|
}
|
|
490
|
+
getOutputAddress(idx, network = utils_js_1.NETWORK) {
|
|
491
|
+
const out = this.getOutput(idx);
|
|
492
|
+
if (!out.script)
|
|
493
|
+
return;
|
|
494
|
+
return (0, payment_js_1.Address)(network).encode(payment_js_1.OutScript.decode(out.script));
|
|
495
|
+
}
|
|
467
496
|
get outputsLength() {
|
|
468
497
|
return this.outputs.length;
|
|
469
498
|
}
|
|
@@ -472,7 +501,7 @@ class Transaction {
|
|
|
472
501
|
if (amount === undefined)
|
|
473
502
|
amount = cur?.amount;
|
|
474
503
|
if (typeof amount !== 'bigint')
|
|
475
|
-
throw new Error(
|
|
504
|
+
throw new Error(`Wrong amount type, should be of type bigint in sats, but got ${amount} of type ${typeof amount}`);
|
|
476
505
|
if (typeof script === 'string')
|
|
477
506
|
script = base_1.hex.decode(script);
|
|
478
507
|
if (script === undefined)
|
|
@@ -555,7 +584,7 @@ class Transaction {
|
|
|
555
584
|
else if (isSingle) {
|
|
556
585
|
outputs = outputs.slice(0, idx).fill(EMPTY_OUTPUT).concat([outputs[idx]]);
|
|
557
586
|
}
|
|
558
|
-
const tmpTx =
|
|
587
|
+
const tmpTx = script_js_2.RawTx.encode({
|
|
559
588
|
lockTime: this.lockTime,
|
|
560
589
|
version: this.version,
|
|
561
590
|
segwitFlag: false,
|
|
@@ -576,10 +605,10 @@ class Transaction {
|
|
|
576
605
|
if (!isAny && !isSingle && !isNone)
|
|
577
606
|
sequenceHash = u.sha256x2(...inputs.map((i) => P.U32LE.encode(i.sequence)));
|
|
578
607
|
if (!isSingle && !isNone) {
|
|
579
|
-
outputHash = u.sha256x2(...outputs.map(
|
|
608
|
+
outputHash = u.sha256x2(...outputs.map(script_js_2.RawOutput.encode));
|
|
580
609
|
}
|
|
581
610
|
else if (isSingle && idx < outputs.length)
|
|
582
|
-
outputHash = u.sha256x2(
|
|
611
|
+
outputHash = u.sha256x2(script_js_2.RawOutput.encode(outputs[idx]));
|
|
583
612
|
const input = inputs[idx];
|
|
584
613
|
return u.sha256x2(P.I32LE.encode(this.version), inputHash, sequenceHash, P.bytes(32, true).encode(input.txid), P.U32LE.encode(input.index), script_js_1.VarBytes.encode(prevOutScript), P.U64LE.encode(amount), P.U32LE.encode(input.sequence), outputHash, P.U32LE.encode(this.lockTime), P.U32LE.encode(hashType));
|
|
585
614
|
}
|
|
@@ -607,7 +636,7 @@ class Transaction {
|
|
|
607
636
|
].map((i) => u.sha256((0, utils_js_1.concatBytes)(...i))));
|
|
608
637
|
}
|
|
609
638
|
if (outType === SignatureHash.ALL) {
|
|
610
|
-
out.push(u.sha256((0, utils_js_1.concatBytes)(...outputs.map(
|
|
639
|
+
out.push(u.sha256((0, utils_js_1.concatBytes)(...outputs.map(script_js_2.RawOutput.encode))));
|
|
611
640
|
}
|
|
612
641
|
const spendType = (annex ? 1 : 0) | (leafScript ? 2 : 0);
|
|
613
642
|
out.push(new Uint8Array([spendType]));
|
|
@@ -620,7 +649,7 @@ class Transaction {
|
|
|
620
649
|
if (spendType & 1)
|
|
621
650
|
out.push(u.sha256(script_js_1.VarBytes.encode(annex || P.EMPTY)));
|
|
622
651
|
if (outType === SignatureHash.SINGLE)
|
|
623
|
-
out.push(idx < outputs.length ? u.sha256(
|
|
652
|
+
out.push(idx < outputs.length ? u.sha256(script_js_2.RawOutput.encode(outputs[idx])) : EMPTY32);
|
|
624
653
|
if (leafScript)
|
|
625
654
|
out.push((0, payment_js_1.tapLeafHash)(leafScript, leafVer), P.U8.encode(0), P.I32LE.encode(codeSeparator));
|
|
626
655
|
return u.tagSchnorr('TapSighash', ...out);
|
|
@@ -676,8 +705,6 @@ class Transaction {
|
|
|
676
705
|
// Taproot
|
|
677
706
|
const prevOut = (0, utxo_js_1.getPrevOut)(input);
|
|
678
707
|
if (inputType.txType === 'taproot') {
|
|
679
|
-
if (input.tapBip32Derivation)
|
|
680
|
-
throw new Error('tapBip32Derivation unsupported');
|
|
681
708
|
const prevOuts = this.inputs.map(utxo_js_1.getPrevOut);
|
|
682
709
|
const prevOutScript = prevOuts.map((i) => i.script);
|
|
683
710
|
const amount = prevOuts.map((i) => i.amount);
|
|
@@ -969,8 +996,10 @@ class Transaction {
|
|
|
969
996
|
throw new Error(`Transaction/combine: different ${k} length this=${this[k].length} other=${other[k].length}`);
|
|
970
997
|
}
|
|
971
998
|
}
|
|
972
|
-
const thisUnsigned = this.global.unsignedTx ?
|
|
973
|
-
const otherUnsigned = other.global.unsignedTx
|
|
999
|
+
const thisUnsigned = this.global.unsignedTx ? script_js_2.RawOldTx.encode(this.global.unsignedTx) : P.EMPTY;
|
|
1000
|
+
const otherUnsigned = other.global.unsignedTx
|
|
1001
|
+
? script_js_2.RawOldTx.encode(other.global.unsignedTx)
|
|
1002
|
+
: P.EMPTY;
|
|
974
1003
|
if (!(0, utils_js_1.equalBytes)(thisUnsigned, otherUnsigned))
|
|
975
1004
|
throw new Error(`Transaction/combine: different unsigned tx`);
|
|
976
1005
|
this.global = psbt.mergeKeyMap(psbt.PSBTGlobal, this.global, other.global);
|
|
@@ -994,7 +1023,6 @@ function PSBTCombine(psbts) {
|
|
|
994
1023
|
tx.combine(Transaction.fromPSBT(psbts[i]));
|
|
995
1024
|
return tx.toPSBT();
|
|
996
1025
|
}
|
|
997
|
-
exports.PSBTCombine = PSBTCombine;
|
|
998
1026
|
// Copy-pasted from bip32 derive, maybe do something like 'bip32.parsePath'?
|
|
999
1027
|
const HARDENED_OFFSET = 0x80000000;
|
|
1000
1028
|
function bip32Path(path) {
|
|
@@ -1018,5 +1046,4 @@ function bip32Path(path) {
|
|
|
1018
1046
|
}
|
|
1019
1047
|
return out;
|
|
1020
1048
|
}
|
|
1021
|
-
exports.bip32Path = bip32Path;
|
|
1022
1049
|
//# sourceMappingURL=transaction.js.map
|