@btc-vision/bitcoin 6.5.6 → 7.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HOW_TO_WRITE_GOOD_CODE.md +2436 -0
- package/benchmark/psbt-2000-inputs.bench.ts +178 -0
- package/benchmark/signing.bench.ts +147 -0
- package/browser/address.d.ts +56 -9
- package/browser/address.d.ts.map +1 -0
- package/browser/bech32utils.d.ts +9 -1
- package/browser/bech32utils.d.ts.map +1 -0
- package/browser/bip66.d.ts +11 -6
- package/browser/bip66.d.ts.map +1 -0
- package/browser/block.d.ts +117 -11
- package/browser/block.d.ts.map +1 -0
- package/browser/branded.d.ts +20 -0
- package/browser/branded.d.ts.map +1 -0
- package/browser/crypto/crypto.d.ts +1 -0
- package/browser/crypto/crypto.d.ts.map +1 -0
- package/browser/crypto.d.ts +46 -7
- package/browser/crypto.d.ts.map +1 -0
- package/browser/ecc/context.d.ts +129 -0
- package/browser/ecc/context.d.ts.map +1 -0
- package/browser/ecc/index.d.ts +11 -0
- package/browser/ecc/index.d.ts.map +1 -0
- package/browser/ecc/types.d.ts +128 -0
- package/browser/ecc/types.d.ts.map +1 -0
- package/browser/ecpair.d.ts +99 -0
- package/browser/errors.d.ts +124 -0
- package/browser/errors.d.ts.map +1 -0
- package/browser/index.d.ts +32 -5
- package/browser/index.d.ts.map +1 -0
- package/browser/index.js +12482 -101
- package/browser/io/BinaryReader.d.ts +276 -0
- package/browser/io/BinaryReader.d.ts.map +1 -0
- package/browser/io/BinaryWriter.d.ts +391 -0
- package/browser/io/BinaryWriter.d.ts.map +1 -0
- package/browser/io/MemoryPool.d.ts +220 -0
- package/browser/io/MemoryPool.d.ts.map +1 -0
- package/browser/io/base64.d.ts +13 -0
- package/browser/io/base64.d.ts.map +1 -0
- package/browser/io/hex.d.ts +67 -0
- package/browser/io/hex.d.ts.map +1 -0
- package/browser/io/index.d.ts +17 -0
- package/browser/io/index.d.ts.map +1 -0
- package/browser/io/utils.d.ts +199 -0
- package/browser/io/utils.d.ts.map +1 -0
- package/browser/merkle.d.ts +10 -1
- package/browser/merkle.d.ts.map +1 -0
- package/browser/networks.d.ts +70 -9
- package/browser/networks.d.ts.map +1 -0
- package/browser/opcodes.d.ts +1 -0
- package/browser/opcodes.d.ts.map +1 -0
- package/browser/payments/bip341.d.ts +35 -9
- package/browser/payments/bip341.d.ts.map +1 -0
- package/browser/payments/embed.d.ts +112 -1
- package/browser/payments/embed.d.ts.map +1 -0
- package/browser/payments/index.d.ts +17 -10
- package/browser/payments/index.d.ts.map +1 -0
- package/browser/payments/p2ms.d.ts +150 -0
- package/browser/payments/p2ms.d.ts.map +1 -0
- package/browser/payments/p2op.d.ts +150 -24
- package/browser/payments/p2op.d.ts.map +1 -0
- package/browser/payments/p2pk.d.ts +154 -1
- package/browser/payments/p2pk.d.ts.map +1 -0
- package/browser/payments/p2pkh.d.ts +176 -1
- package/browser/payments/p2pkh.d.ts.map +1 -0
- package/browser/payments/p2sh.d.ts +150 -1
- package/browser/payments/p2sh.d.ts.map +1 -0
- package/browser/payments/p2tr.d.ts +185 -1
- package/browser/payments/p2tr.d.ts.map +1 -0
- package/browser/payments/p2wpkh.d.ts +161 -1
- package/browser/payments/p2wpkh.d.ts.map +1 -0
- package/browser/payments/p2wsh.d.ts +146 -1
- package/browser/payments/p2wsh.d.ts.map +1 -0
- package/browser/payments/types.d.ts +94 -64
- package/browser/payments/types.d.ts.map +1 -0
- package/browser/psbt/bip371.d.ts +34 -8
- package/browser/psbt/bip371.d.ts.map +1 -0
- package/browser/psbt/psbtutils.d.ts +56 -16
- package/browser/psbt/psbtutils.d.ts.map +1 -0
- package/browser/psbt/types.d.ts +245 -0
- package/browser/psbt/types.d.ts.map +1 -0
- package/browser/psbt/utils.d.ts +64 -0
- package/browser/psbt/utils.d.ts.map +1 -0
- package/browser/psbt/validation.d.ts +84 -0
- package/browser/psbt/validation.d.ts.map +1 -0
- package/browser/psbt.d.ts +82 -118
- package/browser/psbt.d.ts.map +1 -0
- package/browser/pubkey.d.ts +27 -6
- package/browser/pubkey.d.ts.map +1 -0
- package/browser/push_data.d.ts +24 -2
- package/browser/push_data.d.ts.map +1 -0
- package/browser/script.d.ts +33 -8
- package/browser/script.d.ts.map +1 -0
- package/browser/script_number.d.ts +17 -0
- package/browser/script_number.d.ts.map +1 -0
- package/browser/script_signature.d.ts +23 -5
- package/browser/script_signature.d.ts.map +1 -0
- package/browser/transaction.d.ts +160 -18
- package/browser/transaction.d.ts.map +1 -0
- package/browser/types.d.ts +36 -38
- package/browser/types.d.ts.map +1 -0
- package/browser/workers/WorkerSigningPool.d.ts +143 -0
- package/browser/workers/WorkerSigningPool.d.ts.map +1 -0
- package/browser/workers/WorkerSigningPool.node.d.ts +116 -0
- package/browser/workers/WorkerSigningPool.node.d.ts.map +1 -0
- package/browser/workers/ecc-bundle.d.ts +25 -0
- package/browser/workers/ecc-bundle.d.ts.map +1 -0
- package/browser/workers/index.d.ts +91 -0
- package/browser/workers/index.d.ts.map +1 -0
- package/browser/workers/psbt-parallel.d.ts +88 -0
- package/browser/workers/psbt-parallel.d.ts.map +1 -0
- package/browser/workers/signing-worker.d.ts +37 -0
- package/browser/workers/signing-worker.d.ts.map +1 -0
- package/browser/workers/types.d.ts +365 -0
- package/browser/workers/types.d.ts.map +1 -0
- package/build/address.d.ts +57 -10
- package/build/address.d.ts.map +1 -0
- package/build/address.js +80 -24
- package/build/address.js.map +1 -0
- package/build/bech32utils.d.ts +9 -1
- package/build/bech32utils.d.ts.map +1 -0
- package/build/bech32utils.js +10 -2
- package/build/bech32utils.js.map +1 -0
- package/build/bip66.d.ts +11 -6
- package/build/bip66.d.ts.map +1 -0
- package/build/bip66.js +32 -3
- package/build/bip66.js.map +1 -0
- package/build/block.d.ts +117 -11
- package/build/block.d.ts.map +1 -0
- package/build/block.js +204 -72
- package/build/block.js.map +1 -0
- package/build/branded.d.ts +20 -0
- package/build/branded.d.ts.map +1 -0
- package/build/branded.js +7 -0
- package/build/branded.js.map +1 -0
- package/build/crypto/crypto.d.ts +1 -0
- package/build/crypto/crypto.d.ts.map +1 -0
- package/build/crypto/crypto.js +1 -0
- package/build/crypto/crypto.js.map +1 -0
- package/build/crypto.d.ts +46 -7
- package/build/crypto.d.ts.map +1 -0
- package/build/crypto.js +65 -20
- package/build/crypto.js.map +1 -0
- package/build/ecc/context.d.ts +135 -0
- package/build/ecc/context.d.ts.map +1 -0
- package/build/ecc/context.js +232 -0
- package/build/ecc/context.js.map +1 -0
- package/build/ecc/index.d.ts +11 -0
- package/build/ecc/index.d.ts.map +1 -0
- package/build/ecc/index.js +11 -0
- package/build/ecc/index.js.map +1 -0
- package/build/ecc/types.d.ts +134 -0
- package/build/ecc/types.d.ts.map +1 -0
- package/build/ecc/types.js +8 -0
- package/build/ecc/types.js.map +1 -0
- package/build/errors.d.ts +124 -0
- package/build/errors.d.ts.map +1 -0
- package/build/errors.js +155 -0
- package/build/errors.js.map +1 -0
- package/build/index.d.ts +32 -5
- package/build/index.d.ts.map +1 -0
- package/build/index.js +26 -3
- package/build/index.js.map +1 -0
- package/build/io/BinaryReader.d.ts +276 -0
- package/build/io/BinaryReader.d.ts.map +1 -0
- package/build/io/BinaryReader.js +425 -0
- package/build/io/BinaryReader.js.map +1 -0
- package/build/io/BinaryWriter.d.ts +391 -0
- package/build/io/BinaryWriter.d.ts.map +1 -0
- package/build/io/BinaryWriter.js +611 -0
- package/build/io/BinaryWriter.js.map +1 -0
- package/build/io/MemoryPool.d.ts +220 -0
- package/build/io/MemoryPool.d.ts.map +1 -0
- package/build/io/MemoryPool.js +309 -0
- package/build/io/MemoryPool.js.map +1 -0
- package/build/io/base64.d.ts +13 -0
- package/build/io/base64.d.ts.map +1 -0
- package/build/io/base64.js +20 -0
- package/build/io/base64.js.map +1 -0
- package/build/io/hex.d.ts +67 -0
- package/build/io/hex.d.ts.map +1 -0
- package/build/io/hex.js +138 -0
- package/build/io/hex.js.map +1 -0
- package/build/io/index.d.ts +17 -0
- package/build/io/index.d.ts.map +1 -0
- package/build/io/index.js +23 -0
- package/build/io/index.js.map +1 -0
- package/build/io/utils.d.ts +199 -0
- package/build/io/utils.d.ts.map +1 -0
- package/build/io/utils.js +271 -0
- package/build/io/utils.js.map +1 -0
- package/build/merkle.d.ts +10 -1
- package/build/merkle.d.ts.map +1 -0
- package/build/merkle.js +12 -1
- package/build/merkle.js.map +1 -0
- package/build/networks.d.ts +70 -9
- package/build/networks.d.ts.map +1 -0
- package/build/networks.js +90 -4
- package/build/networks.js.map +1 -0
- package/build/opcodes.d.ts +1 -0
- package/build/opcodes.d.ts.map +1 -0
- package/build/opcodes.js +1 -0
- package/build/opcodes.js.map +1 -0
- package/build/payments/bip341.d.ts +36 -9
- package/build/payments/bip341.d.ts.map +1 -0
- package/build/payments/bip341.js +35 -15
- package/build/payments/bip341.js.map +1 -0
- package/build/payments/embed.d.ts +120 -1
- package/build/payments/embed.d.ts.map +1 -0
- package/build/payments/embed.js +215 -34
- package/build/payments/embed.js.map +1 -0
- package/build/payments/index.d.ts +17 -10
- package/build/payments/index.d.ts.map +1 -0
- package/build/payments/index.js +20 -10
- package/build/payments/index.js.map +1 -0
- package/build/payments/p2ms.d.ts +159 -1
- package/build/payments/p2ms.d.ts.map +1 -0
- package/build/payments/p2ms.js +427 -108
- package/build/payments/p2ms.js.map +1 -0
- package/build/payments/p2op.d.ts +158 -24
- package/build/payments/p2op.d.ts.map +1 -0
- package/build/payments/p2op.js +379 -93
- package/build/payments/p2op.js.map +1 -0
- package/build/payments/p2pk.d.ts +162 -1
- package/build/payments/p2pk.d.ts.map +1 -0
- package/build/payments/p2pk.js +327 -58
- package/build/payments/p2pk.js.map +1 -0
- package/build/payments/p2pkh.d.ts +185 -1
- package/build/payments/p2pkh.d.ts.map +1 -0
- package/build/payments/p2pkh.js +467 -114
- package/build/payments/p2pkh.js.map +1 -0
- package/build/payments/p2sh.d.ts +159 -1
- package/build/payments/p2sh.d.ts.map +1 -0
- package/build/payments/p2sh.js +500 -152
- package/build/payments/p2sh.js.map +1 -0
- package/build/payments/p2tr.d.ts +193 -1
- package/build/payments/p2tr.d.ts.map +1 -0
- package/build/payments/p2tr.js +592 -174
- package/build/payments/p2tr.js.map +1 -0
- package/build/payments/p2wpkh.d.ts +170 -1
- package/build/payments/p2wpkh.d.ts.map +1 -0
- package/build/payments/p2wpkh.js +429 -104
- package/build/payments/p2wpkh.js.map +1 -0
- package/build/payments/p2wsh.d.ts +155 -1
- package/build/payments/p2wsh.d.ts.map +1 -0
- package/build/payments/p2wsh.js +466 -144
- package/build/payments/p2wsh.js.map +1 -0
- package/build/payments/types.d.ts +98 -64
- package/build/payments/types.d.ts.map +1 -0
- package/build/payments/types.js +17 -13
- package/build/payments/types.js.map +1 -0
- package/build/psbt/bip371.d.ts +35 -9
- package/build/psbt/bip371.d.ts.map +1 -0
- package/build/psbt/bip371.js +113 -28
- package/build/psbt/bip371.js.map +1 -0
- package/build/psbt/psbtutils.d.ts +56 -16
- package/build/psbt/psbtutils.d.ts.map +1 -0
- package/build/psbt/psbtutils.js +71 -16
- package/build/psbt/psbtutils.js.map +1 -0
- package/build/psbt/types.d.ts +249 -0
- package/build/psbt/types.d.ts.map +1 -0
- package/build/psbt/types.js +6 -0
- package/build/psbt/types.js.map +1 -0
- package/build/psbt/utils.d.ts +68 -0
- package/build/psbt/utils.d.ts.map +1 -0
- package/build/psbt/utils.js +171 -0
- package/build/psbt/utils.js.map +1 -0
- package/build/psbt/validation.d.ts +88 -0
- package/build/psbt/validation.d.ts.map +1 -0
- package/build/psbt/validation.js +149 -0
- package/build/psbt/validation.js.map +1 -0
- package/build/psbt.d.ts +84 -120
- package/build/psbt.d.ts.map +1 -0
- package/build/psbt.js +411 -412
- package/build/psbt.js.map +1 -0
- package/build/pubkey.d.ts +27 -6
- package/build/pubkey.d.ts.map +1 -0
- package/build/pubkey.js +36 -12
- package/build/pubkey.js.map +1 -0
- package/build/push_data.d.ts +24 -2
- package/build/push_data.d.ts.map +1 -0
- package/build/push_data.js +44 -12
- package/build/push_data.js.map +1 -0
- package/build/script.d.ts +33 -8
- package/build/script.d.ts.map +1 -0
- package/build/script.js +100 -36
- package/build/script.js.map +1 -0
- package/build/script_number.d.ts +17 -0
- package/build/script_number.d.ts.map +1 -0
- package/build/script_number.js +19 -0
- package/build/script_number.js.map +1 -0
- package/build/script_signature.d.ts +23 -5
- package/build/script_signature.d.ts.map +1 -0
- package/build/script_signature.js +48 -15
- package/build/script_signature.js.map +1 -0
- package/build/transaction.d.ts +160 -18
- package/build/transaction.d.ts.map +1 -0
- package/build/transaction.js +443 -176
- package/build/transaction.js.map +1 -0
- package/build/tsconfig.build.tsbuildinfo +1 -0
- package/build/types.d.ts +36 -38
- package/build/types.d.ts.map +1 -0
- package/build/types.js +175 -57
- package/build/types.js.map +1 -0
- package/build/workers/WorkerSigningPool.d.ts +174 -0
- package/build/workers/WorkerSigningPool.d.ts.map +1 -0
- package/build/workers/WorkerSigningPool.js +553 -0
- package/build/workers/WorkerSigningPool.js.map +1 -0
- package/build/workers/WorkerSigningPool.node.d.ts +124 -0
- package/build/workers/WorkerSigningPool.node.d.ts.map +1 -0
- package/build/workers/WorkerSigningPool.node.js +753 -0
- package/build/workers/WorkerSigningPool.node.js.map +1 -0
- package/build/workers/ecc-bundle.d.ts +25 -0
- package/build/workers/ecc-bundle.d.ts.map +1 -0
- package/build/workers/ecc-bundle.js +25 -0
- package/build/workers/ecc-bundle.js.map +1 -0
- package/build/workers/index.d.ts +91 -0
- package/build/workers/index.d.ts.map +1 -0
- package/build/workers/index.js +114 -0
- package/build/workers/index.js.map +1 -0
- package/build/workers/psbt-parallel.d.ts +117 -0
- package/build/workers/psbt-parallel.d.ts.map +1 -0
- package/build/workers/psbt-parallel.js +233 -0
- package/build/workers/psbt-parallel.js.map +1 -0
- package/build/workers/signing-worker.d.ts +37 -0
- package/build/workers/signing-worker.d.ts.map +1 -0
- package/build/workers/signing-worker.js +350 -0
- package/build/workers/signing-worker.js.map +1 -0
- package/build/workers/types.d.ts +365 -0
- package/build/workers/types.d.ts.map +1 -0
- package/build/workers/types.js +60 -0
- package/build/workers/types.js.map +1 -0
- package/package.json +66 -8
- package/scripts/bundle-ecc.ts +111 -0
- package/src/address.ts +81 -44
- package/src/bech32utils.ts +3 -3
- package/src/bip66.ts +34 -24
- package/src/block.ts +196 -84
- package/src/branded.ts +18 -0
- package/src/crypto.ts +64 -26
- package/src/ecc/context.ts +277 -0
- package/src/ecc/index.ts +14 -0
- package/src/ecc/types.ts +154 -0
- package/src/ecpair.d.ts +99 -0
- package/src/errors.ts +163 -0
- package/src/index.ts +113 -9
- package/src/io/BinaryReader.ts +461 -0
- package/src/io/BinaryWriter.ts +696 -0
- package/src/io/MemoryPool.ts +343 -0
- package/src/io/base64.ts +20 -0
- package/src/io/hex.ts +155 -0
- package/src/io/index.ts +41 -0
- package/src/io/utils.ts +283 -0
- package/src/merkle.ts +14 -9
- package/src/networks.ts +9 -9
- package/src/payments/bip341.ts +34 -33
- package/src/payments/embed.ts +244 -41
- package/src/payments/index.ts +12 -10
- package/src/payments/p2ms.ts +490 -118
- package/src/payments/p2op.ts +431 -133
- package/src/payments/p2pk.ts +370 -72
- package/src/payments/p2pkh.ts +524 -130
- package/src/payments/p2sh.ts +572 -172
- package/src/payments/p2tr.ts +686 -194
- package/src/payments/p2wpkh.ts +484 -107
- package/src/payments/p2wsh.ts +526 -164
- package/src/payments/types.ts +80 -66
- package/src/psbt/bip371.ts +68 -51
- package/src/psbt/psbtutils.ts +39 -40
- package/src/psbt/types.ts +331 -0
- package/src/psbt/utils.ts +188 -0
- package/src/psbt/validation.ts +192 -0
- package/src/psbt.ts +566 -809
- package/src/pubkey.ts +22 -23
- package/src/push_data.ts +18 -16
- package/src/script.ts +82 -64
- package/src/script_number.ts +6 -6
- package/src/script_signature.ts +33 -36
- package/src/transaction.ts +458 -238
- package/src/types.ts +231 -100
- package/src/workers/WorkerSigningPool.node.ts +887 -0
- package/src/workers/WorkerSigningPool.ts +670 -0
- package/src/workers/ecc-bundle.ts +26 -0
- package/src/workers/index.ts +165 -0
- package/src/workers/psbt-parallel.ts +332 -0
- package/src/workers/signing-worker.ts +353 -0
- package/src/workers/types.ts +413 -0
- package/test/address.spec.ts +9 -6
- package/test/bitcoin.core.spec.ts +16 -17
- package/test/block.spec.ts +8 -7
- package/test/bufferutils.spec.ts +228 -214
- package/test/crypto.spec.ts +19 -11
- package/test/fixtures/p2pk.json +0 -8
- package/test/fixtures/p2pkh.json +1 -1
- package/test/fixtures/p2sh.json +1 -1
- package/test/fixtures/script.json +1 -1
- package/test/fixtures/transaction.json +2 -2
- package/test/integration/_regtest.ts +25 -0
- package/test/integration/addresses.spec.ts +4 -3
- package/test/integration/bip32.spec.ts +2 -1
- package/test/integration/blocks.spec.ts +1 -1
- package/test/integration/cltv.spec.ts +18 -16
- package/test/integration/csv.spec.ts +37 -64
- package/test/integration/payments.spec.ts +5 -3
- package/test/integration/taproot.spec.ts +76 -83
- package/test/integration/transactions.spec.ts +38 -35
- package/test/payments.spec.ts +35 -13
- package/test/payments.utils.ts +17 -16
- package/test/psbt.spec.ts +111 -100
- package/test/script.spec.ts +11 -10
- package/test/script_signature.spec.ts +9 -11
- package/test/taproot-cache.spec.ts +694 -0
- package/test/transaction.spec.ts +32 -40
- package/test/types.spec.ts +74 -29
- package/test/workers-pool.spec.ts +963 -0
- package/test/workers-signing.spec.ts +635 -0
- package/test/workers.spec.ts +1390 -0
- package/tsconfig.base.json +34 -18
- package/tsconfig.browser.json +15 -0
- package/tsconfig.build.json +5 -0
- package/tsconfig.json +5 -14
- package/vite.config.browser.ts +3 -42
- package/vitest.config.integration.ts +2 -0
- package/browser/bufferutils.d.ts +0 -34
- package/browser/chunks/crypto-BhCpKpek.js +0 -2033
- package/browser/chunks/payments-B1wlSccx.js +0 -1089
- package/browser/chunks/psbt-BCNk7JUx.js +0 -4055
- package/browser/chunks/script-DyPItFEl.js +0 -318
- package/browser/chunks/transaction-C_UbhMGn.js +0 -432
- package/browser/chunks/utils-DNZi-T5W.js +0 -761
- package/browser/ecc_lib.d.ts +0 -3
- package/browser/hooks/AdvancedSignatureManager.d.ts +0 -16
- package/browser/hooks/HookedSigner.d.ts +0 -4
- package/browser/hooks/SignatureManager.d.ts +0 -13
- package/browser/payments/lazy.d.ts +0 -2
- package/browser/typeforce.d.ts +0 -38
- package/build/bufferutils.d.ts +0 -34
- package/build/bufferutils.js +0 -141
- package/build/ecc_lib.d.ts +0 -3
- package/build/ecc_lib.js +0 -61
- package/build/hooks/AdvancedSignatureManager.d.ts +0 -16
- package/build/hooks/AdvancedSignatureManager.js +0 -52
- package/build/hooks/HookedSigner.d.ts +0 -4
- package/build/hooks/HookedSigner.js +0 -64
- package/build/hooks/SignatureManager.d.ts +0 -13
- package/build/hooks/SignatureManager.js +0 -45
- package/build/payments/lazy.d.ts +0 -2
- package/build/payments/lazy.js +0 -28
- package/build/tsconfig.tsbuildinfo +0 -1
- package/src/bufferutils.ts +0 -188
- package/src/ecc_lib.ts +0 -94
- package/src/hooks/AdvancedSignatureManager.ts +0 -104
- package/src/hooks/HookedSigner.ts +0 -108
- package/src/hooks/SignatureManager.ts +0 -84
- package/src/payments/lazy.ts +0 -28
- package/src/typeforce.d.ts +0 -38
- package/tsconfig.webpack.json +0 -18
package/build/payments/p2tr.js
CHANGED
|
@@ -1,77 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pay-to-Taproot (P2TR) payment class.
|
|
3
|
+
*
|
|
4
|
+
* P2TR is the Taproot output type (BIP341). It supports both key-path spending
|
|
5
|
+
* (single signature) and script-path spending (merkle tree of scripts).
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
1
9
|
import { bech32m } from 'bech32';
|
|
2
|
-
import { Buffer as NBuffer } from 'buffer';
|
|
3
10
|
import { fromBech32 } from '../bech32utils.js';
|
|
4
|
-
import { getEccLib } from '../
|
|
11
|
+
import { getEccLib } from '../ecc/context.js';
|
|
5
12
|
import { bitcoin as BITCOIN_NETWORK } from '../networks.js';
|
|
6
13
|
import * as bscript from '../script.js';
|
|
7
|
-
import {
|
|
14
|
+
import { stacksEqual, TAPLEAF_VERSION_MASK, } from '../types.js';
|
|
8
15
|
import { findScriptPath, LEAF_VERSION_TAPSCRIPT, rootHashFromPath, tapleafHash, toHashTree, tweakKey, } from './bip341.js';
|
|
16
|
+
import { concat, equals } from '../io/index.js';
|
|
9
17
|
import { PaymentType } from './types.js';
|
|
10
|
-
import * as lazy from './lazy.js';
|
|
11
18
|
const OPS = bscript.opcodes;
|
|
12
19
|
const TAPROOT_WITNESS_VERSION = 0x01;
|
|
13
20
|
const ANNEX_PREFIX = 0x50;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Pay-to-Taproot (P2TR) payment class.
|
|
23
|
+
*
|
|
24
|
+
* Creates locking scripts of the form: `OP_1 {x-only pubkey}`
|
|
25
|
+
*
|
|
26
|
+
* Key-path spending witness: `[signature]`
|
|
27
|
+
* Script-path spending witness: `[script inputs..., script, control block]`
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { P2TR } from '@btc-vision/bitcoin';
|
|
32
|
+
*
|
|
33
|
+
* // Key-path only (no scripts)
|
|
34
|
+
* const keyOnly = P2TR.fromInternalPubkey(internalPubkey);
|
|
35
|
+
* console.log(keyOnly.address); // bc1p... address
|
|
36
|
+
*
|
|
37
|
+
* // With script tree
|
|
38
|
+
* const withScripts = P2TR.fromInternalPubkey(internalPubkey, scriptTree);
|
|
39
|
+
*
|
|
40
|
+
* // Decode an existing output
|
|
41
|
+
* const decoded = P2TR.fromOutput(scriptPubKey);
|
|
42
|
+
* console.log(decoded.pubkey); // 32-byte x-only pubkey
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export class P2TR {
|
|
46
|
+
// Static public fields
|
|
47
|
+
static NAME = PaymentType.P2TR;
|
|
48
|
+
// Private instance fields
|
|
49
|
+
#network;
|
|
50
|
+
#opts;
|
|
51
|
+
// Input data (provided by user)
|
|
52
|
+
#inputAddress;
|
|
53
|
+
#inputPubkey;
|
|
54
|
+
#inputInternalPubkey;
|
|
55
|
+
#inputHash;
|
|
56
|
+
#inputScriptTree;
|
|
57
|
+
#inputSignature;
|
|
58
|
+
#inputOutput;
|
|
59
|
+
#inputWitness;
|
|
60
|
+
#inputRedeem;
|
|
61
|
+
#inputRedeemVersion;
|
|
62
|
+
// Cached computed values
|
|
63
|
+
#address;
|
|
64
|
+
#pubkey;
|
|
65
|
+
#internalPubkey;
|
|
66
|
+
#hash;
|
|
67
|
+
#signature;
|
|
68
|
+
#output;
|
|
69
|
+
#redeem;
|
|
70
|
+
#redeemVersion;
|
|
71
|
+
#witness;
|
|
72
|
+
// Cache flags
|
|
73
|
+
#addressComputed = false;
|
|
74
|
+
#pubkeyComputed = false;
|
|
75
|
+
#internalPubkeyComputed = false;
|
|
76
|
+
#hashComputed = false;
|
|
77
|
+
#signatureComputed = false;
|
|
78
|
+
#outputComputed = false;
|
|
79
|
+
#redeemComputed = false;
|
|
80
|
+
#redeemVersionComputed = false;
|
|
81
|
+
#witnessComputed = false;
|
|
82
|
+
// Decoded address cache
|
|
83
|
+
#decodedAddress;
|
|
84
|
+
#decodedAddressComputed = false;
|
|
85
|
+
// Witness without annex
|
|
86
|
+
#witnessWithoutAnnex;
|
|
87
|
+
#witnessWithoutAnnexComputed = false;
|
|
88
|
+
// Hash tree cache
|
|
89
|
+
#hashTree;
|
|
90
|
+
#hashTreeComputed = false;
|
|
91
|
+
/**
|
|
92
|
+
* Creates a new P2TR payment instance.
|
|
93
|
+
*
|
|
94
|
+
* @param params - Payment parameters
|
|
95
|
+
* @param params.address - Bech32m encoded address (bc1p...)
|
|
96
|
+
* @param params.pubkey - x-only output pubkey (32 bytes)
|
|
97
|
+
* @param params.internalPubkey - x-only internal pubkey (32 bytes)
|
|
98
|
+
* @param params.hash - Merkle root (32 bytes, or empty for key-path only)
|
|
99
|
+
* @param params.scriptTree - Full script tree definition
|
|
100
|
+
* @param params.signature - Schnorr signature (for key-path spending)
|
|
101
|
+
* @param params.output - The scriptPubKey
|
|
102
|
+
* @param params.witness - The witness stack
|
|
103
|
+
* @param params.redeem - Redeem script for script-path spending
|
|
104
|
+
* @param params.redeemVersion - Leaf version (defaults to LEAF_VERSION_TAPSCRIPT)
|
|
105
|
+
* @param params.network - Network parameters (defaults to mainnet)
|
|
106
|
+
* @param opts - Payment options
|
|
107
|
+
* @param opts.validate - Whether to validate inputs (default: true)
|
|
108
|
+
*
|
|
109
|
+
* @throws {TypeError} If validation is enabled and data is invalid
|
|
110
|
+
*/
|
|
111
|
+
constructor(params, opts) {
|
|
112
|
+
this.#network = params.network ?? BITCOIN_NETWORK;
|
|
113
|
+
this.#opts = {
|
|
114
|
+
validate: opts?.validate ?? true,
|
|
115
|
+
allowIncomplete: opts?.allowIncomplete ?? false,
|
|
116
|
+
};
|
|
117
|
+
// Store input data
|
|
118
|
+
this.#inputAddress = params.address;
|
|
119
|
+
this.#inputPubkey = params.pubkey;
|
|
120
|
+
this.#inputInternalPubkey = params.internalPubkey;
|
|
121
|
+
this.#inputHash = params.hash;
|
|
122
|
+
this.#inputScriptTree = params.scriptTree;
|
|
123
|
+
this.#inputSignature = params.signature;
|
|
124
|
+
this.#inputOutput = params.output;
|
|
125
|
+
this.#inputWitness = params.witness;
|
|
126
|
+
this.#inputRedeem = params.redeem;
|
|
127
|
+
this.#inputRedeemVersion = params.redeemVersion;
|
|
128
|
+
// Validate if requested
|
|
129
|
+
if (this.#opts.validate) {
|
|
130
|
+
this.#validate();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Public getters
|
|
134
|
+
/**
|
|
135
|
+
* Payment type discriminant.
|
|
136
|
+
*/
|
|
137
|
+
get name() {
|
|
138
|
+
return PaymentType.P2TR;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Network parameters.
|
|
142
|
+
*/
|
|
143
|
+
get network() {
|
|
144
|
+
return this.#network;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Bech32m encoded address (bc1p... for mainnet).
|
|
148
|
+
*/
|
|
149
|
+
get address() {
|
|
150
|
+
if (!this.#addressComputed) {
|
|
151
|
+
this.#address = this.#computeAddress();
|
|
152
|
+
this.#addressComputed = true;
|
|
153
|
+
}
|
|
154
|
+
return this.#address;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* x-only output pubkey (32 bytes).
|
|
158
|
+
* This is the tweaked pubkey that appears in the output.
|
|
159
|
+
*/
|
|
160
|
+
get pubkey() {
|
|
161
|
+
if (!this.#pubkeyComputed) {
|
|
162
|
+
this.#pubkey = this.#computePubkey();
|
|
163
|
+
this.#pubkeyComputed = true;
|
|
164
|
+
}
|
|
165
|
+
return this.#pubkey;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* x-only internal pubkey (32 bytes).
|
|
169
|
+
* This is the untweaked pubkey before adding the merkle root tweak.
|
|
170
|
+
*/
|
|
171
|
+
get internalPubkey() {
|
|
172
|
+
if (!this.#internalPubkeyComputed) {
|
|
173
|
+
this.#internalPubkey = this.#computeInternalPubkey();
|
|
174
|
+
this.#internalPubkeyComputed = true;
|
|
175
|
+
}
|
|
176
|
+
return this.#internalPubkey;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Merkle root hash (32 bytes).
|
|
180
|
+
* Present when a script tree is defined.
|
|
181
|
+
*/
|
|
182
|
+
get hash() {
|
|
183
|
+
if (!this.#hashComputed) {
|
|
184
|
+
this.#hash = this.#computeHash();
|
|
185
|
+
this.#hashComputed = true;
|
|
186
|
+
}
|
|
187
|
+
return this.#hash;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Schnorr signature (for key-path spending).
|
|
191
|
+
*/
|
|
192
|
+
get signature() {
|
|
193
|
+
if (!this.#signatureComputed) {
|
|
194
|
+
this.#signature = this.#computeSignature();
|
|
195
|
+
this.#signatureComputed = true;
|
|
196
|
+
}
|
|
197
|
+
return this.#signature;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* The scriptPubKey: `OP_1 {32-byte x-only pubkey}`
|
|
201
|
+
*/
|
|
202
|
+
get output() {
|
|
203
|
+
if (!this.#outputComputed) {
|
|
204
|
+
this.#output = this.#computeOutput();
|
|
205
|
+
this.#outputComputed = true;
|
|
206
|
+
}
|
|
207
|
+
return this.#output;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Redeem script information (for script-path spending).
|
|
211
|
+
*/
|
|
212
|
+
get redeem() {
|
|
213
|
+
if (!this.#redeemComputed) {
|
|
214
|
+
this.#redeem = this.#computeRedeem();
|
|
215
|
+
this.#redeemComputed = true;
|
|
216
|
+
}
|
|
217
|
+
return this.#redeem;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Leaf version (defaults to LEAF_VERSION_TAPSCRIPT = 0xc0).
|
|
221
|
+
*/
|
|
222
|
+
get redeemVersion() {
|
|
223
|
+
if (!this.#redeemVersionComputed) {
|
|
224
|
+
this.#redeemVersion = this.#computeRedeemVersion();
|
|
225
|
+
this.#redeemVersionComputed = true;
|
|
226
|
+
}
|
|
227
|
+
return this.#redeemVersion ?? LEAF_VERSION_TAPSCRIPT;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Witness stack.
|
|
231
|
+
* Key-path: `[signature]`
|
|
232
|
+
* Script-path: `[script inputs..., script, control block]`
|
|
233
|
+
*/
|
|
234
|
+
get witness() {
|
|
235
|
+
if (!this.#witnessComputed) {
|
|
236
|
+
this.#witness = this.#computeWitness();
|
|
237
|
+
this.#witnessComputed = true;
|
|
238
|
+
}
|
|
239
|
+
return this.#witness;
|
|
240
|
+
}
|
|
241
|
+
// Static factory methods
|
|
242
|
+
/**
|
|
243
|
+
* Creates a P2TR payment from an internal pubkey (key-path only).
|
|
244
|
+
*
|
|
245
|
+
* @param internalPubkey - x-only internal pubkey (32 bytes)
|
|
246
|
+
* @param scriptTree - Optional script tree
|
|
247
|
+
* @param network - Network parameters (defaults to mainnet)
|
|
248
|
+
* @returns A new P2TR payment instance
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```typescript
|
|
252
|
+
* // Key-path only
|
|
253
|
+
* const p2tr = P2TR.fromInternalPubkey(internalPubkey);
|
|
254
|
+
*
|
|
255
|
+
* // With script tree
|
|
256
|
+
* const withScripts = P2TR.fromInternalPubkey(internalPubkey, scriptTree);
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
static fromInternalPubkey(internalPubkey, scriptTree, network) {
|
|
260
|
+
return new P2TR({ internalPubkey, scriptTree, network });
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Creates a P2TR payment from a bech32m address.
|
|
264
|
+
*
|
|
265
|
+
* @param address - Bech32m encoded address (bc1p...)
|
|
266
|
+
* @param network - Network parameters (defaults to mainnet)
|
|
267
|
+
* @returns A new P2TR payment instance
|
|
268
|
+
*/
|
|
269
|
+
static fromAddress(address, network) {
|
|
270
|
+
return new P2TR({ address, network });
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Creates a P2TR payment from a scriptPubKey.
|
|
274
|
+
*
|
|
275
|
+
* @param output - The scriptPubKey
|
|
276
|
+
* @param network - Network parameters (defaults to mainnet)
|
|
277
|
+
* @returns A new P2TR payment instance
|
|
278
|
+
*/
|
|
279
|
+
static fromOutput(output, network) {
|
|
280
|
+
return new P2TR({ output, network });
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Creates a P2TR payment from a signature (for key-path spending).
|
|
284
|
+
*
|
|
285
|
+
* @param signature - Schnorr signature
|
|
286
|
+
* @param internalPubkey - x-only internal pubkey
|
|
287
|
+
* @param network - Network parameters (defaults to mainnet)
|
|
288
|
+
* @returns A new P2TR payment instance
|
|
289
|
+
*/
|
|
290
|
+
static fromSignature(signature, internalPubkey, network) {
|
|
291
|
+
return new P2TR({ signature, internalPubkey, network });
|
|
292
|
+
}
|
|
293
|
+
// Private helper methods
|
|
294
|
+
#getDecodedAddress() {
|
|
295
|
+
if (!this.#decodedAddressComputed) {
|
|
296
|
+
if (this.#inputAddress) {
|
|
297
|
+
const decoded = fromBech32(this.#inputAddress);
|
|
298
|
+
if (decoded) {
|
|
299
|
+
this.#decodedAddress = {
|
|
300
|
+
version: decoded.version,
|
|
301
|
+
prefix: decoded.prefix,
|
|
302
|
+
data: decoded.data,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
this.#decodedAddressComputed = true;
|
|
307
|
+
}
|
|
308
|
+
return this.#decodedAddress;
|
|
309
|
+
}
|
|
310
|
+
#getWitnessWithoutAnnex() {
|
|
311
|
+
if (!this.#witnessWithoutAnnexComputed) {
|
|
312
|
+
if (this.#inputWitness && this.#inputWitness.length > 0) {
|
|
313
|
+
// Remove annex if present
|
|
314
|
+
if (this.#inputWitness.length >= 2 &&
|
|
315
|
+
this.#inputWitness[this.#inputWitness.length - 1][0] === ANNEX_PREFIX) {
|
|
316
|
+
this.#witnessWithoutAnnex = this.#inputWitness.slice(0, -1);
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
this.#witnessWithoutAnnex = this.#inputWitness.slice();
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
this.#witnessWithoutAnnexComputed = true;
|
|
323
|
+
}
|
|
324
|
+
return this.#witnessWithoutAnnex;
|
|
325
|
+
}
|
|
326
|
+
#getHashTree() {
|
|
327
|
+
if (!this.#hashTreeComputed) {
|
|
328
|
+
if (this.#inputScriptTree) {
|
|
329
|
+
this.#hashTree = toHashTree(this.#inputScriptTree);
|
|
330
|
+
}
|
|
331
|
+
else if (this.#inputHash) {
|
|
332
|
+
this.#hashTree = { hash: this.#inputHash };
|
|
333
|
+
}
|
|
334
|
+
this.#hashTreeComputed = true;
|
|
335
|
+
}
|
|
336
|
+
return this.#hashTree;
|
|
337
|
+
}
|
|
338
|
+
// Private computation methods
|
|
339
|
+
#computeAddress() {
|
|
340
|
+
if (this.#inputAddress) {
|
|
341
|
+
return this.#inputAddress;
|
|
342
|
+
}
|
|
343
|
+
const pk = this.pubkey;
|
|
344
|
+
if (!pk)
|
|
345
|
+
return undefined;
|
|
346
|
+
const words = bech32m.toWords(pk);
|
|
67
347
|
words.unshift(TAPROOT_WITNESS_VERSION);
|
|
68
|
-
return bech32m.encode(network.bech32, words);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
348
|
+
return bech32m.encode(this.#network.bech32, words);
|
|
349
|
+
}
|
|
350
|
+
#computePubkey() {
|
|
351
|
+
if (this.#inputPubkey) {
|
|
352
|
+
return this.#inputPubkey;
|
|
353
|
+
}
|
|
354
|
+
if (this.#inputOutput) {
|
|
355
|
+
return this.#inputOutput.subarray(2);
|
|
356
|
+
}
|
|
357
|
+
if (this.#inputAddress) {
|
|
358
|
+
return this.#getDecodedAddress()?.data;
|
|
359
|
+
}
|
|
360
|
+
const internalPk = this.internalPubkey;
|
|
361
|
+
if (internalPk) {
|
|
362
|
+
const tweakedKey = tweakKey(internalPk, this.hash);
|
|
363
|
+
if (tweakedKey) {
|
|
364
|
+
return tweakedKey.x;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return undefined;
|
|
368
|
+
}
|
|
369
|
+
#computeInternalPubkey() {
|
|
370
|
+
if (this.#inputInternalPubkey) {
|
|
371
|
+
return this.#inputInternalPubkey;
|
|
372
|
+
}
|
|
373
|
+
const witness = this.#getWitnessWithoutAnnex();
|
|
374
|
+
if (witness && witness.length > 1) {
|
|
375
|
+
return witness[witness.length - 1].subarray(1, 33);
|
|
376
|
+
}
|
|
377
|
+
return undefined;
|
|
378
|
+
}
|
|
379
|
+
#computeHash() {
|
|
380
|
+
const hashTree = this.#getHashTree();
|
|
381
|
+
if (hashTree) {
|
|
73
382
|
return hashTree.hash;
|
|
74
|
-
|
|
383
|
+
}
|
|
384
|
+
const w = this.#getWitnessWithoutAnnex();
|
|
75
385
|
if (w && w.length > 1) {
|
|
76
386
|
const controlBlock = w[w.length - 1];
|
|
77
387
|
const leafVersion = controlBlock[0] & TAPLEAF_VERSION_MASK;
|
|
@@ -83,176 +393,284 @@ export function p2tr(a, opts) {
|
|
|
83
393
|
return rootHashFromPath(controlBlock, leafHash);
|
|
84
394
|
}
|
|
85
395
|
return undefined;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
return;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
396
|
+
}
|
|
397
|
+
#computeSignature() {
|
|
398
|
+
if (this.#inputSignature) {
|
|
399
|
+
return this.#inputSignature;
|
|
400
|
+
}
|
|
401
|
+
const witness = this.#getWitnessWithoutAnnex();
|
|
402
|
+
if (witness && witness.length === 1) {
|
|
403
|
+
return witness[0];
|
|
404
|
+
}
|
|
405
|
+
return undefined;
|
|
406
|
+
}
|
|
407
|
+
#computeOutput() {
|
|
408
|
+
if (this.#inputOutput) {
|
|
409
|
+
return this.#inputOutput;
|
|
410
|
+
}
|
|
411
|
+
const pk = this.pubkey;
|
|
412
|
+
if (!pk)
|
|
413
|
+
return undefined;
|
|
414
|
+
return bscript.compile([OPS.OP_1, pk]);
|
|
415
|
+
}
|
|
416
|
+
#computeRedeem() {
|
|
417
|
+
if (this.#inputRedeem) {
|
|
418
|
+
return this.#inputRedeem;
|
|
419
|
+
}
|
|
420
|
+
const witness = this.#getWitnessWithoutAnnex();
|
|
421
|
+
if (!witness || witness.length < 2) {
|
|
422
|
+
return undefined;
|
|
97
423
|
}
|
|
98
|
-
return LEAF_VERSION_TAPSCRIPT;
|
|
99
|
-
});
|
|
100
|
-
lazy.prop(o, 'redeem', () => {
|
|
101
|
-
const witness = _witness();
|
|
102
|
-
if (!witness || witness.length < 2)
|
|
103
|
-
return;
|
|
104
424
|
return {
|
|
105
425
|
output: witness[witness.length - 2],
|
|
106
426
|
witness: witness.slice(0, -2),
|
|
107
427
|
redeemVersion: witness[witness.length - 1][0] & TAPLEAF_VERSION_MASK,
|
|
108
428
|
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
return
|
|
113
|
-
if (a.output)
|
|
114
|
-
return a.output.subarray(2);
|
|
115
|
-
if (a.address)
|
|
116
|
-
return _address().data;
|
|
117
|
-
if (o.internalPubkey) {
|
|
118
|
-
const tweakedKey = tweakKey(o.internalPubkey, o.hash);
|
|
119
|
-
if (tweakedKey)
|
|
120
|
-
return tweakedKey.x;
|
|
429
|
+
}
|
|
430
|
+
#computeRedeemVersion() {
|
|
431
|
+
if (this.#inputRedeemVersion !== undefined) {
|
|
432
|
+
return this.#inputRedeemVersion;
|
|
121
433
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
if (
|
|
135
|
-
return;
|
|
136
|
-
return witness[0];
|
|
137
|
-
});
|
|
138
|
-
lazy.prop(o, 'witness', () => {
|
|
139
|
-
if (a.witness)
|
|
140
|
-
return a.witness;
|
|
141
|
-
const hashTree = _hashTree();
|
|
142
|
-
if (hashTree && a.redeem && a.redeem.output && a.internalPubkey) {
|
|
434
|
+
if (this.#inputRedeem &&
|
|
435
|
+
this.#inputRedeem.redeemVersion !== undefined &&
|
|
436
|
+
this.#inputRedeem.redeemVersion !== null) {
|
|
437
|
+
return this.#inputRedeem.redeemVersion;
|
|
438
|
+
}
|
|
439
|
+
return LEAF_VERSION_TAPSCRIPT;
|
|
440
|
+
}
|
|
441
|
+
#computeWitness() {
|
|
442
|
+
if (this.#inputWitness) {
|
|
443
|
+
return this.#inputWitness;
|
|
444
|
+
}
|
|
445
|
+
const hashTree = this.#getHashTree();
|
|
446
|
+
if (hashTree && this.#inputRedeem?.output && this.#inputInternalPubkey) {
|
|
143
447
|
const leafHash = tapleafHash({
|
|
144
|
-
output:
|
|
145
|
-
version:
|
|
448
|
+
output: this.#inputRedeem.output,
|
|
449
|
+
version: this.redeemVersion,
|
|
146
450
|
});
|
|
147
451
|
const path = findScriptPath(hashTree, leafHash);
|
|
148
452
|
if (!path)
|
|
149
|
-
return;
|
|
150
|
-
const outputKey = tweakKey(
|
|
453
|
+
return undefined;
|
|
454
|
+
const outputKey = tweakKey(this.#inputInternalPubkey, hashTree.hash);
|
|
151
455
|
if (!outputKey)
|
|
152
|
-
return;
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
if (
|
|
162
|
-
|
|
456
|
+
return undefined;
|
|
457
|
+
const version = this.redeemVersion ?? 0xc0;
|
|
458
|
+
const controlBlock = concat([
|
|
459
|
+
new Uint8Array([version | outputKey.parity]),
|
|
460
|
+
this.#inputInternalPubkey,
|
|
461
|
+
...path,
|
|
462
|
+
]);
|
|
463
|
+
return [this.#inputRedeem.output, controlBlock];
|
|
464
|
+
}
|
|
465
|
+
if (this.#inputSignature) {
|
|
466
|
+
return [this.#inputSignature];
|
|
467
|
+
}
|
|
468
|
+
return undefined;
|
|
469
|
+
}
|
|
470
|
+
// Validation
|
|
471
|
+
#validate() {
|
|
472
|
+
let pubkey = new Uint8Array(0);
|
|
473
|
+
if (this.#inputAddress) {
|
|
474
|
+
const addr = this.#getDecodedAddress();
|
|
475
|
+
if (!addr) {
|
|
476
|
+
throw new TypeError('Invalid address');
|
|
477
|
+
}
|
|
478
|
+
if (this.#network && this.#network.bech32 !== addr.prefix) {
|
|
163
479
|
throw new TypeError('Invalid prefix or Network mismatch');
|
|
164
|
-
|
|
480
|
+
}
|
|
481
|
+
if (addr.version !== TAPROOT_WITNESS_VERSION) {
|
|
165
482
|
throw new TypeError('Invalid address version');
|
|
166
|
-
|
|
483
|
+
}
|
|
484
|
+
if (addr.data.length !== 32) {
|
|
167
485
|
throw new TypeError('Invalid address data');
|
|
168
|
-
|
|
486
|
+
}
|
|
487
|
+
pubkey = addr.data;
|
|
169
488
|
}
|
|
170
|
-
if (
|
|
171
|
-
if (pubkey.length > 0 && !
|
|
489
|
+
if (this.#inputPubkey) {
|
|
490
|
+
if (pubkey.length > 0 && !equals(pubkey, this.#inputPubkey)) {
|
|
172
491
|
throw new TypeError('Pubkey mismatch');
|
|
173
|
-
|
|
174
|
-
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
pubkey = this.#inputPubkey;
|
|
495
|
+
}
|
|
175
496
|
}
|
|
176
|
-
if (
|
|
177
|
-
if (
|
|
497
|
+
if (this.#inputOutput) {
|
|
498
|
+
if (this.#inputOutput.length !== 34 ||
|
|
499
|
+
this.#inputOutput[0] !== OPS.OP_1 ||
|
|
500
|
+
this.#inputOutput[1] !== 0x20) {
|
|
178
501
|
throw new TypeError('Output is invalid');
|
|
179
|
-
|
|
502
|
+
}
|
|
503
|
+
if (pubkey.length > 0 && !equals(pubkey, this.#inputOutput.subarray(2))) {
|
|
180
504
|
throw new TypeError('Pubkey mismatch');
|
|
181
|
-
|
|
182
|
-
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
pubkey = this.#inputOutput.subarray(2);
|
|
508
|
+
}
|
|
183
509
|
}
|
|
184
|
-
if (
|
|
185
|
-
const tweakedKey = tweakKey(
|
|
186
|
-
if (
|
|
510
|
+
if (this.#inputInternalPubkey) {
|
|
511
|
+
const tweakedKey = tweakKey(this.#inputInternalPubkey, this.hash);
|
|
512
|
+
if (!tweakedKey) {
|
|
513
|
+
throw new TypeError('Invalid internal pubkey');
|
|
514
|
+
}
|
|
515
|
+
if (pubkey.length > 0 && !equals(pubkey, tweakedKey.x)) {
|
|
187
516
|
throw new TypeError('Pubkey mismatch');
|
|
188
|
-
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
189
519
|
pubkey = tweakedKey.x;
|
|
520
|
+
}
|
|
190
521
|
}
|
|
191
|
-
const hashTree =
|
|
192
|
-
if (
|
|
193
|
-
if (!
|
|
522
|
+
const hashTree = this.#getHashTree();
|
|
523
|
+
if (this.#inputHash && hashTree) {
|
|
524
|
+
if (!equals(this.#inputHash, hashTree.hash)) {
|
|
194
525
|
throw new TypeError('Hash mismatch');
|
|
526
|
+
}
|
|
195
527
|
}
|
|
196
|
-
if (
|
|
528
|
+
if (this.#inputRedeem?.output && hashTree) {
|
|
197
529
|
const leafHash = tapleafHash({
|
|
198
|
-
output:
|
|
199
|
-
version:
|
|
530
|
+
output: this.#inputRedeem.output,
|
|
531
|
+
version: this.redeemVersion,
|
|
200
532
|
});
|
|
201
|
-
if (!findScriptPath(hashTree, leafHash))
|
|
533
|
+
if (!findScriptPath(hashTree, leafHash)) {
|
|
202
534
|
throw new TypeError('Redeem script not in tree');
|
|
535
|
+
}
|
|
203
536
|
}
|
|
204
|
-
const witness =
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
537
|
+
const witness = this.#getWitnessWithoutAnnex();
|
|
538
|
+
// Compare provided redeem with computed from witness
|
|
539
|
+
if (this.#inputRedeem && this.redeem) {
|
|
540
|
+
if (this.#inputRedeem.redeemVersion) {
|
|
541
|
+
if (this.#inputRedeem.redeemVersion !== this.redeem.redeemVersion) {
|
|
208
542
|
throw new TypeError('Redeem.redeemVersion and witness mismatch');
|
|
543
|
+
}
|
|
209
544
|
}
|
|
210
|
-
if (
|
|
211
|
-
|
|
545
|
+
if (this.#inputRedeem.output) {
|
|
546
|
+
const decompiled = bscript.decompile(this.#inputRedeem.output);
|
|
547
|
+
if (!decompiled || decompiled.length === 0) {
|
|
212
548
|
throw new TypeError('Redeem.output is invalid');
|
|
213
|
-
|
|
549
|
+
}
|
|
550
|
+
if (this.redeem.output && !equals(this.#inputRedeem.output, this.redeem.output)) {
|
|
214
551
|
throw new TypeError('Redeem.output and witness mismatch');
|
|
552
|
+
}
|
|
215
553
|
}
|
|
216
|
-
if (
|
|
217
|
-
if (
|
|
554
|
+
if (this.#inputRedeem.witness) {
|
|
555
|
+
if (this.redeem.witness &&
|
|
556
|
+
!stacksEqual(this.#inputRedeem.witness, this.redeem.witness)) {
|
|
218
557
|
throw new TypeError('Redeem.witness and witness mismatch');
|
|
558
|
+
}
|
|
219
559
|
}
|
|
220
560
|
}
|
|
221
|
-
if (witness && witness.length) {
|
|
561
|
+
if (witness && witness.length > 0) {
|
|
222
562
|
if (witness.length === 1) {
|
|
223
|
-
|
|
563
|
+
// Key-path spending
|
|
564
|
+
if (this.#inputSignature && !equals(this.#inputSignature, witness[0])) {
|
|
224
565
|
throw new TypeError('Signature mismatch');
|
|
566
|
+
}
|
|
225
567
|
}
|
|
226
568
|
else {
|
|
569
|
+
// Script-path spending
|
|
227
570
|
const controlBlock = witness[witness.length - 1];
|
|
228
|
-
if (controlBlock.length < 33)
|
|
571
|
+
if (controlBlock.length < 33) {
|
|
229
572
|
throw new TypeError(`The control-block length is too small. Got ${controlBlock.length}, expected min 33.`);
|
|
230
|
-
|
|
573
|
+
}
|
|
574
|
+
if ((controlBlock.length - 33) % 32 !== 0) {
|
|
231
575
|
throw new TypeError(`The control-block length of ${controlBlock.length} is incorrect!`);
|
|
576
|
+
}
|
|
232
577
|
const m = (controlBlock.length - 33) / 32;
|
|
233
|
-
if (m > 128)
|
|
578
|
+
if (m > 128) {
|
|
234
579
|
throw new TypeError(`The script path is too long. Got ${m}, expected max 128.`);
|
|
235
|
-
|
|
236
|
-
|
|
580
|
+
}
|
|
581
|
+
const internalPk = controlBlock.subarray(1, 33);
|
|
582
|
+
if (this.#inputInternalPubkey && !equals(this.#inputInternalPubkey, internalPk)) {
|
|
237
583
|
throw new TypeError('Internal pubkey mismatch');
|
|
238
|
-
|
|
584
|
+
}
|
|
585
|
+
if (!getEccLib().isXOnlyPoint(internalPk)) {
|
|
239
586
|
throw new TypeError('Invalid internalPubkey for p2tr witness');
|
|
587
|
+
}
|
|
240
588
|
const leafVersion = controlBlock[0] & TAPLEAF_VERSION_MASK;
|
|
241
589
|
const script = witness[witness.length - 2];
|
|
242
590
|
const leafHash = tapleafHash({
|
|
243
591
|
output: script,
|
|
244
592
|
version: leafVersion,
|
|
245
593
|
});
|
|
246
|
-
const
|
|
247
|
-
const outputKey = tweakKey(
|
|
248
|
-
if (!outputKey)
|
|
594
|
+
const computedHash = rootHashFromPath(controlBlock, leafHash);
|
|
595
|
+
const outputKey = tweakKey(internalPk, computedHash);
|
|
596
|
+
if (!outputKey) {
|
|
249
597
|
throw new TypeError('Invalid outputKey for p2tr witness');
|
|
250
|
-
|
|
598
|
+
}
|
|
599
|
+
if (pubkey.length > 0 && !equals(pubkey, outputKey.x)) {
|
|
251
600
|
throw new TypeError('Pubkey mismatch for p2tr witness');
|
|
252
|
-
|
|
601
|
+
}
|
|
602
|
+
if (outputKey.parity !== (controlBlock[0] & 1)) {
|
|
253
603
|
throw new Error('Incorrect parity');
|
|
604
|
+
}
|
|
254
605
|
}
|
|
255
606
|
}
|
|
256
607
|
}
|
|
257
|
-
|
|
608
|
+
/**
|
|
609
|
+
* Converts to a plain P2TRPayment object for backwards compatibility.
|
|
610
|
+
*
|
|
611
|
+
* @returns A P2TRPayment object
|
|
612
|
+
*/
|
|
613
|
+
toPayment() {
|
|
614
|
+
return {
|
|
615
|
+
name: this.name,
|
|
616
|
+
network: this.network,
|
|
617
|
+
address: this.address,
|
|
618
|
+
pubkey: this.pubkey,
|
|
619
|
+
internalPubkey: this.internalPubkey,
|
|
620
|
+
hash: this.hash,
|
|
621
|
+
scriptTree: this.#inputScriptTree,
|
|
622
|
+
signature: this.signature,
|
|
623
|
+
output: this.output,
|
|
624
|
+
redeem: this.redeem,
|
|
625
|
+
redeemVersion: this.redeemVersion,
|
|
626
|
+
witness: this.witness,
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Creates a Pay-to-Taproot (P2TR) payment object.
|
|
632
|
+
*
|
|
633
|
+
* This is the legacy factory function for backwards compatibility.
|
|
634
|
+
* For new code, prefer using the P2TR class directly.
|
|
635
|
+
*
|
|
636
|
+
* @param a - The payment object containing the necessary data
|
|
637
|
+
* @param opts - Optional payment options
|
|
638
|
+
* @returns The P2TR payment object
|
|
639
|
+
* @throws {TypeError} If the required data is not provided or if the data is invalid
|
|
640
|
+
*
|
|
641
|
+
* @example
|
|
642
|
+
* ```typescript
|
|
643
|
+
* import { p2tr } from '@btc-vision/bitcoin';
|
|
644
|
+
*
|
|
645
|
+
* // Key-path only
|
|
646
|
+
* const payment = p2tr({ internalPubkey });
|
|
647
|
+
*
|
|
648
|
+
* // With script tree
|
|
649
|
+
* const withScripts = p2tr({ internalPubkey, scriptTree });
|
|
650
|
+
* ```
|
|
651
|
+
*/
|
|
652
|
+
export function p2tr(a, opts) {
|
|
653
|
+
if (!a.address &&
|
|
654
|
+
!a.output &&
|
|
655
|
+
!a.pubkey &&
|
|
656
|
+
!a.internalPubkey &&
|
|
657
|
+
!(a.witness && a.witness.length > 1)) {
|
|
658
|
+
throw new TypeError('Not enough data');
|
|
659
|
+
}
|
|
660
|
+
const instance = new P2TR({
|
|
661
|
+
address: a.address,
|
|
662
|
+
pubkey: a.pubkey,
|
|
663
|
+
internalPubkey: a.internalPubkey,
|
|
664
|
+
hash: a.hash,
|
|
665
|
+
scriptTree: a.scriptTree,
|
|
666
|
+
signature: a.signature,
|
|
667
|
+
output: a.output,
|
|
668
|
+
witness: a.witness,
|
|
669
|
+
redeem: a.redeem,
|
|
670
|
+
redeemVersion: a.redeemVersion,
|
|
671
|
+
network: a.network,
|
|
672
|
+
}, opts);
|
|
673
|
+
// Return a merged object for backwards compatibility
|
|
674
|
+
return Object.assign(instance.toPayment(), a);
|
|
258
675
|
}
|
|
676
|
+
//# sourceMappingURL=p2tr.js.map
|