@btc-vision/bitcoin 7.0.0-alpha.0 → 7.0.0-alpha.10
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 +455 -155
- package/browser/address.d.ts +6 -2
- package/browser/address.d.ts.map +1 -1
- package/browser/block.d.ts.map +1 -1
- package/browser/branded.d.ts +3 -14
- package/browser/branded.d.ts.map +1 -1
- package/browser/chunks/psbt-parallel-BBFlkmiv.js +10717 -0
- package/browser/crypto.d.ts +1 -1
- package/browser/ecc/context.d.ts +25 -24
- package/browser/ecc/context.d.ts.map +1 -1
- package/browser/ecc/index.d.ts +1 -1
- package/browser/ecc/index.d.ts.map +1 -1
- package/browser/ecc/types.d.ts +10 -123
- package/browser/ecc/types.d.ts.map +1 -1
- package/browser/env.d.ts +13 -0
- package/browser/env.d.ts.map +1 -0
- package/browser/index.d.ts +7 -7
- package/browser/index.d.ts.map +1 -1
- package/browser/index.js +2497 -11686
- package/browser/io/BinaryReader.d.ts +15 -15
- package/browser/io/BinaryReader.d.ts.map +1 -1
- package/browser/io/BinaryWriter.d.ts +17 -17
- package/browser/io/BinaryWriter.d.ts.map +1 -1
- package/browser/io/hex.d.ts.map +1 -1
- package/browser/io/index.d.ts +0 -1
- package/browser/io/index.d.ts.map +1 -1
- package/browser/opcodes.d.ts +11 -0
- package/browser/opcodes.d.ts.map +1 -1
- package/browser/payments/bip341.d.ts +1 -1
- package/browser/payments/bip341.d.ts.map +1 -1
- package/browser/payments/embed.d.ts +1 -1
- package/browser/payments/embed.d.ts.map +1 -1
- package/browser/payments/p2ms.d.ts.map +1 -1
- package/browser/payments/p2op.d.ts +1 -1
- package/browser/payments/p2op.d.ts.map +1 -1
- package/browser/payments/p2pk.d.ts +1 -1
- package/browser/payments/p2pk.d.ts.map +1 -1
- package/browser/payments/p2pkh.d.ts +1 -1
- package/browser/payments/p2pkh.d.ts.map +1 -1
- package/browser/payments/p2sh.d.ts.map +1 -1
- package/browser/payments/p2tr.d.ts +2 -2
- package/browser/payments/p2tr.d.ts.map +1 -1
- package/browser/payments/p2wpkh.d.ts +1 -1
- package/browser/payments/p2wpkh.d.ts.map +1 -1
- package/browser/payments/p2wsh.d.ts.map +1 -1
- package/browser/payments/types.d.ts +1 -1
- package/browser/payments/types.d.ts.map +1 -1
- package/browser/psbt/PsbtCache.d.ts +54 -0
- package/browser/psbt/PsbtCache.d.ts.map +1 -0
- package/browser/psbt/PsbtFinalizer.d.ts +21 -0
- package/browser/psbt/PsbtFinalizer.d.ts.map +1 -0
- package/browser/psbt/PsbtSigner.d.ts +32 -0
- package/browser/psbt/PsbtSigner.d.ts.map +1 -0
- package/browser/psbt/PsbtTransaction.d.ts +25 -0
- package/browser/psbt/PsbtTransaction.d.ts.map +1 -0
- package/browser/psbt/bip371.d.ts.map +1 -1
- package/browser/psbt/types.d.ts +5 -71
- package/browser/psbt/types.d.ts.map +1 -1
- package/browser/psbt/validation.d.ts +1 -1
- package/browser/psbt/validation.d.ts.map +1 -1
- package/browser/psbt.d.ts +26 -40
- package/browser/psbt.d.ts.map +1 -1
- package/browser/script.d.ts.map +1 -1
- package/browser/transaction.d.ts +4 -4
- package/browser/transaction.d.ts.map +1 -1
- package/browser/types.d.ts +5 -3
- package/browser/types.d.ts.map +1 -1
- package/browser/workers/WorkerSigningPool.d.ts +24 -17
- package/browser/workers/WorkerSigningPool.d.ts.map +1 -1
- package/browser/workers/WorkerSigningPool.node.d.ts +19 -12
- package/browser/workers/WorkerSigningPool.node.d.ts.map +1 -1
- package/browser/workers/WorkerSigningPool.sequential.d.ts +67 -0
- package/browser/workers/WorkerSigningPool.sequential.d.ts.map +1 -0
- package/browser/workers/WorkerSigningPool.worklet.d.ts +64 -0
- package/browser/workers/WorkerSigningPool.worklet.d.ts.map +1 -0
- package/browser/workers/index.browser.d.ts +16 -0
- package/browser/workers/index.browser.d.ts.map +1 -0
- package/browser/workers/index.d.ts +4 -64
- package/browser/workers/index.d.ts.map +1 -1
- package/browser/workers/index.js +28 -0
- package/browser/workers/index.node.d.ts +17 -0
- package/browser/workers/index.node.d.ts.map +1 -0
- package/browser/workers/index.react-native.d.ts +28 -0
- package/browser/workers/index.react-native.d.ts.map +1 -0
- package/browser/workers/index.shared.d.ts +15 -0
- package/browser/workers/index.shared.d.ts.map +1 -0
- package/browser/workers/psbt-parallel.d.ts +2 -3
- package/browser/workers/psbt-parallel.d.ts.map +1 -1
- package/browser/workers/types.d.ts +17 -0
- package/browser/workers/types.d.ts.map +1 -1
- package/build/address.d.ts +6 -2
- package/build/address.d.ts.map +1 -1
- package/build/address.js +32 -19
- package/build/address.js.map +1 -1
- package/build/bech32utils.js.map +1 -1
- package/build/block.d.ts.map +1 -1
- package/build/block.js +2 -4
- package/build/block.js.map +1 -1
- package/build/branded.d.ts +3 -14
- package/build/branded.d.ts.map +1 -1
- package/build/branded.js +0 -5
- package/build/branded.js.map +1 -1
- package/build/crypto.d.ts +1 -1
- package/build/ecc/context.d.ts +25 -24
- package/build/ecc/context.d.ts.map +1 -1
- package/build/ecc/context.js +29 -101
- package/build/ecc/context.js.map +1 -1
- package/build/ecc/index.d.ts +1 -1
- package/build/ecc/index.d.ts.map +1 -1
- package/build/ecc/types.d.ts +7 -126
- package/build/ecc/types.d.ts.map +1 -1
- package/build/ecc/types.js +4 -1
- package/build/ecc/types.js.map +1 -1
- package/build/env.d.ts +13 -0
- package/build/env.d.ts.map +1 -0
- package/build/env.js +198 -0
- package/build/env.js.map +1 -0
- package/build/index.d.ts +8 -7
- package/build/index.d.ts.map +1 -1
- package/build/index.js +9 -7
- package/build/index.js.map +1 -1
- package/build/io/BinaryReader.d.ts +15 -15
- package/build/io/BinaryReader.d.ts.map +1 -1
- package/build/io/BinaryReader.js +17 -17
- package/build/io/BinaryReader.js.map +1 -1
- package/build/io/BinaryWriter.d.ts +17 -17
- package/build/io/BinaryWriter.d.ts.map +1 -1
- package/build/io/BinaryWriter.js +39 -39
- package/build/io/BinaryWriter.js.map +1 -1
- package/build/io/hex.d.ts.map +1 -1
- package/build/io/hex.js +2 -1
- package/build/io/hex.js.map +1 -1
- package/build/io/index.d.ts +0 -1
- package/build/io/index.d.ts.map +1 -1
- package/build/io/index.js +0 -2
- package/build/io/index.js.map +1 -1
- package/build/opcodes.d.ts +11 -0
- package/build/opcodes.d.ts.map +1 -1
- package/build/opcodes.js +19 -4
- package/build/opcodes.js.map +1 -1
- package/build/payments/bip341.d.ts +1 -2
- package/build/payments/bip341.d.ts.map +1 -1
- package/build/payments/bip341.js +1 -2
- package/build/payments/bip341.js.map +1 -1
- package/build/payments/embed.d.ts +1 -1
- package/build/payments/embed.d.ts.map +1 -1
- package/build/payments/embed.js +14 -14
- package/build/payments/embed.js.map +1 -1
- package/build/payments/p2ms.d.ts.map +1 -1
- package/build/payments/p2ms.js +21 -21
- package/build/payments/p2ms.js.map +1 -1
- package/build/payments/p2op.d.ts +1 -1
- package/build/payments/p2op.d.ts.map +1 -1
- package/build/payments/p2op.js +18 -18
- package/build/payments/p2op.js.map +1 -1
- package/build/payments/p2pk.d.ts +1 -1
- package/build/payments/p2pk.d.ts.map +1 -1
- package/build/payments/p2pk.js +17 -17
- package/build/payments/p2pk.js.map +1 -1
- package/build/payments/p2pkh.d.ts +1 -1
- package/build/payments/p2pkh.d.ts.map +1 -1
- package/build/payments/p2pkh.js +20 -20
- package/build/payments/p2pkh.js.map +1 -1
- package/build/payments/p2sh.d.ts.map +1 -1
- package/build/payments/p2sh.js +22 -20
- package/build/payments/p2sh.js.map +1 -1
- package/build/payments/p2tr.d.ts +2 -2
- package/build/payments/p2tr.d.ts.map +1 -1
- package/build/payments/p2tr.js +25 -26
- package/build/payments/p2tr.js.map +1 -1
- package/build/payments/p2wpkh.d.ts +1 -1
- package/build/payments/p2wpkh.d.ts.map +1 -1
- package/build/payments/p2wpkh.js +20 -20
- package/build/payments/p2wpkh.js.map +1 -1
- package/build/payments/p2wsh.d.ts.map +1 -1
- package/build/payments/p2wsh.js +22 -22
- package/build/payments/p2wsh.js.map +1 -1
- package/build/payments/types.d.ts +1 -1
- package/build/payments/types.d.ts.map +1 -1
- package/build/psbt/PsbtCache.d.ts +54 -0
- package/build/psbt/PsbtCache.d.ts.map +1 -0
- package/build/psbt/PsbtCache.js +249 -0
- package/build/psbt/PsbtCache.js.map +1 -0
- package/build/psbt/PsbtFinalizer.d.ts +21 -0
- package/build/psbt/PsbtFinalizer.d.ts.map +1 -0
- package/build/psbt/PsbtFinalizer.js +157 -0
- package/build/psbt/PsbtFinalizer.js.map +1 -0
- package/build/psbt/PsbtSigner.d.ts +32 -0
- package/build/psbt/PsbtSigner.d.ts.map +1 -0
- package/build/psbt/PsbtSigner.js +192 -0
- package/build/psbt/PsbtSigner.js.map +1 -0
- package/build/psbt/PsbtTransaction.d.ts +25 -0
- package/build/psbt/PsbtTransaction.d.ts.map +1 -0
- package/build/psbt/PsbtTransaction.js +61 -0
- package/build/psbt/PsbtTransaction.js.map +1 -0
- package/build/psbt/bip371.d.ts.map +1 -1
- package/build/psbt/bip371.js +6 -2
- package/build/psbt/bip371.js.map +1 -1
- package/build/psbt/psbtutils.js +1 -1
- package/build/psbt/psbtutils.js.map +1 -1
- package/build/psbt/types.d.ts +5 -71
- package/build/psbt/types.d.ts.map +1 -1
- package/build/psbt/validation.d.ts +1 -1
- package/build/psbt/validation.d.ts.map +1 -1
- package/build/psbt/validation.js +1 -1
- package/build/psbt/validation.js.map +1 -1
- package/build/psbt.d.ts +26 -40
- package/build/psbt.d.ts.map +1 -1
- package/build/psbt.js +180 -808
- package/build/psbt.js.map +1 -1
- package/build/script.d.ts.map +1 -1
- package/build/script.js +4 -4
- package/build/script.js.map +1 -1
- package/build/transaction.d.ts +4 -4
- package/build/transaction.d.ts.map +1 -1
- package/build/transaction.js +6 -5
- package/build/transaction.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/build/types.d.ts +5 -3
- package/build/types.d.ts.map +1 -1
- package/build/types.js +14 -25
- package/build/types.js.map +1 -1
- package/build/workers/WorkerSigningPool.d.ts +24 -17
- package/build/workers/WorkerSigningPool.d.ts.map +1 -1
- package/build/workers/WorkerSigningPool.js +36 -25
- package/build/workers/WorkerSigningPool.js.map +1 -1
- package/build/workers/WorkerSigningPool.node.d.ts +19 -12
- package/build/workers/WorkerSigningPool.node.d.ts.map +1 -1
- package/build/workers/WorkerSigningPool.node.js +60 -28
- package/build/workers/WorkerSigningPool.node.js.map +1 -1
- package/build/workers/WorkerSigningPool.sequential.d.ts +76 -0
- package/build/workers/WorkerSigningPool.sequential.d.ts.map +1 -0
- package/build/workers/WorkerSigningPool.sequential.js +160 -0
- package/build/workers/WorkerSigningPool.sequential.js.map +1 -0
- package/build/workers/WorkerSigningPool.worklet.d.ts +79 -0
- package/build/workers/WorkerSigningPool.worklet.d.ts.map +1 -0
- package/build/workers/WorkerSigningPool.worklet.js +390 -0
- package/build/workers/WorkerSigningPool.worklet.js.map +1 -0
- package/build/workers/index.browser.d.ts +24 -0
- package/build/workers/index.browser.d.ts.map +1 -0
- package/build/workers/index.browser.js +30 -0
- package/build/workers/index.browser.js.map +1 -0
- package/build/workers/index.d.ts +6 -18
- package/build/workers/index.d.ts.map +1 -1
- package/build/workers/index.js +12 -14
- package/build/workers/index.js.map +1 -1
- package/build/workers/index.node.d.ts +38 -0
- package/build/workers/index.node.d.ts.map +1 -0
- package/build/workers/index.node.js +45 -0
- package/build/workers/index.node.js.map +1 -0
- package/build/workers/index.react-native.d.ts +28 -0
- package/build/workers/index.react-native.d.ts.map +1 -0
- package/build/workers/index.react-native.js +67 -0
- package/build/workers/index.react-native.js.map +1 -0
- package/build/workers/index.shared.d.ts +15 -0
- package/build/workers/index.shared.d.ts.map +1 -0
- package/build/workers/index.shared.js +20 -0
- package/build/workers/index.shared.js.map +1 -0
- package/build/workers/psbt-parallel.d.ts +2 -3
- package/build/workers/psbt-parallel.d.ts.map +1 -1
- package/build/workers/psbt-parallel.js +4 -4
- package/build/workers/psbt-parallel.js.map +1 -1
- package/build/workers/types.d.ts +17 -0
- package/build/workers/types.d.ts.map +1 -1
- package/build/workers/types.js.map +1 -1
- package/package.json +48 -9
- package/src/address.ts +53 -21
- package/src/bech32utils.ts +3 -3
- package/src/block.ts +17 -10
- package/src/branded.ts +15 -13
- package/src/crypto.ts +1 -1
- package/src/ecc/context.ts +36 -136
- package/src/ecc/index.ts +2 -2
- package/src/ecc/types.ts +7 -145
- package/src/env.ts +239 -0
- package/src/index.ts +57 -22
- package/src/io/BinaryReader.ts +18 -18
- package/src/io/BinaryWriter.ts +43 -43
- package/src/io/hex.ts +2 -1
- package/src/io/index.ts +0 -3
- package/src/opcodes.ts +21 -4
- package/src/payments/bip341.ts +5 -7
- package/src/payments/embed.ts +19 -19
- package/src/payments/p2ms.ts +34 -27
- package/src/payments/p2op.ts +22 -22
- package/src/payments/p2pk.ts +22 -22
- package/src/payments/p2pkh.ts +28 -28
- package/src/payments/p2sh.ts +33 -30
- package/src/payments/p2tr.ts +40 -40
- package/src/payments/p2wpkh.ts +30 -30
- package/src/payments/p2wsh.ts +29 -29
- package/src/payments/types.ts +1 -1
- package/src/psbt/PsbtCache.ts +325 -0
- package/src/psbt/PsbtFinalizer.ts +213 -0
- package/src/psbt/PsbtSigner.ts +302 -0
- package/src/psbt/PsbtTransaction.ts +82 -0
- package/src/psbt/bip371.ts +7 -3
- package/src/psbt/psbtutils.ts +1 -1
- package/src/psbt/types.ts +5 -94
- package/src/psbt/validation.ts +5 -12
- package/src/psbt.ts +376 -1201
- package/src/script.ts +6 -9
- package/src/transaction.ts +19 -15
- package/src/types.ts +33 -45
- package/src/workers/WorkerSigningPool.node.ts +72 -36
- package/src/workers/WorkerSigningPool.sequential.ts +191 -0
- package/src/workers/WorkerSigningPool.ts +48 -39
- package/src/workers/WorkerSigningPool.worklet.ts +522 -0
- package/src/workers/index.browser.ts +34 -0
- package/src/workers/index.node.ts +50 -0
- package/src/workers/index.react-native.ts +110 -0
- package/src/workers/index.shared.ts +58 -0
- package/src/workers/index.ts +14 -65
- package/src/workers/psbt-parallel.ts +8 -13
- package/src/workers/types.ts +26 -1
- package/test/address.spec.ts +2 -2
- package/test/bitcoin.core.spec.ts +5 -2
- package/test/browser/payments.spec.ts +151 -0
- package/test/browser/psbt.spec.ts +1510 -0
- package/test/browser/script.spec.ts +223 -0
- package/test/browser/setup.ts +13 -0
- package/test/browser/workers-signing.spec.ts +537 -0
- package/test/crypto.spec.ts +2 -2
- package/test/env.spec.ts +418 -0
- package/test/fixtures/core/base58_encode_decode.json +12 -48
- package/test/fixtures/core/base58_keys_invalid.json +50 -150
- package/test/fixtures/core/sighash.json +1 -3
- package/test/fixtures/core/tx_valid.json +133 -501
- package/test/fixtures/embed.json +3 -11
- package/test/fixtures/p2ms.json +21 -91
- package/test/fixtures/p2pk.json +5 -24
- package/test/fixtures/p2pkh.json +7 -36
- package/test/fixtures/p2sh.json +8 -54
- package/test/fixtures/p2tr.json +2 -6
- package/test/fixtures/p2wpkh.json +7 -36
- package/test/fixtures/p2wsh.json +14 -59
- package/test/fixtures/psbt.json +2 -6
- package/test/fixtures/script.json +12 -48
- package/test/integration/addresses.spec.ts +11 -5
- package/test/integration/bip32.spec.ts +1 -1
- package/test/integration/cltv.spec.ts +10 -6
- package/test/integration/csv.spec.ts +10 -9
- package/test/integration/payments.spec.ts +8 -4
- package/test/integration/taproot.spec.ts +26 -6
- package/test/integration/transactions.spec.ts +22 -8
- package/test/payments.spec.ts +1 -1
- package/test/payments.utils.ts +1 -1
- package/test/psbt.spec.ts +250 -64
- package/test/script_signature.spec.ts +1 -1
- package/test/transaction.spec.ts +18 -5
- package/test/tsconfig.json +6 -20
- package/test/workers-pool.spec.ts +65 -23
- package/test/workers-sequential.spec.ts +669 -0
- package/test/workers-signing.spec.ts +7 -3
- package/test/workers-worklet.spec.ts +500 -0
- package/test/workers.spec.ts +6 -7
- package/typedoc.json +39 -0
- package/vite.config.browser.ts +31 -6
- package/vitest.config.browser.ts +68 -0
- package/browser/ecpair.d.ts +0 -99
- package/browser/io/MemoryPool.d.ts +0 -220
- package/browser/io/MemoryPool.d.ts.map +0 -1
- package/build/io/MemoryPool.d.ts +0 -220
- package/build/io/MemoryPool.d.ts.map +0 -1
- package/build/io/MemoryPool.js +0 -309
- package/build/io/MemoryPool.js.map +0 -1
- package/src/ecpair.d.ts +0 -99
- package/src/io/MemoryPool.ts +0 -343
- package/test/taproot-cache.spec.ts +0 -694
package/build/psbt.js
CHANGED
|
@@ -1,32 +1,44 @@
|
|
|
1
|
-
import { Psbt as PsbtBase
|
|
2
|
-
import { clone,
|
|
3
|
-
import { fromOutputScript,
|
|
1
|
+
import { checkForInput, checkForOutput, Psbt as PsbtBase } from 'bip174';
|
|
2
|
+
import { clone, equals, fromBase64, fromHex, toHex } from './io/index.js';
|
|
3
|
+
import { fromOutputScript, toOutputScript } from './address.js';
|
|
4
4
|
import { bitcoin as btcNetwork } from './networks.js';
|
|
5
5
|
import * as payments from './payments/index.js';
|
|
6
|
-
import { tapleafHash } from './payments/bip341.js';
|
|
7
6
|
import { checkTaprootInputFields, checkTaprootOutputFields, isTaprootInput, serializeTaprootSignature, tapScriptFinalizer, } from './psbt/bip371.js';
|
|
8
7
|
import { toXOnly } from './pubkey.js';
|
|
9
|
-
import { isP2TR, isP2WPKH, pubkeyInScript, witnessStackToScriptWitness, } from './psbt/psbtutils.js';
|
|
10
|
-
import { check32Bit, checkCache, checkInputsForPartialSig, checkPartialSigSighashes, checkScriptForPubkey, checkTxEmpty, checkTxForDupeIns, checkTxInputCache, isFinalized, } from './psbt/validation.js';
|
|
11
|
-
import { checkInvalidP2WSH, classifyScript, compressPubkey, getMeaningfulScript, isPubkeyLike, isSigLike, range, scriptWitnessToWitnessStack, sighashTypeToString, } from './psbt/utils.js';
|
|
12
8
|
import * as bscript from './script.js';
|
|
13
9
|
import { Transaction } from './transaction.js';
|
|
10
|
+
// Import composition classes
|
|
11
|
+
import { PsbtCache } from './psbt/PsbtCache.js';
|
|
12
|
+
import { PsbtSigner } from './psbt/PsbtSigner.js';
|
|
13
|
+
import { getFinalScripts as _getFinalScripts, prepareFinalScripts as _prepareFinalScripts, PsbtFinalizer, } from './psbt/PsbtFinalizer.js';
|
|
14
|
+
import { PsbtTransaction, transactionFromBuffer } from './psbt/PsbtTransaction.js';
|
|
15
|
+
import { check32Bit, checkCache, checkInputsForPartialSig, checkPartialSigSighashes, checkScriptForPubkey, checkTxForDupeIns, checkTxInputCache, isFinalized, } from './psbt/validation.js';
|
|
16
|
+
import { checkInvalidP2WSH, classifyScript, getMeaningfulScript, range } from './psbt/utils.js';
|
|
17
|
+
import { witnessStackToScriptWitness } from './psbt/psbtutils.js';
|
|
18
|
+
// Re-export for backwards compatibility
|
|
19
|
+
export { getFinalScripts, prepareFinalScripts };
|
|
20
|
+
export { PsbtCache } from './psbt/PsbtCache.js';
|
|
21
|
+
export { PsbtSigner } from './psbt/PsbtSigner.js';
|
|
22
|
+
export { PsbtFinalizer } from './psbt/PsbtFinalizer.js';
|
|
23
|
+
export { PsbtTransaction, transactionFromBuffer } from './psbt/PsbtTransaction.js';
|
|
14
24
|
/**
|
|
15
25
|
* These are the default arguments for a Psbt instance.
|
|
16
26
|
*/
|
|
17
27
|
const DEFAULT_OPTS = {
|
|
18
|
-
/**
|
|
19
|
-
* A bitcoinjs Network object. This is only used if you pass an `address`
|
|
20
|
-
* parameter to addOutput. Otherwise it is not needed and can be left default.
|
|
21
|
-
*/
|
|
22
28
|
network: btcNetwork,
|
|
23
|
-
|
|
24
|
-
* When extractTransaction is called, the fee rate is checked.
|
|
25
|
-
* THIS IS NOT TO BE RELIED ON.
|
|
26
|
-
* It is only here as a last ditch effort to prevent sending a 500 BTC fee etc.
|
|
27
|
-
*/
|
|
28
|
-
maximumFeeRate: 5000, // satoshi per byte
|
|
29
|
+
maximumFeeRate: 5000,
|
|
29
30
|
};
|
|
31
|
+
/** Helper to create a Transaction from a buffer */
|
|
32
|
+
function txFromBuffer(buf) {
|
|
33
|
+
return Transaction.fromBuffer(buf);
|
|
34
|
+
}
|
|
35
|
+
// Standalone exports that delegate to PsbtFinalizer
|
|
36
|
+
function getFinalScripts(inputIndex, input, script, isSegwit, isP2SH, isP2WSH, canRunChecks = true, solution) {
|
|
37
|
+
return _getFinalScripts(inputIndex, input, script, isSegwit, isP2SH, isP2WSH, canRunChecks, solution);
|
|
38
|
+
}
|
|
39
|
+
function prepareFinalScripts(script, scriptType, partialSig, isSegwit, isP2SH, isP2WSH, solution) {
|
|
40
|
+
return _prepareFinalScripts(script, scriptType, partialSig, isSegwit, isP2SH, isP2WSH, solution);
|
|
41
|
+
}
|
|
30
42
|
/**
|
|
31
43
|
* Psbt class can parse and generate a PSBT binary based off of the BIP174.
|
|
32
44
|
* There are 6 roles that this class fulfills. (Explained in BIP174)
|
|
@@ -64,39 +76,23 @@ const DEFAULT_OPTS = {
|
|
|
64
76
|
* Transaction Extractor: This role will perform some checks before returning a
|
|
65
77
|
* Transaction object. Such as fee rate not being larger than maximumFeeRate etc.
|
|
66
78
|
*/
|
|
67
|
-
/**
|
|
68
|
-
* Psbt class can parse and generate a PSBT binary based off of the BIP174.
|
|
69
|
-
*/
|
|
70
79
|
export class Psbt {
|
|
71
80
|
data;
|
|
72
81
|
#cache;
|
|
82
|
+
#signer;
|
|
83
|
+
#finalizer;
|
|
73
84
|
#opts;
|
|
74
85
|
constructor(opts = {}, data = new PsbtBase(new PsbtTransaction())) {
|
|
75
86
|
this.data = data;
|
|
76
87
|
this.#opts = Object.assign({}, DEFAULT_OPTS, opts);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
nonWitnessUtxoBufCache: [],
|
|
80
|
-
txInCache: {},
|
|
81
|
-
// unsignedTx.tx property is dynamically added by PsbtBase
|
|
82
|
-
tx: this.data.globalMap.unsignedTx.tx,
|
|
83
|
-
unsafeSignNonSegwit: false,
|
|
84
|
-
hasSignatures: false,
|
|
85
|
-
};
|
|
88
|
+
const tx = this.data.globalMap.unsignedTx.tx;
|
|
89
|
+
this.#cache = new PsbtCache(tx);
|
|
86
90
|
if (opts.version === 3) {
|
|
87
91
|
this.setVersionTRUC();
|
|
88
92
|
}
|
|
89
93
|
else if (this.data.inputs.length === 0)
|
|
90
94
|
this.setVersion(2);
|
|
91
95
|
}
|
|
92
|
-
/** @internal - Exposed for testing. Do not use in production code. */
|
|
93
|
-
get __CACHE() {
|
|
94
|
-
return this.#cache;
|
|
95
|
-
}
|
|
96
|
-
/** @internal - Exposed for testing. Do not use in production code. */
|
|
97
|
-
get opts() {
|
|
98
|
-
return this.#opts;
|
|
99
|
-
}
|
|
100
96
|
get inputCount() {
|
|
101
97
|
return this.data.inputs.length;
|
|
102
98
|
}
|
|
@@ -125,7 +121,9 @@ export class Psbt {
|
|
|
125
121
|
try {
|
|
126
122
|
address = fromOutputScript(output.script, this.#opts.network);
|
|
127
123
|
}
|
|
128
|
-
catch (_) {
|
|
124
|
+
catch (_) {
|
|
125
|
+
// Not all scripts can be converted to an address
|
|
126
|
+
}
|
|
129
127
|
return {
|
|
130
128
|
script: clone(output.script),
|
|
131
129
|
value: output.value,
|
|
@@ -133,6 +131,20 @@ export class Psbt {
|
|
|
133
131
|
};
|
|
134
132
|
});
|
|
135
133
|
}
|
|
134
|
+
/** Lazily initialized signer - created on first access */
|
|
135
|
+
get #lazySigner() {
|
|
136
|
+
if (!this.#signer) {
|
|
137
|
+
this.#signer = new PsbtSigner(this.#cache, txFromBuffer);
|
|
138
|
+
}
|
|
139
|
+
return this.#signer;
|
|
140
|
+
}
|
|
141
|
+
/** Lazily initialized finalizer - created on first access */
|
|
142
|
+
get #lazyFinalizer() {
|
|
143
|
+
if (!this.#finalizer) {
|
|
144
|
+
this.#finalizer = new PsbtFinalizer(this.#cache, txFromBuffer);
|
|
145
|
+
}
|
|
146
|
+
return this.#finalizer;
|
|
147
|
+
}
|
|
136
148
|
static fromBase64(data, opts = {}) {
|
|
137
149
|
const buffer = fromBase64(data);
|
|
138
150
|
return this.fromBuffer(buffer, opts);
|
|
@@ -145,7 +157,6 @@ export class Psbt {
|
|
|
145
157
|
const psbtBase = PsbtBase.fromBuffer(buffer, transactionFromBuffer);
|
|
146
158
|
const psbt = new Psbt(opts, psbtBase);
|
|
147
159
|
checkTxForDupeIns(psbt.#cache.tx, psbt.#cache);
|
|
148
|
-
// Check if restored PSBT has any signatures (partial or finalized)
|
|
149
160
|
psbt.#cache.hasSignatures = psbt.data.inputs.some((input) => input.partialSig?.length ||
|
|
150
161
|
input.tapKeySig ||
|
|
151
162
|
input.tapScriptSig?.length ||
|
|
@@ -158,20 +169,21 @@ export class Psbt {
|
|
|
158
169
|
return this;
|
|
159
170
|
}
|
|
160
171
|
clone() {
|
|
161
|
-
|
|
162
|
-
const clonedOpts = JSON.parse(JSON.stringify(this.#opts));
|
|
172
|
+
const clonedOpts = structuredClone(this.#opts);
|
|
163
173
|
return Psbt.fromBuffer(new Uint8Array(this.data.toBuffer()), clonedOpts);
|
|
164
174
|
}
|
|
175
|
+
get maximumFeeRate() {
|
|
176
|
+
return this.#opts.maximumFeeRate;
|
|
177
|
+
}
|
|
165
178
|
setMaximumFeeRate(satoshiPerByte) {
|
|
166
|
-
check32Bit(satoshiPerByte);
|
|
179
|
+
check32Bit(satoshiPerByte);
|
|
167
180
|
this.#opts.maximumFeeRate = satoshiPerByte;
|
|
168
181
|
}
|
|
169
182
|
setVersion(version) {
|
|
170
183
|
check32Bit(version);
|
|
171
184
|
checkInputsForPartialSig(this.data.inputs, 'setVersion', this.#cache.hasSignatures);
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
c.extractedTx = undefined;
|
|
185
|
+
this.#cache.tx.version = version;
|
|
186
|
+
this.#cache.invalidate('outputs');
|
|
175
187
|
return this;
|
|
176
188
|
}
|
|
177
189
|
setVersionTRUC() {
|
|
@@ -180,20 +192,18 @@ export class Psbt {
|
|
|
180
192
|
setLocktime(locktime) {
|
|
181
193
|
check32Bit(locktime);
|
|
182
194
|
checkInputsForPartialSig(this.data.inputs, 'setLocktime', this.#cache.hasSignatures);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
c.extractedTx = undefined;
|
|
195
|
+
this.#cache.tx.locktime = locktime;
|
|
196
|
+
this.#cache.invalidate('outputs');
|
|
186
197
|
return this;
|
|
187
198
|
}
|
|
188
199
|
setInputSequence(inputIndex, sequence) {
|
|
189
200
|
check32Bit(sequence);
|
|
190
201
|
checkInputsForPartialSig(this.data.inputs, 'setInputSequence', this.#cache.hasSignatures);
|
|
191
|
-
|
|
192
|
-
if (c.tx.ins.length <= inputIndex) {
|
|
202
|
+
if (this.#cache.tx.ins.length <= inputIndex) {
|
|
193
203
|
throw new Error('Input index too high');
|
|
194
204
|
}
|
|
195
|
-
|
|
196
|
-
|
|
205
|
+
this.#cache.tx.ins[inputIndex].sequence = sequence;
|
|
206
|
+
this.#cache.invalidate('outputs');
|
|
197
207
|
return this;
|
|
198
208
|
}
|
|
199
209
|
addInputs(inputDatas, checkPartialSigs = true) {
|
|
@@ -211,7 +221,6 @@ export class Psbt {
|
|
|
211
221
|
}
|
|
212
222
|
if (inputData.witnessScript)
|
|
213
223
|
checkInvalidP2WSH(inputData.witnessScript);
|
|
214
|
-
// Convert witnessUtxo for bip174 v3 compatibility (value: bigint, script: Uint8Array)
|
|
215
224
|
const normalizedInputData = inputData.witnessUtxo
|
|
216
225
|
? {
|
|
217
226
|
...inputData,
|
|
@@ -223,45 +232,25 @@ export class Psbt {
|
|
|
223
232
|
},
|
|
224
233
|
}
|
|
225
234
|
: inputData;
|
|
226
|
-
const c = this.#cache;
|
|
227
235
|
this.data.addInput(normalizedInputData);
|
|
228
|
-
const txIn =
|
|
229
|
-
checkTxInputCache(
|
|
236
|
+
const txIn = this.#cache.tx.ins[this.#cache.tx.ins.length - 1];
|
|
237
|
+
checkTxInputCache(this.#cache, txIn);
|
|
230
238
|
const inputIndex = this.data.inputs.length - 1;
|
|
231
239
|
const input = this.data.inputs[inputIndex];
|
|
232
240
|
if (input.nonWitnessUtxo) {
|
|
233
|
-
|
|
241
|
+
this.#cache.addNonWitnessTxCache(input, inputIndex, txFromBuffer);
|
|
234
242
|
}
|
|
235
|
-
|
|
236
|
-
c.feeRate = undefined;
|
|
237
|
-
c.extractedTx = undefined;
|
|
238
|
-
c.prevOuts = undefined;
|
|
239
|
-
c.signingScripts = undefined;
|
|
240
|
-
c.values = undefined;
|
|
241
|
-
c.taprootHashCache = undefined;
|
|
243
|
+
this.#cache.invalidate('full');
|
|
242
244
|
return this;
|
|
243
245
|
}
|
|
244
246
|
addOutputs(outputDatas, checkPartialSigs = true) {
|
|
245
247
|
outputDatas.forEach((outputData) => this.addOutput(outputData, checkPartialSigs));
|
|
246
248
|
return this;
|
|
247
249
|
}
|
|
248
|
-
/**
|
|
249
|
-
* Add an output to the PSBT.
|
|
250
|
-
*
|
|
251
|
-
* **PERFORMANCE WARNING:** Passing an `address` string is ~10x slower than passing
|
|
252
|
-
* a `script` directly due to address parsing overhead (bech32 decode, etc.).
|
|
253
|
-
* For high-performance use cases with many outputs, pre-compute the script using
|
|
254
|
-
* `toOutputScript(address, network)` and pass `{ script, value }` instead.
|
|
255
|
-
*
|
|
256
|
-
* @param outputData - Output data with either `address` or `script`, and `value`
|
|
257
|
-
* @param checkPartialSigs - Whether to check for existing signatures (default: true)
|
|
258
|
-
*/
|
|
259
250
|
addOutput(outputData, checkPartialSigs = true) {
|
|
260
251
|
const hasAddress = 'address' in outputData;
|
|
261
252
|
const hasScript = 'script' in outputData;
|
|
262
|
-
if (!outputData ||
|
|
263
|
-
outputData.value === undefined ||
|
|
264
|
-
(!hasAddress && !hasScript)) {
|
|
253
|
+
if (!outputData || outputData.value === undefined || (!hasAddress && !hasScript)) {
|
|
265
254
|
throw new Error(`Invalid arguments for Psbt.addOutput. ` +
|
|
266
255
|
`Requires single object with at least [script or address] and [value]`);
|
|
267
256
|
}
|
|
@@ -275,12 +264,8 @@ export class Psbt {
|
|
|
275
264
|
outputData = Object.assign({}, outputData, { script });
|
|
276
265
|
}
|
|
277
266
|
checkTaprootOutputFields(outputData, outputData, 'addOutput');
|
|
278
|
-
const c = this.#cache;
|
|
279
267
|
this.data.addOutput(outputData);
|
|
280
|
-
|
|
281
|
-
c.feeRate = undefined;
|
|
282
|
-
c.extractedTx = undefined;
|
|
283
|
-
c.taprootHashCache = undefined;
|
|
268
|
+
this.#cache.invalidate('outputs');
|
|
284
269
|
return this;
|
|
285
270
|
}
|
|
286
271
|
extractTransaction(disableFeeCheck, disableOutputChecks) {
|
|
@@ -289,24 +274,24 @@ export class Psbt {
|
|
|
289
274
|
}
|
|
290
275
|
if (!this.data.inputs.every(isFinalized))
|
|
291
276
|
throw new Error('Not finalized');
|
|
292
|
-
const c = this.#cache;
|
|
293
277
|
if (!disableFeeCheck) {
|
|
294
|
-
|
|
278
|
+
this.#cache.computeFeeRate(this.data.inputs, disableOutputChecks, txFromBuffer);
|
|
279
|
+
this.#cache.checkFees(this.#opts);
|
|
295
280
|
}
|
|
296
|
-
if (
|
|
297
|
-
return
|
|
298
|
-
const tx =
|
|
299
|
-
|
|
281
|
+
if (this.#cache.extractedTx)
|
|
282
|
+
return this.#cache.extractedTx;
|
|
283
|
+
const tx = this.#cache.tx.clone();
|
|
284
|
+
this.#cache.finalizeAndComputeAmounts(this.data.inputs, tx, true, disableOutputChecks, txFromBuffer);
|
|
300
285
|
return tx;
|
|
301
286
|
}
|
|
302
287
|
getFeeRate(disableOutputChecks = false) {
|
|
303
|
-
return
|
|
288
|
+
return this.#cache.computeFeeRate(this.data.inputs, disableOutputChecks, txFromBuffer);
|
|
304
289
|
}
|
|
305
290
|
getFee(disableOutputChecks = false) {
|
|
306
|
-
return
|
|
291
|
+
return this.#cache.computeFee(this.data.inputs, disableOutputChecks, txFromBuffer);
|
|
307
292
|
}
|
|
308
293
|
finalizeAllInputs() {
|
|
309
|
-
checkForInput(this.data.inputs, 0);
|
|
294
|
+
checkForInput(this.data.inputs, 0);
|
|
310
295
|
range(this.data.inputs.length).forEach((idx) => this.finalizeInput(idx));
|
|
311
296
|
return this;
|
|
312
297
|
}
|
|
@@ -325,36 +310,35 @@ export class Psbt {
|
|
|
325
310
|
}
|
|
326
311
|
getInputType(inputIndex) {
|
|
327
312
|
const input = checkForInput(this.data.inputs, inputIndex);
|
|
328
|
-
const script = getScriptFromUtxo(inputIndex, input,
|
|
329
|
-
const result = getMeaningfulScript(script, inputIndex, 'input', input.redeemScript ||
|
|
330
|
-
|
|
331
|
-
redeemFromFinalWitnessScript(input.finalScriptWitness));
|
|
313
|
+
const script = this.#cache.getScriptFromUtxo(inputIndex, input, txFromBuffer);
|
|
314
|
+
const result = getMeaningfulScript(script, inputIndex, 'input', input.redeemScript || this.#cache.redeemFromFinalScriptSig(input.finalScriptSig), input.witnessScript ||
|
|
315
|
+
this.#cache.redeemFromFinalWitnessScript(input.finalScriptWitness));
|
|
332
316
|
const type = result.type === 'raw' ? '' : result.type + '-';
|
|
333
317
|
const mainType = classifyScript(result.meaningfulScript);
|
|
334
318
|
return (type + mainType);
|
|
335
319
|
}
|
|
336
320
|
inputHasPubkey(inputIndex, pubkey) {
|
|
337
321
|
const input = checkForInput(this.data.inputs, inputIndex);
|
|
338
|
-
return pubkeyInInput(pubkey, input, inputIndex,
|
|
322
|
+
return this.#cache.pubkeyInInput(pubkey, input, inputIndex, txFromBuffer);
|
|
339
323
|
}
|
|
340
324
|
inputHasHDKey(inputIndex, root) {
|
|
341
325
|
const input = checkForInput(this.data.inputs, inputIndex);
|
|
342
|
-
const derivationIsMine = bip32DerivationIsMine(root);
|
|
326
|
+
const derivationIsMine = this.#lazySigner.bip32DerivationIsMine(root);
|
|
343
327
|
return !!input.bip32Derivation && input.bip32Derivation.some(derivationIsMine);
|
|
344
328
|
}
|
|
345
329
|
outputHasPubkey(outputIndex, pubkey) {
|
|
346
330
|
const output = checkForOutput(this.data.outputs, outputIndex);
|
|
347
|
-
return pubkeyInOutput(pubkey, output, outputIndex
|
|
331
|
+
return this.#cache.pubkeyInOutput(pubkey, output, outputIndex);
|
|
348
332
|
}
|
|
349
333
|
outputHasHDKey(outputIndex, root) {
|
|
350
334
|
const output = checkForOutput(this.data.outputs, outputIndex);
|
|
351
|
-
const derivationIsMine = bip32DerivationIsMine(root);
|
|
335
|
+
const derivationIsMine = this.#lazySigner.bip32DerivationIsMine(root);
|
|
352
336
|
return !!output.bip32Derivation && output.bip32Derivation.some(derivationIsMine);
|
|
353
337
|
}
|
|
354
338
|
validateSignaturesOfAllInputs(validator) {
|
|
355
|
-
checkForInput(this.data.inputs, 0);
|
|
339
|
+
checkForInput(this.data.inputs, 0);
|
|
356
340
|
const results = range(this.data.inputs.length).map((idx) => this.validateSignaturesOfInput(idx, validator));
|
|
357
|
-
return results.
|
|
341
|
+
return results.every((res) => res);
|
|
358
342
|
}
|
|
359
343
|
validateSignaturesOfInput(inputIndex, validator, pubkey) {
|
|
360
344
|
const input = this.data.inputs[inputIndex];
|
|
@@ -381,56 +365,43 @@ export class Psbt {
|
|
|
381
365
|
}
|
|
382
366
|
return this;
|
|
383
367
|
}
|
|
384
|
-
signAllInputsHDAsync(hdKeyPair, sighashTypes = [Transaction.SIGHASH_ALL]) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
resolve();
|
|
403
|
-
});
|
|
404
|
-
});
|
|
368
|
+
async signAllInputsHDAsync(hdKeyPair, sighashTypes = [Transaction.SIGHASH_ALL]) {
|
|
369
|
+
if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
|
|
370
|
+
throw new Error('Need HDSigner to sign input');
|
|
371
|
+
}
|
|
372
|
+
const results = [];
|
|
373
|
+
const promises = [];
|
|
374
|
+
for (const i of range(this.data.inputs.length)) {
|
|
375
|
+
promises.push(this.signInputHDAsync(i, hdKeyPair, sighashTypes).then(() => {
|
|
376
|
+
results.push(true);
|
|
377
|
+
}, () => {
|
|
378
|
+
results.push(false);
|
|
379
|
+
}));
|
|
380
|
+
}
|
|
381
|
+
await Promise.all(promises);
|
|
382
|
+
if (results.every((v) => !v)) {
|
|
383
|
+
throw new Error('No inputs were signed');
|
|
384
|
+
}
|
|
405
385
|
}
|
|
406
386
|
signInputHD(inputIndex, hdKeyPair, sighashTypes = [Transaction.SIGHASH_ALL]) {
|
|
407
387
|
if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
|
|
408
388
|
throw new Error('Need HDSigner to sign input');
|
|
409
389
|
}
|
|
410
|
-
const signers = getSignersFromHD(inputIndex, this.data.inputs, hdKeyPair);
|
|
390
|
+
const signers = this.#lazySigner.getSignersFromHD(inputIndex, this.data.inputs, hdKeyPair);
|
|
411
391
|
signers.forEach((signer) => this.signInput(inputIndex, signer, sighashTypes));
|
|
412
392
|
return this;
|
|
413
393
|
}
|
|
414
|
-
signInputHDAsync(inputIndex, hdKeyPair, sighashTypes = [Transaction.SIGHASH_ALL]) {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
return Promise.all(promises)
|
|
422
|
-
.then(() => {
|
|
423
|
-
resolve();
|
|
424
|
-
})
|
|
425
|
-
.catch(reject);
|
|
426
|
-
});
|
|
394
|
+
async signInputHDAsync(inputIndex, hdKeyPair, sighashTypes = [Transaction.SIGHASH_ALL]) {
|
|
395
|
+
if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
|
|
396
|
+
throw new Error('Need HDSigner to sign input');
|
|
397
|
+
}
|
|
398
|
+
const signers = this.#lazySigner.getSignersFromHD(inputIndex, this.data.inputs, hdKeyPair);
|
|
399
|
+
const promises = signers.map((signer) => this.signInputAsync(inputIndex, signer, sighashTypes));
|
|
400
|
+
await Promise.all(promises);
|
|
427
401
|
}
|
|
428
402
|
signAllInputs(keyPair, sighashTypes) {
|
|
429
403
|
if (!keyPair || !keyPair.publicKey)
|
|
430
404
|
throw new Error('Need Signer to sign input');
|
|
431
|
-
// TODO: Add a pubkey/pubkeyhash cache to each input
|
|
432
|
-
// as input information is added, then eventually
|
|
433
|
-
// optimize this method.
|
|
434
405
|
const results = [];
|
|
435
406
|
for (const i of range(this.data.inputs.length)) {
|
|
436
407
|
try {
|
|
@@ -446,29 +417,22 @@ export class Psbt {
|
|
|
446
417
|
}
|
|
447
418
|
return this;
|
|
448
419
|
}
|
|
449
|
-
signAllInputsAsync(keyPair, sighashTypes) {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
return Promise.all(promises).then(() => {
|
|
466
|
-
if (results.every((v) => !v)) {
|
|
467
|
-
return reject(new Error('No inputs were signed'));
|
|
468
|
-
}
|
|
469
|
-
resolve();
|
|
470
|
-
});
|
|
471
|
-
});
|
|
420
|
+
async signAllInputsAsync(keyPair, sighashTypes) {
|
|
421
|
+
if (!keyPair || !keyPair.publicKey)
|
|
422
|
+
throw new Error('Need Signer to sign input');
|
|
423
|
+
const results = [];
|
|
424
|
+
const promises = [];
|
|
425
|
+
for (const [i] of this.data.inputs.entries()) {
|
|
426
|
+
promises.push(this.signInputAsync(i, keyPair, sighashTypes).then(() => {
|
|
427
|
+
results.push(true);
|
|
428
|
+
}, () => {
|
|
429
|
+
results.push(false);
|
|
430
|
+
}));
|
|
431
|
+
}
|
|
432
|
+
await Promise.all(promises);
|
|
433
|
+
if (results.every((v) => !v)) {
|
|
434
|
+
throw new Error('No inputs were signed');
|
|
435
|
+
}
|
|
472
436
|
}
|
|
473
437
|
signInput(inputIndex, keyPair, sighashTypes) {
|
|
474
438
|
if (!keyPair || !keyPair.publicKey) {
|
|
@@ -490,25 +454,21 @@ export class Psbt {
|
|
|
490
454
|
}
|
|
491
455
|
throw new Error(`Input #${inputIndex} is not of type Taproot.`);
|
|
492
456
|
}
|
|
493
|
-
signInputAsync(inputIndex, keyPair, sighashTypes) {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
return this.#signInputAsync(inputIndex, keyPair, sighashTypes);
|
|
501
|
-
});
|
|
457
|
+
async signInputAsync(inputIndex, keyPair, sighashTypes) {
|
|
458
|
+
if (!keyPair || !keyPair.publicKey)
|
|
459
|
+
throw new Error('Need Signer to sign input');
|
|
460
|
+
const input = checkForInput(this.data.inputs, inputIndex);
|
|
461
|
+
if (isTaprootInput(input))
|
|
462
|
+
return this.#signTaprootInputAsync(inputIndex, input, keyPair, undefined, sighashTypes);
|
|
463
|
+
return this.#signInputAsync(inputIndex, keyPair, sighashTypes);
|
|
502
464
|
}
|
|
503
|
-
signTaprootInputAsync(inputIndex, keyPair, tapLeafHash, sighashTypes) {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
throw new Error(`Input #${inputIndex} is not of type Taproot.`);
|
|
511
|
-
});
|
|
465
|
+
async signTaprootInputAsync(inputIndex, keyPair, tapLeafHash, sighashTypes) {
|
|
466
|
+
if (!keyPair || !keyPair.publicKey)
|
|
467
|
+
throw new Error('Need Signer to sign input');
|
|
468
|
+
const input = checkForInput(this.data.inputs, inputIndex);
|
|
469
|
+
if (isTaprootInput(input))
|
|
470
|
+
return this.#signTaprootInputAsync(inputIndex, input, keyPair, tapLeafHash, sighashTypes);
|
|
471
|
+
throw new Error(`Input #${inputIndex} is not of type Taproot.`);
|
|
512
472
|
}
|
|
513
473
|
toBuffer() {
|
|
514
474
|
checkCache(this.#cache);
|
|
@@ -530,7 +490,6 @@ export class Psbt {
|
|
|
530
490
|
if (updateData.witnessScript)
|
|
531
491
|
checkInvalidP2WSH(updateData.witnessScript);
|
|
532
492
|
checkTaprootInputFields(this.data.inputs[inputIndex], updateData, 'updateInput');
|
|
533
|
-
// Convert witnessUtxo for bip174 v3 compatibility (value: bigint, script: Uint8Array)
|
|
534
493
|
const normalizedUpdate = updateData.witnessUtxo
|
|
535
494
|
? {
|
|
536
495
|
...updateData,
|
|
@@ -544,7 +503,7 @@ export class Psbt {
|
|
|
544
503
|
: updateData;
|
|
545
504
|
this.data.updateInput(inputIndex, normalizedUpdate);
|
|
546
505
|
if (updateData.nonWitnessUtxo) {
|
|
547
|
-
|
|
506
|
+
this.#cache.addNonWitnessTxCache(this.data.inputs[inputIndex], inputIndex, txFromBuffer);
|
|
548
507
|
}
|
|
549
508
|
return this;
|
|
550
509
|
}
|
|
@@ -576,13 +535,13 @@ export class Psbt {
|
|
|
576
535
|
const pubkey = keyPair.publicKey instanceof Uint8Array
|
|
577
536
|
? keyPair.publicKey
|
|
578
537
|
: new Uint8Array(keyPair.publicKey);
|
|
579
|
-
const hashesForSig = getTaprootHashesForSig(inputIndex, input, this.data.inputs, pubkey,
|
|
538
|
+
const hashesForSig = this.#lazySigner.getTaprootHashesForSig(inputIndex, input, this.data.inputs, pubkey, tapLeafHashToSign, allowedSighashTypes);
|
|
580
539
|
if (!hashesForSig || !hashesForSig.length)
|
|
581
540
|
throw new Error(`Can not sign for input #${inputIndex} with the key ${toHex(pubkey)}`);
|
|
582
541
|
return hashesForSig;
|
|
583
542
|
}
|
|
584
543
|
#finalizeInput(inputIndex, input, finalScriptsFunc = getFinalScripts, canRunChecks = true) {
|
|
585
|
-
const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(inputIndex, input
|
|
544
|
+
const { script, isP2SH, isP2WSH, isSegwit } = this.#lazyFinalizer.getScriptFromInput(inputIndex, input);
|
|
586
545
|
if (!script)
|
|
587
546
|
throw new Error(`No script found for input #${inputIndex}`);
|
|
588
547
|
checkPartialSigSighashes(input);
|
|
@@ -599,7 +558,6 @@ export class Psbt {
|
|
|
599
558
|
#finalizeTaprootInput(inputIndex, input, tapLeafHashToFinalize, finalScriptsFunc = tapScriptFinalizer) {
|
|
600
559
|
if (!input.witnessUtxo)
|
|
601
560
|
throw new Error(`Cannot finalize input #${inputIndex}. Missing witness utxo.`);
|
|
602
|
-
// Check key spend first. Increased privacy and reduced block space.
|
|
603
561
|
if (input.tapKeySig) {
|
|
604
562
|
const payment = payments.p2tr({
|
|
605
563
|
output: input.witnessUtxo.script,
|
|
@@ -619,14 +577,12 @@ export class Psbt {
|
|
|
619
577
|
}
|
|
620
578
|
#validateSignaturesOfInput(inputIndex, validator, pubkey) {
|
|
621
579
|
const input = this.data.inputs[inputIndex];
|
|
622
|
-
const partialSig =
|
|
580
|
+
const partialSig = input?.partialSig;
|
|
623
581
|
if (!input || !partialSig || partialSig.length < 1)
|
|
624
582
|
throw new Error('No signatures to validate');
|
|
625
583
|
if (typeof validator !== 'function')
|
|
626
584
|
throw new Error('Need validator function to validate signatures');
|
|
627
|
-
const mySigs = pubkey
|
|
628
|
-
? partialSig.filter((sig) => equals(sig.pubkey, pubkey))
|
|
629
|
-
: partialSig;
|
|
585
|
+
const mySigs = pubkey ? partialSig.filter((sig) => equals(sig.pubkey, pubkey)) : partialSig;
|
|
630
586
|
if (mySigs.length < 1)
|
|
631
587
|
throw new Error('No signatures for this pubkey');
|
|
632
588
|
const results = [];
|
|
@@ -638,9 +594,9 @@ export class Psbt {
|
|
|
638
594
|
const pSigPubkey = pSig.pubkey;
|
|
639
595
|
const sig = bscript.signature.decode(pSigSignature);
|
|
640
596
|
const { hash, script } = sighashCache !== sig.hashType || !hashCache || !scriptCache
|
|
641
|
-
? getHashForSig(inputIndex, Object.assign({}, input, {
|
|
597
|
+
? this.#lazySigner.getHashForSig(inputIndex, Object.assign({}, input, {
|
|
642
598
|
sighashType: sig.hashType,
|
|
643
|
-
}),
|
|
599
|
+
}), true)
|
|
644
600
|
: { hash: hashCache, script: scriptCache };
|
|
645
601
|
sighashCache = sig.hashType;
|
|
646
602
|
hashCache = hash;
|
|
@@ -652,22 +608,22 @@ export class Psbt {
|
|
|
652
608
|
}
|
|
653
609
|
#validateSignaturesOfTaprootInput(inputIndex, validator, pubkey) {
|
|
654
610
|
const input = this.data.inputs[inputIndex];
|
|
655
|
-
const tapKeySig =
|
|
656
|
-
const tapScriptSig =
|
|
611
|
+
const tapKeySig = input?.tapKeySig;
|
|
612
|
+
const tapScriptSig = input?.tapScriptSig;
|
|
657
613
|
if (!input && !tapKeySig && !(tapScriptSig && !tapScriptSig.length))
|
|
658
614
|
throw new Error('No signatures to validate');
|
|
659
615
|
if (typeof validator !== 'function')
|
|
660
616
|
throw new Error('Need validator function to validate signatures');
|
|
661
617
|
const xPubkey = pubkey ? toXOnly(pubkey) : undefined;
|
|
662
618
|
const allHashses = xPubkey
|
|
663
|
-
? getTaprootHashesForSig(inputIndex, input, this.data.inputs, xPubkey
|
|
664
|
-
: getAllTaprootHashesForSig(inputIndex, input, this.data.inputs
|
|
619
|
+
? this.#lazySigner.getTaprootHashesForSig(inputIndex, input, this.data.inputs, xPubkey)
|
|
620
|
+
: this.#lazySigner.getAllTaprootHashesForSig(inputIndex, input, this.data.inputs);
|
|
665
621
|
if (!allHashses.length)
|
|
666
622
|
throw new Error('No signatures for this pubkey');
|
|
667
623
|
const tapKeyHash = allHashses.find((h) => !h.leafHash);
|
|
668
624
|
let validationResultCount = 0;
|
|
669
625
|
if (tapKeySig && tapKeyHash) {
|
|
670
|
-
const isValidTapkeySig = validator(tapKeyHash.pubkey, tapKeyHash.hash, trimTaprootSig(tapKeySig));
|
|
626
|
+
const isValidTapkeySig = validator(tapKeyHash.pubkey, tapKeyHash.hash, this.#lazySigner.trimTaprootSig(tapKeySig));
|
|
671
627
|
if (!isValidTapkeySig)
|
|
672
628
|
return false;
|
|
673
629
|
validationResultCount++;
|
|
@@ -677,7 +633,7 @@ export class Psbt {
|
|
|
677
633
|
const tapSigPubkey = tapSig.pubkey;
|
|
678
634
|
const tapSigHash = allHashses.find((h) => equals(tapSigPubkey, h.pubkey));
|
|
679
635
|
if (tapSigHash) {
|
|
680
|
-
const isValidTapScriptSig = validator(tapSigPubkey, tapSigHash.hash, trimTaprootSig(tapSig.signature));
|
|
636
|
+
const isValidTapScriptSig = validator(tapSigPubkey, tapSigHash.hash, this.#lazySigner.trimTaprootSig(tapSig.signature));
|
|
681
637
|
if (!isValidTapScriptSig)
|
|
682
638
|
return false;
|
|
683
639
|
validationResultCount++;
|
|
@@ -690,7 +646,7 @@ export class Psbt {
|
|
|
690
646
|
const pubkey = keyPair.publicKey instanceof Uint8Array
|
|
691
647
|
? keyPair.publicKey
|
|
692
648
|
: new Uint8Array(keyPair.publicKey);
|
|
693
|
-
const { hash, sighashType } = getHashAndSighashType(this.data.inputs, inputIndex, pubkey,
|
|
649
|
+
const { hash, sighashType } = this.#lazySigner.getHashAndSighashType(this.data.inputs, inputIndex, pubkey, sighashTypes);
|
|
694
650
|
const sig = keyPair.sign(hash);
|
|
695
651
|
const partialSig = [
|
|
696
652
|
{
|
|
@@ -708,7 +664,6 @@ export class Psbt {
|
|
|
708
664
|
: new Uint8Array(keyPair.publicKey));
|
|
709
665
|
if (!('signSchnorr' in keyPair) || typeof keyPair.signSchnorr !== 'function')
|
|
710
666
|
throw new Error(`Need Schnorr Signer to sign taproot input #${inputIndex}.`);
|
|
711
|
-
// checkTaprootHashesForSig validates signSchnorr exists
|
|
712
667
|
const hashesForSig = this.checkTaprootHashesForSig(inputIndex, input, keyPair, tapLeafHashToSign, allowedSighashTypes);
|
|
713
668
|
const signSchnorr = keyPair.signSchnorr.bind(keyPair);
|
|
714
669
|
const tapKeySig = hashesForSig
|
|
@@ -731,22 +686,21 @@ export class Psbt {
|
|
|
731
686
|
}
|
|
732
687
|
return this;
|
|
733
688
|
}
|
|
734
|
-
#signInputAsync(inputIndex, keyPair, sighashTypes = [Transaction.SIGHASH_ALL]) {
|
|
689
|
+
async #signInputAsync(inputIndex, keyPair, sighashTypes = [Transaction.SIGHASH_ALL]) {
|
|
735
690
|
const pubkey = keyPair.publicKey instanceof Uint8Array
|
|
736
691
|
? keyPair.publicKey
|
|
737
692
|
: new Uint8Array(keyPair.publicKey);
|
|
738
|
-
const { hash, sighashType } = getHashAndSighashType(this.data.inputs, inputIndex, pubkey,
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
});
|
|
693
|
+
const { hash, sighashType } = this.#lazySigner.getHashAndSighashType(this.data.inputs, inputIndex, pubkey, sighashTypes);
|
|
694
|
+
const signature = await keyPair.sign(hash);
|
|
695
|
+
const sig = signature instanceof Uint8Array ? signature : new Uint8Array(signature);
|
|
696
|
+
const partialSig = [
|
|
697
|
+
{
|
|
698
|
+
pubkey,
|
|
699
|
+
signature: bscript.signature.encode(sig, sighashType),
|
|
700
|
+
},
|
|
701
|
+
];
|
|
702
|
+
this.data.updateInput(inputIndex, { partialSig });
|
|
703
|
+
this.#cache.hasSignatures = true;
|
|
750
704
|
}
|
|
751
705
|
async #signTaprootInputAsync(inputIndex, input, keyPair, tapLeafHash, sighashTypes = [Transaction.SIGHASH_DEFAULT]) {
|
|
752
706
|
const pubkey = (keyPair.publicKey instanceof Uint8Array
|
|
@@ -754,610 +708,28 @@ export class Psbt {
|
|
|
754
708
|
: new Uint8Array(keyPair.publicKey));
|
|
755
709
|
if (!('signSchnorr' in keyPair) || typeof keyPair.signSchnorr !== 'function')
|
|
756
710
|
throw new Error(`Need Schnorr Signer to sign taproot input #${inputIndex}.`);
|
|
757
|
-
// checkTaprootHashesForSig validates signSchnorr exists
|
|
758
711
|
const hashesForSig = this.checkTaprootHashesForSig(inputIndex, input, keyPair, tapLeafHash, sighashTypes);
|
|
759
712
|
const signSchnorr = keyPair.signSchnorr.bind(keyPair);
|
|
760
|
-
const
|
|
761
|
-
const tapKeyHash = hashesForSig.filter((h) => !h.leafHash)[0];
|
|
713
|
+
const tapKeyHash = hashesForSig.find((h) => !h.leafHash);
|
|
762
714
|
if (tapKeyHash) {
|
|
763
|
-
const
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
});
|
|
768
|
-
signaturePromises.push(tapKeySigPromise);
|
|
715
|
+
const sig = await signSchnorr(tapKeyHash.hash);
|
|
716
|
+
const tapKeySig = serializeTaprootSignature(sig, input.sighashType);
|
|
717
|
+
this.data.updateInput(inputIndex, { tapKeySig });
|
|
718
|
+
this.#cache.hasSignatures = true;
|
|
769
719
|
}
|
|
770
720
|
const tapScriptHashes = hashesForSig.filter((h) => !!h.leafHash);
|
|
771
721
|
if (tapScriptHashes.length) {
|
|
772
|
-
const
|
|
722
|
+
const tapScriptSigs = await Promise.all(tapScriptHashes.map(async (tsh) => {
|
|
773
723
|
const signature = await signSchnorr(tsh.hash);
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
return { tapScriptSig };
|
|
782
|
-
});
|
|
783
|
-
signaturePromises.push(...tapScriptSigPromises);
|
|
784
|
-
}
|
|
785
|
-
const results = await Promise.all(signaturePromises);
|
|
786
|
-
for (const v of results) {
|
|
787
|
-
this.data.updateInput(inputIndex, v);
|
|
724
|
+
return {
|
|
725
|
+
pubkey: toXOnly(pubkey),
|
|
726
|
+
signature: serializeTaprootSignature(signature, input.sighashType),
|
|
727
|
+
leafHash: tsh.leafHash,
|
|
728
|
+
};
|
|
729
|
+
}));
|
|
730
|
+
this.data.updateInput(inputIndex, { tapScriptSig: tapScriptSigs });
|
|
788
731
|
this.#cache.hasSignatures = true;
|
|
789
732
|
}
|
|
790
733
|
}
|
|
791
734
|
}
|
|
792
|
-
/**
|
|
793
|
-
* This function is needed to pass to the bip174 base class's fromBuffer.
|
|
794
|
-
* It takes the "transaction buffer" portion of the psbt buffer and returns a
|
|
795
|
-
* Transaction (From the bip174 library) interface.
|
|
796
|
-
*/
|
|
797
|
-
const transactionFromBuffer = (buffer) => new PsbtTransaction(buffer);
|
|
798
|
-
/**
|
|
799
|
-
* This class implements the Transaction interface from bip174 library.
|
|
800
|
-
* It contains a bitcoinjs-lib Transaction object.
|
|
801
|
-
*/
|
|
802
|
-
class PsbtTransaction {
|
|
803
|
-
tx;
|
|
804
|
-
constructor(buffer = new Uint8Array([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) {
|
|
805
|
-
this.tx = Transaction.fromBuffer(buffer);
|
|
806
|
-
checkTxEmpty(this.tx);
|
|
807
|
-
Object.defineProperty(this, 'tx', {
|
|
808
|
-
enumerable: false,
|
|
809
|
-
writable: true,
|
|
810
|
-
});
|
|
811
|
-
}
|
|
812
|
-
getInputOutputCounts() {
|
|
813
|
-
return {
|
|
814
|
-
inputCount: this.tx.ins.length,
|
|
815
|
-
outputCount: this.tx.outs.length,
|
|
816
|
-
};
|
|
817
|
-
}
|
|
818
|
-
addInput(input) {
|
|
819
|
-
if (input.hash === undefined ||
|
|
820
|
-
input.index === undefined ||
|
|
821
|
-
(!(input.hash instanceof Uint8Array) && typeof input.hash !== 'string') ||
|
|
822
|
-
typeof input.index !== 'number') {
|
|
823
|
-
throw new Error('Error adding input.');
|
|
824
|
-
}
|
|
825
|
-
const hash = (typeof input.hash === 'string' ? reverse(fromHex(input.hash)) : input.hash);
|
|
826
|
-
this.tx.addInput(hash, input.index, input.sequence);
|
|
827
|
-
}
|
|
828
|
-
addOutput(output) {
|
|
829
|
-
if (output.script === undefined ||
|
|
830
|
-
output.value === undefined ||
|
|
831
|
-
!(output.script instanceof Uint8Array) ||
|
|
832
|
-
typeof output.value !== 'bigint') {
|
|
833
|
-
throw new Error('Error adding output.');
|
|
834
|
-
}
|
|
835
|
-
this.tx.addOutput(output.script, output.value);
|
|
836
|
-
}
|
|
837
|
-
toBuffer() {
|
|
838
|
-
return this.tx.toBuffer();
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
function canFinalize(input, script, scriptType) {
|
|
842
|
-
switch (scriptType) {
|
|
843
|
-
case 'pubkey':
|
|
844
|
-
case 'pubkeyhash':
|
|
845
|
-
case 'witnesspubkeyhash':
|
|
846
|
-
return hasSigs(1, input.partialSig);
|
|
847
|
-
case 'multisig': {
|
|
848
|
-
const p2ms = payments.p2ms({
|
|
849
|
-
output: script,
|
|
850
|
-
});
|
|
851
|
-
if (p2ms.m === undefined)
|
|
852
|
-
throw new Error('Cannot determine m for multisig');
|
|
853
|
-
return hasSigs(p2ms.m, input.partialSig, p2ms.pubkeys);
|
|
854
|
-
}
|
|
855
|
-
case 'nonstandard':
|
|
856
|
-
return true;
|
|
857
|
-
default:
|
|
858
|
-
return false;
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
function hasSigs(neededSigs, partialSig, pubkeys) {
|
|
862
|
-
if (!partialSig)
|
|
863
|
-
return false;
|
|
864
|
-
let sigs;
|
|
865
|
-
if (pubkeys) {
|
|
866
|
-
sigs = pubkeys
|
|
867
|
-
.map((pkey) => {
|
|
868
|
-
const pubkey = compressPubkey(pkey);
|
|
869
|
-
return partialSig.find((pSig) => equals(pSig.pubkey, pubkey));
|
|
870
|
-
})
|
|
871
|
-
.filter((v) => !!v);
|
|
872
|
-
}
|
|
873
|
-
else {
|
|
874
|
-
sigs = partialSig;
|
|
875
|
-
}
|
|
876
|
-
if (sigs.length > neededSigs)
|
|
877
|
-
throw new Error('Too many signatures');
|
|
878
|
-
return sigs.length === neededSigs;
|
|
879
|
-
}
|
|
880
|
-
function bip32DerivationIsMine(root) {
|
|
881
|
-
return (d) => {
|
|
882
|
-
const fingerprint = root.fingerprint instanceof Uint8Array
|
|
883
|
-
? root.fingerprint
|
|
884
|
-
: new Uint8Array(root.fingerprint);
|
|
885
|
-
if (!equals(d.masterFingerprint, fingerprint))
|
|
886
|
-
return false;
|
|
887
|
-
const derivedPubkey = root.derivePath(d.path).publicKey;
|
|
888
|
-
const pubkey = derivedPubkey instanceof Uint8Array ? derivedPubkey : new Uint8Array(derivedPubkey);
|
|
889
|
-
if (!equals(pubkey, d.pubkey))
|
|
890
|
-
return false;
|
|
891
|
-
return true;
|
|
892
|
-
};
|
|
893
|
-
}
|
|
894
|
-
function checkFees(psbt, cache, opts) {
|
|
895
|
-
const feeRate = cache.feeRate || psbt.getFeeRate();
|
|
896
|
-
if (!cache.extractedTx)
|
|
897
|
-
throw new Error('Transaction not extracted');
|
|
898
|
-
const vsize = cache.extractedTx.virtualSize();
|
|
899
|
-
const satoshis = feeRate * vsize;
|
|
900
|
-
if (feeRate >= opts.maximumFeeRate) {
|
|
901
|
-
throw new Error(`Warning: You are paying around ${(satoshis / 1e8).toFixed(8)} in ` +
|
|
902
|
-
`fees, which is ${feeRate} satoshi per byte for a transaction ` +
|
|
903
|
-
`with a VSize of ${vsize} bytes (segwit counted as 0.25 byte per ` +
|
|
904
|
-
`byte). Use setMaximumFeeRate method to raise your threshold, or ` +
|
|
905
|
-
`pass true to the first arg of extractTransaction.`);
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
function getTxCacheValue(key, name, inputs, c, disableOutputChecks = false) {
|
|
909
|
-
if (!inputs.every(isFinalized))
|
|
910
|
-
throw new Error(`PSBT must be finalized to calculate ${name}`);
|
|
911
|
-
if (key === 'feeRate' && c.feeRate)
|
|
912
|
-
return c.feeRate;
|
|
913
|
-
if (key === 'fee' && c.fee)
|
|
914
|
-
return c.fee;
|
|
915
|
-
let tx;
|
|
916
|
-
let mustFinalize = true;
|
|
917
|
-
if (c.extractedTx) {
|
|
918
|
-
tx = c.extractedTx;
|
|
919
|
-
mustFinalize = false;
|
|
920
|
-
}
|
|
921
|
-
else {
|
|
922
|
-
tx = c.tx.clone();
|
|
923
|
-
}
|
|
924
|
-
inputFinalizeGetAmts(inputs, tx, c, mustFinalize, disableOutputChecks);
|
|
925
|
-
const value = key === 'feeRate' ? c.feeRate : c.fee;
|
|
926
|
-
if (value === undefined)
|
|
927
|
-
throw new Error(`Failed to calculate ${name}`);
|
|
928
|
-
return value;
|
|
929
|
-
}
|
|
930
|
-
export function getFinalScripts(inputIndex, input, script, isSegwit, isP2SH, isP2WSH, canRunChecks = true, solution) {
|
|
931
|
-
const scriptType = classifyScript(script);
|
|
932
|
-
if (!canFinalize(input, script, scriptType) && canRunChecks) {
|
|
933
|
-
throw new Error(`Can not finalize input #${inputIndex}`);
|
|
934
|
-
}
|
|
935
|
-
if (!input.partialSig)
|
|
936
|
-
throw new Error('Input missing partial signatures');
|
|
937
|
-
return prepareFinalScripts(script, scriptType, input.partialSig, isSegwit, isP2SH, isP2WSH, solution);
|
|
938
|
-
}
|
|
939
|
-
export function prepareFinalScripts(script, scriptType, partialSig, isSegwit, isP2SH, isP2WSH, solution) {
|
|
940
|
-
let finalScriptSig;
|
|
941
|
-
let finalScriptWitness;
|
|
942
|
-
// Wow, the payments API is very handy
|
|
943
|
-
const payment = getPayment(script, scriptType, partialSig);
|
|
944
|
-
const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment });
|
|
945
|
-
const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment });
|
|
946
|
-
if (isSegwit) {
|
|
947
|
-
if (p2wsh && p2wsh.witness) {
|
|
948
|
-
finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness);
|
|
949
|
-
}
|
|
950
|
-
else if (payment && payment.witness) {
|
|
951
|
-
finalScriptWitness = witnessStackToScriptWitness(payment.witness);
|
|
952
|
-
}
|
|
953
|
-
else {
|
|
954
|
-
// nonstandard segwit script
|
|
955
|
-
finalScriptWitness = witnessStackToScriptWitness(solution ?? [new Uint8Array([0x00])]);
|
|
956
|
-
}
|
|
957
|
-
if (p2sh) {
|
|
958
|
-
finalScriptSig = p2sh?.input;
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
else {
|
|
962
|
-
if (p2sh) {
|
|
963
|
-
finalScriptSig = p2sh?.input;
|
|
964
|
-
}
|
|
965
|
-
else {
|
|
966
|
-
if (!payment) {
|
|
967
|
-
finalScriptSig = (Array.isArray(solution) && solution[0] ? solution[0] : new Uint8Array([0x01]));
|
|
968
|
-
}
|
|
969
|
-
else {
|
|
970
|
-
finalScriptSig = payment.input;
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
return {
|
|
975
|
-
finalScriptSig,
|
|
976
|
-
finalScriptWitness,
|
|
977
|
-
};
|
|
978
|
-
}
|
|
979
|
-
function getHashAndSighashType(inputs, inputIndex, pubkey, cache, sighashTypes) {
|
|
980
|
-
const input = checkForInput(inputs, inputIndex);
|
|
981
|
-
const { hash, sighashType, script } = getHashForSig(inputIndex, input, cache, false, sighashTypes);
|
|
982
|
-
checkScriptForPubkey(pubkey, script, 'sign');
|
|
983
|
-
return {
|
|
984
|
-
hash,
|
|
985
|
-
sighashType,
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
|
-
function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) {
|
|
989
|
-
const unsignedTx = cache.tx;
|
|
990
|
-
const sighashType = input.sighashType || Transaction.SIGHASH_ALL;
|
|
991
|
-
checkSighashTypeAllowed(sighashType, sighashTypes);
|
|
992
|
-
let hash;
|
|
993
|
-
let prevout;
|
|
994
|
-
if (input.nonWitnessUtxo) {
|
|
995
|
-
const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(cache, input, inputIndex);
|
|
996
|
-
const prevoutHash = unsignedTx.ins[inputIndex].hash;
|
|
997
|
-
const utxoHash = nonWitnessUtxoTx.getHash();
|
|
998
|
-
// If a non-witness UTXO is provided, its hash must match the hash specified in the prevout
|
|
999
|
-
if (!equals(prevoutHash, utxoHash)) {
|
|
1000
|
-
throw new Error(`Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`);
|
|
1001
|
-
}
|
|
1002
|
-
const prevoutIndex = unsignedTx.ins[inputIndex].index;
|
|
1003
|
-
prevout = nonWitnessUtxoTx.outs[prevoutIndex];
|
|
1004
|
-
}
|
|
1005
|
-
else if (input.witnessUtxo) {
|
|
1006
|
-
prevout = {
|
|
1007
|
-
script: input.witnessUtxo.script,
|
|
1008
|
-
value: input.witnessUtxo.value,
|
|
1009
|
-
};
|
|
1010
|
-
}
|
|
1011
|
-
else {
|
|
1012
|
-
throw new Error('Need a Utxo input item for signing');
|
|
1013
|
-
}
|
|
1014
|
-
const { meaningfulScript, type } = getMeaningfulScript(prevout.script, inputIndex, 'input', input.redeemScript, input.witnessScript);
|
|
1015
|
-
const script = meaningfulScript;
|
|
1016
|
-
if (['p2sh-p2wsh', 'p2wsh'].indexOf(type) >= 0) {
|
|
1017
|
-
hash = unsignedTx.hashForWitnessV0(inputIndex, script, prevout.value, sighashType);
|
|
1018
|
-
}
|
|
1019
|
-
else if (isP2WPKH(meaningfulScript)) {
|
|
1020
|
-
// P2WPKH uses the P2PKH template for prevoutScript when signing
|
|
1021
|
-
const p2pkhPayment = payments.p2pkh({
|
|
1022
|
-
hash: meaningfulScript.subarray(2),
|
|
1023
|
-
});
|
|
1024
|
-
if (!p2pkhPayment.output)
|
|
1025
|
-
throw new Error('Unable to create signing script');
|
|
1026
|
-
hash = unsignedTx.hashForWitnessV0(inputIndex, p2pkhPayment.output, prevout.value, sighashType);
|
|
1027
|
-
}
|
|
1028
|
-
else {
|
|
1029
|
-
// non-segwit
|
|
1030
|
-
if (input.nonWitnessUtxo === undefined && !cache.unsafeSignNonSegwit)
|
|
1031
|
-
throw new Error(`Input #${inputIndex} has witnessUtxo but non-segwit script: ` +
|
|
1032
|
-
toHex(meaningfulScript));
|
|
1033
|
-
if (!forValidate && cache.unsafeSignNonSegwit)
|
|
1034
|
-
console.warn('Warning: Signing non-segwit inputs without the full parent transaction ' +
|
|
1035
|
-
'means there is a chance that a miner could feed you incorrect information ' +
|
|
1036
|
-
"to trick you into paying large fees. This behavior is the same as Psbt's predecessor " +
|
|
1037
|
-
'(TransactionBuilder - now removed) when signing non-segwit scripts. You are not ' +
|
|
1038
|
-
'able to export this Psbt with toBuffer|toBase64|toHex since it is not ' +
|
|
1039
|
-
'BIP174 compliant.\n*********************\nPROCEED WITH CAUTION!\n' +
|
|
1040
|
-
'*********************');
|
|
1041
|
-
hash = unsignedTx.hashForSignature(inputIndex, script, sighashType);
|
|
1042
|
-
}
|
|
1043
|
-
return {
|
|
1044
|
-
script,
|
|
1045
|
-
sighashType,
|
|
1046
|
-
hash,
|
|
1047
|
-
};
|
|
1048
|
-
}
|
|
1049
|
-
function getAllTaprootHashesForSig(inputIndex, input, inputs, cache) {
|
|
1050
|
-
const allPublicKeys = [];
|
|
1051
|
-
if (input.tapInternalKey) {
|
|
1052
|
-
const key = getPrevoutTaprootKey(inputIndex, input, cache);
|
|
1053
|
-
if (key) {
|
|
1054
|
-
allPublicKeys.push(key);
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
if (input.tapScriptSig) {
|
|
1058
|
-
const tapScriptPubkeys = input.tapScriptSig.map((tss) => tss.pubkey);
|
|
1059
|
-
allPublicKeys.push(...tapScriptPubkeys);
|
|
1060
|
-
}
|
|
1061
|
-
const allHashes = allPublicKeys.map((pubicKey) => getTaprootHashesForSig(inputIndex, input, inputs, pubicKey, cache));
|
|
1062
|
-
return allHashes.flat();
|
|
1063
|
-
}
|
|
1064
|
-
function getPrevoutTaprootKey(inputIndex, input, cache) {
|
|
1065
|
-
const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache);
|
|
1066
|
-
return isP2TR(script) ? script.subarray(2, 34) : null;
|
|
1067
|
-
}
|
|
1068
|
-
function trimTaprootSig(signature) {
|
|
1069
|
-
return signature.length === 64 ? signature : signature.subarray(0, 64);
|
|
1070
|
-
}
|
|
1071
|
-
function getTaprootHashesForSig(inputIndex, input, inputs, pubkey, cache, tapLeafHashToSign, allowedSighashTypes) {
|
|
1072
|
-
const unsignedTx = cache.tx;
|
|
1073
|
-
const sighashType = input.sighashType || Transaction.SIGHASH_DEFAULT;
|
|
1074
|
-
checkSighashTypeAllowed(sighashType, allowedSighashTypes);
|
|
1075
|
-
if (!cache.prevOuts) {
|
|
1076
|
-
const prevOuts = inputs.map((i, index) => getScriptAndAmountFromUtxo(index, i, cache));
|
|
1077
|
-
cache.prevOuts = prevOuts;
|
|
1078
|
-
cache.signingScripts = prevOuts.map((o) => o.script);
|
|
1079
|
-
cache.values = prevOuts.map((o) => o.value);
|
|
1080
|
-
}
|
|
1081
|
-
const signingScripts = cache.signingScripts;
|
|
1082
|
-
const values = cache.values;
|
|
1083
|
-
// Compute taproot hash cache once for all inputs (O(n) -> O(1) per input)
|
|
1084
|
-
if (!cache.taprootHashCache) {
|
|
1085
|
-
cache.taprootHashCache = unsignedTx.getTaprootHashCache(signingScripts, values);
|
|
1086
|
-
}
|
|
1087
|
-
const taprootCache = cache.taprootHashCache;
|
|
1088
|
-
const hashes = [];
|
|
1089
|
-
if (input.tapInternalKey && !tapLeafHashToSign) {
|
|
1090
|
-
const outputKey = getPrevoutTaprootKey(inputIndex, input, cache) || new Uint8Array(0);
|
|
1091
|
-
if (equals(toXOnly(pubkey), outputKey)) {
|
|
1092
|
-
const tapKeyHash = unsignedTx.hashForWitnessV1(inputIndex, signingScripts, values, sighashType, undefined, undefined, taprootCache);
|
|
1093
|
-
hashes.push({ pubkey: pubkey, hash: tapKeyHash });
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
const tapLeafHashes = (input.tapLeafScript || [])
|
|
1097
|
-
.filter((tapLeaf) => pubkeyInScript(pubkey, tapLeaf.script))
|
|
1098
|
-
.map((tapLeaf) => {
|
|
1099
|
-
const hash = tapleafHash({
|
|
1100
|
-
output: tapLeaf.script,
|
|
1101
|
-
version: tapLeaf.leafVersion,
|
|
1102
|
-
});
|
|
1103
|
-
return Object.assign({ hash }, tapLeaf);
|
|
1104
|
-
})
|
|
1105
|
-
.filter((tapLeaf) => !tapLeafHashToSign || equals(tapLeafHashToSign, tapLeaf.hash))
|
|
1106
|
-
.map((tapLeaf) => {
|
|
1107
|
-
const tapScriptHash = unsignedTx.hashForWitnessV1(inputIndex, signingScripts, values, sighashType, tapLeaf.hash, undefined, taprootCache);
|
|
1108
|
-
return {
|
|
1109
|
-
pubkey: pubkey,
|
|
1110
|
-
hash: tapScriptHash,
|
|
1111
|
-
leafHash: tapLeaf.hash,
|
|
1112
|
-
};
|
|
1113
|
-
});
|
|
1114
|
-
return hashes.concat(tapLeafHashes);
|
|
1115
|
-
}
|
|
1116
|
-
function checkSighashTypeAllowed(sighashType, sighashTypes) {
|
|
1117
|
-
if (sighashTypes && sighashTypes.indexOf(sighashType) < 0) {
|
|
1118
|
-
const str = sighashTypeToString(sighashType);
|
|
1119
|
-
throw new Error(`Sighash type is not allowed. Retry the sign method passing the ` +
|
|
1120
|
-
`sighashTypes array of whitelisted types. Sighash type: ${str}`);
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
function getPayment(script, scriptType, partialSig) {
|
|
1124
|
-
const scriptBranded = script;
|
|
1125
|
-
switch (scriptType) {
|
|
1126
|
-
case 'multisig': {
|
|
1127
|
-
const sigs = getSortedSigs(script, partialSig);
|
|
1128
|
-
return payments.p2ms({
|
|
1129
|
-
output: scriptBranded,
|
|
1130
|
-
signatures: sigs,
|
|
1131
|
-
});
|
|
1132
|
-
}
|
|
1133
|
-
case 'pubkey':
|
|
1134
|
-
return payments.p2pk({
|
|
1135
|
-
output: scriptBranded,
|
|
1136
|
-
signature: partialSig[0].signature,
|
|
1137
|
-
});
|
|
1138
|
-
case 'pubkeyhash':
|
|
1139
|
-
return payments.p2pkh({
|
|
1140
|
-
output: scriptBranded,
|
|
1141
|
-
pubkey: partialSig[0].pubkey,
|
|
1142
|
-
signature: partialSig[0].signature,
|
|
1143
|
-
});
|
|
1144
|
-
case 'witnesspubkeyhash':
|
|
1145
|
-
return payments.p2wpkh({
|
|
1146
|
-
output: scriptBranded,
|
|
1147
|
-
pubkey: partialSig[0].pubkey,
|
|
1148
|
-
signature: partialSig[0].signature,
|
|
1149
|
-
});
|
|
1150
|
-
default:
|
|
1151
|
-
throw new Error(`Unknown script type: ${scriptType}`);
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
function getScriptFromInput(inputIndex, input, cache) {
|
|
1155
|
-
const unsignedTx = cache.tx;
|
|
1156
|
-
const res = {
|
|
1157
|
-
script: null,
|
|
1158
|
-
isSegwit: false,
|
|
1159
|
-
isP2SH: false,
|
|
1160
|
-
isP2WSH: false,
|
|
1161
|
-
};
|
|
1162
|
-
res.isP2SH = !!input.redeemScript;
|
|
1163
|
-
res.isP2WSH = !!input.witnessScript;
|
|
1164
|
-
if (input.witnessScript) {
|
|
1165
|
-
res.script = input.witnessScript;
|
|
1166
|
-
}
|
|
1167
|
-
else if (input.redeemScript) {
|
|
1168
|
-
res.script = input.redeemScript;
|
|
1169
|
-
}
|
|
1170
|
-
else {
|
|
1171
|
-
if (input.nonWitnessUtxo) {
|
|
1172
|
-
const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(cache, input, inputIndex);
|
|
1173
|
-
const prevoutIndex = unsignedTx.ins[inputIndex].index;
|
|
1174
|
-
res.script = nonWitnessUtxoTx.outs[prevoutIndex].script;
|
|
1175
|
-
}
|
|
1176
|
-
else if (input.witnessUtxo) {
|
|
1177
|
-
res.script = input.witnessUtxo.script;
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
if (input.witnessScript || (res.script && isP2WPKH(res.script))) {
|
|
1181
|
-
res.isSegwit = true;
|
|
1182
|
-
}
|
|
1183
|
-
else {
|
|
1184
|
-
try {
|
|
1185
|
-
const output = res.script;
|
|
1186
|
-
if (!output)
|
|
1187
|
-
throw new TypeError('Invalid script for segwit address');
|
|
1188
|
-
res.isSegwit = isUnknownSegwitVersion(output);
|
|
1189
|
-
}
|
|
1190
|
-
catch (e) { }
|
|
1191
|
-
}
|
|
1192
|
-
return res;
|
|
1193
|
-
}
|
|
1194
|
-
function getSignersFromHD(inputIndex, inputs, hdKeyPair) {
|
|
1195
|
-
const input = checkForInput(inputs, inputIndex);
|
|
1196
|
-
if (!input.bip32Derivation || input.bip32Derivation.length === 0) {
|
|
1197
|
-
throw new Error('Need bip32Derivation to sign with HD');
|
|
1198
|
-
}
|
|
1199
|
-
const myDerivations = input.bip32Derivation
|
|
1200
|
-
.map((bipDv) => {
|
|
1201
|
-
if (equals(bipDv.masterFingerprint, hdKeyPair.fingerprint)) {
|
|
1202
|
-
return bipDv;
|
|
1203
|
-
}
|
|
1204
|
-
else {
|
|
1205
|
-
return;
|
|
1206
|
-
}
|
|
1207
|
-
})
|
|
1208
|
-
.filter((v) => !!v);
|
|
1209
|
-
if (myDerivations.length === 0) {
|
|
1210
|
-
throw new Error('Need one bip32Derivation masterFingerprint to match the HDSigner fingerprint');
|
|
1211
|
-
}
|
|
1212
|
-
return myDerivations.map((bipDv) => {
|
|
1213
|
-
const node = hdKeyPair.derivePath(bipDv.path);
|
|
1214
|
-
if (!equals(bipDv.pubkey, node.publicKey)) {
|
|
1215
|
-
throw new Error('pubkey did not match bip32Derivation');
|
|
1216
|
-
}
|
|
1217
|
-
return node;
|
|
1218
|
-
});
|
|
1219
|
-
}
|
|
1220
|
-
function getSortedSigs(script, partialSig) {
|
|
1221
|
-
const p2ms = payments.p2ms({ output: script });
|
|
1222
|
-
if (!p2ms.pubkeys)
|
|
1223
|
-
throw new Error('Cannot extract pubkeys from multisig script');
|
|
1224
|
-
// for each pubkey in order of p2ms script
|
|
1225
|
-
const result = [];
|
|
1226
|
-
for (const pk of p2ms.pubkeys) {
|
|
1227
|
-
// filter partialSig array by pubkey being equal
|
|
1228
|
-
const matched = partialSig.filter((ps) => {
|
|
1229
|
-
return equals(ps.pubkey, pk);
|
|
1230
|
-
})[0];
|
|
1231
|
-
if (matched) {
|
|
1232
|
-
result.push(new Uint8Array(matched.signature));
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
return result;
|
|
1236
|
-
}
|
|
1237
|
-
function addNonWitnessTxCache(cache, input, inputIndex) {
|
|
1238
|
-
if (!input.nonWitnessUtxo)
|
|
1239
|
-
throw new Error('nonWitnessUtxo is required');
|
|
1240
|
-
// Prevent prototype pollution - ensure input is a valid object
|
|
1241
|
-
if (input === null || input === Object.prototype) {
|
|
1242
|
-
throw new Error('Invalid input object');
|
|
1243
|
-
}
|
|
1244
|
-
const nonWitnessUtxoBuf = input.nonWitnessUtxo;
|
|
1245
|
-
cache.nonWitnessUtxoBufCache[inputIndex] = nonWitnessUtxoBuf;
|
|
1246
|
-
cache.nonWitnessUtxoTxCache[inputIndex] = Transaction.fromBuffer(nonWitnessUtxoBuf);
|
|
1247
|
-
const self = cache;
|
|
1248
|
-
const selfIndex = inputIndex;
|
|
1249
|
-
delete input.nonWitnessUtxo;
|
|
1250
|
-
// Using Reflect.defineProperty to avoid prototype pollution concerns
|
|
1251
|
-
Reflect.defineProperty(input, 'nonWitnessUtxo', {
|
|
1252
|
-
enumerable: true,
|
|
1253
|
-
get() {
|
|
1254
|
-
const buf = self.nonWitnessUtxoBufCache[selfIndex];
|
|
1255
|
-
const txCache = self.nonWitnessUtxoTxCache[selfIndex];
|
|
1256
|
-
if (buf !== undefined) {
|
|
1257
|
-
return buf;
|
|
1258
|
-
}
|
|
1259
|
-
else {
|
|
1260
|
-
const newBuf = txCache.toBuffer();
|
|
1261
|
-
self.nonWitnessUtxoBufCache[selfIndex] = newBuf;
|
|
1262
|
-
return newBuf;
|
|
1263
|
-
}
|
|
1264
|
-
},
|
|
1265
|
-
set(data) {
|
|
1266
|
-
self.nonWitnessUtxoBufCache[selfIndex] = data;
|
|
1267
|
-
},
|
|
1268
|
-
});
|
|
1269
|
-
}
|
|
1270
|
-
function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize, disableOutputChecks) {
|
|
1271
|
-
let inputAmount = 0n;
|
|
1272
|
-
inputs.forEach((input, idx) => {
|
|
1273
|
-
if (mustFinalize && input.finalScriptSig)
|
|
1274
|
-
tx.ins[idx].script = input.finalScriptSig;
|
|
1275
|
-
if (mustFinalize && input.finalScriptWitness) {
|
|
1276
|
-
tx.ins[idx].witness = scriptWitnessToWitnessStack(input.finalScriptWitness);
|
|
1277
|
-
}
|
|
1278
|
-
if (input.witnessUtxo) {
|
|
1279
|
-
inputAmount += input.witnessUtxo.value;
|
|
1280
|
-
}
|
|
1281
|
-
else if (input.nonWitnessUtxo) {
|
|
1282
|
-
const nwTx = nonWitnessUtxoTxFromCache(cache, input, idx);
|
|
1283
|
-
const vout = tx.ins[idx].index;
|
|
1284
|
-
const out = nwTx.outs[vout];
|
|
1285
|
-
inputAmount += out.value;
|
|
1286
|
-
}
|
|
1287
|
-
});
|
|
1288
|
-
const outputAmount = tx.outs.reduce((total, o) => total + o.value, 0n);
|
|
1289
|
-
const fee = inputAmount - outputAmount;
|
|
1290
|
-
if (!disableOutputChecks) {
|
|
1291
|
-
if (fee < 0n) {
|
|
1292
|
-
throw new Error(`Outputs are spending more than Inputs ${inputAmount} < ${outputAmount}`);
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
const bytes = tx.virtualSize();
|
|
1296
|
-
cache.fee = Number(fee);
|
|
1297
|
-
cache.extractedTx = tx;
|
|
1298
|
-
cache.feeRate = Math.floor(Number(fee) / bytes);
|
|
1299
|
-
}
|
|
1300
|
-
function nonWitnessUtxoTxFromCache(cache, input, inputIndex) {
|
|
1301
|
-
const c = cache.nonWitnessUtxoTxCache;
|
|
1302
|
-
if (!c[inputIndex]) {
|
|
1303
|
-
addNonWitnessTxCache(cache, input, inputIndex);
|
|
1304
|
-
}
|
|
1305
|
-
return c[inputIndex];
|
|
1306
|
-
}
|
|
1307
|
-
function getScriptFromUtxo(inputIndex, input, cache) {
|
|
1308
|
-
const { script } = getScriptAndAmountFromUtxo(inputIndex, input, cache);
|
|
1309
|
-
return script;
|
|
1310
|
-
}
|
|
1311
|
-
function getScriptAndAmountFromUtxo(inputIndex, input, cache) {
|
|
1312
|
-
if (input.witnessUtxo !== undefined) {
|
|
1313
|
-
return {
|
|
1314
|
-
script: input.witnessUtxo.script,
|
|
1315
|
-
value: input.witnessUtxo.value,
|
|
1316
|
-
};
|
|
1317
|
-
}
|
|
1318
|
-
else if (input.nonWitnessUtxo !== undefined) {
|
|
1319
|
-
const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(cache, input, inputIndex);
|
|
1320
|
-
const o = nonWitnessUtxoTx.outs[cache.tx.ins[inputIndex].index];
|
|
1321
|
-
return { script: o.script, value: o.value };
|
|
1322
|
-
}
|
|
1323
|
-
else {
|
|
1324
|
-
throw new Error("Can't find pubkey in input without Utxo data");
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
function pubkeyInInput(pubkey, input, inputIndex, cache) {
|
|
1328
|
-
const script = getScriptFromUtxo(inputIndex, input, cache);
|
|
1329
|
-
const { meaningfulScript } = getMeaningfulScript(script, inputIndex, 'input', input.redeemScript, input.witnessScript);
|
|
1330
|
-
return pubkeyInScript(pubkey, meaningfulScript);
|
|
1331
|
-
}
|
|
1332
|
-
function pubkeyInOutput(pubkey, output, outputIndex, cache) {
|
|
1333
|
-
const script = cache.tx.outs[outputIndex].script;
|
|
1334
|
-
const { meaningfulScript } = getMeaningfulScript(script, outputIndex, 'output', output.redeemScript, output.witnessScript);
|
|
1335
|
-
return pubkeyInScript(pubkey, meaningfulScript);
|
|
1336
|
-
}
|
|
1337
|
-
function redeemFromFinalScriptSig(finalScript) {
|
|
1338
|
-
if (!finalScript)
|
|
1339
|
-
return;
|
|
1340
|
-
const decomp = bscript.decompile(finalScript);
|
|
1341
|
-
if (!decomp)
|
|
1342
|
-
return;
|
|
1343
|
-
const lastItem = decomp[decomp.length - 1];
|
|
1344
|
-
if (!(lastItem instanceof Uint8Array) || isPubkeyLike(lastItem) || isSigLike(lastItem))
|
|
1345
|
-
return;
|
|
1346
|
-
const sDecomp = bscript.decompile(lastItem);
|
|
1347
|
-
if (!sDecomp)
|
|
1348
|
-
return;
|
|
1349
|
-
return lastItem;
|
|
1350
|
-
}
|
|
1351
|
-
function redeemFromFinalWitnessScript(finalScript) {
|
|
1352
|
-
if (!finalScript)
|
|
1353
|
-
return;
|
|
1354
|
-
const decomp = scriptWitnessToWitnessStack(finalScript);
|
|
1355
|
-
const lastItem = decomp[decomp.length - 1];
|
|
1356
|
-
if (isPubkeyLike(lastItem))
|
|
1357
|
-
return;
|
|
1358
|
-
const sDecomp = bscript.decompile(lastItem);
|
|
1359
|
-
if (!sDecomp)
|
|
1360
|
-
return;
|
|
1361
|
-
return lastItem;
|
|
1362
|
-
}
|
|
1363
735
|
//# sourceMappingURL=psbt.js.map
|