@btc-vision/bitcoin 6.5.5 → 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/AUDIT/README.md +9 -0
- package/HOW_TO_WRITE_GOOD_CODE.md +2436 -0
- package/SECURITY.md +27 -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 +37 -13
- 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 +83 -25
- 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 +24 -25
- 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 +11 -0
- package/browser/bufferutils.d.ts +0 -34
- package/browser/chunks/crypto-BhCpKpek.js +0 -2033
- package/browser/chunks/payments-yjA0Evsv.js +0 -1089
- package/browser/chunks/psbt-URK2hBFc.js +0 -4039
- 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/src/payments/p2tr.ts
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
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
|
+
*/
|
|
9
|
+
|
|
1
10
|
import { bech32m } from 'bech32';
|
|
2
|
-
import { Buffer as NBuffer } from 'buffer';
|
|
3
11
|
import { fromBech32 } from '../bech32utils.js';
|
|
4
|
-
import { getEccLib } from '../
|
|
5
|
-
import { bitcoin as BITCOIN_NETWORK } from '../networks.js';
|
|
12
|
+
import { getEccLib } from '../ecc/context.js';
|
|
13
|
+
import { bitcoin as BITCOIN_NETWORK, type Network } from '../networks.js';
|
|
6
14
|
import * as bscript from '../script.js';
|
|
7
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
stacksEqual,
|
|
17
|
+
TAPLEAF_VERSION_MASK,
|
|
18
|
+
type Bytes32,
|
|
19
|
+
type Script,
|
|
20
|
+
type SchnorrSignature,
|
|
21
|
+
type Taptree,
|
|
22
|
+
type XOnlyPublicKey,
|
|
23
|
+
} from '../types.js';
|
|
8
24
|
import {
|
|
9
25
|
findScriptPath,
|
|
10
26
|
LEAF_VERSION_TAPSCRIPT,
|
|
@@ -12,298 +28,774 @@ import {
|
|
|
12
28
|
tapleafHash,
|
|
13
29
|
toHashTree,
|
|
14
30
|
tweakKey,
|
|
31
|
+
type HashTree,
|
|
15
32
|
} from './bip341.js';
|
|
16
|
-
import {
|
|
17
|
-
import
|
|
33
|
+
import { concat, equals } from '../io/index.js';
|
|
34
|
+
import { PaymentType, type P2TRPayment, type PaymentOpts, type ScriptRedeem } from './types.js';
|
|
18
35
|
|
|
19
36
|
const OPS = bscript.opcodes;
|
|
20
37
|
const TAPROOT_WITNESS_VERSION = 0x01;
|
|
21
38
|
const ANNEX_PREFIX = 0x50;
|
|
22
39
|
|
|
23
40
|
/**
|
|
24
|
-
*
|
|
41
|
+
* Pay-to-Taproot (P2TR) payment class.
|
|
42
|
+
*
|
|
43
|
+
* Creates locking scripts of the form: `OP_1 {x-only pubkey}`
|
|
44
|
+
*
|
|
45
|
+
* Key-path spending witness: `[signature]`
|
|
46
|
+
* Script-path spending witness: `[script inputs..., script, control block]`
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* import { P2TR } from '@btc-vision/bitcoin';
|
|
51
|
+
*
|
|
52
|
+
* // Key-path only (no scripts)
|
|
53
|
+
* const keyOnly = P2TR.fromInternalPubkey(internalPubkey);
|
|
54
|
+
* console.log(keyOnly.address); // bc1p... address
|
|
25
55
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
56
|
+
* // With script tree
|
|
57
|
+
* const withScripts = P2TR.fromInternalPubkey(internalPubkey, scriptTree);
|
|
58
|
+
*
|
|
59
|
+
* // Decode an existing output
|
|
60
|
+
* const decoded = P2TR.fromOutput(scriptPubKey);
|
|
61
|
+
* console.log(decoded.pubkey); // 32-byte x-only pubkey
|
|
62
|
+
* ```
|
|
30
63
|
*/
|
|
31
|
-
export
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
64
|
+
export class P2TR {
|
|
65
|
+
// Static public fields
|
|
66
|
+
static readonly NAME = PaymentType.P2TR;
|
|
67
|
+
|
|
68
|
+
// Private instance fields
|
|
69
|
+
readonly #network: Network;
|
|
70
|
+
readonly #opts: Required<PaymentOpts>;
|
|
71
|
+
|
|
72
|
+
// Input data (provided by user)
|
|
73
|
+
#inputAddress?: string | undefined;
|
|
74
|
+
#inputPubkey?: Uint8Array | undefined;
|
|
75
|
+
#inputInternalPubkey?: Uint8Array | undefined;
|
|
76
|
+
#inputHash?: Uint8Array | undefined;
|
|
77
|
+
#inputScriptTree?: Taptree | undefined;
|
|
78
|
+
#inputSignature?: Uint8Array | undefined;
|
|
79
|
+
#inputOutput?: Uint8Array | undefined;
|
|
80
|
+
#inputWitness?: Uint8Array[] | undefined;
|
|
81
|
+
#inputRedeem?: ScriptRedeem | undefined;
|
|
82
|
+
#inputRedeemVersion?: number | undefined;
|
|
83
|
+
|
|
84
|
+
// Cached computed values
|
|
85
|
+
#address?: string | undefined;
|
|
86
|
+
#pubkey?: XOnlyPublicKey | undefined;
|
|
87
|
+
#internalPubkey?: XOnlyPublicKey | undefined;
|
|
88
|
+
#hash?: Bytes32 | undefined;
|
|
89
|
+
#signature?: SchnorrSignature | undefined;
|
|
90
|
+
#output?: Script | undefined;
|
|
91
|
+
#redeem?: ScriptRedeem | undefined;
|
|
92
|
+
#redeemVersion?: number | undefined;
|
|
93
|
+
#witness?: Uint8Array[] | undefined;
|
|
94
|
+
|
|
95
|
+
// Cache flags
|
|
96
|
+
#addressComputed = false;
|
|
97
|
+
#pubkeyComputed = false;
|
|
98
|
+
#internalPubkeyComputed = false;
|
|
99
|
+
#hashComputed = false;
|
|
100
|
+
#signatureComputed = false;
|
|
101
|
+
#outputComputed = false;
|
|
102
|
+
#redeemComputed = false;
|
|
103
|
+
#redeemVersionComputed = false;
|
|
104
|
+
#witnessComputed = false;
|
|
105
|
+
|
|
106
|
+
// Decoded address cache
|
|
107
|
+
#decodedAddress?: { version: number; prefix: string; data: Uint8Array } | undefined;
|
|
108
|
+
#decodedAddressComputed = false;
|
|
109
|
+
|
|
110
|
+
// Witness without annex
|
|
111
|
+
#witnessWithoutAnnex?: Uint8Array[] | undefined;
|
|
112
|
+
#witnessWithoutAnnexComputed = false;
|
|
113
|
+
|
|
114
|
+
// Hash tree cache
|
|
115
|
+
#hashTree?: HashTree | undefined;
|
|
116
|
+
#hashTreeComputed = false;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Creates a new P2TR payment instance.
|
|
120
|
+
*
|
|
121
|
+
* @param params - Payment parameters
|
|
122
|
+
* @param params.address - Bech32m encoded address (bc1p...)
|
|
123
|
+
* @param params.pubkey - x-only output pubkey (32 bytes)
|
|
124
|
+
* @param params.internalPubkey - x-only internal pubkey (32 bytes)
|
|
125
|
+
* @param params.hash - Merkle root (32 bytes, or empty for key-path only)
|
|
126
|
+
* @param params.scriptTree - Full script tree definition
|
|
127
|
+
* @param params.signature - Schnorr signature (for key-path spending)
|
|
128
|
+
* @param params.output - The scriptPubKey
|
|
129
|
+
* @param params.witness - The witness stack
|
|
130
|
+
* @param params.redeem - Redeem script for script-path spending
|
|
131
|
+
* @param params.redeemVersion - Leaf version (defaults to LEAF_VERSION_TAPSCRIPT)
|
|
132
|
+
* @param params.network - Network parameters (defaults to mainnet)
|
|
133
|
+
* @param opts - Payment options
|
|
134
|
+
* @param opts.validate - Whether to validate inputs (default: true)
|
|
135
|
+
*
|
|
136
|
+
* @throws {TypeError} If validation is enabled and data is invalid
|
|
137
|
+
*/
|
|
138
|
+
constructor(
|
|
139
|
+
params: {
|
|
140
|
+
address?: string | undefined;
|
|
141
|
+
pubkey?: Uint8Array | undefined;
|
|
142
|
+
internalPubkey?: Uint8Array | undefined;
|
|
143
|
+
hash?: Uint8Array | undefined;
|
|
144
|
+
scriptTree?: Taptree | undefined;
|
|
145
|
+
signature?: Uint8Array | undefined;
|
|
146
|
+
output?: Uint8Array | undefined;
|
|
147
|
+
witness?: Uint8Array[] | undefined;
|
|
148
|
+
redeem?: ScriptRedeem | undefined;
|
|
149
|
+
redeemVersion?: number | undefined;
|
|
150
|
+
network?: Network | undefined;
|
|
151
|
+
},
|
|
152
|
+
opts?: PaymentOpts,
|
|
153
|
+
) {
|
|
154
|
+
this.#network = params.network ?? BITCOIN_NETWORK;
|
|
155
|
+
this.#opts = {
|
|
156
|
+
validate: opts?.validate ?? true,
|
|
157
|
+
allowIncomplete: opts?.allowIncomplete ?? false,
|
|
158
|
+
};
|
|
40
159
|
|
|
41
|
-
|
|
160
|
+
// Store input data
|
|
161
|
+
this.#inputAddress = params.address;
|
|
162
|
+
this.#inputPubkey = params.pubkey;
|
|
163
|
+
this.#inputInternalPubkey = params.internalPubkey;
|
|
164
|
+
this.#inputHash = params.hash;
|
|
165
|
+
this.#inputScriptTree = params.scriptTree;
|
|
166
|
+
this.#inputSignature = params.signature;
|
|
167
|
+
this.#inputOutput = params.output;
|
|
168
|
+
this.#inputWitness = params.witness;
|
|
169
|
+
this.#inputRedeem = params.redeem;
|
|
170
|
+
this.#inputRedeemVersion = params.redeemVersion;
|
|
171
|
+
|
|
172
|
+
// Validate if requested
|
|
173
|
+
if (this.#opts.validate) {
|
|
174
|
+
this.#validate();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
42
177
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
|
|
59
|
-
}),
|
|
60
|
-
redeemVersion: typef.maybe(typef.Number),
|
|
61
|
-
},
|
|
62
|
-
a,
|
|
63
|
-
);
|
|
178
|
+
// Public getters
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Payment type discriminant.
|
|
182
|
+
*/
|
|
183
|
+
get name(): typeof PaymentType.P2TR {
|
|
184
|
+
return PaymentType.P2TR;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Network parameters.
|
|
189
|
+
*/
|
|
190
|
+
get network(): Network {
|
|
191
|
+
return this.#network;
|
|
192
|
+
}
|
|
64
193
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Bech32m encoded address (bc1p... for mainnet).
|
|
196
|
+
*/
|
|
197
|
+
get address(): string | undefined {
|
|
198
|
+
if (!this.#addressComputed) {
|
|
199
|
+
this.#address = this.#computeAddress();
|
|
200
|
+
this.#addressComputed = true;
|
|
201
|
+
}
|
|
202
|
+
return this.#address;
|
|
203
|
+
}
|
|
68
204
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
205
|
+
/**
|
|
206
|
+
* x-only output pubkey (32 bytes).
|
|
207
|
+
* This is the tweaked pubkey that appears in the output.
|
|
208
|
+
*/
|
|
209
|
+
get pubkey(): XOnlyPublicKey | undefined {
|
|
210
|
+
if (!this.#pubkeyComputed) {
|
|
211
|
+
this.#pubkey = this.#computePubkey();
|
|
212
|
+
this.#pubkeyComputed = true;
|
|
74
213
|
}
|
|
75
|
-
return
|
|
76
|
-
}
|
|
214
|
+
return this.#pubkey;
|
|
215
|
+
}
|
|
77
216
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
217
|
+
/**
|
|
218
|
+
* x-only internal pubkey (32 bytes).
|
|
219
|
+
* This is the untweaked pubkey before adding the merkle root tweak.
|
|
220
|
+
*/
|
|
221
|
+
get internalPubkey(): XOnlyPublicKey | undefined {
|
|
222
|
+
if (!this.#internalPubkeyComputed) {
|
|
223
|
+
this.#internalPubkey = this.#computeInternalPubkey();
|
|
224
|
+
this.#internalPubkeyComputed = true;
|
|
225
|
+
}
|
|
226
|
+
return this.#internalPubkey;
|
|
227
|
+
}
|
|
83
228
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
229
|
+
/**
|
|
230
|
+
* Merkle root hash (32 bytes).
|
|
231
|
+
* Present when a script tree is defined.
|
|
232
|
+
*/
|
|
233
|
+
get hash(): Bytes32 | undefined {
|
|
234
|
+
if (!this.#hashComputed) {
|
|
235
|
+
this.#hash = this.#computeHash();
|
|
236
|
+
this.#hashComputed = true;
|
|
237
|
+
}
|
|
238
|
+
return this.#hash;
|
|
239
|
+
}
|
|
89
240
|
|
|
90
|
-
|
|
91
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Schnorr signature (for key-path spending).
|
|
243
|
+
*/
|
|
244
|
+
get signature(): SchnorrSignature | undefined {
|
|
245
|
+
if (!this.#signatureComputed) {
|
|
246
|
+
this.#signature = this.#computeSignature();
|
|
247
|
+
this.#signatureComputed = true;
|
|
248
|
+
}
|
|
249
|
+
return this.#signature;
|
|
250
|
+
}
|
|
92
251
|
|
|
93
|
-
|
|
252
|
+
/**
|
|
253
|
+
* The scriptPubKey: `OP_1 {32-byte x-only pubkey}`
|
|
254
|
+
*/
|
|
255
|
+
get output(): Script | undefined {
|
|
256
|
+
if (!this.#outputComputed) {
|
|
257
|
+
this.#output = this.#computeOutput();
|
|
258
|
+
this.#outputComputed = true;
|
|
259
|
+
}
|
|
260
|
+
return this.#output;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Redeem script information (for script-path spending).
|
|
265
|
+
*/
|
|
266
|
+
get redeem(): ScriptRedeem | undefined {
|
|
267
|
+
if (!this.#redeemComputed) {
|
|
268
|
+
this.#redeem = this.#computeRedeem();
|
|
269
|
+
this.#redeemComputed = true;
|
|
270
|
+
}
|
|
271
|
+
return this.#redeem;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Leaf version (defaults to LEAF_VERSION_TAPSCRIPT = 0xc0).
|
|
276
|
+
*/
|
|
277
|
+
get redeemVersion(): number {
|
|
278
|
+
if (!this.#redeemVersionComputed) {
|
|
279
|
+
this.#redeemVersion = this.#computeRedeemVersion();
|
|
280
|
+
this.#redeemVersionComputed = true;
|
|
281
|
+
}
|
|
282
|
+
return this.#redeemVersion ?? LEAF_VERSION_TAPSCRIPT;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Witness stack.
|
|
287
|
+
* Key-path: `[signature]`
|
|
288
|
+
* Script-path: `[script inputs..., script, control block]`
|
|
289
|
+
*/
|
|
290
|
+
get witness(): Uint8Array[] | undefined {
|
|
291
|
+
if (!this.#witnessComputed) {
|
|
292
|
+
this.#witness = this.#computeWitness();
|
|
293
|
+
this.#witnessComputed = true;
|
|
294
|
+
}
|
|
295
|
+
return this.#witness;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Static factory methods
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Creates a P2TR payment from an internal pubkey (key-path only).
|
|
302
|
+
*
|
|
303
|
+
* @param internalPubkey - x-only internal pubkey (32 bytes)
|
|
304
|
+
* @param scriptTree - Optional script tree
|
|
305
|
+
* @param network - Network parameters (defaults to mainnet)
|
|
306
|
+
* @returns A new P2TR payment instance
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* ```typescript
|
|
310
|
+
* // Key-path only
|
|
311
|
+
* const p2tr = P2TR.fromInternalPubkey(internalPubkey);
|
|
312
|
+
*
|
|
313
|
+
* // With script tree
|
|
314
|
+
* const withScripts = P2TR.fromInternalPubkey(internalPubkey, scriptTree);
|
|
315
|
+
* ```
|
|
316
|
+
*/
|
|
317
|
+
static fromInternalPubkey(
|
|
318
|
+
internalPubkey: XOnlyPublicKey,
|
|
319
|
+
scriptTree?: Taptree,
|
|
320
|
+
network?: Network,
|
|
321
|
+
): P2TR {
|
|
322
|
+
return new P2TR({ internalPubkey, scriptTree, network });
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Creates a P2TR payment from a bech32m address.
|
|
327
|
+
*
|
|
328
|
+
* @param address - Bech32m encoded address (bc1p...)
|
|
329
|
+
* @param network - Network parameters (defaults to mainnet)
|
|
330
|
+
* @returns A new P2TR payment instance
|
|
331
|
+
*/
|
|
332
|
+
static fromAddress(address: string, network?: Network): P2TR {
|
|
333
|
+
return new P2TR({ address, network });
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Creates a P2TR payment from a scriptPubKey.
|
|
338
|
+
*
|
|
339
|
+
* @param output - The scriptPubKey
|
|
340
|
+
* @param network - Network parameters (defaults to mainnet)
|
|
341
|
+
* @returns A new P2TR payment instance
|
|
342
|
+
*/
|
|
343
|
+
static fromOutput(output: Uint8Array, network?: Network): P2TR {
|
|
344
|
+
return new P2TR({ output, network });
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Creates a P2TR payment from a signature (for key-path spending).
|
|
349
|
+
*
|
|
350
|
+
* @param signature - Schnorr signature
|
|
351
|
+
* @param internalPubkey - x-only internal pubkey
|
|
352
|
+
* @param network - Network parameters (defaults to mainnet)
|
|
353
|
+
* @returns A new P2TR payment instance
|
|
354
|
+
*/
|
|
355
|
+
static fromSignature(
|
|
356
|
+
signature: SchnorrSignature,
|
|
357
|
+
internalPubkey?: XOnlyPublicKey,
|
|
358
|
+
network?: Network,
|
|
359
|
+
): P2TR {
|
|
360
|
+
return new P2TR({ signature, internalPubkey, network });
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Private helper methods
|
|
364
|
+
|
|
365
|
+
#getDecodedAddress(): { version: number; prefix: string; data: Uint8Array } | undefined {
|
|
366
|
+
if (!this.#decodedAddressComputed) {
|
|
367
|
+
if (this.#inputAddress) {
|
|
368
|
+
const decoded = fromBech32(this.#inputAddress);
|
|
369
|
+
if (decoded) {
|
|
370
|
+
this.#decodedAddress = {
|
|
371
|
+
version: decoded.version,
|
|
372
|
+
prefix: decoded.prefix,
|
|
373
|
+
data: decoded.data,
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
this.#decodedAddressComputed = true;
|
|
378
|
+
}
|
|
379
|
+
return this.#decodedAddress;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
#getWitnessWithoutAnnex(): Uint8Array[] | undefined {
|
|
383
|
+
if (!this.#witnessWithoutAnnexComputed) {
|
|
384
|
+
if (this.#inputWitness && this.#inputWitness.length > 0) {
|
|
385
|
+
// Remove annex if present
|
|
386
|
+
if (
|
|
387
|
+
this.#inputWitness.length >= 2 &&
|
|
388
|
+
this.#inputWitness[this.#inputWitness.length - 1]![0] === ANNEX_PREFIX
|
|
389
|
+
) {
|
|
390
|
+
this.#witnessWithoutAnnex = this.#inputWitness.slice(0, -1);
|
|
391
|
+
} else {
|
|
392
|
+
this.#witnessWithoutAnnex = this.#inputWitness.slice();
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
this.#witnessWithoutAnnexComputed = true;
|
|
396
|
+
}
|
|
397
|
+
return this.#witnessWithoutAnnex;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
#getHashTree(): HashTree | undefined {
|
|
401
|
+
if (!this.#hashTreeComputed) {
|
|
402
|
+
if (this.#inputScriptTree) {
|
|
403
|
+
this.#hashTree = toHashTree(this.#inputScriptTree);
|
|
404
|
+
} else if (this.#inputHash) {
|
|
405
|
+
this.#hashTree = { hash: this.#inputHash as Bytes32 };
|
|
406
|
+
}
|
|
407
|
+
this.#hashTreeComputed = true;
|
|
408
|
+
}
|
|
409
|
+
return this.#hashTree;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Private computation methods
|
|
413
|
+
|
|
414
|
+
#computeAddress(): string | undefined {
|
|
415
|
+
if (this.#inputAddress) {
|
|
416
|
+
return this.#inputAddress;
|
|
417
|
+
}
|
|
418
|
+
const pk = this.pubkey;
|
|
419
|
+
if (!pk) return undefined;
|
|
420
|
+
|
|
421
|
+
const words = bech32m.toWords(pk);
|
|
94
422
|
words.unshift(TAPROOT_WITNESS_VERSION);
|
|
95
|
-
return bech32m.encode(network.bech32, words);
|
|
96
|
-
}
|
|
423
|
+
return bech32m.encode(this.#network.bech32, words);
|
|
424
|
+
}
|
|
97
425
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
426
|
+
#computePubkey(): XOnlyPublicKey | undefined {
|
|
427
|
+
if (this.#inputPubkey) {
|
|
428
|
+
return this.#inputPubkey as XOnlyPublicKey;
|
|
429
|
+
}
|
|
430
|
+
if (this.#inputOutput) {
|
|
431
|
+
return this.#inputOutput.subarray(2) as XOnlyPublicKey;
|
|
432
|
+
}
|
|
433
|
+
if (this.#inputAddress) {
|
|
434
|
+
return this.#getDecodedAddress()?.data as XOnlyPublicKey | undefined;
|
|
435
|
+
}
|
|
436
|
+
const internalPk = this.internalPubkey;
|
|
437
|
+
if (internalPk) {
|
|
438
|
+
const tweakedKey = tweakKey(internalPk, this.hash);
|
|
439
|
+
if (tweakedKey) {
|
|
440
|
+
return tweakedKey.x as XOnlyPublicKey;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return undefined;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
#computeInternalPubkey(): XOnlyPublicKey | undefined {
|
|
447
|
+
if (this.#inputInternalPubkey) {
|
|
448
|
+
return this.#inputInternalPubkey as XOnlyPublicKey;
|
|
449
|
+
}
|
|
450
|
+
const witness = this.#getWitnessWithoutAnnex();
|
|
451
|
+
if (witness && witness.length > 1) {
|
|
452
|
+
return witness[witness.length - 1]!.subarray(1, 33) as XOnlyPublicKey;
|
|
453
|
+
}
|
|
454
|
+
return undefined;
|
|
455
|
+
}
|
|
101
456
|
|
|
102
|
-
|
|
457
|
+
#computeHash(): Bytes32 | undefined {
|
|
458
|
+
const hashTree = this.#getHashTree();
|
|
459
|
+
if (hashTree) {
|
|
460
|
+
return hashTree.hash as Bytes32;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const w = this.#getWitnessWithoutAnnex();
|
|
103
464
|
if (w && w.length > 1) {
|
|
104
|
-
const controlBlock = w[w.length - 1]
|
|
105
|
-
const leafVersion = controlBlock[0] & TAPLEAF_VERSION_MASK;
|
|
106
|
-
const script = w[w.length - 2]
|
|
465
|
+
const controlBlock = w[w.length - 1]!;
|
|
466
|
+
const leafVersion = controlBlock[0]! & TAPLEAF_VERSION_MASK;
|
|
467
|
+
const script = w[w.length - 2]!;
|
|
107
468
|
const leafHash = tapleafHash({
|
|
108
469
|
output: script,
|
|
109
470
|
version: leafVersion,
|
|
110
471
|
});
|
|
111
|
-
return rootHashFromPath(controlBlock, leafHash);
|
|
472
|
+
return rootHashFromPath(controlBlock, leafHash) as Bytes32;
|
|
112
473
|
}
|
|
113
474
|
|
|
114
475
|
return undefined;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
return
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
#computeSignature(): SchnorrSignature | undefined {
|
|
479
|
+
if (this.#inputSignature) {
|
|
480
|
+
return this.#inputSignature as SchnorrSignature;
|
|
481
|
+
}
|
|
482
|
+
const witness = this.#getWitnessWithoutAnnex();
|
|
483
|
+
if (witness && witness.length === 1) {
|
|
484
|
+
return witness[0] as SchnorrSignature;
|
|
485
|
+
}
|
|
486
|
+
return undefined;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
#computeOutput(): Script | undefined {
|
|
490
|
+
if (this.#inputOutput) {
|
|
491
|
+
return this.#inputOutput as Script;
|
|
124
492
|
}
|
|
493
|
+
const pk = this.pubkey;
|
|
494
|
+
if (!pk) return undefined;
|
|
125
495
|
|
|
126
|
-
return
|
|
127
|
-
}
|
|
128
|
-
lazy.prop(o, 'redeem', () => {
|
|
129
|
-
const witness = _witness(); // witness without annex
|
|
130
|
-
if (!witness || witness.length < 2) return;
|
|
496
|
+
return bscript.compile([OPS.OP_1, pk]) as Script;
|
|
497
|
+
}
|
|
131
498
|
|
|
499
|
+
#computeRedeem(): ScriptRedeem | undefined {
|
|
500
|
+
if (this.#inputRedeem) {
|
|
501
|
+
return this.#inputRedeem;
|
|
502
|
+
}
|
|
503
|
+
const witness = this.#getWitnessWithoutAnnex();
|
|
504
|
+
if (!witness || witness.length < 2) {
|
|
505
|
+
return undefined;
|
|
506
|
+
}
|
|
132
507
|
return {
|
|
133
|
-
output: witness[witness.length - 2],
|
|
508
|
+
output: witness[witness.length - 2] as Script,
|
|
134
509
|
witness: witness.slice(0, -2),
|
|
135
|
-
redeemVersion: witness[witness.length - 1][0] & TAPLEAF_VERSION_MASK,
|
|
510
|
+
redeemVersion: witness[witness.length - 1]![0]! & TAPLEAF_VERSION_MASK,
|
|
136
511
|
};
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (a.witness) return a.witness;
|
|
161
|
-
const hashTree = _hashTree();
|
|
162
|
-
if (hashTree && a.redeem && a.redeem.output && a.internalPubkey) {
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
#computeRedeemVersion(): number | undefined {
|
|
515
|
+
if (this.#inputRedeemVersion !== undefined) {
|
|
516
|
+
return this.#inputRedeemVersion;
|
|
517
|
+
}
|
|
518
|
+
if (
|
|
519
|
+
this.#inputRedeem &&
|
|
520
|
+
this.#inputRedeem.redeemVersion !== undefined &&
|
|
521
|
+
this.#inputRedeem.redeemVersion !== null
|
|
522
|
+
) {
|
|
523
|
+
return this.#inputRedeem.redeemVersion;
|
|
524
|
+
}
|
|
525
|
+
return LEAF_VERSION_TAPSCRIPT;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
#computeWitness(): Uint8Array[] | undefined {
|
|
529
|
+
if (this.#inputWitness) {
|
|
530
|
+
return this.#inputWitness;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const hashTree = this.#getHashTree();
|
|
534
|
+
if (hashTree && this.#inputRedeem?.output && this.#inputInternalPubkey) {
|
|
163
535
|
const leafHash = tapleafHash({
|
|
164
|
-
output:
|
|
165
|
-
version:
|
|
536
|
+
output: this.#inputRedeem.output,
|
|
537
|
+
version: this.redeemVersion,
|
|
166
538
|
});
|
|
167
539
|
const path = findScriptPath(hashTree, leafHash);
|
|
168
|
-
if (!path) return;
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
540
|
+
if (!path) return undefined;
|
|
541
|
+
|
|
542
|
+
const outputKey = tweakKey(this.#inputInternalPubkey as XOnlyPublicKey, hashTree.hash);
|
|
543
|
+
if (!outputKey) return undefined;
|
|
544
|
+
|
|
545
|
+
const version = this.redeemVersion ?? 0xc0;
|
|
546
|
+
const controlBlock = concat([
|
|
547
|
+
new Uint8Array([version | outputKey.parity]),
|
|
548
|
+
this.#inputInternalPubkey,
|
|
549
|
+
...path,
|
|
550
|
+
]);
|
|
551
|
+
return [this.#inputRedeem.output, controlBlock];
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (this.#inputSignature) {
|
|
555
|
+
return [this.#inputSignature];
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return undefined;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// Validation
|
|
562
|
+
|
|
563
|
+
#validate(): void {
|
|
564
|
+
let pubkey: Uint8Array = new Uint8Array(0);
|
|
565
|
+
|
|
566
|
+
if (this.#inputAddress) {
|
|
567
|
+
const addr = this.#getDecodedAddress();
|
|
568
|
+
if (!addr) {
|
|
569
|
+
throw new TypeError('Invalid address');
|
|
570
|
+
}
|
|
571
|
+
if (this.#network && this.#network.bech32 !== addr.prefix) {
|
|
186
572
|
throw new TypeError('Invalid prefix or Network mismatch');
|
|
187
|
-
|
|
573
|
+
}
|
|
574
|
+
if (addr.version !== TAPROOT_WITNESS_VERSION) {
|
|
188
575
|
throw new TypeError('Invalid address version');
|
|
189
|
-
|
|
190
|
-
|
|
576
|
+
}
|
|
577
|
+
if (addr.data.length !== 32) {
|
|
578
|
+
throw new TypeError('Invalid address data');
|
|
579
|
+
}
|
|
580
|
+
pubkey = addr.data;
|
|
191
581
|
}
|
|
192
582
|
|
|
193
|
-
if (
|
|
194
|
-
if (pubkey.length > 0 && !
|
|
583
|
+
if (this.#inputPubkey) {
|
|
584
|
+
if (pubkey.length > 0 && !equals(pubkey, this.#inputPubkey)) {
|
|
195
585
|
throw new TypeError('Pubkey mismatch');
|
|
196
|
-
else
|
|
586
|
+
} else {
|
|
587
|
+
pubkey = this.#inputPubkey;
|
|
588
|
+
}
|
|
197
589
|
}
|
|
198
590
|
|
|
199
|
-
if (
|
|
200
|
-
if (
|
|
591
|
+
if (this.#inputOutput) {
|
|
592
|
+
if (
|
|
593
|
+
this.#inputOutput.length !== 34 ||
|
|
594
|
+
this.#inputOutput[0] !== OPS.OP_1 ||
|
|
595
|
+
this.#inputOutput[1] !== 0x20
|
|
596
|
+
) {
|
|
201
597
|
throw new TypeError('Output is invalid');
|
|
202
|
-
|
|
598
|
+
}
|
|
599
|
+
if (pubkey.length > 0 && !equals(pubkey, this.#inputOutput.subarray(2))) {
|
|
203
600
|
throw new TypeError('Pubkey mismatch');
|
|
204
|
-
else
|
|
601
|
+
} else {
|
|
602
|
+
pubkey = this.#inputOutput.subarray(2);
|
|
603
|
+
}
|
|
205
604
|
}
|
|
206
605
|
|
|
207
|
-
if (
|
|
208
|
-
const tweakedKey = tweakKey(
|
|
209
|
-
if (
|
|
606
|
+
if (this.#inputInternalPubkey) {
|
|
607
|
+
const tweakedKey = tweakKey(this.#inputInternalPubkey as XOnlyPublicKey, this.hash);
|
|
608
|
+
if (!tweakedKey) {
|
|
609
|
+
throw new TypeError('Invalid internal pubkey');
|
|
610
|
+
}
|
|
611
|
+
if (pubkey.length > 0 && !equals(pubkey, tweakedKey.x)) {
|
|
210
612
|
throw new TypeError('Pubkey mismatch');
|
|
211
|
-
else
|
|
613
|
+
} else {
|
|
614
|
+
pubkey = tweakedKey.x;
|
|
615
|
+
}
|
|
212
616
|
}
|
|
213
617
|
|
|
214
|
-
|
|
215
|
-
if (!getEccLib().isXOnlyPoint(pubkey))
|
|
216
|
-
throw new TypeError('Invalid pubkey for p2tr');
|
|
217
|
-
}*/
|
|
618
|
+
const hashTree = this.#getHashTree();
|
|
218
619
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
620
|
+
if (this.#inputHash && hashTree) {
|
|
621
|
+
if (!equals(this.#inputHash, hashTree.hash)) {
|
|
622
|
+
throw new TypeError('Hash mismatch');
|
|
623
|
+
}
|
|
223
624
|
}
|
|
224
625
|
|
|
225
|
-
if (
|
|
626
|
+
if (this.#inputRedeem?.output && hashTree) {
|
|
226
627
|
const leafHash = tapleafHash({
|
|
227
|
-
output:
|
|
228
|
-
version:
|
|
628
|
+
output: this.#inputRedeem.output,
|
|
629
|
+
version: this.redeemVersion,
|
|
229
630
|
});
|
|
230
|
-
if (!findScriptPath(hashTree, leafHash))
|
|
631
|
+
if (!findScriptPath(hashTree, leafHash)) {
|
|
231
632
|
throw new TypeError('Redeem script not in tree');
|
|
633
|
+
}
|
|
232
634
|
}
|
|
233
635
|
|
|
234
|
-
const witness =
|
|
636
|
+
const witness = this.#getWitnessWithoutAnnex();
|
|
235
637
|
|
|
236
|
-
//
|
|
237
|
-
if (
|
|
238
|
-
if (
|
|
239
|
-
if (
|
|
638
|
+
// Compare provided redeem with computed from witness
|
|
639
|
+
if (this.#inputRedeem && this.redeem) {
|
|
640
|
+
if (this.#inputRedeem.redeemVersion) {
|
|
641
|
+
if (this.#inputRedeem.redeemVersion !== this.redeem.redeemVersion) {
|
|
240
642
|
throw new TypeError('Redeem.redeemVersion and witness mismatch');
|
|
643
|
+
}
|
|
241
644
|
}
|
|
242
645
|
|
|
243
|
-
if (
|
|
244
|
-
|
|
646
|
+
if (this.#inputRedeem.output) {
|
|
647
|
+
const decompiled = bscript.decompile(this.#inputRedeem.output);
|
|
648
|
+
if (!decompiled || decompiled.length === 0) {
|
|
245
649
|
throw new TypeError('Redeem.output is invalid');
|
|
650
|
+
}
|
|
246
651
|
|
|
247
|
-
|
|
248
|
-
if (o.redeem.output && !a.redeem.output.equals(o.redeem.output))
|
|
652
|
+
if (this.redeem.output && !equals(this.#inputRedeem.output, this.redeem.output)) {
|
|
249
653
|
throw new TypeError('Redeem.output and witness mismatch');
|
|
654
|
+
}
|
|
250
655
|
}
|
|
251
|
-
if (
|
|
252
|
-
if (
|
|
656
|
+
if (this.#inputRedeem.witness) {
|
|
657
|
+
if (
|
|
658
|
+
this.redeem.witness &&
|
|
659
|
+
!stacksEqual(this.#inputRedeem.witness, this.redeem.witness)
|
|
660
|
+
) {
|
|
253
661
|
throw new TypeError('Redeem.witness and witness mismatch');
|
|
662
|
+
}
|
|
254
663
|
}
|
|
255
664
|
}
|
|
256
665
|
|
|
257
|
-
if (witness && witness.length) {
|
|
666
|
+
if (witness && witness.length > 0) {
|
|
258
667
|
if (witness.length === 1) {
|
|
259
|
-
//
|
|
260
|
-
if (
|
|
668
|
+
// Key-path spending
|
|
669
|
+
if (this.#inputSignature && !equals(this.#inputSignature!, witness[0]!)) {
|
|
261
670
|
throw new TypeError('Signature mismatch');
|
|
671
|
+
}
|
|
262
672
|
} else {
|
|
263
|
-
//
|
|
264
|
-
const controlBlock = witness[witness.length - 1]
|
|
265
|
-
if (controlBlock.length < 33)
|
|
673
|
+
// Script-path spending
|
|
674
|
+
const controlBlock = witness[witness.length - 1]!;
|
|
675
|
+
if (controlBlock.length < 33) {
|
|
266
676
|
throw new TypeError(
|
|
267
677
|
`The control-block length is too small. Got ${controlBlock.length}, expected min 33.`,
|
|
268
678
|
);
|
|
679
|
+
}
|
|
269
680
|
|
|
270
|
-
if ((controlBlock.length - 33) % 32 !== 0)
|
|
681
|
+
if ((controlBlock.length - 33) % 32 !== 0) {
|
|
271
682
|
throw new TypeError(
|
|
272
683
|
`The control-block length of ${controlBlock.length} is incorrect!`,
|
|
273
684
|
);
|
|
685
|
+
}
|
|
274
686
|
|
|
275
687
|
const m = (controlBlock.length - 33) / 32;
|
|
276
|
-
if (m > 128)
|
|
688
|
+
if (m > 128) {
|
|
277
689
|
throw new TypeError(`The script path is too long. Got ${m}, expected max 128.`);
|
|
690
|
+
}
|
|
278
691
|
|
|
279
|
-
const
|
|
280
|
-
if (
|
|
692
|
+
const internalPk = controlBlock.subarray(1, 33);
|
|
693
|
+
if (this.#inputInternalPubkey && !equals(this.#inputInternalPubkey!, internalPk)) {
|
|
281
694
|
throw new TypeError('Internal pubkey mismatch');
|
|
695
|
+
}
|
|
282
696
|
|
|
283
|
-
if (!getEccLib().isXOnlyPoint(
|
|
697
|
+
if (!getEccLib().isXOnlyPoint(internalPk)) {
|
|
284
698
|
throw new TypeError('Invalid internalPubkey for p2tr witness');
|
|
699
|
+
}
|
|
285
700
|
|
|
286
|
-
const leafVersion = controlBlock[0] & TAPLEAF_VERSION_MASK;
|
|
287
|
-
const script = witness[witness.length - 2]
|
|
701
|
+
const leafVersion = controlBlock[0]! & TAPLEAF_VERSION_MASK;
|
|
702
|
+
const script = witness[witness.length - 2]!;
|
|
288
703
|
|
|
289
704
|
const leafHash = tapleafHash({
|
|
290
705
|
output: script,
|
|
291
706
|
version: leafVersion,
|
|
292
707
|
});
|
|
293
|
-
const
|
|
708
|
+
const computedHash = rootHashFromPath(controlBlock, leafHash);
|
|
294
709
|
|
|
295
|
-
const outputKey = tweakKey(
|
|
296
|
-
if (!outputKey)
|
|
297
|
-
// todo: needs test data
|
|
710
|
+
const outputKey = tweakKey(internalPk as XOnlyPublicKey, computedHash);
|
|
711
|
+
if (!outputKey) {
|
|
298
712
|
throw new TypeError('Invalid outputKey for p2tr witness');
|
|
713
|
+
}
|
|
299
714
|
|
|
300
|
-
if (pubkey.length && !
|
|
715
|
+
if (pubkey.length > 0 && !equals(pubkey, outputKey.x)) {
|
|
301
716
|
throw new TypeError('Pubkey mismatch for p2tr witness');
|
|
717
|
+
}
|
|
302
718
|
|
|
303
|
-
if (outputKey.parity !== (controlBlock[0] & 1))
|
|
719
|
+
if (outputKey.parity !== (controlBlock[0]! & 1)) {
|
|
720
|
+
throw new Error('Incorrect parity');
|
|
721
|
+
}
|
|
304
722
|
}
|
|
305
723
|
}
|
|
306
724
|
}
|
|
307
725
|
|
|
308
|
-
|
|
726
|
+
/**
|
|
727
|
+
* Converts to a plain P2TRPayment object for backwards compatibility.
|
|
728
|
+
*
|
|
729
|
+
* @returns A P2TRPayment object
|
|
730
|
+
*/
|
|
731
|
+
toPayment(): P2TRPayment {
|
|
732
|
+
return {
|
|
733
|
+
name: this.name,
|
|
734
|
+
network: this.network,
|
|
735
|
+
address: this.address,
|
|
736
|
+
pubkey: this.pubkey,
|
|
737
|
+
internalPubkey: this.internalPubkey,
|
|
738
|
+
hash: this.hash,
|
|
739
|
+
scriptTree: this.#inputScriptTree,
|
|
740
|
+
signature: this.signature,
|
|
741
|
+
output: this.output,
|
|
742
|
+
redeem: this.redeem,
|
|
743
|
+
redeemVersion: this.redeemVersion,
|
|
744
|
+
witness: this.witness,
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Creates a Pay-to-Taproot (P2TR) payment object.
|
|
751
|
+
*
|
|
752
|
+
* This is the legacy factory function for backwards compatibility.
|
|
753
|
+
* For new code, prefer using the P2TR class directly.
|
|
754
|
+
*
|
|
755
|
+
* @param a - The payment object containing the necessary data
|
|
756
|
+
* @param opts - Optional payment options
|
|
757
|
+
* @returns The P2TR payment object
|
|
758
|
+
* @throws {TypeError} If the required data is not provided or if the data is invalid
|
|
759
|
+
*
|
|
760
|
+
* @example
|
|
761
|
+
* ```typescript
|
|
762
|
+
* import { p2tr } from '@btc-vision/bitcoin';
|
|
763
|
+
*
|
|
764
|
+
* // Key-path only
|
|
765
|
+
* const payment = p2tr({ internalPubkey });
|
|
766
|
+
*
|
|
767
|
+
* // With script tree
|
|
768
|
+
* const withScripts = p2tr({ internalPubkey, scriptTree });
|
|
769
|
+
* ```
|
|
770
|
+
*/
|
|
771
|
+
export function p2tr(a: Omit<P2TRPayment, 'name'>, opts?: PaymentOpts): P2TRPayment {
|
|
772
|
+
if (
|
|
773
|
+
!a.address &&
|
|
774
|
+
!a.output &&
|
|
775
|
+
!a.pubkey &&
|
|
776
|
+
!a.internalPubkey &&
|
|
777
|
+
!(a.witness && a.witness.length > 1)
|
|
778
|
+
) {
|
|
779
|
+
throw new TypeError('Not enough data');
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
const instance = new P2TR(
|
|
783
|
+
{
|
|
784
|
+
address: a.address,
|
|
785
|
+
pubkey: a.pubkey,
|
|
786
|
+
internalPubkey: a.internalPubkey,
|
|
787
|
+
hash: a.hash,
|
|
788
|
+
scriptTree: a.scriptTree,
|
|
789
|
+
signature: a.signature,
|
|
790
|
+
output: a.output,
|
|
791
|
+
witness: a.witness,
|
|
792
|
+
redeem: a.redeem,
|
|
793
|
+
redeemVersion: a.redeemVersion,
|
|
794
|
+
network: a.network,
|
|
795
|
+
},
|
|
796
|
+
opts,
|
|
797
|
+
);
|
|
798
|
+
|
|
799
|
+
// Return a merged object for backwards compatibility
|
|
800
|
+
return Object.assign(instance.toPayment(), a);
|
|
309
801
|
}
|