@bsv/sdk 1.0.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/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- package/.github/ISSUE_TEMPLATE/discussion.md +24 -0
- package/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +23 -0
- package/CHANGELOG.md +72 -0
- package/CONTRIBUTING.md +85 -0
- package/LICENSE.txt +28 -0
- package/README.md +87 -0
- package/ROADMAP.md +3 -0
- package/dist/cjs/mod.js +25 -0
- package/dist/cjs/mod.js.map +1 -0
- package/dist/cjs/package.json +42 -0
- package/dist/cjs/src/compat/BIP39.js +272 -0
- package/dist/cjs/src/compat/BIP39.js.map +1 -0
- package/dist/cjs/src/compat/BSM.js +77 -0
- package/dist/cjs/src/compat/BSM.js.map +1 -0
- package/dist/cjs/src/compat/ECIES.js +483 -0
- package/dist/cjs/src/compat/ECIES.js.map +1 -0
- package/dist/cjs/src/compat/HD.js +326 -0
- package/dist/cjs/src/compat/HD.js.map +1 -0
- package/dist/cjs/src/compat/Mnemonic.js +298 -0
- package/dist/cjs/src/compat/Mnemonic.js.map +1 -0
- package/dist/cjs/src/compat/bip-39-wordlist-en.js +2057 -0
- package/dist/cjs/src/compat/bip-39-wordlist-en.js.map +1 -0
- package/dist/cjs/src/compat/index.js +37 -0
- package/dist/cjs/src/compat/index.js.map +1 -0
- package/dist/cjs/src/messages/EncryptedMessage.js +69 -0
- package/dist/cjs/src/messages/EncryptedMessage.js.map +1 -0
- package/dist/cjs/src/messages/SignedMessage.js +85 -0
- package/dist/cjs/src/messages/SignedMessage.js.map +1 -0
- package/dist/cjs/src/messages/index.js +29 -0
- package/dist/cjs/src/messages/index.js.map +1 -0
- package/dist/cjs/src/primitives/AESGCM.js +384 -0
- package/dist/cjs/src/primitives/AESGCM.js.map +1 -0
- package/dist/cjs/src/primitives/BasePoint.js +19 -0
- package/dist/cjs/src/primitives/BasePoint.js.map +1 -0
- package/dist/cjs/src/primitives/BigNumber.js +4269 -0
- package/dist/cjs/src/primitives/BigNumber.js.map +1 -0
- package/dist/cjs/src/primitives/Curve.js +1126 -0
- package/dist/cjs/src/primitives/Curve.js.map +1 -0
- package/dist/cjs/src/primitives/DRBG.js +99 -0
- package/dist/cjs/src/primitives/DRBG.js.map +1 -0
- package/dist/cjs/src/primitives/ECDSA.js +169 -0
- package/dist/cjs/src/primitives/ECDSA.js.map +1 -0
- package/dist/cjs/src/primitives/Hash.js +1332 -0
- package/dist/cjs/src/primitives/Hash.js.map +1 -0
- package/dist/cjs/src/primitives/JacobianPoint.js +400 -0
- package/dist/cjs/src/primitives/JacobianPoint.js.map +1 -0
- package/dist/cjs/src/primitives/K256.js +111 -0
- package/dist/cjs/src/primitives/K256.js.map +1 -0
- package/dist/cjs/src/primitives/Mersenne.js +118 -0
- package/dist/cjs/src/primitives/Mersenne.js.map +1 -0
- package/dist/cjs/src/primitives/MontgomoryMethod.js +150 -0
- package/dist/cjs/src/primitives/MontgomoryMethod.js.map +1 -0
- package/dist/cjs/src/primitives/Point.js +819 -0
- package/dist/cjs/src/primitives/Point.js.map +1 -0
- package/dist/cjs/src/primitives/PrivateKey.js +190 -0
- package/dist/cjs/src/primitives/PrivateKey.js.map +1 -0
- package/dist/cjs/src/primitives/PublicKey.js +151 -0
- package/dist/cjs/src/primitives/PublicKey.js.map +1 -0
- package/dist/cjs/src/primitives/Random.js +57 -0
- package/dist/cjs/src/primitives/Random.js.map +1 -0
- package/dist/cjs/src/primitives/ReductionContext.js +490 -0
- package/dist/cjs/src/primitives/ReductionContext.js.map +1 -0
- package/dist/cjs/src/primitives/Signature.js +220 -0
- package/dist/cjs/src/primitives/Signature.js.map +1 -0
- package/dist/cjs/src/primitives/SymmetricKey.js +69 -0
- package/dist/cjs/src/primitives/SymmetricKey.js.map +1 -0
- package/dist/cjs/src/primitives/TransactionSignature.js +172 -0
- package/dist/cjs/src/primitives/TransactionSignature.js.map +1 -0
- package/dist/cjs/src/primitives/index.js +45 -0
- package/dist/cjs/src/primitives/index.js.map +1 -0
- package/dist/cjs/src/primitives/utils.js +615 -0
- package/dist/cjs/src/primitives/utils.js.map +1 -0
- package/dist/cjs/src/script/LockingScript.js +35 -0
- package/dist/cjs/src/script/LockingScript.js.map +1 -0
- package/dist/cjs/src/script/OP.js +208 -0
- package/dist/cjs/src/script/OP.js.map +1 -0
- package/dist/cjs/src/script/Script.js +429 -0
- package/dist/cjs/src/script/Script.js.map +1 -0
- package/dist/cjs/src/script/ScriptChunk.js +3 -0
- package/dist/cjs/src/script/ScriptChunk.js.map +1 -0
- package/dist/cjs/src/script/ScriptTemplate.js +3 -0
- package/dist/cjs/src/script/ScriptTemplate.js.map +1 -0
- package/dist/cjs/src/script/Spend.js +1252 -0
- package/dist/cjs/src/script/Spend.js.map +1 -0
- package/dist/cjs/src/script/UnlockingScript.js +35 -0
- package/dist/cjs/src/script/UnlockingScript.js.map +1 -0
- package/dist/cjs/src/script/index.js +32 -0
- package/dist/cjs/src/script/index.js.map +1 -0
- package/dist/cjs/src/script/templates/P2PKH.js +98 -0
- package/dist/cjs/src/script/templates/P2PKH.js.map +1 -0
- package/dist/cjs/src/script/templates/RPuzzle.js +125 -0
- package/dist/cjs/src/script/templates/RPuzzle.js.map +1 -0
- package/dist/cjs/src/script/templates/index.js +11 -0
- package/dist/cjs/src/script/templates/index.js.map +1 -0
- package/dist/cjs/src/transaction/Broadcaster.js +3 -0
- package/dist/cjs/src/transaction/Broadcaster.js.map +1 -0
- package/dist/cjs/src/transaction/ChainTracker.js +3 -0
- package/dist/cjs/src/transaction/ChainTracker.js.map +1 -0
- package/dist/cjs/src/transaction/FeeModel.js +3 -0
- package/dist/cjs/src/transaction/FeeModel.js.map +1 -0
- package/dist/cjs/src/transaction/MerklePath.js +239 -0
- package/dist/cjs/src/transaction/MerklePath.js.map +1 -0
- package/dist/cjs/src/transaction/Transaction.js +557 -0
- package/dist/cjs/src/transaction/Transaction.js.map +1 -0
- package/dist/cjs/src/transaction/TransactionInput.js +3 -0
- package/dist/cjs/src/transaction/TransactionInput.js.map +1 -0
- package/dist/cjs/src/transaction/TransactionOutput.js +3 -0
- package/dist/cjs/src/transaction/TransactionOutput.js.map +1 -0
- package/dist/cjs/src/transaction/broadcasters/ARC.js +101 -0
- package/dist/cjs/src/transaction/broadcasters/ARC.js.map +1 -0
- package/dist/cjs/src/transaction/broadcasters/index.js +9 -0
- package/dist/cjs/src/transaction/broadcasters/index.js.map +1 -0
- package/dist/cjs/src/transaction/fee-models/SatoshisPerKilobyte.js +69 -0
- package/dist/cjs/src/transaction/fee-models/SatoshisPerKilobyte.js.map +1 -0
- package/dist/cjs/src/transaction/fee-models/index.js +9 -0
- package/dist/cjs/src/transaction/fee-models/index.js.map +1 -0
- package/dist/cjs/src/transaction/index.js +11 -0
- package/dist/cjs/src/transaction/index.js.map +1 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/esm/mod.js +9 -0
- package/dist/esm/mod.js.map +1 -0
- package/dist/esm/src/compat/BIP39.js +272 -0
- package/dist/esm/src/compat/BIP39.js.map +1 -0
- package/dist/esm/src/compat/BSM.js +45 -0
- package/dist/esm/src/compat/BSM.js.map +1 -0
- package/dist/esm/src/compat/ECIES.js +454 -0
- package/dist/esm/src/compat/ECIES.js.map +1 -0
- package/dist/esm/src/compat/HD.js +304 -0
- package/dist/esm/src/compat/HD.js.map +1 -0
- package/dist/esm/src/compat/Mnemonic.js +272 -0
- package/dist/esm/src/compat/Mnemonic.js.map +1 -0
- package/dist/esm/src/compat/bip-39-wordlist-en.js +2054 -0
- package/dist/esm/src/compat/bip-39-wordlist-en.js.map +1 -0
- package/dist/esm/src/compat/index.js +5 -0
- package/dist/esm/src/compat/index.js.map +1 -0
- package/dist/esm/src/messages/EncryptedMessage.js +61 -0
- package/dist/esm/src/messages/EncryptedMessage.js.map +1 -0
- package/dist/esm/src/messages/SignedMessage.js +77 -0
- package/dist/esm/src/messages/SignedMessage.js.map +1 -0
- package/dist/esm/src/messages/index.js +3 -0
- package/dist/esm/src/messages/index.js.map +1 -0
- package/dist/esm/src/primitives/AESGCM.js +371 -0
- package/dist/esm/src/primitives/AESGCM.js.map +1 -0
- package/dist/esm/src/primitives/BasePoint.js +16 -0
- package/dist/esm/src/primitives/BasePoint.js.map +1 -0
- package/dist/esm/src/primitives/BigNumber.js +4304 -0
- package/dist/esm/src/primitives/BigNumber.js.map +1 -0
- package/dist/esm/src/primitives/Curve.js +1141 -0
- package/dist/esm/src/primitives/Curve.js.map +1 -0
- package/dist/esm/src/primitives/DRBG.js +98 -0
- package/dist/esm/src/primitives/DRBG.js.map +1 -0
- package/dist/esm/src/primitives/ECDSA.js +161 -0
- package/dist/esm/src/primitives/ECDSA.js.map +1 -0
- package/dist/esm/src/primitives/Hash.js +1336 -0
- package/dist/esm/src/primitives/Hash.js.map +1 -0
- package/dist/esm/src/primitives/JacobianPoint.js +398 -0
- package/dist/esm/src/primitives/JacobianPoint.js.map +1 -0
- package/dist/esm/src/primitives/K256.js +105 -0
- package/dist/esm/src/primitives/K256.js.map +1 -0
- package/dist/esm/src/primitives/Mersenne.js +117 -0
- package/dist/esm/src/primitives/Mersenne.js.map +1 -0
- package/dist/esm/src/primitives/MontgomoryMethod.js +149 -0
- package/dist/esm/src/primitives/MontgomoryMethod.js.map +1 -0
- package/dist/esm/src/primitives/Point.js +816 -0
- package/dist/esm/src/primitives/Point.js.map +1 -0
- package/dist/esm/src/primitives/PrivateKey.js +184 -0
- package/dist/esm/src/primitives/PrivateKey.js.map +1 -0
- package/dist/esm/src/primitives/PublicKey.js +145 -0
- package/dist/esm/src/primitives/PublicKey.js.map +1 -0
- package/dist/esm/src/primitives/Random.js +56 -0
- package/dist/esm/src/primitives/Random.js.map +1 -0
- package/dist/esm/src/primitives/ReductionContext.js +486 -0
- package/dist/esm/src/primitives/ReductionContext.js.map +1 -0
- package/dist/esm/src/primitives/Signature.js +223 -0
- package/dist/esm/src/primitives/Signature.js.map +1 -0
- package/dist/esm/src/primitives/SymmetricKey.js +63 -0
- package/dist/esm/src/primitives/SymmetricKey.js.map +1 -0
- package/dist/esm/src/primitives/TransactionSignature.js +144 -0
- package/dist/esm/src/primitives/TransactionSignature.js.map +1 -0
- package/dist/esm/src/primitives/index.js +9 -0
- package/dist/esm/src/primitives/index.js.map +1 -0
- package/dist/esm/src/primitives/utils.js +601 -0
- package/dist/esm/src/primitives/utils.js.map +1 -0
- package/dist/esm/src/script/LockingScript.js +29 -0
- package/dist/esm/src/script/LockingScript.js.map +1 -0
- package/dist/esm/src/script/OP.js +206 -0
- package/dist/esm/src/script/OP.js.map +1 -0
- package/dist/esm/src/script/Script.js +424 -0
- package/dist/esm/src/script/Script.js.map +1 -0
- package/dist/esm/src/script/ScriptChunk.js +2 -0
- package/dist/esm/src/script/ScriptChunk.js.map +1 -0
- package/dist/esm/src/script/ScriptTemplate.js +2 -0
- package/dist/esm/src/script/ScriptTemplate.js.map +1 -0
- package/dist/esm/src/script/Spend.js +1240 -0
- package/dist/esm/src/script/Spend.js.map +1 -0
- package/dist/esm/src/script/UnlockingScript.js +29 -0
- package/dist/esm/src/script/UnlockingScript.js.map +1 -0
- package/dist/esm/src/script/index.js +7 -0
- package/dist/esm/src/script/index.js.map +1 -0
- package/dist/esm/src/script/templates/P2PKH.js +92 -0
- package/dist/esm/src/script/templates/P2PKH.js.map +1 -0
- package/dist/esm/src/script/templates/RPuzzle.js +119 -0
- package/dist/esm/src/script/templates/RPuzzle.js.map +1 -0
- package/dist/esm/src/script/templates/index.js +3 -0
- package/dist/esm/src/script/templates/index.js.map +1 -0
- package/dist/esm/src/transaction/Broadcaster.js +2 -0
- package/dist/esm/src/transaction/Broadcaster.js.map +1 -0
- package/dist/esm/src/transaction/ChainTracker.js +2 -0
- package/dist/esm/src/transaction/ChainTracker.js.map +1 -0
- package/dist/esm/src/transaction/FeeModel.js +2 -0
- package/dist/esm/src/transaction/FeeModel.js.map +1 -0
- package/dist/esm/src/transaction/MerklePath.js +237 -0
- package/dist/esm/src/transaction/MerklePath.js.map +1 -0
- package/dist/esm/src/transaction/Transaction.js +557 -0
- package/dist/esm/src/transaction/Transaction.js.map +1 -0
- package/dist/esm/src/transaction/TransactionInput.js +2 -0
- package/dist/esm/src/transaction/TransactionInput.js.map +1 -0
- package/dist/esm/src/transaction/TransactionOutput.js +2 -0
- package/dist/esm/src/transaction/TransactionOutput.js.map +1 -0
- package/dist/esm/src/transaction/broadcasters/ARC.js +100 -0
- package/dist/esm/src/transaction/broadcasters/ARC.js.map +1 -0
- package/dist/esm/src/transaction/broadcasters/index.js +2 -0
- package/dist/esm/src/transaction/broadcasters/index.js.map +1 -0
- package/dist/esm/src/transaction/fee-models/SatoshisPerKilobyte.js +71 -0
- package/dist/esm/src/transaction/fee-models/SatoshisPerKilobyte.js.map +1 -0
- package/dist/esm/src/transaction/fee-models/index.js +2 -0
- package/dist/esm/src/transaction/fee-models/index.js.map +1 -0
- package/dist/esm/src/transaction/index.js +3 -0
- package/dist/esm/src/transaction/index.js.map +1 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -0
- package/dist/types/mod.d.ts +9 -0
- package/dist/types/mod.d.ts.map +1 -0
- package/dist/types/src/compat/BIP39.d.ts +132 -0
- package/dist/types/src/compat/BIP39.d.ts.map +1 -0
- package/dist/types/src/compat/BSM.d.ts +28 -0
- package/dist/types/src/compat/BSM.d.ts.map +1 -0
- package/dist/types/src/compat/ECIES.d.ts +62 -0
- package/dist/types/src/compat/ECIES.d.ts.map +1 -0
- package/dist/types/src/compat/HD.d.ts +117 -0
- package/dist/types/src/compat/HD.d.ts.map +1 -0
- package/dist/types/src/compat/Mnemonic.d.ts +132 -0
- package/dist/types/src/compat/Mnemonic.d.ts.map +1 -0
- package/dist/types/src/compat/bip-39-wordlist-en.d.ts +5 -0
- package/dist/types/src/compat/bip-39-wordlist-en.d.ts.map +1 -0
- package/dist/types/src/compat/index.d.ts +5 -0
- package/dist/types/src/compat/index.d.ts.map +1 -0
- package/dist/types/src/messages/EncryptedMessage.d.ts +20 -0
- package/dist/types/src/messages/EncryptedMessage.d.ts.map +1 -0
- package/dist/types/src/messages/SignedMessage.d.ts +21 -0
- package/dist/types/src/messages/SignedMessage.d.ts.map +1 -0
- package/dist/types/src/messages/index.d.ts +3 -0
- package/dist/types/src/messages/index.d.ts.map +1 -0
- package/dist/types/src/primitives/AESGCM.d.ts +14 -0
- package/dist/types/src/primitives/AESGCM.d.ts.map +1 -0
- package/dist/types/src/primitives/BasePoint.d.ts +22 -0
- package/dist/types/src/primitives/BasePoint.d.ts.map +1 -0
- package/dist/types/src/primitives/BigNumber.d.ts +1895 -0
- package/dist/types/src/primitives/BigNumber.d.ts.map +1 -0
- package/dist/types/src/primitives/Curve.d.ts +55 -0
- package/dist/types/src/primitives/Curve.d.ts.map +1 -0
- package/dist/types/src/primitives/DRBG.d.ts +54 -0
- package/dist/types/src/primitives/DRBG.d.ts.map +1 -0
- package/dist/types/src/primitives/ECDSA.d.ts +39 -0
- package/dist/types/src/primitives/ECDSA.d.ts.map +1 -0
- package/dist/types/src/primitives/Hash.d.ts +411 -0
- package/dist/types/src/primitives/Hash.d.ts.map +1 -0
- package/dist/types/src/primitives/JacobianPoint.d.ts +164 -0
- package/dist/types/src/primitives/JacobianPoint.d.ts.map +1 -0
- package/dist/types/src/primitives/K256.d.ts +53 -0
- package/dist/types/src/primitives/K256.d.ts.map +1 -0
- package/dist/types/src/primitives/Mersenne.d.ts +72 -0
- package/dist/types/src/primitives/Mersenne.d.ts.map +1 -0
- package/dist/types/src/primitives/MontgomoryMethod.d.ts +96 -0
- package/dist/types/src/primitives/MontgomoryMethod.d.ts.map +1 -0
- package/dist/types/src/primitives/Point.d.ts +303 -0
- package/dist/types/src/primitives/Point.d.ts.map +1 -0
- package/dist/types/src/primitives/PrivateKey.d.ts +143 -0
- package/dist/types/src/primitives/PrivateKey.d.ts.map +1 -0
- package/dist/types/src/primitives/PublicKey.d.ts +108 -0
- package/dist/types/src/primitives/PublicKey.d.ts.map +1 -0
- package/dist/types/src/primitives/Random.d.ts +14 -0
- package/dist/types/src/primitives/Random.d.ts.map +1 -0
- package/dist/types/src/primitives/ReductionContext.d.ts +308 -0
- package/dist/types/src/primitives/ReductionContext.d.ts.map +1 -0
- package/dist/types/src/primitives/Signature.d.ts +100 -0
- package/dist/types/src/primitives/Signature.d.ts.map +1 -0
- package/dist/types/src/primitives/SymmetricKey.d.ts +44 -0
- package/dist/types/src/primitives/SymmetricKey.d.ts.map +1 -0
- package/dist/types/src/primitives/TransactionSignature.d.ts +36 -0
- package/dist/types/src/primitives/TransactionSignature.d.ts.map +1 -0
- package/dist/types/src/primitives/index.d.ts +9 -0
- package/dist/types/src/primitives/index.d.ts.map +1 -0
- package/dist/types/src/primitives/utils.d.ts +118 -0
- package/dist/types/src/primitives/utils.d.ts.map +1 -0
- package/dist/types/src/script/LockingScript.d.ts +25 -0
- package/dist/types/src/script/LockingScript.d.ts.map +1 -0
- package/dist/types/src/script/OP.d.ts +193 -0
- package/dist/types/src/script/OP.d.ts.map +1 -0
- package/dist/types/src/script/Script.d.ts +148 -0
- package/dist/types/src/script/Script.d.ts.map +1 -0
- package/dist/types/src/script/ScriptChunk.d.ts +8 -0
- package/dist/types/src/script/ScriptChunk.d.ts.map +1 -0
- package/dist/types/src/script/ScriptTemplate.d.ts +33 -0
- package/dist/types/src/script/ScriptTemplate.d.ts.map +1 -0
- package/dist/types/src/script/Spend.d.ts +103 -0
- package/dist/types/src/script/Spend.d.ts.map +1 -0
- package/dist/types/src/script/UnlockingScript.d.ts +25 -0
- package/dist/types/src/script/UnlockingScript.d.ts.map +1 -0
- package/dist/types/src/script/index.d.ts +8 -0
- package/dist/types/src/script/index.d.ts.map +1 -0
- package/dist/types/src/script/templates/P2PKH.d.ts +37 -0
- package/dist/types/src/script/templates/P2PKH.d.ts.map +1 -0
- package/dist/types/src/script/templates/RPuzzle.d.ts +47 -0
- package/dist/types/src/script/templates/RPuzzle.d.ts.map +1 -0
- package/dist/types/src/script/templates/index.d.ts +3 -0
- package/dist/types/src/script/templates/index.d.ts.map +1 -0
- package/dist/types/src/transaction/Broadcaster.d.ts +39 -0
- package/dist/types/src/transaction/Broadcaster.d.ts.map +1 -0
- package/dist/types/src/transaction/ChainTracker.d.ts +23 -0
- package/dist/types/src/transaction/ChainTracker.d.ts.map +1 -0
- package/dist/types/src/transaction/FeeModel.d.ts +12 -0
- package/dist/types/src/transaction/FeeModel.d.ts.map +1 -0
- package/dist/types/src/transaction/MerklePath.d.ts +91 -0
- package/dist/types/src/transaction/MerklePath.d.ts.map +1 -0
- package/dist/types/src/transaction/Transaction.d.ts +181 -0
- package/dist/types/src/transaction/Transaction.d.ts.map +1 -0
- package/dist/types/src/transaction/TransactionInput.d.ts +63 -0
- package/dist/types/src/transaction/TransactionInput.d.ts.map +1 -0
- package/dist/types/src/transaction/TransactionOutput.d.ts +36 -0
- package/dist/types/src/transaction/TransactionOutput.d.ts.map +1 -0
- package/dist/types/src/transaction/broadcasters/ARC.d.ts +28 -0
- package/dist/types/src/transaction/broadcasters/ARC.d.ts.map +1 -0
- package/dist/types/src/transaction/broadcasters/index.d.ts +2 -0
- package/dist/types/src/transaction/broadcasters/index.d.ts.map +1 -0
- package/dist/types/src/transaction/fee-models/SatoshisPerKilobyte.d.ts +26 -0
- package/dist/types/src/transaction/fee-models/SatoshisPerKilobyte.d.ts.map +1 -0
- package/dist/types/src/transaction/fee-models/index.d.ts +2 -0
- package/dist/types/src/transaction/fee-models/index.d.ts.map +1 -0
- package/dist/types/src/transaction/index.d.ts +7 -0
- package/dist/types/src/transaction/index.d.ts.map +1 -0
- package/dist/types/tsconfig.types.tsbuildinfo +1 -0
- package/docs/README.md +9 -0
- package/docs/compat.md +2856 -0
- package/docs/getting-started/COMMONJS.md +94 -0
- package/docs/getting-started/REACT-TS.md +131 -0
- package/docs/getting-started/TS-NODE.md +106 -0
- package/docs/getting-started/VUE.md +103 -0
- package/docs/messages.md +146 -0
- package/docs/primitives.md +7440 -0
- package/docs/script.md +766 -0
- package/docs/transaction.md +741 -0
- package/jest.config.js +6 -0
- package/mod.ts +8 -0
- package/package.json +137 -0
- package/src/compat/BSM.ts +51 -0
- package/src/compat/ECIES.ts +557 -0
- package/src/compat/HD.ts +348 -0
- package/src/compat/Mnemonic.ts +295 -0
- package/src/compat/__tests/BSM.test.ts +38 -0
- package/src/compat/__tests/ECIES.test.ts +90 -0
- package/src/compat/__tests/HD.test.ts +405 -0
- package/src/compat/__tests/Mnemonic.test.ts +177 -0
- package/src/compat/__tests/Mnemonic.vectors.ts +172 -0
- package/src/compat/bip-39-wordlist-en.ts +2053 -0
- package/src/compat/index.ts +4 -0
- package/src/messages/EncryptedMessage.ts +70 -0
- package/src/messages/SignedMessage.ts +87 -0
- package/src/messages/__tests/EncryptedMessage.test.ts +36 -0
- package/src/messages/__tests/SignedMessage.test.ts +53 -0
- package/src/messages/index.ts +2 -0
- package/src/primitives/AESGCM.ts +479 -0
- package/src/primitives/BasePoint.ts +21 -0
- package/src/primitives/BigNumber.ts +4619 -0
- package/src/primitives/Curve.ts +1163 -0
- package/src/primitives/DRBG.ts +102 -0
- package/src/primitives/ECDSA.ts +164 -0
- package/src/primitives/Hash.ts +1420 -0
- package/src/primitives/JacobianPoint.ts +410 -0
- package/src/primitives/K256.ts +116 -0
- package/src/primitives/Mersenne.ts +123 -0
- package/src/primitives/MontgomoryMethod.ts +160 -0
- package/src/primitives/Point.ts +852 -0
- package/src/primitives/PrivateKey.ts +195 -0
- package/src/primitives/PublicKey.ts +154 -0
- package/src/primitives/Random.ts +55 -0
- package/src/primitives/ReductionContext.ts +528 -0
- package/src/primitives/Signature.ts +235 -0
- package/src/primitives/SymmetricKey.ts +75 -0
- package/src/primitives/TransactionSignature.ts +189 -0
- package/src/primitives/__tests/AESGCM.test.ts +338 -0
- package/src/primitives/__tests/BRC42.private.vectors.ts +33 -0
- package/src/primitives/__tests/BRC42.public.vectors.ts +33 -0
- package/src/primitives/__tests/BigNumber.arithmatic.test.ts +572 -0
- package/src/primitives/__tests/BigNumber.binary.test.ts +203 -0
- package/src/primitives/__tests/BigNumber.constructor.test.ts +176 -0
- package/src/primitives/__tests/BigNumber.dhGroup.test.ts +18 -0
- package/src/primitives/__tests/BigNumber.fixtures.ts +264 -0
- package/src/primitives/__tests/BigNumber.serializers.test.ts +157 -0
- package/src/primitives/__tests/BigNumber.utils.test.ts +347 -0
- package/src/primitives/__tests/Curve.unit.test.ts +192 -0
- package/src/primitives/__tests/DRBG.test.ts +18 -0
- package/src/primitives/__tests/DRBG.vectors.ts +167 -0
- package/src/primitives/__tests/ECDH.test.ts +31 -0
- package/src/primitives/__tests/ECDSA.test.ts +58 -0
- package/src/primitives/__tests/HMAC.test.ts +59 -0
- package/src/primitives/__tests/Hash.test.ts +121 -0
- package/src/primitives/__tests/PBKDF2.vectors.ts +119 -0
- package/src/primitives/__tests/PrivateKey.test.ts +17 -0
- package/src/primitives/__tests/PublicKey.test.ts +66 -0
- package/src/primitives/__tests/Random.test.ts +14 -0
- package/src/primitives/__tests/Reader.test.ts +296 -0
- package/src/primitives/__tests/ReductionContext.test.ts +279 -0
- package/src/primitives/__tests/SymmetricKey.test.ts +58 -0
- package/src/primitives/__tests/SymmetricKey.vectors.ts +40 -0
- package/src/primitives/__tests/Writer.test.ts +198 -0
- package/src/primitives/__tests/sighash.vectors.ts +3503 -0
- package/src/primitives/__tests/utils.test.ts +108 -0
- package/src/primitives/index.ts +8 -0
- package/src/primitives/utils.ts +665 -0
- package/src/script/LockingScript.ts +30 -0
- package/src/script/OP.ts +219 -0
- package/src/script/Script.ts +426 -0
- package/src/script/ScriptChunk.ts +7 -0
- package/src/script/ScriptTemplate.ts +36 -0
- package/src/script/Spend.ts +1379 -0
- package/src/script/UnlockingScript.ts +30 -0
- package/src/script/__tests/Script.test.ts +369 -0
- package/src/script/__tests/Spend.test.ts +248 -0
- package/src/script/__tests/script.invalid.vectors.ts +925 -0
- package/src/script/__tests/script.valid.vectors.ts +1120 -0
- package/src/script/__tests/scriptFromVector.ts +42 -0
- package/src/script/__tests/spend.valid.vectors.ts +2288 -0
- package/src/script/index.ts +7 -0
- package/src/script/templates/P2PKH.ts +109 -0
- package/src/script/templates/RPuzzle.ts +140 -0
- package/src/script/templates/index.ts +2 -0
- package/src/transaction/Broadcaster.ts +42 -0
- package/src/transaction/ChainTracker.ts +22 -0
- package/src/transaction/FeeModel.ts +13 -0
- package/src/transaction/MerklePath.ts +259 -0
- package/src/transaction/Transaction.ts +602 -0
- package/src/transaction/TransactionInput.ts +63 -0
- package/src/transaction/TransactionOutput.ts +37 -0
- package/src/transaction/__tests/MerklePath.test.ts +181 -0
- package/src/transaction/__tests/Transaction.test.ts +413 -0
- package/src/transaction/__tests/bigtx.vectors.ts +4 -0
- package/src/transaction/__tests/bump.invalid.vectors.ts +8 -0
- package/src/transaction/__tests/bump.valid.vectors.ts +4 -0
- package/src/transaction/__tests/tx.invalid.vectors.ts +281 -0
- package/src/transaction/__tests/tx.valid.vectors.ts +364 -0
- package/src/transaction/broadcasters/ARC.ts +106 -0
- package/src/transaction/broadcasters/__tests/ARC.test.ts +115 -0
- package/src/transaction/broadcasters/index.ts +1 -0
- package/src/transaction/fee-models/SatoshisPerKilobyte.ts +71 -0
- package/src/transaction/fee-models/index.ts +1 -0
- package/src/transaction/index.ts +6 -0
- package/ts2md.json +5 -0
- package/tsconfig.base.json +26 -0
- package/tsconfig.cjs.json +11 -0
- package/tsconfig.eslint.json +12 -0
- package/tsconfig.esm.json +9 -0
- package/tsconfig.json +17 -0
- package/tsconfig.types.json +11 -0
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
import TransactionInput from './TransactionInput.js'
|
|
2
|
+
import TransactionOutput from './TransactionOutput.js'
|
|
3
|
+
import UnlockingScript from '../script/UnlockingScript.js'
|
|
4
|
+
import LockingScript from '../script/LockingScript.js'
|
|
5
|
+
import { Reader, Writer, toHex, toArray } from '../primitives/utils.js'
|
|
6
|
+
import { hash256 } from '../primitives/Hash.js'
|
|
7
|
+
import BigNumber from '../primitives/BigNumber.js'
|
|
8
|
+
import FeeModel from './FeeModel.js'
|
|
9
|
+
import SatoshisPerKilobyte from './fee-models/SatoshisPerKilobyte.js'
|
|
10
|
+
import { Broadcaster, BroadcastResponse, BroadcastFailure } from './Broadcaster.js'
|
|
11
|
+
import MerklePath from './MerklePath.js'
|
|
12
|
+
import Spend from '../script/Spend.js'
|
|
13
|
+
import ChainTracker from './ChainTracker.js'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Represents a complete Bitcoin transaction. This class encapsulates all the details
|
|
17
|
+
* required for creating, signing, and processing a Bitcoin transaction, including
|
|
18
|
+
* inputs, outputs, and various transaction-related methods.
|
|
19
|
+
*
|
|
20
|
+
* @class Transaction
|
|
21
|
+
* @property {number} version - The version number of the transaction. Used to specify
|
|
22
|
+
* which set of rules this transaction follows.
|
|
23
|
+
* @property {TransactionInput[]} inputs - An array of TransactionInput objects, representing
|
|
24
|
+
* the inputs for the transaction. Each input references a previous transaction's output.
|
|
25
|
+
* @property {TransactionOutput[]} outputs - An array of TransactionOutput objects, representing
|
|
26
|
+
* the outputs for the transaction. Each output specifies the amount of satoshis to be
|
|
27
|
+
* transferred and the conditions under which they can be spent.
|
|
28
|
+
* @property {number} lockTime - The lock time of the transaction. If non-zero, it specifies the
|
|
29
|
+
* earliest time or block height at which the transaction can be added to the block chain.
|
|
30
|
+
* @property {Record<string, any>} metadata - A key-value store for attaching additional data to
|
|
31
|
+
* the transaction object, not included in the transaction itself. Useful for adding descriptions, internal reference numbers, or other information.
|
|
32
|
+
* @property {MerkleProof} [merkleProof] - Optional. A merkle proof demonstrating the transaction's
|
|
33
|
+
* inclusion in a block. Useful for transaction verification using SPV.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // Creating a new transaction
|
|
37
|
+
* let tx = new Transaction();
|
|
38
|
+
* tx.addInput(...);
|
|
39
|
+
* tx.addOutput(...);
|
|
40
|
+
* await tx.fee();
|
|
41
|
+
* await tx.sign();
|
|
42
|
+
* await tx.broadcast();
|
|
43
|
+
*
|
|
44
|
+
* @description
|
|
45
|
+
* The Transaction class provides comprehensive
|
|
46
|
+
* functionality to handle various aspects of transaction creation, including
|
|
47
|
+
* adding inputs and outputs, computing fees, signing the transaction, and
|
|
48
|
+
* generating its binary or hexadecimal representation.
|
|
49
|
+
*/
|
|
50
|
+
export default class Transaction {
|
|
51
|
+
version: number
|
|
52
|
+
inputs: TransactionInput[]
|
|
53
|
+
outputs: TransactionOutput[]
|
|
54
|
+
lockTime: number
|
|
55
|
+
metadata: Record<string, any>
|
|
56
|
+
merklePath?: MerklePath
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Creates a new transaction, linked to its inputs and their associated merkle paths, from a BEEF (BRC-62) structure.
|
|
60
|
+
* @param beef A binary representation of a transaction in BEEF format.
|
|
61
|
+
* @returns An anchored transaction, linked to its associated inputs populated with merkle paths.
|
|
62
|
+
*/
|
|
63
|
+
static fromBEEF(beef: number[]): Transaction {
|
|
64
|
+
const reader = new Reader(beef)
|
|
65
|
+
// Read the version
|
|
66
|
+
const version = reader.readUInt32LE()
|
|
67
|
+
if (version !== 4022206465) {
|
|
68
|
+
throw new Error(`Invalid BEEF version. Expected 4022206465, received ${version}.`)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Read the BUMPs
|
|
72
|
+
const numberOfBUMPs = reader.readVarIntNum()
|
|
73
|
+
const BUMPs = []
|
|
74
|
+
for (let i = 0; i < numberOfBUMPs; i++) {
|
|
75
|
+
BUMPs.push(MerklePath.fromReader(reader))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Read all transactions into an object
|
|
79
|
+
// The object has keys of TXIDs and values of objects with transactions and BUMP indexes
|
|
80
|
+
const numberOfTransactions = reader.readVarIntNum()
|
|
81
|
+
const transactions: Record<string, { pathIndex?: number, tx: Transaction }> = {}
|
|
82
|
+
let lastTXID: string
|
|
83
|
+
for (let i = 0; i < numberOfTransactions; i++) {
|
|
84
|
+
const tx = Transaction.fromReader(reader)
|
|
85
|
+
const obj: { pathIndex?: number, tx: Transaction } = { tx }
|
|
86
|
+
const txid = tx.id('hex') as string
|
|
87
|
+
if (i + 1 === numberOfTransactions) { // The last tXID is stored for later
|
|
88
|
+
lastTXID = txid
|
|
89
|
+
}
|
|
90
|
+
const hasBump = Boolean(reader.readUInt8())
|
|
91
|
+
if (hasBump) {
|
|
92
|
+
obj.pathIndex = reader.readVarIntNum()
|
|
93
|
+
}
|
|
94
|
+
transactions[txid] = obj
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Recursive function for adding merkle proofs or input transactions
|
|
98
|
+
const addPathOrInputs = (obj: { pathIndex?: number, tx: Transaction }): void => {
|
|
99
|
+
if (typeof obj.pathIndex === 'number') {
|
|
100
|
+
const path = BUMPs[obj.pathIndex]
|
|
101
|
+
if (typeof path !== 'object') {
|
|
102
|
+
throw new Error('Invalid merkle path index found in BEEF!')
|
|
103
|
+
}
|
|
104
|
+
obj.tx.merklePath = path
|
|
105
|
+
} else {
|
|
106
|
+
for (let i = 0; i < obj.tx.inputs.length; i++) {
|
|
107
|
+
const input = obj.tx.inputs[i]
|
|
108
|
+
const sourceObj = transactions[input.sourceTXID]
|
|
109
|
+
if (typeof sourceObj !== 'object') {
|
|
110
|
+
throw new Error(`Reference to unknown TXID in BUMP: ${input.sourceTXID}`)
|
|
111
|
+
}
|
|
112
|
+
input.sourceTransaction = sourceObj.tx
|
|
113
|
+
addPathOrInputs(sourceObj)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Read the final transaction and Add inputs and merkle proofs to the final transaction, returning it
|
|
119
|
+
addPathOrInputs(transactions[lastTXID])
|
|
120
|
+
return transactions[lastTXID].tx
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private static fromReader(br: Reader): Transaction {
|
|
124
|
+
const version = br.readUInt32LE()
|
|
125
|
+
const inputsLength = br.readVarIntNum()
|
|
126
|
+
const inputs: TransactionInput[] = []
|
|
127
|
+
for (let i = 0; i < inputsLength; i++) {
|
|
128
|
+
const sourceTXID = toHex(br.readReverse(32))
|
|
129
|
+
const sourceOutputIndex = br.readUInt32LE()
|
|
130
|
+
const scriptLength = br.readVarIntNum()
|
|
131
|
+
const scriptBin = br.read(scriptLength)
|
|
132
|
+
const unlockingScript = UnlockingScript.fromBinary(scriptBin)
|
|
133
|
+
const sequence = br.readUInt32LE()
|
|
134
|
+
inputs.push({
|
|
135
|
+
sourceTXID,
|
|
136
|
+
sourceOutputIndex,
|
|
137
|
+
unlockingScript,
|
|
138
|
+
sequence
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
const outputsLength = br.readVarIntNum()
|
|
142
|
+
const outputs: TransactionOutput[] = []
|
|
143
|
+
for (let i = 0; i < outputsLength; i++) {
|
|
144
|
+
const satoshis = br.readUInt64LEBn().toNumber()
|
|
145
|
+
const scriptLength = br.readVarIntNum()
|
|
146
|
+
const scriptBin = br.read(scriptLength)
|
|
147
|
+
const lockingScript = LockingScript.fromBinary(scriptBin)
|
|
148
|
+
outputs.push({
|
|
149
|
+
satoshis,
|
|
150
|
+
lockingScript
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
const lockTime = br.readUInt32LE()
|
|
154
|
+
return new Transaction(version, inputs, outputs, lockTime)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Creates a Transaction instance from a binary array.
|
|
159
|
+
*
|
|
160
|
+
* @static
|
|
161
|
+
* @param {number[]} bin - The binary array representation of the transaction.
|
|
162
|
+
* @returns {Transaction} - A new Transaction instance.
|
|
163
|
+
*/
|
|
164
|
+
static fromBinary(bin: number[]): Transaction {
|
|
165
|
+
const br = new Reader(bin)
|
|
166
|
+
return Transaction.fromReader(br)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Creates a Transaction instance from a hexadecimal string.
|
|
171
|
+
*
|
|
172
|
+
* @static
|
|
173
|
+
* @param {string} hex - The hexadecimal string representation of the transaction.
|
|
174
|
+
* @returns {Transaction} - A new Transaction instance.
|
|
175
|
+
*/
|
|
176
|
+
static fromHex(hex: string): Transaction {
|
|
177
|
+
return Transaction.fromBinary(toArray(hex, 'hex'))
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Creates a Transaction instance from a hexadecimal string encoded BEEF.
|
|
182
|
+
*
|
|
183
|
+
* @static
|
|
184
|
+
* @param {string} hex - The hexadecimal string representation of the transaction BEEF.
|
|
185
|
+
* @returns {Transaction} - A new Transaction instance.
|
|
186
|
+
*/
|
|
187
|
+
static fromHexBEEF(hex: string): Transaction {
|
|
188
|
+
return Transaction.fromBEEF(toArray(hex, 'hex'))
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
constructor(
|
|
192
|
+
version: number = 1,
|
|
193
|
+
inputs: TransactionInput[] = [],
|
|
194
|
+
outputs: TransactionOutput[] = [],
|
|
195
|
+
lockTime: number = 0,
|
|
196
|
+
metadata: Record<string, any> = {},
|
|
197
|
+
merklePath?: MerklePath
|
|
198
|
+
) {
|
|
199
|
+
this.version = version
|
|
200
|
+
this.inputs = inputs
|
|
201
|
+
this.outputs = outputs
|
|
202
|
+
this.lockTime = lockTime
|
|
203
|
+
this.metadata = metadata
|
|
204
|
+
this.merklePath = merklePath
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Adds a new input to the transaction.
|
|
209
|
+
*
|
|
210
|
+
* @param {TransactionInput} input - The TransactionInput object to add to the transaction.
|
|
211
|
+
* @throws {Error} - If the input does not have a sourceTXID or sourceTransaction defined.
|
|
212
|
+
*/
|
|
213
|
+
addInput(input: TransactionInput): void {
|
|
214
|
+
if (
|
|
215
|
+
typeof input.sourceTXID === 'undefined' &&
|
|
216
|
+
typeof input.sourceTransaction === 'undefined'
|
|
217
|
+
) {
|
|
218
|
+
throw new Error('A reference to an an input transaction is required. If the input transaction itself cannot be referenced, its TXID must still be provided.')
|
|
219
|
+
}
|
|
220
|
+
// If the input sequence number hasn't been set, the expectation is that it is final.
|
|
221
|
+
if (typeof input.sequence === 'undefined') {
|
|
222
|
+
input.sequence = 0xFFFFFFFF
|
|
223
|
+
}
|
|
224
|
+
this.inputs.push(input)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Adds a new output to the transaction.
|
|
229
|
+
*
|
|
230
|
+
* @param {TransactionOutput} output - The TransactionOutput object to add to the transaction.
|
|
231
|
+
*/
|
|
232
|
+
addOutput(output: TransactionOutput): void {
|
|
233
|
+
this.outputs.push(output)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Updates the transaction's metadata.
|
|
238
|
+
*
|
|
239
|
+
* @param {Record<string, any>} metadata - The metadata object to merge into the existing metadata.
|
|
240
|
+
*/
|
|
241
|
+
updateMetadata(metadata: Record<string, any>): void {
|
|
242
|
+
this.metadata = {
|
|
243
|
+
...this.metadata,
|
|
244
|
+
...metadata
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Computes fees prior to signing.
|
|
250
|
+
* If no fee model is provided, uses a SatoshisPerKilobyte fee model that pays 10 sat/kb.
|
|
251
|
+
*
|
|
252
|
+
* @param model - The initialized fee model to use
|
|
253
|
+
* @param changeDistribution - Specifies how the change should be distributed
|
|
254
|
+
* amongst the change outputs
|
|
255
|
+
*
|
|
256
|
+
* TODO: Benford's law change distribution.
|
|
257
|
+
*/
|
|
258
|
+
async fee(model?: FeeModel, changeDistribution: 'equal' | 'random' = 'equal'): Promise<void> {
|
|
259
|
+
if (typeof model === 'undefined') {
|
|
260
|
+
model = new SatoshisPerKilobyte(10)
|
|
261
|
+
}
|
|
262
|
+
const fee = await model.computeFee(this)
|
|
263
|
+
// change = inputs - fee - non-change outputs
|
|
264
|
+
let change = 0
|
|
265
|
+
for (const input of this.inputs) {
|
|
266
|
+
if (typeof input.sourceTransaction !== 'object') {
|
|
267
|
+
throw new Error('Source transactions are required for all inputs during fee computation')
|
|
268
|
+
}
|
|
269
|
+
change += input.sourceTransaction.outputs[input.sourceOutputIndex].satoshis
|
|
270
|
+
}
|
|
271
|
+
change -= fee
|
|
272
|
+
let changeCount = 0
|
|
273
|
+
for (const out of this.outputs) {
|
|
274
|
+
if (!out.change) {
|
|
275
|
+
change -= out.satoshis
|
|
276
|
+
} else {
|
|
277
|
+
changeCount++
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (change <= changeCount) {
|
|
282
|
+
// There is not enough change to distribute among the change outputs.
|
|
283
|
+
// We'll remove all change outputs and leave the extra for the miners.
|
|
284
|
+
for (let i = 0; i < this.outputs.length; i++) {
|
|
285
|
+
if (this.outputs[i].change) {
|
|
286
|
+
this.outputs.splice(i, 1)
|
|
287
|
+
i--
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Distribute change among change outputs
|
|
294
|
+
if (changeDistribution === 'random') {
|
|
295
|
+
// TODO
|
|
296
|
+
throw new Error('Not yet implemented')
|
|
297
|
+
} else if (changeDistribution === 'equal') {
|
|
298
|
+
const perOutput = Math.floor(change / changeCount)
|
|
299
|
+
for (const out of this.outputs) {
|
|
300
|
+
if (out.change) {
|
|
301
|
+
out.satoshis = perOutput
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Signs a transaction, hydrating all its unlocking scripts based on the provided script templates where they are available.
|
|
309
|
+
*/
|
|
310
|
+
async sign(): Promise<void> {
|
|
311
|
+
for (const out of this.outputs) {
|
|
312
|
+
if (typeof out.satoshis === 'undefined') {
|
|
313
|
+
if (out.change) {
|
|
314
|
+
throw new Error('There are still change outputs with uncomputed amounts. Use the fee() method to compute the change amounts and transaction fees prior to signing.')
|
|
315
|
+
} else {
|
|
316
|
+
throw new Error('One or more transaction outputs is missing an amount. Ensure all output amounts are provided before signing.')
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
for (let i = 0, l = this.inputs.length; i < l; i++) {
|
|
321
|
+
if (typeof this.inputs[i].unlockingScriptTemplate === 'object') {
|
|
322
|
+
this.inputs[i].unlockingScript = await this.inputs[i]
|
|
323
|
+
.unlockingScriptTemplate
|
|
324
|
+
.sign(this, i)
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Broadcasts a transaction.
|
|
331
|
+
*
|
|
332
|
+
* @param broadcaster The Broadcaster instance wwhere the transaction will be sent
|
|
333
|
+
* @returns A BroadcastResponse or BroadcastFailure from the Broadcaster
|
|
334
|
+
*/
|
|
335
|
+
async broadcast(broadcaster: Broadcaster): Promise<BroadcastResponse | BroadcastFailure> {
|
|
336
|
+
return await broadcaster.broadcast(this)
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Converts the transaction to a binary array format.
|
|
341
|
+
*
|
|
342
|
+
* @returns {number[]} - The binary array representation of the transaction.
|
|
343
|
+
*/
|
|
344
|
+
toBinary(): number[] {
|
|
345
|
+
const writer = new Writer()
|
|
346
|
+
writer.writeUInt32LE(this.version)
|
|
347
|
+
writer.writeVarIntNum(this.inputs.length)
|
|
348
|
+
for (const i of this.inputs) {
|
|
349
|
+
if (typeof i.sourceTransaction !== 'undefined') {
|
|
350
|
+
writer.write(i.sourceTransaction.hash() as number[])
|
|
351
|
+
} else {
|
|
352
|
+
writer.writeReverse(toArray(i.sourceTXID, 'hex'))
|
|
353
|
+
}
|
|
354
|
+
writer.writeUInt32LE(i.sourceOutputIndex)
|
|
355
|
+
const scriptBin = i.unlockingScript.toBinary()
|
|
356
|
+
writer.writeVarIntNum(scriptBin.length)
|
|
357
|
+
writer.write(scriptBin)
|
|
358
|
+
writer.writeUInt32LE(i.sequence)
|
|
359
|
+
}
|
|
360
|
+
writer.writeVarIntNum(this.outputs.length)
|
|
361
|
+
for (const o of this.outputs) {
|
|
362
|
+
writer.writeUInt64LE(o.satoshis)
|
|
363
|
+
const scriptBin = o.lockingScript.toBinary()
|
|
364
|
+
writer.writeVarIntNum(scriptBin.length)
|
|
365
|
+
writer.write(scriptBin)
|
|
366
|
+
}
|
|
367
|
+
writer.writeUInt32LE(this.lockTime)
|
|
368
|
+
return writer.toArray()
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Converts the transaction to a BRC-30 EF format.
|
|
373
|
+
*
|
|
374
|
+
* @returns {number[]} - The BRC-30 EF representation of the transaction.
|
|
375
|
+
*/
|
|
376
|
+
toEF(): number[] {
|
|
377
|
+
const writer = new Writer()
|
|
378
|
+
writer.writeUInt32LE(this.version)
|
|
379
|
+
writer.write([0, 0, 0, 0, 0, 0xef])
|
|
380
|
+
writer.writeVarIntNum(this.inputs.length)
|
|
381
|
+
for (const i of this.inputs) {
|
|
382
|
+
if (typeof i.sourceTransaction === 'undefined') {
|
|
383
|
+
throw new Error('All inputs must have source transactions when serializing to EF format')
|
|
384
|
+
}
|
|
385
|
+
writer.write(i.sourceTransaction.hash() as number[])
|
|
386
|
+
writer.writeUInt32LE(i.sourceOutputIndex)
|
|
387
|
+
const scriptBin = i.unlockingScript.toBinary()
|
|
388
|
+
writer.writeVarIntNum(scriptBin.length)
|
|
389
|
+
writer.write(scriptBin)
|
|
390
|
+
writer.writeUInt32LE(i.sequence)
|
|
391
|
+
writer.writeUInt64LE(i.sourceTransaction.outputs[i.sourceOutputIndex].satoshis)
|
|
392
|
+
const lockingScriptBin = i.sourceTransaction.outputs[i.sourceOutputIndex].lockingScript.toBinary()
|
|
393
|
+
writer.writeVarIntNum(lockingScriptBin.length)
|
|
394
|
+
writer.write(lockingScriptBin)
|
|
395
|
+
}
|
|
396
|
+
writer.writeVarIntNum(this.outputs.length)
|
|
397
|
+
for (const o of this.outputs) {
|
|
398
|
+
writer.writeUInt64LE(o.satoshis)
|
|
399
|
+
const scriptBin = o.lockingScript.toBinary()
|
|
400
|
+
writer.writeVarIntNum(scriptBin.length)
|
|
401
|
+
writer.write(scriptBin)
|
|
402
|
+
}
|
|
403
|
+
writer.writeUInt32LE(this.lockTime)
|
|
404
|
+
return writer.toArray()
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Converts the transaction to a hexadecimal string EF.
|
|
409
|
+
*
|
|
410
|
+
* @returns {string} - The hexadecimal string representation of the transaction EF.
|
|
411
|
+
*/
|
|
412
|
+
toHexEF(): string {
|
|
413
|
+
return toHex(this.toEF())
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Converts the transaction to a hexadecimal string format.
|
|
418
|
+
*
|
|
419
|
+
* @returns {string} - The hexadecimal string representation of the transaction.
|
|
420
|
+
*/
|
|
421
|
+
toHex(): string {
|
|
422
|
+
return toHex(this.toBinary())
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Converts the transaction to a hexadecimal string BEEF.
|
|
427
|
+
*
|
|
428
|
+
* @returns {string} - The hexadecimal string representation of the transaction BEEF.
|
|
429
|
+
*/
|
|
430
|
+
toHexBEEF(): string {
|
|
431
|
+
return toHex(this.toBEEF())
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Calculates the transaction's hash.
|
|
436
|
+
*
|
|
437
|
+
* @param {'hex' | undefined} enc - The encoding to use for the hash. If 'hex', returns a hexadecimal string; otherwise returns a binary array.
|
|
438
|
+
* @returns {string | number[]} - The hash of the transaction in the specified format.
|
|
439
|
+
*/
|
|
440
|
+
hash(enc?: 'hex'): number[] | string {
|
|
441
|
+
return hash256(this.toBinary(), enc)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Calculates the transaction's ID.
|
|
446
|
+
*
|
|
447
|
+
* @param {'hex' | undefined} enc - The encoding to use for the ID. If 'hex', returns a hexadecimal string; otherwise returns a binary array.
|
|
448
|
+
* @returns {string | number[]} - The ID of the transaction in the specified format.
|
|
449
|
+
*/
|
|
450
|
+
id(enc?: 'hex'): number[] | string {
|
|
451
|
+
const id = hash256(this.toBinary()) as number[]
|
|
452
|
+
id.reverse()
|
|
453
|
+
if (enc === 'hex') {
|
|
454
|
+
return toHex(id)
|
|
455
|
+
}
|
|
456
|
+
return id
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Verifies the legitimacy of the Bitcoin transaction according to the rules of SPV by ensuring all the input transactions link back to valid block headers, the chain of spends for all inputs are valid, and the sum of inputs is not less than the sum of outputs.
|
|
461
|
+
*
|
|
462
|
+
* @param chainTracker - An instance of ChainTracker, a Bitcoin block header tracker. If the value is set to 'scripts only', headers will not be verified.
|
|
463
|
+
*
|
|
464
|
+
* @returns Whether the transaction is valid according to the rules of SPV.
|
|
465
|
+
*/
|
|
466
|
+
async verify(chainTracker: ChainTracker | 'scripts only'): Promise<boolean> {
|
|
467
|
+
// If the transaction has a valid merkle path, verification is complete.
|
|
468
|
+
if (typeof this.merklePath === 'object' && chainTracker !== 'scripts only') {
|
|
469
|
+
const proofValid = await this.merklePath.verify(
|
|
470
|
+
this.id('hex') as string,
|
|
471
|
+
chainTracker
|
|
472
|
+
)
|
|
473
|
+
// Note that if the proof is provided but not valid, the transaction could still be verified by proving all inputs (if they are available) and checking the associated spends.
|
|
474
|
+
if (proofValid) {
|
|
475
|
+
return true
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Verify each input transaction and evaluate the spend events.
|
|
480
|
+
// Also, keep a total of the input amounts for later.
|
|
481
|
+
let inputTotal = 0
|
|
482
|
+
for (let i = 0; i < this.inputs.length; i++) {
|
|
483
|
+
const input = this.inputs[i]
|
|
484
|
+
if (typeof input.sourceTransaction !== 'object') {
|
|
485
|
+
throw new Error(`Verification failed because the input at index ${i} of transaction ${this.id('hex') as string} is missing an associated source transaction. This source transaction is required for transaction verification because there is no merkle proof for the transaction spending a UTXO it contains.`)
|
|
486
|
+
}
|
|
487
|
+
if (typeof input.unlockingScript !== 'object') {
|
|
488
|
+
throw new Error(`Verification failed because the input at index ${i} of transaction ${this.id('hex') as string} is missing an associated unlocking script. This script is required for transaction verification because there is no merkle proof for the transaction spending the UTXO.`)
|
|
489
|
+
}
|
|
490
|
+
const sourceOutput = input.sourceTransaction.outputs[input.sourceOutputIndex]
|
|
491
|
+
inputTotal += sourceOutput.satoshis
|
|
492
|
+
const inputVerified = await input.sourceTransaction.verify(chainTracker)
|
|
493
|
+
if (!inputVerified) {
|
|
494
|
+
return false
|
|
495
|
+
}
|
|
496
|
+
const otherInputs = [...this.inputs]
|
|
497
|
+
otherInputs.splice(i, 1)
|
|
498
|
+
const spend = new Spend({
|
|
499
|
+
sourceTXID: input.sourceTransaction.id('hex') as string,
|
|
500
|
+
sourceOutputIndex: input.sourceOutputIndex,
|
|
501
|
+
lockingScript: sourceOutput.lockingScript,
|
|
502
|
+
sourceSatoshis: sourceOutput.satoshis,
|
|
503
|
+
transactionVersion: this.version,
|
|
504
|
+
otherInputs,
|
|
505
|
+
unlockingScript: input.unlockingScript,
|
|
506
|
+
inputSequence: input.sequence,
|
|
507
|
+
inputIndex: i,
|
|
508
|
+
outputs: this.outputs,
|
|
509
|
+
lockTime: this.lockTime
|
|
510
|
+
})
|
|
511
|
+
const spendValid = spend.validate()
|
|
512
|
+
if (!spendValid) {
|
|
513
|
+
return false
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Total the outputs to ensure they don't amount to more than the inputs
|
|
518
|
+
let outputTotal = 0
|
|
519
|
+
for (const out of this.outputs) {
|
|
520
|
+
if (typeof out.satoshis !== 'number') {
|
|
521
|
+
throw new Error('Every output must have a defined amount during transaction verification.')
|
|
522
|
+
}
|
|
523
|
+
outputTotal += out.satoshis
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return outputTotal <= inputTotal
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Serializes this transaction, together with its inputs and the respective merkle proofs, into the BEEF (BRC-62) format. This enables efficient verification of its compliance with the rules of SPV.
|
|
531
|
+
*
|
|
532
|
+
* @returns The serialized BEEF structure
|
|
533
|
+
*/
|
|
534
|
+
toBEEF(): number[] {
|
|
535
|
+
const writer = new Writer()
|
|
536
|
+
writer.writeUInt32LE(4022206465)
|
|
537
|
+
const BUMPs: MerklePath[] = []
|
|
538
|
+
const txs: Array<{ tx: Transaction, pathIndex?: number }> = []
|
|
539
|
+
|
|
540
|
+
// Recursive function to add paths and input transactions for a TX
|
|
541
|
+
const addPathsAndInputs = (tx: Transaction): void => {
|
|
542
|
+
const obj: { tx: Transaction, pathIndex?: number } = { tx }
|
|
543
|
+
const hasProof = typeof tx.merklePath === 'object'
|
|
544
|
+
if (hasProof) {
|
|
545
|
+
let added = false
|
|
546
|
+
// If this proof is identical to another one previously added, we use that first. Otherwise, we try to merge it with proofs from the same block.
|
|
547
|
+
for (let i = 0; i < BUMPs.length; i++) {
|
|
548
|
+
if (BUMPs[i] === tx.merklePath) { // Literally the same
|
|
549
|
+
obj.pathIndex = i
|
|
550
|
+
added = true
|
|
551
|
+
break
|
|
552
|
+
}
|
|
553
|
+
if (BUMPs[i].blockHeight === tx.merklePath.blockHeight) {
|
|
554
|
+
// Probably the same...
|
|
555
|
+
const rootA = BUMPs[i].computeRoot()
|
|
556
|
+
const rootB = tx.merklePath.computeRoot()
|
|
557
|
+
if (rootA === rootB) {
|
|
558
|
+
// Definitely the same... combine them to save space
|
|
559
|
+
BUMPs[i].combine(tx.merklePath)
|
|
560
|
+
obj.pathIndex = i
|
|
561
|
+
added = true
|
|
562
|
+
break
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
// Finally, if the proof is not yet added, add a new path.
|
|
567
|
+
if (!added) {
|
|
568
|
+
obj.pathIndex = BUMPs.length
|
|
569
|
+
BUMPs.push(tx.merklePath)
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
txs.unshift(obj)
|
|
573
|
+
if (!hasProof) {
|
|
574
|
+
for (let i = 0; i < tx.inputs.length; i++) {
|
|
575
|
+
const input = tx.inputs[i]
|
|
576
|
+
if (typeof input.sourceTransaction !== 'object') {
|
|
577
|
+
throw new Error('A required source transaction is missing!')
|
|
578
|
+
}
|
|
579
|
+
addPathsAndInputs(input.sourceTransaction)
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
addPathsAndInputs(this)
|
|
585
|
+
|
|
586
|
+
writer.writeVarIntNum(BUMPs.length)
|
|
587
|
+
for (const b of BUMPs) {
|
|
588
|
+
writer.write(b.toBinary())
|
|
589
|
+
}
|
|
590
|
+
writer.writeVarIntNum(txs.length)
|
|
591
|
+
for (const t of txs) {
|
|
592
|
+
writer.write(t.tx.toBinary())
|
|
593
|
+
if (typeof t.pathIndex === 'number') {
|
|
594
|
+
writer.writeUInt8(1)
|
|
595
|
+
writer.writeVarIntNum(t.pathIndex)
|
|
596
|
+
} else {
|
|
597
|
+
writer.writeUInt8(0)
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return writer.toArray()
|
|
601
|
+
}
|
|
602
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import UnlockingScript from '../script/UnlockingScript.js'
|
|
2
|
+
import Transaction from './Transaction.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents an input to a Bitcoin transaction.
|
|
6
|
+
* This interface defines the structure and components required to construct
|
|
7
|
+
* a transaction input in the Bitcoin blockchain.
|
|
8
|
+
*
|
|
9
|
+
* @interface TransactionInput
|
|
10
|
+
* @property {Transaction} [sourceTransaction] - Optional. The source transaction
|
|
11
|
+
* from which this input is derived. This is the transaction whose output
|
|
12
|
+
* is being spent by this input. Preferably provided if available.
|
|
13
|
+
* @property {string} [sourceTXID] - Optional. The transaction ID (TXID) of the source
|
|
14
|
+
* transaction. Required if the source transaction itself is not provided.
|
|
15
|
+
* This uniquely identifies the transaction within the blockchain.
|
|
16
|
+
* @property {number} sourceOutputIndex - The index of the output in the source transaction
|
|
17
|
+
* that this input is spending. It is zero-based, indicating the position of the
|
|
18
|
+
* output in the array of outputs of the source transaction.
|
|
19
|
+
* @property {UnlockingScript} [unlockingScript] - Optional. The script that 'unlocks' the
|
|
20
|
+
* source output for spending. This script typically contains signatures and
|
|
21
|
+
* public keys that evidence the ownership of the output.
|
|
22
|
+
* @property {Object} [unlockingScriptTemplate] - Optional. A template for generating the
|
|
23
|
+
* unlocking script. Useful when the unlocking script needs to be generated
|
|
24
|
+
* dynamically.
|
|
25
|
+
* @property {Function} unlockingScriptTemplate.sign - A function that, when given the
|
|
26
|
+
* current transaction and the index of this input, returns a Promise that
|
|
27
|
+
* resolves to the UnlockingScript.
|
|
28
|
+
* @property {Function} unlockingScriptTemplate.estimateLength - A function that estimates
|
|
29
|
+
* the length of the unlocking script, given the transaction and the input index.
|
|
30
|
+
* @property {number} sequence - A sequence number for the input. Used to enable
|
|
31
|
+
* updates to this input. If set to a non-final value (less than 0xFFFFFFFF),
|
|
32
|
+
* it indicates that the input may be replaced in the future.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Creating a simple transaction input
|
|
36
|
+
* let txInput = {
|
|
37
|
+
* sourceTXID: '123abc...',
|
|
38
|
+
* sourceOutputIndex: 0,
|
|
39
|
+
* sequence: 0xFFFFFFFF
|
|
40
|
+
* };
|
|
41
|
+
*
|
|
42
|
+
* // Using an unlocking script template
|
|
43
|
+
* txInput.unlockingScriptTemplate = {
|
|
44
|
+
* sign: async (tx, index) => { ... },
|
|
45
|
+
* estimateLength: async (tx, index) => { ... }
|
|
46
|
+
* };
|
|
47
|
+
*
|
|
48
|
+
* @description
|
|
49
|
+
* This interface links an input to a
|
|
50
|
+
* previous output and provides mechanisms (through unlocking scripts) to authorize the
|
|
51
|
+
* spending of that output.
|
|
52
|
+
*/
|
|
53
|
+
export default interface TransactionInput {
|
|
54
|
+
sourceTransaction?: Transaction
|
|
55
|
+
sourceTXID?: string
|
|
56
|
+
sourceOutputIndex: number
|
|
57
|
+
unlockingScript?: UnlockingScript
|
|
58
|
+
unlockingScriptTemplate?: {
|
|
59
|
+
sign: (tx: Transaction, inputIndex: number) => Promise<UnlockingScript>
|
|
60
|
+
estimateLength: (tx: Transaction, inputIndex: number) => Promise<number>
|
|
61
|
+
}
|
|
62
|
+
sequence: number
|
|
63
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import BigNumber from '../primitives/BigNumber.js'
|
|
2
|
+
import LockingScript from '../script/LockingScript.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Represents an output in a Bitcoin transaction.
|
|
6
|
+
* This interface defines the structure and components necessary to construct
|
|
7
|
+
* a transaction output, which secures owned Bitcoins to be unlocked later.
|
|
8
|
+
*
|
|
9
|
+
* @interface TransactionOutput
|
|
10
|
+
* @property {number} [satoshis] - Optional. The amount of satoshis (the smallest unit of Bitcoin) to be transferred by this output.
|
|
11
|
+
* @property {LockingScript} lockingScript - The script that 'locks' the satoshis,
|
|
12
|
+
* specifying the conditions under which they can be spent. This script is
|
|
13
|
+
* essential for securing the funds and typically contains cryptographic
|
|
14
|
+
* puzzles that need to be solved to spend the output.
|
|
15
|
+
* @property {boolean} [change] - Optional. A flag that indicates whether this output
|
|
16
|
+
* is a change output. If true, it means this output is returning funds back
|
|
17
|
+
* to the sender, usually as the 'change' from the transaction inputs.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Creating a simple transaction output
|
|
21
|
+
* let txOutput = {
|
|
22
|
+
* satoshis: 1000,
|
|
23
|
+
* lockingScript: LockingScript.fromASM('OP_DUP OP_HASH160 ... OP_EQUALVERIFY OP_CHECKSIG'),
|
|
24
|
+
* change: false
|
|
25
|
+
* };
|
|
26
|
+
*
|
|
27
|
+
* @description
|
|
28
|
+
* The TransactionOutput interface defines how bitcoins are to be distributed in a transaction, either to a recipient or
|
|
29
|
+
* back to the sender as change. The lockingScript is critical as it determines the conditions
|
|
30
|
+
* under which the output can be spent, typically requiring a digital signature matching the
|
|
31
|
+
* intended recipient's public key.
|
|
32
|
+
*/
|
|
33
|
+
export default interface TransactionOutput {
|
|
34
|
+
satoshis?: number
|
|
35
|
+
lockingScript: LockingScript
|
|
36
|
+
change?: boolean
|
|
37
|
+
}
|