@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/p2sh.ts
CHANGED
|
@@ -1,210 +1,610 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pay-to-Script-Hash (P2SH) payment class.
|
|
3
|
+
*
|
|
4
|
+
* P2SH allows spending to be based on a hash of a script, with the actual
|
|
5
|
+
* script revealed only at spend time. This enables complex spending conditions
|
|
6
|
+
* while keeping addresses short.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
|
|
1
11
|
import * as bs58check from 'bs58check';
|
|
2
12
|
import * as bcrypto from '../crypto.js';
|
|
3
|
-
import { bitcoin as BITCOIN_NETWORK } from '../networks.js';
|
|
13
|
+
import { bitcoin as BITCOIN_NETWORK, type Network } from '../networks.js';
|
|
4
14
|
import * as bscript from '../script.js';
|
|
5
|
-
import { stacksEqual,
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
15
|
+
import { stacksEqual, type Bytes20, type Script, type Stack } from '../types.js';
|
|
16
|
+
import { alloc, equals } from '../io/index.js';
|
|
17
|
+
import {
|
|
18
|
+
PaymentType,
|
|
19
|
+
type P2SHPayment,
|
|
20
|
+
type Payment,
|
|
21
|
+
type PaymentOpts,
|
|
22
|
+
type ScriptRedeem,
|
|
23
|
+
} from './types.js';
|
|
8
24
|
|
|
9
25
|
const OPS = bscript.opcodes;
|
|
10
26
|
|
|
11
|
-
// input: [redeemScriptSig ...] {redeemScript}
|
|
12
|
-
// witness: <?>
|
|
13
|
-
// output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL
|
|
14
27
|
/**
|
|
15
|
-
*
|
|
28
|
+
* Pay-to-Script-Hash (P2SH) payment class.
|
|
29
|
+
*
|
|
30
|
+
* Creates locking scripts of the form:
|
|
31
|
+
* `OP_HASH160 {hash160(redeemScript)} OP_EQUAL`
|
|
32
|
+
*
|
|
33
|
+
* Spending requires: `{redeemScriptSig...} {redeemScript}`
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { P2SH, P2MS } from '@btc-vision/bitcoin';
|
|
38
|
+
*
|
|
39
|
+
* // Wrap a multisig in P2SH
|
|
40
|
+
* const multisig = P2MS.fromPubkeys(2, [pubkey1, pubkey2, pubkey3]);
|
|
41
|
+
* const p2sh = P2SH.fromRedeem({ output: multisig.output });
|
|
42
|
+
* console.log(p2sh.address); // 3... address
|
|
16
43
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
44
|
+
* // Decode an existing output
|
|
45
|
+
* const decoded = P2SH.fromOutput(scriptPubKey);
|
|
46
|
+
* console.log(decoded.hash); // 20-byte script hash
|
|
47
|
+
* ```
|
|
21
48
|
*/
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
opts = Object.assign({ validate: true }, opts || {});
|
|
49
|
+
export class P2SH {
|
|
50
|
+
// Static public fields
|
|
51
|
+
static readonly NAME = PaymentType.P2SH;
|
|
27
52
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
address: typef.maybe(typef.String),
|
|
33
|
-
hash: typef.maybe(typef.BufferN(20)),
|
|
34
|
-
output: typef.maybe(typef.BufferN(23)),
|
|
35
|
-
|
|
36
|
-
redeem: typef.maybe({
|
|
37
|
-
network: typef.maybe(typef.Object),
|
|
38
|
-
output: typef.maybe(typef.Buffer),
|
|
39
|
-
input: typef.maybe(typef.Buffer),
|
|
40
|
-
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
|
|
41
|
-
}),
|
|
42
|
-
input: typef.maybe(typef.Buffer),
|
|
43
|
-
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
|
|
44
|
-
},
|
|
45
|
-
a,
|
|
46
|
-
);
|
|
53
|
+
// Private instance fields
|
|
54
|
+
readonly #network: Network;
|
|
55
|
+
readonly #opts: Required<PaymentOpts>;
|
|
47
56
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
57
|
+
// Input data (provided by user)
|
|
58
|
+
#inputAddress?: string | undefined;
|
|
59
|
+
#inputHash?: Uint8Array | undefined;
|
|
60
|
+
#inputOutput?: Uint8Array | undefined;
|
|
61
|
+
#inputInput?: Uint8Array | undefined;
|
|
62
|
+
#inputRedeem?: ScriptRedeem | undefined;
|
|
63
|
+
#inputWitness?: Uint8Array[] | undefined;
|
|
64
|
+
|
|
65
|
+
// Cached computed values
|
|
66
|
+
#address?: string | undefined;
|
|
67
|
+
#hash?: Uint8Array | undefined;
|
|
68
|
+
#output?: Uint8Array | undefined;
|
|
69
|
+
#input?: Uint8Array | undefined;
|
|
70
|
+
#redeem?: ScriptRedeem | undefined;
|
|
71
|
+
#witness?: Uint8Array[] | undefined;
|
|
72
|
+
|
|
73
|
+
// Cache flags
|
|
74
|
+
#addressComputed = false;
|
|
75
|
+
#hashComputed = false;
|
|
76
|
+
#outputComputed = false;
|
|
77
|
+
#inputComputed = false;
|
|
78
|
+
#redeemComputed = false;
|
|
79
|
+
#witnessComputed = false;
|
|
80
|
+
|
|
81
|
+
// Decoded address cache
|
|
82
|
+
#decodedAddress?: { version: number; hash: Uint8Array } | undefined;
|
|
83
|
+
#decodedAddressComputed = false;
|
|
84
|
+
|
|
85
|
+
// Decoded input chunks cache
|
|
86
|
+
#inputChunks?: Stack | undefined;
|
|
87
|
+
#inputChunksComputed = false;
|
|
88
|
+
|
|
89
|
+
// Derived redeem from input
|
|
90
|
+
#derivedRedeem?: ScriptRedeem | undefined;
|
|
91
|
+
#derivedRedeemComputed = false;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Creates a new P2SH payment instance.
|
|
95
|
+
*
|
|
96
|
+
* @param params - Payment parameters
|
|
97
|
+
* @param params.address - Base58Check encoded address (3...)
|
|
98
|
+
* @param params.hash - 20-byte script hash
|
|
99
|
+
* @param params.output - The scriptPubKey
|
|
100
|
+
* @param params.input - The scriptSig
|
|
101
|
+
* @param params.redeem - The redeem script information
|
|
102
|
+
* @param params.witness - The witness stack (for wrapped SegWit)
|
|
103
|
+
* @param params.network - Network parameters (defaults to mainnet)
|
|
104
|
+
* @param opts - Payment options
|
|
105
|
+
* @param opts.validate - Whether to validate inputs (default: true)
|
|
106
|
+
*
|
|
107
|
+
* @throws {TypeError} If validation is enabled and data is invalid
|
|
108
|
+
*/
|
|
109
|
+
constructor(
|
|
110
|
+
params: {
|
|
111
|
+
address?: string | undefined;
|
|
112
|
+
hash?: Uint8Array | undefined;
|
|
113
|
+
output?: Uint8Array | undefined;
|
|
114
|
+
input?: Uint8Array | undefined;
|
|
115
|
+
redeem?: ScriptRedeem | undefined;
|
|
116
|
+
witness?: Uint8Array[] | undefined;
|
|
117
|
+
network?: Network | undefined;
|
|
118
|
+
},
|
|
119
|
+
opts?: PaymentOpts,
|
|
120
|
+
) {
|
|
121
|
+
// Derive network from redeem if not specified
|
|
122
|
+
let network = params.network;
|
|
123
|
+
if (!network) {
|
|
124
|
+
network = (params.redeem && params.redeem.network) || BITCOIN_NETWORK;
|
|
125
|
+
}
|
|
126
|
+
this.#network = network;
|
|
127
|
+
this.#opts = {
|
|
128
|
+
validate: opts?.validate ?? true,
|
|
129
|
+
allowIncomplete: opts?.allowIncomplete ?? false,
|
|
76
130
|
};
|
|
77
|
-
});
|
|
78
131
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
132
|
+
// Store input data
|
|
133
|
+
this.#inputAddress = params.address;
|
|
134
|
+
this.#inputHash = params.hash;
|
|
135
|
+
this.#inputOutput = params.output;
|
|
136
|
+
this.#inputInput = params.input;
|
|
137
|
+
this.#inputRedeem = params.redeem;
|
|
138
|
+
this.#inputWitness = params.witness;
|
|
139
|
+
|
|
140
|
+
// Validate if requested
|
|
141
|
+
if (this.#opts.validate) {
|
|
142
|
+
this.#validate();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Public getters
|
|
82
147
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Payment type discriminant.
|
|
150
|
+
*/
|
|
151
|
+
get name(): string {
|
|
152
|
+
const r = this.redeem;
|
|
153
|
+
if (r !== undefined && r.name !== undefined) {
|
|
154
|
+
return `p2sh-${r.name}`;
|
|
155
|
+
}
|
|
156
|
+
return PaymentType.P2SH;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Network parameters.
|
|
161
|
+
*/
|
|
162
|
+
get network(): Network {
|
|
163
|
+
return this.#network;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Base58Check encoded address (3... for mainnet).
|
|
168
|
+
*/
|
|
169
|
+
get address(): string | undefined {
|
|
170
|
+
if (!this.#addressComputed) {
|
|
171
|
+
this.#address = this.#computeAddress();
|
|
172
|
+
this.#addressComputed = true;
|
|
173
|
+
}
|
|
174
|
+
return this.#address;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 20-byte script hash (HASH160 of redeem script).
|
|
179
|
+
*/
|
|
180
|
+
get hash(): Bytes20 | undefined {
|
|
181
|
+
if (!this.#hashComputed) {
|
|
182
|
+
this.#hash = this.#computeHash();
|
|
183
|
+
this.#hashComputed = true;
|
|
184
|
+
}
|
|
185
|
+
return this.#hash as Bytes20 | undefined;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* The scriptPubKey: `OP_HASH160 {hash} OP_EQUAL`
|
|
190
|
+
*/
|
|
191
|
+
get output(): Script | undefined {
|
|
192
|
+
if (!this.#outputComputed) {
|
|
193
|
+
this.#output = this.#computeOutput();
|
|
194
|
+
this.#outputComputed = true;
|
|
195
|
+
}
|
|
196
|
+
return this.#output as Script | undefined;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* The scriptSig: `{redeemScriptSig...} {redeemScript}`
|
|
201
|
+
*/
|
|
202
|
+
get input(): Script | undefined {
|
|
203
|
+
if (!this.#inputComputed) {
|
|
204
|
+
this.#input = this.#computeInput();
|
|
205
|
+
this.#inputComputed = true;
|
|
206
|
+
}
|
|
207
|
+
return this.#input as Script | undefined;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* The redeem script information.
|
|
212
|
+
*/
|
|
213
|
+
get redeem(): ScriptRedeem | undefined {
|
|
214
|
+
if (!this.#redeemComputed) {
|
|
215
|
+
this.#redeem = this.#computeRedeem();
|
|
216
|
+
this.#redeemComputed = true;
|
|
217
|
+
}
|
|
218
|
+
return this.#redeem;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* The witness stack (for wrapped SegWit).
|
|
223
|
+
*/
|
|
224
|
+
get witness(): Uint8Array[] | undefined {
|
|
225
|
+
if (!this.#witnessComputed) {
|
|
226
|
+
this.#witness = this.#computeWitness();
|
|
227
|
+
this.#witnessComputed = true;
|
|
228
|
+
}
|
|
229
|
+
return this.#witness;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Static factory methods
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Creates a P2SH payment from a redeem script.
|
|
236
|
+
*
|
|
237
|
+
* @param redeem - The redeem script information
|
|
238
|
+
* @param network - Network parameters (defaults to mainnet)
|
|
239
|
+
* @returns A new P2SH payment instance
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* const p2sh = P2SH.fromRedeem({ output: redeemScript });
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
static fromRedeem(redeem: ScriptRedeem, network?: Network): P2SH {
|
|
247
|
+
return new P2SH({ redeem, network });
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Creates a P2SH payment from a Base58Check address.
|
|
252
|
+
*
|
|
253
|
+
* @param address - Base58Check encoded address
|
|
254
|
+
* @param network - Network parameters (defaults to mainnet)
|
|
255
|
+
* @returns A new P2SH payment instance
|
|
256
|
+
*/
|
|
257
|
+
static fromAddress(address: string, network?: Network): P2SH {
|
|
258
|
+
return new P2SH({ address, network });
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Creates a P2SH payment from a 20-byte script hash.
|
|
263
|
+
*
|
|
264
|
+
* @param hash - 20-byte script hash
|
|
265
|
+
* @param network - Network parameters (defaults to mainnet)
|
|
266
|
+
* @returns A new P2SH payment instance
|
|
267
|
+
*/
|
|
268
|
+
static fromHash(hash: Bytes20, network?: Network): P2SH {
|
|
269
|
+
return new P2SH({ hash, network });
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Creates a P2SH payment from a scriptPubKey.
|
|
274
|
+
*
|
|
275
|
+
* @param output - The scriptPubKey
|
|
276
|
+
* @param network - Network parameters (defaults to mainnet)
|
|
277
|
+
* @returns A new P2SH payment instance
|
|
278
|
+
*/
|
|
279
|
+
static fromOutput(output: Uint8Array, network?: Network): P2SH {
|
|
280
|
+
return new P2SH({ output, network });
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Private helper methods
|
|
284
|
+
|
|
285
|
+
#getDecodedAddress(): { version: number; hash: Uint8Array } | undefined {
|
|
286
|
+
if (!this.#decodedAddressComputed) {
|
|
287
|
+
if (this.#inputAddress) {
|
|
288
|
+
const payload = new Uint8Array(bs58check.default.decode(this.#inputAddress));
|
|
289
|
+
this.#decodedAddress = {
|
|
290
|
+
version: payload[0]!,
|
|
291
|
+
hash: payload.subarray(1),
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
this.#decodedAddressComputed = true;
|
|
295
|
+
}
|
|
296
|
+
return this.#decodedAddress;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
#getInputChunks(): Stack | undefined {
|
|
300
|
+
if (!this.#inputChunksComputed) {
|
|
301
|
+
if (this.#inputInput) {
|
|
302
|
+
this.#inputChunks = (bscript.decompile(this.#inputInput) as Stack) ?? undefined;
|
|
303
|
+
}
|
|
304
|
+
this.#inputChunksComputed = true;
|
|
305
|
+
}
|
|
306
|
+
return this.#inputChunks;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
#getDerivedRedeem(): ScriptRedeem | undefined {
|
|
310
|
+
if (!this.#derivedRedeemComputed) {
|
|
311
|
+
const chunks = this.#getInputChunks();
|
|
312
|
+
if (chunks) {
|
|
313
|
+
const lastChunk = chunks[chunks.length - 1];
|
|
314
|
+
this.#derivedRedeem = {
|
|
315
|
+
network: this.#network,
|
|
316
|
+
output:
|
|
317
|
+
(lastChunk === OPS.OP_FALSE ? new Uint8Array(0) : (lastChunk as Uint8Array)) as Script,
|
|
318
|
+
input: bscript.compile(chunks.slice(0, -1)) as Script,
|
|
319
|
+
witness: this.#inputWitness || [],
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
this.#derivedRedeemComputed = true;
|
|
323
|
+
}
|
|
324
|
+
return this.#derivedRedeem;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Private computation methods
|
|
328
|
+
|
|
329
|
+
#computeAddress(): string | undefined {
|
|
330
|
+
if (this.#inputAddress) {
|
|
331
|
+
return this.#inputAddress;
|
|
332
|
+
}
|
|
333
|
+
const h = this.hash;
|
|
334
|
+
if (!h) return undefined;
|
|
335
|
+
|
|
336
|
+
const payload = alloc(21);
|
|
337
|
+
payload[0] = this.#network.scriptHash;
|
|
338
|
+
payload.set(h, 1);
|
|
86
339
|
return bs58check.default.encode(payload);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
#computeHash(): Bytes20 | undefined {
|
|
343
|
+
if (this.#inputHash) {
|
|
344
|
+
return this.#inputHash as Bytes20;
|
|
345
|
+
}
|
|
346
|
+
if (this.#inputOutput) {
|
|
347
|
+
return this.#inputOutput.subarray(2, 22) as Bytes20;
|
|
348
|
+
}
|
|
349
|
+
if (this.#inputAddress) {
|
|
350
|
+
return this.#getDecodedAddress()?.hash as Bytes20 | undefined;
|
|
351
|
+
}
|
|
352
|
+
const r = this.redeem;
|
|
353
|
+
if (r && r.output) {
|
|
354
|
+
return bcrypto.hash160(r.output) as Bytes20;
|
|
355
|
+
}
|
|
356
|
+
return undefined;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
#computeOutput(): Script | undefined {
|
|
360
|
+
if (this.#inputOutput) {
|
|
361
|
+
return this.#inputOutput as Script;
|
|
362
|
+
}
|
|
363
|
+
const h = this.hash;
|
|
364
|
+
if (!h) return undefined;
|
|
365
|
+
|
|
366
|
+
return bscript.compile([OPS.OP_HASH160, h, OPS.OP_EQUAL]) as Script;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
#computeInput(): Script | undefined {
|
|
370
|
+
if (this.#inputInput) {
|
|
371
|
+
return this.#inputInput as Script;
|
|
372
|
+
}
|
|
373
|
+
const r = this.#inputRedeem;
|
|
374
|
+
if (!r || !r.input || !r.output) {
|
|
375
|
+
return undefined;
|
|
376
|
+
}
|
|
377
|
+
return bscript.compile(([] as Stack).concat(bscript.decompile(r.input) as Stack, r.output)) as Script;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
#computeRedeem(): ScriptRedeem | undefined {
|
|
381
|
+
if (this.#inputRedeem) {
|
|
382
|
+
return this.#inputRedeem;
|
|
383
|
+
}
|
|
384
|
+
if (this.#inputInput) {
|
|
385
|
+
return this.#getDerivedRedeem();
|
|
386
|
+
}
|
|
387
|
+
return undefined;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
#computeWitness(): Uint8Array[] | undefined {
|
|
391
|
+
if (this.#inputWitness) {
|
|
392
|
+
return this.#inputWitness;
|
|
393
|
+
}
|
|
394
|
+
const r = this.redeem;
|
|
395
|
+
if (r && r.witness) {
|
|
396
|
+
return r.witness;
|
|
397
|
+
}
|
|
398
|
+
if (this.input) {
|
|
399
|
+
return [];
|
|
400
|
+
}
|
|
401
|
+
return undefined;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Validation
|
|
405
|
+
|
|
406
|
+
#checkRedeem(redeem: Payment): void {
|
|
407
|
+
// Is the redeem output empty/invalid?
|
|
408
|
+
if (redeem.output) {
|
|
409
|
+
const decompile = bscript.decompile(redeem.output);
|
|
410
|
+
if (!decompile || decompile.length < 1) {
|
|
411
|
+
throw new TypeError('Redeem.output too short');
|
|
412
|
+
}
|
|
413
|
+
if (redeem.output.byteLength > 520) {
|
|
414
|
+
throw new TypeError('Redeem.output unspendable if larger than 520 bytes');
|
|
415
|
+
}
|
|
416
|
+
if (bscript.countNonPushOnlyOPs(decompile) > 201) {
|
|
417
|
+
throw new TypeError('Redeem.output unspendable with more than 201 non-push ops');
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (redeem.input) {
|
|
422
|
+
const hasInput = redeem.input.length > 0;
|
|
423
|
+
const hasWitness = redeem.witness && redeem.witness.length > 0;
|
|
424
|
+
if (!hasInput && !hasWitness) {
|
|
425
|
+
throw new TypeError('Empty input');
|
|
426
|
+
}
|
|
427
|
+
if (hasInput && hasWitness) {
|
|
428
|
+
throw new TypeError('Input and witness provided');
|
|
429
|
+
}
|
|
430
|
+
if (hasInput) {
|
|
431
|
+
const richunks = bscript.decompile(redeem.input) as Stack;
|
|
432
|
+
if (!bscript.isPushOnly(richunks)) {
|
|
433
|
+
throw new TypeError('Non push-only scriptSig');
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
#validate(): void {
|
|
440
|
+
let hash: Uint8Array = new Uint8Array(0);
|
|
441
|
+
|
|
442
|
+
if (this.#inputAddress) {
|
|
443
|
+
const addr = this.#getDecodedAddress();
|
|
444
|
+
if (!addr) {
|
|
445
|
+
throw new TypeError('Invalid address');
|
|
446
|
+
}
|
|
447
|
+
if (addr.version !== this.#network.scriptHash) {
|
|
124
448
|
throw new TypeError('Invalid version or Network mismatch');
|
|
125
|
-
|
|
126
|
-
hash
|
|
449
|
+
}
|
|
450
|
+
if (addr.hash.length !== 20) {
|
|
451
|
+
throw new TypeError('Invalid address');
|
|
452
|
+
}
|
|
453
|
+
hash = addr.hash;
|
|
127
454
|
}
|
|
128
455
|
|
|
129
|
-
if (
|
|
130
|
-
if (hash.length > 0 && !
|
|
131
|
-
|
|
456
|
+
if (this.#inputHash) {
|
|
457
|
+
if (hash.length > 0 && !equals(hash, this.#inputHash)) {
|
|
458
|
+
throw new TypeError('Hash mismatch');
|
|
459
|
+
} else {
|
|
460
|
+
hash = this.#inputHash;
|
|
461
|
+
}
|
|
132
462
|
}
|
|
133
463
|
|
|
134
|
-
if (
|
|
464
|
+
if (this.#inputOutput) {
|
|
135
465
|
if (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
)
|
|
466
|
+
this.#inputOutput.length !== 23 ||
|
|
467
|
+
this.#inputOutput[0] !== OPS.OP_HASH160 ||
|
|
468
|
+
this.#inputOutput[1] !== 0x14 ||
|
|
469
|
+
this.#inputOutput[22] !== OPS.OP_EQUAL
|
|
470
|
+
) {
|
|
141
471
|
throw new TypeError('Output is invalid');
|
|
472
|
+
}
|
|
142
473
|
|
|
143
|
-
const hash2 =
|
|
144
|
-
if (hash.length > 0 && !
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
// inlined to prevent 'no-inner-declarations' failing
|
|
149
|
-
const checkRedeem = (redeem: Payment): void => {
|
|
150
|
-
// is the redeem output empty/invalid?
|
|
151
|
-
if (redeem.output) {
|
|
152
|
-
const decompile = bscript.decompile(redeem.output);
|
|
153
|
-
if (!decompile || decompile.length < 1)
|
|
154
|
-
throw new TypeError('Redeem.output too short');
|
|
155
|
-
if (redeem.output.byteLength > 520)
|
|
156
|
-
throw new TypeError('Redeem.output unspendable if larger than 520 bytes');
|
|
157
|
-
if (bscript.countNonPushOnlyOPs(decompile) > 201)
|
|
158
|
-
throw new TypeError(
|
|
159
|
-
'Redeem.output unspendable with more than 201 non-push ops',
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
// match hash against other sources
|
|
163
|
-
const hash2 = bcrypto.hash160(redeem.output);
|
|
164
|
-
if (hash.length > 0 && !hash.equals(hash2)) throw new TypeError('Hash mismatch');
|
|
165
|
-
else hash = hash2;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (redeem.input) {
|
|
169
|
-
const hasInput = redeem.input.length > 0;
|
|
170
|
-
const hasWitness = redeem.witness && redeem.witness.length > 0;
|
|
171
|
-
if (!hasInput && !hasWitness) throw new TypeError('Empty input');
|
|
172
|
-
if (hasInput && hasWitness) throw new TypeError('Input and witness provided');
|
|
173
|
-
if (hasInput) {
|
|
174
|
-
const richunks = bscript.decompile(redeem.input) as Stack;
|
|
175
|
-
if (!bscript.isPushOnly(richunks))
|
|
176
|
-
throw new TypeError('Non push-only scriptSig');
|
|
177
|
-
}
|
|
474
|
+
const hash2 = this.#inputOutput.subarray(2, 22);
|
|
475
|
+
if (hash.length > 0 && !equals(hash, hash2)) {
|
|
476
|
+
throw new TypeError('Hash mismatch');
|
|
477
|
+
} else {
|
|
478
|
+
hash = hash2;
|
|
178
479
|
}
|
|
179
|
-
}
|
|
480
|
+
}
|
|
180
481
|
|
|
181
|
-
if (
|
|
182
|
-
const chunks =
|
|
183
|
-
if (!chunks || chunks.length < 1)
|
|
184
|
-
|
|
482
|
+
if (this.#inputInput) {
|
|
483
|
+
const chunks = this.#getInputChunks();
|
|
484
|
+
if (!chunks || chunks.length < 1) {
|
|
485
|
+
throw new TypeError('Input too short');
|
|
486
|
+
}
|
|
487
|
+
const derived = this.#getDerivedRedeem();
|
|
488
|
+
if (!derived || !(derived.output instanceof Uint8Array)) {
|
|
489
|
+
throw new TypeError('Input is invalid');
|
|
490
|
+
}
|
|
185
491
|
|
|
186
|
-
checkRedeem(
|
|
492
|
+
this.#checkRedeem(derived);
|
|
493
|
+
|
|
494
|
+
// Match hash against redeem output
|
|
495
|
+
if (derived.output) {
|
|
496
|
+
const hash2 = bcrypto.hash160(derived.output);
|
|
497
|
+
if (hash.length > 0 && !equals(hash, hash2)) {
|
|
498
|
+
throw new TypeError('Hash mismatch');
|
|
499
|
+
} else {
|
|
500
|
+
hash = hash2;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
187
503
|
}
|
|
188
504
|
|
|
189
|
-
if (
|
|
190
|
-
if (
|
|
505
|
+
if (this.#inputRedeem) {
|
|
506
|
+
if (this.#inputRedeem.network && this.#inputRedeem.network !== this.#network) {
|
|
191
507
|
throw new TypeError('Network mismatch');
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
508
|
+
}
|
|
509
|
+
if (this.#inputInput) {
|
|
510
|
+
const derived = this.#getDerivedRedeem();
|
|
511
|
+
if (derived) {
|
|
512
|
+
if (
|
|
513
|
+
this.#inputRedeem.output &&
|
|
514
|
+
derived.output &&
|
|
515
|
+
!equals(this.#inputRedeem.output, derived.output)
|
|
516
|
+
) {
|
|
517
|
+
throw new TypeError('Redeem.output mismatch');
|
|
518
|
+
}
|
|
519
|
+
if (
|
|
520
|
+
this.#inputRedeem.input &&
|
|
521
|
+
derived.input &&
|
|
522
|
+
!equals(this.#inputRedeem.input, derived.input)
|
|
523
|
+
) {
|
|
524
|
+
throw new TypeError('Redeem.input mismatch');
|
|
525
|
+
}
|
|
526
|
+
}
|
|
198
527
|
}
|
|
199
528
|
|
|
200
|
-
checkRedeem(
|
|
529
|
+
this.#checkRedeem(this.#inputRedeem);
|
|
530
|
+
|
|
531
|
+
// Match hash against redeem output
|
|
532
|
+
if (this.#inputRedeem.output) {
|
|
533
|
+
const hash2 = bcrypto.hash160(this.#inputRedeem.output);
|
|
534
|
+
if (hash.length > 0 && !equals(hash, hash2)) {
|
|
535
|
+
throw new TypeError('Hash mismatch');
|
|
536
|
+
}
|
|
537
|
+
}
|
|
201
538
|
}
|
|
202
539
|
|
|
203
|
-
if (
|
|
204
|
-
if (
|
|
540
|
+
if (this.#inputWitness) {
|
|
541
|
+
if (
|
|
542
|
+
this.#inputRedeem &&
|
|
543
|
+
this.#inputRedeem.witness &&
|
|
544
|
+
!stacksEqual(this.#inputRedeem.witness, this.#inputWitness)
|
|
545
|
+
) {
|
|
205
546
|
throw new TypeError('Witness and redeem.witness mismatch');
|
|
547
|
+
}
|
|
206
548
|
}
|
|
207
549
|
}
|
|
208
550
|
|
|
209
|
-
|
|
551
|
+
/**
|
|
552
|
+
* Converts to a plain P2SHPayment object for backwards compatibility.
|
|
553
|
+
*
|
|
554
|
+
* @returns A P2SHPayment object
|
|
555
|
+
*/
|
|
556
|
+
toPayment(): P2SHPayment {
|
|
557
|
+
return {
|
|
558
|
+
name: this.name,
|
|
559
|
+
network: this.network,
|
|
560
|
+
address: this.address,
|
|
561
|
+
hash: this.hash,
|
|
562
|
+
output: this.output,
|
|
563
|
+
input: this.input,
|
|
564
|
+
redeem: this.redeem,
|
|
565
|
+
witness: this.witness,
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Creates a Pay-to-Script-Hash (P2SH) payment object.
|
|
572
|
+
*
|
|
573
|
+
* This is the legacy factory function for backwards compatibility.
|
|
574
|
+
* For new code, prefer using the P2SH class directly.
|
|
575
|
+
*
|
|
576
|
+
* @param a - The payment object containing the necessary data
|
|
577
|
+
* @param opts - Optional payment options
|
|
578
|
+
* @returns The P2SH payment object
|
|
579
|
+
* @throws {TypeError} If the required data is not provided or if the data is invalid
|
|
580
|
+
*
|
|
581
|
+
* @example
|
|
582
|
+
* ```typescript
|
|
583
|
+
* import { p2sh, p2ms } from '@btc-vision/bitcoin';
|
|
584
|
+
*
|
|
585
|
+
* // Wrap a multisig in P2SH
|
|
586
|
+
* const multisig = p2ms({ m: 2, pubkeys: [pk1, pk2, pk3] });
|
|
587
|
+
* const payment = p2sh({ redeem: multisig });
|
|
588
|
+
* ```
|
|
589
|
+
*/
|
|
590
|
+
export function p2sh(a: Omit<P2SHPayment, 'name'>, opts?: PaymentOpts): P2SHPayment {
|
|
591
|
+
if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) {
|
|
592
|
+
throw new TypeError('Not enough data');
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const instance = new P2SH(
|
|
596
|
+
{
|
|
597
|
+
address: a.address,
|
|
598
|
+
hash: a.hash,
|
|
599
|
+
output: a.output,
|
|
600
|
+
input: a.input,
|
|
601
|
+
redeem: a.redeem,
|
|
602
|
+
witness: a.witness,
|
|
603
|
+
network: a.network,
|
|
604
|
+
},
|
|
605
|
+
opts,
|
|
606
|
+
);
|
|
607
|
+
|
|
608
|
+
// Return a merged object for backwards compatibility
|
|
609
|
+
return Object.assign(instance.toPayment(), a);
|
|
210
610
|
}
|