├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── example ├── android │ ├── app │ │ ├── BUCK │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── rnbitcoinjsexample │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── keystores │ │ └── BUCK │ └── settings.gradle ├── index.android.js ├── index.ios.js ├── ios │ ├── RNBitcoinJSExample.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── RNBitcoinJSExample.xcscheme │ ├── RNBitcoinJSExample │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Base.lproj │ │ │ └── LaunchScreen.xib │ │ ├── Images.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ └── main.m │ └── RNBitcoinJSExampleTests │ │ ├── Info.plist │ │ └── RNBitcoinJSExampleTests.m ├── package.json └── shim.js ├── package.json └── src ├── address.js ├── block.js ├── bufferutils.js ├── crypto.js ├── ecdsa.js ├── ecpair.js ├── ecsignature.js ├── hdnode.js ├── index.js ├── networks.js ├── script.js ├── script_number.js ├── templates ├── index.js ├── 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 /.gitignore: -------------------------------------------------------------------------------- 1 | coverage 2 | node_modules 3 | .nyc_output 4 | npm-debug.log 5 | 6 | # OSX 7 | # 8 | .DS_Store 9 | 10 | # Xcode 11 | # 12 | build/ 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata 22 | *.xccheckout 23 | *.moved-aside 24 | DerivedData 25 | *.hmap 26 | *.ipa 27 | *.xcuserstate 28 | project.xcworkspace 29 | 30 | # Android/IJ 31 | # 32 | *.iml 33 | .idea 34 | .gradle 35 | local.properties 36 | android/app/build 37 | 38 | # node.js 39 | # 40 | node_modules/ 41 | npm-debug.log 42 | 43 | # BUCK 44 | buck-out/ 45 | \.buckd/ 46 | android/app/libs 47 | android/keystores/debug.keystore 48 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "4" 5 | - "5" 6 | - "6" 7 | - "7" 8 | matrix: 9 | include: 10 | - node_js: "7" 11 | env: TEST_SUITE=standard 12 | - node_js: "7" 13 | env: TEST_SUITE=coverage 14 | env: 15 | - TEST_SUITE=integration 16 | - TEST_SUITE=unit 17 | script: npm run-script $TEST_SUITE 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 3.0.0 2 | From this release users can expect out-of-the-box Segregated Witness support. 3 | The majority of breaking changes have been in how `script` encoding/decoding occurs, with the introduction of witness stacks. 4 | 5 | __added__ 6 | - Added `script.types` enums (#679) 7 | - Added `script.*.*.{check,encode,decode[,encodeStack,decodeStack]}` functions (#681, #682) 8 | - Added minimal `TransactionBuilder.prototype.build` absurd fee-safety (#696) 9 | - Added `script.(decompile/compile)PushOnly` and `script.toStack` functions (#700) 10 | - Added `Transaction.prototype.toBuffer` Segregated Witness serialization support (#684, #701) 11 | - Added `Transaction.prototype.hasWitnesses` (#718) 12 | - Added `script.witnessCommitment.*` template 13 | - Added `TransactionBuilder.prototype.sign` now has two additional parameters, `witnessValue`, and `witnessScript` 14 | - Added `Transaction.hashForWitnessV0` and `Transaction.setWitness` (5c2fdb60436714f18440dc709f0be065928c1e49) 15 | 16 | __fixed__ 17 | - Fixed `script` must compile minimally (#638) 18 | - Fixed `Transaction` and `Block` versions should be Int32, signed integers (#662) 19 | 20 | __removed__ 21 | - Removed `ecdsa.calcPubKeyRecoveryParam`, `ecdsa.recoverPubKey` (#456) 22 | - Removed `buffer-equals`/`buffer-compare` dependencies (#650) 23 | - Removed `HDNode.prototype.toString` (#665) 24 | - Removed `dogecoin` network (#675) 25 | - Removed `message` export, moved to [`bitcoinjs-message`](https://github.com/bitcoinjs/bitcoinjs-message) (#456) 26 | 27 | __renamed__ 28 | - Removed `script.*` functions in favour of `bitcoin.script.*.(input/output).(encode/decode/check)` style (#682) 29 | 30 | # 2.3.0 31 | __added__ 32 | - Added `HDNode.prototype.isNeutered` (#536) 33 | - Added `HDNode.prototype.derivePath` (#538) 34 | - Added typeforce checking for `HDNode.prototype.derive*` (#539) 35 | - Added `Transaction.prototype.isCoinbase` (#578) 36 | - Added `Block.prototype.checkMerkleRoot` (#580) 37 | - Added `Block.calculateMerkleRoot` (#580) 38 | - Added `TransactionBuilder.prototype.setVersion` (#599) 39 | - Added `script.isWitnessPubKeyHashOutput` (#602) 40 | - Added `script.isWitnessScriptHashOutput` (#602) 41 | - Added `script.witnessPubKeyHashOutput` (#602) 42 | - Added `script.witnessScriptHashOutput` (#602) 43 | - Added `script.witnessScriptHashInput` (#602) 44 | 45 | __fixed__ 46 | - Fixed "BIP32 is undefined" when network list given to `HDNode` but no compatible version found (#550) 47 | - Fixed `writePushDataInt` output to adhere to minimal data push policy (#617) 48 | 49 | 50 | # 2.2.0 51 | __added__ 52 | - Added `Block.calculateTarget` for difficulty calculations (#509) 53 | - Added `Block.prototype.checkProofOfWork` (#509) 54 | - Added `opcodes.OP_CHECKLOCKTIMEVERIFY` alias for `OP_NOP2` (#511) 55 | - Added `script.number.[encode/decode]` for CScriptNum-encoded `Buffer`s (#516) 56 | - Added `TransactionBuilder.prototype.setLockTime` (#507) 57 | 58 | __fixed__ 59 | - Bumped `typeforce` version to fix erroneous error message from `types.Hash*bit` types (#534) 60 | 61 | 62 | # 2.1.4 63 | __fixed__ 64 | - script.isPubKeyHashOutput and script.isScriptHashOutput no longer allow for non-minimal data pushes (per bitcoin/bitcoin `IsStandard` policy) (#499) 65 | - TransactionBuilder.addOutput now allows for SIGHASH_SINGLE, throwing if the contract is violated (#504) 66 | - remove use of `const`, use ES5 only (#502) 67 | 68 | 69 | # 2.1.3 70 | __fixed__ 71 | - Bumped typeforce to 1.5.5 (see #493) 72 | 73 | 74 | # 2.1.2 75 | __fixed__ 76 | - Add missing CHANGELOG entry for 2.1.1 77 | 78 | 79 | # 2.1.1 80 | __changed__ 81 | - removed use of `buffer-reverse`, dependency only kept for `bufferutils.reverse`, to be deprecated (#478) 82 | 83 | __fixed__ 84 | - `isMultisigOutput` no longer allows data chunks for `m`/`n` (#482) 85 | - `isMultisigOutput`'s `n` value must now match the number of public keys (as per bitcoin/bitcoin) (#484) 86 | 87 | 88 | # 2.1.0 89 | From this release users should use the HDNode directly (compared to accessing `.keyPair`) when performing ECDSA operations such as `sign` or `verify`. 90 | Ideally you shoud not have to directly access `HDNode` internals for general usage, as it can often be confusing and error prone. 91 | 92 | __added__ 93 | - `ECPair.prototype.getNetwork` 94 | - `HDNode.prototype.getNetwork`, wraps the underyling keyPair's `getNetwork` method 95 | - `HDNode.prototype.getPublicKeyBuffer`, wraps the underyling keyPair's `getPublicKeyBuffer` method 96 | - `HDNode.prototype.sign`, wraps the underlying keyPair's `sign` method 97 | - `HDNode.prototype.verify`, wraps the underlying keyPair's `verify` method 98 | 99 | 100 | # 2.0.0 101 | 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. 102 | 103 | 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. 104 | Several other cumbersome modules have been removed, with their new independent modules recommended for usage instead for greater modularity in your projects. 105 | 106 | ----------------------------- 107 | 108 | Backward incompatible changes: 109 | 110 | __added__ 111 | - 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 112 | - 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 113 | - export `ECPair`, a merged replacement for `ECKey`/`ECPubKey`, invalid types will throw via `typeforce` 114 | 115 | __changed__ 116 | - `address.toOutputScript`, `ECPair.prototype.fromWIF` and `HDNode.prototype.fromBase58` no longer automatically detect the network, `networks.bitcoin` is always assumed unless given. 117 | - `assert` was used for type checking, now replaced by `typeforce` 118 | - `BIP66` compliant strict DER signature validation was added to `ECSignature.fromDER`, changing the exact exception messages slightly, see #448. 119 | 120 | - `new HDNode(d/Q, chainCode, network)` -> `new HDNode(keyPair, chainCode)`, now uses `ECPair` 121 | - `HDNode.prototype.toBase58(false)` -> `HDNode.prototype.neutered().toBase58()` for exporting an extended public key 122 | - `HDNode.prototype.toBase58(true)` -> `HDNode.prototype.toBase58()` for exporting an extended private key 123 | 124 | - `Transaction.prototype.hashForSignature(prevOutScript, inIndex, hashType)` -> `Transaction.prototype.hashForSignature(inIndex, prevOutScript, hashType)` 125 | - `Transaction.prototype.addInput(hash, ...)`: `hash` could be a string, Transaction or Buffer -> `hash` can now **only** be a `Buffer`. 126 | - `Transaction.prototype.addOutput(scriptPubKey, ...)`: `scriptPubKey ` could be a string, `Address` or a `Buffer` -> `scriptPubKey` can now **only** be a `Buffer`. 127 | - `TransactionBuilder` API unchanged. 128 | 129 | __removed__ 130 | - export `Address`, `strings` are now used, benchwith no performance loss for most use cases 131 | - export `base58check`, use [`bs58check`](https://github.com/bitcoinjs/bs58check) instead 132 | - export `ecdsa`, use [`ecurve`](https://github.com/cryptocoinjs/ecurve) instead 133 | - export `ECKey`, use new export `ECPair` instead 134 | - export `ECPubKey`, use new export `ECPair` instead 135 | - export `Wallet`, see README.md#complementing-libraries instead 136 | - export `Script`, use new utility export `script` instead (#438 for more information) 137 | 138 | - `crypto.HmacSHA256 `, use [node crypto](https://nodejs.org/api/crypto.html) instead 139 | - `crypto.HmacSHA512 `, use [node crypto](https://nodejs.org/api/crypto.html) instead 140 | 141 | - `Transaction.prototype.sign`, use `TransactionBuilder.prototype.sign` 142 | - `Transaction.prototype.signInput`, use `TransactionBuilder.prototype.sign` 143 | - `Transaction.prototype.validateInput`, use `Transaction.prototype.hashForSignature` and `ECPair.verify` 144 | 145 | - `HDNode.fromBuffer`, use `HDNode.fromBase58` instead 146 | - `HDNode.fromHex`, use `HDNode.fromBase58` instead 147 | - `HDNode.toBuffer`, use `HDNode.prototype.toBase58` instead 148 | - `HDNode.toHex`, use `HDNode.prototype.toBase58` instead 149 | 150 | - `networks.*.magic`, see the comment [here](https://github.com/bitcoinjs/bitcoinjs-lib/pull/432/files#r36715792) 151 | - `networks.[viacoin|viacointestnet|gamerscoin|jumbucks|zetacoin]`, import these yourself (see #383/a0e6ee7) 152 | - `networks.*.estimateFee`, out-dated 153 | 154 | __renamed__ 155 | - `Message` -> `message` 156 | - `scripts` -> `script` 157 | - `scripts.dataOutput ` -> `script.nullDataOutput` (per [convention](https://org/en/glossary/null-data-transaction)) 158 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2016 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 | # ReactNative BitcoinJS (react-native-bitcoinjs-lib) 2 | 3 | [![Build Status](https://travis-ci.org/bitcoinjs/bitcoinjs-lib.png?branch=master)](https://travis-ci.org/bitcoinjs/bitcoinjs-lib) 4 | [![NPM](https://img.shields.io/npm/v/bitcoinjs-lib.svg)](https://www.npmjs.org/package/bitcoinjs-lib) 5 | [![tip for next commit](https://tip4commit.com/projects/735.svg)](http://tip4commit.com/projects/735) 6 | 7 | [![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) 8 | 9 | 10 | ReactNative-ready fork of the [original bitcoinjs package](https://github.com/bitcoinjs/bitcoinjs-lib). 11 | Used by over a million wallet users and the backbone for almost all Bitcoin web wallets in production today. 12 | 13 | 14 | ## Features 15 | 16 | - Clean: Pure JavaScript, concise code, easy to read. 17 | - Tested: Coverage > 90%, third-party integration tests. 18 | - Careful: Two person approval process for small, focused pull requests. 19 | - Compatible: Works on Node.js and all modern browsers. 20 | - Powerful: Support for advanced features, such as multi-sig, HD Wallets. 21 | - Secure: Strong random number generation, PGP signed releases, trusted developers. 22 | - Principled: No support for browsers with crap RNG (IE < 11) 23 | - Standardized: Node community coding style, Browserify, Node's stdlib and Buffers. 24 | - Fast: Optimized code, uses typed arrays instead of byte arrays for performance. 25 | - Experiment-friendly: Bitcoin Mainnet and Testnet support. 26 | - Altcoin-ready: Capable of working with bitcoin-derived cryptocurrencies (such as Dogecoin). 27 | 28 | ## Installation 29 | 30 | `npm i react-native-bitcoinjs-lib --save` 31 | 32 | 33 | ## Setup 34 | 35 | Create the react native project. 36 | 37 | `react-native init fooApp` 38 | 39 | Install rn-nodeify to be able to use Node.js libs. 40 | 41 | `npm i rn-nodeify -g` 42 | 43 | Add this postinstall script to install & hack the Node.js libs for the usage in React Native. 44 | 45 | `"postinstall": "rn-nodeify --install stream,buffer,events,assert --hack"` 46 | 47 | Install & link required dependencies. 48 | 49 | `npm i react-native-bitcoinjs-lib react-native-randombytes --save && react-native link react-native-randombytes` 50 | 51 | Run the postinstall, it will create a shim.js file which you need to include in your index file (see Usage). 52 | 53 | `npm run postinstall` 54 | 55 | Run the app 56 | 57 | `react-native run-android` or `react-native run-ios` 58 | 59 | ## Usage 60 | 61 | Edit index.android.js and index.ios.js 62 | 63 | ```javascript 64 | // node.js libs 65 | import './shim' // make sure to use es6 import and not require() 66 | import Bitcoin from 'react-native-bitcoinjs-lib' 67 | [...] 68 | const keypair = Bitcoin.ECPair.makeRandom() 69 | console.log(keypair.getAddress()) // your brand new base58-encoded Bitcoin address 70 | ``` 71 | 72 | 73 | ## Examples 74 | 75 | Run the example app or refer to the [original repository](https://github.com/bitcoinjs/bitcoinjs-lib#examples) for more available examples. 76 | 77 | 78 | ## Projects utilizing BitcoinJS [for Node.js and Browsers](https://github.com/bitcoinjs/bitcoinjs-lib) 79 | 80 | - [BitAddress](https://www.bitaddress.org) 81 | - [Blockchain.info](https://blockchain.info/wallet) 82 | - [Blocktrail](https://www.blocktrail.com/) 83 | - [Dark Wallet](https://www.darkwallet.is/) 84 | - [DecentralBank](http://decentralbank.com/) 85 | - [Dogechain Wallet](https://dogechain.info) 86 | - [EI8HT Wallet](http://ei8.ht/) 87 | - [GreenAddress](https://greenaddress.it) 88 | - [Robocoin](https://wallet.robocoin.com) 89 | - [Skyhook ATM](http://projectskyhook.com) 90 | 91 | ## Projects utilizing BitcoinJS [for React Native](https://github.com/nexustech-solutions/react-native-bitcoinjs-lib) 92 | 93 | - [ReactNative Bitcoin Wallet](https://github.com/nexustech-solutions/react-native-bitcoin-wallet) 94 | 95 | ## Complementing Libraries 96 | 97 | - [BIP21](https://github.com/bitcoinjs/bip21) - A BIP21 compatible URL encoding utility library 98 | - [BIP38](https://github.com/bitcoinjs/bip38) - Passphrase-protected private keys 99 | - [BIP39](https://github.com/novalabio/react-native-bip39) - ReactNative-ready Mnemonic generation for deterministic keys 100 | - [BIP32-Utils](https://github.com/novalabio/react-native-bip32-utils) - ReactNative-ready set of utilities for working with BIP32 101 | - [BIP32-Wallet](https://github.com/bitcoinjs/bip32-wallet) - A BIP32 Wallet backed by bitcoinjs-lib, lite on features but heavily tested 102 | - [BIP66](https://github.com/bitcoinjs/bip66) - Strict DER signature decoding 103 | - [BIP69](https://github.com/bitcoinjs/bip69) - Lexicographical Indexing of Transaction Inputs and Outputs 104 | - [Base58](https://github.com/cryptocoinjs/bs58) - Base58 encoding/decoding 105 | - [Base58 Check](https://github.com/bitcoinjs/bs58check) - Base58 check encoding/decoding 106 | - [BCoin](https://github.com/indutny/bcoin) - BIP37 / Bloom Filters / SPV client 107 | - [insight](https://github.com/bitpay/insight) - A bitcoin blockchain API for web wallets. 108 | 109 | 110 | ## Alternatives 111 | 112 | There are currently no alternatives for React Native. 113 | 114 | ## LICENSE [MIT](LICENSE) 115 | 116 | 117 | ## Copyright 118 | 119 | BitcoinJS (c) 2011-2016 bitcoinjs-lib contributors 120 | 121 | Released under MIT license 122 | -------------------------------------------------------------------------------- /example/android/app/BUCK: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | # To learn about Buck see [Docs](https://buckbuild.com/). 4 | # To run your application with Buck: 5 | # - install Buck 6 | # - `npm start` - to start the packager 7 | # - `cd android` 8 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 9 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 10 | # - `buck install -r android/app` - compile, install and run application 11 | # 12 | 13 | lib_deps = [] 14 | for jarfile in glob(['libs/*.jar']): 15 | name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile) 16 | lib_deps.append(':' + name) 17 | prebuilt_jar( 18 | name = name, 19 | binary_jar = jarfile, 20 | ) 21 | 22 | for aarfile in glob(['libs/*.aar']): 23 | name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile) 24 | lib_deps.append(':' + name) 25 | android_prebuilt_aar( 26 | name = name, 27 | aar = aarfile, 28 | ) 29 | 30 | android_library( 31 | name = 'all-libs', 32 | exported_deps = lib_deps 33 | ) 34 | 35 | android_library( 36 | name = 'app-code', 37 | srcs = glob([ 38 | 'src/main/java/**/*.java', 39 | ]), 40 | deps = [ 41 | ':all-libs', 42 | ':build_config', 43 | ':res', 44 | ], 45 | ) 46 | 47 | android_build_config( 48 | name = 'build_config', 49 | package = 'com.rnbitcoinjsexample', 50 | ) 51 | 52 | android_resource( 53 | name = 'res', 54 | res = 'src/main/res', 55 | package = 'com.rnbitcoinjsexample', 56 | ) 57 | 58 | android_binary( 59 | name = 'app', 60 | package_type = 'debug', 61 | manifest = 'src/main/AndroidManifest.xml', 62 | keystore = '//android/keystores:debug', 63 | deps = [ 64 | ':app-code', 65 | ], 66 | ) 67 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // whether to bundle JS and assets in debug mode 22 | * bundleInDebug: false, 23 | * 24 | * // whether to bundle JS and assets in release mode 25 | * bundleInRelease: true, 26 | * 27 | * // whether to bundle JS and assets in another build variant (if configured). 28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 29 | * // The configuration property can be in the following formats 30 | * // 'bundleIn${productFlavor}${buildType}' 31 | * // 'bundleIn${buildType}' 32 | * // bundleInFreeDebug: true, 33 | * // bundleInPaidRelease: true, 34 | * // bundleInBeta: true, 35 | * 36 | * // the root of your project, i.e. where "package.json" lives 37 | * root: "../../", 38 | * 39 | * // where to put the JS bundle asset in debug mode 40 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 41 | * 42 | * // where to put the JS bundle asset in release mode 43 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 44 | * 45 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 46 | * // require('./image.png')), in debug mode 47 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 48 | * 49 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 50 | * // require('./image.png')), in release mode 51 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 52 | * 53 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 54 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 55 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 56 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 57 | * // for example, you might want to remove it from here. 58 | * inputExcludes: ["android/**", "ios/**"], 59 | * 60 | * // override which node gets called and with what additional arguments 61 | * nodeExecutableAndArgs: ["node"] 62 | * 63 | * // supply additional arguments to the packager 64 | * extraPackagerArgs: [] 65 | * ] 66 | */ 67 | 68 | apply from: "../../node_modules/react-native/react.gradle" 69 | 70 | /** 71 | * Set this to true to create two separate APKs instead of one: 72 | * - An APK that only works on ARM devices 73 | * - An APK that only works on x86 devices 74 | * The advantage is the size of the APK is reduced by about 4MB. 75 | * Upload all the APKs to the Play Store and people will download 76 | * the correct one based on the CPU architecture of their device. 77 | */ 78 | def enableSeparateBuildPerCPUArchitecture = false 79 | 80 | /** 81 | * Run Proguard to shrink the Java bytecode in release builds. 82 | */ 83 | def enableProguardInReleaseBuilds = false 84 | 85 | android { 86 | compileSdkVersion 23 87 | buildToolsVersion "23.0.1" 88 | 89 | defaultConfig { 90 | applicationId "com.rnbitcoinjsexample" 91 | minSdkVersion 16 92 | targetSdkVersion 22 93 | versionCode 1 94 | versionName "1.0" 95 | ndk { 96 | abiFilters "armeabi-v7a", "x86" 97 | } 98 | } 99 | splits { 100 | abi { 101 | reset() 102 | enable enableSeparateBuildPerCPUArchitecture 103 | universalApk false // If true, also generate a universal APK 104 | include "armeabi-v7a", "x86" 105 | } 106 | } 107 | buildTypes { 108 | release { 109 | minifyEnabled enableProguardInReleaseBuilds 110 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 111 | } 112 | } 113 | // applicationVariants are e.g. debug, release 114 | applicationVariants.all { variant -> 115 | variant.outputs.each { output -> 116 | // For each separate APK per architecture, set a unique version code as described here: 117 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 118 | def versionCodes = ["armeabi-v7a":1, "x86":2] 119 | def abi = output.getFilter(OutputFile.ABI) 120 | if (abi != null) { // null for the universal-debug, universal-release variants 121 | output.versionCodeOverride = 122 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 123 | } 124 | } 125 | } 126 | } 127 | 128 | dependencies { 129 | compile project(':react-native-randombytes') 130 | compile fileTree(dir: "libs", include: ["*.jar"]) 131 | compile "com.android.support:appcompat-v7:23.0.1" 132 | compile "com.facebook.react:react-native:+" // From node_modules 133 | } 134 | 135 | // Run this once to be able to run the application with BUCK 136 | // puts all compile dependencies into folder libs for BUCK to use 137 | task copyDownloadableDepsToLibs(type: Copy) { 138 | from configurations.compile 139 | into 'libs' 140 | } 141 | -------------------------------------------------------------------------------- /example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 30 | 31 | # Do not strip any method/class that is annotated with @DoNotStrip 32 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 33 | -keep @com.facebook.common.internal.DoNotStrip class * 34 | -keepclassmembers class * { 35 | @com.facebook.proguard.annotations.DoNotStrip *; 36 | @com.facebook.common.internal.DoNotStrip *; 37 | } 38 | 39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 40 | void set*(***); 41 | *** get*(); 42 | } 43 | 44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 46 | -keepclassmembers,includedescriptorclasses class * { native ; } 47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 50 | 51 | -dontwarn com.facebook.react.** 52 | 53 | # okhttp 54 | 55 | -keepattributes Signature 56 | -keepattributes *Annotation* 57 | -keep class okhttp3.** { *; } 58 | -keep interface okhttp3.** { *; } 59 | -dontwarn okhttp3.** 60 | 61 | # okio 62 | 63 | -keep class sun.misc.Unsafe { *; } 64 | -dontwarn java.nio.file.* 65 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 66 | -dontwarn okio.** 67 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/rnbitcoinjsexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.rnbitcoinjsexample; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "RNBitcoinJSExample"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/rnbitcoinjsexample/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.rnbitcoinjsexample; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | 6 | import com.facebook.react.ReactApplication; 7 | import com.bitgo.randombytes.RandomBytesPackage; 8 | import com.facebook.react.ReactInstanceManager; 9 | import com.facebook.react.ReactNativeHost; 10 | import com.facebook.react.ReactPackage; 11 | import com.facebook.react.shell.MainReactPackage; 12 | 13 | import java.util.Arrays; 14 | import java.util.List; 15 | 16 | public class MainApplication extends Application implements ReactApplication { 17 | 18 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 19 | @Override 20 | protected boolean getUseDeveloperSupport() { 21 | return BuildConfig.DEBUG; 22 | } 23 | 24 | @Override 25 | protected List getPackages() { 26 | return Arrays.asList( 27 | new MainReactPackage(), 28 | new RandomBytesPackage() 29 | ); 30 | } 31 | }; 32 | 33 | @Override 34 | public ReactNativeHost getReactNativeHost() { 35 | return mReactNativeHost; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/novalabio/react-native-bitcoinjs-lib/84c2a4dafd25cc9f035a34754886ce3b8d3912e5/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/novalabio/react-native-bitcoinjs-lib/84c2a4dafd25cc9f035a34754886ce3b8d3912e5/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/novalabio/react-native-bitcoinjs-lib/84c2a4dafd25cc9f035a34754886ce3b8d3912e5/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/novalabio/react-native-bitcoinjs-lib/84c2a4dafd25cc9f035a34754886ce3b8d3912e5/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | RNBitcoinJSExample 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/novalabio/react-native-bitcoinjs-lib/84c2a4dafd25cc9f035a34754886ce3b8d3912e5/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 6 | -------------------------------------------------------------------------------- /example/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /example/android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = 'debug', 3 | store = 'debug.keystore', 4 | properties = 'debug.keystore.properties', 5 | visibility = [ 6 | 'PUBLIC', 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'RNBitcoinJSExample' 2 | 3 | include ':app' 4 | include ':react-native-randombytes' 5 | project(':react-native-randombytes').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-randombytes/android') 6 | -------------------------------------------------------------------------------- /example/index.android.js: -------------------------------------------------------------------------------- 1 | 'use-strict' 2 | 3 | /* base libs */ 4 | import './shim' 5 | import Bitcoin from 'react-native-bitcoinjs-lib' 6 | import React, { Component, PropTypes } from 'react' 7 | import { 8 | View, 9 | Text, 10 | StyleSheet, 11 | AppRegistry, 12 | TouchableOpacity, 13 | } from 'react-native' 14 | 15 | export default class RNBitcoinJSExample extends Component { 16 | 17 | constructor(props) { 18 | super(props) 19 | 20 | this.state = { 21 | address: '', 22 | } 23 | 24 | this.generateNewAddress = this.generateNewAddress.bind(this) 25 | } 26 | 27 | generateNewAddress = () => { 28 | const keypair = Bitcoin.ECPair.makeRandom() 29 | this.setState({address: keypair.getAddress()}) 30 | } 31 | 32 | render() { 33 | return( 34 | 35 | React Native 36 | Bitcoin Wallet 37 | 38 | Generate new address 39 | 40 | {this.state.address} 41 | 42 | ) 43 | } 44 | } 45 | 46 | const styles = StyleSheet.create({ 47 | container: { 48 | flex: 1, 49 | padding: 10, 50 | alignItems: 'center', 51 | justifyContent: 'center', 52 | }, 53 | title: { 54 | padding: 8, 55 | fontSize: 18, 56 | fontWeight: '900', 57 | }, 58 | button: { 59 | width: 200, 60 | borderRadius: 4, 61 | marginBottom: 25, 62 | paddingVertical: 8, 63 | alignItems: 'center', 64 | paddingHorizontal: 20, 65 | justifyContent: 'center', 66 | backgroundColor: '#00cc44', 67 | }, 68 | buttonText: { 69 | color: '#fff', 70 | }, 71 | address: { 72 | flex: 1, 73 | fontSize: 15, 74 | color: '#b5b5b5', 75 | fontWeight: '600', 76 | textAlign: 'center', 77 | } 78 | }) 79 | 80 | AppRegistry.registerComponent('RNBitcoinJSExample', () => RNBitcoinJSExample); 81 | -------------------------------------------------------------------------------- /example/index.ios.js: -------------------------------------------------------------------------------- 1 | 'use-strict' 2 | 3 | /* base libs */ 4 | import './shim' 5 | import Bitcoin from 'react-native-bitcoinjs-lib' 6 | import React, { Component, PropTypes } from 'react' 7 | import { 8 | View, 9 | Text, 10 | StyleSheet, 11 | AppRegistry, 12 | TouchableOpacity, 13 | } from 'react-native' 14 | 15 | export default class RNBitcoinJSExample extends Component { 16 | 17 | constructor(props) { 18 | super(props) 19 | 20 | this.state = { 21 | address: '', 22 | } 23 | 24 | this.generateNewAddress = this.generateNewAddress.bind(this) 25 | } 26 | 27 | generateNewAddress = () => { 28 | const keypair = Bitcoin.ECPair.makeRandom() 29 | this.setState({address: keypair.getAddress()}) 30 | } 31 | 32 | render() { 33 | return( 34 | 35 | React Native 36 | Bitcoin Wallet 37 | 38 | Generate new address 39 | 40 | {this.state.address} 41 | 42 | ) 43 | } 44 | } 45 | 46 | const styles = StyleSheet.create({ 47 | container: { 48 | flex: 1, 49 | padding: 10, 50 | alignItems: 'center', 51 | justifyContent: 'center', 52 | }, 53 | title: { 54 | padding: 8, 55 | fontSize: 18, 56 | fontWeight: '900', 57 | }, 58 | button: { 59 | width: 200, 60 | borderRadius: 4, 61 | marginBottom: 25, 62 | paddingVertical: 8, 63 | alignItems: 'center', 64 | paddingHorizontal: 20, 65 | justifyContent: 'center', 66 | backgroundColor: '#00cc44', 67 | }, 68 | buttonText: { 69 | color: '#fff', 70 | }, 71 | address: { 72 | flex: 1, 73 | fontSize: 15, 74 | color: '#b5b5b5', 75 | fontWeight: '600', 76 | textAlign: 'center', 77 | } 78 | }) 79 | 80 | AppRegistry.registerComponent('RNBitcoinJSExample', () => RNBitcoinJSExample); 81 | -------------------------------------------------------------------------------- /example/ios/RNBitcoinJSExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | /* Begin PBXBuildFile section */ 9 | 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; 10 | 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; 11 | 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; }; 12 | 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; 13 | 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; 14 | 00E356F31AD99517003FC87E /* RNBitcoinJSExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* RNBitcoinJSExampleTests.m */; }; 15 | 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; }; 16 | 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; }; 17 | 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; }; 18 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 19 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; 20 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 21 | 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 22 | 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 23 | 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 24 | 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; 25 | 2E39B232C6094AA4AD267DF4 /* libRNRandomBytes.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E963B52C4E924F28AC6AB241 /* libRNRandomBytes.a */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; 32 | proxyType = 2; 33 | remoteGlobalIDString = 134814201AA4EA6300B7C361; 34 | remoteInfo = RCTActionSheet; 35 | }; 36 | 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; 39 | proxyType = 2; 40 | remoteGlobalIDString = 134814201AA4EA6300B7C361; 41 | remoteInfo = RCTGeolocation; 42 | }; 43 | 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; 46 | proxyType = 2; 47 | remoteGlobalIDString = 58B5115D1A9E6B3D00147676; 48 | remoteInfo = RCTImage; 49 | }; 50 | 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = { 51 | isa = PBXContainerItemProxy; 52 | containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; 53 | proxyType = 2; 54 | remoteGlobalIDString = 58B511DB1A9E6C8500147676; 55 | remoteInfo = RCTNetwork; 56 | }; 57 | 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = { 58 | isa = PBXContainerItemProxy; 59 | containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; 60 | proxyType = 2; 61 | remoteGlobalIDString = 832C81801AAF6DEF007FA2F7; 62 | remoteInfo = RCTVibration; 63 | }; 64 | 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { 65 | isa = PBXContainerItemProxy; 66 | containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; 67 | proxyType = 1; 68 | remoteGlobalIDString = 13B07F861A680F5B00A75B9A; 69 | remoteInfo = RNBitcoinJSExample; 70 | }; 71 | 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = { 72 | isa = PBXContainerItemProxy; 73 | containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; 74 | proxyType = 2; 75 | remoteGlobalIDString = 134814201AA4EA6300B7C361; 76 | remoteInfo = RCTSettings; 77 | }; 78 | 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = { 79 | isa = PBXContainerItemProxy; 80 | containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; 81 | proxyType = 2; 82 | remoteGlobalIDString = 3C86DF461ADF2C930047B81A; 83 | remoteInfo = RCTWebSocket; 84 | }; 85 | 146834031AC3E56700842450 /* PBXContainerItemProxy */ = { 86 | isa = PBXContainerItemProxy; 87 | containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; 88 | proxyType = 2; 89 | remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; 90 | remoteInfo = React; 91 | }; 92 | 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = { 93 | isa = PBXContainerItemProxy; 94 | containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; 95 | proxyType = 2; 96 | remoteGlobalIDString = 134814201AA4EA6300B7C361; 97 | remoteInfo = RCTLinking; 98 | }; 99 | 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = { 100 | isa = PBXContainerItemProxy; 101 | containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; 102 | proxyType = 2; 103 | remoteGlobalIDString = 58B5119B1A9E6C1200147676; 104 | remoteInfo = RCTText; 105 | }; 106 | /* End PBXContainerItemProxy section */ 107 | 108 | /* Begin PBXFileReference section */ 109 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = main.jsbundle; path = main.jsbundle; sourceTree = ""; }; 110 | 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = ""; }; 111 | 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = ""; }; 112 | 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj; sourceTree = ""; }; 113 | 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; 114 | 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = ""; }; 115 | 00E356EE1AD99517003FC87E /* RNBitcoinJSExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RNBitcoinJSExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 116 | 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 117 | 00E356F21AD99517003FC87E /* RNBitcoinJSExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNBitcoinJSExampleTests.m; sourceTree = ""; }; 118 | 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj; sourceTree = ""; }; 119 | 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; 120 | 13B07F961A680F5B00A75B9A /* RNBitcoinJSExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RNBitcoinJSExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 121 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = RNBitcoinJSExample/AppDelegate.h; sourceTree = ""; }; 122 | 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = RNBitcoinJSExample/AppDelegate.m; sourceTree = ""; }; 123 | 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 124 | 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = RNBitcoinJSExample/Images.xcassets; sourceTree = ""; }; 125 | 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = RNBitcoinJSExample/Info.plist; sourceTree = ""; }; 126 | 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = RNBitcoinJSExample/main.m; sourceTree = ""; }; 127 | 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../node_modules/react-native/React/React.xcodeproj; sourceTree = ""; }; 128 | 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = ""; }; 129 | 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../node_modules/react-native/Libraries/Text/RCTText.xcodeproj; sourceTree = ""; }; 130 | AECBCB3FA2AD45418643BA9F /* RNRandomBytes.xcodeproj */ = {isa = PBXFileReference; name = "RNRandomBytes.xcodeproj"; path = "../node_modules/react-native-randombytes/RNRandomBytes.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; 131 | E963B52C4E924F28AC6AB241 /* libRNRandomBytes.a */ = {isa = PBXFileReference; name = "libRNRandomBytes.a"; path = "libRNRandomBytes.a"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; }; 132 | /* End PBXFileReference section */ 133 | 134 | /* Begin PBXFrameworksBuildPhase section */ 135 | 00E356EB1AD99517003FC87E /* Frameworks */ = { 136 | isa = PBXFrameworksBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { 144 | isa = PBXFrameworksBuildPhase; 145 | buildActionMask = 2147483647; 146 | files = ( 147 | 146834051AC3E58100842450 /* libReact.a in Frameworks */, 148 | 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, 149 | 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */, 150 | 00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */, 151 | 133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */, 152 | 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */, 153 | 139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */, 154 | 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, 155 | 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */, 156 | 139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */, 157 | 2E39B232C6094AA4AD267DF4 /* libRNRandomBytes.a in Frameworks */, 158 | ); 159 | runOnlyForDeploymentPostprocessing = 0; 160 | }; 161 | /* End PBXFrameworksBuildPhase section */ 162 | 163 | /* Begin PBXGroup section */ 164 | 00C302A81ABCB8CE00DB3ED1 /* Products */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */, 168 | ); 169 | name = Products; 170 | sourceTree = ""; 171 | }; 172 | 00C302B61ABCB90400DB3ED1 /* Products */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */, 176 | ); 177 | name = Products; 178 | sourceTree = ""; 179 | }; 180 | 00C302BC1ABCB91800DB3ED1 /* Products */ = { 181 | isa = PBXGroup; 182 | children = ( 183 | 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */, 184 | ); 185 | name = Products; 186 | sourceTree = ""; 187 | }; 188 | 00C302D41ABCB9D200DB3ED1 /* Products */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */, 192 | ); 193 | name = Products; 194 | sourceTree = ""; 195 | }; 196 | 00C302E01ABCB9EE00DB3ED1 /* Products */ = { 197 | isa = PBXGroup; 198 | children = ( 199 | 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */, 200 | ); 201 | name = Products; 202 | sourceTree = ""; 203 | }; 204 | 00E356EF1AD99517003FC87E /* RNBitcoinJSExampleTests */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | 00E356F21AD99517003FC87E /* RNBitcoinJSExampleTests.m */, 208 | 00E356F01AD99517003FC87E /* Supporting Files */, 209 | ); 210 | path = RNBitcoinJSExampleTests; 211 | sourceTree = ""; 212 | }; 213 | 00E356F01AD99517003FC87E /* Supporting Files */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | 00E356F11AD99517003FC87E /* Info.plist */, 217 | ); 218 | name = "Supporting Files"; 219 | sourceTree = ""; 220 | }; 221 | 139105B71AF99BAD00B5F7CC /* Products */ = { 222 | isa = PBXGroup; 223 | children = ( 224 | 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */, 225 | ); 226 | name = Products; 227 | sourceTree = ""; 228 | }; 229 | 139FDEE71B06529A00C62182 /* Products */ = { 230 | isa = PBXGroup; 231 | children = ( 232 | 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */, 233 | ); 234 | name = Products; 235 | sourceTree = ""; 236 | }; 237 | 13B07FAE1A68108700A75B9A /* RNBitcoinJSExample */ = { 238 | isa = PBXGroup; 239 | children = ( 240 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */, 241 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 242 | 13B07FB01A68108700A75B9A /* AppDelegate.m */, 243 | 13B07FB51A68108700A75B9A /* Images.xcassets */, 244 | 13B07FB61A68108700A75B9A /* Info.plist */, 245 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, 246 | 13B07FB71A68108700A75B9A /* main.m */, 247 | ); 248 | name = RNBitcoinJSExample; 249 | sourceTree = ""; 250 | }; 251 | 146834001AC3E56700842450 /* Products */ = { 252 | isa = PBXGroup; 253 | children = ( 254 | 146834041AC3E56700842450 /* libReact.a */, 255 | ); 256 | name = Products; 257 | sourceTree = ""; 258 | }; 259 | 78C398B11ACF4ADC00677621 /* Products */ = { 260 | isa = PBXGroup; 261 | children = ( 262 | 78C398B91ACF4ADC00677621 /* libRCTLinking.a */, 263 | ); 264 | name = Products; 265 | sourceTree = ""; 266 | }; 267 | 832341AE1AAA6A7D00B99B32 /* Libraries */ = { 268 | isa = PBXGroup; 269 | children = ( 270 | 146833FF1AC3E56700842450 /* React.xcodeproj */, 271 | 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, 272 | 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, 273 | 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */, 274 | 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */, 275 | 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */, 276 | 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */, 277 | 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, 278 | 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */, 279 | 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */, 280 | AECBCB3FA2AD45418643BA9F /* RNRandomBytes.xcodeproj */, 281 | ); 282 | name = Libraries; 283 | sourceTree = ""; 284 | }; 285 | 832341B11AAA6A8300B99B32 /* Products */ = { 286 | isa = PBXGroup; 287 | children = ( 288 | 832341B51AAA6A8300B99B32 /* libRCTText.a */, 289 | ); 290 | name = Products; 291 | sourceTree = ""; 292 | }; 293 | 83CBB9F61A601CBA00E9B192 = { 294 | isa = PBXGroup; 295 | children = ( 296 | 13B07FAE1A68108700A75B9A /* RNBitcoinJSExample */, 297 | 832341AE1AAA6A7D00B99B32 /* Libraries */, 298 | 00E356EF1AD99517003FC87E /* RNBitcoinJSExampleTests */, 299 | 83CBBA001A601CBA00E9B192 /* Products */, 300 | ); 301 | indentWidth = 2; 302 | sourceTree = ""; 303 | tabWidth = 2; 304 | }; 305 | 83CBBA001A601CBA00E9B192 /* Products */ = { 306 | isa = PBXGroup; 307 | children = ( 308 | 13B07F961A680F5B00A75B9A /* RNBitcoinJSExample.app */, 309 | 00E356EE1AD99517003FC87E /* RNBitcoinJSExampleTests.xctest */, 310 | ); 311 | name = Products; 312 | sourceTree = ""; 313 | }; 314 | /* End PBXGroup section */ 315 | 316 | /* Begin PBXNativeTarget section */ 317 | 00E356ED1AD99517003FC87E /* RNBitcoinJSExampleTests */ = { 318 | isa = PBXNativeTarget; 319 | buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "RNBitcoinJSExampleTests" */; 320 | buildPhases = ( 321 | 00E356EA1AD99517003FC87E /* Sources */, 322 | 00E356EB1AD99517003FC87E /* Frameworks */, 323 | 00E356EC1AD99517003FC87E /* Resources */, 324 | ); 325 | buildRules = ( 326 | ); 327 | dependencies = ( 328 | 00E356F51AD99517003FC87E /* PBXTargetDependency */, 329 | ); 330 | name = RNBitcoinJSExampleTests; 331 | productName = RNBitcoinJSExampleTests; 332 | productReference = 00E356EE1AD99517003FC87E /* RNBitcoinJSExampleTests.xctest */; 333 | productType = "com.apple.product-type.bundle.unit-test"; 334 | }; 335 | 13B07F861A680F5B00A75B9A /* RNBitcoinJSExample */ = { 336 | isa = PBXNativeTarget; 337 | buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "RNBitcoinJSExample" */; 338 | buildPhases = ( 339 | 13B07F871A680F5B00A75B9A /* Sources */, 340 | 13B07F8C1A680F5B00A75B9A /* Frameworks */, 341 | 13B07F8E1A680F5B00A75B9A /* Resources */, 342 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 343 | ); 344 | buildRules = ( 345 | ); 346 | dependencies = ( 347 | ); 348 | name = RNBitcoinJSExample; 349 | productName = "Hello World"; 350 | productReference = 13B07F961A680F5B00A75B9A /* RNBitcoinJSExample.app */; 351 | productType = "com.apple.product-type.application"; 352 | }; 353 | /* End PBXNativeTarget section */ 354 | 355 | /* Begin PBXProject section */ 356 | 83CBB9F71A601CBA00E9B192 /* Project object */ = { 357 | isa = PBXProject; 358 | attributes = { 359 | LastUpgradeCheck = 610; 360 | ORGANIZATIONNAME = Facebook; 361 | TargetAttributes = { 362 | 00E356ED1AD99517003FC87E = { 363 | CreatedOnToolsVersion = 6.2; 364 | TestTargetID = 13B07F861A680F5B00A75B9A; 365 | }; 366 | }; 367 | }; 368 | buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "RNBitcoinJSExample" */; 369 | compatibilityVersion = "Xcode 3.2"; 370 | developmentRegion = English; 371 | hasScannedForEncodings = 0; 372 | knownRegions = ( 373 | en, 374 | Base, 375 | ); 376 | mainGroup = 83CBB9F61A601CBA00E9B192; 377 | productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; 378 | projectDirPath = ""; 379 | projectReferences = ( 380 | { 381 | ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */; 382 | ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; 383 | }, 384 | { 385 | ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */; 386 | ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; 387 | }, 388 | { 389 | ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */; 390 | ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */; 391 | }, 392 | { 393 | ProductGroup = 78C398B11ACF4ADC00677621 /* Products */; 394 | ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */; 395 | }, 396 | { 397 | ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */; 398 | ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */; 399 | }, 400 | { 401 | ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */; 402 | ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */; 403 | }, 404 | { 405 | ProductGroup = 832341B11AAA6A8300B99B32 /* Products */; 406 | ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; 407 | }, 408 | { 409 | ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */; 410 | ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */; 411 | }, 412 | { 413 | ProductGroup = 139FDEE71B06529A00C62182 /* Products */; 414 | ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */; 415 | }, 416 | { 417 | ProductGroup = 146834001AC3E56700842450 /* Products */; 418 | ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */; 419 | }, 420 | ); 421 | projectRoot = ""; 422 | targets = ( 423 | 13B07F861A680F5B00A75B9A /* RNBitcoinJSExample */, 424 | 00E356ED1AD99517003FC87E /* RNBitcoinJSExampleTests */, 425 | ); 426 | }; 427 | /* End PBXProject section */ 428 | 429 | /* Begin PBXReferenceProxy section */ 430 | 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = { 431 | isa = PBXReferenceProxy; 432 | fileType = archive.ar; 433 | path = libRCTActionSheet.a; 434 | remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */; 435 | sourceTree = BUILT_PRODUCTS_DIR; 436 | }; 437 | 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = { 438 | isa = PBXReferenceProxy; 439 | fileType = archive.ar; 440 | path = libRCTGeolocation.a; 441 | remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */; 442 | sourceTree = BUILT_PRODUCTS_DIR; 443 | }; 444 | 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = { 445 | isa = PBXReferenceProxy; 446 | fileType = archive.ar; 447 | path = libRCTImage.a; 448 | remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */; 449 | sourceTree = BUILT_PRODUCTS_DIR; 450 | }; 451 | 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = { 452 | isa = PBXReferenceProxy; 453 | fileType = archive.ar; 454 | path = libRCTNetwork.a; 455 | remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */; 456 | sourceTree = BUILT_PRODUCTS_DIR; 457 | }; 458 | 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = { 459 | isa = PBXReferenceProxy; 460 | fileType = archive.ar; 461 | path = libRCTVibration.a; 462 | remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */; 463 | sourceTree = BUILT_PRODUCTS_DIR; 464 | }; 465 | 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = { 466 | isa = PBXReferenceProxy; 467 | fileType = archive.ar; 468 | path = libRCTSettings.a; 469 | remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */; 470 | sourceTree = BUILT_PRODUCTS_DIR; 471 | }; 472 | 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = { 473 | isa = PBXReferenceProxy; 474 | fileType = archive.ar; 475 | path = libRCTWebSocket.a; 476 | remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */; 477 | sourceTree = BUILT_PRODUCTS_DIR; 478 | }; 479 | 146834041AC3E56700842450 /* libReact.a */ = { 480 | isa = PBXReferenceProxy; 481 | fileType = archive.ar; 482 | path = libReact.a; 483 | remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; 484 | sourceTree = BUILT_PRODUCTS_DIR; 485 | }; 486 | 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = { 487 | isa = PBXReferenceProxy; 488 | fileType = archive.ar; 489 | path = libRCTLinking.a; 490 | remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */; 491 | sourceTree = BUILT_PRODUCTS_DIR; 492 | }; 493 | 832341B51AAA6A8300B99B32 /* libRCTText.a */ = { 494 | isa = PBXReferenceProxy; 495 | fileType = archive.ar; 496 | path = libRCTText.a; 497 | remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; 498 | sourceTree = BUILT_PRODUCTS_DIR; 499 | }; 500 | /* End PBXReferenceProxy section */ 501 | 502 | /* Begin PBXResourcesBuildPhase section */ 503 | 00E356EC1AD99517003FC87E /* Resources */ = { 504 | isa = PBXResourcesBuildPhase; 505 | buildActionMask = 2147483647; 506 | files = ( 507 | ); 508 | runOnlyForDeploymentPostprocessing = 0; 509 | }; 510 | 13B07F8E1A680F5B00A75B9A /* Resources */ = { 511 | isa = PBXResourcesBuildPhase; 512 | buildActionMask = 2147483647; 513 | files = ( 514 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 515 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, 516 | ); 517 | runOnlyForDeploymentPostprocessing = 0; 518 | }; 519 | /* End PBXResourcesBuildPhase section */ 520 | 521 | /* Begin PBXShellScriptBuildPhase section */ 522 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { 523 | isa = PBXShellScriptBuildPhase; 524 | buildActionMask = 2147483647; 525 | files = ( 526 | ); 527 | inputPaths = ( 528 | ); 529 | name = "Bundle React Native code and images"; 530 | outputPaths = ( 531 | ); 532 | runOnlyForDeploymentPostprocessing = 0; 533 | shellPath = /bin/sh; 534 | shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh"; 535 | showEnvVarsInLog = 1; 536 | }; 537 | /* End PBXShellScriptBuildPhase section */ 538 | 539 | /* Begin PBXSourcesBuildPhase section */ 540 | 00E356EA1AD99517003FC87E /* Sources */ = { 541 | isa = PBXSourcesBuildPhase; 542 | buildActionMask = 2147483647; 543 | files = ( 544 | 00E356F31AD99517003FC87E /* RNBitcoinJSExampleTests.m in Sources */, 545 | ); 546 | runOnlyForDeploymentPostprocessing = 0; 547 | }; 548 | 13B07F871A680F5B00A75B9A /* Sources */ = { 549 | isa = PBXSourcesBuildPhase; 550 | buildActionMask = 2147483647; 551 | files = ( 552 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, 553 | 13B07FC11A68108700A75B9A /* main.m in Sources */, 554 | ); 555 | runOnlyForDeploymentPostprocessing = 0; 556 | }; 557 | /* End PBXSourcesBuildPhase section */ 558 | 559 | /* Begin PBXTargetDependency section */ 560 | 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { 561 | isa = PBXTargetDependency; 562 | target = 13B07F861A680F5B00A75B9A /* RNBitcoinJSExample */; 563 | targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; 564 | }; 565 | /* End PBXTargetDependency section */ 566 | 567 | /* Begin PBXVariantGroup section */ 568 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { 569 | isa = PBXVariantGroup; 570 | children = ( 571 | 13B07FB21A68108700A75B9A /* Base */, 572 | ); 573 | name = LaunchScreen.xib; 574 | path = RNBitcoinJSExample; 575 | sourceTree = ""; 576 | }; 577 | /* End PBXVariantGroup section */ 578 | 579 | /* Begin XCBuildConfiguration section */ 580 | 00E356F61AD99517003FC87E /* Debug */ = { 581 | isa = XCBuildConfiguration; 582 | buildSettings = { 583 | BUNDLE_LOADER = "$(TEST_HOST)"; 584 | GCC_PREPROCESSOR_DEFINITIONS = ( 585 | "DEBUG=1", 586 | "$(inherited)", 587 | ); 588 | INFOPLIST_FILE = RNBitcoinJSExampleTests/Info.plist; 589 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 590 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 591 | PRODUCT_NAME = "$(TARGET_NAME)"; 592 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RNBitcoinJSExample.app/RNBitcoinJSExample"; 593 | LIBRARY_SEARCH_PATHS = ( 594 | "$(inherited)", 595 | "\"$(SRCROOT)/$(TARGET_NAME)\"", 596 | ); 597 | }; 598 | name = Debug; 599 | }; 600 | 00E356F71AD99517003FC87E /* Release */ = { 601 | isa = XCBuildConfiguration; 602 | buildSettings = { 603 | BUNDLE_LOADER = "$(TEST_HOST)"; 604 | COPY_PHASE_STRIP = NO; 605 | INFOPLIST_FILE = RNBitcoinJSExampleTests/Info.plist; 606 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 607 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 608 | PRODUCT_NAME = "$(TARGET_NAME)"; 609 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/RNBitcoinJSExample.app/RNBitcoinJSExample"; 610 | LIBRARY_SEARCH_PATHS = ( 611 | "$(inherited)", 612 | "\"$(SRCROOT)/$(TARGET_NAME)\"", 613 | ); 614 | }; 615 | name = Release; 616 | }; 617 | 13B07F941A680F5B00A75B9A /* Debug */ = { 618 | isa = XCBuildConfiguration; 619 | buildSettings = { 620 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 621 | CURRENT_PROJECT_VERSION = 1; 622 | DEAD_CODE_STRIPPING = NO; 623 | HEADER_SEARCH_PATHS = ( 624 | "$(inherited)", 625 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 626 | "$(SRCROOT)/../node_modules/react-native/React/**", 627 | "$(SRCROOT)/../node_modules/react-native-randombytes", 628 | ); 629 | INFOPLIST_FILE = "RNBitcoinJSExample/Info.plist"; 630 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 631 | OTHER_LDFLAGS = ( 632 | "$(inherited)", 633 | "-ObjC", 634 | "-lc++", 635 | ); 636 | PRODUCT_NAME = RNBitcoinJSExample; 637 | VERSIONING_SYSTEM = "apple-generic"; 638 | }; 639 | name = Debug; 640 | }; 641 | 13B07F951A680F5B00A75B9A /* Release */ = { 642 | isa = XCBuildConfiguration; 643 | buildSettings = { 644 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 645 | CURRENT_PROJECT_VERSION = 1; 646 | HEADER_SEARCH_PATHS = ( 647 | "$(inherited)", 648 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 649 | "$(SRCROOT)/../node_modules/react-native/React/**", 650 | "$(SRCROOT)/../node_modules/react-native-randombytes", 651 | ); 652 | INFOPLIST_FILE = "RNBitcoinJSExample/Info.plist"; 653 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 654 | OTHER_LDFLAGS = ( 655 | "$(inherited)", 656 | "-ObjC", 657 | "-lc++", 658 | ); 659 | PRODUCT_NAME = RNBitcoinJSExample; 660 | VERSIONING_SYSTEM = "apple-generic"; 661 | }; 662 | name = Release; 663 | }; 664 | 83CBBA201A601CBA00E9B192 /* Debug */ = { 665 | isa = XCBuildConfiguration; 666 | buildSettings = { 667 | ALWAYS_SEARCH_USER_PATHS = NO; 668 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 669 | CLANG_CXX_LIBRARY = "libc++"; 670 | CLANG_ENABLE_MODULES = YES; 671 | CLANG_ENABLE_OBJC_ARC = YES; 672 | CLANG_WARN_BOOL_CONVERSION = YES; 673 | CLANG_WARN_CONSTANT_CONVERSION = YES; 674 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 675 | CLANG_WARN_EMPTY_BODY = YES; 676 | CLANG_WARN_ENUM_CONVERSION = YES; 677 | CLANG_WARN_INT_CONVERSION = YES; 678 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 679 | CLANG_WARN_UNREACHABLE_CODE = YES; 680 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 681 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 682 | COPY_PHASE_STRIP = NO; 683 | ENABLE_STRICT_OBJC_MSGSEND = YES; 684 | GCC_C_LANGUAGE_STANDARD = gnu99; 685 | GCC_DYNAMIC_NO_PIC = NO; 686 | GCC_OPTIMIZATION_LEVEL = 0; 687 | GCC_PREPROCESSOR_DEFINITIONS = ( 688 | "DEBUG=1", 689 | "$(inherited)", 690 | ); 691 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 692 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 693 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 694 | GCC_WARN_UNDECLARED_SELECTOR = YES; 695 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 696 | GCC_WARN_UNUSED_FUNCTION = YES; 697 | GCC_WARN_UNUSED_VARIABLE = YES; 698 | HEADER_SEARCH_PATHS = ( 699 | "$(inherited)", 700 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 701 | "$(SRCROOT)/../node_modules/react-native/React/**", 702 | "$(SRCROOT)/../node_modules/react-native-randombytes", 703 | ); 704 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 705 | MTL_ENABLE_DEBUG_INFO = YES; 706 | ONLY_ACTIVE_ARCH = YES; 707 | SDKROOT = iphoneos; 708 | }; 709 | name = Debug; 710 | }; 711 | 83CBBA211A601CBA00E9B192 /* Release */ = { 712 | isa = XCBuildConfiguration; 713 | buildSettings = { 714 | ALWAYS_SEARCH_USER_PATHS = NO; 715 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 716 | CLANG_CXX_LIBRARY = "libc++"; 717 | CLANG_ENABLE_MODULES = YES; 718 | CLANG_ENABLE_OBJC_ARC = YES; 719 | CLANG_WARN_BOOL_CONVERSION = YES; 720 | CLANG_WARN_CONSTANT_CONVERSION = YES; 721 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 722 | CLANG_WARN_EMPTY_BODY = YES; 723 | CLANG_WARN_ENUM_CONVERSION = YES; 724 | CLANG_WARN_INT_CONVERSION = YES; 725 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 726 | CLANG_WARN_UNREACHABLE_CODE = YES; 727 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 728 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 729 | COPY_PHASE_STRIP = YES; 730 | ENABLE_NS_ASSERTIONS = NO; 731 | ENABLE_STRICT_OBJC_MSGSEND = YES; 732 | GCC_C_LANGUAGE_STANDARD = gnu99; 733 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 734 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 735 | GCC_WARN_UNDECLARED_SELECTOR = YES; 736 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 737 | GCC_WARN_UNUSED_FUNCTION = YES; 738 | GCC_WARN_UNUSED_VARIABLE = YES; 739 | HEADER_SEARCH_PATHS = ( 740 | "$(inherited)", 741 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 742 | "$(SRCROOT)/../node_modules/react-native/React/**", 743 | "$(SRCROOT)/../node_modules/react-native-randombytes", 744 | ); 745 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 746 | MTL_ENABLE_DEBUG_INFO = NO; 747 | SDKROOT = iphoneos; 748 | VALIDATE_PRODUCT = YES; 749 | }; 750 | name = Release; 751 | }; 752 | /* End XCBuildConfiguration section */ 753 | 754 | /* Begin XCConfigurationList section */ 755 | 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "RNBitcoinJSExampleTests" */ = { 756 | isa = XCConfigurationList; 757 | buildConfigurations = ( 758 | 00E356F61AD99517003FC87E /* Debug */, 759 | 00E356F71AD99517003FC87E /* Release */, 760 | ); 761 | defaultConfigurationIsVisible = 0; 762 | defaultConfigurationName = Release; 763 | }; 764 | 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "RNBitcoinJSExample" */ = { 765 | isa = XCConfigurationList; 766 | buildConfigurations = ( 767 | 13B07F941A680F5B00A75B9A /* Debug */, 768 | 13B07F951A680F5B00A75B9A /* Release */, 769 | ); 770 | defaultConfigurationIsVisible = 0; 771 | defaultConfigurationName = Release; 772 | }; 773 | 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "RNBitcoinJSExample" */ = { 774 | isa = XCConfigurationList; 775 | buildConfigurations = ( 776 | 83CBBA201A601CBA00E9B192 /* Debug */, 777 | 83CBBA211A601CBA00E9B192 /* Release */, 778 | ); 779 | defaultConfigurationIsVisible = 0; 780 | defaultConfigurationName = Release; 781 | }; 782 | /* End XCConfigurationList section */ 783 | }; 784 | rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; 785 | } 786 | -------------------------------------------------------------------------------- /example/ios/RNBitcoinJSExample.xcodeproj/xcshareddata/xcschemes/RNBitcoinJSExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /example/ios/RNBitcoinJSExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /example/ios/RNBitcoinJSExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import "RCTBundleURLProvider.h" 13 | #import "RCTRootView.h" 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | NSURL *jsCodeLocation; 20 | 21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 22 | 23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 24 | moduleName:@"RNBitcoinJSExample" 25 | initialProperties:nil 26 | launchOptions:launchOptions]; 27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 28 | 29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 30 | UIViewController *rootViewController = [UIViewController new]; 31 | rootViewController.view = rootView; 32 | self.window.rootViewController = rootViewController; 33 | [self.window makeKeyAndVisible]; 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /example/ios/RNBitcoinJSExample/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /example/ios/RNBitcoinJSExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /example/ios/RNBitcoinJSExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | NSLocationWhenInUseUsageDescription 40 | 41 | NSAppTransportSecurity 42 | 43 | 44 | NSExceptionDomains 45 | 46 | localhost 47 | 48 | NSTemporaryExceptionAllowsInsecureHTTPLoads 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /example/ios/RNBitcoinJSExample/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /example/ios/RNBitcoinJSExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/ios/RNBitcoinJSExampleTests/RNBitcoinJSExampleTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import 12 | 13 | #import "RCTLog.h" 14 | #import "RCTRootView.h" 15 | 16 | #define TIMEOUT_SECONDS 600 17 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 18 | 19 | @interface RNBitcoinJSExampleTests : XCTestCase 20 | 21 | @end 22 | 23 | @implementation RNBitcoinJSExampleTests 24 | 25 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 26 | { 27 | if (test(view)) { 28 | return YES; 29 | } 30 | for (UIView *subview in [view subviews]) { 31 | if ([self findSubviewInView:subview matching:test]) { 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | 38 | - (void)testRendersWelcomeScreen 39 | { 40 | UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; 41 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 42 | BOOL foundElement = NO; 43 | 44 | __block NSString *redboxError = nil; 45 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 46 | if (level >= RCTLogLevelError) { 47 | redboxError = message; 48 | } 49 | }); 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | RCTSetLogFunction(RCTDefaultLogFunction); 64 | 65 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 66 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 67 | } 68 | 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RNBitcoinJSExample", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start", 7 | "postinstall": "rn-nodeify --install stream,buffer,events,assert --hack", 8 | "test": "jest" 9 | }, 10 | "dependencies": { 11 | "assert": "^1.4.1", 12 | "events": "^1.1.1", 13 | "react": "15.3.2", 14 | "react-native": "^0.35.0", 15 | "react-native-bitcoinjs-lib": "^2.3.2", 16 | "react-native-randombytes": "^2.1.0", 17 | "readable-stream": "^1.0.33", 18 | "stream-browserify": "^1.0.0" 19 | }, 20 | "jest": { 21 | "preset": "jest-react-native" 22 | }, 23 | "devDependencies": { 24 | "babel-jest": "16.0.0", 25 | "babel-preset-react-native": "1.9.0", 26 | "jest": "16.0.2", 27 | "jest-react-native": "16.0.0", 28 | "react-test-renderer": "15.3.2" 29 | }, 30 | "react-native": { 31 | "_stream_transform": "readable-stream/transform", 32 | "_stream_readable": "readable-stream/readable", 33 | "_stream_writable": "readable-stream/writable", 34 | "_stream_duplex": "readable-stream/duplex", 35 | "_stream_passthrough": "readable-stream/passthrough", 36 | "stream": "stream-browserify" 37 | }, 38 | "browser": { 39 | "_stream_transform": "readable-stream/transform", 40 | "_stream_readable": "readable-stream/readable", 41 | "_stream_writable": "readable-stream/writable", 42 | "_stream_duplex": "readable-stream/duplex", 43 | "_stream_passthrough": "readable-stream/passthrough", 44 | "stream": "stream-browserify" 45 | } 46 | } -------------------------------------------------------------------------------- /example/shim.js: -------------------------------------------------------------------------------- 1 | if (typeof __dirname === 'undefined') global.__dirname = '/' 2 | if (typeof __filename === 'undefined') global.__filename = '' 3 | if (typeof process === 'undefined') { 4 | global.process = require('process') 5 | } else { 6 | var bProcess = require('process') 7 | for (var p in bProcess) { 8 | if (!(p in process)) { 9 | process[p] = bProcess[p] 10 | } 11 | } 12 | } 13 | 14 | process.browser = false 15 | if (typeof Buffer === 'undefined') global.Buffer = require('buffer').Buffer 16 | 17 | // global.location = global.location || { port: 80 } 18 | var isDev = typeof __DEV__ === 'boolean' && __DEV__ 19 | process.env['NODE_ENV'] = isDev ? 'development' : 'production' 20 | if (typeof localStorage !== 'undefined') { 21 | localStorage.debug = isDev ? '*' : '' 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-bitcoinjs-lib", 3 | "version": "2.3.9", 4 | "description": "Client-side Bitcoin JavaScript library for React Native", 5 | "main": "./src/index.js", 6 | "engines": { 7 | "node": ">=4.0.0" 8 | }, 9 | "keywords": [ 10 | "bitcoin", 11 | "react-native", 12 | "reactnative", 13 | "library", 14 | "wallet" 15 | ], 16 | "contributors": [ 17 | { 18 | "name": "Daniel Cousens", 19 | "email": "bitcoin@dcousens.com", 20 | "url": "http://dcousens.com" 21 | }, 22 | { 23 | "name": "Kyle Drake", 24 | "email": "kyle@kyledrake.net", 25 | "url": "http://kyledrake.net/" 26 | }, 27 | { 28 | "name": "Wei Lu", 29 | "email": "luwei.here@gmail.com", 30 | "url": "http://weilu.github.io/" 31 | }, 32 | { 33 | "name": "Stefan Thomas", 34 | "email": "justmoon@members.fsf.org", 35 | "url": "http://www.justmoon.net" 36 | }, 37 | { 38 | "name": "Alberto Dallaporta", 39 | "email": "alberto@novalab.io", 40 | "url": "https://novalab.io" 41 | } 42 | ], 43 | "scripts": { 44 | "coverage-report": "nyc report --reporter=lcov", 45 | "coverage-html": "nyc report --reporter=html", 46 | "coverage": "nyc --check-coverage --branches 90 --functions 90 mocha", 47 | "integration": "mocha test/integration/", 48 | "standard": "standard", 49 | "test": "npm run standard && npm run coverage", 50 | "unit": "mocha" 51 | }, 52 | "repository": { 53 | "type": "git", 54 | "url": "https://github.com/novalabio/react-native-bitcoinjs-lib" 55 | }, 56 | "files": [ 57 | "src" 58 | ], 59 | "dependencies": { 60 | "bigi": "^1.4.0", 61 | "bip66": "^1.1.0", 62 | "bitcoin-ops": "^1.3.0", 63 | "bs58check": "^2.0.0", 64 | "ecurve": "^1.0.0", 65 | "merkle-lib": "^2.0.10", 66 | "pushdata-bitcoin": "^1.0.1", 67 | "react-native-crypto": "^2.0.1", 68 | "react-native-randombytes": "^2.2.0", 69 | "typeforce": "^1.8.7", 70 | "varuint-bitcoin": "^1.0.4", 71 | "wif": "^2.0.1" 72 | }, 73 | "devDependencies": { 74 | "async": "^2.0.1", 75 | "bip39": "^2.3.0", 76 | "bs58": "^4.0.0", 77 | "cb-http-client": "^0.2.0", 78 | "coinselect": "^3.1.1", 79 | "minimaldata": "^1.0.2", 80 | "mocha": "^3.1.0", 81 | "nyc": "^10.2.0", 82 | "proxyquire": "^1.4.0", 83 | "sinon": "^1.12.2", 84 | "standard": "^9.0.2" 85 | }, 86 | "license": "MIT" 87 | } 88 | -------------------------------------------------------------------------------- /src/address.js: -------------------------------------------------------------------------------- 1 | var bs58check = require('bs58check') 2 | var bscript = require('./script') 3 | var networks = require('./networks') 4 | var typeforce = require('typeforce') 5 | var types = require('./types') 6 | 7 | function fromBase58Check (address) { 8 | var payload = bs58check.decode(address) 9 | if (payload.length < 21) throw new TypeError(address + ' is too short') 10 | if (payload.length > 21) throw new TypeError(address + ' is too long') 11 | 12 | var version = payload[0] 13 | var hash = payload.slice(1) 14 | 15 | return { hash: hash, version: version } 16 | } 17 | 18 | function toBase58Check (hash, version) { 19 | typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments) 20 | 21 | var payload = new Buffer(21) 22 | payload.writeUInt8(version, 0) 23 | hash.copy(payload, 1) 24 | 25 | return bs58check.encode(payload) 26 | } 27 | 28 | function fromOutputScript (outputScript, network) { 29 | network = network || networks.bitcoin 30 | 31 | if (bscript.pubKeyHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(3, 23), network.pubKeyHash) 32 | if (bscript.scriptHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(2, 22), network.scriptHash) 33 | 34 | throw new Error(bscript.toASM(outputScript) + ' has no matching Address') 35 | } 36 | 37 | function toOutputScript (address, network) { 38 | network = network || networks.bitcoin 39 | 40 | var decode = fromBase58Check(address) 41 | if (decode.version === network.pubKeyHash) return bscript.pubKeyHash.output.encode(decode.hash) 42 | if (decode.version === network.scriptHash) return bscript.scriptHash.output.encode(decode.hash) 43 | 44 | throw new Error(address + ' has no matching Script') 45 | } 46 | 47 | module.exports = { 48 | fromBase58Check: fromBase58Check, 49 | fromOutputScript: fromOutputScript, 50 | toBase58Check: toBase58Check, 51 | toOutputScript: toOutputScript 52 | } 53 | -------------------------------------------------------------------------------- /src/block.js: -------------------------------------------------------------------------------- 1 | var bcrypto = require('./crypto') 2 | var fastMerkleRoot = require('merkle-lib/fastRoot') 3 | var typeforce = require('typeforce') 4 | var types = require('./types') 5 | var varuint = require('varuint-bitcoin') 6 | 7 | var Transaction = require('./transaction') 8 | 9 | function Block () { 10 | this.version = 1 11 | this.prevHash = null 12 | this.merkleRoot = null 13 | this.timestamp = 0 14 | this.bits = 0 15 | this.nonce = 0 16 | } 17 | 18 | Block.fromBuffer = function (buffer) { 19 | if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)') 20 | 21 | var offset = 0 22 | function readSlice (n) { 23 | offset += n 24 | return buffer.slice(offset - n, offset) 25 | } 26 | 27 | function readUInt32 () { 28 | var i = buffer.readUInt32LE(offset) 29 | offset += 4 30 | return i 31 | } 32 | 33 | function readInt32 () { 34 | var i = buffer.readInt32LE(offset) 35 | offset += 4 36 | return i 37 | } 38 | 39 | var block = new Block() 40 | block.version = readInt32() 41 | block.prevHash = readSlice(32) 42 | block.merkleRoot = readSlice(32) 43 | block.timestamp = readUInt32() 44 | block.bits = readUInt32() 45 | block.nonce = readUInt32() 46 | 47 | if (buffer.length === 80) return block 48 | 49 | function readVarInt () { 50 | var vi = varuint.decode(buffer, offset) 51 | offset += varuint.decode.bytes 52 | return vi 53 | } 54 | 55 | function readTransaction () { 56 | var tx = Transaction.fromBuffer(buffer.slice(offset), true) 57 | offset += tx.byteLength() 58 | return tx 59 | } 60 | 61 | var nTransactions = readVarInt() 62 | block.transactions = [] 63 | 64 | for (var i = 0; i < nTransactions; ++i) { 65 | var tx = readTransaction() 66 | block.transactions.push(tx) 67 | } 68 | 69 | return block 70 | } 71 | 72 | Block.prototype.byteLength = function (headersOnly) { 73 | if (headersOnly || !this.transactions) return 80 74 | 75 | return 80 + varuint.encodingLength(this.transactions.length) + this.transactions.reduce(function (a, x) { 76 | return a + x.byteLength() 77 | }, 0) 78 | } 79 | 80 | Block.fromHex = function (hex) { 81 | return Block.fromBuffer(new Buffer(hex, 'hex')) 82 | } 83 | 84 | Block.prototype.getHash = function () { 85 | return bcrypto.hash256(this.toBuffer(true)) 86 | } 87 | 88 | Block.prototype.getId = function () { 89 | return this.getHash().reverse().toString('hex') 90 | } 91 | 92 | Block.prototype.getUTCDate = function () { 93 | var date = new Date(0) // epoch 94 | date.setUTCSeconds(this.timestamp) 95 | 96 | return date 97 | } 98 | 99 | // TODO: buffer, offset compatibility 100 | Block.prototype.toBuffer = function (headersOnly) { 101 | var buffer = new Buffer(this.byteLength(headersOnly)) 102 | 103 | var offset = 0 104 | function writeSlice (slice) { 105 | slice.copy(buffer, offset) 106 | offset += slice.length 107 | } 108 | 109 | function writeInt32 (i) { 110 | buffer.writeInt32LE(i, offset) 111 | offset += 4 112 | } 113 | function writeUInt32 (i) { 114 | buffer.writeUInt32LE(i, offset) 115 | offset += 4 116 | } 117 | 118 | writeInt32(this.version) 119 | writeSlice(this.prevHash) 120 | writeSlice(this.merkleRoot) 121 | writeUInt32(this.timestamp) 122 | writeUInt32(this.bits) 123 | writeUInt32(this.nonce) 124 | 125 | if (headersOnly || !this.transactions) return buffer 126 | 127 | varuint.encode(this.transactions.length, buffer, offset) 128 | offset += varuint.encode.bytes 129 | 130 | this.transactions.forEach(function (tx) { 131 | var txSize = tx.byteLength() // TODO: extract from toBuffer? 132 | tx.toBuffer(buffer, offset) 133 | offset += txSize 134 | }) 135 | 136 | return buffer 137 | } 138 | 139 | Block.prototype.toHex = function (headersOnly) { 140 | return this.toBuffer(headersOnly).toString('hex') 141 | } 142 | 143 | Block.calculateTarget = function (bits) { 144 | var exponent = ((bits & 0xff000000) >> 24) - 3 145 | var mantissa = bits & 0x007fffff 146 | var target = new Buffer(32) 147 | target.fill(0) 148 | target.writeUInt32BE(mantissa, 28 - exponent) 149 | return target 150 | } 151 | 152 | Block.calculateMerkleRoot = function (transactions) { 153 | typeforce([{ getHash: types.Function }], transactions) 154 | if (transactions.length === 0) throw TypeError('Cannot compute merkle root for zero transactions') 155 | 156 | var hashes = transactions.map(function (transaction) { 157 | return transaction.getHash() 158 | }) 159 | 160 | return fastMerkleRoot(hashes, bcrypto.hash256) 161 | } 162 | 163 | Block.prototype.checkMerkleRoot = function () { 164 | if (!this.transactions) return false 165 | 166 | var actualMerkleRoot = Block.calculateMerkleRoot(this.transactions) 167 | return this.merkleRoot.compare(actualMerkleRoot) === 0 168 | } 169 | 170 | Block.prototype.checkProofOfWork = function () { 171 | var hash = this.getHash().reverse() 172 | var target = Block.calculateTarget(this.bits) 173 | 174 | return hash.compare(target) <= 0 175 | } 176 | 177 | module.exports = Block 178 | -------------------------------------------------------------------------------- /src/bufferutils.js: -------------------------------------------------------------------------------- 1 | var pushdata = require('pushdata-bitcoin') 2 | var varuint = require('varuint-bitcoin') 3 | 4 | // https://github.com/feross/buffer/blob/master/index.js#L1127 5 | function verifuint (value, max) { 6 | if (typeof value !== 'number') throw new Error('cannot write a non-number as a number') 7 | if (value < 0) throw new Error('specified a negative value for writing an unsigned value') 8 | if (value > max) throw new Error('RangeError: value out of range') 9 | if (Math.floor(value) !== value) throw new Error('value has a fractional component') 10 | } 11 | 12 | function readUInt64LE (buffer, offset) { 13 | var a = buffer.readUInt32LE(offset) 14 | var b = buffer.readUInt32LE(offset + 4) 15 | b *= 0x100000000 16 | 17 | verifuint(b + a, 0x001fffffffffffff) 18 | 19 | return b + a 20 | } 21 | 22 | function writeUInt64LE (buffer, value, offset) { 23 | verifuint(value, 0x001fffffffffffff) 24 | 25 | buffer.writeInt32LE(value & -1, offset) 26 | buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4) 27 | return offset + 8 28 | } 29 | 30 | // TODO: remove in 4.0.0? 31 | function readVarInt (buffer, offset) { 32 | var result = varuint.decode(buffer, offset) 33 | 34 | return { 35 | number: result, 36 | size: varuint.decode.bytes 37 | } 38 | } 39 | 40 | // TODO: remove in 4.0.0? 41 | function writeVarInt (buffer, number, offset) { 42 | varuint.encode(number, buffer, offset) 43 | return varuint.encode.bytes 44 | } 45 | 46 | module.exports = { 47 | pushDataSize: pushdata.encodingLength, 48 | readPushDataInt: pushdata.decode, 49 | readUInt64LE: readUInt64LE, 50 | readVarInt: readVarInt, 51 | varIntBuffer: varuint.encode, 52 | varIntSize: varuint.encodingLength, 53 | writePushDataInt: pushdata.encode, 54 | writeUInt64LE: writeUInt64LE, 55 | writeVarInt: writeVarInt 56 | } 57 | -------------------------------------------------------------------------------- /src/crypto.js: -------------------------------------------------------------------------------- 1 | var createHash = require('react-native-crypto').createHash 2 | 3 | function ripemd160 (buffer) { 4 | return createHash('rmd160').update(buffer).digest() 5 | } 6 | 7 | function sha1 (buffer) { 8 | return createHash('sha1').update(buffer).digest() 9 | } 10 | 11 | function sha256 (buffer) { 12 | return createHash('sha256').update(buffer).digest() 13 | } 14 | 15 | function hash160 (buffer) { 16 | return ripemd160(sha256(buffer)) 17 | } 18 | 19 | function hash256 (buffer) { 20 | return sha256(sha256(buffer)) 21 | } 22 | 23 | module.exports = { 24 | hash160: hash160, 25 | hash256: hash256, 26 | ripemd160: ripemd160, 27 | sha1: sha1, 28 | sha256: sha256 29 | } 30 | -------------------------------------------------------------------------------- /src/ecdsa.js: -------------------------------------------------------------------------------- 1 | var createHmac = require('react-native-crypto').createHmac 2 | var typeforce = require('typeforce') 3 | var types = require('./types') 4 | 5 | var BigInteger = require('bigi') 6 | var ECSignature = require('./ecsignature') 7 | 8 | var ZERO = new Buffer([0]) 9 | var ONE = new Buffer([1]) 10 | 11 | var ecurve = require('ecurve') 12 | var secp256k1 = ecurve.getCurveByName('secp256k1') 13 | 14 | // https://tools.ietf.org/html/rfc6979#section-3.2 15 | function deterministicGenerateK (hash, x, checkSig) { 16 | typeforce(types.tuple( 17 | types.Hash256bit, 18 | types.Buffer256bit, 19 | types.Function 20 | ), arguments) 21 | 22 | var k = new Buffer(32) 23 | var v = new Buffer(32) 24 | 25 | // Step A, ignored as hash already provided 26 | // Step B 27 | v.fill(1) 28 | 29 | // Step C 30 | k.fill(0) 31 | 32 | // Step D 33 | k = createHmac('sha256', k) 34 | .update(v) 35 | .update(ZERO) 36 | .update(x) 37 | .update(hash) 38 | .digest() 39 | 40 | // Step E 41 | v = createHmac('sha256', k).update(v).digest() 42 | 43 | // Step F 44 | k = createHmac('sha256', k) 45 | .update(v) 46 | .update(ONE) 47 | .update(x) 48 | .update(hash) 49 | .digest() 50 | 51 | // Step G 52 | v = createHmac('sha256', k).update(v).digest() 53 | 54 | // Step H1/H2a, ignored as tlen === qlen (256 bit) 55 | // Step H2b 56 | v = createHmac('sha256', k).update(v).digest() 57 | 58 | var T = BigInteger.fromBuffer(v) 59 | 60 | // Step H3, repeat until T is within the interval [1, n - 1] and is suitable for ECDSA 61 | while (T.signum() <= 0 || T.compareTo(secp256k1.n) >= 0 || !checkSig(T)) { 62 | k = createHmac('sha256', k) 63 | .update(v) 64 | .update(ZERO) 65 | .digest() 66 | 67 | v = createHmac('sha256', k).update(v).digest() 68 | 69 | // Step H1/H2a, again, ignored as tlen === qlen (256 bit) 70 | // Step H2b again 71 | v = createHmac('sha256', k).update(v).digest() 72 | T = BigInteger.fromBuffer(v) 73 | } 74 | 75 | return T 76 | } 77 | 78 | var N_OVER_TWO = secp256k1.n.shiftRight(1) 79 | 80 | function sign (hash, d) { 81 | typeforce(types.tuple(types.Hash256bit, types.BigInt), arguments) 82 | 83 | var x = d.toBuffer(32) 84 | var e = BigInteger.fromBuffer(hash) 85 | var n = secp256k1.n 86 | var G = secp256k1.G 87 | 88 | var r, s 89 | deterministicGenerateK(hash, x, function (k) { 90 | var Q = G.multiply(k) 91 | 92 | if (secp256k1.isInfinity(Q)) return false 93 | 94 | r = Q.affineX.mod(n) 95 | if (r.signum() === 0) return false 96 | 97 | s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n) 98 | if (s.signum() === 0) return false 99 | 100 | return true 101 | }) 102 | 103 | // enforce low S values, see bip62: 'low s values in signatures' 104 | if (s.compareTo(N_OVER_TWO) > 0) { 105 | s = n.subtract(s) 106 | } 107 | 108 | return new ECSignature(r, s) 109 | } 110 | 111 | function verify (hash, signature, Q) { 112 | typeforce(types.tuple( 113 | types.Hash256bit, 114 | types.ECSignature, 115 | types.ECPoint 116 | ), arguments) 117 | 118 | var n = secp256k1.n 119 | var G = secp256k1.G 120 | 121 | var r = signature.r 122 | var s = signature.s 123 | 124 | // 1.4.1 Enforce r and s are both integers in the interval [1, n − 1] 125 | if (r.signum() <= 0 || r.compareTo(n) >= 0) return false 126 | if (s.signum() <= 0 || s.compareTo(n) >= 0) return false 127 | 128 | // 1.4.2 H = Hash(M), already done by the user 129 | // 1.4.3 e = H 130 | var e = BigInteger.fromBuffer(hash) 131 | 132 | // Compute s^-1 133 | var sInv = s.modInverse(n) 134 | 135 | // 1.4.4 Compute u1 = es^−1 mod n 136 | // u2 = rs^−1 mod n 137 | var u1 = e.multiply(sInv).mod(n) 138 | var u2 = r.multiply(sInv).mod(n) 139 | 140 | // 1.4.5 Compute R = (xR, yR) 141 | // R = u1G + u2Q 142 | var R = G.multiplyTwo(u1, Q, u2) 143 | 144 | // 1.4.5 (cont.) Enforce R is not at infinity 145 | if (secp256k1.isInfinity(R)) return false 146 | 147 | // 1.4.6 Convert the field element R.x to an integer 148 | var xR = R.affineX 149 | 150 | // 1.4.7 Set v = xR mod n 151 | var v = xR.mod(n) 152 | 153 | // 1.4.8 If v = r, output "valid", and if v != r, output "invalid" 154 | return v.equals(r) 155 | } 156 | 157 | module.exports = { 158 | deterministicGenerateK: deterministicGenerateK, 159 | sign: sign, 160 | verify: verify, 161 | 162 | // TODO: remove 163 | __curve: secp256k1 164 | } 165 | -------------------------------------------------------------------------------- /src/ecpair.js: -------------------------------------------------------------------------------- 1 | var baddress = require('./address') 2 | var bcrypto = require('./crypto') 3 | var ecdsa = require('./ecdsa') 4 | var randomBytes = require('react-native-randombytes').randomBytes 5 | var typeforce = require('typeforce') 6 | var types = require('./types') 7 | var wif = require('wif') 8 | 9 | var NETWORKS = require('./networks') 10 | var BigInteger = require('bigi') 11 | 12 | var ecurve = require('ecurve') 13 | var secp256k1 = ecdsa.__curve 14 | 15 | function ECPair (d, Q, options) { 16 | if (options) { 17 | typeforce({ 18 | compressed: types.maybe(types.Boolean), 19 | network: types.maybe(types.Network) 20 | }, options) 21 | } 22 | 23 | options = options || {} 24 | 25 | if (d) { 26 | if (d.signum() <= 0) throw new Error('Private key must be greater than 0') 27 | if (d.compareTo(secp256k1.n) >= 0) throw new Error('Private key must be less than the curve order') 28 | if (Q) throw new TypeError('Unexpected publicKey parameter') 29 | 30 | this.d = d 31 | } else { 32 | typeforce(types.ECPoint, Q) 33 | 34 | this.__Q = Q 35 | } 36 | 37 | this.compressed = options.compressed === undefined ? true : options.compressed 38 | this.network = options.network || NETWORKS.bitcoin 39 | } 40 | 41 | Object.defineProperty(ECPair.prototype, 'Q', { 42 | get: function () { 43 | if (!this.__Q && this.d) { 44 | this.__Q = secp256k1.G.multiply(this.d) 45 | } 46 | 47 | return this.__Q 48 | } 49 | }) 50 | 51 | ECPair.fromPublicKeyBuffer = function (buffer, network) { 52 | var Q = ecurve.Point.decodeFrom(secp256k1, buffer) 53 | 54 | return new ECPair(null, Q, { 55 | compressed: Q.compressed, 56 | network: network 57 | }) 58 | } 59 | 60 | ECPair.fromWIF = function (string, network) { 61 | var decoded = wif.decode(string) 62 | var version = decoded.version 63 | 64 | // list of networks? 65 | if (types.Array(network)) { 66 | network = network.filter(function (x) { 67 | return version === x.wif 68 | }).pop() 69 | 70 | if (!network) throw new Error('Unknown network version') 71 | 72 | // otherwise, assume a network object (or default to bitcoin) 73 | } else { 74 | network = network || NETWORKS.bitcoin 75 | 76 | if (version !== network.wif) throw new Error('Invalid network version') 77 | } 78 | 79 | var d = BigInteger.fromBuffer(decoded.privateKey) 80 | 81 | return new ECPair(d, null, { 82 | compressed: decoded.compressed, 83 | network: network 84 | }) 85 | } 86 | 87 | ECPair.makeRandom = function (options) { 88 | options = options || {} 89 | 90 | var rng = options.rng || randomBytes 91 | 92 | var d 93 | do { 94 | var buffer = rng(32) 95 | typeforce(types.Buffer256bit, buffer) 96 | 97 | d = BigInteger.fromBuffer(buffer) 98 | } while (d.signum() <= 0 || d.compareTo(secp256k1.n) >= 0) 99 | 100 | return new ECPair(d, null, options) 101 | } 102 | 103 | ECPair.prototype.getAddress = function () { 104 | return baddress.toBase58Check(bcrypto.hash160(this.getPublicKeyBuffer()), this.getNetwork().pubKeyHash) 105 | } 106 | 107 | ECPair.prototype.getNetwork = function () { 108 | return this.network 109 | } 110 | 111 | ECPair.prototype.getPublicKeyBuffer = function () { 112 | return this.Q.getEncoded(this.compressed) 113 | } 114 | 115 | ECPair.prototype.sign = function (hash) { 116 | if (!this.d) throw new Error('Missing private key') 117 | 118 | return ecdsa.sign(hash, this.d) 119 | } 120 | 121 | ECPair.prototype.toWIF = function () { 122 | if (!this.d) throw new Error('Missing private key') 123 | 124 | return wif.encode(this.network.wif, this.d.toBuffer(32), this.compressed) 125 | } 126 | 127 | ECPair.prototype.verify = function (hash, signature) { 128 | return ecdsa.verify(hash, signature, this.Q) 129 | } 130 | 131 | module.exports = ECPair 132 | -------------------------------------------------------------------------------- /src/ecsignature.js: -------------------------------------------------------------------------------- 1 | var bip66 = require('bip66') 2 | var typeforce = require('typeforce') 3 | var types = require('./types') 4 | 5 | var BigInteger = require('bigi') 6 | 7 | function ECSignature (r, s) { 8 | typeforce(types.tuple(types.BigInt, types.BigInt), arguments) 9 | 10 | this.r = r 11 | this.s = s 12 | } 13 | 14 | ECSignature.parseCompact = function (buffer) { 15 | if (buffer.length !== 65) throw new Error('Invalid signature length') 16 | 17 | var flagByte = buffer.readUInt8(0) - 27 18 | if (flagByte !== (flagByte & 7)) throw new Error('Invalid signature parameter') 19 | 20 | var compressed = !!(flagByte & 4) 21 | var recoveryParam = flagByte & 3 22 | 23 | var r = BigInteger.fromBuffer(buffer.slice(1, 33)) 24 | var s = BigInteger.fromBuffer(buffer.slice(33)) 25 | 26 | return { 27 | compressed: compressed, 28 | i: recoveryParam, 29 | signature: new ECSignature(r, s) 30 | } 31 | } 32 | 33 | ECSignature.fromDER = function (buffer) { 34 | var decode = bip66.decode(buffer) 35 | var r = BigInteger.fromDERInteger(decode.r) 36 | var s = BigInteger.fromDERInteger(decode.s) 37 | 38 | return new ECSignature(r, s) 39 | } 40 | 41 | // BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed) 42 | ECSignature.parseScriptSignature = function (buffer) { 43 | var hashType = buffer.readUInt8(buffer.length - 1) 44 | var hashTypeMod = hashType & ~0x80 45 | 46 | if (hashTypeMod <= 0x00 || hashTypeMod >= 0x04) throw new Error('Invalid hashType ' + hashType) 47 | 48 | return { 49 | signature: ECSignature.fromDER(buffer.slice(0, -1)), 50 | hashType: hashType 51 | } 52 | } 53 | 54 | ECSignature.prototype.toCompact = function (i, compressed) { 55 | if (compressed) { 56 | i += 4 57 | } 58 | 59 | i += 27 60 | 61 | var buffer = new Buffer(65) 62 | buffer.writeUInt8(i, 0) 63 | 64 | this.r.toBuffer(32).copy(buffer, 1) 65 | this.s.toBuffer(32).copy(buffer, 33) 66 | 67 | return buffer 68 | } 69 | 70 | ECSignature.prototype.toDER = function () { 71 | var r = new Buffer(this.r.toDERInteger()) 72 | var s = new Buffer(this.s.toDERInteger()) 73 | 74 | return bip66.encode(r, s) 75 | } 76 | 77 | ECSignature.prototype.toScriptSignature = function (hashType) { 78 | var hashTypeMod = hashType & ~0x80 79 | if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType) 80 | 81 | var hashTypeBuffer = new Buffer(1) 82 | hashTypeBuffer.writeUInt8(hashType, 0) 83 | 84 | return Buffer.concat([this.toDER(), hashTypeBuffer]) 85 | } 86 | 87 | module.exports = ECSignature 88 | -------------------------------------------------------------------------------- /src/hdnode.js: -------------------------------------------------------------------------------- 1 | var base58check = require('bs58check') 2 | var bcrypto = require('./crypto') 3 | var createHmac = require('create-hmac') 4 | var typeforce = require('typeforce') 5 | var types = require('./types') 6 | var NETWORKS = require('./networks') 7 | 8 | var BigInteger = require('bigi') 9 | var ECPair = require('./ecpair') 10 | 11 | var ecurve = require('ecurve') 12 | var curve = ecurve.getCurveByName('secp256k1') 13 | 14 | function HDNode (keyPair, chainCode) { 15 | typeforce(types.tuple('ECPair', types.Buffer256bit), arguments) 16 | 17 | if (!keyPair.compressed) throw new TypeError('BIP32 only allows compressed keyPairs') 18 | 19 | this.keyPair = keyPair 20 | this.chainCode = chainCode 21 | this.depth = 0 22 | this.index = 0 23 | this.parentFingerprint = 0x00000000 24 | } 25 | 26 | HDNode.HIGHEST_BIT = 0x80000000 27 | HDNode.LENGTH = 78 28 | HDNode.MASTER_SECRET = new Buffer('Bitcoin seed') 29 | 30 | HDNode.fromSeedBuffer = function (seed, network) { 31 | typeforce(types.tuple(types.Buffer, types.maybe(types.Network)), arguments) 32 | 33 | if (seed.length < 16) throw new TypeError('Seed should be at least 128 bits') 34 | if (seed.length > 64) throw new TypeError('Seed should be at most 512 bits') 35 | 36 | var I = createHmac('sha512', HDNode.MASTER_SECRET).update(seed).digest() 37 | var IL = I.slice(0, 32) 38 | var IR = I.slice(32) 39 | 40 | // In case IL is 0 or >= n, the master key is invalid 41 | // This is handled by the ECPair constructor 42 | var pIL = BigInteger.fromBuffer(IL) 43 | var keyPair = new ECPair(pIL, null, { 44 | network: network 45 | }) 46 | 47 | return new HDNode(keyPair, IR) 48 | } 49 | 50 | HDNode.fromSeedHex = function (hex, network) { 51 | return HDNode.fromSeedBuffer(new Buffer(hex, 'hex'), network) 52 | } 53 | 54 | HDNode.fromBase58 = function (string, networks) { 55 | var buffer = base58check.decode(string) 56 | if (buffer.length !== 78) throw new Error('Invalid buffer length') 57 | 58 | // 4 bytes: version bytes 59 | var version = buffer.readUInt32BE(0) 60 | var network 61 | 62 | // list of networks? 63 | if (Array.isArray(networks)) { 64 | network = networks.filter(function (x) { 65 | return version === x.bip32.private || 66 | version === x.bip32.public 67 | }).pop() 68 | 69 | if (!network) throw new Error('Unknown network version') 70 | 71 | // otherwise, assume a network object (or default to bitcoin) 72 | } else { 73 | network = networks || NETWORKS.bitcoin 74 | } 75 | 76 | if (version !== network.bip32.private && 77 | version !== network.bip32.public) throw new Error('Invalid network version') 78 | 79 | // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ... 80 | var depth = buffer[4] 81 | 82 | // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key) 83 | var parentFingerprint = buffer.readUInt32BE(5) 84 | if (depth === 0) { 85 | if (parentFingerprint !== 0x00000000) throw new Error('Invalid parent fingerprint') 86 | } 87 | 88 | // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized. 89 | // This is encoded in MSB order. (0x00000000 if master key) 90 | var index = buffer.readUInt32BE(9) 91 | if (depth === 0 && index !== 0) throw new Error('Invalid index') 92 | 93 | // 32 bytes: the chain code 94 | var chainCode = buffer.slice(13, 45) 95 | var keyPair 96 | 97 | // 33 bytes: private key data (0x00 + k) 98 | if (version === network.bip32.private) { 99 | if (buffer.readUInt8(45) !== 0x00) throw new Error('Invalid private key') 100 | 101 | var d = BigInteger.fromBuffer(buffer.slice(46, 78)) 102 | keyPair = new ECPair(d, null, { network: network }) 103 | 104 | // 33 bytes: public key data (0x02 + X or 0x03 + X) 105 | } else { 106 | var Q = ecurve.Point.decodeFrom(curve, buffer.slice(45, 78)) 107 | // Q.compressed is assumed, if somehow this assumption is broken, `new HDNode` will throw 108 | 109 | // Verify that the X coordinate in the public point corresponds to a point on the curve. 110 | // If not, the extended public key is invalid. 111 | curve.validate(Q) 112 | 113 | keyPair = new ECPair(null, Q, { network: network }) 114 | } 115 | 116 | var hd = new HDNode(keyPair, chainCode) 117 | hd.depth = depth 118 | hd.index = index 119 | hd.parentFingerprint = parentFingerprint 120 | 121 | return hd 122 | } 123 | 124 | HDNode.prototype.getAddress = function () { 125 | return this.keyPair.getAddress() 126 | } 127 | 128 | HDNode.prototype.getIdentifier = function () { 129 | return bcrypto.hash160(this.keyPair.getPublicKeyBuffer()) 130 | } 131 | 132 | HDNode.prototype.getFingerprint = function () { 133 | return this.getIdentifier().slice(0, 4) 134 | } 135 | 136 | HDNode.prototype.getNetwork = function () { 137 | return this.keyPair.getNetwork() 138 | } 139 | 140 | HDNode.prototype.getPublicKeyBuffer = function () { 141 | return this.keyPair.getPublicKeyBuffer() 142 | } 143 | 144 | HDNode.prototype.neutered = function () { 145 | var neuteredKeyPair = new ECPair(null, this.keyPair.Q, { 146 | network: this.keyPair.network 147 | }) 148 | 149 | var neutered = new HDNode(neuteredKeyPair, this.chainCode) 150 | neutered.depth = this.depth 151 | neutered.index = this.index 152 | neutered.parentFingerprint = this.parentFingerprint 153 | 154 | return neutered 155 | } 156 | 157 | HDNode.prototype.sign = function (hash) { 158 | return this.keyPair.sign(hash) 159 | } 160 | 161 | HDNode.prototype.verify = function (hash, signature) { 162 | return this.keyPair.verify(hash, signature) 163 | } 164 | 165 | HDNode.prototype.toBase58 = function (__isPrivate) { 166 | if (__isPrivate !== undefined) throw new TypeError('Unsupported argument in 2.0.0') 167 | 168 | // Version 169 | var network = this.keyPair.network 170 | var version = (!this.isNeutered()) ? network.bip32.private : network.bip32.public 171 | var buffer = new Buffer(78) 172 | 173 | // 4 bytes: version bytes 174 | buffer.writeUInt32BE(version, 0) 175 | 176 | // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, .... 177 | buffer.writeUInt8(this.depth, 4) 178 | 179 | // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key) 180 | buffer.writeUInt32BE(this.parentFingerprint, 5) 181 | 182 | // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized. 183 | // This is encoded in big endian. (0x00000000 if master key) 184 | buffer.writeUInt32BE(this.index, 9) 185 | 186 | // 32 bytes: the chain code 187 | this.chainCode.copy(buffer, 13) 188 | 189 | // 33 bytes: the public key or private key data 190 | if (!this.isNeutered()) { 191 | // 0x00 + k for private keys 192 | buffer.writeUInt8(0, 45) 193 | this.keyPair.d.toBuffer(32).copy(buffer, 46) 194 | 195 | // 33 bytes: the public key 196 | } else { 197 | // X9.62 encoding for public keys 198 | this.keyPair.getPublicKeyBuffer().copy(buffer, 45) 199 | } 200 | 201 | return base58check.encode(buffer) 202 | } 203 | 204 | // https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#child-key-derivation-ckd-functions 205 | HDNode.prototype.derive = function (index) { 206 | typeforce(types.UInt32, index) 207 | 208 | var isHardened = index >= HDNode.HIGHEST_BIT 209 | var data = new Buffer(37) 210 | 211 | // Hardened child 212 | if (isHardened) { 213 | if (this.isNeutered()) throw new TypeError('Could not derive hardened child key') 214 | 215 | // data = 0x00 || ser256(kpar) || ser32(index) 216 | data[0] = 0x00 217 | this.keyPair.d.toBuffer(32).copy(data, 1) 218 | data.writeUInt32BE(index, 33) 219 | 220 | // Normal child 221 | } else { 222 | // data = serP(point(kpar)) || ser32(index) 223 | // = serP(Kpar) || ser32(index) 224 | this.keyPair.getPublicKeyBuffer().copy(data, 0) 225 | data.writeUInt32BE(index, 33) 226 | } 227 | 228 | var I = createHmac('sha512', this.chainCode).update(data).digest() 229 | var IL = I.slice(0, 32) 230 | var IR = I.slice(32) 231 | 232 | var pIL = BigInteger.fromBuffer(IL) 233 | 234 | // In case parse256(IL) >= n, proceed with the next value for i 235 | if (pIL.compareTo(curve.n) >= 0) { 236 | return this.derive(index + 1) 237 | } 238 | 239 | // Private parent key -> private child key 240 | var derivedKeyPair 241 | if (!this.isNeutered()) { 242 | // ki = parse256(IL) + kpar (mod n) 243 | var ki = pIL.add(this.keyPair.d).mod(curve.n) 244 | 245 | // In case ki == 0, proceed with the next value for i 246 | if (ki.signum() === 0) { 247 | return this.derive(index + 1) 248 | } 249 | 250 | derivedKeyPair = new ECPair(ki, null, { 251 | network: this.keyPair.network 252 | }) 253 | 254 | // Public parent key -> public child key 255 | } else { 256 | // Ki = point(parse256(IL)) + Kpar 257 | // = G*IL + Kpar 258 | var Ki = curve.G.multiply(pIL).add(this.keyPair.Q) 259 | 260 | // In case Ki is the point at infinity, proceed with the next value for i 261 | if (curve.isInfinity(Ki)) { 262 | return this.derive(index + 1) 263 | } 264 | 265 | derivedKeyPair = new ECPair(null, Ki, { 266 | network: this.keyPair.network 267 | }) 268 | } 269 | 270 | var hd = new HDNode(derivedKeyPair, IR) 271 | hd.depth = this.depth + 1 272 | hd.index = index 273 | hd.parentFingerprint = this.getFingerprint().readUInt32BE(0) 274 | 275 | return hd 276 | } 277 | 278 | HDNode.prototype.deriveHardened = function (index) { 279 | typeforce(types.UInt31, index) 280 | 281 | // Only derives hardened private keys by default 282 | return this.derive(index + HDNode.HIGHEST_BIT) 283 | } 284 | 285 | // Private === not neutered 286 | // Public === neutered 287 | HDNode.prototype.isNeutered = function () { 288 | return !(this.keyPair.d) 289 | } 290 | 291 | HDNode.prototype.derivePath = function (path) { 292 | typeforce(types.BIP32Path, path) 293 | 294 | var splitPath = path.split('/') 295 | if (splitPath[0] === 'm') { 296 | if (this.parentFingerprint) { 297 | throw new Error('Not a master node') 298 | } 299 | 300 | splitPath = splitPath.slice(1) 301 | } 302 | 303 | return splitPath.reduce(function (prevHd, indexStr) { 304 | var index 305 | if (indexStr.slice(-1) === "'") { 306 | index = parseInt(indexStr.slice(0, -1), 10) 307 | return prevHd.deriveHardened(index) 308 | } else { 309 | index = parseInt(indexStr, 10) 310 | return prevHd.derive(index) 311 | } 312 | }, this) 313 | } 314 | 315 | module.exports = HDNode 316 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Block: require('./block'), 3 | ECPair: require('./ecpair'), 4 | ECSignature: require('./ecsignature'), 5 | HDNode: require('./hdnode'), 6 | Transaction: require('./transaction'), 7 | TransactionBuilder: require('./transaction_builder'), 8 | 9 | address: require('./address'), 10 | bufferutils: require('./bufferutils'), // TODO: remove in 4.0.0 11 | crypto: require('./crypto'), 12 | networks: require('./networks'), 13 | opcodes: require('bitcoin-ops'), 14 | script: require('./script') 15 | } 16 | -------------------------------------------------------------------------------- /src/networks.js: -------------------------------------------------------------------------------- 1 | // https://en.bitcoin.it/wiki/List_of_address_prefixes 2 | // Dogecoin BIP32 is a proposed standard: https://bitcointalk.org/index.php?topic=409731 3 | 4 | module.exports = { 5 | bitcoin: { 6 | messagePrefix: '\x18Bitcoin Signed Message:\n', 7 | bip32: { 8 | public: 0x0488b21e, 9 | private: 0x0488ade4 10 | }, 11 | pubKeyHash: 0x00, 12 | scriptHash: 0x05, 13 | wif: 0x80 14 | }, 15 | testnet: { 16 | messagePrefix: '\x18Bitcoin Signed Message:\n', 17 | bip32: { 18 | public: 0x043587cf, 19 | private: 0x04358394 20 | }, 21 | pubKeyHash: 0x6f, 22 | scriptHash: 0xc4, 23 | wif: 0xef 24 | }, 25 | litecoin: { 26 | messagePrefix: '\x19Litecoin Signed Message:\n', 27 | bip32: { 28 | public: 0x019da462, 29 | private: 0x019d9cfe 30 | }, 31 | pubKeyHash: 0x30, 32 | scriptHash: 0x32, 33 | wif: 0xb0 34 | }, 35 | giracoin: { 36 | messagePrefix: '\x18Giracoin Signed Message:\n', 37 | bip32: { 38 | public: 0x0488b21e, 39 | private: 0x0488ade4 40 | }, 41 | pubKeyHash: 0x26, 42 | scriptHash: 0x05, 43 | wif: 0x80 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/script.js: -------------------------------------------------------------------------------- 1 | var bip66 = require('bip66') 2 | var pushdata = require('pushdata-bitcoin') 3 | var typeforce = require('typeforce') 4 | var types = require('./types') 5 | var scriptNumber = require('./script_number') 6 | 7 | var OPS = require('bitcoin-ops') 8 | var REVERSE_OPS = require('bitcoin-ops/map') 9 | var OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 10 | 11 | function isOPInt (value) { 12 | return types.Number(value) && 13 | ((value === OPS.OP_0) || 14 | (value >= OPS.OP_1 && value <= OPS.OP_16) || 15 | (value === OPS.OP_1NEGATE)) 16 | } 17 | 18 | function isPushOnlyChunk (value) { 19 | return types.Buffer(value) || isOPInt(value) 20 | } 21 | 22 | function isPushOnly (value) { 23 | return types.Array(value) && value.every(isPushOnlyChunk) 24 | } 25 | 26 | function compile (chunks) { 27 | // TODO: remove me 28 | if (Buffer.isBuffer(chunks)) return chunks 29 | 30 | typeforce(types.Array, chunks) 31 | 32 | var bufferSize = chunks.reduce(function (accum, chunk) { 33 | // data chunk 34 | if (Buffer.isBuffer(chunk)) { 35 | // adhere to BIP62.3, minimal push policy 36 | if (chunk.length === 1 && (chunk[0] === 0x81 || (chunk[0] >= 1 && chunk[0] <= 16))) { 37 | return accum + 1 38 | } 39 | 40 | return accum + pushdata.encodingLength(chunk.length) + chunk.length 41 | } 42 | 43 | // opcode 44 | return accum + 1 45 | }, 0.0) 46 | 47 | var buffer = new Buffer(bufferSize) 48 | var offset = 0 49 | 50 | chunks.forEach(function (chunk) { 51 | // data chunk 52 | if (Buffer.isBuffer(chunk)) { 53 | // adhere to BIP62.3, minimal push policy 54 | if (chunk.length === 1 && chunk[0] >= 1 && chunk[0] <= 16) { 55 | var opcode = OP_INT_BASE + chunk[0] 56 | buffer.writeUInt8(opcode, offset) 57 | offset += 1 58 | return 59 | } 60 | 61 | if (chunk.length === 1 && chunk[0] === 0x81) { 62 | buffer.writeUInt8(OPS.OP_1NEGATE, offset) 63 | offset += 1 64 | return 65 | } 66 | 67 | offset += pushdata.encode(buffer, chunk.length, offset) 68 | 69 | chunk.copy(buffer, offset) 70 | offset += chunk.length 71 | 72 | // opcode 73 | } else { 74 | buffer.writeUInt8(chunk, offset) 75 | offset += 1 76 | } 77 | }) 78 | 79 | if (offset !== buffer.length) throw new Error('Could not decode chunks') 80 | return buffer 81 | } 82 | 83 | function decompile (buffer) { 84 | // TODO: remove me 85 | if (types.Array(buffer)) return buffer 86 | 87 | typeforce(types.Buffer, buffer) 88 | 89 | var chunks = [] 90 | var i = 0 91 | 92 | while (i < buffer.length) { 93 | var opcode = buffer[i] 94 | 95 | // data chunk 96 | if ((opcode > OPS.OP_0) && (opcode <= OPS.OP_PUSHDATA4)) { 97 | var d = pushdata.decode(buffer, i) 98 | 99 | // did reading a pushDataInt fail? empty script 100 | if (d === null) return [] 101 | i += d.size 102 | 103 | // attempt to read too much data? empty script 104 | if (i + d.number > buffer.length) return [] 105 | 106 | var data = buffer.slice(i, i + d.number) 107 | i += d.number 108 | 109 | chunks.push(data) 110 | 111 | // opcode 112 | } else { 113 | chunks.push(opcode) 114 | 115 | i += 1 116 | } 117 | } 118 | 119 | return chunks 120 | } 121 | 122 | function toASM (chunks) { 123 | if (Buffer.isBuffer(chunks)) { 124 | chunks = decompile(chunks) 125 | } 126 | 127 | return chunks.map(function (chunk) { 128 | // data? 129 | if (Buffer.isBuffer(chunk)) return chunk.toString('hex') 130 | 131 | // opcode! 132 | return REVERSE_OPS[chunk] 133 | }).join(' ') 134 | } 135 | 136 | function fromASM (asm) { 137 | typeforce(types.String, asm) 138 | 139 | return compile(asm.split(' ').map(function (chunkStr) { 140 | // opcode? 141 | if (OPS[chunkStr] !== undefined) return OPS[chunkStr] 142 | typeforce(types.Hex, chunkStr) 143 | 144 | // data! 145 | return new Buffer(chunkStr, 'hex') 146 | })) 147 | } 148 | 149 | function toStack (chunks) { 150 | chunks = decompile(chunks) 151 | typeforce(isPushOnly, chunks) 152 | 153 | return chunks.map(function (op) { 154 | if (Buffer.isBuffer(op)) return op 155 | if (op === OPS.OP_0) return new Buffer(0) 156 | 157 | return scriptNumber.encode(op - OP_INT_BASE) 158 | }) 159 | } 160 | 161 | function isCanonicalPubKey (buffer) { 162 | if (!Buffer.isBuffer(buffer)) return false 163 | if (buffer.length < 33) return false 164 | 165 | switch (buffer[0]) { 166 | case 0x02: 167 | case 0x03: 168 | return buffer.length === 33 169 | case 0x04: 170 | return buffer.length === 65 171 | } 172 | 173 | return false 174 | } 175 | 176 | function isDefinedHashType (hashType) { 177 | var hashTypeMod = hashType & ~0x80 178 | 179 | // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE 180 | return hashTypeMod > 0x00 && hashTypeMod < 0x04 181 | } 182 | 183 | function isCanonicalSignature (buffer) { 184 | if (!Buffer.isBuffer(buffer)) return false 185 | if (!isDefinedHashType(buffer[buffer.length - 1])) return false 186 | 187 | return bip66.check(buffer.slice(0, -1)) 188 | } 189 | 190 | exports.compile = compile 191 | exports.decompile = decompile 192 | exports.fromASM = fromASM 193 | exports.toASM = toASM 194 | exports.toStack = toStack 195 | exports.number = require('./script_number') 196 | exports.isCanonicalPubKey = isCanonicalPubKey 197 | exports.isCanonicalSignature = isCanonicalSignature 198 | exports.isPushOnly = isPushOnly 199 | exports.isDefinedHashType = isDefinedHashType 200 | 201 | var templates = require('./templates') 202 | for (var k in templates) 203 | exports[k] = templates[k] 204 | -------------------------------------------------------------------------------- /src/script_number.js: -------------------------------------------------------------------------------- 1 | function decode (buffer, maxLength, minimal) { 2 | maxLength = maxLength || 4 3 | minimal = minimal === undefined ? true : minimal 4 | 5 | var length = buffer.length 6 | if (length === 0) return 0 7 | if (length > maxLength) throw new TypeError('Script number overflow') 8 | if (minimal) { 9 | if ((buffer[length - 1] & 0x7f) === 0) { 10 | if (length <= 1 || (buffer[length - 2] & 0x80) === 0) throw new Error('Non-minimally encoded script number') 11 | } 12 | } 13 | 14 | // 40-bit 15 | if (length === 5) { 16 | var a = buffer.readUInt32LE(0) 17 | var b = buffer.readUInt8(4) 18 | 19 | if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a) 20 | return b * 0x100000000 + a 21 | } 22 | 23 | var result = 0 24 | 25 | // 32-bit / 24-bit / 16-bit / 8-bit 26 | for (var i = 0; i < length; ++i) { 27 | result |= buffer[i] << (8 * i) 28 | } 29 | 30 | if (buffer[length - 1] & 0x80) return -(result & ~(0x80 << (8 * (length - 1)))) 31 | return result 32 | } 33 | 34 | function scriptNumSize (i) { 35 | return i > 0x7fffffff ? 5 36 | : i > 0x7fffff ? 4 37 | : i > 0x7fff ? 3 38 | : i > 0x7f ? 2 39 | : i > 0x00 ? 1 40 | : 0 41 | } 42 | 43 | function encode (number) { 44 | var value = Math.abs(number) 45 | var size = scriptNumSize(value) 46 | var buffer = new Buffer(size) 47 | var negative = number < 0 48 | 49 | for (var i = 0; i < size; ++i) { 50 | buffer.writeUInt8(value & 0xff, i) 51 | value >>= 8 52 | } 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 | 60 | return buffer 61 | } 62 | 63 | module.exports = { 64 | decode: decode, 65 | encode: encode 66 | } 67 | -------------------------------------------------------------------------------- /src/templates/index.js: -------------------------------------------------------------------------------- 1 | var decompile = require('../script').decompile 2 | var multisig = require('./multisig') 3 | var nullData = require('./nulldata') 4 | var pubKey = require('./pubkey') 5 | var pubKeyHash = require('./pubkeyhash') 6 | var scriptHash = require('./scripthash') 7 | var witnessPubKeyHash = require('./witnesspubkeyhash') 8 | var witnessScriptHash = require('./witnessscripthash') 9 | var witnessCommitment = require('./witnesscommitment') 10 | 11 | var types = { 12 | MULTISIG: 'multisig', 13 | NONSTANDARD: 'nonstandard', 14 | NULLDATA: 'nulldata', 15 | P2PK: 'pubkey', 16 | P2PKH: 'pubkeyhash', 17 | P2SH: 'scripthash', 18 | P2WPKH: 'witnesspubkeyhash', 19 | P2WSH: 'witnessscripthash', 20 | WITNESS_COMMITMENT: 'witnesscommitment' 21 | } 22 | 23 | function classifyOutput (script) { 24 | if (witnessPubKeyHash.output.check(script)) return types.P2WPKH 25 | if (witnessScriptHash.output.check(script)) return types.P2WSH 26 | if (pubKeyHash.output.check(script)) return types.P2PKH 27 | if (scriptHash.output.check(script)) return types.P2SH 28 | 29 | // XXX: optimization, below functions .decompile before use 30 | var chunks = decompile(script) 31 | if (multisig.output.check(chunks)) return types.MULTISIG 32 | if (pubKey.output.check(chunks)) return types.P2PK 33 | if (witnessCommitment.output.check(chunks)) return types.WITNESS_COMMITMENT 34 | if (nullData.output.check(chunks)) return types.NULLDATA 35 | 36 | return types.NONSTANDARD 37 | } 38 | 39 | function classifyInput (script, allowIncomplete) { 40 | // XXX: optimization, below functions .decompile before use 41 | var chunks = decompile(script) 42 | 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.MULTISIG 46 | if (pubKey.input.check(chunks)) return types.P2PK 47 | 48 | return types.NONSTANDARD 49 | } 50 | 51 | function classifyWitness (script, allowIncomplete) { 52 | // XXX: optimization, below functions .decompile before use 53 | var chunks = decompile(script) 54 | 55 | if (witnessPubKeyHash.input.check(chunks)) return types.P2WPKH 56 | if (witnessScriptHash.input.check(chunks, allowIncomplete)) return types.P2WSH 57 | 58 | return types.NONSTANDARD 59 | } 60 | 61 | module.exports = { 62 | classifyInput: classifyInput, 63 | classifyOutput: classifyOutput, 64 | classifyWitness: classifyWitness, 65 | multisig: multisig, 66 | nullData: nullData, 67 | pubKey: pubKey, 68 | pubKeyHash: pubKeyHash, 69 | scriptHash: scriptHash, 70 | witnessPubKeyHash: witnessPubKeyHash, 71 | witnessScriptHash: witnessScriptHash, 72 | witnessCommitment: witnessCommitment, 73 | types: types 74 | } 75 | -------------------------------------------------------------------------------- /src/templates/multisig/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | input: require('./input'), 3 | output: require('./output') 4 | } 5 | -------------------------------------------------------------------------------- /src/templates/multisig/input.js: -------------------------------------------------------------------------------- 1 | // OP_0 [signatures ...] 2 | 3 | var bscript = require('../../script') 4 | var typeforce = require('typeforce') 5 | var OPS = require('bitcoin-ops') 6 | 7 | function partialSignature (value) { 8 | return value === OPS.OP_0 || bscript.isCanonicalSignature(value) 9 | } 10 | 11 | function check (script, allowIncomplete) { 12 | var chunks = bscript.decompile(script) 13 | if (chunks.length < 2) return false 14 | if (chunks[0] !== OPS.OP_0) return false 15 | 16 | if (allowIncomplete) { 17 | return chunks.slice(1).every(partialSignature) 18 | } 19 | 20 | return chunks.slice(1).every(bscript.isCanonicalSignature) 21 | } 22 | check.toJSON = function () { return 'multisig input' } 23 | 24 | function encodeStack (signatures, scriptPubKey) { 25 | typeforce([partialSignature], signatures) 26 | 27 | if (scriptPubKey) { 28 | var scriptData = bscript.multisig.output.decode(scriptPubKey) 29 | 30 | if (signatures.length < scriptData.m) { 31 | throw new TypeError('Not enough signatures provided') 32 | } 33 | 34 | if (signatures.length > scriptData.pubKeys.length) { 35 | throw new TypeError('Too many signatures provided') 36 | } 37 | } 38 | 39 | return [].concat(new Buffer(0), signatures) 40 | } 41 | 42 | function encode (signatures, scriptPubKey) { 43 | return bscript.compile(encodeStack(signatures, scriptPubKey)) 44 | } 45 | 46 | function decodeStack (stack, allowIncomplete) { 47 | typeforce(check, stack, allowIncomplete) 48 | return stack.slice(1) 49 | } 50 | 51 | function decode (buffer, allowIncomplete) { 52 | var stack = bscript.decompile(buffer) 53 | return decodeStack(stack, allowIncomplete) 54 | } 55 | 56 | module.exports = { 57 | check: check, 58 | decode: decode, 59 | decodeStack: decodeStack, 60 | encode: encode, 61 | encodeStack: encodeStack 62 | } 63 | -------------------------------------------------------------------------------- /src/templates/multisig/output.js: -------------------------------------------------------------------------------- 1 | // m [pubKeys ...] n OP_CHECKMULTISIG 2 | 3 | var bscript = require('../../script') 4 | var types = require('../../types') 5 | var typeforce = require('typeforce') 6 | var OPS = require('bitcoin-ops') 7 | var OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1 8 | 9 | function check (script, allowIncomplete) { 10 | var chunks = bscript.decompile(script) 11 | 12 | if (chunks.length < 4) return false 13 | if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) return false 14 | if (!types.Number(chunks[0])) return false 15 | if (!types.Number(chunks[chunks.length - 2])) return false 16 | var m = chunks[0] - OP_INT_BASE 17 | var n = chunks[chunks.length - 2] - OP_INT_BASE 18 | 19 | if (m <= 0) return false 20 | if (n > 16) return false 21 | if (m > n) return false 22 | if (n !== chunks.length - 3) return false 23 | if (allowIncomplete) return true 24 | 25 | var keys = chunks.slice(1, -2) 26 | return keys.every(bscript.isCanonicalPubKey) 27 | } 28 | check.toJSON = function () { return 'multi-sig output' } 29 | 30 | function encode (m, pubKeys) { 31 | typeforce({ 32 | m: types.Number, 33 | pubKeys: [bscript.isCanonicalPubKey] 34 | }, { 35 | m: m, 36 | pubKeys: pubKeys 37 | }) 38 | 39 | var n = pubKeys.length 40 | if (n < m) throw new TypeError('Not enough pubKeys provided') 41 | 42 | return bscript.compile([].concat( 43 | OP_INT_BASE + m, 44 | pubKeys, 45 | OP_INT_BASE + n, 46 | OPS.OP_CHECKMULTISIG 47 | )) 48 | } 49 | 50 | function decode (buffer, allowIncomplete) { 51 | var chunks = bscript.decompile(buffer) 52 | typeforce(check, chunks, allowIncomplete) 53 | 54 | return { 55 | m: chunks[0] - OP_INT_BASE, 56 | pubKeys: chunks.slice(1, -2) 57 | } 58 | } 59 | 60 | module.exports = { 61 | check: check, 62 | decode: decode, 63 | encode: encode 64 | } 65 | -------------------------------------------------------------------------------- /src/templates/nulldata.js: -------------------------------------------------------------------------------- 1 | // OP_RETURN {data} 2 | 3 | var bscript = require('../script') 4 | var types = require('../types') 5 | var typeforce = require('typeforce') 6 | var OPS = require('bitcoin-ops') 7 | 8 | function check (script) { 9 | var buffer = bscript.compile(script) 10 | 11 | return buffer.length > 1 && 12 | buffer[0] === OPS.OP_RETURN 13 | } 14 | check.toJSON = function () { return 'null data output' } 15 | 16 | function encode (data) { 17 | typeforce(types.Buffer, data) 18 | 19 | return bscript.compile([OPS.OP_RETURN, data]) 20 | } 21 | 22 | function decode (buffer) { 23 | typeforce(check, buffer) 24 | 25 | return buffer.slice(2) 26 | } 27 | 28 | module.exports = { 29 | output: { 30 | check: check, 31 | decode: decode, 32 | encode: encode 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/templates/pubkey/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | input: require('./input'), 3 | output: require('./output') 4 | } 5 | -------------------------------------------------------------------------------- /src/templates/pubkey/input.js: -------------------------------------------------------------------------------- 1 | // {signature} 2 | 3 | var bscript = require('../../script') 4 | var types = require('../../types') 5 | var typeforce = require('typeforce') 6 | 7 | function check (script) { 8 | var chunks = bscript.decompile(script) 9 | 10 | return chunks.length === 1 && 11 | bscript.isCanonicalSignature(chunks[0]) 12 | } 13 | check.toJSON = function () { return 'pubKey input' } 14 | 15 | function encodeStack (signature) { 16 | typeforce(types.Buffer, signature) 17 | return [signature] 18 | } 19 | 20 | function encode (signature) { 21 | return bscript.compile(encodeStack(signature)) 22 | } 23 | 24 | function decodeStack (stack) { 25 | typeforce(check, stack) 26 | return stack[0] 27 | } 28 | 29 | function decode (buffer) { 30 | var stack = bscript.decompile(buffer) 31 | return decodeStack(stack) 32 | } 33 | 34 | module.exports = { 35 | check: check, 36 | decode: decode, 37 | decodeStack: decodeStack, 38 | encode: encode, 39 | encodeStack: encodeStack 40 | } 41 | -------------------------------------------------------------------------------- /src/templates/pubkey/output.js: -------------------------------------------------------------------------------- 1 | // {pubKey} OP_CHECKSIG 2 | 3 | var bscript = require('../../script') 4 | var typeforce = require('typeforce') 5 | var OPS = require('bitcoin-ops') 6 | 7 | function check (script) { 8 | var chunks = bscript.decompile(script) 9 | 10 | return chunks.length === 2 && 11 | bscript.isCanonicalPubKey(chunks[0]) && 12 | chunks[1] === OPS.OP_CHECKSIG 13 | } 14 | check.toJSON = function () { return 'pubKey output' } 15 | 16 | function encode (pubKey) { 17 | typeforce(bscript.isCanonicalPubKey, pubKey) 18 | 19 | return bscript.compile([pubKey, OPS.OP_CHECKSIG]) 20 | } 21 | 22 | function decode (buffer) { 23 | var chunks = bscript.decompile(buffer) 24 | typeforce(check, chunks) 25 | 26 | return chunks[0] 27 | } 28 | 29 | module.exports = { 30 | check: check, 31 | decode: decode, 32 | encode: encode 33 | } 34 | -------------------------------------------------------------------------------- /src/templates/pubkeyhash/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | input: require('./input'), 3 | output: require('./output') 4 | } 5 | -------------------------------------------------------------------------------- /src/templates/pubkeyhash/input.js: -------------------------------------------------------------------------------- 1 | // {signature} {pubKey} 2 | 3 | var bscript = require('../../script') 4 | var types = require('../../types') 5 | var typeforce = require('typeforce') 6 | 7 | function check (script) { 8 | var chunks = bscript.decompile(script) 9 | 10 | return chunks.length === 2 && 11 | bscript.isCanonicalSignature(chunks[0]) && 12 | bscript.isCanonicalPubKey(chunks[1]) 13 | } 14 | check.toJSON = function () { return 'pubKeyHash input' } 15 | 16 | function encodeStack (signature, pubKey) { 17 | typeforce({ 18 | signature: types.Buffer, pubKey: types.Buffer 19 | }, { 20 | signature: signature, pubKey: pubKey 21 | }) 22 | 23 | return [signature, pubKey] 24 | } 25 | 26 | function encode (signature, pubKey) { 27 | return bscript.compile(encodeStack(signature, pubKey)) 28 | } 29 | 30 | function decodeStack (stack) { 31 | typeforce(check, stack) 32 | 33 | return { 34 | signature: stack[0], 35 | pubKey: stack[1] 36 | } 37 | } 38 | 39 | function decode (buffer) { 40 | var stack = bscript.decompile(buffer) 41 | return decodeStack(stack) 42 | } 43 | 44 | module.exports = { 45 | check: check, 46 | decode: decode, 47 | decodeStack: decodeStack, 48 | encode: encode, 49 | encodeStack: encodeStack 50 | } 51 | -------------------------------------------------------------------------------- /src/templates/pubkeyhash/output.js: -------------------------------------------------------------------------------- 1 | // OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG 2 | 3 | var bscript = require('../../script') 4 | var types = require('../../types') 5 | var typeforce = require('typeforce') 6 | var OPS = require('bitcoin-ops') 7 | 8 | function check (script) { 9 | var buffer = bscript.compile(script) 10 | 11 | return buffer.length === 25 && 12 | buffer[0] === OPS.OP_DUP && 13 | buffer[1] === OPS.OP_HASH160 && 14 | buffer[2] === 0x14 && 15 | buffer[23] === OPS.OP_EQUALVERIFY && 16 | buffer[24] === OPS.OP_CHECKSIG 17 | } 18 | check.toJSON = function () { return 'pubKeyHash output' } 19 | 20 | function encode (pubKeyHash) { 21 | typeforce(types.Hash160bit, pubKeyHash) 22 | 23 | return bscript.compile([ 24 | OPS.OP_DUP, 25 | OPS.OP_HASH160, 26 | pubKeyHash, 27 | OPS.OP_EQUALVERIFY, 28 | OPS.OP_CHECKSIG 29 | ]) 30 | } 31 | 32 | function decode (buffer) { 33 | typeforce(check, buffer) 34 | 35 | return buffer.slice(3, 23) 36 | } 37 | 38 | module.exports = { 39 | check: check, 40 | decode: decode, 41 | encode: encode 42 | } 43 | -------------------------------------------------------------------------------- /src/templates/scripthash/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | input: require('./input'), 3 | output: require('./output') 4 | } 5 | -------------------------------------------------------------------------------- /src/templates/scripthash/input.js: -------------------------------------------------------------------------------- 1 | // {serialized scriptPubKey script} 2 | 3 | var bscript = require('../../script') 4 | var typeforce = require('typeforce') 5 | 6 | function check (script, allowIncomplete) { 7 | var chunks = bscript.decompile(script) 8 | if (chunks.length < 1) return false 9 | 10 | var lastChunk = chunks[chunks.length - 1] 11 | if (!Buffer.isBuffer(lastChunk)) return false 12 | 13 | var scriptSigChunks = bscript.decompile(bscript.compile(chunks.slice(0, -1))) 14 | var redeemScriptChunks = bscript.decompile(lastChunk) 15 | 16 | // is redeemScript a valid script? 17 | if (redeemScriptChunks.length === 0) return false 18 | 19 | // is redeemScriptSig push only? 20 | if (!bscript.isPushOnly(scriptSigChunks)) return false 21 | 22 | var inputType = bscript.classifyInput(scriptSigChunks, allowIncomplete) 23 | var outputType = bscript.classifyOutput(redeemScriptChunks) 24 | if (chunks.length === 1) { 25 | return outputType === bscript.types.P2WSH || outputType === bscript.types.P2WPKH 26 | } 27 | return inputType === outputType 28 | } 29 | check.toJSON = function () { return 'scriptHash input' } 30 | 31 | function encodeStack (redeemScriptStack, redeemScript) { 32 | var serializedScriptPubKey = bscript.compile(redeemScript) 33 | 34 | return [].concat(redeemScriptStack, serializedScriptPubKey) 35 | } 36 | 37 | function encode (redeemScriptSig, redeemScript) { 38 | var redeemScriptStack = bscript.decompile(redeemScriptSig) 39 | 40 | return bscript.compile(encodeStack(redeemScriptStack, redeemScript)) 41 | } 42 | 43 | function decodeStack (stack) { 44 | typeforce(check, stack) 45 | 46 | return { 47 | redeemScriptStack: stack.slice(0, -1), 48 | redeemScript: stack[stack.length - 1] 49 | } 50 | } 51 | 52 | function decode (buffer) { 53 | var stack = bscript.decompile(buffer) 54 | var result = decodeStack(stack) 55 | result.redeemScriptSig = bscript.compile(result.redeemScriptStack) 56 | delete result.redeemScriptStack 57 | return result 58 | } 59 | 60 | module.exports = { 61 | check: check, 62 | decode: decode, 63 | decodeStack: decodeStack, 64 | encode: encode, 65 | encodeStack: encodeStack 66 | } 67 | -------------------------------------------------------------------------------- /src/templates/scripthash/output.js: -------------------------------------------------------------------------------- 1 | // OP_HASH160 {scriptHash} OP_EQUAL 2 | 3 | var bscript = require('../../script') 4 | var types = require('../../types') 5 | var typeforce = require('typeforce') 6 | var OPS = require('bitcoin-ops') 7 | 8 | function check (script) { 9 | var buffer = bscript.compile(script) 10 | 11 | return buffer.length === 23 && 12 | buffer[0] === OPS.OP_HASH160 && 13 | buffer[1] === 0x14 && 14 | buffer[22] === OPS.OP_EQUAL 15 | } 16 | check.toJSON = function () { return 'scriptHash output' } 17 | 18 | function encode (scriptHash) { 19 | typeforce(types.Hash160bit, scriptHash) 20 | 21 | return bscript.compile([OPS.OP_HASH160, scriptHash, OPS.OP_EQUAL]) 22 | } 23 | 24 | function decode (buffer) { 25 | typeforce(check, buffer) 26 | 27 | return buffer.slice(2, 22) 28 | } 29 | 30 | module.exports = { 31 | check: check, 32 | decode: decode, 33 | encode: encode 34 | } 35 | -------------------------------------------------------------------------------- /src/templates/witnesscommitment/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | output: require('./output') 3 | } 4 | -------------------------------------------------------------------------------- /src/templates/witnesscommitment/output.js: -------------------------------------------------------------------------------- 1 | // OP_RETURN {aa21a9ed} {commitment} 2 | 3 | var bscript = require('../../script') 4 | var types = require('../../types') 5 | var typeforce = require('typeforce') 6 | var OPS = require('bitcoin-ops') 7 | 8 | var HEADER = new Buffer('aa21a9ed', 'hex') 9 | 10 | function check (script) { 11 | var buffer = bscript.compile(script) 12 | 13 | return buffer.length > 37 && 14 | buffer[0] === OPS.OP_RETURN && 15 | buffer[1] === 0x24 && 16 | buffer.slice(2, 6).equals(HEADER) 17 | } 18 | 19 | check.toJSON = function () { return 'Witness commitment output' } 20 | 21 | function encode (commitment) { 22 | typeforce(types.Hash256bit, commitment) 23 | 24 | return bscript.compile([OPS.OP_RETURN, Buffer.concat([HEADER, commitment])]) 25 | } 26 | 27 | function decode (buffer) { 28 | typeforce(check, buffer) 29 | 30 | return bscript.decompile(buffer)[1].slice(4, 36) 31 | } 32 | 33 | module.exports = { 34 | check: check, 35 | decode: decode, 36 | encode: encode 37 | } 38 | -------------------------------------------------------------------------------- /src/templates/witnesspubkeyhash/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | input: require('./input'), 3 | output: require('./output') 4 | } 5 | -------------------------------------------------------------------------------- /src/templates/witnesspubkeyhash/input.js: -------------------------------------------------------------------------------- 1 | // {signature} {pubKey} 2 | 3 | var pkh = require('../pubkeyhash/input') 4 | 5 | module.exports = { 6 | check: pkh.check, 7 | decodeStack: pkh.decodeStack, 8 | encodeStack: pkh.encodeStack 9 | } 10 | -------------------------------------------------------------------------------- /src/templates/witnesspubkeyhash/output.js: -------------------------------------------------------------------------------- 1 | // OP_0 {pubKeyHash} 2 | 3 | var bscript = require('../../script') 4 | var types = require('../../types') 5 | var typeforce = require('typeforce') 6 | var OPS = require('bitcoin-ops') 7 | 8 | function check (script) { 9 | var buffer = bscript.compile(script) 10 | 11 | return buffer.length === 22 && 12 | buffer[0] === OPS.OP_0 && 13 | buffer[1] === 0x14 14 | } 15 | check.toJSON = function () { return 'Witness pubKeyHash output' } 16 | 17 | function encode (pubKeyHash) { 18 | typeforce(types.Hash160bit, pubKeyHash) 19 | 20 | return bscript.compile([OPS.OP_0, pubKeyHash]) 21 | } 22 | 23 | function decode (buffer) { 24 | typeforce(check, buffer) 25 | 26 | return buffer.slice(2) 27 | } 28 | 29 | module.exports = { 30 | check: check, 31 | decode: decode, 32 | encode: encode 33 | } 34 | -------------------------------------------------------------------------------- /src/templates/witnessscripthash/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | input: require('./input'), 3 | output: require('./output') 4 | } 5 | -------------------------------------------------------------------------------- /src/templates/witnessscripthash/input.js: -------------------------------------------------------------------------------- 1 | // {signature} {pubKey} 2 | 3 | var p2sh = require('../scripthash/input') 4 | 5 | module.exports = { 6 | check: p2sh.check, 7 | decodeStack: p2sh.decodeStack, 8 | encodeStack: p2sh.encodeStack 9 | } 10 | -------------------------------------------------------------------------------- /src/templates/witnessscripthash/output.js: -------------------------------------------------------------------------------- 1 | // OP_0 {scriptHash} 2 | 3 | var bscript = require('../../script') 4 | var types = require('../../types') 5 | var typeforce = require('typeforce') 6 | var OPS = require('bitcoin-ops') 7 | 8 | function check (script) { 9 | var buffer = bscript.compile(script) 10 | 11 | return buffer.length === 34 && 12 | buffer[0] === OPS.OP_0 && 13 | buffer[1] === 0x20 14 | } 15 | check.toJSON = function () { return 'Witness scriptHash output' } 16 | 17 | function encode (scriptHash) { 18 | typeforce(types.Hash256bit, scriptHash) 19 | 20 | return bscript.compile([OPS.OP_0, scriptHash]) 21 | } 22 | 23 | function decode (buffer) { 24 | typeforce(check, buffer) 25 | 26 | return buffer.slice(2) 27 | } 28 | 29 | module.exports = { 30 | check: check, 31 | decode: decode, 32 | encode: encode 33 | } 34 | -------------------------------------------------------------------------------- /src/transaction.js: -------------------------------------------------------------------------------- 1 | var bcrypto = require('./crypto') 2 | var bscript = require('./script') 3 | var bufferutils = require('./bufferutils') 4 | var opcodes = require('bitcoin-ops') 5 | var typeforce = require('typeforce') 6 | var types = require('./types') 7 | var varuint = require('varuint-bitcoin') 8 | 9 | function varSliceSize (someScript) { 10 | var length = someScript.length 11 | 12 | return varuint.encodingLength(length) + length 13 | } 14 | 15 | function vectorSize (someVector) { 16 | var length = someVector.length 17 | 18 | return varuint.encodingLength(length) + someVector.reduce(function (sum, witness) { 19 | return sum + varSliceSize(witness) 20 | }, 0) 21 | } 22 | 23 | function Transaction () { 24 | this.version = 1 25 | this.locktime = 0 26 | this.ins = [] 27 | this.outs = [] 28 | } 29 | 30 | Transaction.DEFAULT_SEQUENCE = 0xffffffff 31 | Transaction.SIGHASH_ALL = 0x01 32 | Transaction.SIGHASH_NONE = 0x02 33 | Transaction.SIGHASH_SINGLE = 0x03 34 | Transaction.SIGHASH_ANYONECANPAY = 0x80 35 | Transaction.ADVANCED_TRANSACTION_MARKER = 0x00 36 | Transaction.ADVANCED_TRANSACTION_FLAG = 0x01 37 | 38 | var EMPTY_SCRIPT = new Buffer(0) 39 | var EMPTY_WITNESS = [] 40 | var ZERO = new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') 41 | var ONE = new Buffer('0000000000000000000000000000000000000000000000000000000000000001', 'hex') 42 | var VALUE_UINT64_MAX = new Buffer('ffffffffffffffff', 'hex') 43 | var BLANK_OUTPUT = { 44 | script: EMPTY_SCRIPT, 45 | valueBuffer: VALUE_UINT64_MAX 46 | } 47 | 48 | Transaction.fromBuffer = function (buffer, __noStrict) { 49 | var offset = 0 50 | function readSlice (n) { 51 | offset += n 52 | return buffer.slice(offset - n, offset) 53 | } 54 | 55 | function readUInt32 () { 56 | var i = buffer.readUInt32LE(offset) 57 | offset += 4 58 | return i 59 | } 60 | 61 | function readInt32 () { 62 | var i = buffer.readInt32LE(offset) 63 | offset += 4 64 | return i 65 | } 66 | 67 | function readUInt64 () { 68 | var i = bufferutils.readUInt64LE(buffer, offset) 69 | offset += 8 70 | return i 71 | } 72 | 73 | function readVarInt () { 74 | var vi = varuint.decode(buffer, offset) 75 | offset += varuint.decode.bytes 76 | return vi 77 | } 78 | 79 | function readVarSlice () { 80 | return readSlice(readVarInt()) 81 | } 82 | 83 | function readVector () { 84 | var count = readVarInt() 85 | var vector = [] 86 | for (var i = 0; i < count; i++) vector.push(readVarSlice()) 87 | return vector 88 | } 89 | 90 | var tx = new Transaction() 91 | tx.version = readInt32() 92 | 93 | var marker = buffer.readUInt8(offset) 94 | var flag = buffer.readUInt8(offset + 1) 95 | 96 | var hasWitnesses = false 97 | if (marker === Transaction.ADVANCED_TRANSACTION_MARKER && 98 | flag === Transaction.ADVANCED_TRANSACTION_FLAG) { 99 | offset += 2 100 | hasWitnesses = true 101 | } 102 | 103 | var vinLen = readVarInt() 104 | for (var i = 0; i < vinLen; ++i) { 105 | tx.ins.push({ 106 | hash: readSlice(32), 107 | index: readUInt32(), 108 | script: readVarSlice(), 109 | sequence: readUInt32(), 110 | witness: EMPTY_WITNESS 111 | }) 112 | } 113 | 114 | var voutLen = readVarInt() 115 | for (i = 0; i < voutLen; ++i) { 116 | tx.outs.push({ 117 | value: readUInt64(), 118 | script: readVarSlice() 119 | }) 120 | } 121 | 122 | if (hasWitnesses) { 123 | for (i = 0; i < vinLen; ++i) { 124 | tx.ins[i].witness = readVector() 125 | } 126 | 127 | // was this pointless? 128 | if (!tx.hasWitnesses()) throw new Error('Transaction has superfluous witness data') 129 | } 130 | 131 | tx.locktime = readUInt32() 132 | 133 | if (__noStrict) return tx 134 | if (offset !== buffer.length) throw new Error('Transaction has unexpected data') 135 | 136 | return tx 137 | } 138 | 139 | Transaction.fromHex = function (hex) { 140 | return Transaction.fromBuffer(Buffer.from(hex, 'hex')) 141 | } 142 | 143 | Transaction.isCoinbaseHash = function (buffer) { 144 | typeforce(types.Hash256bit, buffer) 145 | for (var i = 0; i < 32; ++i) { 146 | if (buffer[i] !== 0) return false 147 | } 148 | return true 149 | } 150 | 151 | Transaction.prototype.isCoinbase = function () { 152 | return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash) 153 | } 154 | 155 | Transaction.prototype.addInput = function (hash, index, sequence, scriptSig) { 156 | typeforce(types.tuple( 157 | types.Hash256bit, 158 | types.UInt32, 159 | types.maybe(types.UInt32), 160 | types.maybe(types.Buffer) 161 | ), arguments) 162 | 163 | if (types.Null(sequence)) { 164 | sequence = Transaction.DEFAULT_SEQUENCE 165 | } 166 | 167 | // Add the input and return the input's index 168 | return (this.ins.push({ 169 | hash: hash, 170 | index: index, 171 | script: scriptSig || EMPTY_SCRIPT, 172 | sequence: sequence, 173 | witness: EMPTY_WITNESS 174 | }) - 1) 175 | } 176 | 177 | Transaction.prototype.addOutput = function (scriptPubKey, value) { 178 | typeforce(types.tuple(types.Buffer, types.Satoshi), arguments) 179 | 180 | // Add the output and return the output's index 181 | return (this.outs.push({ 182 | script: scriptPubKey, 183 | value: value 184 | }) - 1) 185 | } 186 | 187 | Transaction.prototype.hasWitnesses = function () { 188 | return this.ins.some(function (x) { 189 | return x.witness.length !== 0 190 | }) 191 | } 192 | 193 | Transaction.prototype.byteLength = function () { 194 | return this.__byteLength(true) 195 | } 196 | 197 | Transaction.prototype.__byteLength = function (__allowWitness) { 198 | var hasWitnesses = __allowWitness && this.hasWitnesses() 199 | 200 | return ( 201 | (hasWitnesses ? 10 : 8) + 202 | varuint.encodingLength(this.ins.length) + 203 | varuint.encodingLength(this.outs.length) + 204 | this.ins.reduce(function (sum, input) { return sum + 40 + varSliceSize(input.script) }, 0) + 205 | this.outs.reduce(function (sum, output) { return sum + 8 + varSliceSize(output.script) }, 0) + 206 | (hasWitnesses ? this.ins.reduce(function (sum, input) { return sum + vectorSize(input.witness) }, 0) : 0) 207 | ) 208 | } 209 | 210 | Transaction.prototype.clone = function () { 211 | var newTx = new Transaction() 212 | newTx.version = this.version 213 | newTx.locktime = this.locktime 214 | 215 | newTx.ins = this.ins.map(function (txIn) { 216 | return { 217 | hash: txIn.hash, 218 | index: txIn.index, 219 | script: txIn.script, 220 | sequence: txIn.sequence, 221 | witness: txIn.witness 222 | } 223 | }) 224 | 225 | newTx.outs = this.outs.map(function (txOut) { 226 | return { 227 | script: txOut.script, 228 | value: txOut.value 229 | } 230 | }) 231 | 232 | return newTx 233 | } 234 | 235 | /** 236 | * Hash transaction for signing a specific input. 237 | * 238 | * Bitcoin uses a different hash for each signed transaction input. 239 | * This method copies the transaction, makes the necessary changes based on the 240 | * hashType, and then hashes the result. 241 | * This hash can then be used to sign the provided transaction input. 242 | */ 243 | Transaction.prototype.hashForSignature = function (inIndex, prevOutScript, hashType) { 244 | typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments) 245 | 246 | // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29 247 | if (inIndex >= this.ins.length) return ONE 248 | 249 | // ignore OP_CODESEPARATOR 250 | var ourScript = bscript.compile(bscript.decompile(prevOutScript).filter(function (x) { 251 | return x !== opcodes.OP_CODESEPARATOR 252 | })) 253 | 254 | var txTmp = this.clone() 255 | 256 | // SIGHASH_NONE: ignore all outputs? (wildcard payee) 257 | if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { 258 | txTmp.outs = [] 259 | 260 | // ignore sequence numbers (except at inIndex) 261 | txTmp.ins.forEach(function (input, i) { 262 | if (i === inIndex) return 263 | 264 | input.sequence = 0 265 | }) 266 | 267 | // SIGHASH_SINGLE: ignore all outputs, except at the same index? 268 | } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { 269 | // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60 270 | if (inIndex >= this.outs.length) return ONE 271 | 272 | // truncate outputs after 273 | txTmp.outs.length = inIndex + 1 274 | 275 | // "blank" outputs before 276 | for (var i = 0; i < inIndex; i++) { 277 | txTmp.outs[i] = BLANK_OUTPUT 278 | } 279 | 280 | // ignore sequence numbers (except at inIndex) 281 | txTmp.ins.forEach(function (input, y) { 282 | if (y === inIndex) return 283 | 284 | input.sequence = 0 285 | }) 286 | } 287 | 288 | // SIGHASH_ANYONECANPAY: ignore inputs entirely? 289 | if (hashType & Transaction.SIGHASH_ANYONECANPAY) { 290 | txTmp.ins = [txTmp.ins[inIndex]] 291 | txTmp.ins[0].script = ourScript 292 | 293 | // SIGHASH_ALL: only ignore input scripts 294 | } else { 295 | // "blank" others input scripts 296 | txTmp.ins.forEach(function (input) { input.script = EMPTY_SCRIPT }) 297 | txTmp.ins[inIndex].script = ourScript 298 | } 299 | 300 | // serialize and hash 301 | var buffer = new Buffer(txTmp.__byteLength(false) + 4) 302 | buffer.writeInt32LE(hashType, buffer.length - 4) 303 | txTmp.__toBuffer(buffer, 0, false) 304 | 305 | return bcrypto.hash256(buffer) 306 | } 307 | 308 | Transaction.prototype.hashForWitnessV0 = function (inIndex, prevOutScript, value, hashType) { 309 | typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments) 310 | 311 | var tbuffer, toffset 312 | function writeSlice (slice) { toffset += slice.copy(tbuffer, toffset) } 313 | function writeUInt32 (i) { toffset = tbuffer.writeUInt32LE(i, toffset) } 314 | function writeUInt64 (i) { toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset) } 315 | function writeVarInt (i) { 316 | varuint.encode(i, tbuffer, toffset) 317 | toffset += varuint.encode.bytes 318 | } 319 | function writeVarSlice (slice) { writeVarInt(slice.length); writeSlice(slice) } 320 | 321 | var hashOutputs = ZERO 322 | var hashPrevouts = ZERO 323 | var hashSequence = ZERO 324 | 325 | if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) { 326 | tbuffer = new Buffer(36 * this.ins.length) 327 | toffset = 0 328 | 329 | this.ins.forEach(function (txIn) { 330 | writeSlice(txIn.hash) 331 | writeUInt32(txIn.index) 332 | }) 333 | 334 | hashPrevouts = bcrypto.hash256(tbuffer) 335 | } 336 | 337 | if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) && 338 | (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && 339 | (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { 340 | tbuffer = new Buffer(4 * this.ins.length) 341 | toffset = 0 342 | 343 | this.ins.forEach(function (txIn) { 344 | writeUInt32(txIn.sequence) 345 | }) 346 | 347 | hashSequence = bcrypto.hash256(tbuffer) 348 | } 349 | 350 | if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE && 351 | (hashType & 0x1f) !== Transaction.SIGHASH_NONE) { 352 | var txOutsSize = this.outs.reduce(function (sum, output) { 353 | return sum + 8 + varSliceSize(output.script) 354 | }, 0) 355 | 356 | tbuffer = new Buffer(txOutsSize) 357 | toffset = 0 358 | 359 | this.outs.forEach(function (out) { 360 | writeUInt64(out.value) 361 | writeVarSlice(out.script) 362 | }) 363 | 364 | hashOutputs = bcrypto.hash256(tbuffer) 365 | } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) { 366 | var output = this.outs[inIndex] 367 | 368 | tbuffer = new Buffer(8 + varSliceSize(output.script)) 369 | toffset = 0 370 | writeUInt64(output.value) 371 | writeVarSlice(output.script) 372 | 373 | hashOutputs = bcrypto.hash256(tbuffer) 374 | } 375 | 376 | tbuffer = new Buffer(156 + varSliceSize(prevOutScript)) 377 | toffset = 0 378 | 379 | var input = this.ins[inIndex] 380 | writeUInt32(this.version) 381 | writeSlice(hashPrevouts) 382 | writeSlice(hashSequence) 383 | writeSlice(input.hash) 384 | writeUInt32(input.index) 385 | writeVarSlice(prevOutScript) 386 | writeUInt64(value) 387 | writeUInt32(input.sequence) 388 | writeSlice(hashOutputs) 389 | writeUInt32(this.locktime) 390 | writeUInt32(hashType) 391 | return bcrypto.hash256(tbuffer) 392 | } 393 | 394 | Transaction.prototype.getHash = function () { 395 | return bcrypto.hash256(this.__toBuffer(undefined, undefined, false)) 396 | } 397 | 398 | Transaction.prototype.getId = function () { 399 | // transaction hash's are displayed in reverse order 400 | return this.getHash().reverse().toString('hex') 401 | } 402 | 403 | Transaction.prototype.toBuffer = function (buffer, initialOffset) { 404 | return this.__toBuffer(buffer, initialOffset, true) 405 | } 406 | 407 | Transaction.prototype.__toBuffer = function (buffer, initialOffset, __allowWitness) { 408 | if (!buffer) buffer = new Buffer(this.__byteLength(__allowWitness)) 409 | 410 | var offset = initialOffset || 0 411 | function writeSlice (slice) { offset += slice.copy(buffer, offset) } 412 | function writeUInt8 (i) { offset = buffer.writeUInt8(i, offset) } 413 | function writeUInt32 (i) { offset = buffer.writeUInt32LE(i, offset) } 414 | function writeInt32 (i) { offset = buffer.writeInt32LE(i, offset) } 415 | function writeUInt64 (i) { offset = bufferutils.writeUInt64LE(buffer, i, offset) } 416 | function writeVarInt (i) { 417 | varuint.encode(i, buffer, offset) 418 | offset += varuint.encode.bytes 419 | } 420 | function writeVarSlice (slice) { writeVarInt(slice.length); writeSlice(slice) } 421 | function writeVector (vector) { writeVarInt(vector.length); vector.forEach(writeVarSlice) } 422 | 423 | writeInt32(this.version) 424 | 425 | var hasWitnesses = __allowWitness && this.hasWitnesses() 426 | 427 | if (hasWitnesses) { 428 | writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER) 429 | writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG) 430 | } 431 | 432 | writeVarInt(this.ins.length) 433 | 434 | this.ins.forEach(function (txIn) { 435 | writeSlice(txIn.hash) 436 | writeUInt32(txIn.index) 437 | writeVarSlice(txIn.script) 438 | writeUInt32(txIn.sequence) 439 | }) 440 | 441 | writeVarInt(this.outs.length) 442 | this.outs.forEach(function (txOut) { 443 | if (!txOut.valueBuffer) { 444 | writeUInt64(txOut.value) 445 | } else { 446 | writeSlice(txOut.valueBuffer) 447 | } 448 | 449 | writeVarSlice(txOut.script) 450 | }) 451 | 452 | if (hasWitnesses) { 453 | this.ins.forEach(function (input) { 454 | writeVector(input.witness) 455 | }) 456 | } 457 | 458 | writeUInt32(this.locktime) 459 | 460 | // avoid slicing unless necessary 461 | if (initialOffset !== undefined) return buffer.slice(initialOffset, offset) 462 | return buffer 463 | } 464 | 465 | Transaction.prototype.toHex = function () { 466 | return this.toBuffer().toString('hex') 467 | } 468 | 469 | Transaction.prototype.setInputScript = function (index, scriptSig) { 470 | typeforce(types.tuple(types.Number, types.Buffer), arguments) 471 | 472 | this.ins[index].script = scriptSig 473 | } 474 | 475 | Transaction.prototype.setWitness = function (index, witness) { 476 | typeforce(types.tuple(types.Number, [types.Buffer]), arguments) 477 | 478 | this.ins[index].witness = witness 479 | } 480 | 481 | module.exports = Transaction 482 | -------------------------------------------------------------------------------- /src/transaction_builder.js: -------------------------------------------------------------------------------- 1 | var baddress = require('./address') 2 | var bcrypto = require('./crypto') 3 | var bscript = require('./script') 4 | var networks = require('./networks') 5 | var ops = require('bitcoin-ops') 6 | var typeforce = require('typeforce') 7 | var types = require('./types') 8 | var scriptTypes = bscript.types 9 | var SIGNABLE = [bscript.types.P2PKH, bscript.types.P2PK, bscript.types.MULTISIG] 10 | var P2SH = SIGNABLE.concat([bscript.types.P2WPKH, bscript.types.P2WSH]) 11 | 12 | var ECPair = require('./ecpair') 13 | var ECSignature = require('./ecsignature') 14 | var Transaction = require('./transaction') 15 | 16 | function extractChunks (type, chunks, script) { 17 | var pubKeys = [] 18 | var signatures = [] 19 | switch (type) { 20 | case scriptTypes.P2PKH: 21 | // if (redeemScript) throw new Error('Nonstandard... P2SH(P2PKH)') 22 | pubKeys = chunks.slice(1) 23 | signatures = chunks.slice(0, 1) 24 | break 25 | 26 | case scriptTypes.P2PK: 27 | pubKeys[0] = script ? bscript.pubKey.output.decode(script) : undefined 28 | signatures = chunks.slice(0, 1) 29 | break 30 | 31 | case scriptTypes.MULTISIG: 32 | if (script) { 33 | var multisig = bscript.multisig.output.decode(script) 34 | pubKeys = multisig.pubKeys 35 | } 36 | 37 | signatures = chunks.slice(1).map(function (chunk) { 38 | return chunk.length === 0 ? undefined : chunk 39 | }) 40 | break 41 | } 42 | 43 | return { 44 | pubKeys: pubKeys, 45 | signatures: signatures 46 | } 47 | } 48 | function expandInput (scriptSig, witnessStack) { 49 | var prevOutScript 50 | var prevOutType 51 | var scriptType 52 | var script 53 | var redeemScript 54 | var witnessScript 55 | var witnessScriptType 56 | var redeemScriptType 57 | var witness = false 58 | var p2wsh = false 59 | var p2sh = false 60 | var witnessProgram 61 | var chunks 62 | 63 | var scriptSigChunks = bscript.decompile(scriptSig) 64 | var sigType = bscript.classifyInput(scriptSigChunks, true) 65 | if (sigType === scriptTypes.P2SH) { 66 | p2sh = true 67 | redeemScript = scriptSigChunks[scriptSigChunks.length - 1] 68 | redeemScriptType = bscript.classifyOutput(redeemScript) 69 | prevOutScript = bscript.scriptHash.output.encode(bcrypto.hash160(redeemScript)) 70 | prevOutType = scriptTypes.P2SH 71 | script = redeemScript 72 | } 73 | 74 | var classifyWitness = bscript.classifyWitness(witnessStack) 75 | if (classifyWitness === scriptTypes.P2WSH) { 76 | witnessScript = witnessStack[witnessStack.length - 1] 77 | witnessScriptType = bscript.classifyOutput(witnessScript) 78 | p2wsh = true 79 | if (scriptSig.length === 0) { 80 | prevOutScript = bscript.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript)) 81 | prevOutType = scriptTypes.P2WSH 82 | if (typeof redeemScript !== 'undefined') { 83 | throw new Error('Redeem script given when unnecessary') 84 | } 85 | // bare witness 86 | } else { 87 | if (!redeemScript) { 88 | throw new Error('No redeemScript provided for P2WSH, but scriptSig non-empty') 89 | } 90 | witnessProgram = bscript.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript)) 91 | if (!redeemScript.equals(witnessProgram)) { 92 | throw new Error('Redeem script didn\'t match witnessScript') 93 | } 94 | } 95 | 96 | if (SIGNABLE.indexOf(bscript.classifyOutput(witnessScript)) === -1) { 97 | throw new Error('unsupported witness script') 98 | } 99 | script = witnessScript 100 | scriptType = witnessScriptType 101 | chunks = witnessStack.slice(0, -1) 102 | } else if (classifyWitness === scriptTypes.P2WPKH) { 103 | var key = witnessStack[witnessStack.length - 1] 104 | var keyHash = bcrypto.hash160(key) 105 | if (scriptSig.length === 0) { 106 | prevOutScript = bscript.witnessPubKeyHash.output.encode(keyHash) 107 | prevOutType = scriptTypes.P2WPKH 108 | if (typeof redeemScript !== 'undefined') { 109 | throw new Error('Redeem script given when unnecessary') 110 | } 111 | } else { 112 | if (!redeemScript) { 113 | throw new Error('No redeemScript provided for P2WPKH, but scriptSig wasn\'t empty') 114 | } 115 | witnessProgram = bscript.witnessPubKeyHash.output.encode(keyHash) 116 | if (!redeemScript.equals(witnessProgram)) { 117 | throw new Error('Redeem script did not have the right witness program') 118 | } 119 | } 120 | 121 | scriptType = scriptTypes.P2PKH 122 | chunks = witnessStack 123 | } else if (redeemScript) { 124 | if (P2SH.indexOf(redeemScriptType) === -1) { 125 | throw new Error('Bad redeemscript!') 126 | } 127 | 128 | script = redeemScript 129 | scriptType = redeemScriptType 130 | chunks = scriptSigChunks.slice(0, -1) 131 | } else { 132 | prevOutType = scriptType = bscript.classifyInput(scriptSig) 133 | chunks = scriptSigChunks 134 | } 135 | 136 | var expanded = extractChunks(scriptType, chunks, script) 137 | 138 | var result = { 139 | pubKeys: expanded.pubKeys, 140 | signatures: expanded.signatures, 141 | prevOutScript: prevOutScript, 142 | prevOutType: prevOutType, 143 | signType: scriptType, 144 | signScript: script, 145 | witness: Boolean(witness) 146 | } 147 | 148 | if (p2sh) { 149 | result.redeemScript = redeemScript 150 | result.redeemScriptType = redeemScriptType 151 | } 152 | 153 | if (p2wsh) { 154 | result.witnessScript = witnessScript 155 | result.witnessScriptType = witnessScriptType 156 | } 157 | 158 | return result 159 | } 160 | 161 | // could be done in expandInput, but requires the original Transaction for hashForSignature 162 | function fixMultisigOrder (input, transaction, vin) { 163 | if (input.redeemScriptType !== scriptTypes.MULTISIG || !input.redeemScript) return 164 | if (input.pubKeys.length === input.signatures.length) return 165 | 166 | var unmatched = input.signatures.concat() 167 | 168 | input.signatures = input.pubKeys.map(function (pubKey) { 169 | var keyPair = ECPair.fromPublicKeyBuffer(pubKey) 170 | var match 171 | 172 | // check for a signature 173 | unmatched.some(function (signature, i) { 174 | // skip if undefined || OP_0 175 | if (!signature) return false 176 | 177 | // TODO: avoid O(n) hashForSignature 178 | var parsed = ECSignature.parseScriptSignature(signature) 179 | var hash = transaction.hashForSignature(vin, input.redeemScript, parsed.hashType) 180 | 181 | // skip if signature does not match pubKey 182 | if (!keyPair.verify(hash, parsed.signature)) return false 183 | 184 | // remove matched signature from unmatched 185 | unmatched[i] = undefined 186 | match = signature 187 | 188 | return true 189 | }) 190 | 191 | return match 192 | }) 193 | } 194 | 195 | function expandOutput (script, scriptType, ourPubKey) { 196 | typeforce(types.Buffer, script) 197 | 198 | var scriptChunks = bscript.decompile(script) 199 | if (!scriptType) { 200 | scriptType = bscript.classifyOutput(script) 201 | } 202 | 203 | var pubKeys = [] 204 | 205 | switch (scriptType) { 206 | // does our hash160(pubKey) match the output scripts? 207 | case scriptTypes.P2PKH: 208 | if (!ourPubKey) break 209 | 210 | var pkh1 = scriptChunks[2] 211 | var pkh2 = bcrypto.hash160(ourPubKey) 212 | if (pkh1.equals(pkh2)) pubKeys = [ourPubKey] 213 | break 214 | 215 | // does our hash160(pubKey) match the output scripts? 216 | case scriptTypes.P2WPKH: 217 | if (!ourPubKey) break 218 | 219 | var wpkh1 = scriptChunks[1] 220 | var wpkh2 = bcrypto.hash160(ourPubKey) 221 | if (wpkh1.equals(wpkh2)) pubKeys = [ourPubKey] 222 | break 223 | 224 | case scriptTypes.P2PK: 225 | pubKeys = scriptChunks.slice(0, 1) 226 | break 227 | 228 | case scriptTypes.MULTISIG: 229 | pubKeys = scriptChunks.slice(1, -2) 230 | break 231 | 232 | default: return { scriptType: scriptType } 233 | } 234 | 235 | return { 236 | pubKeys: pubKeys, 237 | scriptType: scriptType, 238 | signatures: pubKeys.map(function () { return undefined }) 239 | } 240 | } 241 | 242 | function checkP2shInput (input, redeemScriptHash) { 243 | if (input.prevOutType) { 244 | if (input.prevOutType !== scriptTypes.P2SH) throw new Error('PrevOutScript must be P2SH') 245 | 246 | var prevOutScriptScriptHash = bscript.decompile(input.prevOutScript)[1] 247 | if (!prevOutScriptScriptHash.equals(redeemScriptHash)) throw new Error('Inconsistent hash160(RedeemScript)') 248 | } 249 | } 250 | 251 | function checkP2WSHInput (input, witnessScriptHash) { 252 | if (input.prevOutType) { 253 | if (input.prevOutType !== scriptTypes.P2WSH) throw new Error('PrevOutScript must be P2WSH') 254 | 255 | var scriptHash = bscript.decompile(input.prevOutScript)[1] 256 | if (!scriptHash.equals(witnessScriptHash)) throw new Error('Inconsistent sha25(WitnessScript)') 257 | } 258 | } 259 | 260 | function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScript) { 261 | var expanded 262 | var prevOutType 263 | var prevOutScript 264 | 265 | var p2sh = false 266 | var p2shType 267 | var redeemScriptHash 268 | 269 | var witness = false 270 | var p2wsh = false 271 | var witnessType 272 | var witnessScriptHash 273 | 274 | var signType 275 | var signScript 276 | 277 | if (redeemScript && witnessScript) { 278 | redeemScriptHash = bcrypto.hash160(redeemScript) 279 | witnessScriptHash = bcrypto.sha256(witnessScript) 280 | checkP2shInput(input, redeemScriptHash) 281 | 282 | if (!redeemScript.equals(bscript.witnessScriptHash.output.encode(witnessScriptHash))) throw new Error('Witness script inconsistent with redeem script') 283 | 284 | expanded = expandOutput(witnessScript, undefined, kpPubKey) 285 | if (!expanded.pubKeys) throw new Error('WitnessScript not supported "' + bscript.toASM(redeemScript) + '"') 286 | prevOutType = bscript.types.P2SH 287 | prevOutScript = bscript.scriptHash.output.encode(redeemScriptHash) 288 | p2sh = witness = p2wsh = true 289 | p2shType = bscript.types.P2WSH 290 | signType = witnessType = expanded.scriptType 291 | signScript = witnessScript 292 | } else if (redeemScript) { 293 | redeemScriptHash = bcrypto.hash160(redeemScript) 294 | checkP2shInput(input, redeemScriptHash) 295 | 296 | expanded = expandOutput(redeemScript, undefined, kpPubKey) 297 | if (!expanded.pubKeys) throw new Error('RedeemScript not supported "' + bscript.toASM(redeemScript) + '"') 298 | 299 | prevOutType = bscript.types.P2SH 300 | prevOutScript = bscript.scriptHash.output.encode(redeemScriptHash) 301 | p2sh = true 302 | signType = p2shType = expanded.scriptType 303 | signScript = redeemScript 304 | witness = signType === bscript.types.P2WPKH 305 | } else if (witnessScript) { 306 | witnessScriptHash = bcrypto.sha256(witnessScript) 307 | checkP2WSHInput(input, witnessScriptHash) 308 | 309 | expanded = expandOutput(witnessScript, undefined, kpPubKey) 310 | if (!expanded.pubKeys) throw new Error('WitnessScript not supported "' + bscript.toASM(redeemScript) + '"') 311 | 312 | prevOutType = bscript.types.P2WSH 313 | prevOutScript = bscript.witnessScriptHash.output.encode(witnessScriptHash) 314 | witness = p2wsh = true 315 | signType = witnessType = expanded.scriptType 316 | signScript = witnessScript 317 | } else if (input.prevOutType) { 318 | // embedded scripts are not possible without a redeemScript 319 | if (input.prevOutType === scriptTypes.P2SH || 320 | input.prevOutType === scriptTypes.P2WSH) { 321 | throw new Error('PrevOutScript is ' + input.prevOutType + ', requires redeemScript') 322 | } 323 | 324 | prevOutType = input.prevOutType 325 | prevOutScript = input.prevOutScript 326 | expanded = expandOutput(input.prevOutScript, input.prevOutType, kpPubKey) 327 | if (!expanded.pubKeys) return 328 | 329 | witness = (input.prevOutType === scriptTypes.P2WPKH) 330 | signType = prevOutType 331 | signScript = prevOutScript 332 | } else { 333 | prevOutScript = bscript.pubKeyHash.output.encode(bcrypto.hash160(kpPubKey)) 334 | expanded = expandOutput(prevOutScript, scriptTypes.P2PKH, kpPubKey) 335 | prevOutType = scriptTypes.P2PKH 336 | witness = false 337 | signType = prevOutType 338 | signScript = prevOutScript 339 | } 340 | 341 | if (witness && !types.Satoshi(witnessValue)) { 342 | throw new Error('Input was witness but not given witness value') 343 | } 344 | 345 | if (signType === scriptTypes.P2WPKH) { 346 | signScript = bscript.pubKeyHash.output.encode(bscript.witnessPubKeyHash.output.decode(signScript)) 347 | } 348 | 349 | if (p2sh) { 350 | input.redeemScript = redeemScript 351 | input.redeemScriptType = p2shType 352 | } 353 | 354 | if (p2wsh) { 355 | input.witnessScript = witnessScript 356 | input.witnessScriptType = witnessType 357 | } 358 | 359 | input.pubKeys = expanded.pubKeys 360 | input.signatures = expanded.signatures 361 | input.signScript = signScript 362 | input.signType = signType 363 | input.prevOutScript = prevOutScript 364 | input.prevOutType = prevOutType 365 | input.witness = witness 366 | } 367 | 368 | function buildStack (type, signatures, pubKeys, allowIncomplete) { 369 | if (type === scriptTypes.P2PKH) { 370 | if (signatures.length === 1 && signatures[0] instanceof Buffer && pubKeys.length === 1) return bscript.pubKeyHash.input.encodeStack(signatures[0], pubKeys[0]) 371 | } else if (type === scriptTypes.P2PK) { 372 | if (signatures.length === 1 && signatures[0] instanceof Buffer) return bscript.pubKey.input.encodeStack(signatures[0]) 373 | } else if (type === scriptTypes.MULTISIG) { 374 | if (signatures.length > 0) { 375 | signatures = signatures.map(function (signature) { 376 | return signature || ops.OP_0 377 | }) 378 | if (!allowIncomplete) { 379 | // remove blank signatures 380 | signatures = signatures.filter(function (x) { return x !== ops.OP_0 }) 381 | } 382 | 383 | return bscript.multisig.input.encodeStack(signatures /* see if it's necessary first */) 384 | } 385 | } else { 386 | throw new Error('Not yet supported') 387 | } 388 | 389 | if (!allowIncomplete) throw new Error('Not enough signatures provided') 390 | 391 | return [] 392 | } 393 | 394 | function buildInput (input, allowIncomplete) { 395 | var scriptType = input.prevOutType 396 | var sig = [] 397 | var witness = [] 398 | if (SIGNABLE.indexOf(scriptType) !== -1) { 399 | sig = buildStack(scriptType, input.signatures, input.pubKeys, input.script, allowIncomplete) 400 | } 401 | 402 | var p2sh = false 403 | if (scriptType === bscript.types.P2SH) { 404 | // We can remove this error later when we have a guarantee prepareInput 405 | // rejects unsignable scripts - it MUST be signable at this point. 406 | if (P2SH.indexOf(input.redeemScriptType) === -1) { 407 | throw new Error('Impossible to sign this type') 408 | } 409 | p2sh = true 410 | if (SIGNABLE.indexOf(input.redeemScriptType) !== -1) { 411 | sig = buildStack(input.redeemScriptType, input.signatures, input.pubKeys, allowIncomplete) 412 | } 413 | // If it wasn't SIGNABLE, it's witness, defer to that 414 | scriptType = input.redeemScriptType 415 | } 416 | 417 | if (scriptType === bscript.types.P2WPKH) { 418 | // P2WPKH is a special case of P2PKH 419 | witness = buildStack(bscript.types.P2PKH, input.signatures, input.pubKeys, allowIncomplete) 420 | } else if (scriptType === bscript.types.P2WSH) { 421 | // We can remove this check later 422 | if (SIGNABLE.indexOf(input.witnessScriptType) !== -1) { 423 | witness = buildStack(input.witnessScriptType, input.signatures, input.pubKeys, allowIncomplete) 424 | witness.push(input.witnessScript) 425 | } else { 426 | // We can remove this error later when we have a guarantee prepareInput 427 | // rejects unsignble scripts - it MUST be signable at this point. 428 | throw new Error() 429 | } 430 | 431 | scriptType = input.witnessScriptType 432 | } 433 | 434 | // append redeemScript if necessary 435 | if (p2sh) { 436 | sig.push(input.redeemScript) 437 | } 438 | 439 | return { 440 | type: scriptType, 441 | script: bscript.compile(sig), 442 | witness: witness 443 | } 444 | } 445 | 446 | function TransactionBuilder (network, maximumFeeRate) { 447 | this.prevTxMap = {} 448 | this.network = network || networks.bitcoin 449 | 450 | // WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth) 451 | this.maximumFeeRate = maximumFeeRate || 1000 452 | 453 | this.inputs = [] 454 | this.tx = new Transaction() 455 | } 456 | 457 | TransactionBuilder.prototype.setLockTime = function (locktime) { 458 | typeforce(types.UInt32, locktime) 459 | 460 | // if any signatures exist, throw 461 | if (this.inputs.some(function (input) { 462 | if (!input.signatures) return false 463 | 464 | return input.signatures.some(function (s) { return s }) 465 | })) { 466 | throw new Error('No, this would invalidate signatures') 467 | } 468 | 469 | this.tx.locktime = locktime 470 | } 471 | 472 | TransactionBuilder.prototype.setVersion = function (version) { 473 | typeforce(types.UInt32, version) 474 | 475 | // XXX: this might eventually become more complex depending on what the versions represent 476 | this.tx.version = version 477 | } 478 | 479 | TransactionBuilder.fromTransaction = function (transaction, network) { 480 | var txb = new TransactionBuilder(network) 481 | 482 | // Copy transaction fields 483 | txb.setVersion(transaction.version) 484 | txb.setLockTime(transaction.locktime) 485 | 486 | // Copy outputs (done first to avoid signature invalidation) 487 | transaction.outs.forEach(function (txOut) { 488 | txb.addOutput(txOut.script, txOut.value) 489 | }) 490 | 491 | // Copy inputs 492 | transaction.ins.forEach(function (txIn) { 493 | txb.__addInputUnsafe(txIn.hash, txIn.index, { 494 | sequence: txIn.sequence, 495 | script: txIn.script, 496 | witness: txIn.witness 497 | }) 498 | }) 499 | 500 | // fix some things not possible through the public API 501 | txb.inputs.forEach(function (input, i) { 502 | fixMultisigOrder(input, transaction, i) 503 | }) 504 | 505 | return txb 506 | } 507 | 508 | TransactionBuilder.prototype.addInput = function (txHash, vout, sequence, prevOutScript) { 509 | if (!this.__canModifyInputs()) { 510 | throw new Error('No, this would invalidate signatures') 511 | } 512 | 513 | var value 514 | 515 | // is it a hex string? 516 | if (typeof txHash === 'string') { 517 | // transaction hashs's are displayed in reverse order, un-reverse it 518 | txHash = new Buffer(txHash, 'hex').reverse() 519 | 520 | // is it a Transaction object? 521 | } else if (txHash instanceof Transaction) { 522 | var txOut = txHash.outs[vout] 523 | prevOutScript = txOut.script 524 | value = txOut.value 525 | 526 | txHash = txHash.getHash() 527 | } 528 | 529 | return this.__addInputUnsafe(txHash, vout, { 530 | sequence: sequence, 531 | prevOutScript: prevOutScript, 532 | value: value 533 | }) 534 | } 535 | 536 | TransactionBuilder.prototype.__addInputUnsafe = function (txHash, vout, options) { 537 | if (Transaction.isCoinbaseHash(txHash)) { 538 | throw new Error('coinbase inputs not supported') 539 | } 540 | 541 | var prevTxOut = txHash.toString('hex') + ':' + vout 542 | if (this.prevTxMap[prevTxOut] !== undefined) throw new Error('Duplicate TxOut: ' + prevTxOut) 543 | 544 | var input = {} 545 | 546 | // derive what we can from the scriptSig 547 | if (options.script !== undefined) { 548 | input = expandInput(options.script, options.witness) 549 | } 550 | 551 | // if an input value was given, retain it 552 | if (options.value !== undefined) { 553 | input.value = options.value 554 | } 555 | 556 | // derive what we can from the previous transactions output script 557 | if (!input.prevOutScript && options.prevOutScript) { 558 | var prevOutType 559 | 560 | if (!input.pubKeys && !input.signatures) { 561 | var expanded = expandOutput(options.prevOutScript) 562 | 563 | if (expanded.pubKeys) { 564 | input.pubKeys = expanded.pubKeys 565 | input.signatures = expanded.signatures 566 | } 567 | 568 | prevOutType = expanded.scriptType 569 | } 570 | 571 | input.prevOutScript = options.prevOutScript 572 | input.prevOutType = prevOutType || bscript.classifyOutput(options.prevOutScript) 573 | } 574 | 575 | var vin = this.tx.addInput(txHash, vout, options.sequence, options.scriptSig) 576 | this.inputs[vin] = input 577 | this.prevTxMap[prevTxOut] = vin 578 | 579 | return vin 580 | } 581 | 582 | TransactionBuilder.prototype.addOutput = function (scriptPubKey, value) { 583 | if (!this.__canModifyOutputs()) { 584 | throw new Error('No, this would invalidate signatures') 585 | } 586 | 587 | // Attempt to get a script if it's a base58 address string 588 | if (typeof scriptPubKey === 'string') { 589 | scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network) 590 | } 591 | 592 | return this.tx.addOutput(scriptPubKey, value) 593 | } 594 | 595 | TransactionBuilder.prototype.build = function () { 596 | return this.__build(false) 597 | } 598 | TransactionBuilder.prototype.buildIncomplete = function () { 599 | return this.__build(true) 600 | } 601 | 602 | TransactionBuilder.prototype.__build = function (allowIncomplete) { 603 | if (!allowIncomplete) { 604 | if (!this.tx.ins.length) throw new Error('Transaction has no inputs') 605 | if (!this.tx.outs.length) throw new Error('Transaction has no outputs') 606 | } 607 | 608 | var tx = this.tx.clone() 609 | // Create script signatures from inputs 610 | this.inputs.forEach(function (input, i) { 611 | var scriptType = input.witnessScriptType || input.redeemScriptType || input.prevOutType 612 | if (!scriptType && !allowIncomplete) throw new Error('Transaction is not complete') 613 | var result = buildInput(input, allowIncomplete) 614 | 615 | // skip if no result 616 | if (!allowIncomplete) { 617 | if (SIGNABLE.indexOf(result.type) === -1 && result.type !== bscript.types.P2WPKH) { 618 | throw new Error(result.type + ' not supported') 619 | } 620 | } 621 | 622 | tx.setInputScript(i, result.script) 623 | tx.setWitness(i, result.witness) 624 | }) 625 | 626 | if (!allowIncomplete) { 627 | // do not rely on this, its merely a last resort 628 | if (this.__overMaximumFees(tx.byteLength())) { 629 | throw new Error('Transaction has absurd fees') 630 | } 631 | } 632 | 633 | return tx 634 | } 635 | 636 | function canSign (input) { 637 | return input.prevOutScript !== undefined && 638 | input.signScript !== undefined && 639 | input.pubKeys !== undefined && 640 | input.signatures !== undefined && 641 | input.signatures.length === input.pubKeys.length && 642 | input.pubKeys.length > 0 && 643 | input.witness !== undefined 644 | } 645 | 646 | TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashType, witnessValue, witnessScript) { 647 | if (keyPair.network !== this.network) throw new Error('Inconsistent network') 648 | if (!this.inputs[vin]) throw new Error('No input at index: ' + vin) 649 | hashType = hashType || Transaction.SIGHASH_ALL 650 | 651 | var input = this.inputs[vin] 652 | 653 | // if redeemScript was previously provided, enforce consistency 654 | if (input.redeemScript !== undefined && 655 | redeemScript && 656 | !input.redeemScript.equals(redeemScript)) { 657 | throw new Error('Inconsistent redeemScript') 658 | } 659 | 660 | var kpPubKey = keyPair.getPublicKeyBuffer() 661 | if (!canSign(input)) { 662 | prepareInput(input, kpPubKey, redeemScript, witnessValue, witnessScript) 663 | if (!canSign(input)) throw Error(input.prevOutType + ' not supported') 664 | } 665 | 666 | // ready to sign 667 | var signatureHash 668 | if (input.witness) { 669 | signatureHash = this.tx.hashForWitnessV0(vin, input.signScript, witnessValue, hashType) 670 | } else { 671 | signatureHash = this.tx.hashForSignature(vin, input.signScript, hashType) 672 | } 673 | // enforce in order signing of public keys 674 | var signed = input.pubKeys.some(function (pubKey, i) { 675 | if (!kpPubKey.equals(pubKey)) return false 676 | if (input.signatures[i]) throw new Error('Signature already exists') 677 | 678 | input.signatures[i] = keyPair.sign(signatureHash).toScriptSignature(hashType) 679 | return true 680 | }) 681 | 682 | if (!signed) throw new Error('Key pair cannot sign for this input') 683 | } 684 | 685 | function signatureHashType (buffer) { 686 | return buffer.readUInt8(buffer.length - 1) 687 | } 688 | 689 | TransactionBuilder.prototype.__canModifyInputs = function () { 690 | return this.inputs.every(function (input) { 691 | // any signatures? 692 | if (input.signatures === undefined) return true 693 | 694 | return input.signatures.every(function (signature) { 695 | if (!signature) return true 696 | var hashType = signatureHashType(signature) 697 | 698 | // if SIGHASH_ANYONECANPAY is set, signatures would not 699 | // be invalidated by more inputs 700 | return hashType & Transaction.SIGHASH_ANYONECANPAY 701 | }) 702 | }) 703 | } 704 | 705 | TransactionBuilder.prototype.__canModifyOutputs = function () { 706 | var nInputs = this.tx.ins.length 707 | var nOutputs = this.tx.outs.length 708 | 709 | return this.inputs.every(function (input) { 710 | if (input.signatures === undefined) return true 711 | 712 | return input.signatures.every(function (signature) { 713 | if (!signature) return true 714 | var hashType = signatureHashType(signature) 715 | 716 | var hashTypeMod = hashType & 0x1f 717 | if (hashTypeMod === Transaction.SIGHASH_NONE) return true 718 | if (hashTypeMod === Transaction.SIGHASH_SINGLE) { 719 | // if SIGHASH_SINGLE is set, and nInputs > nOutputs 720 | // some signatures would be invalidated by the addition 721 | // of more outputs 722 | return nInputs <= nOutputs 723 | } 724 | }) 725 | }) 726 | } 727 | 728 | TransactionBuilder.prototype.__overMaximumFees = function (bytes) { 729 | // not all inputs will have .value defined 730 | var incoming = this.inputs.reduce(function (a, x) { return a + (x.value >>> 0) }, 0) 731 | 732 | // but all outputs do, and if we have any input value 733 | // we can immediately determine if the outputs are too small 734 | var outgoing = this.tx.outs.reduce(function (a, x) { return a + x.value }, 0) 735 | var fee = incoming - outgoing 736 | var feeRate = fee / bytes 737 | 738 | return feeRate > this.maximumFeeRate 739 | } 740 | 741 | module.exports = TransactionBuilder 742 | -------------------------------------------------------------------------------- /src/types.js: -------------------------------------------------------------------------------- 1 | var typeforce = require('typeforce') 2 | 3 | var UINT31_MAX = Math.pow(2, 31) - 1 4 | function UInt31 (value) { 5 | return typeforce.UInt32(value) && value <= UINT31_MAX 6 | } 7 | 8 | function BIP32Path (value) { 9 | return typeforce.String(value) && value.match(/^(m\/)?(\d+'?\/)*\d+'?$/) 10 | } 11 | BIP32Path.toJSON = function () { return 'BIP32 derivation path' } 12 | 13 | var SATOSHI_MAX = 21 * 1e14 14 | function Satoshi (value) { 15 | return typeforce.UInt53(value) && value <= SATOSHI_MAX 16 | } 17 | 18 | // external dependent types 19 | var BigInt = typeforce.quacksLike('BigInteger') 20 | var ECPoint = typeforce.quacksLike('Point') 21 | 22 | // exposed, external API 23 | var ECSignature = typeforce.compile({ r: BigInt, s: BigInt }) 24 | var 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 | 35 | // extend typeforce types with ours 36 | var types = { 37 | BigInt: BigInt, 38 | BIP32Path: BIP32Path, 39 | Buffer256bit: typeforce.BufferN(32), 40 | ECPoint: ECPoint, 41 | ECSignature: ECSignature, 42 | Hash160bit: typeforce.BufferN(20), 43 | Hash256bit: typeforce.BufferN(32), 44 | Network: Network, 45 | Satoshi: Satoshi, 46 | UInt31: UInt31 47 | } 48 | 49 | for (var typeName in typeforce) { 50 | types[typeName] = typeforce[typeName] 51 | } 52 | 53 | module.exports = types 54 | --------------------------------------------------------------------------------