@btc-vision/bitcoin 6.5.6 → 7.0.0-alpha.1
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 +57 -10
- 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 +12477 -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 +58 -11
- package/build/address.d.ts.map +1 -0
- package/build/address.js +82 -25
- 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 +202 -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 +35 -9
- package/build/payments/bip341.d.ts.map +1 -0
- package/build/payments/bip341.js +34 -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 -150
- 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 +428 -103
- 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 +465 -143
- 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 +117 -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 +406 -413
- 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 +101 -37
- 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 +169 -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 +68 -9
- package/scripts/bundle-ecc.ts +111 -0
- package/src/address.ts +91 -45
- package/src/bech32utils.ts +3 -3
- package/src/bip66.ts +34 -24
- package/src/block.ts +205 -86
- package/src/branded.ts +18 -0
- package/src/crypto.ts +64 -26
- package/src/ecc/context.ts +280 -0
- package/src/ecc/index.ts +14 -0
- package/src/ecc/types.ts +147 -0
- package/src/ecpair.d.ts +99 -0
- package/src/errors.ts +163 -0
- package/src/index.ts +112 -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 +32 -33
- package/src/payments/embed.ts +244 -41
- package/src/payments/index.ts +12 -10
- package/src/payments/p2ms.ts +497 -118
- package/src/payments/p2op.ts +432 -134
- package/src/payments/p2pk.ts +370 -72
- package/src/payments/p2pkh.ts +524 -130
- package/src/payments/p2sh.ts +572 -169
- package/src/payments/p2tr.ts +686 -194
- package/src/payments/p2wpkh.ts +482 -105
- package/src/payments/p2wsh.ts +524 -162
- package/src/payments/types.ts +80 -66
- package/src/psbt/bip371.ts +72 -51
- package/src/psbt/psbtutils.ts +39 -40
- package/src/psbt/types.ts +324 -0
- package/src/psbt/utils.ts +188 -0
- package/src/psbt/validation.ts +185 -0
- package/src/psbt.ts +608 -827
- package/src/pubkey.ts +22 -23
- package/src/push_data.ts +18 -16
- package/src/script.ts +81 -66
- package/src/script_number.ts +6 -6
- package/src/script_signature.ts +33 -36
- package/src/transaction.ts +462 -239
- package/src/types.ts +229 -100
- package/src/workers/WorkerSigningPool.node.ts +887 -0
- package/src/workers/WorkerSigningPool.ts +666 -0
- package/src/workers/ecc-bundle.ts +26 -0
- package/src/workers/index.ts +165 -0
- package/src/workers/psbt-parallel.ts +327 -0
- package/src/workers/signing-worker.ts +353 -0
- package/src/workers/types.ts +417 -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/typedoc.json +29 -0
- 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/src/payments/p2tr.ts
CHANGED
|
@@ -1,309 +1,801 @@
|
|
|
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
|
+
type Bytes32,
|
|
17
|
+
type SchnorrSignature,
|
|
18
|
+
type Script,
|
|
19
|
+
stacksEqual,
|
|
20
|
+
TAPLEAF_VERSION_MASK,
|
|
21
|
+
type Taptree,
|
|
22
|
+
type XOnlyPublicKey,
|
|
23
|
+
} from '../types.js';
|
|
8
24
|
import {
|
|
9
25
|
findScriptPath,
|
|
26
|
+
type HashTree,
|
|
10
27
|
LEAF_VERSION_TAPSCRIPT,
|
|
11
28
|
rootHashFromPath,
|
|
12
29
|
tapleafHash,
|
|
13
30
|
toHashTree,
|
|
14
31
|
tweakKey,
|
|
15
32
|
} from './bip341.js';
|
|
16
|
-
import {
|
|
17
|
-
import
|
|
33
|
+
import { concat, equals } from '../io/index.js';
|
|
34
|
+
import { type P2TRPayment, type PaymentOpts, PaymentType, 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
|
+
/**
|
|
366
|
+
* Converts to a plain P2TRPayment object for backwards compatibility.
|
|
367
|
+
*
|
|
368
|
+
* @returns A P2TRPayment object
|
|
369
|
+
*/
|
|
370
|
+
toPayment(): P2TRPayment {
|
|
371
|
+
return {
|
|
372
|
+
name: this.name,
|
|
373
|
+
network: this.network,
|
|
374
|
+
address: this.address,
|
|
375
|
+
pubkey: this.pubkey,
|
|
376
|
+
internalPubkey: this.internalPubkey,
|
|
377
|
+
hash: this.hash,
|
|
378
|
+
scriptTree: this.#inputScriptTree,
|
|
379
|
+
signature: this.signature,
|
|
380
|
+
output: this.output,
|
|
381
|
+
redeem: this.redeem,
|
|
382
|
+
redeemVersion: this.redeemVersion,
|
|
383
|
+
witness: this.witness,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
#getDecodedAddress(): { version: number; prefix: string; data: Uint8Array } | undefined {
|
|
388
|
+
if (!this.#decodedAddressComputed) {
|
|
389
|
+
if (this.#inputAddress) {
|
|
390
|
+
const decoded = fromBech32(this.#inputAddress);
|
|
391
|
+
if (decoded) {
|
|
392
|
+
this.#decodedAddress = {
|
|
393
|
+
version: decoded.version,
|
|
394
|
+
prefix: decoded.prefix,
|
|
395
|
+
data: decoded.data,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
this.#decodedAddressComputed = true;
|
|
400
|
+
}
|
|
401
|
+
return this.#decodedAddress;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
#getWitnessWithoutAnnex(): Uint8Array[] | undefined {
|
|
405
|
+
if (!this.#witnessWithoutAnnexComputed) {
|
|
406
|
+
if (this.#inputWitness && this.#inputWitness.length > 0) {
|
|
407
|
+
// Remove annex if present
|
|
408
|
+
if (
|
|
409
|
+
this.#inputWitness.length >= 2 &&
|
|
410
|
+
this.#inputWitness[this.#inputWitness.length - 1]![0] === ANNEX_PREFIX
|
|
411
|
+
) {
|
|
412
|
+
this.#witnessWithoutAnnex = this.#inputWitness.slice(0, -1);
|
|
413
|
+
} else {
|
|
414
|
+
this.#witnessWithoutAnnex = this.#inputWitness.slice();
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
this.#witnessWithoutAnnexComputed = true;
|
|
418
|
+
}
|
|
419
|
+
return this.#witnessWithoutAnnex;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Private computation methods
|
|
423
|
+
|
|
424
|
+
#getHashTree(): HashTree | undefined {
|
|
425
|
+
if (!this.#hashTreeComputed) {
|
|
426
|
+
if (this.#inputScriptTree) {
|
|
427
|
+
this.#hashTree = toHashTree(this.#inputScriptTree);
|
|
428
|
+
} else if (this.#inputHash) {
|
|
429
|
+
this.#hashTree = { hash: this.#inputHash as Bytes32 };
|
|
430
|
+
}
|
|
431
|
+
this.#hashTreeComputed = true;
|
|
432
|
+
}
|
|
433
|
+
return this.#hashTree;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
#computeAddress(): string | undefined {
|
|
437
|
+
if (this.#inputAddress) {
|
|
438
|
+
return this.#inputAddress;
|
|
439
|
+
}
|
|
440
|
+
const pk = this.pubkey;
|
|
441
|
+
if (!pk) return undefined;
|
|
442
|
+
|
|
443
|
+
const words = bech32m.toWords(pk);
|
|
94
444
|
words.unshift(TAPROOT_WITNESS_VERSION);
|
|
95
|
-
return bech32m.encode(network.bech32, words);
|
|
96
|
-
}
|
|
445
|
+
return bech32m.encode(this.#network.bech32, words);
|
|
446
|
+
}
|
|
97
447
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
448
|
+
#computePubkey(): XOnlyPublicKey | undefined {
|
|
449
|
+
if (this.#inputPubkey) {
|
|
450
|
+
return this.#inputPubkey as XOnlyPublicKey;
|
|
451
|
+
}
|
|
452
|
+
if (this.#inputOutput) {
|
|
453
|
+
return this.#inputOutput.subarray(2) as XOnlyPublicKey;
|
|
454
|
+
}
|
|
455
|
+
if (this.#inputAddress) {
|
|
456
|
+
return this.#getDecodedAddress()?.data as XOnlyPublicKey | undefined;
|
|
457
|
+
}
|
|
458
|
+
const internalPk = this.internalPubkey;
|
|
459
|
+
if (internalPk) {
|
|
460
|
+
const tweakedKey = tweakKey(internalPk, this.hash);
|
|
461
|
+
if (tweakedKey) {
|
|
462
|
+
return tweakedKey.x as XOnlyPublicKey;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return undefined;
|
|
466
|
+
}
|
|
101
467
|
|
|
102
|
-
|
|
468
|
+
#computeInternalPubkey(): XOnlyPublicKey | undefined {
|
|
469
|
+
if (this.#inputInternalPubkey) {
|
|
470
|
+
return this.#inputInternalPubkey as XOnlyPublicKey;
|
|
471
|
+
}
|
|
472
|
+
const witness = this.#getWitnessWithoutAnnex();
|
|
473
|
+
if (witness && witness.length > 1) {
|
|
474
|
+
return witness[witness.length - 1]!.subarray(1, 33) as XOnlyPublicKey;
|
|
475
|
+
}
|
|
476
|
+
return undefined;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
#computeHash(): Bytes32 | undefined {
|
|
480
|
+
const hashTree = this.#getHashTree();
|
|
481
|
+
if (hashTree) {
|
|
482
|
+
return hashTree.hash as Bytes32;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const w = this.#getWitnessWithoutAnnex();
|
|
103
486
|
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]
|
|
487
|
+
const controlBlock = w[w.length - 1]!;
|
|
488
|
+
const leafVersion = controlBlock[0]! & TAPLEAF_VERSION_MASK;
|
|
489
|
+
const script = w[w.length - 2]!;
|
|
107
490
|
const leafHash = tapleafHash({
|
|
108
491
|
output: script,
|
|
109
492
|
version: leafVersion,
|
|
110
493
|
});
|
|
111
|
-
return rootHashFromPath(controlBlock, leafHash);
|
|
494
|
+
return rootHashFromPath(controlBlock, leafHash) as Bytes32;
|
|
112
495
|
}
|
|
113
496
|
|
|
114
497
|
return undefined;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
lazy.prop(o, 'redeemVersion', () => {
|
|
121
|
-
if (a.redeemVersion) return a.redeemVersion;
|
|
122
|
-
if (a.redeem && a.redeem.redeemVersion !== undefined && a.redeem.redeemVersion !== null) {
|
|
123
|
-
return a.redeem.redeemVersion;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
#computeSignature(): SchnorrSignature | undefined {
|
|
501
|
+
if (this.#inputSignature) {
|
|
502
|
+
return this.#inputSignature as SchnorrSignature;
|
|
124
503
|
}
|
|
504
|
+
const witness = this.#getWitnessWithoutAnnex();
|
|
505
|
+
if (witness && witness.length === 1) {
|
|
506
|
+
return witness[0] as SchnorrSignature;
|
|
507
|
+
}
|
|
508
|
+
return undefined;
|
|
509
|
+
}
|
|
125
510
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
511
|
+
#computeOutput(): Script | undefined {
|
|
512
|
+
if (this.#inputOutput) {
|
|
513
|
+
return this.#inputOutput as Script;
|
|
514
|
+
}
|
|
515
|
+
const pk = this.pubkey;
|
|
516
|
+
if (!pk) return undefined;
|
|
131
517
|
|
|
518
|
+
return bscript.compile([OPS.OP_1, pk]) as Script;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
#computeRedeem(): ScriptRedeem | undefined {
|
|
522
|
+
if (this.#inputRedeem) {
|
|
523
|
+
return this.#inputRedeem;
|
|
524
|
+
}
|
|
525
|
+
const witness = this.#getWitnessWithoutAnnex();
|
|
526
|
+
if (!witness || witness.length < 2) {
|
|
527
|
+
return undefined;
|
|
528
|
+
}
|
|
132
529
|
return {
|
|
133
|
-
output: witness[witness.length - 2],
|
|
530
|
+
output: witness[witness.length - 2] as Script,
|
|
134
531
|
witness: witness.slice(0, -2),
|
|
135
|
-
redeemVersion: witness[witness.length - 1][0] & TAPLEAF_VERSION_MASK,
|
|
532
|
+
redeemVersion: witness[witness.length - 1]![0]! & TAPLEAF_VERSION_MASK,
|
|
136
533
|
};
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
if (hashTree && a.redeem && a.redeem.output && a.internalPubkey) {
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
#computeRedeemVersion(): number | undefined {
|
|
537
|
+
if (this.#inputRedeemVersion !== undefined) {
|
|
538
|
+
return this.#inputRedeemVersion;
|
|
539
|
+
}
|
|
540
|
+
if (
|
|
541
|
+
this.#inputRedeem &&
|
|
542
|
+
this.#inputRedeem.redeemVersion !== undefined &&
|
|
543
|
+
this.#inputRedeem.redeemVersion !== null
|
|
544
|
+
) {
|
|
545
|
+
return this.#inputRedeem.redeemVersion;
|
|
546
|
+
}
|
|
547
|
+
return LEAF_VERSION_TAPSCRIPT;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Validation
|
|
551
|
+
|
|
552
|
+
#computeWitness(): Uint8Array[] | undefined {
|
|
553
|
+
if (this.#inputWitness) {
|
|
554
|
+
return this.#inputWitness;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
const hashTree = this.#getHashTree();
|
|
558
|
+
if (hashTree && this.#inputRedeem?.output && this.#inputInternalPubkey) {
|
|
163
559
|
const leafHash = tapleafHash({
|
|
164
|
-
output:
|
|
165
|
-
version:
|
|
560
|
+
output: this.#inputRedeem.output,
|
|
561
|
+
version: this.redeemVersion,
|
|
166
562
|
});
|
|
167
563
|
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
|
-
|
|
564
|
+
if (!path) return undefined;
|
|
565
|
+
|
|
566
|
+
const outputKey = tweakKey(this.#inputInternalPubkey as XOnlyPublicKey, hashTree.hash);
|
|
567
|
+
if (!outputKey) return undefined;
|
|
568
|
+
|
|
569
|
+
const version = this.redeemVersion ?? 0xc0;
|
|
570
|
+
const controlBlock = concat([
|
|
571
|
+
new Uint8Array([version | outputKey.parity]),
|
|
572
|
+
this.#inputInternalPubkey,
|
|
573
|
+
...path,
|
|
574
|
+
]);
|
|
575
|
+
return [this.#inputRedeem.output, controlBlock];
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
if (this.#inputSignature) {
|
|
579
|
+
return [this.#inputSignature];
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return undefined;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
#validate(): void {
|
|
586
|
+
let pubkey: Uint8Array = new Uint8Array(0);
|
|
587
|
+
|
|
588
|
+
if (this.#inputAddress) {
|
|
589
|
+
const addr = this.#getDecodedAddress();
|
|
590
|
+
if (!addr) {
|
|
591
|
+
throw new TypeError('Invalid address');
|
|
592
|
+
}
|
|
593
|
+
if (this.#network && this.#network.bech32 !== addr.prefix) {
|
|
186
594
|
throw new TypeError('Invalid prefix or Network mismatch');
|
|
187
|
-
|
|
595
|
+
}
|
|
596
|
+
if (addr.version !== TAPROOT_WITNESS_VERSION) {
|
|
188
597
|
throw new TypeError('Invalid address version');
|
|
189
|
-
|
|
190
|
-
|
|
598
|
+
}
|
|
599
|
+
if (addr.data.length !== 32) {
|
|
600
|
+
throw new TypeError('Invalid address data');
|
|
601
|
+
}
|
|
602
|
+
pubkey = addr.data;
|
|
191
603
|
}
|
|
192
604
|
|
|
193
|
-
if (
|
|
194
|
-
if (pubkey.length > 0 && !
|
|
605
|
+
if (this.#inputPubkey) {
|
|
606
|
+
if (pubkey.length > 0 && !equals(pubkey, this.#inputPubkey)) {
|
|
195
607
|
throw new TypeError('Pubkey mismatch');
|
|
196
|
-
else
|
|
608
|
+
} else {
|
|
609
|
+
pubkey = this.#inputPubkey;
|
|
610
|
+
}
|
|
197
611
|
}
|
|
198
612
|
|
|
199
|
-
if (
|
|
200
|
-
if (
|
|
613
|
+
if (this.#inputOutput) {
|
|
614
|
+
if (
|
|
615
|
+
this.#inputOutput.length !== 34 ||
|
|
616
|
+
this.#inputOutput[0] !== OPS.OP_1 ||
|
|
617
|
+
this.#inputOutput[1] !== 0x20
|
|
618
|
+
) {
|
|
201
619
|
throw new TypeError('Output is invalid');
|
|
202
|
-
|
|
620
|
+
}
|
|
621
|
+
if (pubkey.length > 0 && !equals(pubkey, this.#inputOutput.subarray(2))) {
|
|
203
622
|
throw new TypeError('Pubkey mismatch');
|
|
204
|
-
else
|
|
623
|
+
} else {
|
|
624
|
+
pubkey = this.#inputOutput.subarray(2);
|
|
625
|
+
}
|
|
205
626
|
}
|
|
206
627
|
|
|
207
|
-
if (
|
|
208
|
-
const tweakedKey = tweakKey(
|
|
209
|
-
if (
|
|
628
|
+
if (this.#inputInternalPubkey) {
|
|
629
|
+
const tweakedKey = tweakKey(this.#inputInternalPubkey as XOnlyPublicKey, this.hash);
|
|
630
|
+
if (!tweakedKey) {
|
|
631
|
+
throw new TypeError('Invalid internal pubkey');
|
|
632
|
+
}
|
|
633
|
+
if (pubkey.length > 0 && !equals(pubkey, tweakedKey.x)) {
|
|
210
634
|
throw new TypeError('Pubkey mismatch');
|
|
211
|
-
else
|
|
635
|
+
} else {
|
|
636
|
+
pubkey = tweakedKey.x;
|
|
637
|
+
}
|
|
212
638
|
}
|
|
213
639
|
|
|
214
|
-
|
|
215
|
-
if (!getEccLib().isXOnlyPoint(pubkey))
|
|
216
|
-
throw new TypeError('Invalid pubkey for p2tr');
|
|
217
|
-
}*/
|
|
218
|
-
|
|
219
|
-
const hashTree = _hashTree();
|
|
640
|
+
const hashTree = this.#getHashTree();
|
|
220
641
|
|
|
221
|
-
if (
|
|
222
|
-
if (!
|
|
642
|
+
if (this.#inputHash && hashTree) {
|
|
643
|
+
if (!equals(this.#inputHash, hashTree.hash)) {
|
|
644
|
+
throw new TypeError('Hash mismatch');
|
|
645
|
+
}
|
|
223
646
|
}
|
|
224
647
|
|
|
225
|
-
if (
|
|
648
|
+
if (this.#inputRedeem?.output && hashTree) {
|
|
226
649
|
const leafHash = tapleafHash({
|
|
227
|
-
output:
|
|
228
|
-
version:
|
|
650
|
+
output: this.#inputRedeem.output,
|
|
651
|
+
version: this.redeemVersion,
|
|
229
652
|
});
|
|
230
|
-
if (!findScriptPath(hashTree, leafHash))
|
|
653
|
+
if (!findScriptPath(hashTree, leafHash)) {
|
|
231
654
|
throw new TypeError('Redeem script not in tree');
|
|
655
|
+
}
|
|
232
656
|
}
|
|
233
657
|
|
|
234
|
-
const witness =
|
|
658
|
+
const witness = this.#getWitnessWithoutAnnex();
|
|
235
659
|
|
|
236
|
-
//
|
|
237
|
-
if (
|
|
238
|
-
if (
|
|
239
|
-
if (
|
|
660
|
+
// Compare provided redeem with computed from witness
|
|
661
|
+
if (this.#inputRedeem && this.redeem) {
|
|
662
|
+
if (this.#inputRedeem.redeemVersion) {
|
|
663
|
+
if (this.#inputRedeem.redeemVersion !== this.redeem.redeemVersion) {
|
|
240
664
|
throw new TypeError('Redeem.redeemVersion and witness mismatch');
|
|
665
|
+
}
|
|
241
666
|
}
|
|
242
667
|
|
|
243
|
-
if (
|
|
244
|
-
|
|
668
|
+
if (this.#inputRedeem.output) {
|
|
669
|
+
const decompiled = bscript.decompile(this.#inputRedeem.output);
|
|
670
|
+
if (!decompiled || decompiled.length === 0) {
|
|
245
671
|
throw new TypeError('Redeem.output is invalid');
|
|
672
|
+
}
|
|
246
673
|
|
|
247
|
-
|
|
248
|
-
if (o.redeem.output && !a.redeem.output.equals(o.redeem.output))
|
|
674
|
+
if (this.redeem.output && !equals(this.#inputRedeem.output, this.redeem.output)) {
|
|
249
675
|
throw new TypeError('Redeem.output and witness mismatch');
|
|
676
|
+
}
|
|
250
677
|
}
|
|
251
|
-
if (
|
|
252
|
-
if (
|
|
678
|
+
if (this.#inputRedeem.witness) {
|
|
679
|
+
if (
|
|
680
|
+
this.redeem.witness &&
|
|
681
|
+
!stacksEqual(this.#inputRedeem.witness, this.redeem.witness)
|
|
682
|
+
) {
|
|
253
683
|
throw new TypeError('Redeem.witness and witness mismatch');
|
|
684
|
+
}
|
|
254
685
|
}
|
|
255
686
|
}
|
|
256
687
|
|
|
257
|
-
if (witness && witness.length) {
|
|
688
|
+
if (witness && witness.length > 0) {
|
|
258
689
|
if (witness.length === 1) {
|
|
259
|
-
//
|
|
260
|
-
if (
|
|
690
|
+
// Key-path spending
|
|
691
|
+
if (this.#inputSignature && !equals(this.#inputSignature!, witness[0]!)) {
|
|
261
692
|
throw new TypeError('Signature mismatch');
|
|
693
|
+
}
|
|
262
694
|
} else {
|
|
263
|
-
//
|
|
264
|
-
const controlBlock = witness[witness.length - 1]
|
|
265
|
-
if (controlBlock.length < 33)
|
|
695
|
+
// Script-path spending
|
|
696
|
+
const controlBlock = witness[witness.length - 1]!;
|
|
697
|
+
if (controlBlock.length < 33) {
|
|
266
698
|
throw new TypeError(
|
|
267
699
|
`The control-block length is too small. Got ${controlBlock.length}, expected min 33.`,
|
|
268
700
|
);
|
|
701
|
+
}
|
|
269
702
|
|
|
270
|
-
if ((controlBlock.length - 33) % 32 !== 0)
|
|
703
|
+
if ((controlBlock.length - 33) % 32 !== 0) {
|
|
271
704
|
throw new TypeError(
|
|
272
705
|
`The control-block length of ${controlBlock.length} is incorrect!`,
|
|
273
706
|
);
|
|
707
|
+
}
|
|
274
708
|
|
|
275
709
|
const m = (controlBlock.length - 33) / 32;
|
|
276
|
-
if (m > 128)
|
|
710
|
+
if (m > 128) {
|
|
277
711
|
throw new TypeError(`The script path is too long. Got ${m}, expected max 128.`);
|
|
712
|
+
}
|
|
278
713
|
|
|
279
|
-
const
|
|
280
|
-
if (
|
|
714
|
+
const internalPk = controlBlock.subarray(1, 33);
|
|
715
|
+
if (this.#inputInternalPubkey && !equals(this.#inputInternalPubkey!, internalPk)) {
|
|
281
716
|
throw new TypeError('Internal pubkey mismatch');
|
|
717
|
+
}
|
|
282
718
|
|
|
283
|
-
if (!getEccLib().isXOnlyPoint(
|
|
719
|
+
if (!getEccLib().isXOnlyPoint(internalPk)) {
|
|
284
720
|
throw new TypeError('Invalid internalPubkey for p2tr witness');
|
|
721
|
+
}
|
|
285
722
|
|
|
286
|
-
const leafVersion = controlBlock[0] & TAPLEAF_VERSION_MASK;
|
|
287
|
-
const script = witness[witness.length - 2]
|
|
723
|
+
const leafVersion = controlBlock[0]! & TAPLEAF_VERSION_MASK;
|
|
724
|
+
const script = witness[witness.length - 2]!;
|
|
288
725
|
|
|
289
726
|
const leafHash = tapleafHash({
|
|
290
727
|
output: script,
|
|
291
728
|
version: leafVersion,
|
|
292
729
|
});
|
|
293
|
-
const
|
|
730
|
+
const computedHash = rootHashFromPath(controlBlock, leafHash);
|
|
294
731
|
|
|
295
|
-
const outputKey = tweakKey(
|
|
296
|
-
if (!outputKey)
|
|
297
|
-
// todo: needs test data
|
|
732
|
+
const outputKey = tweakKey(internalPk as XOnlyPublicKey, computedHash);
|
|
733
|
+
if (!outputKey) {
|
|
298
734
|
throw new TypeError('Invalid outputKey for p2tr witness');
|
|
735
|
+
}
|
|
299
736
|
|
|
300
|
-
if (pubkey.length && !
|
|
737
|
+
if (pubkey.length > 0 && !equals(pubkey, outputKey.x)) {
|
|
301
738
|
throw new TypeError('Pubkey mismatch for p2tr witness');
|
|
739
|
+
}
|
|
302
740
|
|
|
303
|
-
if (outputKey.parity !== (controlBlock[0] & 1))
|
|
741
|
+
if (outputKey.parity !== (controlBlock[0]! & 1)) {
|
|
742
|
+
throw new Error('Incorrect parity');
|
|
743
|
+
}
|
|
304
744
|
}
|
|
305
745
|
}
|
|
306
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
|
+
);
|
|
307
798
|
|
|
308
|
-
|
|
799
|
+
// Return a merged object for backwards compatibility
|
|
800
|
+
return Object.assign(instance.toPayment(), a);
|
|
309
801
|
}
|