@btc-vision/bitcoin 6.5.1 → 6.5.3
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/browser/chunks/crypto-0PweVewC.js +2033 -0
- package/browser/chunks/{payments-BE4vwHhV.js → payments-CgasufRS.js} +410 -408
- package/browser/chunks/psbt-BIwOrKer.js +4096 -0
- package/browser/chunks/{script-COWGdiOo.js → script-CROJPzz_.js} +96 -96
- package/browser/chunks/{transaction-BiXwH2v4.js → transaction-DchBu35N.js} +158 -147
- package/browser/chunks/{utils-BKmkTzNZ.js → utils-CO5kmxe9.js} +225 -223
- package/browser/crypto.d.ts +1 -1
- package/browser/hooks/HookedSigner.d.ts +1 -1
- package/browser/index.d.ts +23 -1
- package/browser/index.js +6 -6
- package/browser/payments/index.d.ts +2 -2
- package/browser/payments/lazy.d.ts +1 -1
- package/browser/psbt/bip371.d.ts +5 -1
- package/browser/psbt.d.ts +1 -1
- package/browser/typeforce.d.ts +38 -0
- package/browser/types.d.ts +22 -20
- package/build/address.js +2 -2
- package/build/bip66.js +2 -2
- package/build/block.js +2 -2
- package/build/crypto.d.ts +1 -1
- package/build/crypto.js +2 -3
- package/build/hooks/HookedSigner.d.ts +1 -1
- package/build/index.d.ts +23 -1
- package/build/payments/bip341.js +1 -1
- package/build/payments/index.d.ts +2 -2
- package/build/payments/lazy.d.ts +1 -1
- package/build/payments/p2op.js +3 -3
- package/build/payments/p2pk.js +1 -1
- package/build/payments/p2pkh.js +3 -3
- package/build/payments/p2sh.js +3 -3
- package/build/payments/p2tr.js +9 -5
- package/build/payments/p2wpkh.js +3 -3
- package/build/payments/p2wsh.js +2 -2
- package/build/psbt/bip371.d.ts +5 -1
- package/build/psbt/bip371.js +10 -7
- package/build/psbt/psbtutils.js +5 -4
- package/build/psbt.d.ts +1 -1
- package/build/psbt.js +78 -45
- package/build/script.js +2 -2
- package/build/script_signature.js +7 -7
- package/build/transaction.js +22 -10
- package/build/tsconfig.tsbuildinfo +1 -0
- package/build/types.d.ts +22 -20
- package/build/types.js +10 -9
- package/package.json +32 -57
- package/src/address.ts +2 -2
- package/src/bip66.ts +2 -2
- package/src/block.ts +8 -5
- package/src/crypto.ts +3 -4
- package/src/ecc_lib.ts +1 -1
- package/src/hooks/HookedSigner.ts +1 -1
- package/src/index.ts +34 -12
- package/src/payments/bip341.ts +1 -1
- package/src/payments/embed.ts +1 -2
- package/src/payments/index.ts +4 -4
- package/src/payments/lazy.ts +3 -3
- package/src/payments/p2op.ts +4 -3
- package/src/payments/p2pk.ts +1 -1
- package/src/payments/p2pkh.ts +3 -3
- package/src/payments/p2sh.ts +13 -5
- package/src/payments/p2tr.ts +8 -9
- package/src/payments/p2wpkh.ts +3 -3
- package/src/payments/p2wsh.ts +4 -4
- package/src/psbt/bip371.ts +22 -13
- package/src/psbt/psbtutils.ts +8 -5
- package/src/psbt.ts +127 -80
- package/src/script.ts +4 -4
- package/src/script_signature.ts +7 -7
- package/src/transaction.ts +31 -18
- package/src/typeforce.d.ts +38 -0
- package/src/types.ts +34 -29
- package/test/address.spec.ts +12 -4
- package/test/bitcoin.core.spec.ts +1 -1
- package/test/block.spec.ts +1 -1
- package/test/bufferutils.spec.ts +1 -1
- package/test/crypto.spec.ts +3 -2
- package/test/fixtures/address.json +1 -1
- package/test/integration/addresses.spec.ts +1 -1
- package/test/integration/bip32.spec.ts +2 -2
- package/test/integration/blocks.spec.ts +1 -1
- package/test/integration/cltv.spec.ts +3 -3
- package/test/integration/csv.spec.ts +3 -3
- package/test/integration/payments.spec.ts +1 -1
- package/test/integration/taproot.spec.ts +8 -7
- package/test/integration/transactions.spec.ts +2 -2
- package/test/payments.spec.ts +4 -3
- package/test/psbt.spec.ts +106 -74
- package/test/script.spec.ts +73 -7
- package/test/script_number.spec.ts +1 -1
- package/test/script_signature.spec.ts +1 -1
- package/test/transaction.spec.ts +1 -1
- package/test/tsconfig.json +1 -1
- package/test/types.spec.ts +1 -1
- package/vitest.config.ts +16 -0
- package/.babelrc +0 -13
- package/.mocharc.json +0 -13
- package/browser/chunks/crypto-C6FlKKmp.js +0 -2006
- package/browser/chunks/psbt-Dlosf9CT.js +0 -3853
- package/cjs/package.json +0 -3
- package/gulpfile.js +0 -42
- package/src/crypto/crypto-browser.js +0 -75
- package/test/ts-node-register.js +0 -7
- package/webpack.config.js +0 -79
package/src/psbt.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { Psbt as PsbtBase } from 'bip174';
|
|
2
2
|
import * as varuint from 'bip174/src/lib/converter/varint.js';
|
|
3
|
+
|
|
4
|
+
interface VaruintDecode {
|
|
5
|
+
(buffer: Buffer, offset?: number): number;
|
|
6
|
+
bytes: number;
|
|
7
|
+
}
|
|
8
|
+
const varuintDecode = varuint.decode as VaruintDecode;
|
|
3
9
|
import {
|
|
4
10
|
Bip32Derivation,
|
|
5
11
|
KeyValue,
|
|
@@ -16,7 +22,7 @@ import {
|
|
|
16
22
|
TransactionFromBuffer,
|
|
17
23
|
} from 'bip174/src/lib/interfaces.js';
|
|
18
24
|
import { checkForInput, checkForOutput } from 'bip174/src/lib/utils.js';
|
|
19
|
-
import { BIP32Interface } from 'bip32';
|
|
25
|
+
import { BIP32Interface } from '@btc-vision/bip32';
|
|
20
26
|
import { ECPairInterface } from 'ecpair';
|
|
21
27
|
import { fromOutputScript, isUnknownSegwitVersion, toOutputScript } from './address.js';
|
|
22
28
|
import { cloneBuffer, reverseBuffer } from './bufferutils.js';
|
|
@@ -146,8 +152,8 @@ export class Psbt {
|
|
|
146
152
|
__NON_WITNESS_UTXO_TX_CACHE: [],
|
|
147
153
|
__NON_WITNESS_UTXO_BUF_CACHE: [],
|
|
148
154
|
__TX_IN_CACHE: {},
|
|
149
|
-
//
|
|
150
|
-
__TX: this.data.globalMap.unsignedTx.tx,
|
|
155
|
+
// unsignedTx.tx property is dynamically added by PsbtBase
|
|
156
|
+
__TX: (this.data.globalMap.unsignedTx as PsbtTransaction).tx,
|
|
151
157
|
__UNSAFE_SIGN_NONSEGWIT: false,
|
|
152
158
|
};
|
|
153
159
|
|
|
@@ -232,7 +238,8 @@ export class Psbt {
|
|
|
232
238
|
|
|
233
239
|
clone(): Psbt {
|
|
234
240
|
// TODO: more efficient cloning
|
|
235
|
-
|
|
241
|
+
const clonedOpts = JSON.parse(JSON.stringify(this.opts)) as PsbtOptsOptional;
|
|
242
|
+
return Psbt.fromBuffer(this.data.toBuffer(), clonedOpts);
|
|
236
243
|
}
|
|
237
244
|
|
|
238
245
|
setMaximumFeeRate(satoshiPerByte: number): void {
|
|
@@ -316,11 +323,13 @@ export class Psbt {
|
|
|
316
323
|
}
|
|
317
324
|
|
|
318
325
|
addOutput(outputData: PsbtOutputExtended): this {
|
|
326
|
+
const hasAddress = 'address' in outputData;
|
|
327
|
+
const hasScript = 'script' in outputData;
|
|
319
328
|
if (
|
|
320
329
|
arguments.length > 1 ||
|
|
321
330
|
!outputData ||
|
|
322
331
|
outputData.value === undefined ||
|
|
323
|
-
(
|
|
332
|
+
(!hasAddress && !hasScript)
|
|
324
333
|
) {
|
|
325
334
|
throw new Error(
|
|
326
335
|
`Invalid arguments for Psbt.addOutput. ` +
|
|
@@ -328,8 +337,8 @@ export class Psbt {
|
|
|
328
337
|
);
|
|
329
338
|
}
|
|
330
339
|
checkInputsForPartialSig(this.data.inputs, 'addOutput');
|
|
331
|
-
|
|
332
|
-
|
|
340
|
+
if (hasAddress) {
|
|
341
|
+
const { address } = outputData as PsbtOutputExtendedAddress;
|
|
333
342
|
const { network } = this.opts;
|
|
334
343
|
const script = toOutputScript(address, network);
|
|
335
344
|
outputData = Object.assign({}, outputData, { script });
|
|
@@ -367,17 +376,11 @@ export class Psbt {
|
|
|
367
376
|
this.data.inputs,
|
|
368
377
|
this.__CACHE,
|
|
369
378
|
disableOutputChecks,
|
|
370
|
-
)
|
|
379
|
+
);
|
|
371
380
|
}
|
|
372
381
|
|
|
373
382
|
getFee(disableOutputChecks: boolean = false): number {
|
|
374
|
-
return getTxCacheValue(
|
|
375
|
-
'__FEE',
|
|
376
|
-
'fee',
|
|
377
|
-
this.data.inputs,
|
|
378
|
-
this.__CACHE,
|
|
379
|
-
disableOutputChecks,
|
|
380
|
-
)!;
|
|
383
|
+
return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE, disableOutputChecks);
|
|
381
384
|
}
|
|
382
385
|
|
|
383
386
|
finalizeAllInputs(): this {
|
|
@@ -466,7 +469,7 @@ export class Psbt {
|
|
|
466
469
|
const results = range(this.data.inputs.length).map((idx) =>
|
|
467
470
|
this.validateSignaturesOfInput(idx, validator),
|
|
468
471
|
);
|
|
469
|
-
return results.reduce((final, res) => res
|
|
472
|
+
return results.reduce((final, res) => res && final, true);
|
|
470
473
|
}
|
|
471
474
|
|
|
472
475
|
validateSignaturesOfInput(
|
|
@@ -495,7 +498,7 @@ export class Psbt {
|
|
|
495
498
|
results.push(false);
|
|
496
499
|
}
|
|
497
500
|
}
|
|
498
|
-
if (results.every((v) => v
|
|
501
|
+
if (results.every((v) => !v)) {
|
|
499
502
|
throw new Error('No inputs were signed');
|
|
500
503
|
}
|
|
501
504
|
return this;
|
|
@@ -505,7 +508,7 @@ export class Psbt {
|
|
|
505
508
|
hdKeyPair: HDSigner | HDSignerAsync,
|
|
506
509
|
sighashTypes: number[] = [Transaction.SIGHASH_ALL],
|
|
507
510
|
): Promise<void> {
|
|
508
|
-
return new Promise((resolve, reject)
|
|
511
|
+
return new Promise((resolve, reject) => {
|
|
509
512
|
if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
|
|
510
513
|
return reject(new Error('Need HDSigner to sign input'));
|
|
511
514
|
}
|
|
@@ -525,7 +528,7 @@ export class Psbt {
|
|
|
525
528
|
);
|
|
526
529
|
}
|
|
527
530
|
return Promise.all(promises).then(() => {
|
|
528
|
-
if (results.every((v) => v
|
|
531
|
+
if (results.every((v) => !v)) {
|
|
529
532
|
return reject(new Error('No inputs were signed'));
|
|
530
533
|
}
|
|
531
534
|
resolve();
|
|
@@ -551,7 +554,7 @@ export class Psbt {
|
|
|
551
554
|
hdKeyPair: HDSigner | HDSignerAsync,
|
|
552
555
|
sighashTypes: number[] = [Transaction.SIGHASH_ALL],
|
|
553
556
|
): Promise<void> {
|
|
554
|
-
return new Promise((resolve, reject)
|
|
557
|
+
return new Promise((resolve, reject) => {
|
|
555
558
|
if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
|
|
556
559
|
return reject(new Error('Need HDSigner to sign input'));
|
|
557
560
|
}
|
|
@@ -585,7 +588,7 @@ export class Psbt {
|
|
|
585
588
|
results.push(false);
|
|
586
589
|
}
|
|
587
590
|
}
|
|
588
|
-
if (results.every((v) => v
|
|
591
|
+
if (results.every((v) => !v)) {
|
|
589
592
|
throw new Error('No inputs were signed');
|
|
590
593
|
}
|
|
591
594
|
return this;
|
|
@@ -595,7 +598,7 @@ export class Psbt {
|
|
|
595
598
|
keyPair: Signer | SignerAlternative | SignerAsync | BIP32Interface | ECPairInterface,
|
|
596
599
|
sighashTypes?: number[],
|
|
597
600
|
): Promise<void> {
|
|
598
|
-
return new Promise((resolve, reject)
|
|
601
|
+
return new Promise((resolve, reject) => {
|
|
599
602
|
if (!keyPair || !keyPair.publicKey)
|
|
600
603
|
return reject(new Error('Need Signer to sign input'));
|
|
601
604
|
|
|
@@ -617,7 +620,7 @@ export class Psbt {
|
|
|
617
620
|
);
|
|
618
621
|
}
|
|
619
622
|
return Promise.all(promises).then(() => {
|
|
620
|
-
if (results.every((v) => v
|
|
623
|
+
if (results.every((v) => !v)) {
|
|
621
624
|
return reject(new Error('No inputs were signed'));
|
|
622
625
|
}
|
|
623
626
|
resolve();
|
|
@@ -779,11 +782,15 @@ export class Psbt {
|
|
|
779
782
|
if (typeof keyPair.signSchnorr !== 'function')
|
|
780
783
|
throw new Error(`Need Schnorr Signer to sign taproot input #${inputIndex}.`);
|
|
781
784
|
|
|
785
|
+
const pubkey = Buffer.isBuffer(keyPair.publicKey)
|
|
786
|
+
? keyPair.publicKey
|
|
787
|
+
: Buffer.from(keyPair.publicKey);
|
|
788
|
+
|
|
782
789
|
const hashesForSig = getTaprootHashesForSig(
|
|
783
790
|
inputIndex,
|
|
784
791
|
input,
|
|
785
792
|
this.data.inputs,
|
|
786
|
-
|
|
793
|
+
pubkey,
|
|
787
794
|
this.__CACHE,
|
|
788
795
|
tapLeafHashToSign,
|
|
789
796
|
allowedSighashTypes,
|
|
@@ -791,9 +798,7 @@ export class Psbt {
|
|
|
791
798
|
|
|
792
799
|
if (!hashesForSig || !hashesForSig.length)
|
|
793
800
|
throw new Error(
|
|
794
|
-
`Can not sign for input #${inputIndex} with the key ${
|
|
795
|
-
'hex',
|
|
796
|
-
)}`,
|
|
801
|
+
`Can not sign for input #${inputIndex} with the key ${pubkey.toString('hex')}`,
|
|
797
802
|
);
|
|
798
803
|
|
|
799
804
|
return hashesForSig;
|
|
@@ -848,7 +853,8 @@ export class Psbt {
|
|
|
848
853
|
output: input.witnessUtxo.script,
|
|
849
854
|
signature: input.tapKeySig,
|
|
850
855
|
});
|
|
851
|
-
|
|
856
|
+
if (!payment.witness) throw new Error('Cannot finalize taproot key spend');
|
|
857
|
+
const finalScriptWitness = witnessStackToScriptWitness(payment.witness);
|
|
852
858
|
this.data.updateInput(inputIndex, { finalScriptWitness });
|
|
853
859
|
} else {
|
|
854
860
|
const { finalScriptWitness } = finalScriptsFunc(
|
|
@@ -878,13 +884,13 @@ export class Psbt {
|
|
|
878
884
|
const mySigs = pubkey ? partialSig.filter((sig) => sig.pubkey.equals(pubkey)) : partialSig;
|
|
879
885
|
if (mySigs.length < 1) throw new Error('No signatures for this pubkey');
|
|
880
886
|
const results: boolean[] = [];
|
|
881
|
-
let hashCache: Buffer;
|
|
882
|
-
let scriptCache: Buffer;
|
|
883
|
-
let sighashCache: number;
|
|
887
|
+
let hashCache: Buffer | undefined;
|
|
888
|
+
let scriptCache: Buffer | undefined;
|
|
889
|
+
let sighashCache: number | undefined;
|
|
884
890
|
for (const pSig of mySigs) {
|
|
885
891
|
const sig = bscript.signature.decode(pSig.signature);
|
|
886
892
|
const { hash, script } =
|
|
887
|
-
sighashCache
|
|
893
|
+
sighashCache !== sig.hashType || !hashCache || !scriptCache
|
|
888
894
|
? getHashForSig(
|
|
889
895
|
inputIndex,
|
|
890
896
|
Object.assign({}, input, {
|
|
@@ -893,14 +899,14 @@ export class Psbt {
|
|
|
893
899
|
this.__CACHE,
|
|
894
900
|
true,
|
|
895
901
|
)
|
|
896
|
-
: { hash: hashCache
|
|
902
|
+
: { hash: hashCache, script: scriptCache };
|
|
897
903
|
sighashCache = sig.hashType;
|
|
898
904
|
hashCache = hash;
|
|
899
905
|
scriptCache = script;
|
|
900
906
|
checkScriptForPubkey(pSig.pubkey, script, 'verify');
|
|
901
907
|
results.push(validator(pSig.pubkey, hash, sig.signature));
|
|
902
908
|
}
|
|
903
|
-
return results.every((res) => res
|
|
909
|
+
return results.every((res) => res);
|
|
904
910
|
}
|
|
905
911
|
|
|
906
912
|
private validateSignaturesOfTaprootInput(
|
|
@@ -960,18 +966,26 @@ export class Psbt {
|
|
|
960
966
|
): this {
|
|
961
967
|
//hookSigner(keyPair);
|
|
962
968
|
|
|
969
|
+
const pubkey = Buffer.isBuffer(keyPair.publicKey)
|
|
970
|
+
? keyPair.publicKey
|
|
971
|
+
: Buffer.from(keyPair.publicKey);
|
|
972
|
+
|
|
963
973
|
const { hash, sighashType } = getHashAndSighashType(
|
|
964
974
|
this.data.inputs,
|
|
965
975
|
inputIndex,
|
|
966
|
-
|
|
976
|
+
pubkey,
|
|
967
977
|
this.__CACHE,
|
|
968
978
|
sighashTypes,
|
|
969
979
|
);
|
|
970
980
|
|
|
981
|
+
const sig = keyPair.sign(hash);
|
|
971
982
|
const partialSig = [
|
|
972
983
|
{
|
|
973
|
-
pubkey
|
|
974
|
-
signature: bscript.signature.encode(
|
|
984
|
+
pubkey,
|
|
985
|
+
signature: bscript.signature.encode(
|
|
986
|
+
Buffer.isBuffer(sig) ? sig : Buffer.from(sig),
|
|
987
|
+
sighashType,
|
|
988
|
+
),
|
|
975
989
|
},
|
|
976
990
|
];
|
|
977
991
|
|
|
@@ -988,6 +1002,11 @@ export class Psbt {
|
|
|
988
1002
|
): this {
|
|
989
1003
|
//hookSigner(keyPair);
|
|
990
1004
|
|
|
1005
|
+
const pubkey = Buffer.isBuffer(keyPair.publicKey)
|
|
1006
|
+
? keyPair.publicKey
|
|
1007
|
+
: Buffer.from(keyPair.publicKey);
|
|
1008
|
+
|
|
1009
|
+
// checkTaprootHashesForSig validates signSchnorr exists
|
|
991
1010
|
const hashesForSig = this.checkTaprootHashesForSig(
|
|
992
1011
|
inputIndex,
|
|
993
1012
|
input,
|
|
@@ -995,11 +1014,15 @@ export class Psbt {
|
|
|
995
1014
|
tapLeafHashToSign,
|
|
996
1015
|
allowedSighashTypes,
|
|
997
1016
|
);
|
|
1017
|
+
const signSchnorr = (keyPair.signSchnorr as (h: Buffer) => Uint8Array).bind(keyPair);
|
|
1018
|
+
|
|
1019
|
+
const toBuffer = (data: Uint8Array | Buffer): Buffer =>
|
|
1020
|
+
Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
998
1021
|
|
|
999
1022
|
const tapKeySig: TapKeySig = hashesForSig
|
|
1000
1023
|
.filter((h) => !h.leafHash)
|
|
1001
1024
|
.map((h) =>
|
|
1002
|
-
serializeTaprootSignature(
|
|
1025
|
+
serializeTaprootSignature(toBuffer(signSchnorr(h.hash)), input.sighashType),
|
|
1003
1026
|
)[0];
|
|
1004
1027
|
|
|
1005
1028
|
const tapScriptSig: TapScriptSig[] = hashesForSig
|
|
@@ -1007,9 +1030,9 @@ export class Psbt {
|
|
|
1007
1030
|
.map(
|
|
1008
1031
|
(h) =>
|
|
1009
1032
|
({
|
|
1010
|
-
pubkey: toXOnly(
|
|
1033
|
+
pubkey: toXOnly(pubkey),
|
|
1011
1034
|
signature: serializeTaprootSignature(
|
|
1012
|
-
|
|
1035
|
+
toBuffer(signSchnorr(h.hash)),
|
|
1013
1036
|
input.sighashType,
|
|
1014
1037
|
),
|
|
1015
1038
|
leafHash: h.leafHash,
|
|
@@ -1034,19 +1057,24 @@ export class Psbt {
|
|
|
1034
1057
|
): Promise<void> {
|
|
1035
1058
|
//hookSigner(keyPair);
|
|
1036
1059
|
|
|
1060
|
+
const pubkey = Buffer.isBuffer(keyPair.publicKey)
|
|
1061
|
+
? keyPair.publicKey
|
|
1062
|
+
: Buffer.from(keyPair.publicKey);
|
|
1063
|
+
|
|
1037
1064
|
const { hash, sighashType } = getHashAndSighashType(
|
|
1038
1065
|
this.data.inputs,
|
|
1039
1066
|
inputIndex,
|
|
1040
|
-
|
|
1067
|
+
pubkey,
|
|
1041
1068
|
this.__CACHE,
|
|
1042
1069
|
sighashTypes,
|
|
1043
1070
|
);
|
|
1044
1071
|
|
|
1045
1072
|
return Promise.resolve(keyPair.sign(hash)).then((signature) => {
|
|
1073
|
+
const sig = Buffer.isBuffer(signature) ? signature : Buffer.from(signature);
|
|
1046
1074
|
const partialSig = [
|
|
1047
1075
|
{
|
|
1048
|
-
pubkey
|
|
1049
|
-
signature: bscript.signature.encode(
|
|
1076
|
+
pubkey,
|
|
1077
|
+
signature: bscript.signature.encode(sig, sighashType),
|
|
1050
1078
|
},
|
|
1051
1079
|
];
|
|
1052
1080
|
|
|
@@ -1063,6 +1091,11 @@ export class Psbt {
|
|
|
1063
1091
|
): Promise<void> {
|
|
1064
1092
|
//hookSigner(keyPair);
|
|
1065
1093
|
|
|
1094
|
+
const pubkey = Buffer.isBuffer(keyPair.publicKey)
|
|
1095
|
+
? keyPair.publicKey
|
|
1096
|
+
: Buffer.from(keyPair.publicKey);
|
|
1097
|
+
|
|
1098
|
+
// checkTaprootHashesForSig validates signSchnorr exists
|
|
1066
1099
|
const hashesForSig = this.checkTaprootHashesForSig(
|
|
1067
1100
|
inputIndex,
|
|
1068
1101
|
input,
|
|
@@ -1070,6 +1103,12 @@ export class Psbt {
|
|
|
1070
1103
|
tapLeafHash,
|
|
1071
1104
|
sighashTypes,
|
|
1072
1105
|
);
|
|
1106
|
+
const signSchnorr = (
|
|
1107
|
+
keyPair.signSchnorr as (hash: Buffer) => Uint8Array | Promise<Uint8Array>
|
|
1108
|
+
).bind(keyPair);
|
|
1109
|
+
|
|
1110
|
+
const toBuffer = (data: Uint8Array | Buffer): Buffer =>
|
|
1111
|
+
Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
1073
1112
|
|
|
1074
1113
|
const signaturePromises: Promise<
|
|
1075
1114
|
{ tapKeySig: Buffer } | { tapScriptSig: TapScriptSig[] }
|
|
@@ -1077,25 +1116,26 @@ export class Psbt {
|
|
|
1077
1116
|
|
|
1078
1117
|
const tapKeyHash = hashesForSig.filter((h) => !h.leafHash)[0];
|
|
1079
1118
|
if (tapKeyHash) {
|
|
1080
|
-
const tapKeySigPromise = Promise.resolve(
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
},
|
|
1086
|
-
);
|
|
1119
|
+
const tapKeySigPromise = Promise.resolve(signSchnorr(tapKeyHash.hash)).then((sig) => {
|
|
1120
|
+
return {
|
|
1121
|
+
tapKeySig: serializeTaprootSignature(toBuffer(sig), input.sighashType),
|
|
1122
|
+
};
|
|
1123
|
+
});
|
|
1087
1124
|
signaturePromises.push(tapKeySigPromise);
|
|
1088
1125
|
}
|
|
1089
1126
|
|
|
1090
1127
|
const tapScriptHashes = hashesForSig.filter((h) => !!h.leafHash);
|
|
1091
1128
|
if (tapScriptHashes.length) {
|
|
1092
1129
|
const tapScriptSigPromises = tapScriptHashes.map(async (tsh) => {
|
|
1093
|
-
const signature = await
|
|
1130
|
+
const signature = await signSchnorr(tsh.hash);
|
|
1094
1131
|
|
|
1095
1132
|
const tapScriptSig = [
|
|
1096
1133
|
{
|
|
1097
|
-
pubkey: toXOnly(
|
|
1098
|
-
signature: serializeTaprootSignature(
|
|
1134
|
+
pubkey: toXOnly(pubkey),
|
|
1135
|
+
signature: serializeTaprootSignature(
|
|
1136
|
+
toBuffer(signature),
|
|
1137
|
+
input.sighashType,
|
|
1138
|
+
),
|
|
1099
1139
|
leafHash: tsh.leafHash,
|
|
1100
1140
|
} as TapScriptSig,
|
|
1101
1141
|
];
|
|
@@ -1293,11 +1333,12 @@ function canFinalize(input: PsbtInput, script: Buffer, scriptType: string): bool
|
|
|
1293
1333
|
case 'pubkeyhash':
|
|
1294
1334
|
case 'witnesspubkeyhash':
|
|
1295
1335
|
return hasSigs(1, input.partialSig);
|
|
1296
|
-
case 'multisig':
|
|
1336
|
+
case 'multisig': {
|
|
1297
1337
|
const p2ms = payments.p2ms({
|
|
1298
1338
|
output: script,
|
|
1299
1339
|
});
|
|
1300
1340
|
return hasSigs(p2ms.m!, input.partialSig, p2ms.pubkeys);
|
|
1341
|
+
}
|
|
1301
1342
|
case 'nonstandard':
|
|
1302
1343
|
return true;
|
|
1303
1344
|
default:
|
|
@@ -1306,21 +1347,21 @@ function canFinalize(input: PsbtInput, script: Buffer, scriptType: string): bool
|
|
|
1306
1347
|
}
|
|
1307
1348
|
|
|
1308
1349
|
function checkCache(cache: PsbtCache): void {
|
|
1309
|
-
if (cache.__UNSAFE_SIGN_NONSEGWIT
|
|
1350
|
+
if (cache.__UNSAFE_SIGN_NONSEGWIT) {
|
|
1310
1351
|
throw new Error('Not BIP174 compliant, can not export');
|
|
1311
1352
|
}
|
|
1312
1353
|
}
|
|
1313
1354
|
|
|
1314
|
-
function hasSigs(neededSigs: number, partialSig?:
|
|
1355
|
+
function hasSigs(neededSigs: number, partialSig?: PartialSig[], pubkeys?: Buffer[]): boolean {
|
|
1315
1356
|
if (!partialSig) return false;
|
|
1316
|
-
let sigs:
|
|
1357
|
+
let sigs: PartialSig[];
|
|
1317
1358
|
if (pubkeys) {
|
|
1318
1359
|
sigs = pubkeys
|
|
1319
1360
|
.map((pkey) => {
|
|
1320
1361
|
const pubkey = compressPubkey(pkey);
|
|
1321
1362
|
return partialSig.find((pSig) => pSig.pubkey.equals(pubkey));
|
|
1322
1363
|
})
|
|
1323
|
-
.filter((v) => !!v);
|
|
1364
|
+
.filter((v): v is PartialSig => !!v);
|
|
1324
1365
|
} else {
|
|
1325
1366
|
sigs = partialSig;
|
|
1326
1367
|
}
|
|
@@ -1334,8 +1375,13 @@ function isFinalized(input: PsbtInput): boolean {
|
|
|
1334
1375
|
|
|
1335
1376
|
function bip32DerivationIsMine(root: HDSigner): (d: Bip32Derivation) => boolean {
|
|
1336
1377
|
return (d: Bip32Derivation): boolean => {
|
|
1337
|
-
|
|
1338
|
-
|
|
1378
|
+
const fingerprint = Buffer.isBuffer(root.fingerprint)
|
|
1379
|
+
? root.fingerprint
|
|
1380
|
+
: Buffer.from(root.fingerprint);
|
|
1381
|
+
if (!d.masterFingerprint.equals(fingerprint)) return false;
|
|
1382
|
+
const derivedPubkey = root.derivePath(d.path).publicKey;
|
|
1383
|
+
const pubkey = Buffer.isBuffer(derivedPubkey) ? derivedPubkey : Buffer.from(derivedPubkey);
|
|
1384
|
+
if (!pubkey.equals(d.pubkey)) return false;
|
|
1339
1385
|
return true;
|
|
1340
1386
|
};
|
|
1341
1387
|
}
|
|
@@ -1407,7 +1453,7 @@ function checkTxForDupeIns(tx: Transaction, cache: PsbtCache): void {
|
|
|
1407
1453
|
}
|
|
1408
1454
|
|
|
1409
1455
|
function checkTxInputCache(cache: PsbtCache, input: { hash: Buffer; index: number }): void {
|
|
1410
|
-
const key = reverseBuffer(Buffer.from(input.hash)).toString('hex')
|
|
1456
|
+
const key = `${reverseBuffer(Buffer.from(input.hash)).toString('hex')}:${input.index}`;
|
|
1411
1457
|
if (cache.__TX_IN_CACHE[key]) throw new Error('Duplicate input detected.');
|
|
1412
1458
|
cache.__TX_IN_CACHE[key] = 1;
|
|
1413
1459
|
}
|
|
@@ -1445,7 +1491,7 @@ function getTxCacheValue(
|
|
|
1445
1491
|
inputs: PsbtInput[],
|
|
1446
1492
|
c: PsbtCache,
|
|
1447
1493
|
disableOutputChecks: boolean = false,
|
|
1448
|
-
): number
|
|
1494
|
+
): number {
|
|
1449
1495
|
if (!inputs.every(isFinalized)) throw new Error(`PSBT must be finalized to calculate ${name}`);
|
|
1450
1496
|
if (key === '__FEE_RATE' && c.__FEE_RATE) return c.__FEE_RATE;
|
|
1451
1497
|
if (key === '__FEE' && c.__FEE) return c.__FEE;
|
|
@@ -1458,8 +1504,9 @@ function getTxCacheValue(
|
|
|
1458
1504
|
tx = c.__TX.clone();
|
|
1459
1505
|
}
|
|
1460
1506
|
inputFinalizeGetAmts(inputs, tx, c, mustFinalize, disableOutputChecks);
|
|
1461
|
-
|
|
1462
|
-
|
|
1507
|
+
const value = key === '__FEE_RATE' ? c.__FEE_RATE : c.__FEE;
|
|
1508
|
+
if (value === undefined) throw new Error(`Failed to calculate ${name}`);
|
|
1509
|
+
return value;
|
|
1463
1510
|
}
|
|
1464
1511
|
|
|
1465
1512
|
/**
|
|
@@ -1625,7 +1672,7 @@ function getHashForSig(
|
|
|
1625
1672
|
}
|
|
1626
1673
|
|
|
1627
1674
|
const prevoutIndex = unsignedTx.ins[inputIndex].index;
|
|
1628
|
-
prevout = nonWitnessUtxoTx.outs[prevoutIndex]
|
|
1675
|
+
prevout = nonWitnessUtxoTx.outs[prevoutIndex];
|
|
1629
1676
|
} else if (input.witnessUtxo) {
|
|
1630
1677
|
prevout = input.witnessUtxo;
|
|
1631
1678
|
} else {
|
|
@@ -1650,17 +1697,17 @@ function getHashForSig(
|
|
|
1650
1697
|
} else if (isP2WPKH(meaningfulScript)) {
|
|
1651
1698
|
// P2WPKH uses the P2PKH template for prevoutScript when signing
|
|
1652
1699
|
const signingScript = payments.p2pkh({
|
|
1653
|
-
hash: meaningfulScript.
|
|
1700
|
+
hash: meaningfulScript.subarray(2),
|
|
1654
1701
|
}).output!;
|
|
1655
1702
|
hash = unsignedTx.hashForWitnessV0(inputIndex, signingScript, prevout.value, sighashType);
|
|
1656
1703
|
} else {
|
|
1657
1704
|
// non-segwit
|
|
1658
|
-
if (input.nonWitnessUtxo === undefined && cache.__UNSAFE_SIGN_NONSEGWIT
|
|
1705
|
+
if (input.nonWitnessUtxo === undefined && !cache.__UNSAFE_SIGN_NONSEGWIT)
|
|
1659
1706
|
throw new Error(
|
|
1660
1707
|
`Input #${inputIndex} has witnessUtxo but non-segwit script: ` +
|
|
1661
|
-
|
|
1708
|
+
meaningfulScript.toString('hex'),
|
|
1662
1709
|
);
|
|
1663
|
-
if (!forValidate && cache.__UNSAFE_SIGN_NONSEGWIT
|
|
1710
|
+
if (!forValidate && cache.__UNSAFE_SIGN_NONSEGWIT)
|
|
1664
1711
|
console.warn(
|
|
1665
1712
|
'Warning: Signing non-segwit inputs without the full parent transaction ' +
|
|
1666
1713
|
'means there is a chance that a miner could feed you incorrect information ' +
|
|
@@ -1905,8 +1952,8 @@ function getSignersFromHD(
|
|
|
1905
1952
|
}
|
|
1906
1953
|
|
|
1907
1954
|
return myDerivations.map((bipDv) => {
|
|
1908
|
-
const node = hdKeyPair.derivePath(bipDv
|
|
1909
|
-
if (!bipDv
|
|
1955
|
+
const node = hdKeyPair.derivePath(bipDv.path);
|
|
1956
|
+
if (!bipDv.pubkey.equals(node.publicKey)) {
|
|
1910
1957
|
throw new Error('pubkey did not match bip32Derivation');
|
|
1911
1958
|
}
|
|
1912
1959
|
return node;
|
|
@@ -1935,12 +1982,12 @@ function scriptWitnessToWitnessStack(buffer: Buffer): Buffer[] {
|
|
|
1935
1982
|
|
|
1936
1983
|
function readSlice(n: number): Buffer {
|
|
1937
1984
|
offset += n;
|
|
1938
|
-
return buffer.
|
|
1985
|
+
return buffer.subarray(offset - n, offset);
|
|
1939
1986
|
}
|
|
1940
1987
|
|
|
1941
1988
|
function readVarInt(): number {
|
|
1942
|
-
const vi =
|
|
1943
|
-
offset +=
|
|
1989
|
+
const vi = varuintDecode(buffer, offset);
|
|
1990
|
+
offset += varuintDecode.bytes;
|
|
1944
1991
|
return vi;
|
|
1945
1992
|
}
|
|
1946
1993
|
|
|
@@ -2019,11 +2066,11 @@ function inputFinalizeGetAmts(
|
|
|
2019
2066
|
} else if (input.nonWitnessUtxo) {
|
|
2020
2067
|
const nwTx = nonWitnessUtxoTxFromCache(cache, input, idx);
|
|
2021
2068
|
const vout = tx.ins[idx].index;
|
|
2022
|
-
const out = nwTx.outs[vout]
|
|
2069
|
+
const out = nwTx.outs[vout];
|
|
2023
2070
|
inputAmount += out.value;
|
|
2024
2071
|
}
|
|
2025
2072
|
});
|
|
2026
|
-
const outputAmount =
|
|
2073
|
+
const outputAmount = tx.outs.reduce((total, o) => total + o.value, 0);
|
|
2027
2074
|
const fee = inputAmount - outputAmount;
|
|
2028
2075
|
if (!disableOutputChecks) {
|
|
2029
2076
|
if (fee < 0) {
|
|
@@ -2132,11 +2179,11 @@ function redeemFromFinalWitnessScript(finalScript: Buffer | undefined): Buffer |
|
|
|
2132
2179
|
function compressPubkey(pubkey: Buffer): Buffer {
|
|
2133
2180
|
if (pubkey.length === 65) {
|
|
2134
2181
|
const parity = pubkey[64] & 1;
|
|
2135
|
-
const newKey = pubkey.
|
|
2182
|
+
const newKey = Buffer.from(pubkey.subarray(0, 33));
|
|
2136
2183
|
newKey[0] = 2 | parity;
|
|
2137
2184
|
return newKey;
|
|
2138
2185
|
}
|
|
2139
|
-
return
|
|
2186
|
+
return Buffer.from(pubkey);
|
|
2140
2187
|
}
|
|
2141
2188
|
|
|
2142
2189
|
function isPubkeyLike(buf: Buffer): boolean {
|
|
@@ -2170,8 +2217,8 @@ function getMeaningfulScript(
|
|
|
2170
2217
|
|
|
2171
2218
|
if (isP2SHP2WSH) {
|
|
2172
2219
|
meaningfulScript = witnessScript!;
|
|
2173
|
-
checkRedeemScript(index, script, redeemScript
|
|
2174
|
-
checkWitnessScript(index, redeemScript
|
|
2220
|
+
checkRedeemScript(index, script, redeemScript, ioType);
|
|
2221
|
+
checkWitnessScript(index, redeemScript, witnessScript!, ioType);
|
|
2175
2222
|
checkInvalidP2WSH(meaningfulScript);
|
|
2176
2223
|
} else if (isP2WSH) {
|
|
2177
2224
|
meaningfulScript = witnessScript!;
|
package/src/script.ts
CHANGED
|
@@ -36,7 +36,7 @@ export function countNonPushOnlyOPs(value: Stack): number {
|
|
|
36
36
|
return value.length - value.filter(isPushOnlyChunk).length;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
function asMinimalOP(buffer: Buffer): number |
|
|
39
|
+
function asMinimalOP(buffer: Buffer): number | undefined {
|
|
40
40
|
if (buffer.length === 0) return opcodes.OP_0;
|
|
41
41
|
if (buffer.length !== 1) return;
|
|
42
42
|
if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0];
|
|
@@ -135,7 +135,7 @@ export function decompile(buffer: Buffer | Array<number | Buffer>): Array<number
|
|
|
135
135
|
// attempt to read too much data?
|
|
136
136
|
if (i + d.number > buffer.length) return null;
|
|
137
137
|
|
|
138
|
-
const data = buffer.
|
|
138
|
+
const data = buffer.subarray(i, i + d.number);
|
|
139
139
|
i += d.number;
|
|
140
140
|
|
|
141
141
|
// decompile minimally
|
|
@@ -176,7 +176,7 @@ export function toASM(chunks: Buffer | Array<number | Buffer>): string {
|
|
|
176
176
|
if (singleChunkIsBuffer(chunk)) {
|
|
177
177
|
const op = asMinimalOP(chunk);
|
|
178
178
|
if (op === undefined) return chunk.toString('hex');
|
|
179
|
-
chunk = op
|
|
179
|
+
chunk = op;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
// opcode!
|
|
@@ -240,7 +240,7 @@ export function isCanonicalScriptSignature(buffer: Buffer): boolean {
|
|
|
240
240
|
if (!Buffer.isBuffer(buffer)) return false;
|
|
241
241
|
if (!isDefinedHashType(buffer[buffer.length - 1])) return false;
|
|
242
242
|
|
|
243
|
-
return bip66.check(buffer.
|
|
243
|
+
return bip66.check(buffer.subarray(0, -1));
|
|
244
244
|
}
|
|
245
245
|
|
|
246
246
|
export const number = scriptNumber;
|
package/src/script_signature.ts
CHANGED
|
@@ -15,7 +15,7 @@ function toDER(x: Buffer): Buffer {
|
|
|
15
15
|
let i = 0;
|
|
16
16
|
while (x[i] === 0) ++i;
|
|
17
17
|
if (i === x.length) return ZERO;
|
|
18
|
-
x = x.
|
|
18
|
+
x = x.subarray(i);
|
|
19
19
|
if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length);
|
|
20
20
|
return x;
|
|
21
21
|
}
|
|
@@ -28,7 +28,7 @@ function toDER(x: Buffer): Buffer {
|
|
|
28
28
|
* @returns The converted buffer.
|
|
29
29
|
*/
|
|
30
30
|
function fromDER(x: Buffer): Buffer {
|
|
31
|
-
if (x[0] === 0x00) x = x.
|
|
31
|
+
if (x[0] === 0x00) x = x.subarray(1);
|
|
32
32
|
const buffer = Buffer.alloc(32, 0);
|
|
33
33
|
const bstart = Math.max(0, 32 - x.length);
|
|
34
34
|
x.copy(buffer, bstart);
|
|
@@ -50,10 +50,10 @@ interface ScriptSignature {
|
|
|
50
50
|
export function decode(buffer: Buffer): ScriptSignature {
|
|
51
51
|
const hashType = buffer.readUInt8(buffer.length - 1);
|
|
52
52
|
if (!isDefinedHashType(hashType)) {
|
|
53
|
-
throw new Error(
|
|
53
|
+
throw new Error(`Invalid hashType ${hashType}`);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
const decoded = bip66.decode(buffer.
|
|
56
|
+
const decoded = bip66.decode(buffer.subarray(0, -1));
|
|
57
57
|
const r = fromDER(decoded.r);
|
|
58
58
|
const s = fromDER(decoded.s);
|
|
59
59
|
const signature = Buffer.concat([r, s], 64);
|
|
@@ -78,14 +78,14 @@ export function encode(signature: Buffer, hashType: number): Buffer {
|
|
|
78
78
|
);
|
|
79
79
|
|
|
80
80
|
if (!isDefinedHashType(hashType)) {
|
|
81
|
-
throw new Error(
|
|
81
|
+
throw new Error(`Invalid hashType ${hashType}`);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
const hashTypeBuffer = Buffer.allocUnsafe(1);
|
|
85
85
|
hashTypeBuffer.writeUInt8(hashType, 0);
|
|
86
86
|
|
|
87
|
-
const r = toDER(signature.
|
|
88
|
-
const s = toDER(signature.
|
|
87
|
+
const r = toDER(signature.subarray(0, 32));
|
|
88
|
+
const s = toDER(signature.subarray(32, 64));
|
|
89
89
|
|
|
90
90
|
return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]);
|
|
91
91
|
}
|