├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json ├── src ├── address.js ├── block.js ├── bufferutils.js ├── classify.js ├── crypto.js ├── ecpair.js ├── index.js ├── networks.js ├── payments │ ├── embed.js │ ├── index.js │ ├── lazy.js │ ├── p2ms.js │ ├── p2pk.js │ ├── p2pkh.js │ ├── p2sh.js │ ├── p2wpkh.js │ └── p2wsh.js ├── script.js ├── script_number.js ├── script_signature.js ├── templates │ ├── multisig │ │ ├── index.js │ │ ├── input.js │ │ └── output.js │ ├── nulldata.js │ ├── pubkey │ │ ├── index.js │ │ ├── input.js │ │ └── output.js │ ├── pubkeyhash │ │ ├── index.js │ │ ├── input.js │ │ └── output.js │ ├── scripthash │ │ ├── index.js │ │ ├── input.js │ │ └── output.js │ ├── witnesscommitment │ │ ├── index.js │ │ └── output.js │ ├── witnesspubkeyhash │ │ ├── index.js │ │ ├── input.js │ │ └── output.js │ └── witnessscripthash │ │ ├── index.js │ │ ├── input.js │ │ └── output.js ├── transaction.js ├── transaction_builder.js └── types.js └── types ├── address.d.ts ├── block.d.ts ├── bufferutils.d.ts ├── classify.d.ts ├── crypto.d.ts ├── ecpair.d.ts ├── index.d.ts ├── networks.d.ts ├── payments ├── embed.d.ts ├── index.d.ts ├── lazy.d.ts ├── p2ms.d.ts ├── p2pk.d.ts ├── p2pkh.d.ts ├── p2sh.d.ts ├── p2wpkh.d.ts └── p2wsh.d.ts ├── script.d.ts ├── script_number.d.ts ├── script_signature.d.ts ├── templates ├── multisig │ ├── index.d.ts │ ├── input.d.ts │ └── output.d.ts ├── nulldata.d.ts ├── pubkey │ ├── index.d.ts │ ├── input.d.ts │ └── output.d.ts ├── pubkeyhash │ ├── index.d.ts │ ├── input.d.ts │ └── output.d.ts ├── scripthash │ ├── index.d.ts │ ├── input.d.ts │ └── output.d.ts ├── witnesscommitment │ ├── index.d.ts │ └── output.d.ts ├── witnesspubkeyhash │ ├── index.d.ts │ ├── input.d.ts │ └── output.d.ts └── witnessscripthash │ ├── index.d.ts │ ├── input.d.ts │ └── output.d.ts ├── transaction.d.ts ├── transaction_builder.d.ts └── types.d.ts /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 5.0.4 2 | __added__ 3 | - low R value support for ECPair, bip32, and TransactionBuilder (default off) via `txb.setLowR()` (#1385) 4 | 5 | __fixed__ 6 | - Fixed Various TypeScript types that have been pushed out since v5.0.0 (#1388) 7 | 8 | # 5.0.0 9 | __added__ 10 | - TypeScript support (#1319) 11 | - `Block.prototype.checkTxRoots` will check the merkleRoot and witnessCommit if it exists against the transactions array. (e52abec) (0426c66) 12 | 13 | __changed__ 14 | - `Transaction.prototype.getHash` now has `forWitness?: boolean` which when true returns the hash for wtxid (a652d04) 15 | - `Block.calculateMerkleRoot` now has `forWitness?: boolean` which when true returns the witness commit (a652d04) 16 | 17 | __removed__ 18 | - `Block.prototype.checkMerkleRoot` was removed, please use `checkTxRoots` (0426c66) 19 | 20 | # 4.0.5 21 | __fixed__ 22 | - Fixed bug where Angular apps break due to lack of crypto at build time. Reverted #1373 and added (6bead5d). 23 | 24 | # 4.0.4 25 | __fixed__ 26 | - Fixed bug where Electron v4 breaks due to lack of `'rmd160'` alias for ripemd160 hash. (#1373) 27 | 28 | # 4.0.3 29 | __fixed__ 30 | - Fixed `TransactionBuilder` to require that the Transaction has outputs before signing (#1151) 31 | - Fixed `payments.p2sh`, which now takes the network from the redeem attribute if one is not given in the object argument (#1232) 32 | - Fixed `Block.calculateTarget` to allow for exponents up to 29 (#1285) 33 | - Fixed some low priority rarely occurring bugs with multisig payments and `TransactionBuilder` multisig processing (#1307) 34 | 35 | __added__ 36 | - Regtest network object to `networks` (#1261) 37 | 38 | # 4.0.2 39 | __fixed__ 40 | - Fixed `TransactionBuilder` not throwing when payment type validation should fail (#1195) 41 | 42 | __removed__ 43 | - Removed rogue `package.json` from `src/payments` (#1216) 44 | 45 | # 4.0.1 46 | __fixed__ 47 | - Fixed `tiny-secp256k1` dependency version (used `ecurve`) (#1139) 48 | - Fixed `TransactionBuilder` throwing when trying to sign `P2WSH(P2WPKH)` (#1135) 49 | 50 | # 4.0.0 51 | __added__ 52 | - Added [`bip32`](https://github.com/bitcoinjs/bip32) dependency as a primary export (#1073) 53 | - Added `ECPair.fromPrivateKey` (#1070) 54 | - Added `payments` export, with support for `p2pkh`, `p2pk`, `p2ms`, `p2sh`, `p2wpkh`, `p2wsh` and `embed` payment types (#1096, #1119) 55 | - Added `script.signature.encode/decode` for script signatures (#459) 56 | 57 | __changed__ 58 | - `ECPair.prototype.sign` now returns a 64-byte signature `Buffer`, not an `ECSignature` object (#1084) 59 | - `ECPair` (and all ECDSA code) now uses [`tiny-secp256k1`](https://github.com/bitcoinjs/tiny-secp256k1), which uses the [`libsecp256k1` library](https://github.com/bitcoin-core/secp256k1) (#1070) 60 | - `TransactionBuilder` internal variables are now `__` prefixed to discourage public usage (#1038) 61 | - `TransactionBuilder` now defaults to version 2 transaction versions (#1036) 62 | - `script.decompile` now returns `[Buffer]` or `null`, if decompilation failed (#1039) 63 | 64 | __fixed__ 65 | - Fixed `TransactionBuilder` rejecting uncompressed public keys to comply with BIP143 (#987) 66 | 67 | __removed__ 68 | - Removed Node 4/5 LTS support (#1080) 69 | - Removed `ECPair.fromPublicKeyBuffer`, use `ECPair.fromPublicKey` (#1070) 70 | - Removed `ECPair.prototype.getAddress`, use `payments.p2pkh` instead (#1085) 71 | - Removed `ECPair.prototype.getPrivateKey`, use `ECPair.prototype.privateKey` property (#1070) 72 | - Removed `ECPair.prototype.getPublicKey`, use `ECPair.prototype.publicKey` property (#1070) 73 | - Removed `ECPair.prototype.getNetwork`, use `ECPair.prototype.network` property (#1070) 74 | - Removed `ECSignature`, use `script.signature.encode/decode` instead (#459) 75 | - Removed `HDNode`, use `bip32` export instead (#1073) 76 | - Removed `bufferutils` (#1035) 77 | - Removed `networks.litecoin`, BYO non-Bitcoin networks instead (#1095) 78 | - Removed `script.isCanonicalSignature`, use `script.isCanonicalScriptSignature` instead (#1094) 79 | - Removed `script.*.input/output/check` functions (`templates`), use `payments.*` instead (`templates` previously added in #681, #682) (#1119) 80 | - Removed dependency `bigi`, uses `bn.js` internally now (via `tiny-secp256k1`) (#1070, #1112) 81 | - Removed public access to `ECPair` constructor, use exported functions `ECPair.fromPrivateKey`, `ECPair.fromWIF`, `ECPair.makeRandom`, or `ECPair.fromPublicKey` (#1070) 82 | 83 | # 3.3.2 84 | __fixed__ 85 | - Fixed `decodeStack` arbitrarily supporting non-Array arguments (#942) 86 | 87 | # 3.3.1 88 | __changed__ 89 | - Increased the `TransactionBuilder` `maximumFeeRate` from 1000 to 2500 satoshis/byte. (#931) 90 | 91 | # 3.3.0 92 | __added__ 93 | - Added `ECSignature.prototype.toRSBuffer`/`ECSignature.fromRSBuffer` (#915) 94 | - Added support to `TransactionBuilder` for 64-byte signatures via `.sign` (#915) 95 | - Added support to `TransactionBuilder` for the `.publicKey` standard as an alternative to `.getPublicKey()` (#915) 96 | 97 | # 3.2.1 98 | __fixed__ 99 | - Fixed `script.scripthash.input.check` recursion (#898) 100 | - Fixed `TransactionBuilder` sometimes ignoring witness value (#901) 101 | - Fixed `script.witnessScriptHash.input` implementation (previously used the P2SH impl.) (#911) 102 | 103 | # 3.2.0 104 | __added__ 105 | - Added `address.fromBech32/toBech32` (#846) 106 | 107 | # 3.1.0 108 | __added__ 109 | - Added `Transaction.prototype.virtualSize` (#811) 110 | - Added `Transaction.prototype.weight` (#811) 111 | 112 | # 3.0.0 113 | From this release users can expect out-of-the-box Segregated Witness support. 114 | The majority of breaking changes have been in how `script` encoding/decoding occurs, with the introduction of witness stacks. 115 | 116 | __added__ 117 | - Added `script.types` enums (#679) 118 | - Added `script.*.*.{check,encode,decode[,encodeStack,decodeStack]}` functions (#681, #682) 119 | - Added minimal `TransactionBuilder.prototype.build` absurd fee-safety (#696) 120 | - Added `script.(decompile/compile)PushOnly` and `script.toStack` functions (#700) 121 | - Added `Transaction.prototype.toBuffer` Segregated Witness serialization support (#684, #701) 122 | - Added `Transaction.prototype.hasWitnesses` (#718) 123 | - Added `script.witnessCommitment.*` template 124 | - Added `TransactionBuilder.prototype.sign` now has two additional parameters, `witnessValue`, and `witnessScript` 125 | - Added `Transaction.hashForWitnessV0` and `Transaction.setWitness` (5c2fdb60436714f18440dc709f0be065928c1e49) 126 | 127 | __fixed__ 128 | - Fixed `script` must compile minimally (#638) 129 | - Fixed `Transaction` and `Block` versions should be Int32, signed integers (#662) 130 | 131 | __removed__ 132 | - Removed `ecdsa.calcPubKeyRecoveryParam`, `ecdsa.recoverPubKey` (#456) 133 | - Removed `buffer-equals`/`buffer-compare` dependencies (#650) 134 | - Removed `HDNode.prototype.toString` (#665) 135 | - Removed `dogecoin` network (#675) 136 | - Removed `message` export, moved to [`bitcoinjs-message`](https://github.com/bitcoinjs/bitcoinjs-message) (#456) 137 | 138 | __renamed__ 139 | - Removed `script.*` functions in favour of `bitcoin.script.*.(input/output).(encode/decode/check)` style (#682) 140 | 141 | # 2.3.0 142 | __added__ 143 | - Added `HDNode.prototype.isNeutered` (#536) 144 | - Added `HDNode.prototype.derivePath` (#538) 145 | - Added typeforce checking for `HDNode.prototype.derive*` (#539) 146 | - Added `Transaction.prototype.isCoinbase` (#578) 147 | - Added `Block.prototype.checkMerkleRoot` (#580) 148 | - Added `Block.calculateMerkleRoot` (#580) 149 | - Added `TransactionBuilder.prototype.setVersion` (#599) 150 | - Added `script.isWitnessPubKeyHashOutput` (#602) 151 | - Added `script.isWitnessScriptHashOutput` (#602) 152 | - Added `script.witnessPubKeyHashOutput` (#602) 153 | - Added `script.witnessScriptHashOutput` (#602) 154 | - Added `script.witnessScriptHashInput` (#602) 155 | 156 | __fixed__ 157 | - Fixed "BIP32 is undefined" when network list given to `HDNode` but no compatible version found (#550) 158 | - Fixed `writePushDataInt` output to adhere to minimal data push policy (#617) 159 | 160 | 161 | # 2.2.0 162 | __added__ 163 | - Added `Block.calculateTarget` for difficulty calculations (#509) 164 | - Added `Block.prototype.checkProofOfWork` (#509) 165 | - Added `opcodes.OP_CHECKLOCKTIMEVERIFY` alias for `OP_NOP2` (#511) 166 | - Added `script.number.[encode/decode]` for CScriptNum-encoded `Buffer`s (#516) 167 | - Added `TransactionBuilder.prototype.setLockTime` (#507) 168 | 169 | __fixed__ 170 | - Bumped `typeforce` version to fix erroneous error message from `types.Hash*bit` types (#534) 171 | 172 | 173 | # 2.1.4 174 | __fixed__ 175 | - script.isPubKeyHashOutput and script.isScriptHashOutput no longer allow for non-minimal data pushes (per bitcoin/bitcoin `IsStandard` policy) (#499) 176 | - TransactionBuilder.addOutput now allows for SIGHASH_SINGLE, throwing if the contract is violated (#504) 177 | - remove use of `const`, use ES5 only (#502) 178 | 179 | 180 | # 2.1.3 181 | __fixed__ 182 | - Bumped typeforce to 1.5.5 (see #493) 183 | 184 | 185 | # 2.1.2 186 | __fixed__ 187 | - Add missing CHANGELOG entry for 2.1.1 188 | 189 | 190 | # 2.1.1 191 | __changed__ 192 | - removed use of `buffer-reverse`, dependency only kept for `bufferutils.reverse`, to be deprecated (#478) 193 | 194 | __fixed__ 195 | - `isMultisigOutput` no longer allows data chunks for `m`/`n` (#482) 196 | - `isMultisigOutput`'s `n` value must now match the number of public keys (as per bitcoin/bitcoin) (#484) 197 | 198 | 199 | # 2.1.0 200 | From this release users should use the HDNode directly (compared to accessing `.keyPair`) when performing ECDSA operations such as `sign` or `verify`. 201 | Ideally you shoud not have to directly access `HDNode` internals for general usage, as it can often be confusing and error prone. 202 | 203 | __added__ 204 | - `ECPair.prototype.getNetwork` 205 | - `HDNode.prototype.getNetwork`, wraps the underyling keyPair's `getNetwork` method 206 | - `HDNode.prototype.getPublicKeyBuffer`, wraps the underyling keyPair's `getPublicKeyBuffer` method 207 | - `HDNode.prototype.sign`, wraps the underlying keyPair's `sign` method 208 | - `HDNode.prototype.verify`, wraps the underlying keyPair's `verify` method 209 | 210 | 211 | # 2.0.0 212 | In this release we have strived to simplify the API, [using native types](https://github.com/bitcoinjs/bitcoinjs-lib/issues/407) wherevever possible to encourage cross-compatibility with other open source community modules. 213 | 214 | The `ecdsa` module has been removed in lieu of using a new ECDSA module (for performance and safety reasons) during the `2.x.y` major release. 215 | Several other cumbersome modules have been removed, with their new independent modules recommended for usage instead for greater modularity in your projects. 216 | 217 | ----------------------------- 218 | 219 | Backward incompatible changes: 220 | 221 | __added__ 222 | - export `address`, for `address` based [utility functions](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/address.js), most compatible, just without `Address` instantiation, see #401, #444 223 | - export `script`, for `script` based [utility functions](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/script.js), mostly compatible, just without `Script` instantiation, see #438, #444 224 | - export `ECPair`, a merged replacement for `ECKey`/`ECPubKey`, invalid types will throw via `typeforce` 225 | 226 | __changed__ 227 | - `address.toOutputScript`, `ECPair.prototype.fromWIF` and `HDNode.prototype.fromBase58` no longer automatically detect the network, `networks.bitcoin` is always assumed unless given. 228 | - `assert` was used for type checking, now replaced by `typeforce` 229 | - `BIP66` compliant strict DER signature validation was added to `ECSignature.fromDER`, changing the exact exception messages slightly, see #448. 230 | 231 | - `new HDNode(d/Q, chainCode, network)` -> `new HDNode(keyPair, chainCode)`, now uses `ECPair` 232 | - `HDNode.prototype.toBase58(false)` -> `HDNode.prototype.neutered().toBase58()` for exporting an extended public key 233 | - `HDNode.prototype.toBase58(true)` -> `HDNode.prototype.toBase58()` for exporting an extended private key 234 | 235 | - `Transaction.prototype.hashForSignature(prevOutScript, inIndex, hashType)` -> `Transaction.prototype.hashForSignature(inIndex, prevOutScript, hashType)` 236 | - `Transaction.prototype.addInput(hash, ...)`: `hash` could be a string, Transaction or Buffer -> `hash` can now **only** be a `Buffer`. 237 | - `Transaction.prototype.addOutput(scriptPubKey, ...)`: `scriptPubKey ` could be a string, `Address` or a `Buffer` -> `scriptPubKey` can now **only** be a `Buffer`. 238 | - `TransactionBuilder` API unchanged. 239 | 240 | __removed__ 241 | - export `Address`, `strings` are now used, benchwith no performance loss for most use cases 242 | - export `base58check`, use [`bs58check`](https://github.com/bitcoinjs/bs58check) instead 243 | - export `ecdsa`, use [`ecurve`](https://github.com/cryptocoinjs/ecurve) instead 244 | - export `ECKey`, use new export `ECPair` instead 245 | - export `ECPubKey`, use new export `ECPair` instead 246 | - export `Wallet`, see README.md#complementing-libraries instead 247 | - export `Script`, use new utility export `script` instead (#438 for more information) 248 | 249 | - `crypto.HmacSHA256 `, use [node crypto](https://nodejs.org/api/crypto.html) instead 250 | - `crypto.HmacSHA512 `, use [node crypto](https://nodejs.org/api/crypto.html) instead 251 | 252 | - `Transaction.prototype.sign`, use `TransactionBuilder.prototype.sign` 253 | - `Transaction.prototype.signInput`, use `TransactionBuilder.prototype.sign` 254 | - `Transaction.prototype.validateInput`, use `Transaction.prototype.hashForSignature` and `ECPair.verify` 255 | 256 | - `HDNode.fromBuffer`, use `HDNode.fromBase58` instead 257 | - `HDNode.fromHex`, use `HDNode.fromBase58` instead 258 | - `HDNode.toBuffer`, use `HDNode.prototype.toBase58` instead 259 | - `HDNode.toHex`, use `HDNode.prototype.toBase58` instead 260 | 261 | - `networks.*.magic`, see the comment [here](https://github.com/bitcoinjs/bitcoinjs-lib/pull/432/files#r36715792) 262 | - `networks.[viacoin|viacointestnet|gamerscoin|jumbucks|zetacoin]`, import these yourself (see #383/a0e6ee7) 263 | - `networks.*.estimateFee`, out-dated 264 | 265 | __renamed__ 266 | - `Message` -> `message` 267 | - `scripts` -> `script` 268 | - `scripts.dataOutput ` -> `script.nullDataOutput` (per [convention](https://org/en/glossary/null-data-transaction)) 269 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2019 bitcoinjs-lib contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RN-BitcoinJS (rn-bitcoinjs-lib) 2 | 3 | #### Note: Great news! This library is no longer required for bitcoinjs-lib versions 5.1 and up. [Please use this Gist instead to get your RN project up and running.](https://gist.github.com/coreyphillips/4d45160fed016417a5f583f179c2cbdb) 4 | 5 | This is a React Native compatible version of [bitcoinjs-lib](https://github.com/bitcoinjs/bitcoinjs-lib), a javascript Bitcoin library for node.js and browsers. Written in TypeScript, but committing the JS files to verify. 6 | 7 | Released under the terms of the [MIT LICENSE](LICENSE). 8 | 9 | ## Should I use this in production? 10 | If you are thinking of using the *master* branch of this library in production, **stop**. 11 | Master is not stable; it is our development branch, and [only tagged releases may be classified as stable](https://github.com/coreyphillips/rn-bitcoinjs-lib/tags). 12 | 13 | 14 | ## Can I trust this code? 15 | > Don't trust. Verify. 16 | 17 | You shouldn't trust or rely on this repo for anything other than testing. To setup bitcoinjs-lib (5.0.5) in your RN project, please follow the how-to below: 18 | [RN BitcoinJS-Lib (5.0.5) Setup](https://gist.github.com/coreyphillips/9719d7e4b1f6042b993f548d2083cee8) 19 | 20 | If you have any difficulty with the setup instructions below and need a repo for reference, feel free to clone, review and experiment with the pre-built RN repo here: [RNBitcoinJS](https://github.com/coreyphillips/RNBitcoinJS) 21 | 22 | We recommend every user of this library and the [bitcoinjs](https://github.com/bitcoinjs) ecosystem audit and verify any underlying code for its validity and suitability. 23 | 24 | Mistakes and bugs happen, but with your help in resolving and reporting [issues](https://github.com/bitcoinjs/bitcoinjs-lib/issues), together we can produce open source software that is: 25 | 26 | - Easy to audit and verify, 27 | - Tested, with test coverage >95%, 28 | - Advanced and feature rich, 29 | - Standardized, using [prettier](https://github.com/prettier/prettier) and Node `Buffer`'s throughout, and 30 | - Friendly, with a strong and helpful community, ready to answer questions. 31 | 32 | ## Documentation 33 | Presently, we do not have any formal documentation other than our [examples](https://github.com/bitcoinjs/bitcoinjs-lib#examples), please [ask for help](https://github.com/bitcoinjs/bitcoinjs-lib/issues/new) if our examples aren't enough to guide you. 34 | 35 | 36 | ## Installation 37 | ``` bash 38 | yarn add rn-bitcoinjs-lib 39 | ``` 40 | 41 | Typically we support the [Node Maintenance LTS version](https://github.com/nodejs/Release). 42 | If in doubt, see the [.travis.yml](.travis.yml) for what versions are used by our continuous integration tests. 43 | 44 | **WARNING**: We presently don't provide any tooling to verify that the release on `npm` matches GitHub. As such, you should verify anything downloaded by `npm` against your own verified copy. 45 | 46 | 47 | ## Setup 48 | 49 | ### React Native 50 | Install the following dependencies: 51 | ``` bash 52 | yarn add buffer-reverse react-native-randombytes crypto buffer@5 53 | yarn add --dev rn-nodeify 54 | react-native link react-native-randombytes 55 | ``` 56 | Add the following to your script in package.json: 57 | 58 | ``` javascript 59 | "postinstall": "rn-nodeify --install buffer,stream,assert,events,crypto,vm --hack && cd node_modules/bs58 && yarn add base-x@3.0.4 && cd ../../" 60 | ``` 61 | 62 | Install any remaining dependencies and run postinstall. 63 | NOTE: (If you receive an error about "shim.js" not existing just run `yarn install` again): 64 | 65 | ``` bash 66 | yarn install 67 | ``` 68 | 69 | Add the following to shim.js: 70 | ``` javascript 71 | if (typeof Buffer.prototype.reverse === 'undefined') { 72 | var bufferReverse = require('buffer-reverse'); 73 | 74 | Buffer.prototype.reverse = function () { 75 | return bufferReverse(this); 76 | }; 77 | } 78 | ``` 79 | 80 | Add/Uncomment "require('crypto')" at the bottom of shim.js: 81 | 82 | ``` javascript 83 | require('crypto') 84 | ``` 85 | 86 | Finally: 87 | 88 | ``` bash 89 | yarn install 90 | ``` 91 | 92 | **Usage** 93 | ``` javascript 94 | import "./shim"; 95 | const bitcoin = require("rn-bitcoinjs-lib"); 96 | const keyPair = bitcoin.ECPair.makeRandom(); 97 | const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey }); 98 | console.log(address); 99 | ``` 100 | 101 | Crypto is hard. 102 | 103 | When working with private keys, the random number generator is fundamentally one of the most important parts of any software you write. 104 | For random number generation, we *default* to the [`randombytes`](https://github.com/crypto-browserify/randombytes) module, which uses [`window.crypto.getRandomValues`](https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues) in the browser, or Node js' [`crypto.randomBytes`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback), depending on your build system. 105 | Although this default is ~OK, there is no simple way to detect if the underlying RNG provided is good enough, or if it is **catastrophically bad**. 106 | You should always verify this yourself to your own standards. 107 | 108 | This library uses [tiny-secp256k1](https://github.com/bitcoinjs/tiny-secp256k1), which uses [RFC6979](https://tools.ietf.org/html/rfc6979) to help prevent `k` re-use and exploitation. 109 | Unfortunately, this isn't a silver bullet. 110 | Often, Javascript itself is working against us by bypassing these counter-measures. 111 | 112 | Problems in [`Buffer (UInt8Array)`](https://github.com/feross/buffer), for example, can trivially result in **catastrophic fund loss** without any warning. 113 | It can do this through undermining your random number generation, accidentally producing a [duplicate `k` value](https://www.nilsschneider.net/2013/01/28/recovering-bitcoin-private-keys.html), sending Bitcoin to a malformed output script, or any of a million different ways. 114 | Running tests in your target environment is important and a recommended step to verify continuously. 115 | 116 | Finally, **adhere to best practice**. 117 | We are not an authorative source of best practice, but, at the very least: 118 | 119 | * [Don't re-use addresses](https://en.bitcoin.it/wiki/Address_reuse). 120 | * Don't share BIP32 extended public keys ('xpubs'). [They are a liability](https://bitcoin.stackexchange.com/questions/56916/derivation-of-parent-private-key-from-non-hardened-child), and it only takes 1 misplaced private key (or a buggy implementation!) and you are vulnerable to **catastrophic fund loss**. 121 | * [Don't use `Math.random`](https://security.stackexchange.com/questions/181580/why-is-math-random-not-designed-to-be-cryptographically-secure) - in any way - don't. 122 | * Enforce that users always verify (manually) a freshly-decoded human-readable version of their intended transaction before broadcast. 123 | * Don't *ask* users to generate mnemonics, or 'brain wallets', humans are terrible random number generators. 124 | * Lastly, if you can, use [Typescript](https://www.typescriptlang.org/) or similar. 125 | 126 | 127 | 128 | ### Node.js 129 | Use [bitcoinjs-lib](https://github.com/bitcoinjs/bitcoinjs-lib) 130 | 131 | ### Browser 132 | Use [bitcoinjs-lib](https://github.com/bitcoinjs/bitcoinjs-lib) 133 | 134 | ### Typescript or VSCode users 135 | Type declarations for Typescript are included in this library. Normal installation should include all the needed type information. 136 | 137 | ## Examples 138 | The below examples are implemented as integration tests, they should be very easy to understand. 139 | Otherwise, pull requests are appreciated. 140 | Some examples interact (via HTTPS) with a 3rd Party Blockchain Provider (3PBP). 141 | 142 | - [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) 143 | - [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) 144 | - [Generate a 2-of-3 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) 145 | - [Generate a SegWit address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) 146 | - [Generate a SegWit P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) 147 | - [Generate a SegWit 3-of-4 multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) 148 | - [Generate a SegWit 2-of-2 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) 149 | - [Support the retrieval of transactions for an address (3rd party blockchain)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) 150 | - [Generate a Testnet address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) 151 | - [Generate a Litecoin address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js) 152 | - [Create a 1-to-1 Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) 153 | - [Create a 2-to-2 Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) 154 | - [Create (and broadcast via 3PBP) a typical Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) 155 | - [Create (and broadcast via 3PBP) a Transaction with an OP\_RETURN output](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) 156 | - [Create (and broadcast via 3PBP) a Transaction with a 2-of-4 P2SH(multisig) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) 157 | - [Create (and broadcast via 3PBP) a Transaction with a SegWit P2SH(P2WPKH) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) 158 | - [Create (and broadcast via 3PBP) a Transaction with a SegWit P2WPKH input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) 159 | - [Create (and broadcast via 3PBP) a Transaction with a SegWit P2PK input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) 160 | - [Create (and broadcast via 3PBP) a Transaction with a SegWit 3-of-4 P2SH(P2WSH(multisig)) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) 161 | - [Verify a Transaction signature](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js) 162 | - [Import a BIP32 testnet xpriv and export to WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) 163 | - [Export a BIP32 xpriv, then import it](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) 164 | - [Export a BIP32 xpub](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) 165 | - [Create a BIP32, bitcoin, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) 166 | - [Create a BIP44, bitcoin, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) 167 | - [Create a BIP49, bitcoin testnet, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) 168 | - [Use BIP39 to generate BIP32 addresses](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js) 169 | - [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the past)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js) 170 | - [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js) 171 | - [Create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js) 172 | - [Create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js) 173 | - [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future) (simple CHECKSEQUENCEVERIFY)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/csv.js) 174 | - [Create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry (simple CHECKSEQUENCEVERIFY)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/csv.js) 175 | - [Create (and broadcast via 3PBP) a Transaction where Bob and Charles can send (complex CHECKSEQUENCEVERIFY)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/csv.js) 176 | - [Create (and broadcast via 3PBP) a Transaction where Alice (mediator) and Bob can send after 2 blocks (complex CHECKSEQUENCEVERIFY)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/csv.js) 177 | - [Create (and broadcast via 3PBP) a Transaction where Alice (mediator) can send after 5 blocks (complex CHECKSEQUENCEVERIFY)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/csv.js) 178 | 179 | If you have a use case that you feel could be listed here, please [ask for it](https://github.com/bitcoinjs/bitcoinjs-lib/issues/new)! 180 | 181 | 182 | ## Contributing 183 | See [CONTRIBUTING.md](CONTRIBUTING.md). 184 | 185 | 186 | ### Running the test suite 187 | 188 | ``` bash 189 | npm test 190 | npm run-script coverage 191 | ``` 192 | 193 | ## Complementing Libraries 194 | - [BIP21](https://github.com/bitcoinjs/bip21) - A BIP21 compatible URL encoding library 195 | - [BIP38](https://github.com/bitcoinjs/bip38) - Passphrase-protected private keys 196 | - [BIP39](https://github.com/bitcoinjs/bip39) - Mnemonic generation for deterministic keys 197 | - [BIP32-Utils](https://github.com/bitcoinjs/bip32-utils) - A set of utilities for working with BIP32 198 | - [BIP66](https://github.com/bitcoinjs/bip66) - Strict DER signature decoding 199 | - [BIP68](https://github.com/bitcoinjs/bip68) - Relative lock-time encoding library 200 | - [BIP69](https://github.com/bitcoinjs/bip69) - Lexicographical Indexing of Transaction Inputs and Outputs 201 | - [Base58](https://github.com/cryptocoinjs/bs58) - Base58 encoding/decoding 202 | - [Base58 Check](https://github.com/bitcoinjs/bs58check) - Base58 check encoding/decoding 203 | - [Bech32](https://github.com/bitcoinjs/bech32) - A BIP173 compliant Bech32 encoding library 204 | - [coinselect](https://github.com/bitcoinjs/coinselect) - A fee-optimizing, transaction input selection module for bitcoinjs-lib. 205 | - [merkle-lib](https://github.com/bitcoinjs/merkle-lib) - A performance conscious library for merkle root and tree calculations. 206 | - [minimaldata](https://github.com/bitcoinjs/minimaldata) - A module to check bitcoin policy: SCRIPT_VERIFY_MINIMALDATA 207 | 208 | 209 | ## Alternatives 210 | - [BCoin](https://github.com/indutny/bcoin) 211 | - [Bitcore](https://github.com/bitpay/bitcore) 212 | - [Cryptocoin](https://github.com/cryptocoinjs/cryptocoin) 213 | 214 | 215 | ## LICENSE [MIT](LICENSE) 216 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rn-bitcoinjs-lib", 3 | "version": "5.0.5-1", 4 | "description": "Client-side Bitcoin JavaScript library", 5 | "main": "./src/index.js", 6 | "types": "./types/index.d.ts", 7 | "engines": { 8 | "node": ">=8.0.0" 9 | }, 10 | "keywords": [ 11 | "bitcoinjs", 12 | "bitcoin", 13 | "browserify", 14 | "javascript", 15 | "bitcoinjs" 16 | ], 17 | "scripts": { 18 | "build": "npm run clean && tsc -p ./tsconfig.json && npm run formatjs", 19 | "clean": "rimraf src types", 20 | "coverage-report": "npm run build && npm run nobuild:coverage-report", 21 | "coverage-html": "npm run build && npm run nobuild:coverage-html", 22 | "coverage": "npm run build && npm run nobuild:coverage", 23 | "format": "npm run prettier -- --write", 24 | "formatjs": "npm run prettierjs -- --write > /dev/null 2>&1", 25 | "format:ci": "npm run prettier -- --check && npm run prettierjs -- --check", 26 | "gitdiff:ci": "npm run build && git diff --exit-code", 27 | "integration": "npm run build && npm run nobuild:integration", 28 | "lint": "tslint -p tsconfig.json -c tslint.json", 29 | "nobuild:coverage-report": "nyc report --reporter=lcov", 30 | "nobuild:coverage-html": "nyc report --reporter=html", 31 | "nobuild:coverage": "nyc --check-coverage --branches 90 --functions 90 --lines 90 mocha", 32 | "nobuild:integration": "mocha --timeout 50000 test/integration/", 33 | "nobuild:unit": "mocha", 34 | "prettier": "prettier 'ts_src/**/*.ts' --ignore-path ./.prettierignore", 35 | "prettierjs": "prettier 'src/**/*.js' --ignore-path ./.prettierignore", 36 | "test": "npm run build && npm run format:ci && npm run lint && npm run nobuild:coverage", 37 | "unit": "npm run build && npm run nobuild:unit" 38 | }, 39 | "repository": { 40 | "type": "git", 41 | "url": "https://github.com/coreyphillips/rn-bitcoinjs-lib.git" 42 | }, 43 | "files": [ 44 | "src", 45 | "types" 46 | ], 47 | "dependencies": { 48 | "@types/node": "10.12.18", 49 | "bech32": "^1.1.2", 50 | "bip32": "^2.0.3", 51 | "bip66": "^1.1.0", 52 | "bitcoin-ops": "^1.4.0", 53 | "bs58check": "^2.0.0", 54 | "create-hash": "^1.1.0", 55 | "create-hmac": "^1.1.3", 56 | "merkle-lib": "^2.0.10", 57 | "pushdata-bitcoin": "^1.0.1", 58 | "react-native-randombytes": "^3.5.3", 59 | "tiny-secp256k1": "^1.1.1", 60 | "typeforce": "^1.11.3", 61 | "varuint-bitcoin": "^1.0.4", 62 | "wif": "^2.0.1" 63 | }, 64 | "devDependencies": { 65 | "bip39": "^2.3.0", 66 | "bip65": "^1.0.1", 67 | "bip68": "^1.0.3", 68 | "bn.js": "^4.11.8", 69 | "bs58": "^4.0.0", 70 | "dhttp": "^3.0.0", 71 | "hoodwink": "^2.0.0", 72 | "minimaldata": "^1.0.2", 73 | "mocha": "^5.2.0", 74 | "nyc": "^14.1.1", 75 | "prettier": "1.16.4", 76 | "proxyquire": "^2.0.1", 77 | "rimraf": "^2.6.3", 78 | "tslint": "^5.16.0", 79 | "typescript": "3.2.2" 80 | }, 81 | "license": "MIT", 82 | "react-native": { 83 | "crypto": "react-native-crypto", 84 | "_stream_transform": "readable-stream/transform", 85 | "_stream_readable": "readable-stream/readable", 86 | "_stream_writable": "readable-stream/writable", 87 | "_stream_duplex": "readable-stream/duplex", 88 | "_stream_passthrough": "readable-stream/passthrough", 89 | "stream": "stream-browserify", 90 | "vm": "vm-browserify" 91 | }, 92 | "browser": { 93 | "crypto": "react-native-crypto", 94 | "_stream_transform": "readable-stream/transform", 95 | "_stream_readable": "readable-stream/readable", 96 | "_stream_writable": "readable-stream/writable", 97 | "_stream_duplex": "readable-stream/duplex", 98 | "_stream_passthrough": "readable-stream/passthrough", 99 | "stream": "stream-browserify", 100 | "vm": "vm-browserify" 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/address.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const networks = require('./networks'); 4 | const payments = require('./payments'); 5 | const bscript = require('./script'); 6 | const types = require('./types'); 7 | const bech32 = require('bech32'); 8 | const bs58check = require('bs58check'); 9 | const typeforce = require('typeforce'); 10 | function fromBase58Check(address) { 11 | const payload = bs58check.decode(address); 12 | // TODO: 4.0.0, move to "toOutputScript" 13 | if (payload.length < 21) throw new TypeError(address + ' is too short'); 14 | if (payload.length > 21) throw new TypeError(address + ' is too long'); 15 | const version = payload.readUInt8(0); 16 | const hash = payload.slice(1); 17 | return { version, hash }; 18 | } 19 | exports.fromBase58Check = fromBase58Check; 20 | function fromBech32(address) { 21 | const result = bech32.decode(address); 22 | const data = bech32.fromWords(result.words.slice(1)); 23 | return { 24 | version: result.words[0], 25 | prefix: result.prefix, 26 | data: Buffer.from(data), 27 | }; 28 | } 29 | exports.fromBech32 = fromBech32; 30 | function toBase58Check(hash, version) { 31 | typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments); 32 | const payload = Buffer.allocUnsafe(21); 33 | payload.writeUInt8(version, 0); 34 | hash.copy(payload, 1); 35 | return bs58check.encode(payload); 36 | } 37 | exports.toBase58Check = toBase58Check; 38 | function toBech32(data, version, prefix) { 39 | const words = bech32.toWords(data); 40 | words.unshift(version); 41 | return bech32.encode(prefix, words); 42 | } 43 | exports.toBech32 = toBech32; 44 | function fromOutputScript(output, network) { 45 | // TODO: Network 46 | network = network || networks.bitcoin; 47 | try { 48 | return payments.p2pkh({ output, network }).address; 49 | } catch (e) {} 50 | try { 51 | return payments.p2sh({ output, network }).address; 52 | } catch (e) {} 53 | try { 54 | return payments.p2wpkh({ output, network }).address; 55 | } catch (e) {} 56 | try { 57 | return payments.p2wsh({ output, network }).address; 58 | } catch (e) {} 59 | throw new Error(bscript.toASM(output) + ' has no matching Address'); 60 | } 61 | exports.fromOutputScript = fromOutputScript; 62 | function toOutputScript(address, network) { 63 | network = network || networks.bitcoin; 64 | let decodeBase58; 65 | let decodeBech32; 66 | try { 67 | decodeBase58 = fromBase58Check(address); 68 | } catch (e) {} 69 | if (decodeBase58) { 70 | if (decodeBase58.version === network.pubKeyHash) 71 | return payments.p2pkh({ hash: decodeBase58.hash }).output; 72 | if (decodeBase58.version === network.scriptHash) 73 | return payments.p2sh({ hash: decodeBase58.hash }).output; 74 | } else { 75 | try { 76 | decodeBech32 = fromBech32(address); 77 | } catch (e) {} 78 | if (decodeBech32) { 79 | if (decodeBech32.prefix !== network.bech32) 80 | throw new Error(address + ' has an invalid prefix'); 81 | if (decodeBech32.version === 0) { 82 | if (decodeBech32.data.length === 20) 83 | return payments.p2wpkh({ hash: decodeBech32.data }).output; 84 | if (decodeBech32.data.length === 32) 85 | return payments.p2wsh({ hash: decodeBech32.data }).output; 86 | } 87 | } 88 | } 89 | throw new Error(address + ' has no matching Script'); 90 | } 91 | exports.toOutputScript = toOutputScript; 92 | -------------------------------------------------------------------------------- /src/block.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const bufferutils_1 = require('./bufferutils'); 4 | const bcrypto = require('./crypto'); 5 | const transaction_1 = require('./transaction'); 6 | const types = require('./types'); 7 | const fastMerkleRoot = require('merkle-lib/fastRoot'); 8 | const typeforce = require('typeforce'); 9 | const varuint = require('varuint-bitcoin'); 10 | const errorMerkleNoTxes = new TypeError( 11 | 'Cannot compute merkle root for zero transactions', 12 | ); 13 | const errorWitnessNotSegwit = new TypeError( 14 | 'Cannot compute witness commit for non-segwit block', 15 | ); 16 | class Block { 17 | constructor() { 18 | this.version = 1; 19 | this.prevHash = undefined; 20 | this.merkleRoot = undefined; 21 | this.timestamp = 0; 22 | this.witnessCommit = undefined; 23 | this.bits = 0; 24 | this.nonce = 0; 25 | this.transactions = undefined; 26 | } 27 | static fromBuffer(buffer) { 28 | if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)'); 29 | let offset = 0; 30 | const readSlice = n => { 31 | offset += n; 32 | return buffer.slice(offset - n, offset); 33 | }; 34 | const readUInt32 = () => { 35 | const i = buffer.readUInt32LE(offset); 36 | offset += 4; 37 | return i; 38 | }; 39 | const readInt32 = () => { 40 | const i = buffer.readInt32LE(offset); 41 | offset += 4; 42 | return i; 43 | }; 44 | const block = new Block(); 45 | block.version = readInt32(); 46 | block.prevHash = readSlice(32); 47 | block.merkleRoot = readSlice(32); 48 | block.timestamp = readUInt32(); 49 | block.bits = readUInt32(); 50 | block.nonce = readUInt32(); 51 | if (buffer.length === 80) return block; 52 | const readVarInt = () => { 53 | const vi = varuint.decode(buffer, offset); 54 | offset += varuint.decode.bytes; 55 | return vi; 56 | }; 57 | const readTransaction = () => { 58 | const tx = transaction_1.Transaction.fromBuffer( 59 | buffer.slice(offset), 60 | true, 61 | ); 62 | offset += tx.byteLength(); 63 | return tx; 64 | }; 65 | const nTransactions = readVarInt(); 66 | block.transactions = []; 67 | for (let i = 0; i < nTransactions; ++i) { 68 | const tx = readTransaction(); 69 | block.transactions.push(tx); 70 | } 71 | const witnessCommit = block.getWitnessCommit(); 72 | // This Block contains a witness commit 73 | if (witnessCommit) block.witnessCommit = witnessCommit; 74 | return block; 75 | } 76 | static fromHex(hex) { 77 | return Block.fromBuffer(Buffer.from(hex, 'hex')); 78 | } 79 | static calculateTarget(bits) { 80 | const exponent = ((bits & 0xff000000) >> 24) - 3; 81 | const mantissa = bits & 0x007fffff; 82 | const target = Buffer.alloc(32, 0); 83 | target.writeUIntBE(mantissa, 29 - exponent, 3); 84 | return target; 85 | } 86 | static calculateMerkleRoot(transactions, forWitness) { 87 | typeforce([{ getHash: types.Function }], transactions); 88 | if (transactions.length === 0) throw errorMerkleNoTxes; 89 | if (forWitness && !txesHaveWitnessCommit(transactions)) 90 | throw errorWitnessNotSegwit; 91 | const hashes = transactions.map(transaction => 92 | transaction.getHash(forWitness), 93 | ); 94 | const rootHash = fastMerkleRoot(hashes, bcrypto.hash256); 95 | return forWitness 96 | ? bcrypto.hash256( 97 | Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]), 98 | ) 99 | : rootHash; 100 | } 101 | getWitnessCommit() { 102 | if (!txesHaveWitnessCommit(this.transactions)) return null; 103 | // The merkle root for the witness data is in an OP_RETURN output. 104 | // There is no rule for the index of the output, so use filter to find it. 105 | // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed 106 | // If multiple commits are found, the output with highest index is assumed. 107 | const witnessCommits = this.transactions[0].outs 108 | .filter(out => 109 | out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')), 110 | ) 111 | .map(out => out.script.slice(6, 38)); 112 | if (witnessCommits.length === 0) return null; 113 | // Use the commit with the highest output (should only be one though) 114 | const result = witnessCommits[witnessCommits.length - 1]; 115 | if (!(result instanceof Buffer && result.length === 32)) return null; 116 | return result; 117 | } 118 | hasWitnessCommit() { 119 | if ( 120 | this.witnessCommit instanceof Buffer && 121 | this.witnessCommit.length === 32 122 | ) 123 | return true; 124 | if (this.getWitnessCommit() !== null) return true; 125 | return false; 126 | } 127 | hasWitness() { 128 | return anyTxHasWitness(this.transactions); 129 | } 130 | byteLength(headersOnly) { 131 | if (headersOnly || !this.transactions) return 80; 132 | return ( 133 | 80 + 134 | varuint.encodingLength(this.transactions.length) + 135 | this.transactions.reduce((a, x) => a + x.byteLength(), 0) 136 | ); 137 | } 138 | getHash() { 139 | return bcrypto.hash256(this.toBuffer(true)); 140 | } 141 | getId() { 142 | return bufferutils_1.reverseBuffer(this.getHash()).toString('hex'); 143 | } 144 | getUTCDate() { 145 | const date = new Date(0); // epoch 146 | date.setUTCSeconds(this.timestamp); 147 | return date; 148 | } 149 | // TODO: buffer, offset compatibility 150 | toBuffer(headersOnly) { 151 | const buffer = Buffer.allocUnsafe(this.byteLength(headersOnly)); 152 | let offset = 0; 153 | const writeSlice = slice => { 154 | slice.copy(buffer, offset); 155 | offset += slice.length; 156 | }; 157 | const writeInt32 = i => { 158 | buffer.writeInt32LE(i, offset); 159 | offset += 4; 160 | }; 161 | const writeUInt32 = i => { 162 | buffer.writeUInt32LE(i, offset); 163 | offset += 4; 164 | }; 165 | writeInt32(this.version); 166 | writeSlice(this.prevHash); 167 | writeSlice(this.merkleRoot); 168 | writeUInt32(this.timestamp); 169 | writeUInt32(this.bits); 170 | writeUInt32(this.nonce); 171 | if (headersOnly || !this.transactions) return buffer; 172 | varuint.encode(this.transactions.length, buffer, offset); 173 | offset += varuint.encode.bytes; 174 | this.transactions.forEach(tx => { 175 | const txSize = tx.byteLength(); // TODO: extract from toBuffer? 176 | tx.toBuffer(buffer, offset); 177 | offset += txSize; 178 | }); 179 | return buffer; 180 | } 181 | toHex(headersOnly) { 182 | return this.toBuffer(headersOnly).toString('hex'); 183 | } 184 | checkTxRoots() { 185 | // If the Block has segwit transactions but no witness commit, 186 | // there's no way it can be valid, so fail the check. 187 | const hasWitnessCommit = this.hasWitnessCommit(); 188 | if (!hasWitnessCommit && this.hasWitness()) return false; 189 | return ( 190 | this.__checkMerkleRoot() && 191 | (hasWitnessCommit ? this.__checkWitnessCommit() : true) 192 | ); 193 | } 194 | checkProofOfWork() { 195 | const hash = bufferutils_1.reverseBuffer(this.getHash()); 196 | const target = Block.calculateTarget(this.bits); 197 | return hash.compare(target) <= 0; 198 | } 199 | __checkMerkleRoot() { 200 | if (!this.transactions) throw errorMerkleNoTxes; 201 | const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions); 202 | return this.merkleRoot.compare(actualMerkleRoot) === 0; 203 | } 204 | __checkWitnessCommit() { 205 | if (!this.transactions) throw errorMerkleNoTxes; 206 | if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit; 207 | const actualWitnessCommit = Block.calculateMerkleRoot( 208 | this.transactions, 209 | true, 210 | ); 211 | return this.witnessCommit.compare(actualWitnessCommit) === 0; 212 | } 213 | } 214 | exports.Block = Block; 215 | function txesHaveWitnessCommit(transactions) { 216 | return ( 217 | transactions instanceof Array && 218 | transactions[0] && 219 | transactions[0].ins && 220 | transactions[0].ins instanceof Array && 221 | transactions[0].ins[0] && 222 | transactions[0].ins[0].witness && 223 | transactions[0].ins[0].witness instanceof Array && 224 | transactions[0].ins[0].witness.length > 0 225 | ); 226 | } 227 | function anyTxHasWitness(transactions) { 228 | return ( 229 | transactions instanceof Array && 230 | transactions.some( 231 | tx => 232 | typeof tx === 'object' && 233 | tx.ins instanceof Array && 234 | tx.ins.some( 235 | input => 236 | typeof input === 'object' && 237 | input.witness instanceof Array && 238 | input.witness.length > 0, 239 | ), 240 | ) 241 | ); 242 | } 243 | -------------------------------------------------------------------------------- /src/bufferutils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | // https://github.com/feross/buffer/blob/master/index.js#L1127 4 | function verifuint(value, max) { 5 | if (typeof value !== 'number') 6 | throw new Error('cannot write a non-number as a number'); 7 | if (value < 0) 8 | throw new Error('specified a negative value for writing an unsigned value'); 9 | if (value > max) throw new Error('RangeError: value out of range'); 10 | if (Math.floor(value) !== value) 11 | throw new Error('value has a fractional component'); 12 | } 13 | function readUInt64LE(buffer, offset) { 14 | const a = buffer.readUInt32LE(offset); 15 | let b = buffer.readUInt32LE(offset + 4); 16 | b *= 0x100000000; 17 | verifuint(b + a, 0x001fffffffffffff); 18 | return b + a; 19 | } 20 | exports.readUInt64LE = readUInt64LE; 21 | function writeUInt64LE(buffer, value, offset) { 22 | verifuint(value, 0x001fffffffffffff); 23 | buffer.writeInt32LE(value & -1, offset); 24 | buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4); 25 | return offset + 8; 26 | } 27 | exports.writeUInt64LE = writeUInt64LE; 28 | function reverseBuffer(buffer) { 29 | if (buffer.length < 1) return buffer; 30 | let j = buffer.length - 1; 31 | let tmp = 0; 32 | for (let i = 0; i < buffer.length / 2; i++) { 33 | tmp = buffer[i]; 34 | buffer[i] = buffer[j]; 35 | buffer[j] = tmp; 36 | j--; 37 | } 38 | return buffer; 39 | } 40 | exports.reverseBuffer = reverseBuffer; 41 | -------------------------------------------------------------------------------- /src/classify.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const script_1 = require('./script'); 4 | const multisig = require('./templates/multisig'); 5 | const nullData = require('./templates/nulldata'); 6 | const pubKey = require('./templates/pubkey'); 7 | const pubKeyHash = require('./templates/pubkeyhash'); 8 | const scriptHash = require('./templates/scripthash'); 9 | const witnessCommitment = require('./templates/witnesscommitment'); 10 | const witnessPubKeyHash = require('./templates/witnesspubkeyhash'); 11 | const witnessScriptHash = require('./templates/witnessscripthash'); 12 | const types = { 13 | P2MS: 'multisig', 14 | NONSTANDARD: 'nonstandard', 15 | NULLDATA: 'nulldata', 16 | P2PK: 'pubkey', 17 | P2PKH: 'pubkeyhash', 18 | P2SH: 'scripthash', 19 | P2WPKH: 'witnesspubkeyhash', 20 | P2WSH: 'witnessscripthash', 21 | WITNESS_COMMITMENT: 'witnesscommitment', 22 | }; 23 | exports.types = types; 24 | function classifyOutput(script) { 25 | if (witnessPubKeyHash.output.check(script)) return types.P2WPKH; 26 | if (witnessScriptHash.output.check(script)) return types.P2WSH; 27 | if (pubKeyHash.output.check(script)) return types.P2PKH; 28 | if (scriptHash.output.check(script)) return types.P2SH; 29 | // XXX: optimization, below functions .decompile before use 30 | const chunks = script_1.decompile(script); 31 | if (!chunks) throw new TypeError('Invalid script'); 32 | if (multisig.output.check(chunks)) return types.P2MS; 33 | if (pubKey.output.check(chunks)) return types.P2PK; 34 | if (witnessCommitment.output.check(chunks)) return types.WITNESS_COMMITMENT; 35 | if (nullData.output.check(chunks)) return types.NULLDATA; 36 | return types.NONSTANDARD; 37 | } 38 | exports.output = classifyOutput; 39 | function classifyInput(script, allowIncomplete) { 40 | // XXX: optimization, below functions .decompile before use 41 | const chunks = script_1.decompile(script); 42 | if (!chunks) throw new TypeError('Invalid script'); 43 | if (pubKeyHash.input.check(chunks)) return types.P2PKH; 44 | if (scriptHash.input.check(chunks, allowIncomplete)) return types.P2SH; 45 | if (multisig.input.check(chunks, allowIncomplete)) return types.P2MS; 46 | if (pubKey.input.check(chunks)) return types.P2PK; 47 | return types.NONSTANDARD; 48 | } 49 | exports.input = classifyInput; 50 | function classifyWitness(script, allowIncomplete) { 51 | // XXX: optimization, below functions .decompile before use 52 | const chunks = script_1.decompile(script); 53 | if (!chunks) throw new TypeError('Invalid script'); 54 | if (witnessPubKeyHash.input.check(chunks)) return types.P2WPKH; 55 | if (witnessScriptHash.input.check(chunks, allowIncomplete)) 56 | return types.P2WSH; 57 | return types.NONSTANDARD; 58 | } 59 | exports.witness = classifyWitness; 60 | -------------------------------------------------------------------------------- /src/crypto.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const createHash = require('create-hash'); 4 | function ripemd160(buffer) { 5 | try { 6 | return createHash('rmd160') 7 | .update(buffer) 8 | .digest(); 9 | } catch (err) { 10 | return createHash('ripemd160') 11 | .update(buffer) 12 | .digest(); 13 | } 14 | } 15 | exports.ripemd160 = ripemd160; 16 | function sha1(buffer) { 17 | return createHash('sha1') 18 | .update(buffer) 19 | .digest(); 20 | } 21 | exports.sha1 = sha1; 22 | function sha256(buffer) { 23 | return createHash('sha256') 24 | .update(buffer) 25 | .digest(); 26 | } 27 | exports.sha256 = sha256; 28 | function hash160(buffer) { 29 | return ripemd160(sha256(buffer)); 30 | } 31 | exports.hash160 = hash160; 32 | function hash256(buffer) { 33 | return sha256(sha256(buffer)); 34 | } 35 | exports.hash256 = hash256; 36 | -------------------------------------------------------------------------------- /src/ecpair.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const NETWORKS = require('./networks'); 4 | const types = require('./types'); 5 | const ecc = require('tiny-secp256k1'); 6 | import { randomBytes } from 'react-native-randombytes' 7 | const typeforce = require('typeforce'); 8 | const wif = require('wif'); 9 | const isOptions = typeforce.maybe( 10 | typeforce.compile({ 11 | compressed: types.maybe(types.Boolean), 12 | network: types.maybe(types.Network), 13 | }), 14 | ); 15 | class ECPair { 16 | constructor(__D, __Q, options) { 17 | this.__D = __D; 18 | this.__Q = __Q; 19 | if (options === undefined) options = {}; 20 | this.compressed = 21 | options.compressed === undefined ? true : options.compressed; 22 | this.network = options.network || NETWORKS.bitcoin; 23 | if (__Q !== undefined) this.__Q = ecc.pointCompress(__Q, this.compressed); 24 | } 25 | get privateKey() { 26 | return this.__D; 27 | } 28 | get publicKey() { 29 | if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__D, this.compressed); 30 | return this.__Q; 31 | } 32 | toWIF() { 33 | if (!this.__D) throw new Error('Missing private key'); 34 | return wif.encode(this.network.wif, this.__D, this.compressed); 35 | } 36 | sign(hash, lowR = false) { 37 | if (!this.__D) throw new Error('Missing private key'); 38 | if (lowR === false) { 39 | return ecc.sign(hash, this.__D); 40 | } else { 41 | let sig = ecc.sign(hash, this.__D); 42 | const extraData = Buffer.alloc(32, 0); 43 | let counter = 0; 44 | // if first try is lowR, skip the loop 45 | // for second try and on, add extra entropy counting up 46 | while (sig[0] > 0x7f) { 47 | counter++; 48 | extraData.writeUIntLE(counter, 0, 6); 49 | sig = ecc.signWithEntropy(hash, this.__D, extraData); 50 | } 51 | return sig; 52 | } 53 | } 54 | verify(hash, signature) { 55 | return ecc.verify(hash, this.publicKey, signature); 56 | } 57 | } 58 | function fromPrivateKey(buffer, options) { 59 | typeforce(types.Buffer256bit, buffer); 60 | if (!ecc.isPrivate(buffer)) 61 | throw new TypeError('Private key not in range [1, n)'); 62 | typeforce(isOptions, options); 63 | return new ECPair(buffer, undefined, options); 64 | } 65 | exports.fromPrivateKey = fromPrivateKey; 66 | function fromPublicKey(buffer, options) { 67 | typeforce(ecc.isPoint, buffer); 68 | typeforce(isOptions, options); 69 | return new ECPair(undefined, buffer, options); 70 | } 71 | exports.fromPublicKey = fromPublicKey; 72 | function fromWIF(wifString, network) { 73 | const decoded = wif.decode(wifString); 74 | const version = decoded.version; 75 | // list of networks? 76 | if (types.Array(network)) { 77 | network = network 78 | .filter(x => { 79 | return version === x.wif; 80 | }) 81 | .pop(); 82 | if (!network) throw new Error('Unknown network version'); 83 | // otherwise, assume a network object (or default to bitcoin) 84 | } else { 85 | network = network || NETWORKS.bitcoin; 86 | if (version !== network.wif) throw new Error('Invalid network version'); 87 | } 88 | return fromPrivateKey(decoded.privateKey, { 89 | compressed: decoded.compressed, 90 | network: network, 91 | }); 92 | } 93 | exports.fromWIF = fromWIF; 94 | function makeRandom(options) { 95 | typeforce(isOptions, options); 96 | if (options === undefined) options = {}; 97 | const rng = options.rng || randomBytes; 98 | let d; 99 | do { 100 | d = rng(32); 101 | typeforce(types.Buffer256bit, d); 102 | } while (!ecc.isPrivate(d)); 103 | return fromPrivateKey(d, options); 104 | } 105 | exports.makeRandom = makeRandom; 106 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const bip32 = require('bip32'); 4 | exports.bip32 = bip32; 5 | const address = require('./address'); 6 | exports.address = address; 7 | const crypto = require('./crypto'); 8 | exports.crypto = crypto; 9 | const ECPair = require('./ecpair'); 10 | exports.ECPair = ECPair; 11 | const networks = require('./networks'); 12 | exports.networks = networks; 13 | const payments = require('./payments'); 14 | exports.payments = payments; 15 | const script = require('./script'); 16 | exports.script = script; 17 | var block_1 = require('./block'); 18 | exports.Block = block_1.Block; 19 | var script_1 = require('./script'); 20 | exports.opcodes = script_1.OPS; 21 | var transaction_1 = require('./transaction'); 22 | exports.Transaction = transaction_1.Transaction; 23 | var transaction_builder_1 = require('./transaction_builder'); 24 | exports.TransactionBuilder = transaction_builder_1.TransactionBuilder; 25 | -------------------------------------------------------------------------------- /src/networks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | exports.bitcoin = { 4 | messagePrefix: '\x18Bitcoin Signed Message:\n', 5 | bech32: 'bc', 6 | bip32: { 7 | public: 0x0488b21e, 8 | private: 0x0488ade4, 9 | }, 10 | pubKeyHash: 0x00, 11 | scriptHash: 0x05, 12 | wif: 0x80, 13 | }; 14 | exports.regtest = { 15 | messagePrefix: '\x18Bitcoin Signed Message:\n', 16 | bech32: 'bcrt', 17 | bip32: { 18 | public: 0x043587cf, 19 | private: 0x04358394, 20 | }, 21 | pubKeyHash: 0x6f, 22 | scriptHash: 0xc4, 23 | wif: 0xef, 24 | }; 25 | exports.testnet = { 26 | messagePrefix: '\x18Bitcoin Signed Message:\n', 27 | bech32: 'tb', 28 | bip32: { 29 | public: 0x043587cf, 30 | private: 0x04358394, 31 | }, 32 | pubKeyHash: 0x6f, 33 | scriptHash: 0xc4, 34 | wif: 0xef, 35 | }; 36 | -------------------------------------------------------------------------------- /src/payments/embed.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const networks_1 = require('../networks'); 4 | const bscript = require('../script'); 5 | const lazy = require('./lazy'); 6 | const typef = require('typeforce'); 7 | const OPS = bscript.OPS; 8 | function stacksEqual(a, b) { 9 | if (a.length !== b.length) return false; 10 | return a.every((x, i) => { 11 | return x.equals(b[i]); 12 | }); 13 | } 14 | // output: OP_RETURN ... 15 | function p2data(a, opts) { 16 | if (!a.data && !a.output) throw new TypeError('Not enough data'); 17 | opts = Object.assign({ validate: true }, opts || {}); 18 | typef( 19 | { 20 | network: typef.maybe(typef.Object), 21 | output: typef.maybe(typef.Buffer), 22 | data: typef.maybe(typef.arrayOf(typef.Buffer)), 23 | }, 24 | a, 25 | ); 26 | const network = a.network || networks_1.bitcoin; 27 | const o = { network }; 28 | lazy.prop(o, 'output', () => { 29 | if (!a.data) return; 30 | return bscript.compile([OPS.OP_RETURN].concat(a.data)); 31 | }); 32 | lazy.prop(o, 'data', () => { 33 | if (!a.output) return; 34 | return bscript.decompile(a.output).slice(1); 35 | }); 36 | // extended validation 37 | if (opts.validate) { 38 | if (a.output) { 39 | const chunks = bscript.decompile(a.output); 40 | if (chunks[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid'); 41 | if (!chunks.slice(1).every(typef.Buffer)) 42 | throw new TypeError('Output is invalid'); 43 | if (a.data && !stacksEqual(a.data, o.data)) 44 | throw new TypeError('Data mismatch'); 45 | } 46 | } 47 | return Object.assign(o, a); 48 | } 49 | exports.p2data = p2data; 50 | -------------------------------------------------------------------------------- /src/payments/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const embed_1 = require('./embed'); 4 | exports.embed = embed_1.p2data; 5 | const p2ms_1 = require('./p2ms'); 6 | exports.p2ms = p2ms_1.p2ms; 7 | const p2pk_1 = require('./p2pk'); 8 | exports.p2pk = p2pk_1.p2pk; 9 | const p2pkh_1 = require('./p2pkh'); 10 | exports.p2pkh = p2pkh_1.p2pkh; 11 | const p2sh_1 = require('./p2sh'); 12 | exports.p2sh = p2sh_1.p2sh; 13 | const p2wpkh_1 = require('./p2wpkh'); 14 | exports.p2wpkh = p2wpkh_1.p2wpkh; 15 | const p2wsh_1 = require('./p2wsh'); 16 | exports.p2wsh = p2wsh_1.p2wsh; 17 | // TODO 18 | // witness commitment 19 | -------------------------------------------------------------------------------- /src/payments/lazy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | function prop(object, name, f) { 4 | Object.defineProperty(object, name, { 5 | configurable: true, 6 | enumerable: true, 7 | get() { 8 | const _value = f.call(this); 9 | this[name] = _value; 10 | return _value; 11 | }, 12 | set(_value) { 13 | Object.defineProperty(this, name, { 14 | configurable: true, 15 | enumerable: true, 16 | value: _value, 17 | writable: true, 18 | }); 19 | }, 20 | }); 21 | } 22 | exports.prop = prop; 23 | function value(f) { 24 | let _value; 25 | return () => { 26 | if (_value !== undefined) return _value; 27 | _value = f(); 28 | return _value; 29 | }; 30 | } 31 | exports.value = value; 32 | -------------------------------------------------------------------------------- /src/payments/p2ms.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const networks_1 = require('../networks'); 4 | const bscript = require('../script'); 5 | const lazy = require('./lazy'); 6 | const OPS = bscript.OPS; 7 | const typef = require('typeforce'); 8 | const ecc = require('tiny-secp256k1'); 9 | const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1 10 | function stacksEqual(a, b) { 11 | if (a.length !== b.length) return false; 12 | return a.every((x, i) => { 13 | return x.equals(b[i]); 14 | }); 15 | } 16 | // input: OP_0 [signatures ...] 17 | // output: m [pubKeys ...] n OP_CHECKMULTISIG 18 | function p2ms(a, opts) { 19 | if ( 20 | !a.input && 21 | !a.output && 22 | !(a.pubkeys && a.m !== undefined) && 23 | !a.signatures 24 | ) 25 | throw new TypeError('Not enough data'); 26 | opts = Object.assign({ validate: true }, opts || {}); 27 | function isAcceptableSignature(x) { 28 | return ( 29 | bscript.isCanonicalScriptSignature(x) || 30 | (opts.allowIncomplete && x === OPS.OP_0) !== undefined 31 | ); 32 | } 33 | typef( 34 | { 35 | network: typef.maybe(typef.Object), 36 | m: typef.maybe(typef.Number), 37 | n: typef.maybe(typef.Number), 38 | output: typef.maybe(typef.Buffer), 39 | pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)), 40 | signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)), 41 | input: typef.maybe(typef.Buffer), 42 | }, 43 | a, 44 | ); 45 | const network = a.network || networks_1.bitcoin; 46 | const o = { network }; 47 | let chunks = []; 48 | let decoded = false; 49 | function decode(output) { 50 | if (decoded) return; 51 | decoded = true; 52 | chunks = bscript.decompile(output); 53 | o.m = chunks[0] - OP_INT_BASE; 54 | o.n = chunks[chunks.length - 2] - OP_INT_BASE; 55 | o.pubkeys = chunks.slice(1, -2); 56 | } 57 | lazy.prop(o, 'output', () => { 58 | if (!a.m) return; 59 | if (!o.n) return; 60 | if (!a.pubkeys) return; 61 | return bscript.compile( 62 | [].concat( 63 | OP_INT_BASE + a.m, 64 | a.pubkeys, 65 | OP_INT_BASE + o.n, 66 | OPS.OP_CHECKMULTISIG, 67 | ), 68 | ); 69 | }); 70 | lazy.prop(o, 'm', () => { 71 | if (!o.output) return; 72 | decode(o.output); 73 | return o.m; 74 | }); 75 | lazy.prop(o, 'n', () => { 76 | if (!o.pubkeys) return; 77 | return o.pubkeys.length; 78 | }); 79 | lazy.prop(o, 'pubkeys', () => { 80 | if (!a.output) return; 81 | decode(a.output); 82 | return o.pubkeys; 83 | }); 84 | lazy.prop(o, 'signatures', () => { 85 | if (!a.input) return; 86 | return bscript.decompile(a.input).slice(1); 87 | }); 88 | lazy.prop(o, 'input', () => { 89 | if (!a.signatures) return; 90 | return bscript.compile([OPS.OP_0].concat(a.signatures)); 91 | }); 92 | lazy.prop(o, 'witness', () => { 93 | if (!o.input) return; 94 | return []; 95 | }); 96 | // extended validation 97 | if (opts.validate) { 98 | if (a.output) { 99 | decode(a.output); 100 | if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid'); 101 | if (!typef.Number(chunks[chunks.length - 2])) 102 | throw new TypeError('Output is invalid'); 103 | if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) 104 | throw new TypeError('Output is invalid'); 105 | if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3) 106 | throw new TypeError('Output is invalid'); 107 | if (!o.pubkeys.every(x => ecc.isPoint(x))) 108 | throw new TypeError('Output is invalid'); 109 | if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch'); 110 | if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch'); 111 | if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys)) 112 | throw new TypeError('Pubkeys mismatch'); 113 | } 114 | if (a.pubkeys) { 115 | if (a.n !== undefined && a.n !== a.pubkeys.length) 116 | throw new TypeError('Pubkey count mismatch'); 117 | o.n = a.pubkeys.length; 118 | if (o.n < o.m) throw new TypeError('Pubkey count cannot be less than m'); 119 | } 120 | if (a.signatures) { 121 | if (a.signatures.length < o.m) 122 | throw new TypeError('Not enough signatures provided'); 123 | if (a.signatures.length > o.m) 124 | throw new TypeError('Too many signatures provided'); 125 | } 126 | if (a.input) { 127 | if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid'); 128 | if ( 129 | o.signatures.length === 0 || 130 | !o.signatures.every(isAcceptableSignature) 131 | ) 132 | throw new TypeError('Input has invalid signature(s)'); 133 | if (a.signatures && !stacksEqual(a.signatures, o.signatures)) 134 | throw new TypeError('Signature mismatch'); 135 | if (a.m !== undefined && a.m !== a.signatures.length) 136 | throw new TypeError('Signature count mismatch'); 137 | } 138 | } 139 | return Object.assign(o, a); 140 | } 141 | exports.p2ms = p2ms; 142 | -------------------------------------------------------------------------------- /src/payments/p2pk.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const networks_1 = require('../networks'); 4 | const bscript = require('../script'); 5 | const lazy = require('./lazy'); 6 | const typef = require('typeforce'); 7 | const OPS = bscript.OPS; 8 | const ecc = require('tiny-secp256k1'); 9 | // input: {signature} 10 | // output: {pubKey} OP_CHECKSIG 11 | function p2pk(a, opts) { 12 | if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature) 13 | throw new TypeError('Not enough data'); 14 | opts = Object.assign({ validate: true }, opts || {}); 15 | typef( 16 | { 17 | network: typef.maybe(typef.Object), 18 | output: typef.maybe(typef.Buffer), 19 | pubkey: typef.maybe(ecc.isPoint), 20 | signature: typef.maybe(bscript.isCanonicalScriptSignature), 21 | input: typef.maybe(typef.Buffer), 22 | }, 23 | a, 24 | ); 25 | const _chunks = lazy.value(() => { 26 | return bscript.decompile(a.input); 27 | }); 28 | const network = a.network || networks_1.bitcoin; 29 | const o = { network }; 30 | lazy.prop(o, 'output', () => { 31 | if (!a.pubkey) return; 32 | return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]); 33 | }); 34 | lazy.prop(o, 'pubkey', () => { 35 | if (!a.output) return; 36 | return a.output.slice(1, -1); 37 | }); 38 | lazy.prop(o, 'signature', () => { 39 | if (!a.input) return; 40 | return _chunks()[0]; 41 | }); 42 | lazy.prop(o, 'input', () => { 43 | if (!a.signature) return; 44 | return bscript.compile([a.signature]); 45 | }); 46 | lazy.prop(o, 'witness', () => { 47 | if (!o.input) return; 48 | return []; 49 | }); 50 | // extended validation 51 | if (opts.validate) { 52 | if (a.output) { 53 | if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG) 54 | throw new TypeError('Output is invalid'); 55 | if (!ecc.isPoint(o.pubkey)) 56 | throw new TypeError('Output pubkey is invalid'); 57 | if (a.pubkey && !a.pubkey.equals(o.pubkey)) 58 | throw new TypeError('Pubkey mismatch'); 59 | } 60 | if (a.signature) { 61 | if (a.input && !a.input.equals(o.input)) 62 | throw new TypeError('Signature mismatch'); 63 | } 64 | if (a.input) { 65 | if (_chunks().length !== 1) throw new TypeError('Input is invalid'); 66 | if (!bscript.isCanonicalScriptSignature(o.signature)) 67 | throw new TypeError('Input has invalid signature'); 68 | } 69 | } 70 | return Object.assign(o, a); 71 | } 72 | exports.p2pk = p2pk; 73 | -------------------------------------------------------------------------------- /src/payments/p2pkh.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const bcrypto = require('../crypto'); 4 | const networks_1 = require('../networks'); 5 | const bscript = require('../script'); 6 | const lazy = require('./lazy'); 7 | const typef = require('typeforce'); 8 | const OPS = bscript.OPS; 9 | const ecc = require('tiny-secp256k1'); 10 | const bs58check = require('bs58check'); 11 | // input: {signature} {pubkey} 12 | // output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG 13 | function p2pkh(a, opts) { 14 | if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input) 15 | throw new TypeError('Not enough data'); 16 | opts = Object.assign({ validate: true }, opts || {}); 17 | typef( 18 | { 19 | network: typef.maybe(typef.Object), 20 | address: typef.maybe(typef.String), 21 | hash: typef.maybe(typef.BufferN(20)), 22 | output: typef.maybe(typef.BufferN(25)), 23 | pubkey: typef.maybe(ecc.isPoint), 24 | signature: typef.maybe(bscript.isCanonicalScriptSignature), 25 | input: typef.maybe(typef.Buffer), 26 | }, 27 | a, 28 | ); 29 | const _address = lazy.value(() => { 30 | const payload = bs58check.decode(a.address); 31 | const version = payload.readUInt8(0); 32 | const hash = payload.slice(1); 33 | return { version, hash }; 34 | }); 35 | const _chunks = lazy.value(() => { 36 | return bscript.decompile(a.input); 37 | }); 38 | const network = a.network || networks_1.bitcoin; 39 | const o = { network }; 40 | lazy.prop(o, 'address', () => { 41 | if (!o.hash) return; 42 | const payload = Buffer.allocUnsafe(21); 43 | payload.writeUInt8(network.pubKeyHash, 0); 44 | o.hash.copy(payload, 1); 45 | return bs58check.encode(payload); 46 | }); 47 | lazy.prop(o, 'hash', () => { 48 | if (a.output) return a.output.slice(3, 23); 49 | if (a.address) return _address().hash; 50 | if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey); 51 | }); 52 | lazy.prop(o, 'output', () => { 53 | if (!o.hash) return; 54 | return bscript.compile([ 55 | OPS.OP_DUP, 56 | OPS.OP_HASH160, 57 | o.hash, 58 | OPS.OP_EQUALVERIFY, 59 | OPS.OP_CHECKSIG, 60 | ]); 61 | }); 62 | lazy.prop(o, 'pubkey', () => { 63 | if (!a.input) return; 64 | return _chunks()[1]; 65 | }); 66 | lazy.prop(o, 'signature', () => { 67 | if (!a.input) return; 68 | return _chunks()[0]; 69 | }); 70 | lazy.prop(o, 'input', () => { 71 | if (!a.pubkey) return; 72 | if (!a.signature) return; 73 | return bscript.compile([a.signature, a.pubkey]); 74 | }); 75 | lazy.prop(o, 'witness', () => { 76 | if (!o.input) return; 77 | return []; 78 | }); 79 | // extended validation 80 | if (opts.validate) { 81 | let hash = Buffer.from([]); 82 | if (a.address) { 83 | if (_address().version !== network.pubKeyHash) 84 | throw new TypeError('Invalid version or Network mismatch'); 85 | if (_address().hash.length !== 20) throw new TypeError('Invalid address'); 86 | hash = _address().hash; 87 | } 88 | if (a.hash) { 89 | if (hash.length > 0 && !hash.equals(a.hash)) 90 | throw new TypeError('Hash mismatch'); 91 | else hash = a.hash; 92 | } 93 | if (a.output) { 94 | if ( 95 | a.output.length !== 25 || 96 | a.output[0] !== OPS.OP_DUP || 97 | a.output[1] !== OPS.OP_HASH160 || 98 | a.output[2] !== 0x14 || 99 | a.output[23] !== OPS.OP_EQUALVERIFY || 100 | a.output[24] !== OPS.OP_CHECKSIG 101 | ) 102 | throw new TypeError('Output is invalid'); 103 | const hash2 = a.output.slice(3, 23); 104 | if (hash.length > 0 && !hash.equals(hash2)) 105 | throw new TypeError('Hash mismatch'); 106 | else hash = hash2; 107 | } 108 | if (a.pubkey) { 109 | const pkh = bcrypto.hash160(a.pubkey); 110 | if (hash.length > 0 && !hash.equals(pkh)) 111 | throw new TypeError('Hash mismatch'); 112 | else hash = pkh; 113 | } 114 | if (a.input) { 115 | const chunks = _chunks(); 116 | if (chunks.length !== 2) throw new TypeError('Input is invalid'); 117 | if (!bscript.isCanonicalScriptSignature(chunks[0])) 118 | throw new TypeError('Input has invalid signature'); 119 | if (!ecc.isPoint(chunks[1])) 120 | throw new TypeError('Input has invalid pubkey'); 121 | if (a.signature && !a.signature.equals(chunks[0])) 122 | throw new TypeError('Signature mismatch'); 123 | if (a.pubkey && !a.pubkey.equals(chunks[1])) 124 | throw new TypeError('Pubkey mismatch'); 125 | const pkh = bcrypto.hash160(chunks[1]); 126 | if (hash.length > 0 && !hash.equals(pkh)) 127 | throw new TypeError('Hash mismatch'); 128 | } 129 | } 130 | return Object.assign(o, a); 131 | } 132 | exports.p2pkh = p2pkh; 133 | -------------------------------------------------------------------------------- /src/payments/p2sh.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const bcrypto = require('../crypto'); 4 | const networks_1 = require('../networks'); 5 | const bscript = require('../script'); 6 | const lazy = require('./lazy'); 7 | const typef = require('typeforce'); 8 | const OPS = bscript.OPS; 9 | const bs58check = require('bs58check'); 10 | function stacksEqual(a, b) { 11 | if (a.length !== b.length) return false; 12 | return a.every((x, i) => { 13 | return x.equals(b[i]); 14 | }); 15 | } 16 | // input: [redeemScriptSig ...] {redeemScript} 17 | // witness: 18 | // output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL 19 | function p2sh(a, opts) { 20 | if (!a.address && !a.hash && !a.output && !a.redeem && !a.input) 21 | throw new TypeError('Not enough data'); 22 | opts = Object.assign({ validate: true }, opts || {}); 23 | typef( 24 | { 25 | network: typef.maybe(typef.Object), 26 | address: typef.maybe(typef.String), 27 | hash: typef.maybe(typef.BufferN(20)), 28 | output: typef.maybe(typef.BufferN(23)), 29 | redeem: typef.maybe({ 30 | network: typef.maybe(typef.Object), 31 | output: typef.maybe(typef.Buffer), 32 | input: typef.maybe(typef.Buffer), 33 | witness: typef.maybe(typef.arrayOf(typef.Buffer)), 34 | }), 35 | input: typef.maybe(typef.Buffer), 36 | witness: typef.maybe(typef.arrayOf(typef.Buffer)), 37 | }, 38 | a, 39 | ); 40 | let network = a.network; 41 | if (!network) { 42 | network = (a.redeem && a.redeem.network) || networks_1.bitcoin; 43 | } 44 | const o = { network }; 45 | const _address = lazy.value(() => { 46 | const payload = bs58check.decode(a.address); 47 | const version = payload.readUInt8(0); 48 | const hash = payload.slice(1); 49 | return { version, hash }; 50 | }); 51 | const _chunks = lazy.value(() => { 52 | return bscript.decompile(a.input); 53 | }); 54 | const _redeem = lazy.value(() => { 55 | const chunks = _chunks(); 56 | return { 57 | network, 58 | output: chunks[chunks.length - 1], 59 | input: bscript.compile(chunks.slice(0, -1)), 60 | witness: a.witness || [], 61 | }; 62 | }); 63 | // output dependents 64 | lazy.prop(o, 'address', () => { 65 | if (!o.hash) return; 66 | const payload = Buffer.allocUnsafe(21); 67 | payload.writeUInt8(o.network.scriptHash, 0); 68 | o.hash.copy(payload, 1); 69 | return bs58check.encode(payload); 70 | }); 71 | lazy.prop(o, 'hash', () => { 72 | // in order of least effort 73 | if (a.output) return a.output.slice(2, 22); 74 | if (a.address) return _address().hash; 75 | if (o.redeem && o.redeem.output) return bcrypto.hash160(o.redeem.output); 76 | }); 77 | lazy.prop(o, 'output', () => { 78 | if (!o.hash) return; 79 | return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]); 80 | }); 81 | // input dependents 82 | lazy.prop(o, 'redeem', () => { 83 | if (!a.input) return; 84 | return _redeem(); 85 | }); 86 | lazy.prop(o, 'input', () => { 87 | if (!a.redeem || !a.redeem.input || !a.redeem.output) return; 88 | return bscript.compile( 89 | [].concat(bscript.decompile(a.redeem.input), a.redeem.output), 90 | ); 91 | }); 92 | lazy.prop(o, 'witness', () => { 93 | if (o.redeem && o.redeem.witness) return o.redeem.witness; 94 | if (o.input) return []; 95 | }); 96 | if (opts.validate) { 97 | let hash = Buffer.from([]); 98 | if (a.address) { 99 | if (_address().version !== network.scriptHash) 100 | throw new TypeError('Invalid version or Network mismatch'); 101 | if (_address().hash.length !== 20) throw new TypeError('Invalid address'); 102 | hash = _address().hash; 103 | } 104 | if (a.hash) { 105 | if (hash.length > 0 && !hash.equals(a.hash)) 106 | throw new TypeError('Hash mismatch'); 107 | else hash = a.hash; 108 | } 109 | if (a.output) { 110 | if ( 111 | a.output.length !== 23 || 112 | a.output[0] !== OPS.OP_HASH160 || 113 | a.output[1] !== 0x14 || 114 | a.output[22] !== OPS.OP_EQUAL 115 | ) 116 | throw new TypeError('Output is invalid'); 117 | const hash2 = a.output.slice(2, 22); 118 | if (hash.length > 0 && !hash.equals(hash2)) 119 | throw new TypeError('Hash mismatch'); 120 | else hash = hash2; 121 | } 122 | // inlined to prevent 'no-inner-declarations' failing 123 | const checkRedeem = redeem => { 124 | // is the redeem output empty/invalid? 125 | if (redeem.output) { 126 | const decompile = bscript.decompile(redeem.output); 127 | if (!decompile || decompile.length < 1) 128 | throw new TypeError('Redeem.output too short'); 129 | // match hash against other sources 130 | const hash2 = bcrypto.hash160(redeem.output); 131 | if (hash.length > 0 && !hash.equals(hash2)) 132 | throw new TypeError('Hash mismatch'); 133 | else hash = hash2; 134 | } 135 | if (redeem.input) { 136 | const hasInput = redeem.input.length > 0; 137 | const hasWitness = redeem.witness && redeem.witness.length > 0; 138 | if (!hasInput && !hasWitness) throw new TypeError('Empty input'); 139 | if (hasInput && hasWitness) 140 | throw new TypeError('Input and witness provided'); 141 | if (hasInput) { 142 | const richunks = bscript.decompile(redeem.input); 143 | if (!bscript.isPushOnly(richunks)) 144 | throw new TypeError('Non push-only scriptSig'); 145 | } 146 | } 147 | }; 148 | if (a.input) { 149 | const chunks = _chunks(); 150 | if (!chunks || chunks.length < 1) throw new TypeError('Input too short'); 151 | if (!Buffer.isBuffer(_redeem().output)) 152 | throw new TypeError('Input is invalid'); 153 | checkRedeem(_redeem()); 154 | } 155 | if (a.redeem) { 156 | if (a.redeem.network && a.redeem.network !== network) 157 | throw new TypeError('Network mismatch'); 158 | if (a.input) { 159 | const redeem = _redeem(); 160 | if (a.redeem.output && !a.redeem.output.equals(redeem.output)) 161 | throw new TypeError('Redeem.output mismatch'); 162 | if (a.redeem.input && !a.redeem.input.equals(redeem.input)) 163 | throw new TypeError('Redeem.input mismatch'); 164 | } 165 | checkRedeem(a.redeem); 166 | } 167 | if (a.witness) { 168 | if ( 169 | a.redeem && 170 | a.redeem.witness && 171 | !stacksEqual(a.redeem.witness, a.witness) 172 | ) 173 | throw new TypeError('Witness and redeem.witness mismatch'); 174 | } 175 | } 176 | return Object.assign(o, a); 177 | } 178 | exports.p2sh = p2sh; 179 | -------------------------------------------------------------------------------- /src/payments/p2wpkh.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const bcrypto = require('../crypto'); 4 | const networks_1 = require('../networks'); 5 | const bscript = require('../script'); 6 | const lazy = require('./lazy'); 7 | const typef = require('typeforce'); 8 | const OPS = bscript.OPS; 9 | const ecc = require('tiny-secp256k1'); 10 | const bech32 = require('bech32'); 11 | const EMPTY_BUFFER = Buffer.alloc(0); 12 | // witness: {signature} {pubKey} 13 | // input: <> 14 | // output: OP_0 {pubKeyHash} 15 | function p2wpkh(a, opts) { 16 | if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness) 17 | throw new TypeError('Not enough data'); 18 | opts = Object.assign({ validate: true }, opts || {}); 19 | typef( 20 | { 21 | address: typef.maybe(typef.String), 22 | hash: typef.maybe(typef.BufferN(20)), 23 | input: typef.maybe(typef.BufferN(0)), 24 | network: typef.maybe(typef.Object), 25 | output: typef.maybe(typef.BufferN(22)), 26 | pubkey: typef.maybe(ecc.isPoint), 27 | signature: typef.maybe(bscript.isCanonicalScriptSignature), 28 | witness: typef.maybe(typef.arrayOf(typef.Buffer)), 29 | }, 30 | a, 31 | ); 32 | const _address = lazy.value(() => { 33 | const result = bech32.decode(a.address); 34 | const version = result.words.shift(); 35 | const data = bech32.fromWords(result.words); 36 | return { 37 | version, 38 | prefix: result.prefix, 39 | data: Buffer.from(data), 40 | }; 41 | }); 42 | const network = a.network || networks_1.bitcoin; 43 | const o = { network }; 44 | lazy.prop(o, 'address', () => { 45 | if (!o.hash) return; 46 | const words = bech32.toWords(o.hash); 47 | words.unshift(0x00); 48 | return bech32.encode(network.bech32, words); 49 | }); 50 | lazy.prop(o, 'hash', () => { 51 | if (a.output) return a.output.slice(2, 22); 52 | if (a.address) return _address().data; 53 | if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey); 54 | }); 55 | lazy.prop(o, 'output', () => { 56 | if (!o.hash) return; 57 | return bscript.compile([OPS.OP_0, o.hash]); 58 | }); 59 | lazy.prop(o, 'pubkey', () => { 60 | if (a.pubkey) return a.pubkey; 61 | if (!a.witness) return; 62 | return a.witness[1]; 63 | }); 64 | lazy.prop(o, 'signature', () => { 65 | if (!a.witness) return; 66 | return a.witness[0]; 67 | }); 68 | lazy.prop(o, 'input', () => { 69 | if (!o.witness) return; 70 | return EMPTY_BUFFER; 71 | }); 72 | lazy.prop(o, 'witness', () => { 73 | if (!a.pubkey) return; 74 | if (!a.signature) return; 75 | return [a.signature, a.pubkey]; 76 | }); 77 | // extended validation 78 | if (opts.validate) { 79 | let hash = Buffer.from([]); 80 | if (a.address) { 81 | if (network && network.bech32 !== _address().prefix) 82 | throw new TypeError('Invalid prefix or Network mismatch'); 83 | if (_address().version !== 0x00) 84 | throw new TypeError('Invalid address version'); 85 | if (_address().data.length !== 20) 86 | throw new TypeError('Invalid address data'); 87 | hash = _address().data; 88 | } 89 | if (a.hash) { 90 | if (hash.length > 0 && !hash.equals(a.hash)) 91 | throw new TypeError('Hash mismatch'); 92 | else hash = a.hash; 93 | } 94 | if (a.output) { 95 | if ( 96 | a.output.length !== 22 || 97 | a.output[0] !== OPS.OP_0 || 98 | a.output[1] !== 0x14 99 | ) 100 | throw new TypeError('Output is invalid'); 101 | if (hash.length > 0 && !hash.equals(a.output.slice(2))) 102 | throw new TypeError('Hash mismatch'); 103 | else hash = a.output.slice(2); 104 | } 105 | if (a.pubkey) { 106 | const pkh = bcrypto.hash160(a.pubkey); 107 | if (hash.length > 0 && !hash.equals(pkh)) 108 | throw new TypeError('Hash mismatch'); 109 | else hash = pkh; 110 | } 111 | if (a.witness) { 112 | if (a.witness.length !== 2) throw new TypeError('Witness is invalid'); 113 | if (!bscript.isCanonicalScriptSignature(a.witness[0])) 114 | throw new TypeError('Witness has invalid signature'); 115 | if (!ecc.isPoint(a.witness[1])) 116 | throw new TypeError('Witness has invalid pubkey'); 117 | if (a.signature && !a.signature.equals(a.witness[0])) 118 | throw new TypeError('Signature mismatch'); 119 | if (a.pubkey && !a.pubkey.equals(a.witness[1])) 120 | throw new TypeError('Pubkey mismatch'); 121 | const pkh = bcrypto.hash160(a.witness[1]); 122 | if (hash.length > 0 && !hash.equals(pkh)) 123 | throw new TypeError('Hash mismatch'); 124 | } 125 | } 126 | return Object.assign(o, a); 127 | } 128 | exports.p2wpkh = p2wpkh; 129 | -------------------------------------------------------------------------------- /src/payments/p2wsh.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const bcrypto = require('../crypto'); 4 | const networks_1 = require('../networks'); 5 | const bscript = require('../script'); 6 | const lazy = require('./lazy'); 7 | const typef = require('typeforce'); 8 | const OPS = bscript.OPS; 9 | const bech32 = require('bech32'); 10 | const EMPTY_BUFFER = Buffer.alloc(0); 11 | function stacksEqual(a, b) { 12 | if (a.length !== b.length) return false; 13 | return a.every((x, i) => { 14 | return x.equals(b[i]); 15 | }); 16 | } 17 | // input: <> 18 | // witness: [redeemScriptSig ...] {redeemScript} 19 | // output: OP_0 {sha256(redeemScript)} 20 | function p2wsh(a, opts) { 21 | if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness) 22 | throw new TypeError('Not enough data'); 23 | opts = Object.assign({ validate: true }, opts || {}); 24 | typef( 25 | { 26 | network: typef.maybe(typef.Object), 27 | address: typef.maybe(typef.String), 28 | hash: typef.maybe(typef.BufferN(32)), 29 | output: typef.maybe(typef.BufferN(34)), 30 | redeem: typef.maybe({ 31 | input: typef.maybe(typef.Buffer), 32 | network: typef.maybe(typef.Object), 33 | output: typef.maybe(typef.Buffer), 34 | witness: typef.maybe(typef.arrayOf(typef.Buffer)), 35 | }), 36 | input: typef.maybe(typef.BufferN(0)), 37 | witness: typef.maybe(typef.arrayOf(typef.Buffer)), 38 | }, 39 | a, 40 | ); 41 | const _address = lazy.value(() => { 42 | const result = bech32.decode(a.address); 43 | const version = result.words.shift(); 44 | const data = bech32.fromWords(result.words); 45 | return { 46 | version, 47 | prefix: result.prefix, 48 | data: Buffer.from(data), 49 | }; 50 | }); 51 | const _rchunks = lazy.value(() => { 52 | return bscript.decompile(a.redeem.input); 53 | }); 54 | let network = a.network; 55 | if (!network) { 56 | network = (a.redeem && a.redeem.network) || networks_1.bitcoin; 57 | } 58 | const o = { network }; 59 | lazy.prop(o, 'address', () => { 60 | if (!o.hash) return; 61 | const words = bech32.toWords(o.hash); 62 | words.unshift(0x00); 63 | return bech32.encode(network.bech32, words); 64 | }); 65 | lazy.prop(o, 'hash', () => { 66 | if (a.output) return a.output.slice(2); 67 | if (a.address) return _address().data; 68 | if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output); 69 | }); 70 | lazy.prop(o, 'output', () => { 71 | if (!o.hash) return; 72 | return bscript.compile([OPS.OP_0, o.hash]); 73 | }); 74 | lazy.prop(o, 'redeem', () => { 75 | if (!a.witness) return; 76 | return { 77 | output: a.witness[a.witness.length - 1], 78 | input: EMPTY_BUFFER, 79 | witness: a.witness.slice(0, -1), 80 | }; 81 | }); 82 | lazy.prop(o, 'input', () => { 83 | if (!o.witness) return; 84 | return EMPTY_BUFFER; 85 | }); 86 | lazy.prop(o, 'witness', () => { 87 | // transform redeem input to witness stack? 88 | if ( 89 | a.redeem && 90 | a.redeem.input && 91 | a.redeem.input.length > 0 && 92 | a.redeem.output && 93 | a.redeem.output.length > 0 94 | ) { 95 | const stack = bscript.toStack(_rchunks()); 96 | // assign, and blank the existing input 97 | o.redeem = Object.assign({ witness: stack }, a.redeem); 98 | o.redeem.input = EMPTY_BUFFER; 99 | return [].concat(stack, a.redeem.output); 100 | } 101 | if (!a.redeem) return; 102 | if (!a.redeem.output) return; 103 | if (!a.redeem.witness) return; 104 | return [].concat(a.redeem.witness, a.redeem.output); 105 | }); 106 | // extended validation 107 | if (opts.validate) { 108 | let hash = Buffer.from([]); 109 | if (a.address) { 110 | if (_address().prefix !== network.bech32) 111 | throw new TypeError('Invalid prefix or Network mismatch'); 112 | if (_address().version !== 0x00) 113 | throw new TypeError('Invalid address version'); 114 | if (_address().data.length !== 32) 115 | throw new TypeError('Invalid address data'); 116 | hash = _address().data; 117 | } 118 | if (a.hash) { 119 | if (hash.length > 0 && !hash.equals(a.hash)) 120 | throw new TypeError('Hash mismatch'); 121 | else hash = a.hash; 122 | } 123 | if (a.output) { 124 | if ( 125 | a.output.length !== 34 || 126 | a.output[0] !== OPS.OP_0 || 127 | a.output[1] !== 0x20 128 | ) 129 | throw new TypeError('Output is invalid'); 130 | const hash2 = a.output.slice(2); 131 | if (hash.length > 0 && !hash.equals(hash2)) 132 | throw new TypeError('Hash mismatch'); 133 | else hash = hash2; 134 | } 135 | if (a.redeem) { 136 | if (a.redeem.network && a.redeem.network !== network) 137 | throw new TypeError('Network mismatch'); 138 | // is there two redeem sources? 139 | if ( 140 | a.redeem.input && 141 | a.redeem.input.length > 0 && 142 | a.redeem.witness && 143 | a.redeem.witness.length > 0 144 | ) 145 | throw new TypeError('Ambiguous witness source'); 146 | // is the redeem output non-empty? 147 | if (a.redeem.output) { 148 | if (bscript.decompile(a.redeem.output).length === 0) 149 | throw new TypeError('Redeem.output is invalid'); 150 | // match hash against other sources 151 | const hash2 = bcrypto.sha256(a.redeem.output); 152 | if (hash.length > 0 && !hash.equals(hash2)) 153 | throw new TypeError('Hash mismatch'); 154 | else hash = hash2; 155 | } 156 | if (a.redeem.input && !bscript.isPushOnly(_rchunks())) 157 | throw new TypeError('Non push-only scriptSig'); 158 | if ( 159 | a.witness && 160 | a.redeem.witness && 161 | !stacksEqual(a.witness, a.redeem.witness) 162 | ) 163 | throw new TypeError('Witness and redeem.witness mismatch'); 164 | } 165 | if (a.witness) { 166 | if ( 167 | a.redeem && 168 | a.redeem.output && 169 | !a.redeem.output.equals(a.witness[a.witness.length - 1]) 170 | ) 171 | throw new TypeError('Witness and redeem.output mismatch'); 172 | } 173 | } 174 | return Object.assign(o, a); 175 | } 176 | exports.p2wsh = p2wsh; 177 | -------------------------------------------------------------------------------- /src/script.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const scriptNumber = require('./script_number'); 4 | const scriptSignature = require('./script_signature'); 5 | const types = require('./types'); 6 | const bip66 = require('bip66'); 7 | const ecc = require('tiny-secp256k1'); 8 | const pushdata = require('pushdata-bitcoin'); 9 | const typeforce = require('typeforce'); 10 | exports.OPS = require('bitcoin-ops'); 11 | const REVERSE_OPS = require('bitcoin-ops/map'); 12 | const OP_INT_BASE = exports.OPS.OP_RESERVED; // OP_1 - 1 13 | function isOPInt(value) { 14 | return ( 15 | types.Number(value) && 16 | (value === exports.OPS.OP_0 || 17 | (value >= exports.OPS.OP_1 && value <= exports.OPS.OP_16) || 18 | value === exports.OPS.OP_1NEGATE) 19 | ); 20 | } 21 | function isPushOnlyChunk(value) { 22 | return types.Buffer(value) || isOPInt(value); 23 | } 24 | function isPushOnly(value) { 25 | return types.Array(value) && value.every(isPushOnlyChunk); 26 | } 27 | exports.isPushOnly = isPushOnly; 28 | function asMinimalOP(buffer) { 29 | if (buffer.length === 0) return exports.OPS.OP_0; 30 | if (buffer.length !== 1) return; 31 | if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0]; 32 | if (buffer[0] === 0x81) return exports.OPS.OP_1NEGATE; 33 | } 34 | function chunksIsBuffer(buf) { 35 | return Buffer.isBuffer(buf); 36 | } 37 | function chunksIsArray(buf) { 38 | return types.Array(buf); 39 | } 40 | function singleChunkIsBuffer(buf) { 41 | return Buffer.isBuffer(buf); 42 | } 43 | function compile(chunks) { 44 | // TODO: remove me 45 | if (chunksIsBuffer(chunks)) return chunks; 46 | typeforce(types.Array, chunks); 47 | const bufferSize = chunks.reduce((accum, chunk) => { 48 | // data chunk 49 | if (singleChunkIsBuffer(chunk)) { 50 | // adhere to BIP62.3, minimal push policy 51 | if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) { 52 | return accum + 1; 53 | } 54 | return accum + pushdata.encodingLength(chunk.length) + chunk.length; 55 | } 56 | // opcode 57 | return accum + 1; 58 | }, 0.0); 59 | const buffer = Buffer.allocUnsafe(bufferSize); 60 | let offset = 0; 61 | chunks.forEach(chunk => { 62 | // data chunk 63 | if (singleChunkIsBuffer(chunk)) { 64 | // adhere to BIP62.3, minimal push policy 65 | const opcode = asMinimalOP(chunk); 66 | if (opcode !== undefined) { 67 | buffer.writeUInt8(opcode, offset); 68 | offset += 1; 69 | return; 70 | } 71 | offset += pushdata.encode(buffer, chunk.length, offset); 72 | chunk.copy(buffer, offset); 73 | offset += chunk.length; 74 | // opcode 75 | } else { 76 | buffer.writeUInt8(chunk, offset); 77 | offset += 1; 78 | } 79 | }); 80 | if (offset !== buffer.length) throw new Error('Could not decode chunks'); 81 | return buffer; 82 | } 83 | exports.compile = compile; 84 | function decompile(buffer) { 85 | // TODO: remove me 86 | if (chunksIsArray(buffer)) return buffer; 87 | typeforce(types.Buffer, buffer); 88 | const chunks = []; 89 | let i = 0; 90 | while (i < buffer.length) { 91 | const opcode = buffer[i]; 92 | // data chunk 93 | if (opcode > exports.OPS.OP_0 && opcode <= exports.OPS.OP_PUSHDATA4) { 94 | const d = pushdata.decode(buffer, i); 95 | // did reading a pushDataInt fail? 96 | if (d === null) return null; 97 | i += d.size; 98 | // attempt to read too much data? 99 | if (i + d.number > buffer.length) return null; 100 | const data = buffer.slice(i, i + d.number); 101 | i += d.number; 102 | // decompile minimally 103 | const op = asMinimalOP(data); 104 | if (op !== undefined) { 105 | chunks.push(op); 106 | } else { 107 | chunks.push(data); 108 | } 109 | // opcode 110 | } else { 111 | chunks.push(opcode); 112 | i += 1; 113 | } 114 | } 115 | return chunks; 116 | } 117 | exports.decompile = decompile; 118 | function toASM(chunks) { 119 | if (chunksIsBuffer(chunks)) { 120 | chunks = decompile(chunks); 121 | } 122 | return chunks 123 | .map(chunk => { 124 | // data? 125 | if (singleChunkIsBuffer(chunk)) { 126 | const op = asMinimalOP(chunk); 127 | if (op === undefined) return chunk.toString('hex'); 128 | chunk = op; 129 | } 130 | // opcode! 131 | return REVERSE_OPS[chunk]; 132 | }) 133 | .join(' '); 134 | } 135 | exports.toASM = toASM; 136 | function fromASM(asm) { 137 | typeforce(types.String, asm); 138 | return compile( 139 | asm.split(' ').map(chunkStr => { 140 | // opcode? 141 | if (exports.OPS[chunkStr] !== undefined) return exports.OPS[chunkStr]; 142 | typeforce(types.Hex, chunkStr); 143 | // data! 144 | return Buffer.from(chunkStr, 'hex'); 145 | }), 146 | ); 147 | } 148 | exports.fromASM = fromASM; 149 | function toStack(chunks) { 150 | chunks = decompile(chunks); 151 | typeforce(isPushOnly, chunks); 152 | return chunks.map(op => { 153 | if (singleChunkIsBuffer(op)) return op; 154 | if (op === exports.OPS.OP_0) return Buffer.allocUnsafe(0); 155 | return scriptNumber.encode(op - OP_INT_BASE); 156 | }); 157 | } 158 | exports.toStack = toStack; 159 | function isCanonicalPubKey(buffer) { 160 | return ecc.isPoint(buffer); 161 | } 162 | exports.isCanonicalPubKey = isCanonicalPubKey; 163 | function isDefinedHashType(hashType) { 164 | const hashTypeMod = hashType & ~0x80; 165 | // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE 166 | return hashTypeMod > 0x00 && hashTypeMod < 0x04; 167 | } 168 | exports.isDefinedHashType = isDefinedHashType; 169 | function isCanonicalScriptSignature(buffer) { 170 | if (!Buffer.isBuffer(buffer)) return false; 171 | if (!isDefinedHashType(buffer[buffer.length - 1])) return false; 172 | return bip66.check(buffer.slice(0, -1)); 173 | } 174 | exports.isCanonicalScriptSignature = isCanonicalScriptSignature; 175 | // tslint:disable-next-line variable-name 176 | exports.number = scriptNumber; 177 | exports.signature = scriptSignature; 178 | -------------------------------------------------------------------------------- /src/script_number.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | function decode(buffer, maxLength, minimal) { 4 | maxLength = maxLength || 4; 5 | minimal = minimal === undefined ? true : minimal; 6 | const length = buffer.length; 7 | if (length === 0) return 0; 8 | if (length > maxLength) throw new TypeError('Script number overflow'); 9 | if (minimal) { 10 | if ((buffer[length - 1] & 0x7f) === 0) { 11 | if (length <= 1 || (buffer[length - 2] & 0x80) === 0) 12 | throw new Error('Non-minimally encoded script number'); 13 | } 14 | } 15 | // 40-bit 16 | if (length === 5) { 17 | const a = buffer.readUInt32LE(0); 18 | const b = buffer.readUInt8(4); 19 | if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a); 20 | return b * 0x100000000 + a; 21 | } 22 | // 32-bit / 24-bit / 16-bit / 8-bit 23 | let result = 0; 24 | for (let i = 0; i < length; ++i) { 25 | result |= buffer[i] << (8 * i); 26 | } 27 | if (buffer[length - 1] & 0x80) 28 | return -(result & ~(0x80 << (8 * (length - 1)))); 29 | return result; 30 | } 31 | exports.decode = decode; 32 | function scriptNumSize(i) { 33 | return i > 0x7fffffff 34 | ? 5 35 | : i > 0x7fffff 36 | ? 4 37 | : i > 0x7fff 38 | ? 3 39 | : i > 0x7f 40 | ? 2 41 | : i > 0x00 42 | ? 1 43 | : 0; 44 | } 45 | function encode(_number) { 46 | let value = Math.abs(_number); 47 | const size = scriptNumSize(value); 48 | const buffer = Buffer.allocUnsafe(size); 49 | const negative = _number < 0; 50 | for (let i = 0; i < size; ++i) { 51 | buffer.writeUInt8(value & 0xff, i); 52 | value >>= 8; 53 | } 54 | if (buffer[size - 1] & 0x80) { 55 | buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1); 56 | } else if (negative) { 57 | buffer[size - 1] |= 0x80; 58 | } 59 | return buffer; 60 | } 61 | exports.encode = encode; 62 | -------------------------------------------------------------------------------- /src/script_signature.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const types = require('./types'); 4 | const bip66 = require('bip66'); 5 | const typeforce = require('typeforce'); 6 | const ZERO = Buffer.alloc(1, 0); 7 | function toDER(x) { 8 | let i = 0; 9 | while (x[i] === 0) ++i; 10 | if (i === x.length) return ZERO; 11 | x = x.slice(i); 12 | if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length); 13 | return x; 14 | } 15 | function fromDER(x) { 16 | if (x[0] === 0x00) x = x.slice(1); 17 | const buffer = Buffer.alloc(32, 0); 18 | const bstart = Math.max(0, 32 - x.length); 19 | x.copy(buffer, bstart); 20 | return buffer; 21 | } 22 | // BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) 23 | function decode(buffer) { 24 | const hashType = buffer.readUInt8(buffer.length - 1); 25 | const hashTypeMod = hashType & ~0x80; 26 | if (hashTypeMod <= 0 || hashTypeMod >= 4) 27 | throw new Error('Invalid hashType ' + hashType); 28 | const decoded = bip66.decode(buffer.slice(0, -1)); 29 | const r = fromDER(decoded.r); 30 | const s = fromDER(decoded.s); 31 | const signature = Buffer.concat([r, s], 64); 32 | return { signature, hashType }; 33 | } 34 | exports.decode = decode; 35 | function encode(signature, hashType) { 36 | typeforce( 37 | { 38 | signature: types.BufferN(64), 39 | hashType: types.UInt8, 40 | }, 41 | { signature, hashType }, 42 | ); 43 | const hashTypeMod = hashType & ~0x80; 44 | if (hashTypeMod <= 0 || hashTypeMod >= 4) 45 | throw new Error('Invalid hashType ' + hashType); 46 | const hashTypeBuffer = Buffer.allocUnsafe(1); 47 | hashTypeBuffer.writeUInt8(hashType, 0); 48 | const r = toDER(signature.slice(0, 32)); 49 | const s = toDER(signature.slice(32, 64)); 50 | return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]); 51 | } 52 | exports.encode = encode; 53 | -------------------------------------------------------------------------------- /src/templates/multisig/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const input = require('./input'); 4 | exports.input = input; 5 | const output = require('./output'); 6 | exports.output = output; 7 | -------------------------------------------------------------------------------- /src/templates/multisig/input.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // OP_0 [signatures ...] 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | const script_1 = require('../../script'); 6 | function partialSignature(value) { 7 | return ( 8 | value === script_1.OPS.OP_0 || bscript.isCanonicalScriptSignature(value) 9 | ); 10 | } 11 | function check(script, allowIncomplete) { 12 | const chunks = bscript.decompile(script); 13 | if (chunks.length < 2) return false; 14 | if (chunks[0] !== script_1.OPS.OP_0) return false; 15 | if (allowIncomplete) { 16 | return chunks.slice(1).every(partialSignature); 17 | } 18 | return chunks.slice(1).every(bscript.isCanonicalScriptSignature); 19 | } 20 | exports.check = check; 21 | check.toJSON = () => { 22 | return 'multisig input'; 23 | }; 24 | -------------------------------------------------------------------------------- /src/templates/multisig/output.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // m [pubKeys ...] n OP_CHECKMULTISIG 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | const script_1 = require('../../script'); 6 | const types = require('../../types'); 7 | const OP_INT_BASE = script_1.OPS.OP_RESERVED; // OP_1 - 1 8 | function check(script, allowIncomplete) { 9 | const chunks = bscript.decompile(script); 10 | if (chunks.length < 4) return false; 11 | if (chunks[chunks.length - 1] !== script_1.OPS.OP_CHECKMULTISIG) return false; 12 | if (!types.Number(chunks[0])) return false; 13 | if (!types.Number(chunks[chunks.length - 2])) return false; 14 | const m = chunks[0] - OP_INT_BASE; 15 | const n = chunks[chunks.length - 2] - OP_INT_BASE; 16 | if (m <= 0) return false; 17 | if (n > 16) return false; 18 | if (m > n) return false; 19 | if (n !== chunks.length - 3) return false; 20 | if (allowIncomplete) return true; 21 | const keys = chunks.slice(1, -2); 22 | return keys.every(bscript.isCanonicalPubKey); 23 | } 24 | exports.check = check; 25 | check.toJSON = () => { 26 | return 'multi-sig output'; 27 | }; 28 | -------------------------------------------------------------------------------- /src/templates/nulldata.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | // OP_RETURN {data} 4 | const bscript = require('../script'); 5 | const OPS = bscript.OPS; 6 | function check(script) { 7 | const buffer = bscript.compile(script); 8 | return buffer.length > 1 && buffer[0] === OPS.OP_RETURN; 9 | } 10 | exports.check = check; 11 | check.toJSON = () => { 12 | return 'null data output'; 13 | }; 14 | const output = { check }; 15 | exports.output = output; 16 | -------------------------------------------------------------------------------- /src/templates/pubkey/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const input = require('./input'); 4 | exports.input = input; 5 | const output = require('./output'); 6 | exports.output = output; 7 | -------------------------------------------------------------------------------- /src/templates/pubkey/input.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // {signature} 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | function check(script) { 6 | const chunks = bscript.decompile(script); 7 | return chunks.length === 1 && bscript.isCanonicalScriptSignature(chunks[0]); 8 | } 9 | exports.check = check; 10 | check.toJSON = () => { 11 | return 'pubKey input'; 12 | }; 13 | -------------------------------------------------------------------------------- /src/templates/pubkey/output.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // {pubKey} OP_CHECKSIG 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | const script_1 = require('../../script'); 6 | function check(script) { 7 | const chunks = bscript.decompile(script); 8 | return ( 9 | chunks.length === 2 && 10 | bscript.isCanonicalPubKey(chunks[0]) && 11 | chunks[1] === script_1.OPS.OP_CHECKSIG 12 | ); 13 | } 14 | exports.check = check; 15 | check.toJSON = () => { 16 | return 'pubKey output'; 17 | }; 18 | -------------------------------------------------------------------------------- /src/templates/pubkeyhash/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const input = require('./input'); 4 | exports.input = input; 5 | const output = require('./output'); 6 | exports.output = output; 7 | -------------------------------------------------------------------------------- /src/templates/pubkeyhash/input.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // {signature} {pubKey} 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | function check(script) { 6 | const chunks = bscript.decompile(script); 7 | return ( 8 | chunks.length === 2 && 9 | bscript.isCanonicalScriptSignature(chunks[0]) && 10 | bscript.isCanonicalPubKey(chunks[1]) 11 | ); 12 | } 13 | exports.check = check; 14 | check.toJSON = () => { 15 | return 'pubKeyHash input'; 16 | }; 17 | -------------------------------------------------------------------------------- /src/templates/pubkeyhash/output.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | const script_1 = require('../../script'); 6 | function check(script) { 7 | const buffer = bscript.compile(script); 8 | return ( 9 | buffer.length === 25 && 10 | buffer[0] === script_1.OPS.OP_DUP && 11 | buffer[1] === script_1.OPS.OP_HASH160 && 12 | buffer[2] === 0x14 && 13 | buffer[23] === script_1.OPS.OP_EQUALVERIFY && 14 | buffer[24] === script_1.OPS.OP_CHECKSIG 15 | ); 16 | } 17 | exports.check = check; 18 | check.toJSON = () => { 19 | return 'pubKeyHash output'; 20 | }; 21 | -------------------------------------------------------------------------------- /src/templates/scripthash/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const input = require('./input'); 4 | exports.input = input; 5 | const output = require('./output'); 6 | exports.output = output; 7 | -------------------------------------------------------------------------------- /src/templates/scripthash/input.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // {serialized scriptPubKey script} 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | const p2ms = require('../multisig'); 6 | const p2pk = require('../pubkey'); 7 | const p2pkh = require('../pubkeyhash'); 8 | const p2wpkho = require('../witnesspubkeyhash/output'); 9 | const p2wsho = require('../witnessscripthash/output'); 10 | function check(script, allowIncomplete) { 11 | const chunks = bscript.decompile(script); 12 | if (chunks.length < 1) return false; 13 | const lastChunk = chunks[chunks.length - 1]; 14 | if (!Buffer.isBuffer(lastChunk)) return false; 15 | const scriptSigChunks = bscript.decompile( 16 | bscript.compile(chunks.slice(0, -1)), 17 | ); 18 | const redeemScriptChunks = bscript.decompile(lastChunk); 19 | // is redeemScript a valid script? 20 | if (!redeemScriptChunks) return false; 21 | // is redeemScriptSig push only? 22 | if (!bscript.isPushOnly(scriptSigChunks)) return false; 23 | // is witness? 24 | if (chunks.length === 1) { 25 | return ( 26 | p2wsho.check(redeemScriptChunks) || p2wpkho.check(redeemScriptChunks) 27 | ); 28 | } 29 | // match types 30 | if ( 31 | p2pkh.input.check(scriptSigChunks) && 32 | p2pkh.output.check(redeemScriptChunks) 33 | ) 34 | return true; 35 | if ( 36 | p2ms.input.check(scriptSigChunks, allowIncomplete) && 37 | p2ms.output.check(redeemScriptChunks) 38 | ) 39 | return true; 40 | if ( 41 | p2pk.input.check(scriptSigChunks) && 42 | p2pk.output.check(redeemScriptChunks) 43 | ) 44 | return true; 45 | return false; 46 | } 47 | exports.check = check; 48 | check.toJSON = () => { 49 | return 'scriptHash input'; 50 | }; 51 | -------------------------------------------------------------------------------- /src/templates/scripthash/output.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // OP_HASH160 {scriptHash} OP_EQUAL 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | const script_1 = require('../../script'); 6 | function check(script) { 7 | const buffer = bscript.compile(script); 8 | return ( 9 | buffer.length === 23 && 10 | buffer[0] === script_1.OPS.OP_HASH160 && 11 | buffer[1] === 0x14 && 12 | buffer[22] === script_1.OPS.OP_EQUAL 13 | ); 14 | } 15 | exports.check = check; 16 | check.toJSON = () => { 17 | return 'scriptHash output'; 18 | }; 19 | -------------------------------------------------------------------------------- /src/templates/witnesscommitment/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const output = require('./output'); 4 | exports.output = output; 5 | -------------------------------------------------------------------------------- /src/templates/witnesscommitment/output.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // OP_RETURN {aa21a9ed} {commitment} 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | const script_1 = require('../../script'); 6 | const types = require('../../types'); 7 | const typeforce = require('typeforce'); 8 | const HEADER = Buffer.from('aa21a9ed', 'hex'); 9 | function check(script) { 10 | const buffer = bscript.compile(script); 11 | return ( 12 | buffer.length > 37 && 13 | buffer[0] === script_1.OPS.OP_RETURN && 14 | buffer[1] === 0x24 && 15 | buffer.slice(2, 6).equals(HEADER) 16 | ); 17 | } 18 | exports.check = check; 19 | check.toJSON = () => { 20 | return 'Witness commitment output'; 21 | }; 22 | function encode(commitment) { 23 | typeforce(types.Hash256bit, commitment); 24 | const buffer = Buffer.allocUnsafe(36); 25 | HEADER.copy(buffer, 0); 26 | commitment.copy(buffer, 4); 27 | return bscript.compile([script_1.OPS.OP_RETURN, buffer]); 28 | } 29 | exports.encode = encode; 30 | function decode(buffer) { 31 | typeforce(check, buffer); 32 | return bscript.decompile(buffer)[1].slice(4, 36); 33 | } 34 | exports.decode = decode; 35 | -------------------------------------------------------------------------------- /src/templates/witnesspubkeyhash/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const input = require('./input'); 4 | exports.input = input; 5 | const output = require('./output'); 6 | exports.output = output; 7 | -------------------------------------------------------------------------------- /src/templates/witnesspubkeyhash/input.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // {signature} {pubKey} 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | function isCompressedCanonicalPubKey(pubKey) { 6 | return bscript.isCanonicalPubKey(pubKey) && pubKey.length === 33; 7 | } 8 | function check(script) { 9 | const chunks = bscript.decompile(script); 10 | return ( 11 | chunks.length === 2 && 12 | bscript.isCanonicalScriptSignature(chunks[0]) && 13 | isCompressedCanonicalPubKey(chunks[1]) 14 | ); 15 | } 16 | exports.check = check; 17 | check.toJSON = () => { 18 | return 'witnessPubKeyHash input'; 19 | }; 20 | -------------------------------------------------------------------------------- /src/templates/witnesspubkeyhash/output.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // OP_0 {pubKeyHash} 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | const script_1 = require('../../script'); 6 | function check(script) { 7 | const buffer = bscript.compile(script); 8 | return ( 9 | buffer.length === 22 && 10 | buffer[0] === script_1.OPS.OP_0 && 11 | buffer[1] === 0x14 12 | ); 13 | } 14 | exports.check = check; 15 | check.toJSON = () => { 16 | return 'Witness pubKeyHash output'; 17 | }; 18 | -------------------------------------------------------------------------------- /src/templates/witnessscripthash/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const input = require('./input'); 4 | exports.input = input; 5 | const output = require('./output'); 6 | exports.output = output; 7 | -------------------------------------------------------------------------------- /src/templates/witnessscripthash/input.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // {serialized scriptPubKey script} 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | const typeforce = require('typeforce'); 6 | const p2ms = require('../multisig'); 7 | const p2pk = require('../pubkey'); 8 | const p2pkh = require('../pubkeyhash'); 9 | function check(chunks, allowIncomplete) { 10 | typeforce(typeforce.Array, chunks); 11 | if (chunks.length < 1) return false; 12 | const witnessScript = chunks[chunks.length - 1]; 13 | if (!Buffer.isBuffer(witnessScript)) return false; 14 | const witnessScriptChunks = bscript.decompile(witnessScript); 15 | // is witnessScript a valid script? 16 | if (!witnessScriptChunks || witnessScriptChunks.length === 0) return false; 17 | const witnessRawScriptSig = bscript.compile(chunks.slice(0, -1)); 18 | // match types 19 | if ( 20 | p2pkh.input.check(witnessRawScriptSig) && 21 | p2pkh.output.check(witnessScriptChunks) 22 | ) 23 | return true; 24 | if ( 25 | p2ms.input.check(witnessRawScriptSig, allowIncomplete) && 26 | p2ms.output.check(witnessScriptChunks) 27 | ) 28 | return true; 29 | if ( 30 | p2pk.input.check(witnessRawScriptSig) && 31 | p2pk.output.check(witnessScriptChunks) 32 | ) 33 | return true; 34 | return false; 35 | } 36 | exports.check = check; 37 | check.toJSON = () => { 38 | return 'witnessScriptHash input'; 39 | }; 40 | -------------------------------------------------------------------------------- /src/templates/witnessscripthash/output.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // OP_0 {scriptHash} 3 | Object.defineProperty(exports, '__esModule', { value: true }); 4 | const bscript = require('../../script'); 5 | const script_1 = require('../../script'); 6 | function check(script) { 7 | const buffer = bscript.compile(script); 8 | return ( 9 | buffer.length === 34 && 10 | buffer[0] === script_1.OPS.OP_0 && 11 | buffer[1] === 0x20 12 | ); 13 | } 14 | exports.check = check; 15 | check.toJSON = () => { 16 | return 'Witness scriptHash output'; 17 | }; 18 | -------------------------------------------------------------------------------- /src/transaction.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const bufferutils = require('./bufferutils'); 4 | const bufferutils_1 = require('./bufferutils'); 5 | const bcrypto = require('./crypto'); 6 | const bscript = require('./script'); 7 | const script_1 = require('./script'); 8 | const types = require('./types'); 9 | const typeforce = require('typeforce'); 10 | const varuint = require('varuint-bitcoin'); 11 | function varSliceSize(someScript) { 12 | const length = someScript.length; 13 | return varuint.encodingLength(length) + length; 14 | } 15 | function vectorSize(someVector) { 16 | const length = someVector.length; 17 | return ( 18 | varuint.encodingLength(length) + 19 | someVector.reduce((sum, witness) => { 20 | return sum + varSliceSize(witness); 21 | }, 0) 22 | ); 23 | } 24 | const EMPTY_SCRIPT = Buffer.allocUnsafe(0); 25 | const EMPTY_WITNESS = []; 26 | const ZERO = Buffer.from( 27 | '0000000000000000000000000000000000000000000000000000000000000000', 28 | 'hex', 29 | ); 30 | const ONE = Buffer.from( 31 | '0000000000000000000000000000000000000000000000000000000000000001', 32 | 'hex', 33 | ); 34 | const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex'); 35 | const BLANK_OUTPUT = { 36 | script: EMPTY_SCRIPT, 37 | valueBuffer: VALUE_UINT64_MAX, 38 | }; 39 | function isOutput(out) { 40 | return out.value !== undefined; 41 | } 42 | class Transaction { 43 | constructor() { 44 | this.version = 1; 45 | this.locktime = 0; 46 | this.ins = []; 47 | this.outs = []; 48 | } 49 | static fromBuffer(buffer, _NO_STRICT) { 50 | let offset = 0; 51 | function readSlice(n) { 52 | offset += n; 53 | return buffer.slice(offset - n, offset); 54 | } 55 | function readUInt32() { 56 | const i = buffer.readUInt32LE(offset); 57 | offset += 4; 58 | return i; 59 | } 60 | function readInt32() { 61 | const i = buffer.readInt32LE(offset); 62 | offset += 4; 63 | return i; 64 | } 65 | function readUInt64() { 66 | const i = bufferutils.readUInt64LE(buffer, offset); 67 | offset += 8; 68 | return i; 69 | } 70 | function readVarInt() { 71 | const vi = varuint.decode(buffer, offset); 72 | offset += varuint.decode.bytes; 73 | return vi; 74 | } 75 | function readVarSlice() { 76 | return readSlice(readVarInt()); 77 | } 78 | function readVector() { 79 | const count = readVarInt(); 80 | const vector = []; 81 | for (let i = 0; i < count; i++) vector.push(readVarSlice()); 82 | return vector; 83 | } 84 | const tx = new Transaction(); 85 | tx.version = readInt32(); 86 | const marker = buffer.readUInt8(offset); 87 | const flag = buffer.readUInt8(offset + 1); 88 | let hasWitnesses = false; 89 | if ( 90 | marker === Transaction.ADVANCED_TRANSACTION_MARKER && 91 | flag === Transaction.ADVANCED_TRANSACTION_FLAG 92 | ) { 93 | offset += 2; 94 | hasWitnesses = true; 95 | } 96 | const vinLen = readVarInt(); 97 | for (let i = 0; i < vinLen; ++i) { 98 | tx.ins.push({ 99 | hash: readSlice(32), 100 | index: readUInt32(), 101 | script: readVarSlice(), 102 | sequence: readUInt32(), 103 | witness: EMPTY_WITNESS, 104 | }); 105 | } 106 | const voutLen = readVarInt(); 107 | for (let i = 0; i < voutLen; ++i) { 108 | tx.outs.push({ 109 | value: readUInt64(), 110 | script: readVarSlice(), 111 | }); 112 | } 113 | if (hasWitnesses) { 114 | for (let i = 0; i < vinLen; ++i) { 115 | tx.ins[i].witness = readVector(); 116 | } 117 | // was this pointless? 118 | if (!tx.hasWitnesses()) 119 | throw new Error('Transaction has superfluous witness data'); 120 | } 121 | tx.locktime = readUInt32(); 122 | if (_NO_STRICT) return tx; 123 | if (offset !== buffer.length) 124 | throw new Error('Transaction has unexpected data'); 125 | return tx; 126 | } 127 | static fromHex(hex) { 128 | return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false); 129 | } 130 | static isCoinbaseHash(buffer) { 131 | typeforce(types.Hash256bit, buffer); 132 | for (let i = 0; i < 32; ++i) { 133 | if (buffer[i] !== 0) return false; 134 | } 135 | return true; 136 | } 137 | isCoinbase() { 138 | return ( 139 | this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) 140 | ); 141 | } 142 | addInput(hash, index, sequence, scriptSig) { 143 | typeforce( 144 | types.tuple( 145 | types.Hash256bit, 146 | types.UInt32, 147 | types.maybe(types.UInt32), 148 | types.maybe(types.Buffer), 149 | ), 150 | arguments, 151 | ); 152 | if (types.Null(sequence)) { 153 | sequence = Transaction.DEFAULT_SEQUENCE; 154 | } 155 | // Add the input and return the input's index 156 | return ( 157 | this.ins.push({ 158 | hash, 159 | index, 160 | script: scriptSig || EMPTY_SCRIPT, 161 | sequence: sequence, 162 | witness: EMPTY_WITNESS, 163 | }) - 1 164 | ); 165 | } 166 | addOutput(scriptPubKey, value) { 167 | typeforce(types.tuple(types.Buffer, types.Satoshi), arguments); 168 | // Add the output and return the output's index 169 | return ( 170 | this.outs.push({ 171 | script: scriptPubKey, 172 | value, 173 | }) - 1 174 | ); 175 | } 176 | hasWitnesses() { 177 | return this.ins.some(x => { 178 | return x.witness.length !== 0; 179 | }); 180 | } 181 | weight() { 182 | const base = this.__byteLength(false); 183 | const total = this.__byteLength(true); 184 | return base * 3 + total; 185 | } 186 | virtualSize() { 187 | return Math.ceil(this.weight() / 4); 188 | } 189 | byteLength() { 190 | return this.__byteLength(true); 191 | } 192 | clone() { 193 | const newTx = new Transaction(); 194 | newTx.version = this.version; 195 | newTx.locktime = this.locktime; 196 | newTx.ins = this.ins.map(txIn => { 197 | return { 198 | hash: txIn.hash, 199 | index: txIn.index, 200 | script: txIn.script, 201 | sequence: txIn.sequence, 202 | witness: txIn.witness, 203 | }; 204 | }); 205 | newTx.outs = this.outs.map(txOut => { 206 | return { 207 | script: txOut.script, 208 | value: txOut.value, 209 | }; 210 | }); 211 | return newTx; 212 | } 213 | /** 214 | * Hash transaction for signing a specific input. 215 | * 216 | * Bitcoin uses a different hash for each signed transaction input. 217 | * This method copies the transaction, makes the necessary changes based on the 218 | * hashType, and then hashes the result. 219 | * This hash can then be used to sign the provided transaction input. 220 | */ 221 | hashForSignature(inIndex, prevOutScript, hashType) { 222 | typeforce( 223 | types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), 224 | arguments, 225 | ); 226 | // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 227 | if (inIndex >= this.ins.length) return ONE; 228 | // ignore OP_CODESEPARATOR 229 | const ourScript = bscript.compile( 230 | bscript.decompile(prevOutScript).filter(x => { 231 | return x !== script_1.OPS.OP_CODESEPARATOR; 232 | }), 233 | ); 234 | const txTmp = this.clone(); 235 | // SIGHASH_NONE: ignore all outputs? (wildcard payee) 236 | if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { 237 | txTmp.outs = []; 238 | // ignore sequence numbers (except at inIndex) 239 | txTmp.ins.forEach((input, i) => { 240 | if (i === inIndex) return; 241 | input.sequence = 0; 242 | }); 243 | // SIGHASH_SINGLE: ignore all outputs, except at the same index? 244 | } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { 245 | // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 246 | if (inIndex >= this.outs.length) return ONE; 247 | // truncate outputs after 248 | txTmp.outs.length = inIndex + 1; 249 | // "blank" outputs before 250 | for (let i = 0; i < inIndex; i++) { 251 | txTmp.outs[i] = BLANK_OUTPUT; 252 | } 253 | // ignore sequence numbers (except at inIndex) 254 | txTmp.ins.forEach((input, y) => { 255 | if (y === inIndex) return; 256 | input.sequence = 0; 257 | }); 258 | } 259 | // SIGHASH_ANYONECANPAY: ignore inputs entirely? 260 | if (hashType & Transaction.SIGHASH_ANYONECANPAY) { 261 | txTmp.ins = [txTmp.ins[inIndex]]; 262 | txTmp.ins[0].script = ourScript; 263 | // SIGHASH_ALL: only ignore input scripts 264 | } else { 265 | // "blank" others input scripts 266 | txTmp.ins.forEach(input => { 267 | input.script = EMPTY_SCRIPT; 268 | }); 269 | txTmp.ins[inIndex].script = ourScript; 270 | } 271 | // serialize and hash 272 | const buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4); 273 | buffer.writeInt32LE(hashType, buffer.length - 4); 274 | txTmp.__toBuffer(buffer, 0, false); 275 | return bcrypto.hash256(buffer); 276 | } 277 | hashForWitnessV0(inIndex, prevOutScript, value, hashType) { 278 | typeforce( 279 | types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), 280 | arguments, 281 | ); 282 | let tbuffer = Buffer.from([]); 283 | let toffset = 0; 284 | function writeSlice(slice) { 285 | toffset += slice.copy(tbuffer, toffset); 286 | } 287 | function writeUInt32(i) { 288 | toffset = tbuffer.writeUInt32LE(i, toffset); 289 | } 290 | function writeUInt64(i) { 291 | toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset); 292 | } 293 | function writeVarInt(i) { 294 | varuint.encode(i, tbuffer, toffset); 295 | toffset += varuint.encode.bytes; 296 | } 297 | function writeVarSlice(slice) { 298 | writeVarInt(slice.length); 299 | writeSlice(slice); 300 | } 301 | let hashOutputs = ZERO; 302 | let hashPrevouts = ZERO; 303 | let hashSequence = ZERO; 304 | if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { 305 | tbuffer = Buffer.allocUnsafe(36 * this.ins.length); 306 | toffset = 0; 307 | this.ins.forEach(txIn => { 308 | writeSlice(txIn.hash); 309 | writeUInt32(txIn.index); 310 | }); 311 | hashPrevouts = bcrypto.hash256(tbuffer); 312 | } 313 | if ( 314 | !(hashType & Transaction.SIGHASH_ANYONECANPAY) && 315 | (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && 316 | (hashType & 0x1f) !== Transaction.SIGHASH_NONE 317 | ) { 318 | tbuffer = Buffer.allocUnsafe(4 * this.ins.length); 319 | toffset = 0; 320 | this.ins.forEach(txIn => { 321 | writeUInt32(txIn.sequence); 322 | }); 323 | hashSequence = bcrypto.hash256(tbuffer); 324 | } 325 | if ( 326 | (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && 327 | (hashType & 0x1f) !== Transaction.SIGHASH_NONE 328 | ) { 329 | const txOutsSize = this.outs.reduce((sum, output) => { 330 | return sum + 8 + varSliceSize(output.script); 331 | }, 0); 332 | tbuffer = Buffer.allocUnsafe(txOutsSize); 333 | toffset = 0; 334 | this.outs.forEach(out => { 335 | writeUInt64(out.value); 336 | writeVarSlice(out.script); 337 | }); 338 | hashOutputs = bcrypto.hash256(tbuffer); 339 | } else if ( 340 | (hashType & 0x1f) === Transaction.SIGHASH_SINGLE && 341 | inIndex < this.outs.length 342 | ) { 343 | const output = this.outs[inIndex]; 344 | tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script)); 345 | toffset = 0; 346 | writeUInt64(output.value); 347 | writeVarSlice(output.script); 348 | hashOutputs = bcrypto.hash256(tbuffer); 349 | } 350 | tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript)); 351 | toffset = 0; 352 | const input = this.ins[inIndex]; 353 | writeUInt32(this.version); 354 | writeSlice(hashPrevouts); 355 | writeSlice(hashSequence); 356 | writeSlice(input.hash); 357 | writeUInt32(input.index); 358 | writeVarSlice(prevOutScript); 359 | writeUInt64(value); 360 | writeUInt32(input.sequence); 361 | writeSlice(hashOutputs); 362 | writeUInt32(this.locktime); 363 | writeUInt32(hashType); 364 | return bcrypto.hash256(tbuffer); 365 | } 366 | getHash(forWitness) { 367 | // wtxid for coinbase is always 32 bytes of 0x00 368 | if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0); 369 | return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness)); 370 | } 371 | getId() { 372 | // transaction hash's are displayed in reverse order 373 | return bufferutils_1.reverseBuffer(this.getHash(false)).toString('hex'); 374 | } 375 | toBuffer(buffer, initialOffset) { 376 | return this.__toBuffer(buffer, initialOffset, true); 377 | } 378 | toHex() { 379 | return this.toBuffer(undefined, undefined).toString('hex'); 380 | } 381 | setInputScript(index, scriptSig) { 382 | typeforce(types.tuple(types.Number, types.Buffer), arguments); 383 | this.ins[index].script = scriptSig; 384 | } 385 | setWitness(index, witness) { 386 | typeforce(types.tuple(types.Number, [types.Buffer]), arguments); 387 | this.ins[index].witness = witness; 388 | } 389 | __byteLength(_ALLOW_WITNESS) { 390 | const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); 391 | return ( 392 | (hasWitnesses ? 10 : 8) + 393 | varuint.encodingLength(this.ins.length) + 394 | varuint.encodingLength(this.outs.length) + 395 | this.ins.reduce((sum, input) => { 396 | return sum + 40 + varSliceSize(input.script); 397 | }, 0) + 398 | this.outs.reduce((sum, output) => { 399 | return sum + 8 + varSliceSize(output.script); 400 | }, 0) + 401 | (hasWitnesses 402 | ? this.ins.reduce((sum, input) => { 403 | return sum + vectorSize(input.witness); 404 | }, 0) 405 | : 0) 406 | ); 407 | } 408 | __toBuffer(buffer, initialOffset, _ALLOW_WITNESS) { 409 | if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength(_ALLOW_WITNESS)); 410 | let offset = initialOffset || 0; 411 | function writeSlice(slice) { 412 | offset += slice.copy(buffer, offset); 413 | } 414 | function writeUInt8(i) { 415 | offset = buffer.writeUInt8(i, offset); 416 | } 417 | function writeUInt32(i) { 418 | offset = buffer.writeUInt32LE(i, offset); 419 | } 420 | function writeInt32(i) { 421 | offset = buffer.writeInt32LE(i, offset); 422 | } 423 | function writeUInt64(i) { 424 | offset = bufferutils.writeUInt64LE(buffer, i, offset); 425 | } 426 | function writeVarInt(i) { 427 | varuint.encode(i, buffer, offset); 428 | offset += varuint.encode.bytes; 429 | } 430 | function writeVarSlice(slice) { 431 | writeVarInt(slice.length); 432 | writeSlice(slice); 433 | } 434 | function writeVector(vector) { 435 | writeVarInt(vector.length); 436 | vector.forEach(writeVarSlice); 437 | } 438 | writeInt32(this.version); 439 | const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses(); 440 | if (hasWitnesses) { 441 | writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER); 442 | writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG); 443 | } 444 | writeVarInt(this.ins.length); 445 | this.ins.forEach(txIn => { 446 | writeSlice(txIn.hash); 447 | writeUInt32(txIn.index); 448 | writeVarSlice(txIn.script); 449 | writeUInt32(txIn.sequence); 450 | }); 451 | writeVarInt(this.outs.length); 452 | this.outs.forEach(txOut => { 453 | if (isOutput(txOut)) { 454 | writeUInt64(txOut.value); 455 | } else { 456 | writeSlice(txOut.valueBuffer); 457 | } 458 | writeVarSlice(txOut.script); 459 | }); 460 | if (hasWitnesses) { 461 | this.ins.forEach(input => { 462 | writeVector(input.witness); 463 | }); 464 | } 465 | writeUInt32(this.locktime); 466 | // avoid slicing unless necessary 467 | if (initialOffset !== undefined) return buffer.slice(initialOffset, offset); 468 | return buffer; 469 | } 470 | } 471 | Transaction.DEFAULT_SEQUENCE = 0xffffffff; 472 | Transaction.SIGHASH_ALL = 0x01; 473 | Transaction.SIGHASH_NONE = 0x02; 474 | Transaction.SIGHASH_SINGLE = 0x03; 475 | Transaction.SIGHASH_ANYONECANPAY = 0x80; 476 | Transaction.ADVANCED_TRANSACTION_MARKER = 0x00; 477 | Transaction.ADVANCED_TRANSACTION_FLAG = 0x01; 478 | exports.Transaction = Transaction; 479 | -------------------------------------------------------------------------------- /src/transaction_builder.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const baddress = require('./address'); 4 | const bufferutils_1 = require('./bufferutils'); 5 | const classify = require('./classify'); 6 | const bcrypto = require('./crypto'); 7 | const ECPair = require('./ecpair'); 8 | const networks = require('./networks'); 9 | const payments = require('./payments'); 10 | const bscript = require('./script'); 11 | const script_1 = require('./script'); 12 | const transaction_1 = require('./transaction'); 13 | const types = require('./types'); 14 | const typeforce = require('typeforce'); 15 | const SCRIPT_TYPES = classify.types; 16 | function txIsString(tx) { 17 | return typeof tx === 'string' || tx instanceof String; 18 | } 19 | function txIsTransaction(tx) { 20 | return tx instanceof transaction_1.Transaction; 21 | } 22 | class TransactionBuilder { 23 | // WARNING: maximumFeeRate is __NOT__ to be relied on, 24 | // it's just another potential safety mechanism (safety in-depth) 25 | constructor(network = networks.bitcoin, maximumFeeRate = 2500) { 26 | this.network = network; 27 | this.maximumFeeRate = maximumFeeRate; 28 | this.__PREV_TX_SET = {}; 29 | this.__INPUTS = []; 30 | this.__TX = new transaction_1.Transaction(); 31 | this.__TX.version = 2; 32 | this.__USE_LOW_R = false; 33 | } 34 | static fromTransaction(transaction, network) { 35 | const txb = new TransactionBuilder(network); 36 | // Copy transaction fields 37 | txb.setVersion(transaction.version); 38 | txb.setLockTime(transaction.locktime); 39 | // Copy outputs (done first to avoid signature invalidation) 40 | transaction.outs.forEach(txOut => { 41 | txb.addOutput(txOut.script, txOut.value); 42 | }); 43 | // Copy inputs 44 | transaction.ins.forEach(txIn => { 45 | txb.__addInputUnsafe(txIn.hash, txIn.index, { 46 | sequence: txIn.sequence, 47 | script: txIn.script, 48 | witness: txIn.witness, 49 | }); 50 | }); 51 | // fix some things not possible through the public API 52 | txb.__INPUTS.forEach((input, i) => { 53 | fixMultisigOrder(input, transaction, i); 54 | }); 55 | return txb; 56 | } 57 | setLowR(setting) { 58 | typeforce(typeforce.maybe(typeforce.Boolean), setting); 59 | if (setting === undefined) { 60 | setting = true; 61 | } 62 | this.__USE_LOW_R = setting; 63 | return setting; 64 | } 65 | setLockTime(locktime) { 66 | typeforce(types.UInt32, locktime); 67 | // if any signatures exist, throw 68 | if ( 69 | this.__INPUTS.some(input => { 70 | if (!input.signatures) return false; 71 | return input.signatures.some(s => s !== undefined); 72 | }) 73 | ) { 74 | throw new Error('No, this would invalidate signatures'); 75 | } 76 | this.__TX.locktime = locktime; 77 | } 78 | setVersion(version) { 79 | typeforce(types.UInt32, version); 80 | // XXX: this might eventually become more complex depending on what the versions represent 81 | this.__TX.version = version; 82 | } 83 | addInput(txHash, vout, sequence, prevOutScript) { 84 | if (!this.__canModifyInputs()) { 85 | throw new Error('No, this would invalidate signatures'); 86 | } 87 | let value; 88 | // is it a hex string? 89 | if (txIsString(txHash)) { 90 | // transaction hashs's are displayed in reverse order, un-reverse it 91 | txHash = bufferutils_1.reverseBuffer(Buffer.from(txHash, 'hex')); 92 | // is it a Transaction object? 93 | } else if (txIsTransaction(txHash)) { 94 | const txOut = txHash.outs[vout]; 95 | prevOutScript = txOut.script; 96 | value = txOut.value; 97 | txHash = txHash.getHash(false); 98 | } 99 | return this.__addInputUnsafe(txHash, vout, { 100 | sequence, 101 | prevOutScript, 102 | value, 103 | }); 104 | } 105 | addOutput(scriptPubKey, value) { 106 | if (!this.__canModifyOutputs()) { 107 | throw new Error('No, this would invalidate signatures'); 108 | } 109 | // Attempt to get a script if it's a base58 or bech32 address string 110 | if (typeof scriptPubKey === 'string') { 111 | scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network); 112 | } 113 | return this.__TX.addOutput(scriptPubKey, value); 114 | } 115 | build() { 116 | return this.__build(false); 117 | } 118 | buildIncomplete() { 119 | return this.__build(true); 120 | } 121 | sign(vin, keyPair, redeemScript, hashType, witnessValue, witnessScript) { 122 | // TODO: remove keyPair.network matching in 4.0.0 123 | if (keyPair.network && keyPair.network !== this.network) 124 | throw new TypeError('Inconsistent network'); 125 | if (!this.__INPUTS[vin]) throw new Error('No input at index: ' + vin); 126 | hashType = hashType || transaction_1.Transaction.SIGHASH_ALL; 127 | if (this.__needsOutputs(hashType)) 128 | throw new Error('Transaction needs outputs'); 129 | const input = this.__INPUTS[vin]; 130 | // if redeemScript was previously provided, enforce consistency 131 | if ( 132 | input.redeemScript !== undefined && 133 | redeemScript && 134 | !input.redeemScript.equals(redeemScript) 135 | ) { 136 | throw new Error('Inconsistent redeemScript'); 137 | } 138 | const ourPubKey = keyPair.publicKey || keyPair.getPublicKey(); 139 | if (!canSign(input)) { 140 | if (witnessValue !== undefined) { 141 | if (input.value !== undefined && input.value !== witnessValue) 142 | throw new Error('Input did not match witnessValue'); 143 | typeforce(types.Satoshi, witnessValue); 144 | input.value = witnessValue; 145 | } 146 | if (!canSign(input)) { 147 | const prepared = prepareInput( 148 | input, 149 | ourPubKey, 150 | redeemScript, 151 | witnessScript, 152 | ); 153 | // updates inline 154 | Object.assign(input, prepared); 155 | } 156 | if (!canSign(input)) throw Error(input.prevOutType + ' not supported'); 157 | } 158 | // ready to sign 159 | let signatureHash; 160 | if (input.hasWitness) { 161 | signatureHash = this.__TX.hashForWitnessV0( 162 | vin, 163 | input.signScript, 164 | input.value, 165 | hashType, 166 | ); 167 | } else { 168 | signatureHash = this.__TX.hashForSignature( 169 | vin, 170 | input.signScript, 171 | hashType, 172 | ); 173 | } 174 | // enforce in order signing of public keys 175 | const signed = input.pubkeys.some((pubKey, i) => { 176 | if (!ourPubKey.equals(pubKey)) return false; 177 | if (input.signatures[i]) throw new Error('Signature already exists'); 178 | // TODO: add tests 179 | if (ourPubKey.length !== 33 && input.hasWitness) { 180 | throw new Error( 181 | 'BIP143 rejects uncompressed public keys in P2WPKH or P2WSH', 182 | ); 183 | } 184 | const signature = keyPair.sign(signatureHash, this.__USE_LOW_R); 185 | input.signatures[i] = bscript.signature.encode(signature, hashType); 186 | return true; 187 | }); 188 | if (!signed) throw new Error('Key pair cannot sign for this input'); 189 | } 190 | __addInputUnsafe(txHash, vout, options) { 191 | if (transaction_1.Transaction.isCoinbaseHash(txHash)) { 192 | throw new Error('coinbase inputs not supported'); 193 | } 194 | const prevTxOut = txHash.toString('hex') + ':' + vout; 195 | if (this.__PREV_TX_SET[prevTxOut] !== undefined) 196 | throw new Error('Duplicate TxOut: ' + prevTxOut); 197 | let input = {}; 198 | // derive what we can from the scriptSig 199 | if (options.script !== undefined) { 200 | input = expandInput(options.script, options.witness || []); 201 | } 202 | // if an input value was given, retain it 203 | if (options.value !== undefined) { 204 | input.value = options.value; 205 | } 206 | // derive what we can from the previous transactions output script 207 | if (!input.prevOutScript && options.prevOutScript) { 208 | let prevOutType; 209 | if (!input.pubkeys && !input.signatures) { 210 | const expanded = expandOutput(options.prevOutScript); 211 | if (expanded.pubkeys) { 212 | input.pubkeys = expanded.pubkeys; 213 | input.signatures = expanded.signatures; 214 | } 215 | prevOutType = expanded.type; 216 | } 217 | input.prevOutScript = options.prevOutScript; 218 | input.prevOutType = prevOutType || classify.output(options.prevOutScript); 219 | } 220 | const vin = this.__TX.addInput( 221 | txHash, 222 | vout, 223 | options.sequence, 224 | options.scriptSig, 225 | ); 226 | this.__INPUTS[vin] = input; 227 | this.__PREV_TX_SET[prevTxOut] = true; 228 | return vin; 229 | } 230 | __build(allowIncomplete) { 231 | if (!allowIncomplete) { 232 | if (!this.__TX.ins.length) throw new Error('Transaction has no inputs'); 233 | if (!this.__TX.outs.length) throw new Error('Transaction has no outputs'); 234 | } 235 | const tx = this.__TX.clone(); 236 | // create script signatures from inputs 237 | this.__INPUTS.forEach((input, i) => { 238 | if (!input.prevOutType && !allowIncomplete) 239 | throw new Error('Transaction is not complete'); 240 | const result = build(input.prevOutType, input, allowIncomplete); 241 | if (!result) { 242 | if (!allowIncomplete && input.prevOutType === SCRIPT_TYPES.NONSTANDARD) 243 | throw new Error('Unknown input type'); 244 | if (!allowIncomplete) throw new Error('Not enough information'); 245 | return; 246 | } 247 | tx.setInputScript(i, result.input); 248 | tx.setWitness(i, result.witness); 249 | }); 250 | if (!allowIncomplete) { 251 | // do not rely on this, its merely a last resort 252 | if (this.__overMaximumFees(tx.virtualSize())) { 253 | throw new Error('Transaction has absurd fees'); 254 | } 255 | } 256 | return tx; 257 | } 258 | __canModifyInputs() { 259 | return this.__INPUTS.every(input => { 260 | if (!input.signatures) return true; 261 | return input.signatures.every(signature => { 262 | if (!signature) return true; 263 | const hashType = signatureHashType(signature); 264 | // if SIGHASH_ANYONECANPAY is set, signatures would not 265 | // be invalidated by more inputs 266 | return ( 267 | (hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY) !== 0 268 | ); 269 | }); 270 | }); 271 | } 272 | __needsOutputs(signingHashType) { 273 | if (signingHashType === transaction_1.Transaction.SIGHASH_ALL) { 274 | return this.__TX.outs.length === 0; 275 | } 276 | // if inputs are being signed with SIGHASH_NONE, we don't strictly need outputs 277 | // .build() will fail, but .buildIncomplete() is OK 278 | return ( 279 | this.__TX.outs.length === 0 && 280 | this.__INPUTS.some(input => { 281 | if (!input.signatures) return false; 282 | return input.signatures.some(signature => { 283 | if (!signature) return false; // no signature, no issue 284 | const hashType = signatureHashType(signature); 285 | if (hashType & transaction_1.Transaction.SIGHASH_NONE) return false; // SIGHASH_NONE doesn't care about outputs 286 | return true; // SIGHASH_* does care 287 | }); 288 | }) 289 | ); 290 | } 291 | __canModifyOutputs() { 292 | const nInputs = this.__TX.ins.length; 293 | const nOutputs = this.__TX.outs.length; 294 | return this.__INPUTS.every(input => { 295 | if (input.signatures === undefined) return true; 296 | return input.signatures.every(signature => { 297 | if (!signature) return true; 298 | const hashType = signatureHashType(signature); 299 | const hashTypeMod = hashType & 0x1f; 300 | if (hashTypeMod === transaction_1.Transaction.SIGHASH_NONE) return true; 301 | if (hashTypeMod === transaction_1.Transaction.SIGHASH_SINGLE) { 302 | // if SIGHASH_SINGLE is set, and nInputs > nOutputs 303 | // some signatures would be invalidated by the addition 304 | // of more outputs 305 | return nInputs <= nOutputs; 306 | } 307 | return false; 308 | }); 309 | }); 310 | } 311 | __overMaximumFees(bytes) { 312 | // not all inputs will have .value defined 313 | const incoming = this.__INPUTS.reduce((a, x) => a + (x.value >>> 0), 0); 314 | // but all outputs do, and if we have any input value 315 | // we can immediately determine if the outputs are too small 316 | const outgoing = this.__TX.outs.reduce((a, x) => a + x.value, 0); 317 | const fee = incoming - outgoing; 318 | const feeRate = fee / bytes; 319 | return feeRate > this.maximumFeeRate; 320 | } 321 | } 322 | exports.TransactionBuilder = TransactionBuilder; 323 | function expandInput(scriptSig, witnessStack, type, scriptPubKey) { 324 | if (scriptSig.length === 0 && witnessStack.length === 0) return {}; 325 | if (!type) { 326 | let ssType = classify.input(scriptSig, true); 327 | let wsType = classify.witness(witnessStack, true); 328 | if (ssType === SCRIPT_TYPES.NONSTANDARD) ssType = undefined; 329 | if (wsType === SCRIPT_TYPES.NONSTANDARD) wsType = undefined; 330 | type = ssType || wsType; 331 | } 332 | switch (type) { 333 | case SCRIPT_TYPES.P2WPKH: { 334 | const { output, pubkey, signature } = payments.p2wpkh({ 335 | witness: witnessStack, 336 | }); 337 | return { 338 | prevOutScript: output, 339 | prevOutType: SCRIPT_TYPES.P2WPKH, 340 | pubkeys: [pubkey], 341 | signatures: [signature], 342 | }; 343 | } 344 | case SCRIPT_TYPES.P2PKH: { 345 | const { output, pubkey, signature } = payments.p2pkh({ 346 | input: scriptSig, 347 | }); 348 | return { 349 | prevOutScript: output, 350 | prevOutType: SCRIPT_TYPES.P2PKH, 351 | pubkeys: [pubkey], 352 | signatures: [signature], 353 | }; 354 | } 355 | case SCRIPT_TYPES.P2PK: { 356 | const { signature } = payments.p2pk({ input: scriptSig }); 357 | return { 358 | prevOutType: SCRIPT_TYPES.P2PK, 359 | pubkeys: [undefined], 360 | signatures: [signature], 361 | }; 362 | } 363 | case SCRIPT_TYPES.P2MS: { 364 | const { m, pubkeys, signatures } = payments.p2ms( 365 | { 366 | input: scriptSig, 367 | output: scriptPubKey, 368 | }, 369 | { allowIncomplete: true }, 370 | ); 371 | return { 372 | prevOutType: SCRIPT_TYPES.P2MS, 373 | pubkeys, 374 | signatures, 375 | maxSignatures: m, 376 | }; 377 | } 378 | } 379 | if (type === SCRIPT_TYPES.P2SH) { 380 | const { output, redeem } = payments.p2sh({ 381 | input: scriptSig, 382 | witness: witnessStack, 383 | }); 384 | const outputType = classify.output(redeem.output); 385 | const expanded = expandInput( 386 | redeem.input, 387 | redeem.witness, 388 | outputType, 389 | redeem.output, 390 | ); 391 | if (!expanded.prevOutType) return {}; 392 | return { 393 | prevOutScript: output, 394 | prevOutType: SCRIPT_TYPES.P2SH, 395 | redeemScript: redeem.output, 396 | redeemScriptType: expanded.prevOutType, 397 | witnessScript: expanded.witnessScript, 398 | witnessScriptType: expanded.witnessScriptType, 399 | pubkeys: expanded.pubkeys, 400 | signatures: expanded.signatures, 401 | }; 402 | } 403 | if (type === SCRIPT_TYPES.P2WSH) { 404 | const { output, redeem } = payments.p2wsh({ 405 | input: scriptSig, 406 | witness: witnessStack, 407 | }); 408 | const outputType = classify.output(redeem.output); 409 | let expanded; 410 | if (outputType === SCRIPT_TYPES.P2WPKH) { 411 | expanded = expandInput(redeem.input, redeem.witness, outputType); 412 | } else { 413 | expanded = expandInput( 414 | bscript.compile(redeem.witness), 415 | [], 416 | outputType, 417 | redeem.output, 418 | ); 419 | } 420 | if (!expanded.prevOutType) return {}; 421 | return { 422 | prevOutScript: output, 423 | prevOutType: SCRIPT_TYPES.P2WSH, 424 | witnessScript: redeem.output, 425 | witnessScriptType: expanded.prevOutType, 426 | pubkeys: expanded.pubkeys, 427 | signatures: expanded.signatures, 428 | }; 429 | } 430 | return { 431 | prevOutType: SCRIPT_TYPES.NONSTANDARD, 432 | prevOutScript: scriptSig, 433 | }; 434 | } 435 | // could be done in expandInput, but requires the original Transaction for hashForSignature 436 | function fixMultisigOrder(input, transaction, vin) { 437 | if (input.redeemScriptType !== SCRIPT_TYPES.P2MS || !input.redeemScript) 438 | return; 439 | if (input.pubkeys.length === input.signatures.length) return; 440 | const unmatched = input.signatures.concat(); 441 | input.signatures = input.pubkeys.map(pubKey => { 442 | const keyPair = ECPair.fromPublicKey(pubKey); 443 | let match; 444 | // check for a signature 445 | unmatched.some((signature, i) => { 446 | // skip if undefined || OP_0 447 | if (!signature) return false; 448 | // TODO: avoid O(n) hashForSignature 449 | const parsed = bscript.signature.decode(signature); 450 | const hash = transaction.hashForSignature( 451 | vin, 452 | input.redeemScript, 453 | parsed.hashType, 454 | ); 455 | // skip if signature does not match pubKey 456 | if (!keyPair.verify(hash, parsed.signature)) return false; 457 | // remove matched signature from unmatched 458 | unmatched[i] = undefined; 459 | match = signature; 460 | return true; 461 | }); 462 | return match; 463 | }); 464 | } 465 | function expandOutput(script, ourPubKey) { 466 | typeforce(types.Buffer, script); 467 | const type = classify.output(script); 468 | switch (type) { 469 | case SCRIPT_TYPES.P2PKH: { 470 | if (!ourPubKey) return { type }; 471 | // does our hash160(pubKey) match the output scripts? 472 | const pkh1 = payments.p2pkh({ output: script }).hash; 473 | const pkh2 = bcrypto.hash160(ourPubKey); 474 | if (!pkh1.equals(pkh2)) return { type }; 475 | return { 476 | type, 477 | pubkeys: [ourPubKey], 478 | signatures: [undefined], 479 | }; 480 | } 481 | case SCRIPT_TYPES.P2WPKH: { 482 | if (!ourPubKey) return { type }; 483 | // does our hash160(pubKey) match the output scripts? 484 | const wpkh1 = payments.p2wpkh({ output: script }).hash; 485 | const wpkh2 = bcrypto.hash160(ourPubKey); 486 | if (!wpkh1.equals(wpkh2)) return { type }; 487 | return { 488 | type, 489 | pubkeys: [ourPubKey], 490 | signatures: [undefined], 491 | }; 492 | } 493 | case SCRIPT_TYPES.P2PK: { 494 | const p2pk = payments.p2pk({ output: script }); 495 | return { 496 | type, 497 | pubkeys: [p2pk.pubkey], 498 | signatures: [undefined], 499 | }; 500 | } 501 | case SCRIPT_TYPES.P2MS: { 502 | const p2ms = payments.p2ms({ output: script }); 503 | return { 504 | type, 505 | pubkeys: p2ms.pubkeys, 506 | signatures: p2ms.pubkeys.map(() => undefined), 507 | maxSignatures: p2ms.m, 508 | }; 509 | } 510 | } 511 | return { type }; 512 | } 513 | function prepareInput(input, ourPubKey, redeemScript, witnessScript) { 514 | if (redeemScript && witnessScript) { 515 | const p2wsh = payments.p2wsh({ 516 | redeem: { output: witnessScript }, 517 | }); 518 | const p2wshAlt = payments.p2wsh({ output: redeemScript }); 519 | const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); 520 | const p2shAlt = payments.p2sh({ redeem: p2wsh }); 521 | // enforces P2SH(P2WSH(...)) 522 | if (!p2wsh.hash.equals(p2wshAlt.hash)) 523 | throw new Error('Witness script inconsistent with prevOutScript'); 524 | if (!p2sh.hash.equals(p2shAlt.hash)) 525 | throw new Error('Redeem script inconsistent with prevOutScript'); 526 | const expanded = expandOutput(p2wsh.redeem.output, ourPubKey); 527 | if (!expanded.pubkeys) 528 | throw new Error( 529 | expanded.type + 530 | ' not supported as witnessScript (' + 531 | bscript.toASM(witnessScript) + 532 | ')', 533 | ); 534 | if (input.signatures && input.signatures.some(x => x !== undefined)) { 535 | expanded.signatures = input.signatures; 536 | } 537 | const signScript = witnessScript; 538 | if (expanded.type === SCRIPT_TYPES.P2WPKH) 539 | throw new Error('P2SH(P2WSH(P2WPKH)) is a consensus failure'); 540 | return { 541 | redeemScript, 542 | redeemScriptType: SCRIPT_TYPES.P2WSH, 543 | witnessScript, 544 | witnessScriptType: expanded.type, 545 | prevOutType: SCRIPT_TYPES.P2SH, 546 | prevOutScript: p2sh.output, 547 | hasWitness: true, 548 | signScript, 549 | signType: expanded.type, 550 | pubkeys: expanded.pubkeys, 551 | signatures: expanded.signatures, 552 | maxSignatures: expanded.maxSignatures, 553 | }; 554 | } 555 | if (redeemScript) { 556 | const p2sh = payments.p2sh({ redeem: { output: redeemScript } }); 557 | if (input.prevOutScript) { 558 | let p2shAlt; 559 | try { 560 | p2shAlt = payments.p2sh({ output: input.prevOutScript }); 561 | } catch (e) { 562 | throw new Error('PrevOutScript must be P2SH'); 563 | } 564 | if (!p2sh.hash.equals(p2shAlt.hash)) 565 | throw new Error('Redeem script inconsistent with prevOutScript'); 566 | } 567 | const expanded = expandOutput(p2sh.redeem.output, ourPubKey); 568 | if (!expanded.pubkeys) 569 | throw new Error( 570 | expanded.type + 571 | ' not supported as redeemScript (' + 572 | bscript.toASM(redeemScript) + 573 | ')', 574 | ); 575 | if (input.signatures && input.signatures.some(x => x !== undefined)) { 576 | expanded.signatures = input.signatures; 577 | } 578 | let signScript = redeemScript; 579 | if (expanded.type === SCRIPT_TYPES.P2WPKH) { 580 | signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output; 581 | } 582 | return { 583 | redeemScript, 584 | redeemScriptType: expanded.type, 585 | prevOutType: SCRIPT_TYPES.P2SH, 586 | prevOutScript: p2sh.output, 587 | hasWitness: expanded.type === SCRIPT_TYPES.P2WPKH, 588 | signScript, 589 | signType: expanded.type, 590 | pubkeys: expanded.pubkeys, 591 | signatures: expanded.signatures, 592 | maxSignatures: expanded.maxSignatures, 593 | }; 594 | } 595 | if (witnessScript) { 596 | const p2wsh = payments.p2wsh({ redeem: { output: witnessScript } }); 597 | if (input.prevOutScript) { 598 | const p2wshAlt = payments.p2wsh({ output: input.prevOutScript }); 599 | if (!p2wsh.hash.equals(p2wshAlt.hash)) 600 | throw new Error('Witness script inconsistent with prevOutScript'); 601 | } 602 | const expanded = expandOutput(p2wsh.redeem.output, ourPubKey); 603 | if (!expanded.pubkeys) 604 | throw new Error( 605 | expanded.type + 606 | ' not supported as witnessScript (' + 607 | bscript.toASM(witnessScript) + 608 | ')', 609 | ); 610 | if (input.signatures && input.signatures.some(x => x !== undefined)) { 611 | expanded.signatures = input.signatures; 612 | } 613 | const signScript = witnessScript; 614 | if (expanded.type === SCRIPT_TYPES.P2WPKH) 615 | throw new Error('P2WSH(P2WPKH) is a consensus failure'); 616 | return { 617 | witnessScript, 618 | witnessScriptType: expanded.type, 619 | prevOutType: SCRIPT_TYPES.P2WSH, 620 | prevOutScript: p2wsh.output, 621 | hasWitness: true, 622 | signScript, 623 | signType: expanded.type, 624 | pubkeys: expanded.pubkeys, 625 | signatures: expanded.signatures, 626 | maxSignatures: expanded.maxSignatures, 627 | }; 628 | } 629 | if (input.prevOutType && input.prevOutScript) { 630 | // embedded scripts are not possible without extra information 631 | if (input.prevOutType === SCRIPT_TYPES.P2SH) 632 | throw new Error( 633 | 'PrevOutScript is ' + input.prevOutType + ', requires redeemScript', 634 | ); 635 | if (input.prevOutType === SCRIPT_TYPES.P2WSH) 636 | throw new Error( 637 | 'PrevOutScript is ' + input.prevOutType + ', requires witnessScript', 638 | ); 639 | if (!input.prevOutScript) throw new Error('PrevOutScript is missing'); 640 | const expanded = expandOutput(input.prevOutScript, ourPubKey); 641 | if (!expanded.pubkeys) 642 | throw new Error( 643 | expanded.type + 644 | ' not supported (' + 645 | bscript.toASM(input.prevOutScript) + 646 | ')', 647 | ); 648 | if (input.signatures && input.signatures.some(x => x !== undefined)) { 649 | expanded.signatures = input.signatures; 650 | } 651 | let signScript = input.prevOutScript; 652 | if (expanded.type === SCRIPT_TYPES.P2WPKH) { 653 | signScript = payments.p2pkh({ pubkey: expanded.pubkeys[0] }).output; 654 | } 655 | return { 656 | prevOutType: expanded.type, 657 | prevOutScript: input.prevOutScript, 658 | hasWitness: expanded.type === SCRIPT_TYPES.P2WPKH, 659 | signScript, 660 | signType: expanded.type, 661 | pubkeys: expanded.pubkeys, 662 | signatures: expanded.signatures, 663 | maxSignatures: expanded.maxSignatures, 664 | }; 665 | } 666 | const prevOutScript = payments.p2pkh({ pubkey: ourPubKey }).output; 667 | return { 668 | prevOutType: SCRIPT_TYPES.P2PKH, 669 | prevOutScript, 670 | hasWitness: false, 671 | signScript: prevOutScript, 672 | signType: SCRIPT_TYPES.P2PKH, 673 | pubkeys: [ourPubKey], 674 | signatures: [undefined], 675 | }; 676 | } 677 | function build(type, input, allowIncomplete) { 678 | const pubkeys = input.pubkeys || []; 679 | let signatures = input.signatures || []; 680 | switch (type) { 681 | case SCRIPT_TYPES.P2PKH: { 682 | if (pubkeys.length === 0) break; 683 | if (signatures.length === 0) break; 684 | return payments.p2pkh({ pubkey: pubkeys[0], signature: signatures[0] }); 685 | } 686 | case SCRIPT_TYPES.P2WPKH: { 687 | if (pubkeys.length === 0) break; 688 | if (signatures.length === 0) break; 689 | return payments.p2wpkh({ pubkey: pubkeys[0], signature: signatures[0] }); 690 | } 691 | case SCRIPT_TYPES.P2PK: { 692 | if (pubkeys.length === 0) break; 693 | if (signatures.length === 0) break; 694 | return payments.p2pk({ signature: signatures[0] }); 695 | } 696 | case SCRIPT_TYPES.P2MS: { 697 | const m = input.maxSignatures; 698 | if (allowIncomplete) { 699 | signatures = signatures.map(x => x || script_1.OPS.OP_0); 700 | } else { 701 | signatures = signatures.filter(x => x); 702 | } 703 | // if the transaction is not not complete (complete), or if signatures.length === m, validate 704 | // otherwise, the number of OP_0's may be >= m, so don't validate (boo) 705 | const validate = !allowIncomplete || m === signatures.length; 706 | return payments.p2ms( 707 | { m, pubkeys, signatures }, 708 | { allowIncomplete, validate }, 709 | ); 710 | } 711 | case SCRIPT_TYPES.P2SH: { 712 | const redeem = build(input.redeemScriptType, input, allowIncomplete); 713 | if (!redeem) return; 714 | return payments.p2sh({ 715 | redeem: { 716 | output: redeem.output || input.redeemScript, 717 | input: redeem.input, 718 | witness: redeem.witness, 719 | }, 720 | }); 721 | } 722 | case SCRIPT_TYPES.P2WSH: { 723 | const redeem = build(input.witnessScriptType, input, allowIncomplete); 724 | if (!redeem) return; 725 | return payments.p2wsh({ 726 | redeem: { 727 | output: input.witnessScript, 728 | input: redeem.input, 729 | witness: redeem.witness, 730 | }, 731 | }); 732 | } 733 | } 734 | } 735 | function canSign(input) { 736 | return ( 737 | input.signScript !== undefined && 738 | input.signType !== undefined && 739 | input.pubkeys !== undefined && 740 | input.signatures !== undefined && 741 | input.signatures.length === input.pubkeys.length && 742 | input.pubkeys.length > 0 && 743 | (input.hasWitness === false || input.value !== undefined) 744 | ); 745 | } 746 | function signatureHashType(buffer) { 747 | return buffer.readUInt8(buffer.length - 1); 748 | } 749 | -------------------------------------------------------------------------------- /src/types.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const typeforce = require('typeforce'); 4 | const UINT31_MAX = Math.pow(2, 31) - 1; 5 | function UInt31(value) { 6 | return typeforce.UInt32(value) && value <= UINT31_MAX; 7 | } 8 | exports.UInt31 = UInt31; 9 | function BIP32Path(value) { 10 | return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/); 11 | } 12 | exports.BIP32Path = BIP32Path; 13 | BIP32Path.toJSON = () => { 14 | return 'BIP32 derivation path'; 15 | }; 16 | const SATOSHI_MAX = 21 * 1e14; 17 | function Satoshi(value) { 18 | return typeforce.UInt53(value) && value <= SATOSHI_MAX; 19 | } 20 | exports.Satoshi = Satoshi; 21 | // external dependent types 22 | exports.ECPoint = typeforce.quacksLike('Point'); 23 | // exposed, external API 24 | exports.Network = typeforce.compile({ 25 | messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String), 26 | bip32: { 27 | public: typeforce.UInt32, 28 | private: typeforce.UInt32, 29 | }, 30 | pubKeyHash: typeforce.UInt8, 31 | scriptHash: typeforce.UInt8, 32 | wif: typeforce.UInt8, 33 | }); 34 | exports.Buffer256bit = typeforce.BufferN(32); 35 | exports.Hash160bit = typeforce.BufferN(20); 36 | exports.Hash256bit = typeforce.BufferN(32); 37 | exports.Number = typeforce.Number; // tslint:disable-line variable-name 38 | exports.Array = typeforce.Array; 39 | exports.Boolean = typeforce.Boolean; // tslint:disable-line variable-name 40 | exports.String = typeforce.String; // tslint:disable-line variable-name 41 | exports.Buffer = typeforce.Buffer; 42 | exports.Hex = typeforce.Hex; 43 | exports.maybe = typeforce.maybe; 44 | exports.tuple = typeforce.tuple; 45 | exports.UInt8 = typeforce.UInt8; 46 | exports.UInt32 = typeforce.UInt32; 47 | exports.Function = typeforce.Function; 48 | exports.BufferN = typeforce.BufferN; 49 | exports.Null = typeforce.Null; 50 | exports.oneOf = typeforce.oneOf; 51 | -------------------------------------------------------------------------------- /types/address.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Network } from './networks'; 3 | export interface Base58CheckResult { 4 | hash: Buffer; 5 | version: number; 6 | } 7 | export interface Bech32Result { 8 | version: number; 9 | prefix: string; 10 | data: Buffer; 11 | } 12 | export declare function fromBase58Check(address: string): Base58CheckResult; 13 | export declare function fromBech32(address: string): Bech32Result; 14 | export declare function toBase58Check(hash: Buffer, version: number): string; 15 | export declare function toBech32(data: Buffer, version: number, prefix: string): string; 16 | export declare function fromOutputScript(output: Buffer, network?: Network): string; 17 | export declare function toOutputScript(address: string, network?: Network): Buffer; 18 | -------------------------------------------------------------------------------- /types/block.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Transaction } from './transaction'; 3 | export declare class Block { 4 | static fromBuffer(buffer: Buffer): Block; 5 | static fromHex(hex: string): Block; 6 | static calculateTarget(bits: number): Buffer; 7 | static calculateMerkleRoot(transactions: Transaction[], forWitness?: boolean): Buffer; 8 | version: number; 9 | prevHash?: Buffer; 10 | merkleRoot?: Buffer; 11 | timestamp: number; 12 | witnessCommit?: Buffer; 13 | bits: number; 14 | nonce: number; 15 | transactions?: Transaction[]; 16 | getWitnessCommit(): Buffer | null; 17 | hasWitnessCommit(): boolean; 18 | hasWitness(): boolean; 19 | byteLength(headersOnly: boolean): number; 20 | getHash(): Buffer; 21 | getId(): string; 22 | getUTCDate(): Date; 23 | toBuffer(headersOnly: boolean): Buffer; 24 | toHex(headersOnly: boolean): string; 25 | checkTxRoots(): boolean; 26 | checkProofOfWork(): boolean; 27 | private __checkMerkleRoot; 28 | private __checkWitnessCommit; 29 | } 30 | -------------------------------------------------------------------------------- /types/bufferutils.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare function readUInt64LE(buffer: Buffer, offset: number): number; 3 | export declare function writeUInt64LE(buffer: Buffer, value: number, offset: number): number; 4 | export declare function reverseBuffer(buffer: Buffer): Buffer; 5 | -------------------------------------------------------------------------------- /types/classify.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | declare const types: { 3 | P2MS: string; 4 | NONSTANDARD: string; 5 | NULLDATA: string; 6 | P2PK: string; 7 | P2PKH: string; 8 | P2SH: string; 9 | P2WPKH: string; 10 | P2WSH: string; 11 | WITNESS_COMMITMENT: string; 12 | }; 13 | declare function classifyOutput(script: Buffer): string; 14 | declare function classifyInput(script: Buffer, allowIncomplete: boolean): string; 15 | declare function classifyWitness(script: Buffer[], allowIncomplete: boolean): string; 16 | export { classifyInput as input, classifyOutput as output, classifyWitness as witness, types, }; 17 | -------------------------------------------------------------------------------- /types/crypto.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare function ripemd160(buffer: Buffer): Buffer; 3 | export declare function sha1(buffer: Buffer): Buffer; 4 | export declare function sha256(buffer: Buffer): Buffer; 5 | export declare function hash160(buffer: Buffer): Buffer; 6 | export declare function hash256(buffer: Buffer): Buffer; 7 | -------------------------------------------------------------------------------- /types/ecpair.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Network } from './networks'; 3 | interface ECPairOptions { 4 | compressed?: boolean; 5 | network?: Network; 6 | rng?(arg0: number): Buffer; 7 | } 8 | export interface ECPairInterface { 9 | compressed: boolean; 10 | network: Network; 11 | publicKey: Buffer; 12 | privateKey?: Buffer; 13 | toWIF(): string; 14 | sign(hash: Buffer, lowR?: boolean): Buffer; 15 | verify(hash: Buffer, signature: Buffer): boolean; 16 | getPublicKey?(): Buffer; 17 | } 18 | declare class ECPair implements ECPairInterface { 19 | private __D?; 20 | private __Q?; 21 | compressed: boolean; 22 | network: Network; 23 | constructor(__D?: Buffer | undefined, __Q?: Buffer | undefined, options?: ECPairOptions); 24 | readonly privateKey: Buffer | undefined; 25 | readonly publicKey: Buffer; 26 | toWIF(): string; 27 | sign(hash: Buffer, lowR?: boolean): Buffer; 28 | verify(hash: Buffer, signature: Buffer): boolean; 29 | } 30 | declare function fromPrivateKey(buffer: Buffer, options?: ECPairOptions): ECPair; 31 | declare function fromPublicKey(buffer: Buffer, options?: ECPairOptions): ECPair; 32 | declare function fromWIF(wifString: string, network?: Network | Network[]): ECPair; 33 | declare function makeRandom(options?: ECPairOptions): ECPair; 34 | export { makeRandom, fromPrivateKey, fromPublicKey, fromWIF }; 35 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as bip32 from 'bip32'; 2 | import * as address from './address'; 3 | import * as crypto from './crypto'; 4 | import * as ECPair from './ecpair'; 5 | import * as networks from './networks'; 6 | import * as payments from './payments'; 7 | import * as script from './script'; 8 | export { ECPair, address, bip32, crypto, networks, payments, script }; 9 | export { Block } from './block'; 10 | export { OPS as opcodes } from './script'; 11 | export { Transaction } from './transaction'; 12 | export { TransactionBuilder } from './transaction_builder'; 13 | export { BIP32Interface } from 'bip32'; 14 | export { ECPairInterface } from './ecpair'; 15 | export { Network } from './networks'; 16 | export { Payment, PaymentOpts, Stack, StackElement } from './payments'; 17 | export { OpCode } from './script'; 18 | export { Input as TxInput, Output as TxOutput } from './transaction'; 19 | -------------------------------------------------------------------------------- /types/networks.d.ts: -------------------------------------------------------------------------------- 1 | export interface Network { 2 | messagePrefix: string; 3 | bech32: string; 4 | bip32: Bip32; 5 | pubKeyHash: number; 6 | scriptHash: number; 7 | wif: number; 8 | } 9 | interface Bip32 { 10 | public: number; 11 | private: number; 12 | } 13 | export declare const bitcoin: Network; 14 | export declare const regtest: Network; 15 | export declare const testnet: Network; 16 | export {}; 17 | -------------------------------------------------------------------------------- /types/payments/embed.d.ts: -------------------------------------------------------------------------------- 1 | import { Payment, PaymentOpts } from './index'; 2 | export declare function p2data(a: Payment, opts?: PaymentOpts): Payment; 3 | -------------------------------------------------------------------------------- /types/payments/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Network } from '../networks'; 3 | import { p2data as embed } from './embed'; 4 | import { p2ms } from './p2ms'; 5 | import { p2pk } from './p2pk'; 6 | import { p2pkh } from './p2pkh'; 7 | import { p2sh } from './p2sh'; 8 | import { p2wpkh } from './p2wpkh'; 9 | import { p2wsh } from './p2wsh'; 10 | export interface Payment { 11 | network?: Network; 12 | output?: Buffer; 13 | data?: Buffer[]; 14 | m?: number; 15 | n?: number; 16 | pubkeys?: Buffer[]; 17 | input?: Buffer; 18 | signatures?: Buffer[]; 19 | pubkey?: Buffer; 20 | signature?: Buffer; 21 | address?: string; 22 | hash?: Buffer; 23 | redeem?: Payment; 24 | witness?: Buffer[]; 25 | } 26 | export declare type PaymentFunction = () => Payment; 27 | export interface PaymentOpts { 28 | validate?: boolean; 29 | allowIncomplete?: boolean; 30 | } 31 | export declare type StackElement = Buffer | number; 32 | export declare type Stack = StackElement[]; 33 | export declare type StackFunction = () => Stack; 34 | export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh }; 35 | -------------------------------------------------------------------------------- /types/payments/lazy.d.ts: -------------------------------------------------------------------------------- 1 | export declare function prop(object: {}, name: string, f: () => any): void; 2 | export declare function value(f: () => T): () => T; 3 | -------------------------------------------------------------------------------- /types/payments/p2ms.d.ts: -------------------------------------------------------------------------------- 1 | import { Payment, PaymentOpts } from './index'; 2 | export declare function p2ms(a: Payment, opts?: PaymentOpts): Payment; 3 | -------------------------------------------------------------------------------- /types/payments/p2pk.d.ts: -------------------------------------------------------------------------------- 1 | import { Payment, PaymentOpts } from './index'; 2 | export declare function p2pk(a: Payment, opts?: PaymentOpts): Payment; 3 | -------------------------------------------------------------------------------- /types/payments/p2pkh.d.ts: -------------------------------------------------------------------------------- 1 | import { Payment, PaymentOpts } from './index'; 2 | export declare function p2pkh(a: Payment, opts?: PaymentOpts): Payment; 3 | -------------------------------------------------------------------------------- /types/payments/p2sh.d.ts: -------------------------------------------------------------------------------- 1 | import { Payment, PaymentOpts } from './index'; 2 | export declare function p2sh(a: Payment, opts?: PaymentOpts): Payment; 3 | -------------------------------------------------------------------------------- /types/payments/p2wpkh.d.ts: -------------------------------------------------------------------------------- 1 | import { Payment, PaymentOpts } from './index'; 2 | export declare function p2wpkh(a: Payment, opts?: PaymentOpts): Payment; 3 | -------------------------------------------------------------------------------- /types/payments/p2wsh.d.ts: -------------------------------------------------------------------------------- 1 | import { Payment, PaymentOpts } from './index'; 2 | export declare function p2wsh(a: Payment, opts?: PaymentOpts): Payment; 3 | -------------------------------------------------------------------------------- /types/script.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Stack } from './payments'; 3 | import * as scriptNumber from './script_number'; 4 | import * as scriptSignature from './script_signature'; 5 | export declare type OpCode = number; 6 | export declare const OPS: { 7 | [index: string]: number; 8 | }; 9 | export declare function isPushOnly(value: Stack): boolean; 10 | export declare function compile(chunks: Buffer | Stack): Buffer; 11 | export declare function decompile(buffer: Buffer | Array): Array | null; 12 | export declare function toASM(chunks: Buffer | Array): string; 13 | export declare function fromASM(asm: string): Buffer; 14 | export declare function toStack(chunks: Buffer | Array): Buffer[]; 15 | export declare function isCanonicalPubKey(buffer: Buffer): boolean; 16 | export declare function isDefinedHashType(hashType: number): boolean; 17 | export declare function isCanonicalScriptSignature(buffer: Buffer): boolean; 18 | export declare const number: typeof scriptNumber; 19 | export declare const signature: typeof scriptSignature; 20 | -------------------------------------------------------------------------------- /types/script_number.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare function decode(buffer: Buffer, maxLength?: number, minimal?: boolean): number; 3 | export declare function encode(_number: number): Buffer; 4 | -------------------------------------------------------------------------------- /types/script_signature.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | interface ScriptSignature { 3 | signature: Buffer; 4 | hashType: number; 5 | } 6 | export declare function decode(buffer: Buffer): ScriptSignature; 7 | export declare function encode(signature: Buffer, hashType: number): Buffer; 8 | export {}; 9 | -------------------------------------------------------------------------------- /types/templates/multisig/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as input from './input'; 2 | import * as output from './output'; 3 | export { input, output }; 4 | -------------------------------------------------------------------------------- /types/templates/multisig/input.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Stack } from '../../payments'; 3 | export declare function check(script: Buffer | Stack, allowIncomplete?: boolean): boolean; 4 | export declare namespace check { 5 | var toJSON: () => string; 6 | } 7 | -------------------------------------------------------------------------------- /types/templates/multisig/output.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Stack } from '../../payments'; 3 | export declare function check(script: Buffer | Stack, allowIncomplete?: boolean): boolean; 4 | export declare namespace check { 5 | var toJSON: () => string; 6 | } 7 | -------------------------------------------------------------------------------- /types/templates/nulldata.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare function check(script: Buffer | Array): boolean; 3 | export declare namespace check { 4 | var toJSON: () => string; 5 | } 6 | declare const output: { 7 | check: typeof check; 8 | }; 9 | export { output }; 10 | -------------------------------------------------------------------------------- /types/templates/pubkey/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as input from './input'; 2 | import * as output from './output'; 3 | export { input, output }; 4 | -------------------------------------------------------------------------------- /types/templates/pubkey/input.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Stack } from '../../payments'; 3 | export declare function check(script: Buffer | Stack): boolean; 4 | export declare namespace check { 5 | var toJSON: () => string; 6 | } 7 | -------------------------------------------------------------------------------- /types/templates/pubkey/output.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Stack } from '../../payments'; 3 | export declare function check(script: Buffer | Stack): boolean; 4 | export declare namespace check { 5 | var toJSON: () => string; 6 | } 7 | -------------------------------------------------------------------------------- /types/templates/pubkeyhash/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as input from './input'; 2 | import * as output from './output'; 3 | export { input, output }; 4 | -------------------------------------------------------------------------------- /types/templates/pubkeyhash/input.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Stack } from '../../payments'; 3 | export declare function check(script: Buffer | Stack): boolean; 4 | export declare namespace check { 5 | var toJSON: () => string; 6 | } 7 | -------------------------------------------------------------------------------- /types/templates/pubkeyhash/output.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare function check(script: Buffer | Array): boolean; 3 | export declare namespace check { 4 | var toJSON: () => string; 5 | } 6 | -------------------------------------------------------------------------------- /types/templates/scripthash/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as input from './input'; 2 | import * as output from './output'; 3 | export { input, output }; 4 | -------------------------------------------------------------------------------- /types/templates/scripthash/input.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare function check(script: Buffer | Array, allowIncomplete?: boolean): boolean; 3 | export declare namespace check { 4 | var toJSON: () => string; 5 | } 6 | -------------------------------------------------------------------------------- /types/templates/scripthash/output.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare function check(script: Buffer | Array): boolean; 3 | export declare namespace check { 4 | var toJSON: () => string; 5 | } 6 | -------------------------------------------------------------------------------- /types/templates/witnesscommitment/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as output from './output'; 2 | export { output }; 3 | -------------------------------------------------------------------------------- /types/templates/witnesscommitment/output.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare function check(script: Buffer | Array): boolean; 3 | export declare namespace check { 4 | var toJSON: () => string; 5 | } 6 | export declare function encode(commitment: Buffer): Buffer; 7 | export declare function decode(buffer: Buffer): Buffer; 8 | -------------------------------------------------------------------------------- /types/templates/witnesspubkeyhash/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as input from './input'; 2 | import * as output from './output'; 3 | export { input, output }; 4 | -------------------------------------------------------------------------------- /types/templates/witnesspubkeyhash/input.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Stack } from '../../payments'; 3 | export declare function check(script: Buffer | Stack): boolean; 4 | export declare namespace check { 5 | var toJSON: () => string; 6 | } 7 | -------------------------------------------------------------------------------- /types/templates/witnesspubkeyhash/output.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare function check(script: Buffer | Array): boolean; 3 | export declare namespace check { 4 | var toJSON: () => string; 5 | } 6 | -------------------------------------------------------------------------------- /types/templates/witnessscripthash/index.d.ts: -------------------------------------------------------------------------------- 1 | import * as input from './input'; 2 | import * as output from './output'; 3 | export { input, output }; 4 | -------------------------------------------------------------------------------- /types/templates/witnessscripthash/input.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare function check(chunks: Buffer[], allowIncomplete?: boolean): boolean; 3 | export declare namespace check { 4 | var toJSON: () => string; 5 | } 6 | -------------------------------------------------------------------------------- /types/templates/witnessscripthash/output.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare function check(script: Buffer | Array): boolean; 3 | export declare namespace check { 4 | var toJSON: () => string; 5 | } 6 | -------------------------------------------------------------------------------- /types/transaction.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export interface BlankOutput { 3 | script: Buffer; 4 | valueBuffer: Buffer; 5 | } 6 | export interface Output { 7 | script: Buffer; 8 | value: number; 9 | } 10 | declare type OpenOutput = Output | BlankOutput; 11 | export interface Input { 12 | hash: Buffer; 13 | index: number; 14 | script: Buffer; 15 | sequence: number; 16 | witness: Buffer[]; 17 | } 18 | export declare class Transaction { 19 | static readonly DEFAULT_SEQUENCE = 4294967295; 20 | static readonly SIGHASH_ALL = 1; 21 | static readonly SIGHASH_NONE = 2; 22 | static readonly SIGHASH_SINGLE = 3; 23 | static readonly SIGHASH_ANYONECANPAY = 128; 24 | static readonly ADVANCED_TRANSACTION_MARKER = 0; 25 | static readonly ADVANCED_TRANSACTION_FLAG = 1; 26 | static fromBuffer(buffer: Buffer, _NO_STRICT?: boolean): Transaction; 27 | static fromHex(hex: string): Transaction; 28 | static isCoinbaseHash(buffer: Buffer): boolean; 29 | version: number; 30 | locktime: number; 31 | ins: Input[]; 32 | outs: OpenOutput[]; 33 | isCoinbase(): boolean; 34 | addInput(hash: Buffer, index: number, sequence?: number, scriptSig?: Buffer): number; 35 | addOutput(scriptPubKey: Buffer, value: number): number; 36 | hasWitnesses(): boolean; 37 | weight(): number; 38 | virtualSize(): number; 39 | byteLength(): number; 40 | clone(): Transaction; 41 | /** 42 | * Hash transaction for signing a specific input. 43 | * 44 | * Bitcoin uses a different hash for each signed transaction input. 45 | * This method copies the transaction, makes the necessary changes based on the 46 | * hashType, and then hashes the result. 47 | * This hash can then be used to sign the provided transaction input. 48 | */ 49 | hashForSignature(inIndex: number, prevOutScript: Buffer, hashType: number): Buffer; 50 | hashForWitnessV0(inIndex: number, prevOutScript: Buffer, value: number, hashType: number): Buffer; 51 | getHash(forWitness?: boolean): Buffer; 52 | getId(): string; 53 | toBuffer(buffer?: Buffer, initialOffset?: number): Buffer; 54 | toHex(): string; 55 | setInputScript(index: number, scriptSig: Buffer): void; 56 | setWitness(index: number, witness: Buffer[]): void; 57 | private __byteLength; 58 | private __toBuffer; 59 | } 60 | export {}; 61 | -------------------------------------------------------------------------------- /types/transaction_builder.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { ECPairInterface } from './ecpair'; 3 | import { Network } from './networks'; 4 | import { Transaction } from './transaction'; 5 | export declare class TransactionBuilder { 6 | network: Network; 7 | maximumFeeRate: number; 8 | static fromTransaction(transaction: Transaction, network?: Network): TransactionBuilder; 9 | private __PREV_TX_SET; 10 | private __INPUTS; 11 | private __TX; 12 | private __USE_LOW_R; 13 | constructor(network?: Network, maximumFeeRate?: number); 14 | setLowR(setting?: boolean): boolean; 15 | setLockTime(locktime: number): void; 16 | setVersion(version: number): void; 17 | addInput(txHash: Buffer | string | Transaction, vout: number, sequence?: number, prevOutScript?: Buffer): number; 18 | addOutput(scriptPubKey: string | Buffer, value: number): number; 19 | build(): Transaction; 20 | buildIncomplete(): Transaction; 21 | sign(vin: number, keyPair: ECPairInterface, redeemScript?: Buffer, hashType?: number, witnessValue?: number, witnessScript?: Buffer): void; 22 | private __addInputUnsafe; 23 | private __build; 24 | private __canModifyInputs; 25 | private __needsOutputs; 26 | private __canModifyOutputs; 27 | private __overMaximumFees; 28 | } 29 | -------------------------------------------------------------------------------- /types/types.d.ts: -------------------------------------------------------------------------------- 1 | export declare function UInt31(value: number): boolean; 2 | export declare function BIP32Path(value: string): boolean; 3 | export declare namespace BIP32Path { 4 | var toJSON: () => string; 5 | } 6 | export declare function Satoshi(value: number): boolean; 7 | export declare const ECPoint: any; 8 | export declare const Network: any; 9 | export declare const Buffer256bit: any; 10 | export declare const Hash160bit: any; 11 | export declare const Hash256bit: any; 12 | export declare const Number: any; 13 | export declare const Array: any; 14 | export declare const Boolean: any; 15 | export declare const String: any; 16 | export declare const Buffer: any; 17 | export declare const Hex: any; 18 | export declare const maybe: any; 19 | export declare const tuple: any; 20 | export declare const UInt8: any; 21 | export declare const UInt32: any; 22 | export declare const Function: any; 23 | export declare const BufferN: any; 24 | export declare const Null: any; 25 | export declare const oneOf: any; 26 | --------------------------------------------------------------------------------