diff --git a/.github/workflows/main_ci.yml b/.github/workflows/main_ci.yml
deleted file mode 100644
index 7bc62cb..0000000
--- a/.github/workflows/main_ci.yml
+++ /dev/null
@@ -1,94 +0,0 @@
-name: Run Tests
-
-on:
-  push:
-    branches:
-      - master
-  pull_request:
-
-jobs:
-  audit:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-node@v1
-        with:
-          node-version: 12
-          registry-url: https://registry.npmjs.org/
-      - run: npm ci
-      - run: npm run audit
-  unit:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-node@v1
-        with:
-          node-version: 12
-          registry-url: https://registry.npmjs.org/
-      - run: npm ci
-      - run: npm run unit
-  coverage:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-node@v1
-        with:
-          node-version: 12
-          registry-url: https://registry.npmjs.org/
-      - run: npm ci
-      - run: npm run coverage
-  integration:
-    runs-on: ubuntu-latest
-    services:
-      regtest:
-        image: junderw/bitcoinjs-regtest-server@sha256:5b69cf95d9edf6d5b3a00504665d6b3c382a6aa3728fe8ce897974c519061463
-        ports:
-          - 8080:8080
-    steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-node@v1
-        with:
-          node-version: 12
-          registry-url: https://registry.npmjs.org/
-      - run: npm ci
-      - run: APIURL=http://127.0.0.1:8080/1 npm run integration
-  format:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-node@v1
-        with:
-          node-version: 12
-          registry-url: https://registry.npmjs.org/
-      - run: npm ci
-      - run: npm run format:ci
-  gitdiff:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-node@v1
-        with:
-          node-version: 12
-          registry-url: https://registry.npmjs.org/
-      - run: npm ci
-      - run: npm run gitdiff:ci
-  lint:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-node@v1
-        with:
-          node-version: 12
-          registry-url: https://registry.npmjs.org/
-      - run: npm ci
-      - run: npm run lint
-  lint-tests:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-node@v1
-        with:
-          node-version: 12
-          registry-url: https://registry.npmjs.org/
-      - run: npm ci
-      - run: npm run lint:tests
diff --git a/.gitignore b/.gitignore
index d6ceb6b..a6c0ab8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,3 @@ coverage
 node_modules
 .nyc_output
 npm-debug.log
-test/*.js
-test/integration/*.js
-!test/ts-node-register.js
diff --git a/.npm-audit-whitelister.json b/.npm-audit-whitelister.json
deleted file mode 100644
index fe51488..0000000
--- a/.npm-audit-whitelister.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
diff --git a/.prettierignore b/.prettierignore
deleted file mode 100644
index e69de29..0000000
diff --git a/.prettierrc.json b/.prettierrc.json
deleted file mode 100644
index a20502b..0000000
--- a/.prettierrc.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "singleQuote": true,
-  "trailingComma": "all"
-}
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..390acdc
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,18 @@
+sudo: false
+language: node_js
+node_js:
+  - "4"
+  - "5"
+  - "6"
+  - "7"
+  - "8"
+matrix:
+  include:
+    - node_js: "7"
+      env: TEST_SUITE=standard
+    - node_js: "7"
+      env: TEST_SUITE=coverage
+env:
+  - TEST_SUITE=integration
+  - TEST_SUITE=unit
+script: npm run-script $TEST_SUITE
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f7d8f91..0bd846c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,190 +1,3 @@
-# 6.0.0
-__removed__
-- bip32: Removed the re-export. Please add as dependency to your app instead.
-- ECPair: Please use bip32 moving forward. ecpair package was created for those who need it.
-- TransactionBuilder: Any internal files used only in TB (classify, templates, etc.) were also removed.
-
-__added__
-- taproot segwit v1 address support (bech32m) via address module (#1676)
-- hashForWitnessV1 method on Transaction class (#1745)
-
-__fixed__
-- Transaction version read/write differed. (#1717)
-
-# 5.2.0
-__changed__
-- Updated PSBT to allow for witnessUtxo and nonWitnessUtxo simultaneously (Re: segwit psbt bug) (#1563)
-
-__added__
-- PSBT methods `getInputType`, `inputHasPubkey`, `inputHasHDKey`, `outputHasPubkey`, `outputHasHDKey` (#1563)
-
-# 5.1.10
-__fixed__
-- Fixed psbt.signInputAsync (and consequentially all Async signing methods) not handling rejection of keypair.sign properly (#1582)
-
-# 5.1.9
-__fixed__
-- Fixed errors for psbt.txOutputs getter (#1578)
-
-# 5.1.8
-__fixed__
-- Throw errors when p2wsh or p2wpkh contain uncompressed pubkeys (#1573)
-
-__added__
-- Add txInputs and txOutputs for Psbt (#1561)
-
-__changed__
-- (Not exposed) Added BufferWriter to help ease maintenance of certain forks of this library (#1533)
-
-# 5.1.7
-__fixed__
-- Fixed Transaction class Output interface typing for TypeScript (#1506)
-- Add `weight()` to Block class, add optional includeWitness arg to Transaction byteLength method (#1515)
-- Match the old TransactionBuilder behavior of allowing for multiple instances of the same pubkey to be in a p2ms script for PSBT (#1519)
-
-__added__
-- Allow the API consumer to pass in the finalizer functions to allow for any type of transaction to be finalized. It places the most crucial part of transaction construction on the consumer, and should be used with caution. (#1491)
-
-# 5.1.6
-__fixed__
-- `PsbtOutputExtended` did not support using the address attribute properly. It is now fixed.
-
-# 5.1.5
-__added__
-- `Psbt` now has `getFee(): number` for use when all inputs are finalized. It returns the satoshi fee of the transaction. Calling getFee, getFeeRate, or extractTransaction will cache these values so if you call one after the other, the second call will return immediately.
-
-# 5.1.4
-__changed__
-- `Psbt` inputs using segwit scripts can now work with nonWitnessUtxo as well as the original witnessUtxo. The reasoning for this is that nonWitnessUtxo has all the information contained in the witnessUtxo, so rejecting signing even though we have all the info we need is unnecessary. Trying to sign a non-segwit script with a witnessUtxo will still throw an Error as it should.
-
-# 5.1.3
-__changed__
-- TypeScript types: Made Signer and SignerAsync use any for network since we only check for equivalence. (#1448)
-- TypeScript types: Made the args for addInput and addOutput for Psbt actually accept updateInput and updateOutput parameters. (#1449)
-
-# 5.1.2
-__added__
-- `ECPair` and `bip32` objects now have a lowR boolean attribute defaulted to false. You may set it to true to ensure that the sign method uses low R values (#1442) (This is to enable low R usage in Psbt, since we decided not to give the low R flag to the Psbt class, since it makes more sense to be an attribute of the Signer interface)
-
-# 5.1.1
-__changed__
-- Name inconsistencies for Psbt class. (Quick fix)
-
-# 5.1.0
-__added__
-- A new `Psbt` class for creating, distributing, combining, signing, and compiling Transactions (#1425)
-- A `name` attribute to the Payment interface. P2SH and P2WSH are nested with `'-'` as separator, and p2ms is in the format of `'p2ms(m of n)''` all others are just hard coded. (#1433)
-
-__changed__
-- `TransactionBuilder`: Migrate to stricter type checks during sign by switching to a single object parameter (#1416)
-- `tests`: Use regtest-client as separate library (#1421)
-
-# 5.0.5
-__added__
-- Added `ECPairInterface` `Stack` and `StackElement` interfaces to the main index.ts export (TypeScript only affected)
-
-# 5.0.4
-__added__
-- low R value support for ECPair, bip32, and TransactionBuilder (default off) via `txb.setLowR()` (#1385)
-
-__fixed__
-- Fixed Various TypeScript types that have been pushed out since v5.0.0 (#1388)
-
-# 5.0.0
-__added__
-- TypeScript support (#1319)
-- `Block.prototype.checkTxRoots` will check the merkleRoot and witnessCommit if it exists against the transactions array. (e52abec) (0426c66)
-
-__changed__
-- `Transaction.prototype.getHash` now has `forWitness?: boolean` which when true returns the hash for wtxid (a652d04)
-- `Block.calculateMerkleRoot` now has `forWitness?: boolean` which when true returns the witness commit (a652d04)
-
-__removed__
-- `Block.prototype.checkMerkleRoot` was removed, please use `checkTxRoots` (0426c66)
-
-# 4.0.5
-__fixed__
-- Fixed bug where Angular apps break due to lack of crypto at build time. Reverted #1373 and added (6bead5d).
-
-# 4.0.4
-__fixed__
-- Fixed bug where Electron v4 breaks due to lack of `'rmd160'` alias for ripemd160 hash. (#1373)
-
-# 4.0.3
-__fixed__
-- Fixed `TransactionBuilder` to require that the Transaction has outputs before signing (#1151)
-- Fixed `payments.p2sh`, which now takes the network from the redeem attribute if one is not given in the object argument (#1232)
-- Fixed `Block.calculateTarget` to allow for exponents up to 29 (#1285)
-- Fixed some low priority rarely occurring bugs with multisig payments and `TransactionBuilder` multisig processing (#1307)
-
-__added__
-- Regtest network object to `networks` (#1261)
-
-# 4.0.2
-__fixed__
-- Fixed `TransactionBuilder` not throwing when payment type validation should fail (#1195)
-
-__removed__
-- Removed rogue `package.json` from `src/payments` (#1216)
-
-# 4.0.1
-__fixed__
-- Fixed `tiny-secp256k1` dependency version (used `ecurve`) (#1139)
-- Fixed `TransactionBuilder` throwing when trying to sign `P2WSH(P2WPKH)` (#1135)
-
-# 4.0.0
-__added__
-- Added [`bip32`](https://github.com/bitcoinjs/bip32) dependency as a primary export (#1073)
-- Added `ECPair.fromPrivateKey` (#1070)
-- Added `payments` export, with support for `p2pkh`, `p2pk`, `p2ms`, `p2sh`, `p2wpkh`, `p2wsh` and `embed` payment types (#1096, #1119)
-- Added `script.signature.encode/decode` for script signatures (#459)
-
-__changed__
-- `ECPair.prototype.sign` now returns a 64-byte signature `Buffer`, not an `ECSignature` object (#1084)
-- `ECPair` (and all ECDSA code) now uses [`tiny-secp256k1`](https://github.com/bitcoinjs/tiny-secp256k1), which uses the [`libsecp256k1` library](https://github.com/bitcoin-core/secp256k1) (#1070)
-- `TransactionBuilder` internal variables are now `__` prefixed to discourage public usage (#1038)
-- `TransactionBuilder` now defaults to version 2 transaction versions (#1036)
-- `script.decompile` now returns `[Buffer]` or `null`, if decompilation failed (#1039)
-
-__fixed__
-- Fixed `TransactionBuilder` rejecting uncompressed public keys to comply with BIP143 (#987)
-
-__removed__
-- Removed Node 4/5 LTS support (#1080)
-- Removed `ECPair.fromPublicKeyBuffer`, use `ECPair.fromPublicKey` (#1070)
-- Removed `ECPair.prototype.getAddress`, use `payments.p2pkh` instead (#1085)
-- Removed `ECPair.prototype.getPrivateKey`, use `ECPair.prototype.privateKey` property (#1070)
-- Removed `ECPair.prototype.getPublicKey`, use `ECPair.prototype.publicKey` property (#1070)
-- Removed `ECPair.prototype.getNetwork`, use `ECPair.prototype.network` property (#1070)
-- Removed `ECSignature`, use `script.signature.encode/decode` instead (#459)
-- Removed `HDNode`, use `bip32` export instead (#1073)
-- Removed `bufferutils` (#1035)
-- Removed `networks.litecoin`, BYO non-Bitcoin networks instead (#1095)
-- Removed `script.isCanonicalSignature`, use `script.isCanonicalScriptSignature` instead (#1094)
-- Removed `script.*.input/output/check` functions (`templates`), use `payments.*` instead (`templates` previously added in #681, #682) (#1119)
-- Removed dependency `bigi`, uses `bn.js` internally now (via `tiny-secp256k1`) (#1070, #1112)
-- Removed public access to `ECPair` constructor, use exported functions `ECPair.fromPrivateKey`, `ECPair.fromWIF`, `ECPair.makeRandom`, or `ECPair.fromPublicKey` (#1070)
-
-# 3.3.2
-__fixed__
-- Fixed `decodeStack` arbitrarily supporting non-Array arguments (#942)
-
-# 3.3.1
-__changed__
-- Increased the `TransactionBuilder` `maximumFeeRate` from 1000 to 2500 satoshis/byte. (#931)
-
-# 3.3.0
-__added__
-- Added `ECSignature.prototype.toRSBuffer`/`ECSignature.fromRSBuffer` (#915)
-- Added support to `TransactionBuilder` for 64-byte signatures via `.sign` (#915)
-- Added support to `TransactionBuilder` for the `.publicKey` standard as an alternative to `.getPublicKey()` (#915)
-
-# 3.2.1
-__fixed__
-- Fixed `script.scripthash.input.check` recursion (#898)
-- Fixed `TransactionBuilder` sometimes ignoring witness value (#901)
-- Fixed `script.witnessScriptHash.input` implementation (previously used the P2SH impl.) (#911)
-
 # 3.2.0
 __added__
 - Added `address.fromBech32/toBech32` (#846)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index 2c72633..0000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,83 +0,0 @@
-
-[//]: # (This is partially derived from https://github.com/bitcoin/bitcoin/blob/6579d80572d2d33aceabbd3db45a6a9f809aa5e3/CONTRIBUTING.md)
-
-# Contributing to bitcoinjs-lib
-Firstly in terms of structure, there is no particular concept of "bitcoinjs developers" in a sense of privileged people.
-Open source revolves around a meritocracy where contributors who help gain trust from the community.
-
-For practical purpose, there are repository "maintainers" who are responsible for merging pull requests.
-
-We are always accepting of pull requests, but we do adhere to specific standards in regards to coding style, test driven development and commit messages.
-
-
-## Communication Channels
-GitHub is the preferred method of communication between members.
-
-Otherwise, in order of preference:
-* bitcoinjs.slack.com
-* #bitcoinjs-dev on Freenode IRC
-
-
-## Workflow
-The codebase is maintained using the "contributor workflow" where everyone without exception contributes patch proposals using "pull requests".
-This facilitates social contribution, easy testing and peer review.
-
-To contribute a patch, the workflow is as follows:
-
-  1. Fork repository
-  1. Create topic branch
-  1. Commit patches
-  1. Push changes to your fork
-  1. Submit a pull request to https://github.com/bitcoinjs/bitcoinjs-lib
-
-[Commits should be atomic](https://en.wikipedia.org/wiki/Atomic_commit#Atomic_commit_convention) and diffs easy to read.
-
-If your pull request is accepted for merging, you may be asked by a maintainer to squash and or [rebase](https://git-scm.com/docs/git-rebase) your commits before it is merged.
-
-Please refrain from creating several pull requests for the same change.
-
-Patchsets should be focused:
-
-	* Adding a feature, or
-	* Fixing a bug, or
-	* Refactoring code.
-
-If you combine these, the PR may be rejected or asked to be split up.
-
-The length of time required for peer review is unpredictable and will vary from pull request to pull request.
-
-Refer to the [Git manual](https://git-scm.com/doc) for any information about `git`.
-
-
-## Regarding TypeScript
-This library is written in TypeScript with tslint, prettier, and the tsc transpiler. These tools will help during testing to notice improper logic before committing and sending a pull request.
-
-Some rules regarding TypeScript:
-
-* Modify the typescript source code in an IDE that will give you warnings for transpile/lint errors.
-* Once you are done with the modifications, run `npm run format` then `npm test`
-* Running the tests will transpile the ts files into js and d.ts files.
-* Use `git diff` or other tools to verify that the ts and js are changing the same parts.
-* Commit all changes to ts, js, and d.ts files.
-* Add tests where necessary.
-* Submit your pull request.
-
-Using TypeScript is for preventing bugs while writing code, as well as automatically generating type definitions. However, the JS file diffs must be verified, and any unverified JS will not be published to npm.
-
-
-## We adhere to Bitcoin-Core policy
-Bitcoin script payment/script templates are based on community consensus,  but typically adhere to bitcoin-core node policy by default.
-
-- `bitcoinjs.script.decompile` is consensus bound only,  it does not reject based on policy.
-- `bitcoinjs.script.compile` will try to adhere to bitcoin-core `IsStandard` policies rules. (eg. minimalpush in https://github.com/bitcoinjs/bitcoinjs-lib/pull/638)
-
-Any elliptic curve `sign` operations should adhere to `IsStandard` policies, like `LOW_S`, but `verify` should not reject them [by default].
-
-If you need non-standard rejecting `decoding`, you should use an external module,  not this library.
-
-#### TLDR
-Where "standards compliant" refers to the default policies of bitcoin-core,  we adhere to the following:
-- Any "creation" event must create standards-compliant data (standards bound)
-- Any "validation" event must allow for non-standards compliant data (consensus bound)
-
-For stricter validation,  use an external module which we [may have] provided.
diff --git a/LICENSE b/LICENSE
index 0383ebc..fadd21b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2011-2020 bitcoinjs-lib contributors
+Copyright (c) 2011-2018 bitcoinjs-lib contributors
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 9389a73..4105a60 100644
--- a/README.md
+++ b/README.md
@@ -1,139 +1,173 @@
 # BitcoinJS (bitcoinjs-lib)
-[![Github CI](https://github.com/bitcoinjs/bitcoinjs-lib/actions/workflows/main_ci.yml/badge.svg)](https://github.com/bitcoinjs/bitcoinjs-lib/actions/workflows/main_ci.yml) [![NPM](https://img.shields.io/npm/v/bitcoinjs-lib.svg)](https://www.npmjs.org/package/bitcoinjs-lib) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
+[![Build Status](https://travis-ci.org/bitcoinjs/bitcoinjs-lib.png?branch=master)](https://travis-ci.org/bitcoinjs/bitcoinjs-lib)
+[![NPM](https://img.shields.io/npm/v/bitcoinjs-lib.svg)](https://www.npmjs.org/package/bitcoinjs-lib)
+[![tip for next commit](https://tip4commit.com/projects/735.svg)](http://tip4commit.com/projects/735)
 
-A javascript Bitcoin library for node.js and browsers. Written in TypeScript, but committing the JS files to verify.
+[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard)
+
+The pure JavaScript Bitcoin library for node.js and browsers.
+Estimated to be in use by over 15 million wallet users and is the backbone for almost all Bitcoin web wallets in production today.
+
+
+## Features
+- Clean: Pure JavaScript, concise code, easy to read.
+- Tested: Coverage > 90%, third-party integration tests.
+- Careful: Two person approval process for small, focused pull requests.
+- Compatible: Works on Node.js and all modern browsers.
+- Powerful: Support for advanced features, such as multi-sig, HD Wallets.
+- Secure: Strong random number generation, PGP signed releases, trusted developers.
+- Principled: No support for browsers with crap RNG (IE < 11)
+- Standardized: Node community coding style, Browserify, Node's stdlib and Buffers.
+- Fast: Optimized code, uses typed arrays instead of byte arrays for performance.
+- Experiment-friendly: Bitcoin Mainnet and Testnet support.
+- Altcoin-ready: Capable of working with bitcoin-derived cryptocurrencies (such as Dogecoin).
 
-Released under the terms of the [MIT LICENSE](LICENSE).
 
 ## Should I use this in production?
-If you are thinking of using the *master* branch of this library in production, **stop**.
+If you are thinking of using the master branch of this library in production, **stop**.
 Master is not stable; it is our development branch, and [only tagged releases may be classified as stable](https://github.com/bitcoinjs/bitcoinjs-lib/tags).
 
 
-## Can I trust this code?
-> Don't trust. Verify.
-
-We recommend every user of this library and the [bitcoinjs](https://github.com/bitcoinjs) ecosystem audit and verify any underlying code for its validity and suitability,  including reviewing any and all of your project's dependencies.
-
-Mistakes and bugs happen, but with your help in resolving and reporting [issues](https://github.com/bitcoinjs/bitcoinjs-lib/issues), together we can produce open source software that is:
-
-- Easy to audit and verify,
-- Tested, with test coverage >95%,
-- Advanced and feature rich,
-- Standardized, using [prettier](https://github.com/prettier/prettier) and Node `Buffer`'s throughout, and
-- Friendly, with a strong and helpful community, ready to answer questions.
-
-
-## Documentation
-Presently,  we do not have any formal documentation other than our [examples](#examples), please [ask for help](https://github.com/bitcoinjs/bitcoinjs-lib/issues/new) if our examples aren't enough to guide you.
-
-You can find a [Web UI](https://bitcoincore.tech/apps/bitcoinjs-ui/index.html) that covers most of the `psbt.ts`, `transaction.ts` and `p2*.ts` APIs [here](https://bitcoincore.tech/apps/bitcoinjs-ui/index.html).
-
 ## Installation
 ``` bash
 npm install bitcoinjs-lib
-# optionally, install a key derivation library as well
-npm install ecpair bip32
-# ecpair is the ECPair class for single keys
-# bip32 is for generating HD keys
 ```
 
-Previous versions of the library included classes for key management (ECPair, HDNode(->"bip32")) but now these have been separated into different libraries. This lowers the bundle size significantly if you don't need to perform any crypto functions (converting private to public keys and deriving HD keys).
-
-Typically we support the [Node Maintenance LTS version](https://github.com/nodejs/Release). TypeScript target will be set
-to the ECMAScript version in which all features are fully supported by current Active Node LTS.
-However, depending on adoption among other environments (browsers etc.) we may keep the target back a year or two.
-If in doubt, see the [main_ci.yml](.github/workflows/main_ci.yml) for what versions are used by our continuous integration tests.
-
-**WARNING**: We presently don't provide any tooling to verify that the release on `npm` matches GitHub.  As such, you should verify anything downloaded by `npm` against your own verified copy.
-
-
-## Usage
-Crypto is hard.
-
-When working with private keys, the random number generator is fundamentally one of the most important parts of any software you write.
-For random number generation, we *default* to the [`randombytes`](https://github.com/crypto-browserify/randombytes) module, which uses [`window.crypto.getRandomValues`](https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues) in the browser, or Node js' [`crypto.randomBytes`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback), depending on your build system.
-Although this default is ~OK, there is no simple way to detect if the underlying RNG provided is good enough, or if it is **catastrophically bad**.
-You should always verify this yourself to your own standards.
-
-This library uses [tiny-secp256k1](https://github.com/bitcoinjs/tiny-secp256k1), which uses [RFC6979](https://tools.ietf.org/html/rfc6979) to help prevent `k` re-use and exploitation.
-Unfortunately, this isn't a silver bullet.
-Often, Javascript itself is working against us by bypassing these counter-measures.
-
-Problems in [`Buffer (UInt8Array)`](https://github.com/feross/buffer), for example, can trivially result in **catastrophic fund loss** without any warning.
-It can do this through undermining your random number generation, accidentally producing a [duplicate `k` value](https://www.nilsschneider.net/2013/01/28/recovering-bitcoin-private-keys.html), sending Bitcoin to a malformed output script, or any of a million different ways.
-Running tests in your target environment is important and a recommended step to verify continuously.
-
-Finally, **adhere to best practice**.
-We are not an authorative source of best practice, but, at the very least:
-
-* [Don't re-use addresses](https://en.bitcoin.it/wiki/Address_reuse).
-* Don't share BIP32 extended public keys ('xpubs'). [They are a liability](https://bitcoin.stackexchange.com/questions/56916/derivation-of-parent-private-key-from-non-hardened-child), and it only takes 1 misplaced private key (or a buggy implementation!) and you are vulnerable to **catastrophic fund loss**.
-* [Don't use `Math.random`](https://security.stackexchange.com/questions/181580/why-is-math-random-not-designed-to-be-cryptographically-secure) - in any way - don't.
-* Enforce that users always verify (manually) a freshly-decoded human-readable version of their intended transaction before broadcast.
-* [Don't *ask* users to generate mnemonics](https://en.bitcoin.it/wiki/Brainwallet#cite_note-1), or 'brain wallets',  humans are terrible random number generators.
-* Lastly, if you can, use [Typescript](https://www.typescriptlang.org/) or similar.
-
+## Setup
+### Node.js
+``` javascript
+var bitcoin = require('bitcoinjs-lib')
+```
 
 ### Browser
-The recommended method of using `bitcoinjs-lib` in your browser is through [Browserify](https://github.com/substack/node-browserify).
-If you're familiar with how to use browserify, ignore this and carry on, otherwise, it is recommended to read the tutorial at https://browserify.org/.
+If you're familiar with how to use browserify, ignore this and proceed normally.
+These steps are advisory only,  and may not be suitable for your application.
 
-**NOTE**: We use Node Maintenance LTS features, if you need strict ES5, use [`--transform babelify`](https://github.com/babel/babelify) in conjunction with your `browserify` step (using an [`es2015`](https://babeljs.io/docs/plugins/preset-es2015/) preset).
+[Browserify](https://github.com/substack/node-browserify) is assumed to be installed for these steps.
+
+For your project, create an `index.js` file
+``` javascript
+let bitcoin = require('bitcoinjs-lib')
+
+// your code here
+function myFunction () {
+	return bitcoin.ECPair.makeRandom().toWIF()
+}
+
+module.exports = {
+	myFunction
+}
+```
+
+Now, to compile for the browser:
+``` bash
+browserify index.js --standalone foo > app.js
+```
+
+You can now put `<script src="app.js" />` in your web page,  using `foo.myFunction` to create a new Bitcoin private key.
+
+**NOTE**: If you uglify the javascript, you must exclude the following variable names from being mangled: `BigInteger`, `ECPair`, `Point`.
+This is because of the function-name-duck-typing used in [typeforce](https://github.com/dcousens/typeforce).
+
+Example:
+``` bash
+uglifyjs ... --mangle reserved=['BigInteger','ECPair','Point']
+```
+
+**NOTE**: This library tracks Node LTS features,  if you need strict ES5,  use [`--transform babelify`](https://github.com/babel/babelify) in conjunction with your `browserify` step (using an [`es2015`](http://babeljs.io/docs/plugins/preset-es2015/) preset).
+
+**NOTE**: If you expect this library to run on an iOS 10 device, ensure that you are using [buffer@5.0.5](https://github.com/feross/buffer/pull/155) or greater.
 
-**WARNING**: iOS devices have [problems](https://github.com/feross/buffer/issues/136), use at least [buffer@5.0.5](https://github.com/feross/buffer/pull/155) or greater,  and enforce the test suites (for `Buffer`, and any other dependency) pass before use.
 
 ### Typescript or VSCode users
-Type declarations for Typescript are included in this library. Normal installation should include all the needed type information.
+Type declarations for Typescript are available for version `^3.0.0` of the library.
+``` bash
+npm install @types/bitcoinjs-lib
+```
+
+You can now use `bitcoinjs-lib` as a typescript compliant library.
+``` javascript
+import { HDNode, Transaction } from 'bitcoinjs-lib'
+```
+
+For VSCode (and other editors), users are advised to install the type declarations, as Intellisense uses that information to help you code (autocompletion, static analysis).
+
+Report any typescript related bugs at [@dlebrecht DefinitelyTyped fork](https://github.com/dlebrecht/DefinitelyTyped),  submit PRs to [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped)
+
+
+### Flow
+Definitions for [Flow typechecker](https://flowtype.org/) are available in flow-typed repository.
+
+[You can either download them directly](https://github.com/flowtype/flow-typed/blob/master/definitions/npm/bitcoinjs-lib_v2.x.x/flow_v0.17.x-/bitcoinjs-lib_v2.x.x.js) from the repo, or with the flow-typed CLI
+
+    # npm install -g flow-typed
+    $ flow-typed install -f 0.27 bitcoinjs-lib@2.2.0 # 0.27 for flow version, 2.2.0 for bitcoinjs-lib version
+
+The definitions are complete and up to date with version 2.2.0. The definitions are maintained by [@runn1ng](https://github.com/runn1ng).
 
 ## Examples
 The below examples are implemented as integration tests, they should be very easy to understand.
 Otherwise, pull requests are appreciated.
 Some examples interact (via HTTPS) with a 3rd Party Blockchain Provider (3PBP).
 
-- [Taproot Key Spend](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/taproot.md)
-
-- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
-- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
-- [Generate a 2-of-3 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
-- [Generate a SegWit address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
-- [Generate a SegWit P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
-- [Generate a SegWit 3-of-4 multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
-- [Generate a SegWit 2-of-2 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
-- [Support the retrieval of transactions for an address (3rd party blockchain)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
-- [Generate a Testnet address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
-- [Generate a Litecoin address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.spec.ts)
-- [Create a 1-to-1 Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.spec.ts)
-- [Create (and broadcast via 3PBP) a typical Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction with an OP\_RETURN output](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction with a 2-of-4 P2SH(multisig) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction with a SegWit P2SH(P2WPKH) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction with a SegWit P2WPKH input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction with a SegWit P2PK input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction with a SegWit 3-of-4 P2SH(P2WSH(multisig)) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction and sign with an HDSigner interface (bip32)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.spec.ts)
-- [Import a BIP32 testnet xpriv and export to WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.spec.ts)
-- [Export a BIP32 xpriv, then import it](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.spec.ts)
-- [Export a BIP32 xpub](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.spec.ts)
-- [Create a BIP32, bitcoin, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.spec.ts)
-- [Create a BIP44, bitcoin, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.spec.ts)
-- [Create a BIP49, bitcoin testnet, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.spec.ts)
-- [Use BIP39 to generate BIP32 addresses](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the past)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.spec.ts)
-- [Create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future) (simple CHECKSEQUENCEVERIFY)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/csv.spec.ts)
-- [Create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry (simple CHECKSEQUENCEVERIFY)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/csv.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction where Bob and Charles can send (complex CHECKSEQUENCEVERIFY)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/csv.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction where Alice (mediator) and Bob can send after 2 blocks (complex CHECKSEQUENCEVERIFY)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/csv.spec.ts)
-- [Create (and broadcast via 3PBP) a Transaction where Alice (mediator) can send after 5 blocks (complex CHECKSEQUENCEVERIFY)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/csv.spec.ts)
+- [Generate a random address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L12)
+- [Generate an address from a SHA256 hash](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L19)
+- [Import an address via WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L29)
+- [Generate a 2-of-3 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L36)
+- [Generate a SegWit address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L50)
+- [Generate a SegWit P2SH address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L60)
+- [Generate a SegWit 3-of-4 multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L71)
+- [Generate a SegWit 2-of-2 P2SH multisig address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L86)
+- [Support the retrieval of transactions for an address (3rd party blockchain)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L100)
+- [Generate a Testnet address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L121)
+- [Generate a Litecoin address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/addresses.js#L131)
+- [Create a 1-to-1 Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L14)
+- [Create a 2-to-2 Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L28)
+- [Create (and broadcast via 3PBP) a typical Transaction](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L46)
+- [Create (and broadcast via 3PBP) a Transaction with an OP\_RETURN output](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L88)
+- [Create (and broadcast via 3PBP) a Transaction with a 2-of-4 P2SH(multisig) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L115)
+- [Create (and broadcast via 3PBP) a Transaction with a SegWit P2SH(P2WPKH) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L151)
+- [Create (and broadcast via 3PBP) a Transaction with a SegWit 3-of-4 P2SH(P2WSH(multisig)) input](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/transactions.js#L183)
+- [Import a BIP32 testnet xpriv and export to WIF](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L8)
+- [Export a BIP32 xpriv, then import it](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L15)
+- [Export a BIP32 xpub](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L26)
+- [Create a BIP32, bitcoin, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L35)
+- [Create a BIP44, bitcoin, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L50)
+- [Create a BIP49, bitcoin testnet, account 0, external address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L66)
+- [Use BIP39 to generate BIP32 addresses](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/bip32.js#L83)
+- [Create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L37)
+- [Create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L71)
+- [Create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/cltv.js#L104)
+- [Recover a private key from duplicate R values](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L14)
+- [Recover a BIP32 parent private key from the parent public key, and a derived, non-hardened child private key](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/crypto.js#L115)
+- [Generate a single-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L70:)
+- [Generate a single-key stealth address (randomly)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L89:)
+- [Recover parent recipient.d, if a derived private key is leaked (and nonce was revealed)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L105)
+- [Generate a dual-key stealth address](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L122)
+- [Generate a dual-key stealth address (randomly)](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/test/integration/stealth.js#L145)
 
 If you have a use case that you feel could be listed here, please [ask for it](https://github.com/bitcoinjs/bitcoinjs-lib/issues/new)!
 
 
+## Projects utilizing BitcoinJS
+- [BitAddress](https://www.bitaddress.org)
+- [Blockchain.info](https://blockchain.info/wallet)
+- [Blocktrail](https://www.blocktrail.com/)
+- [Dark Wallet](https://www.darkwallet.is/)
+- [DecentralBank](http://decentralbank.com/)
+- [Dogechain Wallet](https://dogechain.info)
+- [EI8HT Wallet](http://ei8.ht/)
+- [GreenAddress](https://greenaddress.it)
+- [Helperbit](https://helperbit.com)
+- [Melis Wallet](https://melis.io)
+- [Robocoin](https://wallet.robocoin.com)
+- [Skyhook ATM](http://projectskyhook.com)
+
+
 ## Contributing
-See [CONTRIBUTING.md](CONTRIBUTING.md).
+We are always accepting of pull requests, but we do adhere to specific standards in regards to coding style, test driven development and commit messages.
+
+Please make your best effort to adhere to these when contributing to save on trivial corrections.
 
 
 ### Running the test suite
@@ -153,7 +187,7 @@ npm run-script coverage
 - [BIP69](https://github.com/bitcoinjs/bip69) - Lexicographical Indexing of Transaction Inputs and Outputs
 - [Base58](https://github.com/cryptocoinjs/bs58) - Base58 encoding/decoding
 - [Base58 Check](https://github.com/bitcoinjs/bs58check) - Base58 check encoding/decoding
-- [Bech32](https://github.com/bitcoinjs/bech32) - A BIP173/BIP350 compliant Bech32/Bech32m encoding library
+- [Bech32](https://github.com/bitcoinjs/bech32) - A BIP173 compliant Bech32 encoding library
 - [coinselect](https://github.com/bitcoinjs/coinselect) - A fee-optimizing, transaction input selection module for bitcoinjs-lib.
 - [merkle-lib](https://github.com/bitcoinjs/merkle-lib) - A performance conscious library for merkle root and tree calculations.
 - [minimaldata](https://github.com/bitcoinjs/minimaldata) - A module to check bitcoin policy: SCRIPT_VERIFY_MINIMALDATA
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 3e5bd51..0000000
--- a/package-lock.json
+++ /dev/null
@@ -1,2680 +0,0 @@
-{
-  "name": "bitcoinjs-lib",
-  "version": "6.0.1",
-  "lockfileVersion": 1,
-  "requires": true,
-  "dependencies": {
-    "@babel/code-frame": {
-      "version": "7.15.8",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz",
-      "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==",
-      "dev": true,
-      "requires": {
-        "@babel/highlight": "^7.14.5"
-      }
-    },
-    "@babel/core": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.13.tgz",
-      "integrity": "sha512-BQKE9kXkPlXHPeqissfxo0lySWJcYdEP0hdtJOH/iJfDdhOCcgtNCjftCJg3qqauB4h+lz2N6ixM++b9DN1Tcw==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.12.13",
-        "@babel/generator": "^7.12.13",
-        "@babel/helper-module-transforms": "^7.12.13",
-        "@babel/helpers": "^7.12.13",
-        "@babel/parser": "^7.12.13",
-        "@babel/template": "^7.12.13",
-        "@babel/traverse": "^7.12.13",
-        "@babel/types": "^7.12.13",
-        "convert-source-map": "^1.7.0",
-        "debug": "^4.1.0",
-        "gensync": "^1.0.0-beta.1",
-        "json5": "^2.1.2",
-        "lodash": "^4.17.19",
-        "semver": "^5.4.1",
-        "source-map": "^0.5.0"
-      },
-      "dependencies": {
-        "@babel/code-frame": {
-          "version": "7.12.13",
-          "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
-          "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
-          "dev": true,
-          "requires": {
-            "@babel/highlight": "^7.12.13"
-          }
-        },
-        "@babel/highlight": {
-          "version": "7.12.13",
-          "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz",
-          "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==",
-          "dev": true,
-          "requires": {
-            "@babel/helper-validator-identifier": "^7.12.11",
-            "chalk": "^2.0.0",
-            "js-tokens": "^4.0.0"
-          }
-        },
-        "debug": {
-          "version": "4.3.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
-      }
-    },
-    "@babel/generator": {
-      "version": "7.12.15",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.15.tgz",
-      "integrity": "sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.12.13",
-        "jsesc": "^2.5.1",
-        "source-map": "^0.5.0"
-      }
-    },
-    "@babel/helper-function-name": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz",
-      "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-get-function-arity": "^7.12.13",
-        "@babel/template": "^7.12.13",
-        "@babel/types": "^7.12.13"
-      }
-    },
-    "@babel/helper-get-function-arity": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz",
-      "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.12.13"
-      }
-    },
-    "@babel/helper-member-expression-to-functions": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.13.tgz",
-      "integrity": "sha512-B+7nN0gIL8FZ8SvMcF+EPyB21KnCcZHQZFczCxbiNGV/O0rsrSBlWGLzmtBJ3GMjSVMIm4lpFhR+VdVBuIsUcQ==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.12.13"
-      }
-    },
-    "@babel/helper-module-imports": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz",
-      "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.12.13"
-      }
-    },
-    "@babel/helper-module-transforms": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.13.tgz",
-      "integrity": "sha512-acKF7EjqOR67ASIlDTupwkKM1eUisNAjaSduo5Cz+793ikfnpe7p4Q7B7EWU2PCoSTPWsQkR7hRUWEIZPiVLGA==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-module-imports": "^7.12.13",
-        "@babel/helper-replace-supers": "^7.12.13",
-        "@babel/helper-simple-access": "^7.12.13",
-        "@babel/helper-split-export-declaration": "^7.12.13",
-        "@babel/helper-validator-identifier": "^7.12.11",
-        "@babel/template": "^7.12.13",
-        "@babel/traverse": "^7.12.13",
-        "@babel/types": "^7.12.13",
-        "lodash": "^4.17.19"
-      }
-    },
-    "@babel/helper-optimise-call-expression": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz",
-      "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.12.13"
-      }
-    },
-    "@babel/helper-replace-supers": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.13.tgz",
-      "integrity": "sha512-pctAOIAMVStI2TMLhozPKbf5yTEXc0OJa0eENheb4w09SrgOWEs+P4nTOZYJQCqs8JlErGLDPDJTiGIp3ygbLg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-member-expression-to-functions": "^7.12.13",
-        "@babel/helper-optimise-call-expression": "^7.12.13",
-        "@babel/traverse": "^7.12.13",
-        "@babel/types": "^7.12.13"
-      }
-    },
-    "@babel/helper-simple-access": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz",
-      "integrity": "sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.12.13"
-      }
-    },
-    "@babel/helper-split-export-declaration": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz",
-      "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.12.13"
-      }
-    },
-    "@babel/helper-validator-identifier": {
-      "version": "7.12.11",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
-      "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==",
-      "dev": true
-    },
-    "@babel/helpers": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.13.tgz",
-      "integrity": "sha512-oohVzLRZ3GQEk4Cjhfs9YkJA4TdIDTObdBEZGrd6F/T0GPSnuV6l22eMcxlvcvzVIPH3VTtxbseudM1zIE+rPQ==",
-      "dev": true,
-      "requires": {
-        "@babel/template": "^7.12.13",
-        "@babel/traverse": "^7.12.13",
-        "@babel/types": "^7.12.13"
-      }
-    },
-    "@babel/highlight": {
-      "version": "7.14.5",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
-      "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-validator-identifier": "^7.14.5",
-        "chalk": "^2.0.0",
-        "js-tokens": "^4.0.0"
-      },
-      "dependencies": {
-        "@babel/helper-validator-identifier": {
-          "version": "7.15.7",
-          "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
-          "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
-          "dev": true
-        }
-      }
-    },
-    "@babel/parser": {
-      "version": "7.12.15",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.15.tgz",
-      "integrity": "sha512-AQBOU2Z9kWwSZMd6lNjCX0GUgFonL1wAM1db8L8PMk9UDaGsRCArBkU4Sc+UCM3AE4hjbXx+h58Lb3QT4oRmrA==",
-      "dev": true
-    },
-    "@babel/template": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz",
-      "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.12.13",
-        "@babel/parser": "^7.12.13",
-        "@babel/types": "^7.12.13"
-      },
-      "dependencies": {
-        "@babel/code-frame": {
-          "version": "7.12.13",
-          "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
-          "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
-          "dev": true,
-          "requires": {
-            "@babel/highlight": "^7.12.13"
-          }
-        },
-        "@babel/highlight": {
-          "version": "7.12.13",
-          "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz",
-          "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==",
-          "dev": true,
-          "requires": {
-            "@babel/helper-validator-identifier": "^7.12.11",
-            "chalk": "^2.0.0",
-            "js-tokens": "^4.0.0"
-          }
-        }
-      }
-    },
-    "@babel/traverse": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz",
-      "integrity": "sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.12.13",
-        "@babel/generator": "^7.12.13",
-        "@babel/helper-function-name": "^7.12.13",
-        "@babel/helper-split-export-declaration": "^7.12.13",
-        "@babel/parser": "^7.12.13",
-        "@babel/types": "^7.12.13",
-        "debug": "^4.1.0",
-        "globals": "^11.1.0",
-        "lodash": "^4.17.19"
-      },
-      "dependencies": {
-        "@babel/code-frame": {
-          "version": "7.12.13",
-          "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
-          "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
-          "dev": true,
-          "requires": {
-            "@babel/highlight": "^7.12.13"
-          }
-        },
-        "@babel/highlight": {
-          "version": "7.12.13",
-          "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz",
-          "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==",
-          "dev": true,
-          "requires": {
-            "@babel/helper-validator-identifier": "^7.12.11",
-            "chalk": "^2.0.0",
-            "js-tokens": "^4.0.0"
-          }
-        },
-        "debug": {
-          "version": "4.3.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
-      }
-    },
-    "@babel/types": {
-      "version": "7.12.13",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz",
-      "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==",
-      "dev": true,
-      "requires": {
-        "@babel/helper-validator-identifier": "^7.12.11",
-        "lodash": "^4.17.19",
-        "to-fast-properties": "^2.0.0"
-      }
-    },
-    "@istanbuljs/load-nyc-config": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
-      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
-      "dev": true,
-      "requires": {
-        "camelcase": "^5.3.1",
-        "find-up": "^4.1.0",
-        "get-package-type": "^0.1.0",
-        "js-yaml": "^3.13.1",
-        "resolve-from": "^5.0.0"
-      },
-      "dependencies": {
-        "find-up": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^4.1.0"
-          }
-        },
-        "p-locate": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.2.0"
-          }
-        },
-        "path-exists": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-          "dev": true
-        }
-      }
-    },
-    "@istanbuljs/schema": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
-      "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==",
-      "dev": true
-    },
-    "@types/base-x": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/@types/base-x/-/base-x-3.0.0.tgz",
-      "integrity": "sha512-vnqSlpsv9uFX5/z8GyKWAfWHhLGJDBkrgRRsnxlsX23DHOlNyqP/eHQiv4TwnYcZULzQIxaWA/xRWU9Dyy4qzw==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
-    "@types/bs58": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/@types/bs58/-/bs58-4.0.0.tgz",
-      "integrity": "sha512-gYX+MHD4G/R+YGYwdhG5gbJj4LsEQGr3Vg6gVDAbe7xC5Bn8dNNG2Lpo6uDX/rT5dE7VBj0rGEFuV8L0AEx4Rg==",
-      "dev": true,
-      "requires": {
-        "@types/base-x": "*"
-      }
-    },
-    "@types/bs58check": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/@types/bs58check/-/bs58check-2.1.0.tgz",
-      "integrity": "sha512-OxsysnJQh82vy9DRbOcw9m2j/WiyqZLn0YBhKxdQ+aCwoHj+tWzyCgpwAkr79IfDXZKxc6h7k89T9pwS78CqTQ==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
-    "@types/create-hash": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/@types/create-hash/-/create-hash-1.2.2.tgz",
-      "integrity": "sha512-Fg8/kfMJObbETFU/Tn+Y0jieYewryLrbKwLCEIwPyklZZVY2qB+64KFjhplGSw+cseZosfFXctXO+PyIYD8iZQ==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
-    "@types/mocha": {
-      "version": "5.2.7",
-      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
-      "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==",
-      "dev": true
-    },
-    "@types/node": {
-      "version": "16.11.7",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz",
-      "integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==",
-      "dev": true
-    },
-    "@types/proxyquire": {
-      "version": "1.3.28",
-      "resolved": "https://registry.npmjs.org/@types/proxyquire/-/proxyquire-1.3.28.tgz",
-      "integrity": "sha512-SQaNzWQ2YZSr7FqAyPPiA3FYpux2Lqh3HWMZQk47x3xbMCqgC/w0dY3dw9rGqlweDDkrySQBcaScXWeR+Yb11Q==",
-      "dev": true
-    },
-    "@types/randombytes": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/@types/randombytes/-/randombytes-2.0.0.tgz",
-      "integrity": "sha512-bz8PhAVlwN72vqefzxa14DKNT8jK/mV66CSjwdVQM/k3Th3EPKfUtdMniwZgMedQTFuywAsfjnZsg+pEnltaMA==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
-    "@types/wif": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/@types/wif/-/wif-2.0.2.tgz",
-      "integrity": "sha512-IiIuBeJzlh4LWJ7kVTrX0nwB60OG0vvGTaWC/SgSbVFw7uYUTF6gEuvDZ1goWkeirekJDD58Y8g7NljQh2fNkA==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
-    "aggregate-error": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
-      "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
-      "dev": true,
-      "requires": {
-        "clean-stack": "^2.0.0",
-        "indent-string": "^4.0.0"
-      }
-    },
-    "ansi-colors": {
-      "version": "3.2.3",
-      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
-      "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==",
-      "dev": true
-    },
-    "ansi-regex": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
-      "dev": true
-    },
-    "ansi-styles": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-      "dev": true,
-      "requires": {
-        "color-convert": "^1.9.0"
-      }
-    },
-    "anymatch": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
-      "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
-      "dev": true,
-      "requires": {
-        "normalize-path": "^3.0.0",
-        "picomatch": "^2.0.4"
-      }
-    },
-    "append-transform": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz",
-      "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==",
-      "dev": true,
-      "requires": {
-        "default-require-extensions": "^3.0.0"
-      }
-    },
-    "archy": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
-      "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
-      "dev": true
-    },
-    "arg": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz",
-      "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==",
-      "dev": true
-    },
-    "argparse": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-      "dev": true,
-      "requires": {
-        "sprintf-js": "~1.0.2"
-      }
-    },
-    "balanced-match": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-      "dev": true
-    },
-    "base-x": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.5.tgz",
-      "integrity": "sha512-C3picSgzPSLE+jW3tcBzJoGwitOtazb5B+5YmAxZm2ybmTi9LNgAtDO/jjVEBZwHoXmDBZ9m/IELj3elJVRBcA==",
-      "requires": {
-        "safe-buffer": "^5.0.1"
-      }
-    },
-    "bech32": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz",
-      "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg=="
-    },
-    "binary-extensions": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
-      "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==",
-      "dev": true
-    },
-    "bip174": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.0.1.tgz",
-      "integrity": "sha512-i3X26uKJOkDTAalYAp0Er+qGMDhrbbh2o93/xiPyAN2s25KrClSpe3VXo/7mNJoqA5qfko8rLS2l3RWZgYmjKQ=="
-    },
-    "bip32": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/bip32/-/bip32-3.0.1.tgz",
-      "integrity": "sha512-Uhpp9aEx3iyiO7CpbNGFxv9WcMIVdGoHG04doQ5Ln0u60uwDah7jUSc3QMV/fSZGm/Oo01/OeAmYevXV+Gz5jQ==",
-      "dev": true,
-      "requires": {
-        "@types/node": "10.12.18",
-        "bs58check": "^2.1.1",
-        "create-hash": "^1.2.0",
-        "create-hmac": "^1.1.7",
-        "typeforce": "^1.11.5",
-        "wif": "^2.0.6"
-      },
-      "dependencies": {
-        "@types/node": {
-          "version": "10.12.18",
-          "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz",
-          "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==",
-          "dev": true
-        }
-      }
-    },
-    "bip39": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz",
-      "integrity": "sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==",
-      "dev": true,
-      "requires": {
-        "@types/node": "11.11.6",
-        "create-hash": "^1.1.0",
-        "pbkdf2": "^3.0.9",
-        "randombytes": "^2.0.1"
-      },
-      "dependencies": {
-        "@types/node": {
-          "version": "11.11.6",
-          "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz",
-          "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==",
-          "dev": true
-        }
-      }
-    },
-    "bip65": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/bip65/-/bip65-1.0.3.tgz",
-      "integrity": "sha512-RQ1nc7xtnLa5XltnCqkoR2zmhuz498RjMJwrLKQzOE049D1HUqnYfon7cVSbwS5UGm0/EQlC2CH+NY3MyITA4Q==",
-      "dev": true
-    },
-    "bip68": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/bip68/-/bip68-1.0.4.tgz",
-      "integrity": "sha512-O1htyufFTYy3EO0JkHg2CLykdXEtV2ssqw47Gq9A0WByp662xpJnMEB9m43LZjsSDjIAOozWRExlFQk2hlV1XQ==",
-      "dev": true
-    },
-    "bitcoin-ops": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/bitcoin-ops/-/bitcoin-ops-1.4.1.tgz",
-      "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==",
-      "dev": true
-    },
-    "bn.js": {
-      "version": "4.11.8",
-      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
-      "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
-      "dev": true
-    },
-    "brace-expansion": {
-      "version": "1.1.11",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "dev": true,
-      "requires": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
-      }
-    },
-    "braces": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-      "dev": true,
-      "requires": {
-        "fill-range": "^7.0.1"
-      }
-    },
-    "browser-stdout": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
-      "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
-      "dev": true
-    },
-    "bs58": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
-      "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
-      "requires": {
-        "base-x": "^3.0.2"
-      }
-    },
-    "bs58check": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
-      "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
-      "requires": {
-        "bs58": "^4.0.0",
-        "create-hash": "^1.1.0",
-        "safe-buffer": "^5.1.2"
-      }
-    },
-    "buffer-from": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
-      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
-      "dev": true
-    },
-    "builtin-modules": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
-      "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
-      "dev": true
-    },
-    "caching-transform": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
-      "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==",
-      "dev": true,
-      "requires": {
-        "hasha": "^5.0.0",
-        "make-dir": "^3.0.0",
-        "package-hash": "^4.0.0",
-        "write-file-atomic": "^3.0.0"
-      }
-    },
-    "camelcase": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-      "dev": true
-    },
-    "chalk": {
-      "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-      "dev": true,
-      "requires": {
-        "ansi-styles": "^3.2.1",
-        "escape-string-regexp": "^1.0.5",
-        "supports-color": "^5.3.0"
-      },
-      "dependencies": {
-        "supports-color": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
-      }
-    },
-    "chokidar": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz",
-      "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==",
-      "dev": true,
-      "requires": {
-        "anymatch": "~3.1.1",
-        "braces": "~3.0.2",
-        "fsevents": "~2.1.1",
-        "glob-parent": "~5.1.0",
-        "is-binary-path": "~2.1.0",
-        "is-glob": "~4.0.1",
-        "normalize-path": "~3.0.0",
-        "readdirp": "~3.2.0"
-      }
-    },
-    "cipher-base": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
-      "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
-      "requires": {
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.0.1"
-      }
-    },
-    "clean-stack": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
-      "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
-      "dev": true
-    },
-    "cliui": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
-      "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
-      "dev": true,
-      "requires": {
-        "string-width": "^3.1.0",
-        "strip-ansi": "^5.2.0",
-        "wrap-ansi": "^5.1.0"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^7.0.1",
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^5.1.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^4.1.0"
-          }
-        }
-      }
-    },
-    "color-convert": {
-      "version": "1.9.3",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-      "dev": true,
-      "requires": {
-        "color-name": "1.1.3"
-      }
-    },
-    "color-name": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-      "dev": true
-    },
-    "commander": {
-      "version": "2.20.3",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-      "dev": true
-    },
-    "commondir": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
-      "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
-      "dev": true
-    },
-    "concat-map": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-      "dev": true
-    },
-    "convert-source-map": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
-      "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "~5.1.1"
-      }
-    },
-    "create-hash": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
-      "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
-      "requires": {
-        "cipher-base": "^1.0.1",
-        "inherits": "^2.0.1",
-        "md5.js": "^1.3.4",
-        "ripemd160": "^2.0.1",
-        "sha.js": "^2.4.0"
-      }
-    },
-    "create-hmac": {
-      "version": "1.1.7",
-      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
-      "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
-      "dev": true,
-      "requires": {
-        "cipher-base": "^1.0.3",
-        "create-hash": "^1.1.0",
-        "inherits": "^2.0.1",
-        "ripemd160": "^2.0.0",
-        "safe-buffer": "^5.0.1",
-        "sha.js": "^2.4.8"
-      }
-    },
-    "cross-spawn": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
-      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
-      "dev": true,
-      "requires": {
-        "path-key": "^3.1.0",
-        "shebang-command": "^2.0.0",
-        "which": "^2.0.1"
-      },
-      "dependencies": {
-        "which": {
-          "version": "2.0.2",
-          "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-          "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-          "dev": true,
-          "requires": {
-            "isexe": "^2.0.0"
-          }
-        }
-      }
-    },
-    "debug": {
-      "version": "3.2.6",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
-      "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
-      "dev": true,
-      "requires": {
-        "ms": "^2.1.1"
-      }
-    },
-    "decamelize": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
-      "dev": true
-    },
-    "default-require-extensions": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz",
-      "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==",
-      "dev": true,
-      "requires": {
-        "strip-bom": "^4.0.0"
-      }
-    },
-    "define-properties": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
-      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
-      "dev": true,
-      "requires": {
-        "object-keys": "^1.0.12"
-      }
-    },
-    "dhttp": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/dhttp/-/dhttp-3.0.3.tgz",
-      "integrity": "sha512-map1b8iyvxSv0uEw3DUDDK5XvH3aYA7QU9DcXy8e3FBIXSwHPHTZWVrOot7Iu9mieWq5XcrZemEJlob6IdCBmg==",
-      "dev": true,
-      "requires": {
-        "statuses": "^1.5.0"
-      }
-    },
-    "diff": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
-      "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
-      "dev": true
-    },
-    "ecpair": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.0.1.tgz",
-      "integrity": "sha512-iT3wztQMeE/nDTlfnAg8dAFUfBS7Tq2BXzq3ae6L+pWgFU0fQ3l0woTzdTBrJV3OxBjxbzjq8EQhAbEmJNWFSw==",
-      "dev": true,
-      "requires": {
-        "randombytes": "^2.1.0",
-        "typeforce": "^1.18.0",
-        "wif": "^2.0.6"
-      }
-    },
-    "emoji-regex": {
-      "version": "7.0.3",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
-      "dev": true
-    },
-    "es-abstract": {
-      "version": "1.17.4",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz",
-      "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==",
-      "dev": true,
-      "requires": {
-        "es-to-primitive": "^1.2.1",
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.1",
-        "is-callable": "^1.1.5",
-        "is-regex": "^1.0.5",
-        "object-inspect": "^1.7.0",
-        "object-keys": "^1.1.1",
-        "object.assign": "^4.1.0",
-        "string.prototype.trimleft": "^2.1.1",
-        "string.prototype.trimright": "^2.1.1"
-      }
-    },
-    "es-to-primitive": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
-      "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
-      "dev": true,
-      "requires": {
-        "is-callable": "^1.1.4",
-        "is-date-object": "^1.0.1",
-        "is-symbol": "^1.0.2"
-      }
-    },
-    "es6-error": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
-      "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
-      "dev": true
-    },
-    "escape-string-regexp": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-      "dev": true
-    },
-    "esprima": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-      "dev": true
-    },
-    "fill-keys": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz",
-      "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=",
-      "dev": true,
-      "requires": {
-        "is-object": "~1.0.1",
-        "merge-descriptors": "~1.0.0"
-      }
-    },
-    "fill-range": {
-      "version": "7.0.1",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-      "dev": true,
-      "requires": {
-        "to-regex-range": "^5.0.1"
-      }
-    },
-    "find-cache-dir": {
-      "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
-      "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
-      "dev": true,
-      "requires": {
-        "commondir": "^1.0.1",
-        "make-dir": "^3.0.2",
-        "pkg-dir": "^4.1.0"
-      }
-    },
-    "find-up": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
-      "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
-      "dev": true,
-      "requires": {
-        "locate-path": "^3.0.0"
-      }
-    },
-    "flat": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz",
-      "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==",
-      "dev": true,
-      "requires": {
-        "is-buffer": "~2.0.3"
-      }
-    },
-    "foreground-child": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
-      "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
-      "dev": true,
-      "requires": {
-        "cross-spawn": "^7.0.0",
-        "signal-exit": "^3.0.2"
-      }
-    },
-    "fromentries": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
-      "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==",
-      "dev": true
-    },
-    "fs.realpath": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
-      "dev": true
-    },
-    "fsevents": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
-      "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==",
-      "dev": true,
-      "optional": true
-    },
-    "function-bind": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
-      "dev": true
-    },
-    "gensync": {
-      "version": "1.0.0-beta.2",
-      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
-      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
-      "dev": true
-    },
-    "get-caller-file": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-      "dev": true
-    },
-    "get-package-type": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
-      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
-      "dev": true
-    },
-    "glob": {
-      "version": "7.1.3",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
-      "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
-      "dev": true,
-      "requires": {
-        "fs.realpath": "^1.0.0",
-        "inflight": "^1.0.4",
-        "inherits": "2",
-        "minimatch": "^3.0.4",
-        "once": "^1.3.0",
-        "path-is-absolute": "^1.0.0"
-      }
-    },
-    "glob-parent": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-      "dev": true,
-      "requires": {
-        "is-glob": "^4.0.1"
-      }
-    },
-    "globals": {
-      "version": "11.12.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
-      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
-      "dev": true
-    },
-    "graceful-fs": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
-      "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
-      "dev": true
-    },
-    "growl": {
-      "version": "1.10.5",
-      "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
-      "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
-      "dev": true
-    },
-    "has": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1"
-      }
-    },
-    "has-flag": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-      "dev": true
-    },
-    "has-symbols": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
-      "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
-      "dev": true
-    },
-    "hash-base": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
-      "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
-      "requires": {
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.0.1"
-      }
-    },
-    "hasha": {
-      "version": "5.2.2",
-      "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz",
-      "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==",
-      "dev": true,
-      "requires": {
-        "is-stream": "^2.0.0",
-        "type-fest": "^0.8.0"
-      }
-    },
-    "he": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
-      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
-      "dev": true
-    },
-    "hoodwink": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/hoodwink/-/hoodwink-2.0.0.tgz",
-      "integrity": "sha512-j1jog3tDfhpWlqbVbh29qc7FG7w+NT4ed+QQFGqvww83+50AzzretB7wykZGOe28mBdvCYH3GdHaVWJQ2lJ/4w==",
-      "dev": true
-    },
-    "html-escaper": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
-      "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
-      "dev": true
-    },
-    "imurmurhash": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
-      "dev": true
-    },
-    "indent-string": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
-      "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
-      "dev": true
-    },
-    "inflight": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
-      "dev": true,
-      "requires": {
-        "once": "^1.3.0",
-        "wrappy": "1"
-      }
-    },
-    "inherits": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
-    },
-    "is-binary-path": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
-      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-      "dev": true,
-      "requires": {
-        "binary-extensions": "^2.0.0"
-      }
-    },
-    "is-buffer": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
-      "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==",
-      "dev": true
-    },
-    "is-callable": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
-      "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
-      "dev": true
-    },
-    "is-date-object": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
-      "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
-      "dev": true
-    },
-    "is-extglob": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
-      "dev": true
-    },
-    "is-fullwidth-code-point": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-      "dev": true
-    },
-    "is-glob": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
-      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
-      "dev": true,
-      "requires": {
-        "is-extglob": "^2.1.1"
-      }
-    },
-    "is-number": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-      "dev": true
-    },
-    "is-object": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz",
-      "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=",
-      "dev": true
-    },
-    "is-regex": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
-      "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
-      "dev": true,
-      "requires": {
-        "has": "^1.0.3"
-      }
-    },
-    "is-stream": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
-      "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
-      "dev": true
-    },
-    "is-symbol": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
-      "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
-      "dev": true,
-      "requires": {
-        "has-symbols": "^1.0.1"
-      }
-    },
-    "is-typedarray": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
-      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
-      "dev": true
-    },
-    "is-windows": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
-      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
-      "dev": true
-    },
-    "isexe": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
-      "dev": true
-    },
-    "istanbul-lib-coverage": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz",
-      "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==",
-      "dev": true
-    },
-    "istanbul-lib-hook": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz",
-      "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==",
-      "dev": true,
-      "requires": {
-        "append-transform": "^2.0.0"
-      }
-    },
-    "istanbul-lib-instrument": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
-      "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
-      "dev": true,
-      "requires": {
-        "@babel/core": "^7.7.5",
-        "@istanbuljs/schema": "^0.1.2",
-        "istanbul-lib-coverage": "^3.0.0",
-        "semver": "^6.3.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        }
-      }
-    },
-    "istanbul-lib-processinfo": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz",
-      "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==",
-      "dev": true,
-      "requires": {
-        "archy": "^1.0.0",
-        "cross-spawn": "^7.0.0",
-        "istanbul-lib-coverage": "^3.0.0-alpha.1",
-        "make-dir": "^3.0.0",
-        "p-map": "^3.0.0",
-        "rimraf": "^3.0.0",
-        "uuid": "^3.3.3"
-      },
-      "dependencies": {
-        "rimraf": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-          "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        }
-      }
-    },
-    "istanbul-lib-report": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
-      "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
-      "dev": true,
-      "requires": {
-        "istanbul-lib-coverage": "^3.0.0",
-        "make-dir": "^3.0.0",
-        "supports-color": "^7.1.0"
-      },
-      "dependencies": {
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.2.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        }
-      }
-    },
-    "istanbul-lib-source-maps": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz",
-      "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==",
-      "dev": true,
-      "requires": {
-        "debug": "^4.1.1",
-        "istanbul-lib-coverage": "^3.0.0",
-        "source-map": "^0.6.1"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
-          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "istanbul-reports": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz",
-      "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==",
-      "dev": true,
-      "requires": {
-        "html-escaper": "^2.0.0",
-        "istanbul-lib-report": "^3.0.0"
-      }
-    },
-    "js-tokens": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-      "dev": true
-    },
-    "js-yaml": {
-      "version": "3.13.1",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
-      "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
-      "dev": true,
-      "requires": {
-        "argparse": "^1.0.7",
-        "esprima": "^4.0.0"
-      }
-    },
-    "jsesc": {
-      "version": "2.5.2",
-      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
-      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
-      "dev": true
-    },
-    "json5": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
-      "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
-      "dev": true,
-      "requires": {
-        "minimist": "^1.2.5"
-      }
-    },
-    "locate-path": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
-      "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
-      "dev": true,
-      "requires": {
-        "p-locate": "^3.0.0",
-        "path-exists": "^3.0.0"
-      }
-    },
-    "lodash": {
-      "version": "4.17.21",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
-      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
-      "dev": true
-    },
-    "lodash.flattendeep": {
-      "version": "4.4.0",
-      "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
-      "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
-      "dev": true
-    },
-    "log-symbols": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
-      "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
-      "dev": true,
-      "requires": {
-        "chalk": "^2.4.2"
-      }
-    },
-    "make-dir": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
-      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
-      "dev": true,
-      "requires": {
-        "semver": "^6.0.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        }
-      }
-    },
-    "make-error": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
-      "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
-      "dev": true
-    },
-    "md5.js": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
-      "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
-      "requires": {
-        "hash-base": "^3.0.0",
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.1.2"
-      }
-    },
-    "merge-descriptors": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
-      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
-      "dev": true
-    },
-    "minimaldata": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/minimaldata/-/minimaldata-1.0.2.tgz",
-      "integrity": "sha1-AfOywB2LJzmEP9hT1AY2xaLrdms=",
-      "dev": true,
-      "requires": {
-        "bitcoin-ops": "^1.3.0",
-        "pushdata-bitcoin": "^1.0.1"
-      }
-    },
-    "minimatch": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
-      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-      "dev": true,
-      "requires": {
-        "brace-expansion": "^1.1.7"
-      }
-    },
-    "minimist": {
-      "version": "1.2.5",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
-      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
-      "dev": true
-    },
-    "mkdirp": {
-      "version": "0.5.3",
-      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz",
-      "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==",
-      "dev": true,
-      "requires": {
-        "minimist": "^1.2.5"
-      }
-    },
-    "mocha": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz",
-      "integrity": "sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA==",
-      "dev": true,
-      "requires": {
-        "ansi-colors": "3.2.3",
-        "browser-stdout": "1.3.1",
-        "chokidar": "3.3.0",
-        "debug": "3.2.6",
-        "diff": "3.5.0",
-        "escape-string-regexp": "1.0.5",
-        "find-up": "3.0.0",
-        "glob": "7.1.3",
-        "growl": "1.10.5",
-        "he": "1.2.0",
-        "js-yaml": "3.13.1",
-        "log-symbols": "3.0.0",
-        "minimatch": "3.0.4",
-        "mkdirp": "0.5.3",
-        "ms": "2.1.1",
-        "node-environment-flags": "1.0.6",
-        "object.assign": "4.1.0",
-        "strip-json-comments": "2.0.1",
-        "supports-color": "6.0.0",
-        "which": "1.3.1",
-        "wide-align": "1.1.3",
-        "yargs": "13.3.2",
-        "yargs-parser": "13.1.2",
-        "yargs-unparser": "1.6.0"
-      }
-    },
-    "module-not-found-error": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz",
-      "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=",
-      "dev": true
-    },
-    "ms": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-      "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
-      "dev": true
-    },
-    "node-environment-flags": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz",
-      "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==",
-      "dev": true,
-      "requires": {
-        "object.getownpropertydescriptors": "^2.0.3",
-        "semver": "^5.7.0"
-      }
-    },
-    "node-preload": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
-      "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==",
-      "dev": true,
-      "requires": {
-        "process-on-spawn": "^1.0.0"
-      }
-    },
-    "normalize-path": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-      "dev": true
-    },
-    "npm-audit-whitelister": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/npm-audit-whitelister/-/npm-audit-whitelister-1.0.2.tgz",
-      "integrity": "sha512-MNaYMUPI4P1cGcnLNvMv0XW4F5NkVEJv2aAfLqXXKY4cgo5lXCHl1h9eUIQnWLKM3WHVOqKzUipMzfunzQZXUg==",
-      "dev": true
-    },
-    "nyc": {
-      "version": "15.1.0",
-      "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
-      "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==",
-      "dev": true,
-      "requires": {
-        "@istanbuljs/load-nyc-config": "^1.0.0",
-        "@istanbuljs/schema": "^0.1.2",
-        "caching-transform": "^4.0.0",
-        "convert-source-map": "^1.7.0",
-        "decamelize": "^1.2.0",
-        "find-cache-dir": "^3.2.0",
-        "find-up": "^4.1.0",
-        "foreground-child": "^2.0.0",
-        "get-package-type": "^0.1.0",
-        "glob": "^7.1.6",
-        "istanbul-lib-coverage": "^3.0.0",
-        "istanbul-lib-hook": "^3.0.0",
-        "istanbul-lib-instrument": "^4.0.0",
-        "istanbul-lib-processinfo": "^2.0.2",
-        "istanbul-lib-report": "^3.0.0",
-        "istanbul-lib-source-maps": "^4.0.0",
-        "istanbul-reports": "^3.0.2",
-        "make-dir": "^3.0.0",
-        "node-preload": "^0.2.1",
-        "p-map": "^3.0.0",
-        "process-on-spawn": "^1.0.0",
-        "resolve-from": "^5.0.0",
-        "rimraf": "^3.0.0",
-        "signal-exit": "^3.0.2",
-        "spawn-wrap": "^2.0.0",
-        "test-exclude": "^6.0.0",
-        "yargs": "^15.0.2"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
-          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
-          "dev": true
-        },
-        "ansi-styles": {
-          "version": "4.3.0",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^2.0.1"
-          }
-        },
-        "cliui": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
-          "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
-          "dev": true,
-          "requires": {
-            "string-width": "^4.2.0",
-            "strip-ansi": "^6.0.0",
-            "wrap-ansi": "^6.2.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "emoji-regex": {
-          "version": "8.0.0",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-          "dev": true
-        },
-        "find-up": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
-          }
-        },
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "is-fullwidth-code-point": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-          "dev": true
-        },
-        "locate-path": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^4.1.0"
-          }
-        },
-        "p-locate": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.2.0"
-          }
-        },
-        "path-exists": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-          "dev": true
-        },
-        "rimraf": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-          "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        },
-        "string-width": {
-          "version": "4.2.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
-          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
-          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^5.0.0"
-          }
-        },
-        "wrap-ansi": {
-          "version": "6.2.0",
-          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
-          "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.0.0",
-            "string-width": "^4.1.0",
-            "strip-ansi": "^6.0.0"
-          }
-        },
-        "yargs": {
-          "version": "15.4.1",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
-          "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
-          "dev": true,
-          "requires": {
-            "cliui": "^6.0.0",
-            "decamelize": "^1.2.0",
-            "find-up": "^4.1.0",
-            "get-caller-file": "^2.0.1",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^2.0.0",
-            "set-blocking": "^2.0.0",
-            "string-width": "^4.2.0",
-            "which-module": "^2.0.0",
-            "y18n": "^4.0.0",
-            "yargs-parser": "^18.1.2"
-          }
-        },
-        "yargs-parser": {
-          "version": "18.1.3",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
-          "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
-          "dev": true,
-          "requires": {
-            "camelcase": "^5.0.0",
-            "decamelize": "^1.2.0"
-          }
-        }
-      }
-    },
-    "object-inspect": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz",
-      "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==",
-      "dev": true
-    },
-    "object-keys": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
-      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
-      "dev": true
-    },
-    "object.assign": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
-      "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.2",
-        "function-bind": "^1.1.1",
-        "has-symbols": "^1.0.0",
-        "object-keys": "^1.0.11"
-      }
-    },
-    "object.getownpropertydescriptors": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz",
-      "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.17.0-next.1"
-      }
-    },
-    "once": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-      "dev": true,
-      "requires": {
-        "wrappy": "1"
-      }
-    },
-    "p-limit": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
-      "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
-      "dev": true,
-      "requires": {
-        "p-try": "^2.0.0"
-      }
-    },
-    "p-locate": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
-      "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
-      "dev": true,
-      "requires": {
-        "p-limit": "^2.0.0"
-      }
-    },
-    "p-map": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
-      "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
-      "dev": true,
-      "requires": {
-        "aggregate-error": "^3.0.0"
-      }
-    },
-    "p-try": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-      "dev": true
-    },
-    "package-hash": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz",
-      "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.15",
-        "hasha": "^5.0.0",
-        "lodash.flattendeep": "^4.4.0",
-        "release-zalgo": "^1.0.0"
-      }
-    },
-    "path-exists": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-      "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
-      "dev": true
-    },
-    "path-is-absolute": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
-      "dev": true
-    },
-    "path-key": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
-      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
-      "dev": true
-    },
-    "path-parse": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
-      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
-      "dev": true
-    },
-    "pbkdf2": {
-      "version": "3.0.17",
-      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
-      "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==",
-      "dev": true,
-      "requires": {
-        "create-hash": "^1.1.2",
-        "create-hmac": "^1.1.4",
-        "ripemd160": "^2.0.1",
-        "safe-buffer": "^5.0.1",
-        "sha.js": "^2.4.8"
-      }
-    },
-    "picomatch": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz",
-      "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==",
-      "dev": true
-    },
-    "pkg-dir": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
-      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
-      "dev": true,
-      "requires": {
-        "find-up": "^4.0.0"
-      },
-      "dependencies": {
-        "find-up": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^4.1.0"
-          }
-        },
-        "p-locate": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.2.0"
-          }
-        },
-        "path-exists": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-          "dev": true
-        }
-      }
-    },
-    "prettier": {
-      "version": "1.16.4",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz",
-      "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==",
-      "dev": true
-    },
-    "process-on-spawn": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
-      "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==",
-      "dev": true,
-      "requires": {
-        "fromentries": "^1.2.0"
-      }
-    },
-    "proxyquire": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.0.tgz",
-      "integrity": "sha512-kptdFArCfGRtQFv3Qwjr10lwbEV0TBJYvfqzhwucyfEXqVgmnAkyEw/S3FYzR5HI9i5QOq4rcqQjZ6AlknlCDQ==",
-      "dev": true,
-      "requires": {
-        "fill-keys": "^1.0.2",
-        "module-not-found-error": "^1.0.0",
-        "resolve": "~1.8.1"
-      }
-    },
-    "pushdata-bitcoin": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz",
-      "integrity": "sha1-FZMdPNlnreUiBvUjqnMxrvfUOvc=",
-      "dev": true,
-      "requires": {
-        "bitcoin-ops": "^1.3.0"
-      }
-    },
-    "randombytes": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
-      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "^5.1.0"
-      }
-    },
-    "readdirp": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz",
-      "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==",
-      "dev": true,
-      "requires": {
-        "picomatch": "^2.0.4"
-      }
-    },
-    "regtest-client": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/regtest-client/-/regtest-client-0.2.0.tgz",
-      "integrity": "sha512-eIcC8Kle/wjS47pRlw7nJpstrJDWp0bkvVPl2KJpJcK3JDNW0fMxJgE/CGpMEUSjhhFXW1rtJMN6kyKw5NIzqg==",
-      "dev": true,
-      "requires": {
-        "bs58check": "^2.1.2",
-        "dhttp": "^3.0.3",
-        "randombytes": "^2.1.0"
-      }
-    },
-    "release-zalgo": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz",
-      "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=",
-      "dev": true,
-      "requires": {
-        "es6-error": "^4.0.1"
-      }
-    },
-    "require-directory": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
-      "dev": true
-    },
-    "require-main-filename": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
-      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
-      "dev": true
-    },
-    "resolve": {
-      "version": "1.8.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
-      "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
-      "dev": true,
-      "requires": {
-        "path-parse": "^1.0.5"
-      }
-    },
-    "resolve-from": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
-      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
-      "dev": true
-    },
-    "rimraf": {
-      "version": "2.6.3",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
-      "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
-      "dev": true,
-      "requires": {
-        "glob": "^7.1.3"
-      },
-      "dependencies": {
-        "glob": {
-          "version": "7.1.4",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
-          "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        }
-      }
-    },
-    "ripemd160": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
-      "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
-      "requires": {
-        "hash-base": "^3.0.0",
-        "inherits": "^2.0.1"
-      }
-    },
-    "safe-buffer": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
-    },
-    "semver": {
-      "version": "5.7.1",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
-      "dev": true
-    },
-    "set-blocking": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
-      "dev": true
-    },
-    "sha.js": {
-      "version": "2.4.11",
-      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
-      "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
-      "requires": {
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.0.1"
-      }
-    },
-    "shebang-command": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
-      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
-      "dev": true,
-      "requires": {
-        "shebang-regex": "^3.0.0"
-      }
-    },
-    "shebang-regex": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
-      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
-      "dev": true
-    },
-    "signal-exit": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
-      "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
-      "dev": true
-    },
-    "source-map": {
-      "version": "0.5.7",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-      "dev": true
-    },
-    "source-map-support": {
-      "version": "0.5.13",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
-      "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
-      "dev": true,
-      "requires": {
-        "buffer-from": "^1.0.0",
-        "source-map": "^0.6.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "spawn-wrap": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
-      "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==",
-      "dev": true,
-      "requires": {
-        "foreground-child": "^2.0.0",
-        "is-windows": "^1.0.2",
-        "make-dir": "^3.0.0",
-        "rimraf": "^3.0.0",
-        "signal-exit": "^3.0.2",
-        "which": "^2.0.1"
-      },
-      "dependencies": {
-        "rimraf": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-          "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        },
-        "which": {
-          "version": "2.0.2",
-          "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-          "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-          "dev": true,
-          "requires": {
-            "isexe": "^2.0.0"
-          }
-        }
-      }
-    },
-    "sprintf-js": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
-      "dev": true
-    },
-    "statuses": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
-      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
-      "dev": true
-    },
-    "string-width": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
-      "dev": true,
-      "requires": {
-        "is-fullwidth-code-point": "^2.0.0",
-        "strip-ansi": "^4.0.0"
-      }
-    },
-    "string.prototype.trimleft": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
-      "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "function-bind": "^1.1.1"
-      }
-    },
-    "string.prototype.trimright": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
-      "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "function-bind": "^1.1.1"
-      }
-    },
-    "strip-ansi": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-      "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
-      "dev": true,
-      "requires": {
-        "ansi-regex": "^3.0.0"
-      }
-    },
-    "strip-bom": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
-      "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
-      "dev": true
-    },
-    "strip-json-comments": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
-      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
-      "dev": true
-    },
-    "supports-color": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
-      "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==",
-      "dev": true,
-      "requires": {
-        "has-flag": "^3.0.0"
-      }
-    },
-    "test-exclude": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
-      "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
-      "dev": true,
-      "requires": {
-        "@istanbuljs/schema": "^0.1.2",
-        "glob": "^7.1.4",
-        "minimatch": "^3.0.4"
-      },
-      "dependencies": {
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        }
-      }
-    },
-    "tiny-secp256k1": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.1.2.tgz",
-      "integrity": "sha512-8qPw7zDK6Hco2tVGYGQeOmOPp/hZnREwy2iIkcq0ygAuqc9WHo29vKN94lNymh1QbB3nthtAMF6KTIrdbsIotA==",
-      "dev": true,
-      "requires": {
-        "uint8array-tools": "0.0.6"
-      }
-    },
-    "to-fast-properties": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
-      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
-      "dev": true
-    },
-    "to-regex-range": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-      "dev": true,
-      "requires": {
-        "is-number": "^7.0.0"
-      }
-    },
-    "ts-node": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz",
-      "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==",
-      "dev": true,
-      "requires": {
-        "arg": "^4.1.0",
-        "diff": "^4.0.1",
-        "make-error": "^1.1.1",
-        "source-map-support": "^0.5.6",
-        "yn": "^3.0.0"
-      },
-      "dependencies": {
-        "diff": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
-          "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
-          "dev": true
-        }
-      }
-    },
-    "tslib": {
-      "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
-      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
-      "dev": true
-    },
-    "tslint": {
-      "version": "6.1.3",
-      "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
-      "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.0.0",
-        "builtin-modules": "^1.1.1",
-        "chalk": "^2.3.0",
-        "commander": "^2.12.1",
-        "diff": "^4.0.1",
-        "glob": "^7.1.1",
-        "js-yaml": "^3.13.1",
-        "minimatch": "^3.0.4",
-        "mkdirp": "^0.5.3",
-        "resolve": "^1.3.2",
-        "semver": "^5.3.0",
-        "tslib": "^1.13.0",
-        "tsutils": "^2.29.0"
-      },
-      "dependencies": {
-        "diff": {
-          "version": "4.0.2",
-          "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
-          "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
-          "dev": true
-        }
-      }
-    },
-    "tsutils": {
-      "version": "2.29.0",
-      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
-      "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
-      "dev": true,
-      "requires": {
-        "tslib": "^1.8.1"
-      }
-    },
-    "type-fest": {
-      "version": "0.8.1",
-      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
-      "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
-      "dev": true
-    },
-    "typedarray-to-buffer": {
-      "version": "3.1.5",
-      "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
-      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
-      "dev": true,
-      "requires": {
-        "is-typedarray": "^1.0.0"
-      }
-    },
-    "typeforce": {
-      "version": "1.18.0",
-      "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
-      "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
-    },
-    "typescript": {
-      "version": "4.4.4",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
-      "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
-      "dev": true
-    },
-    "uint8array-tools": {
-      "version": "0.0.6",
-      "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.6.tgz",
-      "integrity": "sha512-aIvEHNRX1AlOYAr6qSUjQBn4mCduxx6MtC967aRDTb2UUBPj0Ix2ZFQDcmXUUO/UxRPHcw1f5a5nVbCSKDSOqA==",
-      "dev": true
-    },
-    "uuid": {
-      "version": "3.4.0",
-      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
-      "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
-      "dev": true
-    },
-    "varuint-bitcoin": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz",
-      "integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==",
-      "requires": {
-        "safe-buffer": "^5.1.1"
-      }
-    },
-    "which": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
-      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
-      "dev": true,
-      "requires": {
-        "isexe": "^2.0.0"
-      }
-    },
-    "which-module": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
-      "dev": true
-    },
-    "wide-align": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
-      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
-      "dev": true,
-      "requires": {
-        "string-width": "^1.0.2 || 2"
-      }
-    },
-    "wif": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
-      "integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=",
-      "requires": {
-        "bs58check": "<3.0.0"
-      }
-    },
-    "wrap-ansi": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
-      "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
-      "dev": true,
-      "requires": {
-        "ansi-styles": "^3.2.0",
-        "string-width": "^3.0.0",
-        "strip-ansi": "^5.0.0"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^7.0.1",
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^5.1.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^4.1.0"
-          }
-        }
-      }
-    },
-    "wrappy": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-      "dev": true
-    },
-    "write-file-atomic": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
-      "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
-      "dev": true,
-      "requires": {
-        "imurmurhash": "^0.1.4",
-        "is-typedarray": "^1.0.0",
-        "signal-exit": "^3.0.2",
-        "typedarray-to-buffer": "^3.1.5"
-      }
-    },
-    "y18n": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
-      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
-      "dev": true
-    },
-    "yargs": {
-      "version": "13.3.2",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
-      "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
-      "dev": true,
-      "requires": {
-        "cliui": "^5.0.0",
-        "find-up": "^3.0.0",
-        "get-caller-file": "^2.0.1",
-        "require-directory": "^2.1.1",
-        "require-main-filename": "^2.0.0",
-        "set-blocking": "^2.0.0",
-        "string-width": "^3.0.0",
-        "which-module": "^2.0.0",
-        "y18n": "^4.0.0",
-        "yargs-parser": "^13.1.2"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^7.0.1",
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^5.1.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^4.1.0"
-          }
-        }
-      }
-    },
-    "yargs-parser": {
-      "version": "13.1.2",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
-      "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
-      "dev": true,
-      "requires": {
-        "camelcase": "^5.0.0",
-        "decamelize": "^1.2.0"
-      }
-    },
-    "yargs-unparser": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz",
-      "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==",
-      "dev": true,
-      "requires": {
-        "flat": "^4.1.0",
-        "lodash": "^4.17.15",
-        "yargs": "^13.3.0"
-      }
-    },
-    "yn": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
-      "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
-      "dev": true
-    }
-  }
-}
diff --git a/package.json b/package.json
index c5553d5..5594b35 100644
--- a/package.json
+++ b/package.json
@@ -1,11 +1,10 @@
 {
   "name": "bitcoinjs-lib",
-  "version": "6.0.1",
+  "version": "3.3.2",
   "description": "Client-side Bitcoin JavaScript library",
   "main": "./src/index.js",
-  "types": "./src/index.d.ts",
   "engines": {
-    "node": ">=8.0.0"
+    "node": ">=4.0.0"
   },
   "keywords": [
     "bitcoinjs",
@@ -15,31 +14,13 @@
     "bitcoinjs"
   ],
   "scripts": {
-    "audit": "NPM_AUDIT_IGNORE_DEV=1 NPM_AUDIT_IGNORE_LEVEL=low npm-audit-whitelister .npm-audit-whitelister.json",
-    "build": "npm run clean && tsc -p ./tsconfig.json && npm run formatjs",
-    "build:tests": "npm run clean:jstests && tsc -p ./test/tsconfig.json",
-    "clean": "rimraf src",
-    "clean:jstests": "rimraf 'test/**/!(ts-node-register)*.js'",
-    "coverage-report": "npm run build && npm run nobuild:coverage-report",
-    "coverage-html": "npm run build && npm run nobuild:coverage-html",
-    "coverage": "npm run build && npm run nobuild:coverage",
-    "format": "npm run prettier -- --write",
-    "formatjs": "npm run prettierjs -- --write",
-    "format:ci": "npm run prettier -- --check && npm run prettierjs -- --check",
-    "gitdiff:ci": "npm run build && git diff --exit-code",
-    "integration": "npm run build && npm run nobuild:integration",
-    "lint": "tslint -p tsconfig.json -c tslint.json",
-    "lint:tests": "tslint -p test/tsconfig.json -c tslint.json",
-    "mocha:ts": "mocha --recursive --require test/ts-node-register",
-    "nobuild:coverage-report": "nyc report --reporter=lcov",
-    "nobuild:coverage-html": "nyc report --reporter=html",
-    "nobuild:coverage": "npm run build:tests && nyc --check-coverage --branches 90 --functions 90 --lines 90 mocha && npm run clean:jstests",
-    "nobuild:integration": "npm run mocha:ts -- --timeout 50000 'test/integration/*.ts'",
-    "nobuild:unit": "npm run mocha:ts -- 'test/*.ts'",
-    "prettier": "prettier \"ts_src/**/*.ts\" \"test/**/*.ts\" --ignore-path ./.prettierignore",
-    "prettierjs": "prettier \"src/**/*.js\" --ignore-path ./.prettierignore",
-    "test": "npm run build && npm run format:ci && npm run lint && npm run nobuild:coverage",
-    "unit": "npm run build && npm run nobuild:unit"
+    "coverage-report": "nyc report --reporter=lcov",
+    "coverage-html": "nyc report --reporter=html",
+    "coverage": "nyc --check-coverage --branches 90 --functions 90 mocha",
+    "integration": "mocha test/integration/",
+    "standard": "standard",
+    "test": "npm run standard && npm run coverage",
+    "unit": "mocha"
   },
   "repository": {
     "type": "git",
@@ -49,45 +30,34 @@
     "src"
   ],
   "dependencies": {
-    "bech32": "^2.0.0",
-    "bip174": "^2.0.1",
-    "bs58check": "^2.1.2",
+    "bech32": "^1.1.2",
+    "bigi": "^1.4.0",
+    "bip66": "^1.1.0",
+    "bitcoin-ops": "^1.3.0",
+    "bs58check": "^2.0.0",
     "create-hash": "^1.1.0",
+    "create-hmac": "^1.1.3",
+    "ecurve": "^1.0.0",
+    "merkle-lib": "^2.0.10",
+    "pushdata-bitcoin": "^1.0.1",
+    "randombytes": "^2.0.1",
+    "safe-buffer": "^5.0.1",
     "typeforce": "^1.11.3",
-    "varuint-bitcoin": "^1.1.2",
+    "varuint-bitcoin": "^1.0.4",
     "wif": "^2.0.1"
   },
   "devDependencies": {
-    "@types/bs58": "^4.0.0",
-    "@types/bs58check": "^2.1.0",
-    "@types/create-hash": "^1.2.2",
-    "@types/mocha": "^5.2.7",
-    "@types/node": "^16.11.7",
-    "@types/proxyquire": "^1.3.28",
-    "@types/randombytes": "^2.0.0",
-    "@types/wif": "^2.0.2",
-    "bip32": "^3.0.1",
-    "bip39": "^3.0.2",
+    "bip39": "^2.3.0",
     "bip65": "^1.0.1",
-    "bip68": "^1.0.3",
-    "bn.js": "^4.11.8",
     "bs58": "^4.0.0",
-    "dhttp": "^3.0.0",
-    "ecpair": "^2.0.1",
-    "hoodwink": "^2.0.0",
+    "dhttp": "^2.4.2",
     "minimaldata": "^1.0.2",
-    "mocha": "^7.1.1",
-    "npm-audit-whitelister": "^1.0.2",
-    "nyc": "^15.1.0",
-    "prettier": "1.16.4",
-    "proxyquire": "^2.0.1",
-    "randombytes": "^2.1.0",
-    "regtest-client": "0.2.0",
-    "rimraf": "^2.6.3",
-    "tiny-secp256k1": "^2.1.2",
-    "ts-node": "^8.3.0",
-    "tslint": "^6.1.3",
-    "typescript": "^4.4.4"
+    "mocha": "^5.0.1",
+    "nyc": "^11.4.1",
+    "proxyquire": "^1.4.0",
+    "sinon": "^4.3.0",
+    "sinon-test": "^2.1.3",
+    "standard": "^9.0.2"
   },
   "license": "MIT"
 }
diff --git a/src/address.d.ts b/src/address.d.ts
deleted file mode 100644
index be0e00a..0000000
--- a/src/address.d.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/// <reference types="node" />
-import { Network } from './networks';
-export interface Base58CheckResult {
-    hash: Buffer;
-    version: number;
-}
-export interface Bech32Result {
-    version: number;
-    prefix: string;
-    data: Buffer;
-}
-export declare function fromBase58Check(address: string): Base58CheckResult;
-export declare function fromBech32(address: string): Bech32Result;
-export declare function toBase58Check(hash: Buffer, version: number): string;
-export declare function toBech32(data: Buffer, version: number, prefix: string): string;
-export declare function fromOutputScript(output: Buffer, network?: Network): string;
-export declare function toOutputScript(address: string, network?: Network): Buffer;
diff --git a/src/address.js b/src/address.js
index 164bf7e..221f85a 100644
--- a/src/address.js
+++ b/src/address.js
@@ -1,148 +1,97 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.toOutputScript = exports.fromOutputScript = exports.toBech32 = exports.toBase58Check = exports.fromBech32 = exports.fromBase58Check = void 0;
-const networks = require('./networks');
-const payments = require('./payments');
-const bscript = require('./script');
-const types = require('./types');
-const bech32_1 = require('bech32');
-const bs58check = require('bs58check');
-const { typeforce } = types;
-const FUTURE_SEGWIT_MAX_SIZE = 40;
-const FUTURE_SEGWIT_MIN_SIZE = 2;
-const FUTURE_SEGWIT_MAX_VERSION = 16;
-const FUTURE_SEGWIT_MIN_VERSION = 1;
-const FUTURE_SEGWIT_VERSION_DIFF = 0x50;
-const FUTURE_SEGWIT_VERSION_WARNING =
-  'WARNING: Sending to a future segwit version address can lead to loss of funds. ' +
-  'End users MUST be warned carefully in the GUI and asked if they wish to proceed ' +
-  'with caution. Wallets should verify the segwit version from the output of fromBech32, ' +
-  'then decide when it is safe to use which version of segwit.';
-function _toFutureSegwitAddress(output, network) {
-  const data = output.slice(2);
-  if (
-    data.length < FUTURE_SEGWIT_MIN_SIZE ||
-    data.length > FUTURE_SEGWIT_MAX_SIZE
-  )
-    throw new TypeError('Invalid program length for segwit address');
-  const version = output[0] - FUTURE_SEGWIT_VERSION_DIFF;
-  if (
-    version < FUTURE_SEGWIT_MIN_VERSION ||
-    version > FUTURE_SEGWIT_MAX_VERSION
-  )
-    throw new TypeError('Invalid version for segwit address');
-  if (output[1] !== data.length)
-    throw new TypeError('Invalid script for segwit address');
-  console.warn(FUTURE_SEGWIT_VERSION_WARNING);
-  return toBech32(data, version, network.bech32);
-}
-function fromBase58Check(address) {
-  const payload = bs58check.decode(address);
+var Buffer = require('safe-buffer').Buffer
+var bech32 = require('bech32')
+var bs58check = require('bs58check')
+var bscript = require('./script')
+var btemplates = require('./templates')
+var networks = require('./networks')
+var typeforce = require('typeforce')
+var types = require('./types')
+
+function fromBase58Check (address) {
+  var payload = bs58check.decode(address)
+
   // TODO: 4.0.0, move to "toOutputScript"
-  if (payload.length < 21) throw new TypeError(address + ' is too short');
-  if (payload.length > 21) throw new TypeError(address + ' is too long');
-  const version = payload.readUInt8(0);
-  const hash = payload.slice(1);
-  return { version, hash };
+  if (payload.length < 21) throw new TypeError(address + ' is too short')
+  if (payload.length > 21) throw new TypeError(address + ' is too long')
+
+  var version = payload.readUInt8(0)
+  var hash = payload.slice(1)
+
+  return { version: version, hash: hash }
 }
-exports.fromBase58Check = fromBase58Check;
-function fromBech32(address) {
-  let result;
-  let version;
-  try {
-    result = bech32_1.bech32.decode(address);
-  } catch (e) {}
-  if (result) {
-    version = result.words[0];
-    if (version !== 0) throw new TypeError(address + ' uses wrong encoding');
-  } else {
-    result = bech32_1.bech32m.decode(address);
-    version = result.words[0];
-    if (version === 0) throw new TypeError(address + ' uses wrong encoding');
-  }
-  const data = bech32_1.bech32.fromWords(result.words.slice(1));
+
+function fromBech32 (address) {
+  var result = bech32.decode(address)
+  var data = bech32.fromWords(result.words.slice(1))
+
   return {
-    version,
+    version: result.words[0],
     prefix: result.prefix,
-    data: Buffer.from(data),
-  };
+    data: Buffer.from(data)
+  }
 }
-exports.fromBech32 = fromBech32;
-function toBase58Check(hash, version) {
-  typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments);
-  const payload = Buffer.allocUnsafe(21);
-  payload.writeUInt8(version, 0);
-  hash.copy(payload, 1);
-  return bs58check.encode(payload);
+
+function toBase58Check (hash, version) {
+  typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments)
+
+  var payload = Buffer.allocUnsafe(21)
+  payload.writeUInt8(version, 0)
+  hash.copy(payload, 1)
+
+  return bs58check.encode(payload)
 }
-exports.toBase58Check = toBase58Check;
-function toBech32(data, version, prefix) {
-  const words = bech32_1.bech32.toWords(data);
-  words.unshift(version);
-  return version === 0
-    ? bech32_1.bech32.encode(prefix, words)
-    : bech32_1.bech32m.encode(prefix, words);
+
+function toBech32 (data, version, prefix) {
+  var words = bech32.toWords(data)
+  words.unshift(version)
+
+  return bech32.encode(prefix, words)
 }
-exports.toBech32 = toBech32;
-function fromOutputScript(output, network) {
-  // TODO: Network
-  network = network || networks.bitcoin;
-  try {
-    return payments.p2pkh({ output, network }).address;
-  } catch (e) {}
-  try {
-    return payments.p2sh({ output, network }).address;
-  } catch (e) {}
-  try {
-    return payments.p2wpkh({ output, network }).address;
-  } catch (e) {}
-  try {
-    return payments.p2wsh({ output, network }).address;
-  } catch (e) {}
-  try {
-    return _toFutureSegwitAddress(output, network);
-  } catch (e) {}
-  throw new Error(bscript.toASM(output) + ' has no matching Address');
+
+function fromOutputScript (outputScript, network) {
+  network = network || networks.bitcoin
+
+  if (btemplates.pubKeyHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(3, 23), network.pubKeyHash)
+  if (btemplates.scriptHash.output.check(outputScript)) return toBase58Check(bscript.compile(outputScript).slice(2, 22), network.scriptHash)
+  if (btemplates.witnessPubKeyHash.output.check(outputScript)) return toBech32(bscript.compile(outputScript).slice(2, 22), 0, network.bech32)
+  if (btemplates.witnessScriptHash.output.check(outputScript)) return toBech32(bscript.compile(outputScript).slice(2, 34), 0, network.bech32)
+
+  throw new Error(bscript.toASM(outputScript) + ' has no matching Address')
 }
-exports.fromOutputScript = fromOutputScript;
-function toOutputScript(address, network) {
-  network = network || networks.bitcoin;
-  let decodeBase58;
-  let decodeBech32;
+
+function toOutputScript (address, network) {
+  network = network || networks.bitcoin
+
+  var decode
   try {
-    decodeBase58 = fromBase58Check(address);
+    decode = fromBase58Check(address)
   } catch (e) {}
-  if (decodeBase58) {
-    if (decodeBase58.version === network.pubKeyHash)
-      return payments.p2pkh({ hash: decodeBase58.hash }).output;
-    if (decodeBase58.version === network.scriptHash)
-      return payments.p2sh({ hash: decodeBase58.hash }).output;
+
+  if (decode) {
+    if (decode.version === network.pubKeyHash) return btemplates.pubKeyHash.output.encode(decode.hash)
+    if (decode.version === network.scriptHash) return btemplates.scriptHash.output.encode(decode.hash)
   } else {
     try {
-      decodeBech32 = fromBech32(address);
+      decode = fromBech32(address)
     } catch (e) {}
-    if (decodeBech32) {
-      if (decodeBech32.prefix !== network.bech32)
-        throw new Error(address + ' has an invalid prefix');
-      if (decodeBech32.version === 0) {
-        if (decodeBech32.data.length === 20)
-          return payments.p2wpkh({ hash: decodeBech32.data }).output;
-        if (decodeBech32.data.length === 32)
-          return payments.p2wsh({ hash: decodeBech32.data }).output;
-      } else if (
-        decodeBech32.version >= FUTURE_SEGWIT_MIN_VERSION &&
-        decodeBech32.version <= FUTURE_SEGWIT_MAX_VERSION &&
-        decodeBech32.data.length >= FUTURE_SEGWIT_MIN_SIZE &&
-        decodeBech32.data.length <= FUTURE_SEGWIT_MAX_SIZE
-      ) {
-        console.warn(FUTURE_SEGWIT_VERSION_WARNING);
-        return bscript.compile([
-          decodeBech32.version + FUTURE_SEGWIT_VERSION_DIFF,
-          decodeBech32.data,
-        ]);
+
+    if (decode) {
+      if (decode.prefix !== network.bech32) throw new Error(address + ' has an invalid prefix')
+      if (decode.version === 0) {
+        if (decode.data.length === 20) return btemplates.witnessPubKeyHash.output.encode(decode.data)
+        if (decode.data.length === 32) return btemplates.witnessScriptHash.output.encode(decode.data)
       }
     }
   }
-  throw new Error(address + ' has no matching Script');
+
+  throw new Error(address + ' has no matching Script')
+}
+
+module.exports = {
+  fromBase58Check: fromBase58Check,
+  fromBech32: fromBech32,
+  fromOutputScript: fromOutputScript,
+  toBase58Check: toBase58Check,
+  toBech32: toBech32,
+  toOutputScript: toOutputScript
 }
-exports.toOutputScript = toOutputScript;
diff --git a/src/bip66.d.ts b/src/bip66.d.ts
deleted file mode 100644
index 547c57f..0000000
--- a/src/bip66.d.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/// <reference types="node" />
-export declare function check(buffer: Buffer): boolean;
-export declare function decode(buffer: Buffer): {
-    r: Buffer;
-    s: Buffer;
-};
-export declare function encode(r: Buffer, s: Buffer): Buffer;
diff --git a/src/bip66.js b/src/bip66.js
deleted file mode 100644
index 0070f99..0000000
--- a/src/bip66.js
+++ /dev/null
@@ -1,102 +0,0 @@
-'use strict';
-// Reference https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
-// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
-// NOTE: SIGHASH byte ignored AND restricted, truncate before use
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.encode = exports.decode = exports.check = void 0;
-function check(buffer) {
-  if (buffer.length < 8) return false;
-  if (buffer.length > 72) return false;
-  if (buffer[0] !== 0x30) return false;
-  if (buffer[1] !== buffer.length - 2) return false;
-  if (buffer[2] !== 0x02) return false;
-  const lenR = buffer[3];
-  if (lenR === 0) return false;
-  if (5 + lenR >= buffer.length) return false;
-  if (buffer[4 + lenR] !== 0x02) return false;
-  const lenS = buffer[5 + lenR];
-  if (lenS === 0) return false;
-  if (6 + lenR + lenS !== buffer.length) return false;
-  if (buffer[4] & 0x80) return false;
-  if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80)) return false;
-  if (buffer[lenR + 6] & 0x80) return false;
-  if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
-    return false;
-  return true;
-}
-exports.check = check;
-function decode(buffer) {
-  if (buffer.length < 8) throw new Error('DER sequence length is too short');
-  if (buffer.length > 72) throw new Error('DER sequence length is too long');
-  if (buffer[0] !== 0x30) throw new Error('Expected DER sequence');
-  if (buffer[1] !== buffer.length - 2)
-    throw new Error('DER sequence length is invalid');
-  if (buffer[2] !== 0x02) throw new Error('Expected DER integer');
-  const lenR = buffer[3];
-  if (lenR === 0) throw new Error('R length is zero');
-  if (5 + lenR >= buffer.length) throw new Error('R length is too long');
-  if (buffer[4 + lenR] !== 0x02) throw new Error('Expected DER integer (2)');
-  const lenS = buffer[5 + lenR];
-  if (lenS === 0) throw new Error('S length is zero');
-  if (6 + lenR + lenS !== buffer.length) throw new Error('S length is invalid');
-  if (buffer[4] & 0x80) throw new Error('R value is negative');
-  if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80))
-    throw new Error('R value excessively padded');
-  if (buffer[lenR + 6] & 0x80) throw new Error('S value is negative');
-  if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
-    throw new Error('S value excessively padded');
-  // non-BIP66 - extract R, S values
-  return {
-    r: buffer.slice(4, 4 + lenR),
-    s: buffer.slice(6 + lenR),
-  };
-}
-exports.decode = decode;
-/*
- * Expects r and s to be positive DER integers.
- *
- * The DER format uses the most significant bit as a sign bit (& 0x80).
- * If the significant bit is set AND the integer is positive, a 0x00 is prepended.
- *
- * Examples:
- *
- *      0 =>     0x00
- *      1 =>     0x01
- *     -1 =>     0xff
- *    127 =>     0x7f
- *   -127 =>     0x81
- *    128 =>   0x0080
- *   -128 =>     0x80
- *    255 =>   0x00ff
- *   -255 =>   0xff01
- *  16300 =>   0x3fac
- * -16300 =>   0xc054
- *  62300 => 0x00f35c
- * -62300 => 0xff0ca4
- */
-function encode(r, s) {
-  const lenR = r.length;
-  const lenS = s.length;
-  if (lenR === 0) throw new Error('R length is zero');
-  if (lenS === 0) throw new Error('S length is zero');
-  if (lenR > 33) throw new Error('R length is too long');
-  if (lenS > 33) throw new Error('S length is too long');
-  if (r[0] & 0x80) throw new Error('R value is negative');
-  if (s[0] & 0x80) throw new Error('S value is negative');
-  if (lenR > 1 && r[0] === 0x00 && !(r[1] & 0x80))
-    throw new Error('R value excessively padded');
-  if (lenS > 1 && s[0] === 0x00 && !(s[1] & 0x80))
-    throw new Error('S value excessively padded');
-  const signature = Buffer.allocUnsafe(6 + lenR + lenS);
-  // 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
-  signature[0] = 0x30;
-  signature[1] = signature.length - 2;
-  signature[2] = 0x02;
-  signature[3] = r.length;
-  r.copy(signature, 4);
-  signature[4 + lenR] = 0x02;
-  signature[5 + lenR] = s.length;
-  s.copy(signature, 6 + lenR);
-  return signature;
-}
-exports.encode = encode;
diff --git a/src/block.d.ts b/src/block.d.ts
deleted file mode 100644
index 1d90c13..0000000
--- a/src/block.d.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/// <reference types="node" />
-import { Transaction } from './transaction';
-export declare class Block {
-    static fromBuffer(buffer: Buffer): Block;
-    static fromHex(hex: string): Block;
-    static calculateTarget(bits: number): Buffer;
-    static calculateMerkleRoot(transactions: Transaction[], forWitness?: boolean): Buffer;
-    version: number;
-    prevHash?: Buffer;
-    merkleRoot?: Buffer;
-    timestamp: number;
-    witnessCommit?: Buffer;
-    bits: number;
-    nonce: number;
-    transactions?: Transaction[];
-    getWitnessCommit(): Buffer | null;
-    hasWitnessCommit(): boolean;
-    hasWitness(): boolean;
-    weight(): number;
-    byteLength(headersOnly?: boolean, allowWitness?: boolean): number;
-    getHash(): Buffer;
-    getId(): string;
-    getUTCDate(): Date;
-    toBuffer(headersOnly?: boolean): Buffer;
-    toHex(headersOnly?: boolean): string;
-    checkTxRoots(): boolean;
-    checkProofOfWork(): boolean;
-    private __checkMerkleRoot;
-    private __checkWitnessCommit;
-}
diff --git a/src/block.js b/src/block.js
index 2c130c3..c545996 100644
--- a/src/block.js
+++ b/src/block.js
@@ -1,220 +1,177 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.Block = void 0;
-const bufferutils_1 = require('./bufferutils');
-const bcrypto = require('./crypto');
-const merkle_1 = require('./merkle');
-const transaction_1 = require('./transaction');
-const types = require('./types');
-const { typeforce } = types;
-const errorMerkleNoTxes = new TypeError(
-  'Cannot compute merkle root for zero transactions',
-);
-const errorWitnessNotSegwit = new TypeError(
-  'Cannot compute witness commit for non-segwit block',
-);
-class Block {
-  constructor() {
-    this.version = 1;
-    this.prevHash = undefined;
-    this.merkleRoot = undefined;
-    this.timestamp = 0;
-    this.witnessCommit = undefined;
-    this.bits = 0;
-    this.nonce = 0;
-    this.transactions = undefined;
-  }
-  static fromBuffer(buffer) {
-    if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)');
-    const bufferReader = new bufferutils_1.BufferReader(buffer);
-    const block = new Block();
-    block.version = bufferReader.readInt32();
-    block.prevHash = bufferReader.readSlice(32);
-    block.merkleRoot = bufferReader.readSlice(32);
-    block.timestamp = bufferReader.readUInt32();
-    block.bits = bufferReader.readUInt32();
-    block.nonce = bufferReader.readUInt32();
-    if (buffer.length === 80) return block;
-    const readTransaction = () => {
-      const tx = transaction_1.Transaction.fromBuffer(
-        bufferReader.buffer.slice(bufferReader.offset),
-        true,
-      );
-      bufferReader.offset += tx.byteLength();
-      return tx;
-    };
-    const nTransactions = bufferReader.readVarInt();
-    block.transactions = [];
-    for (let i = 0; i < nTransactions; ++i) {
-      const tx = readTransaction();
-      block.transactions.push(tx);
-    }
-    const witnessCommit = block.getWitnessCommit();
-    // This Block contains a witness commit
-    if (witnessCommit) block.witnessCommit = witnessCommit;
-    return block;
-  }
-  static fromHex(hex) {
-    return Block.fromBuffer(Buffer.from(hex, 'hex'));
-  }
-  static calculateTarget(bits) {
-    const exponent = ((bits & 0xff000000) >> 24) - 3;
-    const mantissa = bits & 0x007fffff;
-    const target = Buffer.alloc(32, 0);
-    target.writeUIntBE(mantissa, 29 - exponent, 3);
-    return target;
-  }
-  static calculateMerkleRoot(transactions, forWitness) {
-    typeforce([{ getHash: types.Function }], transactions);
-    if (transactions.length === 0) throw errorMerkleNoTxes;
-    if (forWitness && !txesHaveWitnessCommit(transactions))
-      throw errorWitnessNotSegwit;
-    const hashes = transactions.map(transaction =>
-      transaction.getHash(forWitness),
-    );
-    const rootHash = (0, merkle_1.fastMerkleRoot)(hashes, bcrypto.hash256);
-    return forWitness
-      ? bcrypto.hash256(
-          Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]),
-        )
-      : rootHash;
-  }
-  getWitnessCommit() {
-    if (!txesHaveWitnessCommit(this.transactions)) return null;
-    // The merkle root for the witness data is in an OP_RETURN output.
-    // There is no rule for the index of the output, so use filter to find it.
-    // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed
-    // If multiple commits are found, the output with highest index is assumed.
-    const witnessCommits = this.transactions[0].outs
-      .filter(out =>
-        out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')),
-      )
-      .map(out => out.script.slice(6, 38));
-    if (witnessCommits.length === 0) return null;
-    // Use the commit with the highest output (should only be one though)
-    const result = witnessCommits[witnessCommits.length - 1];
-    if (!(result instanceof Buffer && result.length === 32)) return null;
-    return result;
-  }
-  hasWitnessCommit() {
-    if (
-      this.witnessCommit instanceof Buffer &&
-      this.witnessCommit.length === 32
-    )
-      return true;
-    if (this.getWitnessCommit() !== null) return true;
-    return false;
-  }
-  hasWitness() {
-    return anyTxHasWitness(this.transactions);
-  }
-  weight() {
-    const base = this.byteLength(false, false);
-    const total = this.byteLength(false, true);
-    return base * 3 + total;
-  }
-  byteLength(headersOnly, allowWitness = true) {
-    if (headersOnly || !this.transactions) return 80;
-    return (
-      80 +
-      bufferutils_1.varuint.encodingLength(this.transactions.length) +
-      this.transactions.reduce((a, x) => a + x.byteLength(allowWitness), 0)
-    );
-  }
-  getHash() {
-    return bcrypto.hash256(this.toBuffer(true));
-  }
-  getId() {
-    return (0, bufferutils_1.reverseBuffer)(this.getHash()).toString('hex');
-  }
-  getUTCDate() {
-    const date = new Date(0); // epoch
-    date.setUTCSeconds(this.timestamp);
-    return date;
-  }
-  // TODO: buffer, offset compatibility
-  toBuffer(headersOnly) {
-    const buffer = Buffer.allocUnsafe(this.byteLength(headersOnly));
-    const bufferWriter = new bufferutils_1.BufferWriter(buffer);
-    bufferWriter.writeInt32(this.version);
-    bufferWriter.writeSlice(this.prevHash);
-    bufferWriter.writeSlice(this.merkleRoot);
-    bufferWriter.writeUInt32(this.timestamp);
-    bufferWriter.writeUInt32(this.bits);
-    bufferWriter.writeUInt32(this.nonce);
-    if (headersOnly || !this.transactions) return buffer;
-    bufferutils_1.varuint.encode(
-      this.transactions.length,
-      buffer,
-      bufferWriter.offset,
-    );
-    bufferWriter.offset += bufferutils_1.varuint.encode.bytes;
-    this.transactions.forEach(tx => {
-      const txSize = tx.byteLength(); // TODO: extract from toBuffer?
-      tx.toBuffer(buffer, bufferWriter.offset);
-      bufferWriter.offset += txSize;
-    });
-    return buffer;
-  }
-  toHex(headersOnly) {
-    return this.toBuffer(headersOnly).toString('hex');
-  }
-  checkTxRoots() {
-    // If the Block has segwit transactions but no witness commit,
-    // there's no way it can be valid, so fail the check.
-    const hasWitnessCommit = this.hasWitnessCommit();
-    if (!hasWitnessCommit && this.hasWitness()) return false;
-    return (
-      this.__checkMerkleRoot() &&
-      (hasWitnessCommit ? this.__checkWitnessCommit() : true)
-    );
-  }
-  checkProofOfWork() {
-    const hash = (0, bufferutils_1.reverseBuffer)(this.getHash());
-    const target = Block.calculateTarget(this.bits);
-    return hash.compare(target) <= 0;
-  }
-  __checkMerkleRoot() {
-    if (!this.transactions) throw errorMerkleNoTxes;
-    const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions);
-    return this.merkleRoot.compare(actualMerkleRoot) === 0;
-  }
-  __checkWitnessCommit() {
-    if (!this.transactions) throw errorMerkleNoTxes;
-    if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit;
-    const actualWitnessCommit = Block.calculateMerkleRoot(
-      this.transactions,
-      true,
-    );
-    return this.witnessCommit.compare(actualWitnessCommit) === 0;
-  }
+var Buffer = require('safe-buffer').Buffer
+var bcrypto = require('./crypto')
+var fastMerkleRoot = require('merkle-lib/fastRoot')
+var typeforce = require('typeforce')
+var types = require('./types')
+var varuint = require('varuint-bitcoin')
+
+var Transaction = require('./transaction')
+
+function Block () {
+  this.version = 1
+  this.prevHash = null
+  this.merkleRoot = null
+  this.timestamp = 0
+  this.bits = 0
+  this.nonce = 0
 }
-exports.Block = Block;
-function txesHaveWitnessCommit(transactions) {
-  return (
-    transactions instanceof Array &&
-    transactions[0] &&
-    transactions[0].ins &&
-    transactions[0].ins instanceof Array &&
-    transactions[0].ins[0] &&
-    transactions[0].ins[0].witness &&
-    transactions[0].ins[0].witness instanceof Array &&
-    transactions[0].ins[0].witness.length > 0
-  );
+
+Block.fromBuffer = function (buffer) {
+  if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)')
+
+  var offset = 0
+  function readSlice (n) {
+    offset += n
+    return buffer.slice(offset - n, offset)
+  }
+
+  function readUInt32 () {
+    var i = buffer.readUInt32LE(offset)
+    offset += 4
+    return i
+  }
+
+  function readInt32 () {
+    var i = buffer.readInt32LE(offset)
+    offset += 4
+    return i
+  }
+
+  var block = new Block()
+  block.version = readInt32()
+  block.prevHash = readSlice(32)
+  block.merkleRoot = readSlice(32)
+  block.timestamp = readUInt32()
+  block.bits = readUInt32()
+  block.nonce = readUInt32()
+
+  if (buffer.length === 80) return block
+
+  function readVarInt () {
+    var vi = varuint.decode(buffer, offset)
+    offset += varuint.decode.bytes
+    return vi
+  }
+
+  function readTransaction () {
+    var tx = Transaction.fromBuffer(buffer.slice(offset), true)
+    offset += tx.byteLength()
+    return tx
+  }
+
+  var nTransactions = readVarInt()
+  block.transactions = []
+
+  for (var i = 0; i < nTransactions; ++i) {
+    var tx = readTransaction()
+    block.transactions.push(tx)
+  }
+
+  return block
 }
-function anyTxHasWitness(transactions) {
-  return (
-    transactions instanceof Array &&
-    transactions.some(
-      tx =>
-        typeof tx === 'object' &&
-        tx.ins instanceof Array &&
-        tx.ins.some(
-          input =>
-            typeof input === 'object' &&
-            input.witness instanceof Array &&
-            input.witness.length > 0,
-        ),
-    )
-  );
+
+Block.prototype.byteLength = function (headersOnly) {
+  if (headersOnly || !this.transactions) return 80
+
+  return 80 + varuint.encodingLength(this.transactions.length) + this.transactions.reduce(function (a, x) {
+    return a + x.byteLength()
+  }, 0)
 }
+
+Block.fromHex = function (hex) {
+  return Block.fromBuffer(Buffer.from(hex, 'hex'))
+}
+
+Block.prototype.getHash = function () {
+  return bcrypto.hash256(this.toBuffer(true))
+}
+
+Block.prototype.getId = function () {
+  return this.getHash().reverse().toString('hex')
+}
+
+Block.prototype.getUTCDate = function () {
+  var date = new Date(0) // epoch
+  date.setUTCSeconds(this.timestamp)
+
+  return date
+}
+
+// TODO: buffer, offset compatibility
+Block.prototype.toBuffer = function (headersOnly) {
+  var buffer = Buffer.allocUnsafe(this.byteLength(headersOnly))
+
+  var offset = 0
+  function writeSlice (slice) {
+    slice.copy(buffer, offset)
+    offset += slice.length
+  }
+
+  function writeInt32 (i) {
+    buffer.writeInt32LE(i, offset)
+    offset += 4
+  }
+  function writeUInt32 (i) {
+    buffer.writeUInt32LE(i, offset)
+    offset += 4
+  }
+
+  writeInt32(this.version)
+  writeSlice(this.prevHash)
+  writeSlice(this.merkleRoot)
+  writeUInt32(this.timestamp)
+  writeUInt32(this.bits)
+  writeUInt32(this.nonce)
+
+  if (headersOnly || !this.transactions) return buffer
+
+  varuint.encode(this.transactions.length, buffer, offset)
+  offset += varuint.encode.bytes
+
+  this.transactions.forEach(function (tx) {
+    var txSize = tx.byteLength() // TODO: extract from toBuffer?
+    tx.toBuffer(buffer, offset)
+    offset += txSize
+  })
+
+  return buffer
+}
+
+Block.prototype.toHex = function (headersOnly) {
+  return this.toBuffer(headersOnly).toString('hex')
+}
+
+Block.calculateTarget = function (bits) {
+  var exponent = ((bits & 0xff000000) >> 24) - 3
+  var mantissa = bits & 0x007fffff
+  var target = Buffer.alloc(32, 0)
+  target.writeUInt32BE(mantissa, 28 - exponent)
+  return target
+}
+
+Block.calculateMerkleRoot = function (transactions) {
+  typeforce([{ getHash: types.Function }], transactions)
+  if (transactions.length === 0) throw TypeError('Cannot compute merkle root for zero transactions')
+
+  var hashes = transactions.map(function (transaction) {
+    return transaction.getHash()
+  })
+
+  return fastMerkleRoot(hashes, bcrypto.hash256)
+}
+
+Block.prototype.checkMerkleRoot = function () {
+  if (!this.transactions) return false
+
+  var actualMerkleRoot = Block.calculateMerkleRoot(this.transactions)
+  return this.merkleRoot.compare(actualMerkleRoot) === 0
+}
+
+Block.prototype.checkProofOfWork = function () {
+  var hash = this.getHash().reverse()
+  var target = Block.calculateTarget(this.bits)
+
+  return hash.compare(target) <= 0
+}
+
+module.exports = Block
diff --git a/src/bufferutils.d.ts b/src/bufferutils.d.ts
deleted file mode 100644
index b1d8966..0000000
--- a/src/bufferutils.d.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-/// <reference types="node" />
-import * as varuint from 'varuint-bitcoin';
-export { varuint };
-export declare function readUInt64LE(buffer: Buffer, offset: number): number;
-export declare function writeUInt64LE(buffer: Buffer, value: number, offset: number): number;
-export declare function reverseBuffer(buffer: Buffer): Buffer;
-export declare function cloneBuffer(buffer: Buffer): Buffer;
-/**
- * Helper class for serialization of bitcoin data types into a pre-allocated buffer.
- */
-export declare class BufferWriter {
-    buffer: Buffer;
-    offset: number;
-    static withCapacity(size: number): BufferWriter;
-    constructor(buffer: Buffer, offset?: number);
-    writeUInt8(i: number): void;
-    writeInt32(i: number): void;
-    writeUInt32(i: number): void;
-    writeUInt64(i: number): void;
-    writeVarInt(i: number): void;
-    writeSlice(slice: Buffer): void;
-    writeVarSlice(slice: Buffer): void;
-    writeVector(vector: Buffer[]): void;
-    end(): Buffer;
-}
-/**
- * Helper class for reading of bitcoin data types from a buffer.
- */
-export declare class BufferReader {
-    buffer: Buffer;
-    offset: number;
-    constructor(buffer: Buffer, offset?: number);
-    readUInt8(): number;
-    readInt32(): number;
-    readUInt32(): number;
-    readUInt64(): number;
-    readVarInt(): number;
-    readSlice(n: number): Buffer;
-    readVarSlice(): Buffer;
-    readVector(): Buffer[];
-}
diff --git a/src/bufferutils.js b/src/bufferutils.js
index 83a013b..179e84e 100644
--- a/src/bufferutils.js
+++ b/src/bufferutils.js
@@ -1,154 +1,56 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.BufferReader = exports.BufferWriter = exports.cloneBuffer = exports.reverseBuffer = exports.writeUInt64LE = exports.readUInt64LE = exports.varuint = void 0;
-const types = require('./types');
-const { typeforce } = types;
-const varuint = require('varuint-bitcoin');
-exports.varuint = varuint;
+var pushdata = require('pushdata-bitcoin')
+var varuint = require('varuint-bitcoin')
+
 // https://github.com/feross/buffer/blob/master/index.js#L1127
-function verifuint(value, max) {
-  if (typeof value !== 'number')
-    throw new Error('cannot write a non-number as a number');
-  if (value < 0)
-    throw new Error('specified a negative value for writing an unsigned value');
-  if (value > max) throw new Error('RangeError: value out of range');
-  if (Math.floor(value) !== value)
-    throw new Error('value has a fractional component');
+function verifuint (value, max) {
+  if (typeof value !== 'number') throw new Error('cannot write a non-number as a number')
+  if (value < 0) throw new Error('specified a negative value for writing an unsigned value')
+  if (value > max) throw new Error('RangeError: value out of range')
+  if (Math.floor(value) !== value) throw new Error('value has a fractional component')
 }
-function readUInt64LE(buffer, offset) {
-  const a = buffer.readUInt32LE(offset);
-  let b = buffer.readUInt32LE(offset + 4);
-  b *= 0x100000000;
-  verifuint(b + a, 0x001fffffffffffff);
-  return b + a;
+
+function readUInt64LE (buffer, offset) {
+  var a = buffer.readUInt32LE(offset)
+  var b = buffer.readUInt32LE(offset + 4)
+  b *= 0x100000000
+
+  verifuint(b + a, 0x001fffffffffffff)
+
+  return b + a
 }
-exports.readUInt64LE = readUInt64LE;
-function writeUInt64LE(buffer, value, offset) {
-  verifuint(value, 0x001fffffffffffff);
-  buffer.writeInt32LE(value & -1, offset);
-  buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4);
-  return offset + 8;
+
+function writeUInt64LE (buffer, value, offset) {
+  verifuint(value, 0x001fffffffffffff)
+
+  buffer.writeInt32LE(value & -1, offset)
+  buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4)
+  return offset + 8
 }
-exports.writeUInt64LE = writeUInt64LE;
-function reverseBuffer(buffer) {
-  if (buffer.length < 1) return buffer;
-  let j = buffer.length - 1;
-  let tmp = 0;
-  for (let i = 0; i < buffer.length / 2; i++) {
-    tmp = buffer[i];
-    buffer[i] = buffer[j];
-    buffer[j] = tmp;
-    j--;
-  }
-  return buffer;
-}
-exports.reverseBuffer = reverseBuffer;
-function cloneBuffer(buffer) {
-  const clone = Buffer.allocUnsafe(buffer.length);
-  buffer.copy(clone);
-  return clone;
-}
-exports.cloneBuffer = cloneBuffer;
-/**
- * Helper class for serialization of bitcoin data types into a pre-allocated buffer.
- */
-class BufferWriter {
-  constructor(buffer, offset = 0) {
-    this.buffer = buffer;
-    this.offset = offset;
-    typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]);
-  }
-  static withCapacity(size) {
-    return new BufferWriter(Buffer.alloc(size));
-  }
-  writeUInt8(i) {
-    this.offset = this.buffer.writeUInt8(i, this.offset);
-  }
-  writeInt32(i) {
-    this.offset = this.buffer.writeInt32LE(i, this.offset);
-  }
-  writeUInt32(i) {
-    this.offset = this.buffer.writeUInt32LE(i, this.offset);
-  }
-  writeUInt64(i) {
-    this.offset = writeUInt64LE(this.buffer, i, this.offset);
-  }
-  writeVarInt(i) {
-    varuint.encode(i, this.buffer, this.offset);
-    this.offset += varuint.encode.bytes;
-  }
-  writeSlice(slice) {
-    if (this.buffer.length < this.offset + slice.length) {
-      throw new Error('Cannot write slice out of bounds');
-    }
-    this.offset += slice.copy(this.buffer, this.offset);
-  }
-  writeVarSlice(slice) {
-    this.writeVarInt(slice.length);
-    this.writeSlice(slice);
-  }
-  writeVector(vector) {
-    this.writeVarInt(vector.length);
-    vector.forEach(buf => this.writeVarSlice(buf));
-  }
-  end() {
-    if (this.buffer.length === this.offset) {
-      return this.buffer;
-    }
-    throw new Error(`buffer size ${this.buffer.length}, offset ${this.offset}`);
+
+// TODO: remove in 4.0.0?
+function readVarInt (buffer, offset) {
+  var result = varuint.decode(buffer, offset)
+
+  return {
+    number: result,
+    size: varuint.decode.bytes
   }
 }
-exports.BufferWriter = BufferWriter;
-/**
- * Helper class for reading of bitcoin data types from a buffer.
- */
-class BufferReader {
-  constructor(buffer, offset = 0) {
-    this.buffer = buffer;
-    this.offset = offset;
-    typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]);
-  }
-  readUInt8() {
-    const result = this.buffer.readUInt8(this.offset);
-    this.offset++;
-    return result;
-  }
-  readInt32() {
-    const result = this.buffer.readInt32LE(this.offset);
-    this.offset += 4;
-    return result;
-  }
-  readUInt32() {
-    const result = this.buffer.readUInt32LE(this.offset);
-    this.offset += 4;
-    return result;
-  }
-  readUInt64() {
-    const result = readUInt64LE(this.buffer, this.offset);
-    this.offset += 8;
-    return result;
-  }
-  readVarInt() {
-    const vi = varuint.decode(this.buffer, this.offset);
-    this.offset += varuint.decode.bytes;
-    return vi;
-  }
-  readSlice(n) {
-    if (this.buffer.length < this.offset + n) {
-      throw new Error('Cannot read slice out of bounds');
-    }
-    const result = this.buffer.slice(this.offset, this.offset + n);
-    this.offset += n;
-    return result;
-  }
-  readVarSlice() {
-    return this.readSlice(this.readVarInt());
-  }
-  readVector() {
-    const count = this.readVarInt();
-    const vector = [];
-    for (let i = 0; i < count; i++) vector.push(this.readVarSlice());
-    return vector;
-  }
+
+// TODO: remove in 4.0.0?
+function writeVarInt (buffer, number, offset) {
+  varuint.encode(number, buffer, offset)
+  return varuint.encode.bytes
+}
+
+module.exports = {
+  pushDataSize: pushdata.encodingLength,
+  readPushDataInt: pushdata.decode,
+  readUInt64LE: readUInt64LE,
+  readVarInt: readVarInt,
+  varIntBuffer: varuint.encode,
+  varIntSize: varuint.encodingLength,
+  writePushDataInt: pushdata.encode,
+  writeUInt64LE: writeUInt64LE,
+  writeVarInt: writeVarInt
 }
-exports.BufferReader = BufferReader;
diff --git a/src/crypto.d.ts b/src/crypto.d.ts
deleted file mode 100644
index ec088f3..0000000
--- a/src/crypto.d.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-/// <reference types="node" />
-export declare function ripemd160(buffer: Buffer): Buffer;
-export declare function sha1(buffer: Buffer): Buffer;
-export declare function sha256(buffer: Buffer): Buffer;
-export declare function hash160(buffer: Buffer): Buffer;
-export declare function hash256(buffer: Buffer): Buffer;
-declare const TAGS: readonly ["BIP0340/challenge", "BIP0340/aux", "BIP0340/nonce", "TapLeaf", "TapBranch", "TapSighash", "TapTweak", "KeyAgg list", "KeyAgg coefficient"];
-export declare type TaggedHashPrefix = typeof TAGS[number];
-export declare function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer;
-export {};
diff --git a/src/crypto.js b/src/crypto.js
index 3c308da..1bb39f1 100644
--- a/src/crypto.js
+++ b/src/crypto.js
@@ -1,58 +1,29 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.taggedHash = exports.hash256 = exports.hash160 = exports.sha256 = exports.sha1 = exports.ripemd160 = void 0;
-const createHash = require('create-hash');
-function ripemd160(buffer) {
-  try {
-    return createHash('rmd160')
-      .update(buffer)
-      .digest();
-  } catch (err) {
-    return createHash('ripemd160')
-      .update(buffer)
-      .digest();
-  }
+var createHash = require('create-hash')
+
+function ripemd160 (buffer) {
+  return createHash('rmd160').update(buffer).digest()
 }
-exports.ripemd160 = ripemd160;
-function sha1(buffer) {
-  return createHash('sha1')
-    .update(buffer)
-    .digest();
+
+function sha1 (buffer) {
+  return createHash('sha1').update(buffer).digest()
 }
-exports.sha1 = sha1;
-function sha256(buffer) {
-  return createHash('sha256')
-    .update(buffer)
-    .digest();
+
+function sha256 (buffer) {
+  return createHash('sha256').update(buffer).digest()
 }
-exports.sha256 = sha256;
-function hash160(buffer) {
-  return ripemd160(sha256(buffer));
+
+function hash160 (buffer) {
+  return ripemd160(sha256(buffer))
 }
-exports.hash160 = hash160;
-function hash256(buffer) {
-  return sha256(sha256(buffer));
+
+function hash256 (buffer) {
+  return sha256(sha256(buffer))
 }
-exports.hash256 = hash256;
-const TAGS = [
-  'BIP0340/challenge',
-  'BIP0340/aux',
-  'BIP0340/nonce',
-  'TapLeaf',
-  'TapBranch',
-  'TapSighash',
-  'TapTweak',
-  'KeyAgg list',
-  'KeyAgg coefficient',
-];
-/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
-const TAGGED_HASH_PREFIXES = Object.fromEntries(
-  TAGS.map(tag => {
-    const tagHash = sha256(Buffer.from(tag));
-    return [tag, Buffer.concat([tagHash, tagHash])];
-  }),
-);
-function taggedHash(prefix, data) {
-  return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data]));
+
+module.exports = {
+  hash160: hash160,
+  hash256: hash256,
+  ripemd160: ripemd160,
+  sha1: sha1,
+  sha256: sha256
 }
-exports.taggedHash = taggedHash;
diff --git a/src/ecdsa.js b/src/ecdsa.js
new file mode 100644
index 0000000..8841f6e
--- /dev/null
+++ b/src/ecdsa.js
@@ -0,0 +1,161 @@
+var Buffer = require('safe-buffer').Buffer
+var createHmac = require('create-hmac')
+var typeforce = require('typeforce')
+var types = require('./types')
+
+var BigInteger = require('bigi')
+var ECSignature = require('./ecsignature')
+
+var ZERO = Buffer.alloc(1, 0)
+var ONE = Buffer.alloc(1, 1)
+
+var ecurve = require('ecurve')
+var secp256k1 = ecurve.getCurveByName('secp256k1')
+
+// https://tools.ietf.org/html/rfc6979#section-3.2
+function deterministicGenerateK (hash, x, checkSig) {
+  typeforce(types.tuple(
+    types.Hash256bit,
+    types.Buffer256bit,
+    types.Function
+  ), arguments)
+
+  // Step A, ignored as hash already provided
+  // Step B
+  // Step C
+  var k = Buffer.alloc(32, 0)
+  var v = Buffer.alloc(32, 1)
+
+  // Step D
+  k = createHmac('sha256', k)
+    .update(v)
+    .update(ZERO)
+    .update(x)
+    .update(hash)
+    .digest()
+
+  // Step E
+  v = createHmac('sha256', k).update(v).digest()
+
+  // Step F
+  k = createHmac('sha256', k)
+    .update(v)
+    .update(ONE)
+    .update(x)
+    .update(hash)
+    .digest()
+
+  // Step G
+  v = createHmac('sha256', k).update(v).digest()
+
+  // Step H1/H2a, ignored as tlen === qlen (256 bit)
+  // Step H2b
+  v = createHmac('sha256', k).update(v).digest()
+
+  var T = BigInteger.fromBuffer(v)
+
+  // Step H3, repeat until T is within the interval [1, n - 1] and is suitable for ECDSA
+  while (T.signum() <= 0 || T.compareTo(secp256k1.n) >= 0 || !checkSig(T)) {
+    k = createHmac('sha256', k)
+      .update(v)
+      .update(ZERO)
+      .digest()
+
+    v = createHmac('sha256', k).update(v).digest()
+
+    // Step H1/H2a, again, ignored as tlen === qlen (256 bit)
+    // Step H2b again
+    v = createHmac('sha256', k).update(v).digest()
+    T = BigInteger.fromBuffer(v)
+  }
+
+  return T
+}
+
+var N_OVER_TWO = secp256k1.n.shiftRight(1)
+
+function sign (hash, d) {
+  typeforce(types.tuple(types.Hash256bit, types.BigInt), arguments)
+
+  var x = d.toBuffer(32)
+  var e = BigInteger.fromBuffer(hash)
+  var n = secp256k1.n
+  var G = secp256k1.G
+
+  var r, s
+  deterministicGenerateK(hash, x, function (k) {
+    var Q = G.multiply(k)
+
+    if (secp256k1.isInfinity(Q)) return false
+
+    r = Q.affineX.mod(n)
+    if (r.signum() === 0) return false
+
+    s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n)
+    if (s.signum() === 0) return false
+
+    return true
+  })
+
+  // enforce low S values, see bip62: 'low s values in signatures'
+  if (s.compareTo(N_OVER_TWO) > 0) {
+    s = n.subtract(s)
+  }
+
+  return new ECSignature(r, s)
+}
+
+function verify (hash, signature, Q) {
+  typeforce(types.tuple(
+    types.Hash256bit,
+    types.ECSignature,
+    types.ECPoint
+  ), arguments)
+
+  var n = secp256k1.n
+  var G = secp256k1.G
+
+  var r = signature.r
+  var s = signature.s
+
+  // 1.4.1 Enforce r and s are both integers in the interval [1, n − 1]
+  if (r.signum() <= 0 || r.compareTo(n) >= 0) return false
+  if (s.signum() <= 0 || s.compareTo(n) >= 0) return false
+
+  // 1.4.2 H = Hash(M), already done by the user
+  // 1.4.3 e = H
+  var e = BigInteger.fromBuffer(hash)
+
+  // Compute s^-1
+  var sInv = s.modInverse(n)
+
+  // 1.4.4 Compute u1 = es^−1 mod n
+  //               u2 = rs^−1 mod n
+  var u1 = e.multiply(sInv).mod(n)
+  var u2 = r.multiply(sInv).mod(n)
+
+  // 1.4.5 Compute R = (xR, yR)
+  //               R = u1G + u2Q
+  var R = G.multiplyTwo(u1, Q, u2)
+
+  // 1.4.5 (cont.) Enforce R is not at infinity
+  if (secp256k1.isInfinity(R)) return false
+
+  // 1.4.6 Convert the field element R.x to an integer
+  var xR = R.affineX
+
+  // 1.4.7 Set v = xR mod n
+  var v = xR.mod(n)
+
+  // 1.4.8 If v = r, output "valid", and if v != r, output "invalid"
+  return v.equals(r)
+}
+
+module.exports = {
+  deterministicGenerateK: deterministicGenerateK,
+  sign: sign,
+  verify: verify,
+
+  // TODO: remove
+  __curve: secp256k1
+}
diff --git a/src/ecpair.js b/src/ecpair.js
new file mode 100644
index 0000000..960f270
--- /dev/null
+++ b/src/ecpair.js
@@ -0,0 +1,131 @@
+var baddress = require('./address')
+var bcrypto = require('./crypto')
+var ecdsa = require('./ecdsa')
+var randomBytes = require('randombytes')
+var typeforce = require('typeforce')
+var types = require('./types')
+var wif = require('wif')
+
+var NETWORKS = require('./networks')
+var BigInteger = require('bigi')
+
+var ecurve = require('ecurve')
+var secp256k1 = ecdsa.__curve
+
+function ECPair (d, Q, options) {
+  if (options) {
+    typeforce({
+      compressed: types.maybe(types.Boolean),
+      network: types.maybe(types.Network)
+    }, options)
+  }
+
+  options = options || {}
+
+  if (d) {
+    if (d.signum() <= 0) throw new Error('Private key must be greater than 0')
+    if (d.compareTo(secp256k1.n) >= 0) throw new Error('Private key must be less than the curve order')
+    if (Q) throw new TypeError('Unexpected publicKey parameter')
+
+    this.d = d
+  } else {
+    typeforce(types.ECPoint, Q)
+
+    this.__Q = Q
+  }
+
+  this.compressed = options.compressed === undefined ? true : options.compressed
+  this.network = options.network || NETWORKS.bitcoin
+}
+
+Object.defineProperty(ECPair.prototype, 'Q', {
+  get: function () {
+    if (!this.__Q && this.d) {
+      this.__Q = secp256k1.G.multiply(this.d)
+    }
+
+    return this.__Q
+  }
+})
+
+ECPair.fromPublicKeyBuffer = function (buffer, network) {
+  var Q = ecurve.Point.decodeFrom(secp256k1, buffer)
+
+  return new ECPair(null, Q, {
+    compressed: Q.compressed,
+    network: network
+  })
+}
+
+ECPair.fromWIF = function (string, network) {
+  var decoded = wif.decode(string)
+  var version = decoded.version
+
+  // list of networks?
+  if (types.Array(network)) {
+    network = network.filter(function (x) {
+      return version === x.wif
+    }).pop()
+
+    if (!network) throw new Error('Unknown network version')
+
+  // otherwise, assume a network object (or default to bitcoin)
+  } else {
+    network = network || NETWORKS.bitcoin
+
+    if (version !== network.wif) throw new Error('Invalid network version')
+  }
+
+  var d = BigInteger.fromBuffer(decoded.privateKey)
+
+  return new ECPair(d, null, {
+    compressed: decoded.compressed,
+    network: network
+  })
+}
+
+ECPair.makeRandom = function (options) {
+  options = options || {}
+
+  var rng = options.rng || randomBytes
+
+  var d
+  do {
+    var buffer = rng(32)
+    typeforce(types.Buffer256bit, buffer)
+
+    d = BigInteger.fromBuffer(buffer)
+  } while (d.signum() <= 0 || d.compareTo(secp256k1.n) >= 0)
+
+  return new ECPair(d, null, options)
+}
+
+ECPair.prototype.getAddress = function () {
+  return baddress.toBase58Check(bcrypto.hash160(this.getPublicKeyBuffer()), this.getNetwork().pubKeyHash)
+}
+
+ECPair.prototype.getNetwork = function () {
+  return this.network
+}
+
+ECPair.prototype.getPublicKeyBuffer = function () {
+  return this.Q.getEncoded(this.compressed)
+}
+
+ECPair.prototype.sign = function (hash) {
+  if (!this.d) throw new Error('Missing private key')
+
+  return ecdsa.sign(hash, this.d)
+}
+
+ECPair.prototype.toWIF = function () {
+  if (!this.d) throw new Error('Missing private key')
+
+  return wif.encode(this.network.wif, this.d.toBuffer(32), this.compressed)
+}
+
+ECPair.prototype.verify = function (hash, signature) {
+  return ecdsa.verify(hash, signature, this.Q)
+}
+
+module.exports = ECPair
diff --git a/src/ecsignature.js b/src/ecsignature.js
new file mode 100644
index 0000000..ebdcc36
--- /dev/null
+++ b/src/ecsignature.js
@@ -0,0 +1,97 @@
+var bip66 = require('bip66')
+var typeforce = require('typeforce')
+var types = require('./types')
+
+var BigInteger = require('bigi')
+
+function ECSignature (r, s) {
+  typeforce(types.tuple(types.BigInt, types.BigInt), arguments)
+
+  this.r = r
+  this.s = s
+}
+
+ECSignature.parseCompact = function (buffer) {
+  typeforce(types.BufferN(65), buffer)
+
+  var flagByte = buffer.readUInt8(0) - 27
+  if (flagByte !== (flagByte & 7)) throw new Error('Invalid signature parameter')
+
+  var compressed = !!(flagByte & 4)
+  var recoveryParam = flagByte & 3
+  var signature = ECSignature.fromRSBuffer(buffer.slice(1))
+
+  return {
+    compressed: compressed,
+    i: recoveryParam,
+    signature: signature
+  }
+}
+
+ECSignature.fromRSBuffer = function (buffer) {
+  typeforce(types.BufferN(64), buffer)
+
+  var r = BigInteger.fromBuffer(buffer.slice(0, 32))
+  var s = BigInteger.fromBuffer(buffer.slice(32, 64))
+  return new ECSignature(r, s)
+}
+
+ECSignature.fromDER = function (buffer) {
+  var decode = bip66.decode(buffer)
+  var r = BigInteger.fromDERInteger(decode.r)
+  var s = BigInteger.fromDERInteger(decode.s)
+
+  return new ECSignature(r, s)
+}
+
+// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed)
+ECSignature.parseScriptSignature = function (buffer) {
+  var hashType = buffer.readUInt8(buffer.length - 1)
+  var hashTypeMod = hashType & ~0x80
+
+  if (hashTypeMod <= 0x00 || hashTypeMod >= 0x04) throw new Error('Invalid hashType ' + hashType)
+
+  return {
+    signature: ECSignature.fromDER(buffer.slice(0, -1)),
+    hashType: hashType
+  }
+}
+
+ECSignature.prototype.toCompact = function (i, compressed) {
+  if (compressed) {
+    i += 4
+  }
+
+  i += 27
+
+  var buffer = Buffer.alloc(65)
+  buffer.writeUInt8(i, 0)
+  this.toRSBuffer(buffer, 1)
+  return buffer
+}
+
+ECSignature.prototype.toDER = function () {
+  var r = Buffer.from(this.r.toDERInteger())
+  var s = Buffer.from(this.s.toDERInteger())
+
+  return bip66.encode(r, s)
+}
+
+ECSignature.prototype.toRSBuffer = function (buffer, offset) {
+  buffer = buffer || Buffer.alloc(64)
+  this.r.toBuffer(32).copy(buffer, offset)
+  this.s.toBuffer(32).copy(buffer, offset + 32)
+  return buffer
+}
+
+ECSignature.prototype.toScriptSignature = function (hashType) {
+  var hashTypeMod = hashType & ~0x80
+  if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType)
+
+  var hashTypeBuffer = Buffer.alloc(1)
+  hashTypeBuffer.writeUInt8(hashType, 0)
+
+  return Buffer.concat([this.toDER(), hashTypeBuffer])
+}
+
+module.exports = ECSignature
diff --git a/src/hdnode.js b/src/hdnode.js
new file mode 100644
index 0000000..5ab8ffe
--- /dev/null
+++ b/src/hdnode.js
@@ -0,0 +1,346 @@
+var Buffer = require('safe-buffer').Buffer
+var base58check = require('bs58check')
+var bcrypto = require('./crypto')
+var baddress = require('./address')
+var createHmac = require('create-hmac')
+var typeforce = require('typeforce')
+var types = require('./types')
+var NETWORKS = require('./networks')
+
+var BigInteger = require('bigi')
+var ECPair = require('./ecpair')
+
+// var KeyToScript = require('./keytoscript')
+var ecurve = require('ecurve')
+var curve = ecurve.getCurveByName('secp256k1')
+
+function HDNode (keyPair, chainCode, prefix) {
+  typeforce(types.tuple('ECPair', types.Buffer256bit), arguments)
+  if (!prefix) {
+    prefix = keyPair.network.bip32
+  }
+  if (!keyPair.compressed) throw new TypeError('BIP32 only allows compressed keyPairs')
+
+  this.keyPair = keyPair
+  this.chainCode = chainCode
+  this.depth = 0
+  this.index = 0
+  this.parentFingerprint = 0x00000000
+  this.prefix = prefix
+}
+
+HDNode.HIGHEST_BIT = 0x80000000
+HDNode.LENGTH = 78
+HDNode.MASTER_SECRET = Buffer.from('Bitcoin seed', 'utf8')
+
+HDNode.fromSeedBuffer = function (seed, network, prefix) {
+  typeforce(types.tuple(types.Buffer, types.maybe(types.Network)), arguments)
+
+  if (seed.length < 16) throw new TypeError('Seed should be at least 128 bits')
+  if (seed.length > 64) throw new TypeError('Seed should be at most 512 bits')
+
+  var I = createHmac('sha512', HDNode.MASTER_SECRET).update(seed).digest()
+  var IL = I.slice(0, 32)
+  var IR = I.slice(32)
+
+  // In case IL is 0 or >= n, the master key is invalid
+  // This is handled by the ECPair constructor
+  var pIL = BigInteger.fromBuffer(IL)
+  var keyPair = new ECPair(pIL, null, {
+    network: network
+  })
+
+  return new HDNode(keyPair, IR, prefix)
+}
+
+HDNode.fromSeedHex = function (hex, network, prefix) {
+  return HDNode.fromSeedBuffer(Buffer.from(hex, 'hex'), network, prefix)
+}
+
+/**
+ *
+ * @param {string} string
+ * @param {Array<network>|network} networks
+ * @param {Array<prefix>} prefixes - only used if networks is object/undefined(so bitcoin).
+ * @returns {HDNode}
+ */
+HDNode.fromBase58 = function (string, networks, prefixes) {
+  var buffer = base58check.decode(string)
+  if (buffer.length !== 78) throw new Error('Invalid buffer length')
+
+  // 4 bytes: version bytes
+  var version = buffer.readUInt32BE(0)
+  var network
+
+  // list of networks?
+  var prefix
+  if (Array.isArray(networks)) {
+    network = networks.filter(function (x) {
+      return version === x.bip32.private ||
+             version === x.bip32.public
+    }).pop()
+
+    if (!network) throw new Error('Unknown network version')
+
+    // we found a network by it's bip32 prefixes, use that
+    prefix = network.bip32
+
+  // otherwise, assume a network object (or default to bitcoin)
+  } else {
+    network = networks || NETWORKS.bitcoin
+    if (prefixes) {
+      prefix = prefixes.filter(function (x) {
+        return version === x.private ||
+               version === x.public
+      }).pop()
+    } else {
+      // no special prefixes to consider, use networks bip32 prefix
+      prefix = network.bip32
+    }
+  }
+
+  // sanity check the version against the prefix
+  if (version !== prefix.private &&
+    version !== prefix.public) throw new Error('Invalid network version')
+
+  // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ...
+  var depth = buffer[4]
+
+  // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
+  var parentFingerprint = buffer.readUInt32BE(5)
+  if (depth === 0) {
+    if (parentFingerprint !== 0x00000000) throw new Error('Invalid parent fingerprint')
+  }
+
+  // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized.
+  // This is encoded in MSB order. (0x00000000 if master key)
+  var index = buffer.readUInt32BE(9)
+  if (depth === 0 && index !== 0) throw new Error('Invalid index')
+
+  // 32 bytes: the chain code
+  var chainCode = buffer.slice(13, 45)
+  var keyPair
+
+  // 33 bytes: private key data (0x00 + k)
+  if (version === network.bip32.private) {
+    if (buffer.readUInt8(45) !== 0x00) throw new Error('Invalid private key')
+
+    var d = BigInteger.fromBuffer(buffer.slice(46, 78))
+    keyPair = new ECPair(d, null, { network: network })
+
+  // 33 bytes: public key data (0x02 + X or 0x03 + X)
+  } else {
+    var Q = ecurve.Point.decodeFrom(curve, buffer.slice(45, 78))
+    // Q.compressed is assumed, if somehow this assumption is broken, `new HDNode` will throw
+
+    // Verify that the X coordinate in the public point corresponds to a point on the curve.
+    // If not, the extended public key is invalid.
+    curve.validate(Q)
+
+    keyPair = new ECPair(null, Q, { network: network })
+  }
+
+  var hd = new HDNode(keyPair, chainCode, prefix)
+  hd.depth = depth
+  hd.index = index
+  hd.parentFingerprint = parentFingerprint
+
+  return hd
+}
+
+HDNode.prototype.getScriptData = function () {
+  return this.prefix.scriptFactory.convert(this.keyPair)
+}
+
+HDNode.prototype.getAddress = function () {
+  var scriptData = this.getScriptData()
+  return baddress.fromOutputScript(scriptData.scriptPubKey, this.keyPair.network)
+}
+
+HDNode.prototype.getIdentifier = function () {
+  return bcrypto.hash160(this.keyPair.getPublicKeyBuffer())
+}
+
+HDNode.prototype.getFingerprint = function () {
+  return this.getIdentifier().slice(0, 4)
+}
+
+HDNode.prototype.getNetwork = function () {
+  return this.keyPair.getNetwork()
+}
+
+HDNode.prototype.getPublicKeyBuffer = function () {
+  return this.keyPair.getPublicKeyBuffer()
+}
+
+HDNode.prototype.neutered = function () {
+  var neuteredKeyPair = new ECPair(null, this.keyPair.Q, {
+    network: this.keyPair.network
+  })
+
+  var neutered = new HDNode(neuteredKeyPair, this.chainCode, this.prefix)
+  neutered.depth = this.depth
+  neutered.index = this.index
+  neutered.parentFingerprint = this.parentFingerprint
+
+  return neutered
+}
+
+HDNode.prototype.sign = function (hash) {
+  return this.keyPair.sign(hash)
+}
+
+HDNode.prototype.verify = function (hash, signature) {
+  return this.keyPair.verify(hash, signature)
+}
+
+HDNode.prototype.toBase58 = function (__isPrivate) {
+  if (__isPrivate !== undefined) throw new TypeError('Unsupported argument in 2.0.0')
+
+  // Version
+  var version = (!this.isNeutered()) ? this.prefix.private : this.prefix.public
+  var buffer = Buffer.allocUnsafe(78)
+
+  // 4 bytes: version bytes
+  buffer.writeUInt32BE(version, 0)
+
+  // 1 byte: depth: 0x00 for master nodes, 0x01 for level-1 descendants, ....
+  buffer.writeUInt8(this.depth, 4)
+
+  // 4 bytes: the fingerprint of the parent's key (0x00000000 if master key)
+  buffer.writeUInt32BE(this.parentFingerprint, 5)
+
+  // 4 bytes: child number. This is the number i in xi = xpar/i, with xi the key being serialized.
+  // This is encoded in big endian. (0x00000000 if master key)
+  buffer.writeUInt32BE(this.index, 9)
+
+  // 32 bytes: the chain code
+  this.chainCode.copy(buffer, 13)
+
+  // 33 bytes: the public key or private key data
+  if (!this.isNeutered()) {
+    // 0x00 + k for private keys
+    buffer.writeUInt8(0, 45)
+    this.keyPair.d.toBuffer(32).copy(buffer, 46)
+
+  // 33 bytes: the public key
+  } else {
+    // X9.62 encoding for public keys
+    this.keyPair.getPublicKeyBuffer().copy(buffer, 45)
+  }
+
+  return base58check.encode(buffer)
+}
+
+// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#child-key-derivation-ckd-functions
+HDNode.prototype.derive = function (index) {
+  typeforce(types.UInt32, index)
+
+  var isHardened = index >= HDNode.HIGHEST_BIT
+  var data = Buffer.allocUnsafe(37)
+
+  // Hardened child
+  if (isHardened) {
+    if (this.isNeutered()) throw new TypeError('Could not derive hardened child key')
+
+    // data = 0x00 || ser256(kpar) || ser32(index)
+    data[0] = 0x00
+    this.keyPair.d.toBuffer(32).copy(data, 1)
+    data.writeUInt32BE(index, 33)
+
+  // Normal child
+  } else {
+    // data = serP(point(kpar)) || ser32(index)
+    //      = serP(Kpar) || ser32(index)
+    this.keyPair.getPublicKeyBuffer().copy(data, 0)
+    data.writeUInt32BE(index, 33)
+  }
+
+  var I = createHmac('sha512', this.chainCode).update(data).digest()
+  var IL = I.slice(0, 32)
+  var IR = I.slice(32)
+
+  var pIL = BigInteger.fromBuffer(IL)
+
+  // In case parse256(IL) >= n, proceed with the next value for i
+  if (pIL.compareTo(curve.n) >= 0) {
+    return this.derive(index + 1)
+  }
+
+  // Private parent key -> private child key
+  var derivedKeyPair
+  if (!this.isNeutered()) {
+    // ki = parse256(IL) + kpar (mod n)
+    var ki = pIL.add(this.keyPair.d).mod(curve.n)
+
+    // In case ki == 0, proceed with the next value for i
+    if (ki.signum() === 0) {
+      return this.derive(index + 1)
+    }
+
+    derivedKeyPair = new ECPair(ki, null, {
+      network: this.keyPair.network
+    })
+
+  // Public parent key -> public child key
+  } else {
+    // Ki = point(parse256(IL)) + Kpar
+    //    = G*IL + Kpar
+    var Ki = curve.G.multiply(pIL).add(this.keyPair.Q)
+
+    // In case Ki is the point at infinity, proceed with the next value for i
+    if (curve.isInfinity(Ki)) {
+      return this.derive(index + 1)
+    }
+
+    derivedKeyPair = new ECPair(null, Ki, {
+      network: this.keyPair.network
+    })
+  }
+
+  var hd = new HDNode(derivedKeyPair, IR, this.prefix)
+  hd.depth = this.depth + 1
+  hd.index = index
+  hd.parentFingerprint = this.getFingerprint().readUInt32BE(0)
+
+  return hd
+}
+
+HDNode.prototype.deriveHardened = function (index) {
+  typeforce(types.UInt31, index)
+
+  // Only derives hardened private keys by default
+  return this.derive(index + HDNode.HIGHEST_BIT)
+}
+
+// Private === not neutered
+// Public === neutered
+HDNode.prototype.isNeutered = function () {
+  return !(this.keyPair.d)
+}
+
+HDNode.prototype.derivePath = function (path) {
+  typeforce(types.BIP32Path, path)
+
+  var splitPath = path.split('/')
+  if (splitPath[0] === 'm') {
+    if (this.parentFingerprint) {
+      throw new Error('Not a master node')
+    }
+
+    splitPath = splitPath.slice(1)
+  }
+
+  return splitPath.reduce(function (prevHd, indexStr) {
+    var index
+    if (indexStr.slice(-1) === "'") {
+      index = parseInt(indexStr.slice(0, -1), 10)
+      return prevHd.deriveHardened(index)
+    } else {
+      index = parseInt(indexStr, 10)
+      return prevHd.derive(index)
+    }
+  }, this)
+}
+
+module.exports = HDNode
diff --git a/src/index.d.ts b/src/index.d.ts
deleted file mode 100644
index b93c2aa..0000000
--- a/src/index.d.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import * as address from './address';
-import * as crypto from './crypto';
-import * as networks from './networks';
-import * as payments from './payments';
-import * as script from './script';
-export { address, crypto, networks, payments, script };
-export { Block } from './block';
-export { TaggedHashPrefix } from './crypto';
-export { Psbt, PsbtTxInput, PsbtTxOutput, Signer, SignerAsync, HDSigner, HDSignerAsync, } from './psbt';
-export { OPS as opcodes } from './ops';
-export { Transaction } from './transaction';
-export { Network } from './networks';
-export { Payment, PaymentCreator, PaymentOpts, Stack, StackElement, } from './payments';
-export { Input as TxInput, Output as TxOutput } from './transaction';
diff --git a/src/index.js b/src/index.js
index 983b0cc..1ad7099 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,41 +1,23 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.Transaction = exports.opcodes = exports.Psbt = exports.Block = exports.script = exports.payments = exports.networks = exports.crypto = exports.address = void 0;
-const address = require('./address');
-exports.address = address;
-const crypto = require('./crypto');
-exports.crypto = crypto;
-const networks = require('./networks');
-exports.networks = networks;
-const payments = require('./payments');
-exports.payments = payments;
-const script = require('./script');
-exports.script = script;
-var block_1 = require('./block');
-Object.defineProperty(exports, 'Block', {
-  enumerable: true,
-  get: function() {
-    return block_1.Block;
-  },
-});
-var psbt_1 = require('./psbt');
-Object.defineProperty(exports, 'Psbt', {
-  enumerable: true,
-  get: function() {
-    return psbt_1.Psbt;
-  },
-});
-var ops_1 = require('./ops');
-Object.defineProperty(exports, 'opcodes', {
-  enumerable: true,
-  get: function() {
-    return ops_1.OPS;
-  },
-});
-var transaction_1 = require('./transaction');
-Object.defineProperty(exports, 'Transaction', {
-  enumerable: true,
-  get: function() {
-    return transaction_1.Transaction;
-  },
-});
+var script = require('./script')
+
+var templates = require('./templates')
+for (var key in templates) {
+  script[key] = templates[key]
+}
+
+module.exports = {
+  bufferutils: require('./bufferutils'), // TODO: remove in 4.0.0
+
+  Block: require('./block'),
+  ECPair: require('./ecpair'),
+  ECSignature: require('./ecsignature'),
+  HDNode: require('./hdnode'),
+  Transaction: require('./transaction'),
+  TransactionBuilder: require('./transaction_builder'),
+
+  address: require('./address'),
+  crypto: require('./crypto'),
+  networks: require('./networks'),
+  opcodes: require('bitcoin-ops'),
+  script: script
+}
diff --git a/src/keytoscript.js b/src/keytoscript.js
new file mode 100644
index 0000000..c16272d
--- /dev/null
+++ b/src/keytoscript.js
@@ -0,0 +1,124 @@
+var bcrypto = require('./crypto')
+var btemplates = require('./templates')
+
+function checkAllowedP2sh (keyFactory) {
+  if (!(keyFactory instanceof P2pkhFactory ||
+      keyFactory instanceof P2wpkhFactory ||
+      keyFactory instanceof P2pkFactory
+    )) {
+    throw new Error('Unsupported script factory for P2SH')
+  }
+}
+
+function checkAllowedP2wsh (keyFactory) {
+  if (!(keyFactory instanceof P2pkhFactory ||
+      keyFactory instanceof P2pkFactory
+    )) {
+    throw new Error('Unsupported script factory for P2SH')
+  }
+}
+
+var P2pkFactory = function () {
+
+}
+
+/**
+ * @param {bitcoin.ECPair} key
+ */
+P2pkFactory.prototype.convert = function (key) {
+  return {
+    scriptPubKey: btemplates.pubKey.output.encode(key.getPublicKeyBuffer()),
+    signData: {}
+  }
+}
+
+var P2pkhFactory = function () {
+
+}
+
+/**
+ * @param {bitcoin.ECPair} key
+ */
+P2pkhFactory.prototype.convert = function (key) {
+  var hash160 = bcrypto.hash160(key.getPublicKeyBuffer())
+  return {
+    scriptPubKey: btemplates.pubKeyHash.output.encode(hash160),
+    signData: {}
+  }
+}
+
+var P2wpkhFactory = function () {
+
+}
+
+/**
+ * @param {bitcoin.ECPair} key
+ */
+P2wpkhFactory.prototype.convert = function (key) {
+  var hash160 = bcrypto.hash160(key.getPublicKeyBuffer())
+  return {
+    scriptPubKey: btemplates.witnessPubKeyHash.output.encode(hash160),
+    signData: {}
+  }
+}
+
+var P2shFactory = function (keyFactory) {
+  checkAllowedP2sh(keyFactory)
+  this.factory = keyFactory
+}
+
+P2shFactory.prototype.convert = function (key) {
+  var detail = this.factory.convert(key)
+  var hash160 = bcrypto.hash160(detail.scriptPubKey)
+  return {
+    scriptPubKey: btemplates.scriptHash.output.encode(hash160),
+    signData: {
+      redeemScript: detail.scriptPubKey
+    }
+  }
+}
+
+var P2wshFactory = function (keyFactory) {
+  checkAllowedP2wsh(keyFactory)
+  this.factory = keyFactory
+}
+
+P2wshFactory.prototype.convert = function (key) {
+  var detail = this.factory.convert(key)
+  var hash160 = bcrypto.hash160(detail.scriptPubKey)
+  return {
+    scriptPubKey: btemplates.scriptHash.output.encode(hash160),
+    signData: {
+      redeemScript: detail.scriptPubKey
+    }
+  }
+}
+
+var P2shP2wshFactory = function (keyFactory) {
+  checkAllowedP2wsh(keyFactory)
+  this.factory = keyFactory
+}
+
+P2shP2wshFactory.prototype.convert = function (key) {
+  var detail = this.factory.convert(key)
+  var sha256 = bcrypto.sha256(detail.scriptPubKey)
+  var wp = btemplates.witnessScriptHash.output.encode(sha256)
+  var hash160 = bcrypto.hash160(wp)
+  var spk = btemplates.scriptHash.output.encode(hash160)
+  return {
+    scriptPubKey: spk,
+    signData: {
+      redeemScript: wp,
+      witnessScript: detail.scriptPubKey
+    }
+  }
+}
+
+module.exports = {
+  P2pkhFactory: P2pkhFactory,
+  P2wpkhFactory: P2wpkhFactory,
+  P2pkFactory: P2pkFactory,
+  P2shFactory: P2shFactory,
+  P2wshFactory: P2wshFactory,
+  P2shP2wshFactory: P2shP2wshFactory
+}
diff --git a/src/merkle.d.ts b/src/merkle.d.ts
deleted file mode 100644
index d602201..0000000
--- a/src/merkle.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-/// <reference types="node" />
-export declare function fastMerkleRoot(values: Buffer[], digestFn: (b: Buffer) => Buffer): Buffer;
diff --git a/src/merkle.js b/src/merkle.js
deleted file mode 100644
index e93f9ca..0000000
--- a/src/merkle.js
+++ /dev/null
@@ -1,22 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.fastMerkleRoot = void 0;
-function fastMerkleRoot(values, digestFn) {
-  if (!Array.isArray(values)) throw TypeError('Expected values Array');
-  if (typeof digestFn !== 'function')
-    throw TypeError('Expected digest Function');
-  let length = values.length;
-  const results = values.concat();
-  while (length > 1) {
-    let j = 0;
-    for (let i = 0; i < length; i += 2, ++j) {
-      const left = results[i];
-      const right = i + 1 === length ? left : results[i + 1];
-      const data = Buffer.concat([left, right]);
-      results[j] = digestFn(data);
-    }
-    length = j;
-  }
-  return results[0];
-}
-exports.fastMerkleRoot = fastMerkleRoot;
diff --git a/src/networks.d.ts b/src/networks.d.ts
deleted file mode 100644
index d5590fd..0000000
--- a/src/networks.d.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-export interface Network {
-    messagePrefix: string;
-    bech32: string;
-    bip32: Bip32;
-    pubKeyHash: number;
-    scriptHash: number;
-    wif: number;
-}
-interface Bip32 {
-    public: number;
-    private: number;
-}
-export declare const bitcoin: Network;
-export declare const regtest: Network;
-export declare const testnet: Network;
-export {};
diff --git a/src/networks.js b/src/networks.js
index ea710f8..bfef034 100644
--- a/src/networks.js
+++ b/src/networks.js
@@ -1,36 +1,54 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.testnet = exports.regtest = exports.bitcoin = void 0;
-exports.bitcoin = {
-  messagePrefix: '\x18Bitcoin Signed Message:\n',
-  bech32: 'bc',
-  bip32: {
-    public: 0x0488b21e,
-    private: 0x0488ade4,
+var KeyToScript = require('./keytoscript')
+// https://en.bitcoin.it/wiki/List_of_address_prefixes
+// Dogecoin BIP32 is a proposed standard: https://bitcointalk.org/index.php?topic=409731
+
+var p2pkh = new KeyToScript.P2pkhFactory()
+var p2wpkh = new KeyToScript.P2wpkhFactory()
+
+module.exports = {
+  bitcoin: {
+    messagePrefix: '\x18Bitcoin Signed Message:\n',
+    bech32: 'bc',
+    bip32: {
+      public: 0x0488b21e,
+      private: 0x0488ade4,
+      scriptFactory: p2pkh
+    },
+    bip49: {
+      private: 0x049d7878,
+      public: 0x049d7cb2,
+      scriptFactory: new KeyToScript.P2shFactory(p2wpkh)
+    },
+    bip84: {
+      private: 0x04b2430c,
+      public: 0x04b24746,
+      scriptFactory: p2wpkh
+    },
+    pubKeyHash: 0x00,
+    scriptHash: 0x05,
+    wif: 0x80
   },
-  pubKeyHash: 0x00,
-  scriptHash: 0x05,
-  wif: 0x80,
-};
-exports.regtest = {
-  messagePrefix: '\x18Bitcoin Signed Message:\n',
-  bech32: 'bcrt',
-  bip32: {
-    public: 0x043587cf,
-    private: 0x04358394,
+  testnet: {
+    messagePrefix: '\x18Bitcoin Signed Message:\n',
+    bech32: 'tb',
+    bip32: {
+      public: 0x043587cf,
+      private: 0x04358394,
+      scriptFactory: p2pkh
+    },
+    pubKeyHash: 0x6f,
+    scriptHash: 0xc4,
+    wif: 0xef
   },
-  pubKeyHash: 0x6f,
-  scriptHash: 0xc4,
-  wif: 0xef,
-};
-exports.testnet = {
-  messagePrefix: '\x18Bitcoin Signed Message:\n',
-  bech32: 'tb',
-  bip32: {
-    public: 0x043587cf,
-    private: 0x04358394,
-  },
-  pubKeyHash: 0x6f,
-  scriptHash: 0xc4,
-  wif: 0xef,
-};
+  litecoin: {
+    messagePrefix: '\x19Litecoin Signed Message:\n',
+    bip32: {
+      public: 0x019da462,
+      private: 0x019d9cfe,
+      scriptFactory: p2pkh
+    },
+    pubKeyHash: 0x30,
+    scriptHash: 0x32,
+    wif: 0xb0
+  }
+}
diff --git a/src/ops.d.ts b/src/ops.d.ts
deleted file mode 100644
index cda7a84..0000000
--- a/src/ops.d.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-declare const OPS: {
-    [key: string]: number;
-};
-declare const REVERSE_OPS: {
-    [key: number]: string;
-};
-export { OPS, REVERSE_OPS };
diff --git a/src/ops.js b/src/ops.js
deleted file mode 100644
index 9d629cd..0000000
--- a/src/ops.js
+++ /dev/null
@@ -1,130 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.REVERSE_OPS = exports.OPS = void 0;
-const OPS = {
-  OP_FALSE: 0,
-  OP_0: 0,
-  OP_PUSHDATA1: 76,
-  OP_PUSHDATA2: 77,
-  OP_PUSHDATA4: 78,
-  OP_1NEGATE: 79,
-  OP_RESERVED: 80,
-  OP_TRUE: 81,
-  OP_1: 81,
-  OP_2: 82,
-  OP_3: 83,
-  OP_4: 84,
-  OP_5: 85,
-  OP_6: 86,
-  OP_7: 87,
-  OP_8: 88,
-  OP_9: 89,
-  OP_10: 90,
-  OP_11: 91,
-  OP_12: 92,
-  OP_13: 93,
-  OP_14: 94,
-  OP_15: 95,
-  OP_16: 96,
-  OP_NOP: 97,
-  OP_VER: 98,
-  OP_IF: 99,
-  OP_NOTIF: 100,
-  OP_VERIF: 101,
-  OP_VERNOTIF: 102,
-  OP_ELSE: 103,
-  OP_ENDIF: 104,
-  OP_VERIFY: 105,
-  OP_RETURN: 106,
-  OP_TOALTSTACK: 107,
-  OP_FROMALTSTACK: 108,
-  OP_2DROP: 109,
-  OP_2DUP: 110,
-  OP_3DUP: 111,
-  OP_2OVER: 112,
-  OP_2ROT: 113,
-  OP_2SWAP: 114,
-  OP_IFDUP: 115,
-  OP_DEPTH: 116,
-  OP_DROP: 117,
-  OP_DUP: 118,
-  OP_NIP: 119,
-  OP_OVER: 120,
-  OP_PICK: 121,
-  OP_ROLL: 122,
-  OP_ROT: 123,
-  OP_SWAP: 124,
-  OP_TUCK: 125,
-  OP_CAT: 126,
-  OP_SUBSTR: 127,
-  OP_LEFT: 128,
-  OP_RIGHT: 129,
-  OP_SIZE: 130,
-  OP_INVERT: 131,
-  OP_AND: 132,
-  OP_OR: 133,
-  OP_XOR: 134,
-  OP_EQUAL: 135,
-  OP_EQUALVERIFY: 136,
-  OP_RESERVED1: 137,
-  OP_RESERVED2: 138,
-  OP_1ADD: 139,
-  OP_1SUB: 140,
-  OP_2MUL: 141,
-  OP_2DIV: 142,
-  OP_NEGATE: 143,
-  OP_ABS: 144,
-  OP_NOT: 145,
-  OP_0NOTEQUAL: 146,
-  OP_ADD: 147,
-  OP_SUB: 148,
-  OP_MUL: 149,
-  OP_DIV: 150,
-  OP_MOD: 151,
-  OP_LSHIFT: 152,
-  OP_RSHIFT: 153,
-  OP_BOOLAND: 154,
-  OP_BOOLOR: 155,
-  OP_NUMEQUAL: 156,
-  OP_NUMEQUALVERIFY: 157,
-  OP_NUMNOTEQUAL: 158,
-  OP_LESSTHAN: 159,
-  OP_GREATERTHAN: 160,
-  OP_LESSTHANOREQUAL: 161,
-  OP_GREATERTHANOREQUAL: 162,
-  OP_MIN: 163,
-  OP_MAX: 164,
-  OP_WITHIN: 165,
-  OP_RIPEMD160: 166,
-  OP_SHA1: 167,
-  OP_SHA256: 168,
-  OP_HASH160: 169,
-  OP_HASH256: 170,
-  OP_CODESEPARATOR: 171,
-  OP_CHECKSIG: 172,
-  OP_CHECKSIGVERIFY: 173,
-  OP_CHECKMULTISIG: 174,
-  OP_CHECKMULTISIGVERIFY: 175,
-  OP_NOP1: 176,
-  OP_NOP2: 177,
-  OP_CHECKLOCKTIMEVERIFY: 177,
-  OP_NOP3: 178,
-  OP_CHECKSEQUENCEVERIFY: 178,
-  OP_NOP4: 179,
-  OP_NOP5: 180,
-  OP_NOP6: 181,
-  OP_NOP7: 182,
-  OP_NOP8: 183,
-  OP_NOP9: 184,
-  OP_NOP10: 185,
-  OP_PUBKEYHASH: 253,
-  OP_PUBKEY: 254,
-  OP_INVALIDOPCODE: 255,
-};
-exports.OPS = OPS;
-const REVERSE_OPS = {};
-exports.REVERSE_OPS = REVERSE_OPS;
-for (const op of Object.keys(OPS)) {
-  const code = OPS[op];
-  REVERSE_OPS[code] = op;
-}
diff --git a/src/payments/embed.d.ts b/src/payments/embed.d.ts
deleted file mode 100644
index 76a9ed2..0000000
--- a/src/payments/embed.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import { Payment, PaymentOpts } from './index';
-export declare function p2data(a: Payment, opts?: PaymentOpts): Payment;
diff --git a/src/payments/embed.js b/src/payments/embed.js
deleted file mode 100644
index 4b7218f..0000000
--- a/src/payments/embed.js
+++ /dev/null
@@ -1,52 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.p2data = void 0;
-const networks_1 = require('../networks');
-const bscript = require('../script');
-const types_1 = require('../types');
-const lazy = require('./lazy');
-const OPS = bscript.OPS;
-function stacksEqual(a, b) {
-  if (a.length !== b.length) return false;
-  return a.every((x, i) => {
-    return x.equals(b[i]);
-  });
-}
-// output: OP_RETURN ...
-function p2data(a, opts) {
-  if (!a.data && !a.output) throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-  (0, types_1.typeforce)(
-    {
-      network: types_1.typeforce.maybe(types_1.typeforce.Object),
-      output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
-      data: types_1.typeforce.maybe(
-        types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
-      ),
-    },
-    a,
-  );
-  const network = a.network || networks_1.bitcoin;
-  const o = { name: 'embed', network };
-  lazy.prop(o, 'output', () => {
-    if (!a.data) return;
-    return bscript.compile([OPS.OP_RETURN].concat(a.data));
-  });
-  lazy.prop(o, 'data', () => {
-    if (!a.output) return;
-    return bscript.decompile(a.output).slice(1);
-  });
-  // extended validation
-  if (opts.validate) {
-    if (a.output) {
-      const chunks = bscript.decompile(a.output);
-      if (chunks[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid');
-      if (!chunks.slice(1).every(types_1.typeforce.Buffer))
-        throw new TypeError('Output is invalid');
-      if (a.data && !stacksEqual(a.data, o.data))
-        throw new TypeError('Data mismatch');
-    }
-  }
-  return Object.assign(o, a);
-}
-exports.p2data = p2data;
diff --git a/src/payments/index.d.ts b/src/payments/index.d.ts
deleted file mode 100644
index 1edf071..0000000
--- a/src/payments/index.d.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/// <reference types="node" />
-import { Network } from '../networks';
-import { p2data as embed } from './embed';
-import { p2ms } from './p2ms';
-import { p2pk } from './p2pk';
-import { p2pkh } from './p2pkh';
-import { p2sh } from './p2sh';
-import { p2wpkh } from './p2wpkh';
-import { p2wsh } from './p2wsh';
-export interface Payment {
-    name?: string;
-    network?: Network;
-    output?: Buffer;
-    data?: Buffer[];
-    m?: number;
-    n?: number;
-    pubkeys?: Buffer[];
-    input?: Buffer;
-    signatures?: Buffer[];
-    pubkey?: Buffer;
-    signature?: Buffer;
-    address?: string;
-    hash?: Buffer;
-    redeem?: Payment;
-    witness?: Buffer[];
-}
-export declare type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
-export declare type PaymentFunction = () => Payment;
-export interface PaymentOpts {
-    validate?: boolean;
-    allowIncomplete?: boolean;
-}
-export declare type StackElement = Buffer | number;
-export declare type Stack = StackElement[];
-export declare type StackFunction = () => Stack;
-export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh };
diff --git a/src/payments/index.js b/src/payments/index.js
deleted file mode 100644
index c23c529..0000000
--- a/src/payments/index.js
+++ /dev/null
@@ -1,54 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.p2wsh = exports.p2wpkh = exports.p2sh = exports.p2pkh = exports.p2pk = exports.p2ms = exports.embed = void 0;
-const embed_1 = require('./embed');
-Object.defineProperty(exports, 'embed', {
-  enumerable: true,
-  get: function() {
-    return embed_1.p2data;
-  },
-});
-const p2ms_1 = require('./p2ms');
-Object.defineProperty(exports, 'p2ms', {
-  enumerable: true,
-  get: function() {
-    return p2ms_1.p2ms;
-  },
-});
-const p2pk_1 = require('./p2pk');
-Object.defineProperty(exports, 'p2pk', {
-  enumerable: true,
-  get: function() {
-    return p2pk_1.p2pk;
-  },
-});
-const p2pkh_1 = require('./p2pkh');
-Object.defineProperty(exports, 'p2pkh', {
-  enumerable: true,
-  get: function() {
-    return p2pkh_1.p2pkh;
-  },
-});
-const p2sh_1 = require('./p2sh');
-Object.defineProperty(exports, 'p2sh', {
-  enumerable: true,
-  get: function() {
-    return p2sh_1.p2sh;
-  },
-});
-const p2wpkh_1 = require('./p2wpkh');
-Object.defineProperty(exports, 'p2wpkh', {
-  enumerable: true,
-  get: function() {
-    return p2wpkh_1.p2wpkh;
-  },
-});
-const p2wsh_1 = require('./p2wsh');
-Object.defineProperty(exports, 'p2wsh', {
-  enumerable: true,
-  get: function() {
-    return p2wsh_1.p2wsh;
-  },
-});
-// TODO
-// witness commitment
diff --git a/src/payments/lazy.d.ts b/src/payments/lazy.d.ts
deleted file mode 100644
index 3463906..0000000
--- a/src/payments/lazy.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export declare function prop(object: {}, name: string, f: () => any): void;
-export declare function value<T>(f: () => T): () => T;
diff --git a/src/payments/lazy.js b/src/payments/lazy.js
deleted file mode 100644
index e620c72..0000000
--- a/src/payments/lazy.js
+++ /dev/null
@@ -1,32 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.value = exports.prop = void 0;
-function prop(object, name, f) {
-  Object.defineProperty(object, name, {
-    configurable: true,
-    enumerable: true,
-    get() {
-      const _value = f.call(this);
-      this[name] = _value;
-      return _value;
-    },
-    set(_value) {
-      Object.defineProperty(this, name, {
-        configurable: true,
-        enumerable: true,
-        value: _value,
-        writable: true,
-      });
-    },
-  });
-}
-exports.prop = prop;
-function value(f) {
-  let _value;
-  return () => {
-    if (_value !== undefined) return _value;
-    _value = f();
-    return _value;
-  };
-}
-exports.value = value;
diff --git a/src/payments/p2ms.d.ts b/src/payments/p2ms.d.ts
deleted file mode 100644
index 199e029..0000000
--- a/src/payments/p2ms.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import { Payment, PaymentOpts } from './index';
-export declare function p2ms(a: Payment, opts?: PaymentOpts): Payment;
diff --git a/src/payments/p2ms.js b/src/payments/p2ms.js
deleted file mode 100644
index 0b7e72d..0000000
--- a/src/payments/p2ms.js
+++ /dev/null
@@ -1,150 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.p2ms = void 0;
-const networks_1 = require('../networks');
-const bscript = require('../script');
-const types_1 = require('../types');
-const lazy = require('./lazy');
-const OPS = bscript.OPS;
-const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1
-function stacksEqual(a, b) {
-  if (a.length !== b.length) return false;
-  return a.every((x, i) => {
-    return x.equals(b[i]);
-  });
-}
-// input: OP_0 [signatures ...]
-// output: m [pubKeys ...] n OP_CHECKMULTISIG
-function p2ms(a, opts) {
-  if (
-    !a.input &&
-    !a.output &&
-    !(a.pubkeys && a.m !== undefined) &&
-    !a.signatures
-  )
-    throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-  function isAcceptableSignature(x) {
-    return (
-      bscript.isCanonicalScriptSignature(x) ||
-      (opts.allowIncomplete && x === OPS.OP_0) !== undefined
-    );
-  }
-  (0, types_1.typeforce)(
-    {
-      network: types_1.typeforce.maybe(types_1.typeforce.Object),
-      m: types_1.typeforce.maybe(types_1.typeforce.Number),
-      n: types_1.typeforce.maybe(types_1.typeforce.Number),
-      output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
-      pubkeys: types_1.typeforce.maybe(
-        types_1.typeforce.arrayOf(types_1.isPoint),
-      ),
-      signatures: types_1.typeforce.maybe(
-        types_1.typeforce.arrayOf(isAcceptableSignature),
-      ),
-      input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
-    },
-    a,
-  );
-  const network = a.network || networks_1.bitcoin;
-  const o = { network };
-  let chunks = [];
-  let decoded = false;
-  function decode(output) {
-    if (decoded) return;
-    decoded = true;
-    chunks = bscript.decompile(output);
-    o.m = chunks[0] - OP_INT_BASE;
-    o.n = chunks[chunks.length - 2] - OP_INT_BASE;
-    o.pubkeys = chunks.slice(1, -2);
-  }
-  lazy.prop(o, 'output', () => {
-    if (!a.m) return;
-    if (!o.n) return;
-    if (!a.pubkeys) return;
-    return bscript.compile(
-      [].concat(
-        OP_INT_BASE + a.m,
-        a.pubkeys,
-        OP_INT_BASE + o.n,
-        OPS.OP_CHECKMULTISIG,
-      ),
-    );
-  });
-  lazy.prop(o, 'm', () => {
-    if (!o.output) return;
-    decode(o.output);
-    return o.m;
-  });
-  lazy.prop(o, 'n', () => {
-    if (!o.pubkeys) return;
-    return o.pubkeys.length;
-  });
-  lazy.prop(o, 'pubkeys', () => {
-    if (!a.output) return;
-    decode(a.output);
-    return o.pubkeys;
-  });
-  lazy.prop(o, 'signatures', () => {
-    if (!a.input) return;
-    return bscript.decompile(a.input).slice(1);
-  });
-  lazy.prop(o, 'input', () => {
-    if (!a.signatures) return;
-    return bscript.compile([OPS.OP_0].concat(a.signatures));
-  });
-  lazy.prop(o, 'witness', () => {
-    if (!o.input) return;
-    return [];
-  });
-  lazy.prop(o, 'name', () => {
-    if (!o.m || !o.n) return;
-    return `p2ms(${o.m} of ${o.n})`;
-  });
-  // extended validation
-  if (opts.validate) {
-    if (a.output) {
-      decode(a.output);
-      if (!types_1.typeforce.Number(chunks[0]))
-        throw new TypeError('Output is invalid');
-      if (!types_1.typeforce.Number(chunks[chunks.length - 2]))
-        throw new TypeError('Output is invalid');
-      if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG)
-        throw new TypeError('Output is invalid');
-      if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3)
-        throw new TypeError('Output is invalid');
-      if (!o.pubkeys.every(x => (0, types_1.isPoint)(x)))
-        throw new TypeError('Output is invalid');
-      if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch');
-      if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch');
-      if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys))
-        throw new TypeError('Pubkeys mismatch');
-    }
-    if (a.pubkeys) {
-      if (a.n !== undefined && a.n !== a.pubkeys.length)
-        throw new TypeError('Pubkey count mismatch');
-      o.n = a.pubkeys.length;
-      if (o.n < o.m) throw new TypeError('Pubkey count cannot be less than m');
-    }
-    if (a.signatures) {
-      if (a.signatures.length < o.m)
-        throw new TypeError('Not enough signatures provided');
-      if (a.signatures.length > o.m)
-        throw new TypeError('Too many signatures provided');
-    }
-    if (a.input) {
-      if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid');
-      if (
-        o.signatures.length === 0 ||
-        !o.signatures.every(isAcceptableSignature)
-      )
-        throw new TypeError('Input has invalid signature(s)');
-      if (a.signatures && !stacksEqual(a.signatures, o.signatures))
-        throw new TypeError('Signature mismatch');
-      if (a.m !== undefined && a.m !== a.signatures.length)
-        throw new TypeError('Signature count mismatch');
-    }
-  }
-  return Object.assign(o, a);
-}
-exports.p2ms = p2ms;
diff --git a/src/payments/p2pk.d.ts b/src/payments/p2pk.d.ts
deleted file mode 100644
index d7e824d..0000000
--- a/src/payments/p2pk.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import { Payment, PaymentOpts } from './index';
-export declare function p2pk(a: Payment, opts?: PaymentOpts): Payment;
diff --git a/src/payments/p2pk.js b/src/payments/p2pk.js
deleted file mode 100644
index 2849530..0000000
--- a/src/payments/p2pk.js
+++ /dev/null
@@ -1,72 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.p2pk = void 0;
-const networks_1 = require('../networks');
-const bscript = require('../script');
-const types_1 = require('../types');
-const lazy = require('./lazy');
-const OPS = bscript.OPS;
-// input: {signature}
-// output: {pubKey} OP_CHECKSIG
-function p2pk(a, opts) {
-  if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature)
-    throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-  (0, types_1.typeforce)(
-    {
-      network: types_1.typeforce.maybe(types_1.typeforce.Object),
-      output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
-      pubkey: types_1.typeforce.maybe(types_1.isPoint),
-      signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature),
-      input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
-    },
-    a,
-  );
-  const _chunks = lazy.value(() => {
-    return bscript.decompile(a.input);
-  });
-  const network = a.network || networks_1.bitcoin;
-  const o = { name: 'p2pk', network };
-  lazy.prop(o, 'output', () => {
-    if (!a.pubkey) return;
-    return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]);
-  });
-  lazy.prop(o, 'pubkey', () => {
-    if (!a.output) return;
-    return a.output.slice(1, -1);
-  });
-  lazy.prop(o, 'signature', () => {
-    if (!a.input) return;
-    return _chunks()[0];
-  });
-  lazy.prop(o, 'input', () => {
-    if (!a.signature) return;
-    return bscript.compile([a.signature]);
-  });
-  lazy.prop(o, 'witness', () => {
-    if (!o.input) return;
-    return [];
-  });
-  // extended validation
-  if (opts.validate) {
-    if (a.output) {
-      if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG)
-        throw new TypeError('Output is invalid');
-      if (!(0, types_1.isPoint)(o.pubkey))
-        throw new TypeError('Output pubkey is invalid');
-      if (a.pubkey && !a.pubkey.equals(o.pubkey))
-        throw new TypeError('Pubkey mismatch');
-    }
-    if (a.signature) {
-      if (a.input && !a.input.equals(o.input))
-        throw new TypeError('Signature mismatch');
-    }
-    if (a.input) {
-      if (_chunks().length !== 1) throw new TypeError('Input is invalid');
-      if (!bscript.isCanonicalScriptSignature(o.signature))
-        throw new TypeError('Input has invalid signature');
-    }
-  }
-  return Object.assign(o, a);
-}
-exports.p2pk = p2pk;
diff --git a/src/payments/p2pkh.d.ts b/src/payments/p2pkh.d.ts
deleted file mode 100644
index a33eeb0..0000000
--- a/src/payments/p2pkh.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import { Payment, PaymentOpts } from './index';
-export declare function p2pkh(a: Payment, opts?: PaymentOpts): Payment;
diff --git a/src/payments/p2pkh.js b/src/payments/p2pkh.js
deleted file mode 100644
index 8edc8ba..0000000
--- a/src/payments/p2pkh.js
+++ /dev/null
@@ -1,132 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.p2pkh = void 0;
-const bcrypto = require('../crypto');
-const networks_1 = require('../networks');
-const bscript = require('../script');
-const types_1 = require('../types');
-const lazy = require('./lazy');
-const bs58check = require('bs58check');
-const OPS = bscript.OPS;
-// input: {signature} {pubkey}
-// output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG
-function p2pkh(a, opts) {
-  if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input)
-    throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-  (0, types_1.typeforce)(
-    {
-      network: types_1.typeforce.maybe(types_1.typeforce.Object),
-      address: types_1.typeforce.maybe(types_1.typeforce.String),
-      hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)),
-      output: types_1.typeforce.maybe(types_1.typeforce.BufferN(25)),
-      pubkey: types_1.typeforce.maybe(types_1.isPoint),
-      signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature),
-      input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
-    },
-    a,
-  );
-  const _address = lazy.value(() => {
-    const payload = bs58check.decode(a.address);
-    const version = payload.readUInt8(0);
-    const hash = payload.slice(1);
-    return { version, hash };
-  });
-  const _chunks = lazy.value(() => {
-    return bscript.decompile(a.input);
-  });
-  const network = a.network || networks_1.bitcoin;
-  const o = { name: 'p2pkh', network };
-  lazy.prop(o, 'address', () => {
-    if (!o.hash) return;
-    const payload = Buffer.allocUnsafe(21);
-    payload.writeUInt8(network.pubKeyHash, 0);
-    o.hash.copy(payload, 1);
-    return bs58check.encode(payload);
-  });
-  lazy.prop(o, 'hash', () => {
-    if (a.output) return a.output.slice(3, 23);
-    if (a.address) return _address().hash;
-    if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey);
-  });
-  lazy.prop(o, 'output', () => {
-    if (!o.hash) return;
-    return bscript.compile([
-      OPS.OP_DUP,
-      OPS.OP_HASH160,
-      o.hash,
-      OPS.OP_EQUALVERIFY,
-      OPS.OP_CHECKSIG,
-    ]);
-  });
-  lazy.prop(o, 'pubkey', () => {
-    if (!a.input) return;
-    return _chunks()[1];
-  });
-  lazy.prop(o, 'signature', () => {
-    if (!a.input) return;
-    return _chunks()[0];
-  });
-  lazy.prop(o, 'input', () => {
-    if (!a.pubkey) return;
-    if (!a.signature) return;
-    return bscript.compile([a.signature, a.pubkey]);
-  });
-  lazy.prop(o, 'witness', () => {
-    if (!o.input) return;
-    return [];
-  });
-  // extended validation
-  if (opts.validate) {
-    let hash = Buffer.from([]);
-    if (a.address) {
-      if (_address().version !== network.pubKeyHash)
-        throw new TypeError('Invalid version or Network mismatch');
-      if (_address().hash.length !== 20) throw new TypeError('Invalid address');
-      hash = _address().hash;
-    }
-    if (a.hash) {
-      if (hash.length > 0 && !hash.equals(a.hash))
-        throw new TypeError('Hash mismatch');
-      else hash = a.hash;
-    }
-    if (a.output) {
-      if (
-        a.output.length !== 25 ||
-        a.output[0] !== OPS.OP_DUP ||
-        a.output[1] !== OPS.OP_HASH160 ||
-        a.output[2] !== 0x14 ||
-        a.output[23] !== OPS.OP_EQUALVERIFY ||
-        a.output[24] !== OPS.OP_CHECKSIG
-      )
-        throw new TypeError('Output is invalid');
-      const hash2 = a.output.slice(3, 23);
-      if (hash.length > 0 && !hash.equals(hash2))
-        throw new TypeError('Hash mismatch');
-      else hash = hash2;
-    }
-    if (a.pubkey) {
-      const pkh = bcrypto.hash160(a.pubkey);
-      if (hash.length > 0 && !hash.equals(pkh))
-        throw new TypeError('Hash mismatch');
-      else hash = pkh;
-    }
-    if (a.input) {
-      const chunks = _chunks();
-      if (chunks.length !== 2) throw new TypeError('Input is invalid');
-      if (!bscript.isCanonicalScriptSignature(chunks[0]))
-        throw new TypeError('Input has invalid signature');
-      if (!(0, types_1.isPoint)(chunks[1]))
-        throw new TypeError('Input has invalid pubkey');
-      if (a.signature && !a.signature.equals(chunks[0]))
-        throw new TypeError('Signature mismatch');
-      if (a.pubkey && !a.pubkey.equals(chunks[1]))
-        throw new TypeError('Pubkey mismatch');
-      const pkh = bcrypto.hash160(chunks[1]);
-      if (hash.length > 0 && !hash.equals(pkh))
-        throw new TypeError('Hash mismatch');
-    }
-  }
-  return Object.assign(o, a);
-}
-exports.p2pkh = p2pkh;
diff --git a/src/payments/p2sh.d.ts b/src/payments/p2sh.d.ts
deleted file mode 100644
index bb76772..0000000
--- a/src/payments/p2sh.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import { Payment, PaymentOpts } from './index';
-export declare function p2sh(a: Payment, opts?: PaymentOpts): Payment;
diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js
deleted file mode 100644
index 8710bf1..0000000
--- a/src/payments/p2sh.js
+++ /dev/null
@@ -1,189 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.p2sh = void 0;
-const bcrypto = require('../crypto');
-const networks_1 = require('../networks');
-const bscript = require('../script');
-const types_1 = require('../types');
-const lazy = require('./lazy');
-const bs58check = require('bs58check');
-const OPS = bscript.OPS;
-function stacksEqual(a, b) {
-  if (a.length !== b.length) return false;
-  return a.every((x, i) => {
-    return x.equals(b[i]);
-  });
-}
-// input: [redeemScriptSig ...] {redeemScript}
-// witness: <?>
-// output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL
-function p2sh(a, opts) {
-  if (!a.address && !a.hash && !a.output && !a.redeem && !a.input)
-    throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-  (0, types_1.typeforce)(
-    {
-      network: types_1.typeforce.maybe(types_1.typeforce.Object),
-      address: types_1.typeforce.maybe(types_1.typeforce.String),
-      hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)),
-      output: types_1.typeforce.maybe(types_1.typeforce.BufferN(23)),
-      redeem: types_1.typeforce.maybe({
-        network: types_1.typeforce.maybe(types_1.typeforce.Object),
-        output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
-        input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
-        witness: types_1.typeforce.maybe(
-          types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
-        ),
-      }),
-      input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
-      witness: types_1.typeforce.maybe(
-        types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
-      ),
-    },
-    a,
-  );
-  let network = a.network;
-  if (!network) {
-    network = (a.redeem && a.redeem.network) || networks_1.bitcoin;
-  }
-  const o = { network };
-  const _address = lazy.value(() => {
-    const payload = bs58check.decode(a.address);
-    const version = payload.readUInt8(0);
-    const hash = payload.slice(1);
-    return { version, hash };
-  });
-  const _chunks = lazy.value(() => {
-    return bscript.decompile(a.input);
-  });
-  const _redeem = lazy.value(() => {
-    const chunks = _chunks();
-    return {
-      network,
-      output: chunks[chunks.length - 1],
-      input: bscript.compile(chunks.slice(0, -1)),
-      witness: a.witness || [],
-    };
-  });
-  // output dependents
-  lazy.prop(o, 'address', () => {
-    if (!o.hash) return;
-    const payload = Buffer.allocUnsafe(21);
-    payload.writeUInt8(o.network.scriptHash, 0);
-    o.hash.copy(payload, 1);
-    return bs58check.encode(payload);
-  });
-  lazy.prop(o, 'hash', () => {
-    // in order of least effort
-    if (a.output) return a.output.slice(2, 22);
-    if (a.address) return _address().hash;
-    if (o.redeem && o.redeem.output) return bcrypto.hash160(o.redeem.output);
-  });
-  lazy.prop(o, 'output', () => {
-    if (!o.hash) return;
-    return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]);
-  });
-  // input dependents
-  lazy.prop(o, 'redeem', () => {
-    if (!a.input) return;
-    return _redeem();
-  });
-  lazy.prop(o, 'input', () => {
-    if (!a.redeem || !a.redeem.input || !a.redeem.output) return;
-    return bscript.compile(
-      [].concat(bscript.decompile(a.redeem.input), a.redeem.output),
-    );
-  });
-  lazy.prop(o, 'witness', () => {
-    if (o.redeem && o.redeem.witness) return o.redeem.witness;
-    if (o.input) return [];
-  });
-  lazy.prop(o, 'name', () => {
-    const nameParts = ['p2sh'];
-    if (o.redeem !== undefined && o.redeem.name !== undefined)
-      nameParts.push(o.redeem.name);
-    return nameParts.join('-');
-  });
-  if (opts.validate) {
-    let hash = Buffer.from([]);
-    if (a.address) {
-      if (_address().version !== network.scriptHash)
-        throw new TypeError('Invalid version or Network mismatch');
-      if (_address().hash.length !== 20) throw new TypeError('Invalid address');
-      hash = _address().hash;
-    }
-    if (a.hash) {
-      if (hash.length > 0 && !hash.equals(a.hash))
-        throw new TypeError('Hash mismatch');
-      else hash = a.hash;
-    }
-    if (a.output) {
-      if (
-        a.output.length !== 23 ||
-        a.output[0] !== OPS.OP_HASH160 ||
-        a.output[1] !== 0x14 ||
-        a.output[22] !== OPS.OP_EQUAL
-      )
-        throw new TypeError('Output is invalid');
-      const hash2 = a.output.slice(2, 22);
-      if (hash.length > 0 && !hash.equals(hash2))
-        throw new TypeError('Hash mismatch');
-      else hash = hash2;
-    }
-    // inlined to prevent 'no-inner-declarations' failing
-    const checkRedeem = redeem => {
-      // is the redeem output empty/invalid?
-      if (redeem.output) {
-        const decompile = bscript.decompile(redeem.output);
-        if (!decompile || decompile.length < 1)
-          throw new TypeError('Redeem.output too short');
-        // match hash against other sources
-        const hash2 = bcrypto.hash160(redeem.output);
-        if (hash.length > 0 && !hash.equals(hash2))
-          throw new TypeError('Hash mismatch');
-        else hash = hash2;
-      }
-      if (redeem.input) {
-        const hasInput = redeem.input.length > 0;
-        const hasWitness = redeem.witness && redeem.witness.length > 0;
-        if (!hasInput && !hasWitness) throw new TypeError('Empty input');
-        if (hasInput && hasWitness)
-          throw new TypeError('Input and witness provided');
-        if (hasInput) {
-          const richunks = bscript.decompile(redeem.input);
-          if (!bscript.isPushOnly(richunks))
-            throw new TypeError('Non push-only scriptSig');
-        }
-      }
-    };
-    if (a.input) {
-      const chunks = _chunks();
-      if (!chunks || chunks.length < 1) throw new TypeError('Input too short');
-      if (!Buffer.isBuffer(_redeem().output))
-        throw new TypeError('Input is invalid');
-      checkRedeem(_redeem());
-    }
-    if (a.redeem) {
-      if (a.redeem.network && a.redeem.network !== network)
-        throw new TypeError('Network mismatch');
-      if (a.input) {
-        const redeem = _redeem();
-        if (a.redeem.output && !a.redeem.output.equals(redeem.output))
-          throw new TypeError('Redeem.output mismatch');
-        if (a.redeem.input && !a.redeem.input.equals(redeem.input))
-          throw new TypeError('Redeem.input mismatch');
-      }
-      checkRedeem(a.redeem);
-    }
-    if (a.witness) {
-      if (
-        a.redeem &&
-        a.redeem.witness &&
-        !stacksEqual(a.redeem.witness, a.witness)
-      )
-        throw new TypeError('Witness and redeem.witness mismatch');
-    }
-  }
-  return Object.assign(o, a);
-}
-exports.p2sh = p2sh;
diff --git a/src/payments/p2wpkh.d.ts b/src/payments/p2wpkh.d.ts
deleted file mode 100644
index 3609391..0000000
--- a/src/payments/p2wpkh.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import { Payment, PaymentOpts } from './index';
-export declare function p2wpkh(a: Payment, opts?: PaymentOpts): Payment;
diff --git a/src/payments/p2wpkh.js b/src/payments/p2wpkh.js
deleted file mode 100644
index 168e08f..0000000
--- a/src/payments/p2wpkh.js
+++ /dev/null
@@ -1,132 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.p2wpkh = void 0;
-const bcrypto = require('../crypto');
-const networks_1 = require('../networks');
-const bscript = require('../script');
-const types_1 = require('../types');
-const lazy = require('./lazy');
-const bech32_1 = require('bech32');
-const OPS = bscript.OPS;
-const EMPTY_BUFFER = Buffer.alloc(0);
-// witness: {signature} {pubKey}
-// input: <>
-// output: OP_0 {pubKeyHash}
-function p2wpkh(a, opts) {
-  if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness)
-    throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-  (0, types_1.typeforce)(
-    {
-      address: types_1.typeforce.maybe(types_1.typeforce.String),
-      hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)),
-      input: types_1.typeforce.maybe(types_1.typeforce.BufferN(0)),
-      network: types_1.typeforce.maybe(types_1.typeforce.Object),
-      output: types_1.typeforce.maybe(types_1.typeforce.BufferN(22)),
-      pubkey: types_1.typeforce.maybe(types_1.isPoint),
-      signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature),
-      witness: types_1.typeforce.maybe(
-        types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
-      ),
-    },
-    a,
-  );
-  const _address = lazy.value(() => {
-    const result = bech32_1.bech32.decode(a.address);
-    const version = result.words.shift();
-    const data = bech32_1.bech32.fromWords(result.words);
-    return {
-      version,
-      prefix: result.prefix,
-      data: Buffer.from(data),
-    };
-  });
-  const network = a.network || networks_1.bitcoin;
-  const o = { name: 'p2wpkh', network };
-  lazy.prop(o, 'address', () => {
-    if (!o.hash) return;
-    const words = bech32_1.bech32.toWords(o.hash);
-    words.unshift(0x00);
-    return bech32_1.bech32.encode(network.bech32, words);
-  });
-  lazy.prop(o, 'hash', () => {
-    if (a.output) return a.output.slice(2, 22);
-    if (a.address) return _address().data;
-    if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey || o.pubkey);
-  });
-  lazy.prop(o, 'output', () => {
-    if (!o.hash) return;
-    return bscript.compile([OPS.OP_0, o.hash]);
-  });
-  lazy.prop(o, 'pubkey', () => {
-    if (a.pubkey) return a.pubkey;
-    if (!a.witness) return;
-    return a.witness[1];
-  });
-  lazy.prop(o, 'signature', () => {
-    if (!a.witness) return;
-    return a.witness[0];
-  });
-  lazy.prop(o, 'input', () => {
-    if (!o.witness) return;
-    return EMPTY_BUFFER;
-  });
-  lazy.prop(o, 'witness', () => {
-    if (!a.pubkey) return;
-    if (!a.signature) return;
-    return [a.signature, a.pubkey];
-  });
-  // extended validation
-  if (opts.validate) {
-    let hash = Buffer.from([]);
-    if (a.address) {
-      if (network && network.bech32 !== _address().prefix)
-        throw new TypeError('Invalid prefix or Network mismatch');
-      if (_address().version !== 0x00)
-        throw new TypeError('Invalid address version');
-      if (_address().data.length !== 20)
-        throw new TypeError('Invalid address data');
-      hash = _address().data;
-    }
-    if (a.hash) {
-      if (hash.length > 0 && !hash.equals(a.hash))
-        throw new TypeError('Hash mismatch');
-      else hash = a.hash;
-    }
-    if (a.output) {
-      if (
-        a.output.length !== 22 ||
-        a.output[0] !== OPS.OP_0 ||
-        a.output[1] !== 0x14
-      )
-        throw new TypeError('Output is invalid');
-      if (hash.length > 0 && !hash.equals(a.output.slice(2)))
-        throw new TypeError('Hash mismatch');
-      else hash = a.output.slice(2);
-    }
-    if (a.pubkey) {
-      const pkh = bcrypto.hash160(a.pubkey);
-      if (hash.length > 0 && !hash.equals(pkh))
-        throw new TypeError('Hash mismatch');
-      else hash = pkh;
-      if (!(0, types_1.isPoint)(a.pubkey) || a.pubkey.length !== 33)
-        throw new TypeError('Invalid pubkey for p2wpkh');
-    }
-    if (a.witness) {
-      if (a.witness.length !== 2) throw new TypeError('Witness is invalid');
-      if (!bscript.isCanonicalScriptSignature(a.witness[0]))
-        throw new TypeError('Witness has invalid signature');
-      if (!(0, types_1.isPoint)(a.witness[1]) || a.witness[1].length !== 33)
-        throw new TypeError('Witness has invalid pubkey');
-      if (a.signature && !a.signature.equals(a.witness[0]))
-        throw new TypeError('Signature mismatch');
-      if (a.pubkey && !a.pubkey.equals(a.witness[1]))
-        throw new TypeError('Pubkey mismatch');
-      const pkh = bcrypto.hash160(a.witness[1]);
-      if (hash.length > 0 && !hash.equals(pkh))
-        throw new TypeError('Hash mismatch');
-    }
-  }
-  return Object.assign(o, a);
-}
-exports.p2wpkh = p2wpkh;
diff --git a/src/payments/p2wsh.d.ts b/src/payments/p2wsh.d.ts
deleted file mode 100644
index d9ae925..0000000
--- a/src/payments/p2wsh.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-import { Payment, PaymentOpts } from './index';
-export declare function p2wsh(a: Payment, opts?: PaymentOpts): Payment;
diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.js
deleted file mode 100644
index 66ee1da..0000000
--- a/src/payments/p2wsh.js
+++ /dev/null
@@ -1,212 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.p2wsh = void 0;
-const bcrypto = require('../crypto');
-const networks_1 = require('../networks');
-const bscript = require('../script');
-const types_1 = require('../types');
-const lazy = require('./lazy');
-const bech32_1 = require('bech32');
-const OPS = bscript.OPS;
-const EMPTY_BUFFER = Buffer.alloc(0);
-function stacksEqual(a, b) {
-  if (a.length !== b.length) return false;
-  return a.every((x, i) => {
-    return x.equals(b[i]);
-  });
-}
-function chunkHasUncompressedPubkey(chunk) {
-  if (
-    Buffer.isBuffer(chunk) &&
-    chunk.length === 65 &&
-    chunk[0] === 0x04 &&
-    (0, types_1.isPoint)(chunk)
-  ) {
-    return true;
-  } else {
-    return false;
-  }
-}
-// input: <>
-// witness: [redeemScriptSig ...] {redeemScript}
-// output: OP_0 {sha256(redeemScript)}
-function p2wsh(a, opts) {
-  if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness)
-    throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-  (0, types_1.typeforce)(
-    {
-      network: types_1.typeforce.maybe(types_1.typeforce.Object),
-      address: types_1.typeforce.maybe(types_1.typeforce.String),
-      hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(32)),
-      output: types_1.typeforce.maybe(types_1.typeforce.BufferN(34)),
-      redeem: types_1.typeforce.maybe({
-        input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
-        network: types_1.typeforce.maybe(types_1.typeforce.Object),
-        output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
-        witness: types_1.typeforce.maybe(
-          types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
-        ),
-      }),
-      input: types_1.typeforce.maybe(types_1.typeforce.BufferN(0)),
-      witness: types_1.typeforce.maybe(
-        types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
-      ),
-    },
-    a,
-  );
-  const _address = lazy.value(() => {
-    const result = bech32_1.bech32.decode(a.address);
-    const version = result.words.shift();
-    const data = bech32_1.bech32.fromWords(result.words);
-    return {
-      version,
-      prefix: result.prefix,
-      data: Buffer.from(data),
-    };
-  });
-  const _rchunks = lazy.value(() => {
-    return bscript.decompile(a.redeem.input);
-  });
-  let network = a.network;
-  if (!network) {
-    network = (a.redeem && a.redeem.network) || networks_1.bitcoin;
-  }
-  const o = { network };
-  lazy.prop(o, 'address', () => {
-    if (!o.hash) return;
-    const words = bech32_1.bech32.toWords(o.hash);
-    words.unshift(0x00);
-    return bech32_1.bech32.encode(network.bech32, words);
-  });
-  lazy.prop(o, 'hash', () => {
-    if (a.output) return a.output.slice(2);
-    if (a.address) return _address().data;
-    if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output);
-  });
-  lazy.prop(o, 'output', () => {
-    if (!o.hash) return;
-    return bscript.compile([OPS.OP_0, o.hash]);
-  });
-  lazy.prop(o, 'redeem', () => {
-    if (!a.witness) return;
-    return {
-      output: a.witness[a.witness.length - 1],
-      input: EMPTY_BUFFER,
-      witness: a.witness.slice(0, -1),
-    };
-  });
-  lazy.prop(o, 'input', () => {
-    if (!o.witness) return;
-    return EMPTY_BUFFER;
-  });
-  lazy.prop(o, 'witness', () => {
-    // transform redeem input to witness stack?
-    if (
-      a.redeem &&
-      a.redeem.input &&
-      a.redeem.input.length > 0 &&
-      a.redeem.output &&
-      a.redeem.output.length > 0
-    ) {
-      const stack = bscript.toStack(_rchunks());
-      // assign, and blank the existing input
-      o.redeem = Object.assign({ witness: stack }, a.redeem);
-      o.redeem.input = EMPTY_BUFFER;
-      return [].concat(stack, a.redeem.output);
-    }
-    if (!a.redeem) return;
-    if (!a.redeem.output) return;
-    if (!a.redeem.witness) return;
-    return [].concat(a.redeem.witness, a.redeem.output);
-  });
-  lazy.prop(o, 'name', () => {
-    const nameParts = ['p2wsh'];
-    if (o.redeem !== undefined && o.redeem.name !== undefined)
-      nameParts.push(o.redeem.name);
-    return nameParts.join('-');
-  });
-  // extended validation
-  if (opts.validate) {
-    let hash = Buffer.from([]);
-    if (a.address) {
-      if (_address().prefix !== network.bech32)
-        throw new TypeError('Invalid prefix or Network mismatch');
-      if (_address().version !== 0x00)
-        throw new TypeError('Invalid address version');
-      if (_address().data.length !== 32)
-        throw new TypeError('Invalid address data');
-      hash = _address().data;
-    }
-    if (a.hash) {
-      if (hash.length > 0 && !hash.equals(a.hash))
-        throw new TypeError('Hash mismatch');
-      else hash = a.hash;
-    }
-    if (a.output) {
-      if (
-        a.output.length !== 34 ||
-        a.output[0] !== OPS.OP_0 ||
-        a.output[1] !== 0x20
-      )
-        throw new TypeError('Output is invalid');
-      const hash2 = a.output.slice(2);
-      if (hash.length > 0 && !hash.equals(hash2))
-        throw new TypeError('Hash mismatch');
-      else hash = hash2;
-    }
-    if (a.redeem) {
-      if (a.redeem.network && a.redeem.network !== network)
-        throw new TypeError('Network mismatch');
-      // is there two redeem sources?
-      if (
-        a.redeem.input &&
-        a.redeem.input.length > 0 &&
-        a.redeem.witness &&
-        a.redeem.witness.length > 0
-      )
-        throw new TypeError('Ambiguous witness source');
-      // is the redeem output non-empty?
-      if (a.redeem.output) {
-        if (bscript.decompile(a.redeem.output).length === 0)
-          throw new TypeError('Redeem.output is invalid');
-        // match hash against other sources
-        const hash2 = bcrypto.sha256(a.redeem.output);
-        if (hash.length > 0 && !hash.equals(hash2))
-          throw new TypeError('Hash mismatch');
-        else hash = hash2;
-      }
-      if (a.redeem.input && !bscript.isPushOnly(_rchunks()))
-        throw new TypeError('Non push-only scriptSig');
-      if (
-        a.witness &&
-        a.redeem.witness &&
-        !stacksEqual(a.witness, a.redeem.witness)
-      )
-        throw new TypeError('Witness and redeem.witness mismatch');
-      if (
-        (a.redeem.input && _rchunks().some(chunkHasUncompressedPubkey)) ||
-        (a.redeem.output &&
-          (bscript.decompile(a.redeem.output) || []).some(
-            chunkHasUncompressedPubkey,
-          ))
-      ) {
-        throw new TypeError(
-          'redeem.input or redeem.output contains uncompressed pubkey',
-        );
-      }
-    }
-    if (a.witness && a.witness.length > 0) {
-      const wScript = a.witness[a.witness.length - 1];
-      if (a.redeem && a.redeem.output && !a.redeem.output.equals(wScript))
-        throw new TypeError('Witness and redeem.output mismatch');
-      if (
-        a.witness.some(chunkHasUncompressedPubkey) ||
-        (bscript.decompile(wScript) || []).some(chunkHasUncompressedPubkey)
-      )
-        throw new TypeError('Witness contains uncompressed pubkey');
-    }
-  }
-  return Object.assign(o, a);
-}
-exports.p2wsh = p2wsh;
diff --git a/src/psbt.d.ts b/src/psbt.d.ts
deleted file mode 100644
index 8603a69..0000000
--- a/src/psbt.d.ts
+++ /dev/null
@@ -1,182 +0,0 @@
-/// <reference types="node" />
-import { Psbt as PsbtBase } from 'bip174';
-import { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate } from 'bip174/src/lib/interfaces';
-import { Network } from './networks';
-import { Transaction } from './transaction';
-export interface TransactionInput {
-    hash: string | Buffer;
-    index: number;
-    sequence?: number;
-}
-export interface PsbtTxInput extends TransactionInput {
-    hash: Buffer;
-}
-export interface TransactionOutput {
-    script: Buffer;
-    value: number;
-}
-export interface PsbtTxOutput extends TransactionOutput {
-    address: string | undefined;
-}
-export declare type ValidateSigFunction = (pubkey: Buffer, msghash: Buffer, signature: Buffer) => boolean;
-/**
- * Psbt class can parse and generate a PSBT binary based off of the BIP174.
- * There are 6 roles that this class fulfills. (Explained in BIP174)
- *
- * Creator: This can be done with `new Psbt()`
- * Updater: This can be done with `psbt.addInput(input)`, `psbt.addInputs(inputs)`,
- *   `psbt.addOutput(output)`, `psbt.addOutputs(outputs)` when you are looking to
- *   add new inputs and outputs to the PSBT, and `psbt.updateGlobal(itemObject)`,
- *   `psbt.updateInput(itemObject)`, `psbt.updateOutput(itemObject)`
- *   addInput requires hash: Buffer | string; and index: number; as attributes
- *   and can also include any attributes that are used in updateInput method.
- *   addOutput requires script: Buffer; and value: number; and likewise can include
- *   data for updateOutput.
- *   For a list of what attributes should be what types. Check the bip174 library.
- *   Also, check the integration tests for some examples of usage.
- * Signer: There are a few methods. signAllInputs and signAllInputsAsync, which will search all input
- *   information for your pubkey or pubkeyhash, and only sign inputs where it finds
- *   your info. Or you can explicitly sign a specific input with signInput and
- *   signInputAsync. For the async methods you can create a SignerAsync object
- *   and use something like a hardware wallet to sign with. (You must implement this)
- * Combiner: psbts can be combined easily with `psbt.combine(psbt2, psbt3, psbt4 ...)`
- *   the psbt calling combine will always have precedence when a conflict occurs.
- *   Combine checks if the internal bitcoin transaction is the same, so be sure that
- *   all sequences, version, locktime, etc. are the same before combining.
- * Input Finalizer: This role is fairly important. Not only does it need to construct
- *   the input scriptSigs and witnesses, but it SHOULD verify the signatures etc.
- *   Before running `psbt.finalizeAllInputs()` please run `psbt.validateSignaturesOfAllInputs()`
- *   Running any finalize method will delete any data in the input(s) that are no longer
- *   needed due to the finalized scripts containing the information.
- * Transaction Extractor: This role will perform some checks before returning a
- *   Transaction object. Such as fee rate not being larger than maximumFeeRate etc.
- */
-export declare class Psbt {
-    readonly data: PsbtBase;
-    static fromBase64(data: string, opts?: PsbtOptsOptional): Psbt;
-    static fromHex(data: string, opts?: PsbtOptsOptional): Psbt;
-    static fromBuffer(buffer: Buffer, opts?: PsbtOptsOptional): Psbt;
-    private __CACHE;
-    private opts;
-    constructor(opts?: PsbtOptsOptional, data?: PsbtBase);
-    get inputCount(): number;
-    get version(): number;
-    set version(version: number);
-    get locktime(): number;
-    set locktime(locktime: number);
-    get txInputs(): PsbtTxInput[];
-    get txOutputs(): PsbtTxOutput[];
-    combine(...those: Psbt[]): this;
-    clone(): Psbt;
-    setMaximumFeeRate(satoshiPerByte: number): void;
-    setVersion(version: number): this;
-    setLocktime(locktime: number): this;
-    setInputSequence(inputIndex: number, sequence: number): this;
-    addInputs(inputDatas: PsbtInputExtended[]): this;
-    addInput(inputData: PsbtInputExtended): this;
-    addOutputs(outputDatas: PsbtOutputExtended[]): this;
-    addOutput(outputData: PsbtOutputExtended): this;
-    extractTransaction(disableFeeCheck?: boolean): Transaction;
-    getFeeRate(): number;
-    getFee(): number;
-    finalizeAllInputs(): this;
-    finalizeInput(inputIndex: number, finalScriptsFunc?: FinalScriptsFunc): this;
-    getInputType(inputIndex: number): AllScriptType;
-    inputHasPubkey(inputIndex: number, pubkey: Buffer): boolean;
-    inputHasHDKey(inputIndex: number, root: HDSigner): boolean;
-    outputHasPubkey(outputIndex: number, pubkey: Buffer): boolean;
-    outputHasHDKey(outputIndex: number, root: HDSigner): boolean;
-    validateSignaturesOfAllInputs(validator: ValidateSigFunction): boolean;
-    validateSignaturesOfInput(inputIndex: number, validator: ValidateSigFunction, pubkey?: Buffer): boolean;
-    signAllInputsHD(hdKeyPair: HDSigner, sighashTypes?: number[]): this;
-    signAllInputsHDAsync(hdKeyPair: HDSigner | HDSignerAsync, sighashTypes?: number[]): Promise<void>;
-    signInputHD(inputIndex: number, hdKeyPair: HDSigner, sighashTypes?: number[]): this;
-    signInputHDAsync(inputIndex: number, hdKeyPair: HDSigner | HDSignerAsync, sighashTypes?: number[]): Promise<void>;
-    signAllInputs(keyPair: Signer, sighashTypes?: number[]): this;
-    signAllInputsAsync(keyPair: Signer | SignerAsync, sighashTypes?: number[]): Promise<void>;
-    signInput(inputIndex: number, keyPair: Signer, sighashTypes?: number[]): this;
-    signInputAsync(inputIndex: number, keyPair: Signer | SignerAsync, sighashTypes?: number[]): Promise<void>;
-    toBuffer(): Buffer;
-    toHex(): string;
-    toBase64(): string;
-    updateGlobal(updateData: PsbtGlobalUpdate): this;
-    updateInput(inputIndex: number, updateData: PsbtInputUpdate): this;
-    updateOutput(outputIndex: number, updateData: PsbtOutputUpdate): this;
-    addUnknownKeyValToGlobal(keyVal: KeyValue): this;
-    addUnknownKeyValToInput(inputIndex: number, keyVal: KeyValue): this;
-    addUnknownKeyValToOutput(outputIndex: number, keyVal: KeyValue): this;
-    clearFinalizedInput(inputIndex: number): this;
-}
-interface PsbtOptsOptional {
-    network?: Network;
-    maximumFeeRate?: number;
-}
-interface PsbtInputExtended extends PsbtInput, TransactionInput {
-}
-declare type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript;
-interface PsbtOutputExtendedAddress extends PsbtOutput {
-    address: string;
-    value: number;
-}
-interface PsbtOutputExtendedScript extends PsbtOutput {
-    script: Buffer;
-    value: number;
-}
-interface HDSignerBase {
-    /**
-     * DER format compressed publicKey buffer
-     */
-    publicKey: Buffer;
-    /**
-     * The first 4 bytes of the sha256-ripemd160 of the publicKey
-     */
-    fingerprint: Buffer;
-}
-export interface HDSigner extends HDSignerBase {
-    /**
-     * The path string must match /^m(\/\d+'?)+$/
-     * ex. m/44'/0'/0'/1/23 levels with ' must be hard derivations
-     */
-    derivePath(path: string): HDSigner;
-    /**
-     * Input hash (the "message digest") for the signature algorithm
-     * Return a 64 byte signature (32 byte r and 32 byte s in that order)
-     */
-    sign(hash: Buffer): Buffer;
-}
-/**
- * Same as above but with async sign method
- */
-export interface HDSignerAsync extends HDSignerBase {
-    derivePath(path: string): HDSignerAsync;
-    sign(hash: Buffer): Promise<Buffer>;
-}
-export interface Signer {
-    publicKey: Buffer;
-    network?: any;
-    sign(hash: Buffer, lowR?: boolean): Buffer;
-    getPublicKey?(): Buffer;
-}
-export interface SignerAsync {
-    publicKey: Buffer;
-    network?: any;
-    sign(hash: Buffer, lowR?: boolean): Promise<Buffer>;
-    getPublicKey?(): Buffer;
-}
-/**
- * This function must do two things:
- * 1. Check if the `input` can be finalized. If it can not be finalized, throw.
- *   ie. `Can not finalize input #${inputIndex}`
- * 2. Create the finalScriptSig and finalScriptWitness Buffers.
- */
-declare type FinalScriptsFunc = (inputIndex: number, // Which input is it?
-input: PsbtInput, // The PSBT input contents
-script: Buffer, // The "meaningful" locking script Buffer (redeemScript for P2SH etc.)
-isSegwit: boolean, // Is it segwit?
-isP2SH: boolean, // Is it P2SH?
-isP2WSH: boolean) => {
-    finalScriptSig: Buffer | undefined;
-    finalScriptWitness: Buffer | undefined;
-};
-declare type AllScriptType = 'witnesspubkeyhash' | 'pubkeyhash' | 'multisig' | 'pubkey' | 'nonstandard' | 'p2sh-witnesspubkeyhash' | 'p2sh-pubkeyhash' | 'p2sh-multisig' | 'p2sh-pubkey' | 'p2sh-nonstandard' | 'p2wsh-pubkeyhash' | 'p2wsh-multisig' | 'p2wsh-pubkey' | 'p2wsh-nonstandard' | 'p2sh-p2wsh-pubkeyhash' | 'p2sh-p2wsh-multisig' | 'p2sh-p2wsh-pubkey' | 'p2sh-p2wsh-nonstandard';
-export {};
diff --git a/src/psbt.js b/src/psbt.js
deleted file mode 100644
index 6162195..0000000
--- a/src/psbt.js
+++ /dev/null
@@ -1,1411 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.Psbt = void 0;
-const bip174_1 = require('bip174');
-const varuint = require('bip174/src/lib/converter/varint');
-const utils_1 = require('bip174/src/lib/utils');
-const address_1 = require('./address');
-const bufferutils_1 = require('./bufferutils');
-const crypto_1 = require('./crypto');
-const networks_1 = require('./networks');
-const payments = require('./payments');
-const bscript = require('./script');
-const transaction_1 = require('./transaction');
-/**
- * These are the default arguments for a Psbt instance.
- */
-const DEFAULT_OPTS = {
-  /**
-   * A bitcoinjs Network object. This is only used if you pass an `address`
-   * parameter to addOutput. Otherwise it is not needed and can be left default.
-   */
-  network: networks_1.bitcoin,
-  /**
-   * When extractTransaction is called, the fee rate is checked.
-   * THIS IS NOT TO BE RELIED ON.
-   * It is only here as a last ditch effort to prevent sending a 500 BTC fee etc.
-   */
-  maximumFeeRate: 5000, // satoshi per byte
-};
-/**
- * Psbt class can parse and generate a PSBT binary based off of the BIP174.
- * There are 6 roles that this class fulfills. (Explained in BIP174)
- *
- * Creator: This can be done with `new Psbt()`
- * Updater: This can be done with `psbt.addInput(input)`, `psbt.addInputs(inputs)`,
- *   `psbt.addOutput(output)`, `psbt.addOutputs(outputs)` when you are looking to
- *   add new inputs and outputs to the PSBT, and `psbt.updateGlobal(itemObject)`,
- *   `psbt.updateInput(itemObject)`, `psbt.updateOutput(itemObject)`
- *   addInput requires hash: Buffer | string; and index: number; as attributes
- *   and can also include any attributes that are used in updateInput method.
- *   addOutput requires script: Buffer; and value: number; and likewise can include
- *   data for updateOutput.
- *   For a list of what attributes should be what types. Check the bip174 library.
- *   Also, check the integration tests for some examples of usage.
- * Signer: There are a few methods. signAllInputs and signAllInputsAsync, which will search all input
- *   information for your pubkey or pubkeyhash, and only sign inputs where it finds
- *   your info. Or you can explicitly sign a specific input with signInput and
- *   signInputAsync. For the async methods you can create a SignerAsync object
- *   and use something like a hardware wallet to sign with. (You must implement this)
- * Combiner: psbts can be combined easily with `psbt.combine(psbt2, psbt3, psbt4 ...)`
- *   the psbt calling combine will always have precedence when a conflict occurs.
- *   Combine checks if the internal bitcoin transaction is the same, so be sure that
- *   all sequences, version, locktime, etc. are the same before combining.
- * Input Finalizer: This role is fairly important. Not only does it need to construct
- *   the input scriptSigs and witnesses, but it SHOULD verify the signatures etc.
- *   Before running `psbt.finalizeAllInputs()` please run `psbt.validateSignaturesOfAllInputs()`
- *   Running any finalize method will delete any data in the input(s) that are no longer
- *   needed due to the finalized scripts containing the information.
- * Transaction Extractor: This role will perform some checks before returning a
- *   Transaction object. Such as fee rate not being larger than maximumFeeRate etc.
- */
-class Psbt {
-  constructor(opts = {}, data = new bip174_1.Psbt(new PsbtTransaction())) {
-    this.data = data;
-    // set defaults
-    this.opts = Object.assign({}, DEFAULT_OPTS, opts);
-    this.__CACHE = {
-      __NON_WITNESS_UTXO_TX_CACHE: [],
-      __NON_WITNESS_UTXO_BUF_CACHE: [],
-      __TX_IN_CACHE: {},
-      __TX: this.data.globalMap.unsignedTx.tx,
-      // Psbt's predecesor (TransactionBuilder - now removed) behavior
-      // was to not confirm input values  before signing.
-      // Even though we highly encourage people to get
-      // the full parent transaction to verify values, the ability to
-      // sign non-segwit inputs without the full transaction was often
-      // requested. So the only way to activate is to use @ts-ignore.
-      // We will disable exporting the Psbt when unsafe sign is active.
-      // because it is not BIP174 compliant.
-      __UNSAFE_SIGN_NONSEGWIT: false,
-    };
-    if (this.data.inputs.length === 0) this.setVersion(2);
-    // Make data hidden when enumerating
-    const dpew = (obj, attr, enumerable, writable) =>
-      Object.defineProperty(obj, attr, {
-        enumerable,
-        writable,
-      });
-    dpew(this, '__CACHE', false, true);
-    dpew(this, 'opts', false, true);
-  }
-  static fromBase64(data, opts = {}) {
-    const buffer = Buffer.from(data, 'base64');
-    return this.fromBuffer(buffer, opts);
-  }
-  static fromHex(data, opts = {}) {
-    const buffer = Buffer.from(data, 'hex');
-    return this.fromBuffer(buffer, opts);
-  }
-  static fromBuffer(buffer, opts = {}) {
-    const psbtBase = bip174_1.Psbt.fromBuffer(buffer, transactionFromBuffer);
-    const psbt = new Psbt(opts, psbtBase);
-    checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE);
-    return psbt;
-  }
-  get inputCount() {
-    return this.data.inputs.length;
-  }
-  get version() {
-    return this.__CACHE.__TX.version;
-  }
-  set version(version) {
-    this.setVersion(version);
-  }
-  get locktime() {
-    return this.__CACHE.__TX.locktime;
-  }
-  set locktime(locktime) {
-    this.setLocktime(locktime);
-  }
-  get txInputs() {
-    return this.__CACHE.__TX.ins.map(input => ({
-      hash: (0, bufferutils_1.cloneBuffer)(input.hash),
-      index: input.index,
-      sequence: input.sequence,
-    }));
-  }
-  get txOutputs() {
-    return this.__CACHE.__TX.outs.map(output => {
-      let address;
-      try {
-        address = (0, address_1.fromOutputScript)(
-          output.script,
-          this.opts.network,
-        );
-      } catch (_) {}
-      return {
-        script: (0, bufferutils_1.cloneBuffer)(output.script),
-        value: output.value,
-        address,
-      };
-    });
-  }
-  combine(...those) {
-    this.data.combine(...those.map(o => o.data));
-    return this;
-  }
-  clone() {
-    // TODO: more efficient cloning
-    const res = Psbt.fromBuffer(this.data.toBuffer());
-    res.opts = JSON.parse(JSON.stringify(this.opts));
-    return res;
-  }
-  setMaximumFeeRate(satoshiPerByte) {
-    check32Bit(satoshiPerByte); // 42.9 BTC per byte IS excessive... so throw
-    this.opts.maximumFeeRate = satoshiPerByte;
-  }
-  setVersion(version) {
-    check32Bit(version);
-    checkInputsForPartialSig(this.data.inputs, 'setVersion');
-    const c = this.__CACHE;
-    c.__TX.version = version;
-    c.__EXTRACTED_TX = undefined;
-    return this;
-  }
-  setLocktime(locktime) {
-    check32Bit(locktime);
-    checkInputsForPartialSig(this.data.inputs, 'setLocktime');
-    const c = this.__CACHE;
-    c.__TX.locktime = locktime;
-    c.__EXTRACTED_TX = undefined;
-    return this;
-  }
-  setInputSequence(inputIndex, sequence) {
-    check32Bit(sequence);
-    checkInputsForPartialSig(this.data.inputs, 'setInputSequence');
-    const c = this.__CACHE;
-    if (c.__TX.ins.length <= inputIndex) {
-      throw new Error('Input index too high');
-    }
-    c.__TX.ins[inputIndex].sequence = sequence;
-    c.__EXTRACTED_TX = undefined;
-    return this;
-  }
-  addInputs(inputDatas) {
-    inputDatas.forEach(inputData => this.addInput(inputData));
-    return this;
-  }
-  addInput(inputData) {
-    if (
-      arguments.length > 1 ||
-      !inputData ||
-      inputData.hash === undefined ||
-      inputData.index === undefined
-    ) {
-      throw new Error(
-        `Invalid arguments for Psbt.addInput. ` +
-          `Requires single object with at least [hash] and [index]`,
-      );
-    }
-    checkInputsForPartialSig(this.data.inputs, 'addInput');
-    if (inputData.witnessScript) checkInvalidP2WSH(inputData.witnessScript);
-    const c = this.__CACHE;
-    this.data.addInput(inputData);
-    const txIn = c.__TX.ins[c.__TX.ins.length - 1];
-    checkTxInputCache(c, txIn);
-    const inputIndex = this.data.inputs.length - 1;
-    const input = this.data.inputs[inputIndex];
-    if (input.nonWitnessUtxo) {
-      addNonWitnessTxCache(this.__CACHE, input, inputIndex);
-    }
-    c.__FEE = undefined;
-    c.__FEE_RATE = undefined;
-    c.__EXTRACTED_TX = undefined;
-    return this;
-  }
-  addOutputs(outputDatas) {
-    outputDatas.forEach(outputData => this.addOutput(outputData));
-    return this;
-  }
-  addOutput(outputData) {
-    if (
-      arguments.length > 1 ||
-      !outputData ||
-      outputData.value === undefined ||
-      (outputData.address === undefined && outputData.script === undefined)
-    ) {
-      throw new Error(
-        `Invalid arguments for Psbt.addOutput. ` +
-          `Requires single object with at least [script or address] and [value]`,
-      );
-    }
-    checkInputsForPartialSig(this.data.inputs, 'addOutput');
-    const { address } = outputData;
-    if (typeof address === 'string') {
-      const { network } = this.opts;
-      const script = (0, address_1.toOutputScript)(address, network);
-      outputData = Object.assign(outputData, { script });
-    }
-    const c = this.__CACHE;
-    this.data.addOutput(outputData);
-    c.__FEE = undefined;
-    c.__FEE_RATE = undefined;
-    c.__EXTRACTED_TX = undefined;
-    return this;
-  }
-  extractTransaction(disableFeeCheck) {
-    if (!this.data.inputs.every(isFinalized)) throw new Error('Not finalized');
-    const c = this.__CACHE;
-    if (!disableFeeCheck) {
-      checkFees(this, c, this.opts);
-    }
-    if (c.__EXTRACTED_TX) return c.__EXTRACTED_TX;
-    const tx = c.__TX.clone();
-    inputFinalizeGetAmts(this.data.inputs, tx, c, true);
-    return tx;
-  }
-  getFeeRate() {
-    return getTxCacheValue(
-      '__FEE_RATE',
-      'fee rate',
-      this.data.inputs,
-      this.__CACHE,
-    );
-  }
-  getFee() {
-    return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE);
-  }
-  finalizeAllInputs() {
-    (0, utils_1.checkForInput)(this.data.inputs, 0); // making sure we have at least one
-    range(this.data.inputs.length).forEach(idx => this.finalizeInput(idx));
-    return this;
-  }
-  finalizeInput(inputIndex, finalScriptsFunc = getFinalScripts) {
-    const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
-    const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
-      inputIndex,
-      input,
-      this.__CACHE,
-    );
-    if (!script) throw new Error(`No script found for input #${inputIndex}`);
-    checkPartialSigSighashes(input);
-    const { finalScriptSig, finalScriptWitness } = finalScriptsFunc(
-      inputIndex,
-      input,
-      script,
-      isSegwit,
-      isP2SH,
-      isP2WSH,
-    );
-    if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
-    if (finalScriptWitness)
-      this.data.updateInput(inputIndex, { finalScriptWitness });
-    if (!finalScriptSig && !finalScriptWitness)
-      throw new Error(`Unknown error finalizing input #${inputIndex}`);
-    this.data.clearFinalizedInput(inputIndex);
-    return this;
-  }
-  getInputType(inputIndex) {
-    const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
-    const script = getScriptFromUtxo(inputIndex, input, this.__CACHE);
-    const result = getMeaningfulScript(
-      script,
-      inputIndex,
-      'input',
-      input.redeemScript || redeemFromFinalScriptSig(input.finalScriptSig),
-      input.witnessScript ||
-        redeemFromFinalWitnessScript(input.finalScriptWitness),
-    );
-    const type = result.type === 'raw' ? '' : result.type + '-';
-    const mainType = classifyScript(result.meaningfulScript);
-    return type + mainType;
-  }
-  inputHasPubkey(inputIndex, pubkey) {
-    const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
-    return pubkeyInInput(pubkey, input, inputIndex, this.__CACHE);
-  }
-  inputHasHDKey(inputIndex, root) {
-    const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
-    const derivationIsMine = bip32DerivationIsMine(root);
-    return (
-      !!input.bip32Derivation && input.bip32Derivation.some(derivationIsMine)
-    );
-  }
-  outputHasPubkey(outputIndex, pubkey) {
-    const output = (0, utils_1.checkForOutput)(this.data.outputs, outputIndex);
-    return pubkeyInOutput(pubkey, output, outputIndex, this.__CACHE);
-  }
-  outputHasHDKey(outputIndex, root) {
-    const output = (0, utils_1.checkForOutput)(this.data.outputs, outputIndex);
-    const derivationIsMine = bip32DerivationIsMine(root);
-    return (
-      !!output.bip32Derivation && output.bip32Derivation.some(derivationIsMine)
-    );
-  }
-  validateSignaturesOfAllInputs(validator) {
-    (0, utils_1.checkForInput)(this.data.inputs, 0); // making sure we have at least one
-    const results = range(this.data.inputs.length).map(idx =>
-      this.validateSignaturesOfInput(idx, validator),
-    );
-    return results.reduce((final, res) => res === true && final, true);
-  }
-  validateSignaturesOfInput(inputIndex, validator, pubkey) {
-    const input = this.data.inputs[inputIndex];
-    const partialSig = (input || {}).partialSig;
-    if (!input || !partialSig || partialSig.length < 1)
-      throw new Error('No signatures to validate');
-    if (typeof validator !== 'function')
-      throw new Error('Need validator function to validate signatures');
-    const mySigs = pubkey
-      ? partialSig.filter(sig => sig.pubkey.equals(pubkey))
-      : partialSig;
-    if (mySigs.length < 1) throw new Error('No signatures for this pubkey');
-    const results = [];
-    let hashCache;
-    let scriptCache;
-    let sighashCache;
-    for (const pSig of mySigs) {
-      const sig = bscript.signature.decode(pSig.signature);
-      const { hash, script } =
-        sighashCache !== sig.hashType
-          ? getHashForSig(
-              inputIndex,
-              Object.assign({}, input, { sighashType: sig.hashType }),
-              this.__CACHE,
-              true,
-            )
-          : { hash: hashCache, script: scriptCache };
-      sighashCache = sig.hashType;
-      hashCache = hash;
-      scriptCache = script;
-      checkScriptForPubkey(pSig.pubkey, script, 'verify');
-      results.push(validator(pSig.pubkey, hash, sig.signature));
-    }
-    return results.every(res => res === true);
-  }
-  signAllInputsHD(
-    hdKeyPair,
-    sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
-  ) {
-    if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
-      throw new Error('Need HDSigner to sign input');
-    }
-    const results = [];
-    for (const i of range(this.data.inputs.length)) {
-      try {
-        this.signInputHD(i, hdKeyPair, sighashTypes);
-        results.push(true);
-      } catch (err) {
-        results.push(false);
-      }
-    }
-    if (results.every(v => v === false)) {
-      throw new Error('No inputs were signed');
-    }
-    return this;
-  }
-  signAllInputsHDAsync(
-    hdKeyPair,
-    sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
-  ) {
-    return new Promise((resolve, reject) => {
-      if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
-        return reject(new Error('Need HDSigner to sign input'));
-      }
-      const results = [];
-      const promises = [];
-      for (const i of range(this.data.inputs.length)) {
-        promises.push(
-          this.signInputHDAsync(i, hdKeyPair, sighashTypes).then(
-            () => {
-              results.push(true);
-            },
-            () => {
-              results.push(false);
-            },
-          ),
-        );
-      }
-      return Promise.all(promises).then(() => {
-        if (results.every(v => v === false)) {
-          return reject(new Error('No inputs were signed'));
-        }
-        resolve();
-      });
-    });
-  }
-  signInputHD(
-    inputIndex,
-    hdKeyPair,
-    sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
-  ) {
-    if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
-      throw new Error('Need HDSigner to sign input');
-    }
-    const signers = getSignersFromHD(inputIndex, this.data.inputs, hdKeyPair);
-    signers.forEach(signer => this.signInput(inputIndex, signer, sighashTypes));
-    return this;
-  }
-  signInputHDAsync(
-    inputIndex,
-    hdKeyPair,
-    sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
-  ) {
-    return new Promise((resolve, reject) => {
-      if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
-        return reject(new Error('Need HDSigner to sign input'));
-      }
-      const signers = getSignersFromHD(inputIndex, this.data.inputs, hdKeyPair);
-      const promises = signers.map(signer =>
-        this.signInputAsync(inputIndex, signer, sighashTypes),
-      );
-      return Promise.all(promises)
-        .then(() => {
-          resolve();
-        })
-        .catch(reject);
-    });
-  }
-  signAllInputs(
-    keyPair,
-    sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
-  ) {
-    if (!keyPair || !keyPair.publicKey)
-      throw new Error('Need Signer to sign input');
-    // TODO: Add a pubkey/pubkeyhash cache to each input
-    // as input information is added, then eventually
-    // optimize this method.
-    const results = [];
-    for (const i of range(this.data.inputs.length)) {
-      try {
-        this.signInput(i, keyPair, sighashTypes);
-        results.push(true);
-      } catch (err) {
-        results.push(false);
-      }
-    }
-    if (results.every(v => v === false)) {
-      throw new Error('No inputs were signed');
-    }
-    return this;
-  }
-  signAllInputsAsync(
-    keyPair,
-    sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
-  ) {
-    return new Promise((resolve, reject) => {
-      if (!keyPair || !keyPair.publicKey)
-        return reject(new Error('Need Signer to sign input'));
-      // TODO: Add a pubkey/pubkeyhash cache to each input
-      // as input information is added, then eventually
-      // optimize this method.
-      const results = [];
-      const promises = [];
-      for (const [i] of this.data.inputs.entries()) {
-        promises.push(
-          this.signInputAsync(i, keyPair, sighashTypes).then(
-            () => {
-              results.push(true);
-            },
-            () => {
-              results.push(false);
-            },
-          ),
-        );
-      }
-      return Promise.all(promises).then(() => {
-        if (results.every(v => v === false)) {
-          return reject(new Error('No inputs were signed'));
-        }
-        resolve();
-      });
-    });
-  }
-  signInput(
-    inputIndex,
-    keyPair,
-    sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
-  ) {
-    if (!keyPair || !keyPair.publicKey)
-      throw new Error('Need Signer to sign input');
-    const { hash, sighashType } = getHashAndSighashType(
-      this.data.inputs,
-      inputIndex,
-      keyPair.publicKey,
-      this.__CACHE,
-      sighashTypes,
-    );
-    const partialSig = [
-      {
-        pubkey: keyPair.publicKey,
-        signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
-      },
-    ];
-    this.data.updateInput(inputIndex, { partialSig });
-    return this;
-  }
-  signInputAsync(
-    inputIndex,
-    keyPair,
-    sighashTypes = [transaction_1.Transaction.SIGHASH_ALL],
-  ) {
-    return Promise.resolve().then(() => {
-      if (!keyPair || !keyPair.publicKey)
-        throw new Error('Need Signer to sign input');
-      const { hash, sighashType } = getHashAndSighashType(
-        this.data.inputs,
-        inputIndex,
-        keyPair.publicKey,
-        this.__CACHE,
-        sighashTypes,
-      );
-      return Promise.resolve(keyPair.sign(hash)).then(signature => {
-        const partialSig = [
-          {
-            pubkey: keyPair.publicKey,
-            signature: bscript.signature.encode(signature, sighashType),
-          },
-        ];
-        this.data.updateInput(inputIndex, { partialSig });
-      });
-    });
-  }
-  toBuffer() {
-    checkCache(this.__CACHE);
-    return this.data.toBuffer();
-  }
-  toHex() {
-    checkCache(this.__CACHE);
-    return this.data.toHex();
-  }
-  toBase64() {
-    checkCache(this.__CACHE);
-    return this.data.toBase64();
-  }
-  updateGlobal(updateData) {
-    this.data.updateGlobal(updateData);
-    return this;
-  }
-  updateInput(inputIndex, updateData) {
-    if (updateData.witnessScript) checkInvalidP2WSH(updateData.witnessScript);
-    this.data.updateInput(inputIndex, updateData);
-    if (updateData.nonWitnessUtxo) {
-      addNonWitnessTxCache(
-        this.__CACHE,
-        this.data.inputs[inputIndex],
-        inputIndex,
-      );
-    }
-    return this;
-  }
-  updateOutput(outputIndex, updateData) {
-    this.data.updateOutput(outputIndex, updateData);
-    return this;
-  }
-  addUnknownKeyValToGlobal(keyVal) {
-    this.data.addUnknownKeyValToGlobal(keyVal);
-    return this;
-  }
-  addUnknownKeyValToInput(inputIndex, keyVal) {
-    this.data.addUnknownKeyValToInput(inputIndex, keyVal);
-    return this;
-  }
-  addUnknownKeyValToOutput(outputIndex, keyVal) {
-    this.data.addUnknownKeyValToOutput(outputIndex, keyVal);
-    return this;
-  }
-  clearFinalizedInput(inputIndex) {
-    this.data.clearFinalizedInput(inputIndex);
-    return this;
-  }
-}
-exports.Psbt = Psbt;
-/**
- * This function is needed to pass to the bip174 base class's fromBuffer.
- * It takes the "transaction buffer" portion of the psbt buffer and returns a
- * Transaction (From the bip174 library) interface.
- */
-const transactionFromBuffer = buffer => new PsbtTransaction(buffer);
-/**
- * This class implements the Transaction interface from bip174 library.
- * It contains a bitcoinjs-lib Transaction object.
- */
-class PsbtTransaction {
-  constructor(buffer = Buffer.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) {
-    this.tx = transaction_1.Transaction.fromBuffer(buffer);
-    checkTxEmpty(this.tx);
-    Object.defineProperty(this, 'tx', {
-      enumerable: false,
-      writable: true,
-    });
-  }
-  getInputOutputCounts() {
-    return {
-      inputCount: this.tx.ins.length,
-      outputCount: this.tx.outs.length,
-    };
-  }
-  addInput(input) {
-    if (
-      input.hash === undefined ||
-      input.index === undefined ||
-      (!Buffer.isBuffer(input.hash) && typeof input.hash !== 'string') ||
-      typeof input.index !== 'number'
-    ) {
-      throw new Error('Error adding input.');
-    }
-    const hash =
-      typeof input.hash === 'string'
-        ? (0, bufferutils_1.reverseBuffer)(Buffer.from(input.hash, 'hex'))
-        : input.hash;
-    this.tx.addInput(hash, input.index, input.sequence);
-  }
-  addOutput(output) {
-    if (
-      output.script === undefined ||
-      output.value === undefined ||
-      !Buffer.isBuffer(output.script) ||
-      typeof output.value !== 'number'
-    ) {
-      throw new Error('Error adding output.');
-    }
-    this.tx.addOutput(output.script, output.value);
-  }
-  toBuffer() {
-    return this.tx.toBuffer();
-  }
-}
-function canFinalize(input, script, scriptType) {
-  switch (scriptType) {
-    case 'pubkey':
-    case 'pubkeyhash':
-    case 'witnesspubkeyhash':
-      return hasSigs(1, input.partialSig);
-    case 'multisig':
-      const p2ms = payments.p2ms({ output: script });
-      return hasSigs(p2ms.m, input.partialSig, p2ms.pubkeys);
-    default:
-      return false;
-  }
-}
-function checkCache(cache) {
-  if (cache.__UNSAFE_SIGN_NONSEGWIT !== false) {
-    throw new Error('Not BIP174 compliant, can not export');
-  }
-}
-function hasSigs(neededSigs, partialSig, pubkeys) {
-  if (!partialSig) return false;
-  let sigs;
-  if (pubkeys) {
-    sigs = pubkeys
-      .map(pkey => {
-        const pubkey = compressPubkey(pkey);
-        return partialSig.find(pSig => pSig.pubkey.equals(pubkey));
-      })
-      .filter(v => !!v);
-  } else {
-    sigs = partialSig;
-  }
-  if (sigs.length > neededSigs) throw new Error('Too many signatures');
-  return sigs.length === neededSigs;
-}
-function isFinalized(input) {
-  return !!input.finalScriptSig || !!input.finalScriptWitness;
-}
-function isPaymentFactory(payment) {
-  return script => {
-    try {
-      payment({ output: script });
-      return true;
-    } catch (err) {
-      return false;
-    }
-  };
-}
-const isP2MS = isPaymentFactory(payments.p2ms);
-const isP2PK = isPaymentFactory(payments.p2pk);
-const isP2PKH = isPaymentFactory(payments.p2pkh);
-const isP2WPKH = isPaymentFactory(payments.p2wpkh);
-const isP2WSHScript = isPaymentFactory(payments.p2wsh);
-const isP2SHScript = isPaymentFactory(payments.p2sh);
-function bip32DerivationIsMine(root) {
-  return d => {
-    if (!d.masterFingerprint.equals(root.fingerprint)) return false;
-    if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false;
-    return true;
-  };
-}
-function check32Bit(num) {
-  if (
-    typeof num !== 'number' ||
-    num !== Math.floor(num) ||
-    num > 0xffffffff ||
-    num < 0
-  ) {
-    throw new Error('Invalid 32 bit integer');
-  }
-}
-function checkFees(psbt, cache, opts) {
-  const feeRate = cache.__FEE_RATE || psbt.getFeeRate();
-  const vsize = cache.__EXTRACTED_TX.virtualSize();
-  const satoshis = feeRate * vsize;
-  if (feeRate >= opts.maximumFeeRate) {
-    throw new Error(
-      `Warning: You are paying around ${(satoshis / 1e8).toFixed(8)} in ` +
-        `fees, which is ${feeRate} satoshi per byte for a transaction ` +
-        `with a VSize of ${vsize} bytes (segwit counted as 0.25 byte per ` +
-        `byte). Use setMaximumFeeRate method to raise your threshold, or ` +
-        `pass true to the first arg of extractTransaction.`,
-    );
-  }
-}
-function checkInputsForPartialSig(inputs, action) {
-  inputs.forEach(input => {
-    let throws = false;
-    let pSigs = [];
-    if ((input.partialSig || []).length === 0) {
-      if (!input.finalScriptSig && !input.finalScriptWitness) return;
-      pSigs = getPsigsFromInputFinalScripts(input);
-    } else {
-      pSigs = input.partialSig;
-    }
-    pSigs.forEach(pSig => {
-      const { hashType } = bscript.signature.decode(pSig.signature);
-      const whitelist = [];
-      const isAnyoneCanPay =
-        hashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY;
-      if (isAnyoneCanPay) whitelist.push('addInput');
-      const hashMod = hashType & 0x1f;
-      switch (hashMod) {
-        case transaction_1.Transaction.SIGHASH_ALL:
-          break;
-        case transaction_1.Transaction.SIGHASH_SINGLE:
-        case transaction_1.Transaction.SIGHASH_NONE:
-          whitelist.push('addOutput');
-          whitelist.push('setInputSequence');
-          break;
-      }
-      if (whitelist.indexOf(action) === -1) {
-        throws = true;
-      }
-    });
-    if (throws) {
-      throw new Error('Can not modify transaction, signatures exist.');
-    }
-  });
-}
-function checkPartialSigSighashes(input) {
-  if (!input.sighashType || !input.partialSig) return;
-  const { partialSig, sighashType } = input;
-  partialSig.forEach(pSig => {
-    const { hashType } = bscript.signature.decode(pSig.signature);
-    if (sighashType !== hashType) {
-      throw new Error('Signature sighash does not match input sighash type');
-    }
-  });
-}
-function checkScriptForPubkey(pubkey, script, action) {
-  if (!pubkeyInScript(pubkey, script)) {
-    throw new Error(
-      `Can not ${action} for this input with the key ${pubkey.toString('hex')}`,
-    );
-  }
-}
-function checkTxEmpty(tx) {
-  const isEmpty = tx.ins.every(
-    input =>
-      input.script &&
-      input.script.length === 0 &&
-      input.witness &&
-      input.witness.length === 0,
-  );
-  if (!isEmpty) {
-    throw new Error('Format Error: Transaction ScriptSigs are not empty');
-  }
-}
-function checkTxForDupeIns(tx, cache) {
-  tx.ins.forEach(input => {
-    checkTxInputCache(cache, input);
-  });
-}
-function checkTxInputCache(cache, input) {
-  const key =
-    (0, bufferutils_1.reverseBuffer)(Buffer.from(input.hash)).toString('hex') +
-    ':' +
-    input.index;
-  if (cache.__TX_IN_CACHE[key]) throw new Error('Duplicate input detected.');
-  cache.__TX_IN_CACHE[key] = 1;
-}
-function scriptCheckerFactory(payment, paymentScriptName) {
-  return (inputIndex, scriptPubKey, redeemScript, ioType) => {
-    const redeemScriptOutput = payment({
-      redeem: { output: redeemScript },
-    }).output;
-    if (!scriptPubKey.equals(redeemScriptOutput)) {
-      throw new Error(
-        `${paymentScriptName} for ${ioType} #${inputIndex} doesn't match the scriptPubKey in the prevout`,
-      );
-    }
-  };
-}
-const checkRedeemScript = scriptCheckerFactory(payments.p2sh, 'Redeem script');
-const checkWitnessScript = scriptCheckerFactory(
-  payments.p2wsh,
-  'Witness script',
-);
-function getTxCacheValue(key, name, inputs, c) {
-  if (!inputs.every(isFinalized))
-    throw new Error(`PSBT must be finalized to calculate ${name}`);
-  if (key === '__FEE_RATE' && c.__FEE_RATE) return c.__FEE_RATE;
-  if (key === '__FEE' && c.__FEE) return c.__FEE;
-  let tx;
-  let mustFinalize = true;
-  if (c.__EXTRACTED_TX) {
-    tx = c.__EXTRACTED_TX;
-    mustFinalize = false;
-  } else {
-    tx = c.__TX.clone();
-  }
-  inputFinalizeGetAmts(inputs, tx, c, mustFinalize);
-  if (key === '__FEE_RATE') return c.__FEE_RATE;
-  else if (key === '__FEE') return c.__FEE;
-}
-function getFinalScripts(inputIndex, input, script, isSegwit, isP2SH, isP2WSH) {
-  const scriptType = classifyScript(script);
-  if (!canFinalize(input, script, scriptType))
-    throw new Error(`Can not finalize input #${inputIndex}`);
-  return prepareFinalScripts(
-    script,
-    scriptType,
-    input.partialSig,
-    isSegwit,
-    isP2SH,
-    isP2WSH,
-  );
-}
-function prepareFinalScripts(
-  script,
-  scriptType,
-  partialSig,
-  isSegwit,
-  isP2SH,
-  isP2WSH,
-) {
-  let finalScriptSig;
-  let finalScriptWitness;
-  // Wow, the payments API is very handy
-  const payment = getPayment(script, scriptType, partialSig);
-  const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment });
-  const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment });
-  if (isSegwit) {
-    if (p2wsh) {
-      finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness);
-    } else {
-      finalScriptWitness = witnessStackToScriptWitness(payment.witness);
-    }
-    if (p2sh) {
-      finalScriptSig = p2sh.input;
-    }
-  } else {
-    if (p2sh) {
-      finalScriptSig = p2sh.input;
-    } else {
-      finalScriptSig = payment.input;
-    }
-  }
-  return {
-    finalScriptSig,
-    finalScriptWitness,
-  };
-}
-function getHashAndSighashType(
-  inputs,
-  inputIndex,
-  pubkey,
-  cache,
-  sighashTypes,
-) {
-  const input = (0, utils_1.checkForInput)(inputs, inputIndex);
-  const { hash, sighashType, script } = getHashForSig(
-    inputIndex,
-    input,
-    cache,
-    false,
-    sighashTypes,
-  );
-  checkScriptForPubkey(pubkey, script, 'sign');
-  return {
-    hash,
-    sighashType,
-  };
-}
-function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) {
-  const unsignedTx = cache.__TX;
-  const sighashType =
-    input.sighashType || transaction_1.Transaction.SIGHASH_ALL;
-  if (sighashTypes && sighashTypes.indexOf(sighashType) < 0) {
-    const str = sighashTypeToString(sighashType);
-    throw new Error(
-      `Sighash type is not allowed. Retry the sign method passing the ` +
-        `sighashTypes array of whitelisted types. Sighash type: ${str}`,
-    );
-  }
-  let hash;
-  let prevout;
-  if (input.nonWitnessUtxo) {
-    const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
-      cache,
-      input,
-      inputIndex,
-    );
-    const prevoutHash = unsignedTx.ins[inputIndex].hash;
-    const utxoHash = nonWitnessUtxoTx.getHash();
-    // If a non-witness UTXO is provided, its hash must match the hash specified in the prevout
-    if (!prevoutHash.equals(utxoHash)) {
-      throw new Error(
-        `Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`,
-      );
-    }
-    const prevoutIndex = unsignedTx.ins[inputIndex].index;
-    prevout = nonWitnessUtxoTx.outs[prevoutIndex];
-  } else if (input.witnessUtxo) {
-    prevout = input.witnessUtxo;
-  } else {
-    throw new Error('Need a Utxo input item for signing');
-  }
-  const { meaningfulScript, type } = getMeaningfulScript(
-    prevout.script,
-    inputIndex,
-    'input',
-    input.redeemScript,
-    input.witnessScript,
-  );
-  if (['p2sh-p2wsh', 'p2wsh'].indexOf(type) >= 0) {
-    hash = unsignedTx.hashForWitnessV0(
-      inputIndex,
-      meaningfulScript,
-      prevout.value,
-      sighashType,
-    );
-  } else if (isP2WPKH(meaningfulScript)) {
-    // P2WPKH uses the P2PKH template for prevoutScript when signing
-    const signingScript = payments.p2pkh({ hash: meaningfulScript.slice(2) })
-      .output;
-    hash = unsignedTx.hashForWitnessV0(
-      inputIndex,
-      signingScript,
-      prevout.value,
-      sighashType,
-    );
-  } else {
-    // non-segwit
-    if (
-      input.nonWitnessUtxo === undefined &&
-      cache.__UNSAFE_SIGN_NONSEGWIT === false
-    )
-      throw new Error(
-        `Input #${inputIndex} has witnessUtxo but non-segwit script: ` +
-          `${meaningfulScript.toString('hex')}`,
-      );
-    if (!forValidate && cache.__UNSAFE_SIGN_NONSEGWIT !== false)
-      console.warn(
-        'Warning: Signing non-segwit inputs without the full parent transaction ' +
-          'means there is a chance that a miner could feed you incorrect information ' +
-          "to trick you into paying large fees. This behavior is the same as Psbt's predecesor " +
-          '(TransactionBuilder - now removed) when signing non-segwit scripts. You are not ' +
-          'able to export this Psbt with toBuffer|toBase64|toHex since it is not ' +
-          'BIP174 compliant.\n*********************\nPROCEED WITH CAUTION!\n' +
-          '*********************',
-      );
-    hash = unsignedTx.hashForSignature(
-      inputIndex,
-      meaningfulScript,
-      sighashType,
-    );
-  }
-  return {
-    script: meaningfulScript,
-    sighashType,
-    hash,
-  };
-}
-function getPayment(script, scriptType, partialSig) {
-  let payment;
-  switch (scriptType) {
-    case 'multisig':
-      const sigs = getSortedSigs(script, partialSig);
-      payment = payments.p2ms({
-        output: script,
-        signatures: sigs,
-      });
-      break;
-    case 'pubkey':
-      payment = payments.p2pk({
-        output: script,
-        signature: partialSig[0].signature,
-      });
-      break;
-    case 'pubkeyhash':
-      payment = payments.p2pkh({
-        output: script,
-        pubkey: partialSig[0].pubkey,
-        signature: partialSig[0].signature,
-      });
-      break;
-    case 'witnesspubkeyhash':
-      payment = payments.p2wpkh({
-        output: script,
-        pubkey: partialSig[0].pubkey,
-        signature: partialSig[0].signature,
-      });
-      break;
-  }
-  return payment;
-}
-function getPsigsFromInputFinalScripts(input) {
-  const scriptItems = !input.finalScriptSig
-    ? []
-    : bscript.decompile(input.finalScriptSig) || [];
-  const witnessItems = !input.finalScriptWitness
-    ? []
-    : bscript.decompile(input.finalScriptWitness) || [];
-  return scriptItems
-    .concat(witnessItems)
-    .filter(item => {
-      return Buffer.isBuffer(item) && bscript.isCanonicalScriptSignature(item);
-    })
-    .map(sig => ({ signature: sig }));
-}
-function getScriptFromInput(inputIndex, input, cache) {
-  const unsignedTx = cache.__TX;
-  const res = {
-    script: null,
-    isSegwit: false,
-    isP2SH: false,
-    isP2WSH: false,
-  };
-  res.isP2SH = !!input.redeemScript;
-  res.isP2WSH = !!input.witnessScript;
-  if (input.witnessScript) {
-    res.script = input.witnessScript;
-  } else if (input.redeemScript) {
-    res.script = input.redeemScript;
-  } else {
-    if (input.nonWitnessUtxo) {
-      const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
-        cache,
-        input,
-        inputIndex,
-      );
-      const prevoutIndex = unsignedTx.ins[inputIndex].index;
-      res.script = nonWitnessUtxoTx.outs[prevoutIndex].script;
-    } else if (input.witnessUtxo) {
-      res.script = input.witnessUtxo.script;
-    }
-  }
-  if (input.witnessScript || isP2WPKH(res.script)) {
-    res.isSegwit = true;
-  }
-  return res;
-}
-function getSignersFromHD(inputIndex, inputs, hdKeyPair) {
-  const input = (0, utils_1.checkForInput)(inputs, inputIndex);
-  if (!input.bip32Derivation || input.bip32Derivation.length === 0) {
-    throw new Error('Need bip32Derivation to sign with HD');
-  }
-  const myDerivations = input.bip32Derivation
-    .map(bipDv => {
-      if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) {
-        return bipDv;
-      } else {
-        return;
-      }
-    })
-    .filter(v => !!v);
-  if (myDerivations.length === 0) {
-    throw new Error(
-      'Need one bip32Derivation masterFingerprint to match the HDSigner fingerprint',
-    );
-  }
-  const signers = myDerivations.map(bipDv => {
-    const node = hdKeyPair.derivePath(bipDv.path);
-    if (!bipDv.pubkey.equals(node.publicKey)) {
-      throw new Error('pubkey did not match bip32Derivation');
-    }
-    return node;
-  });
-  return signers;
-}
-function getSortedSigs(script, partialSig) {
-  const p2ms = payments.p2ms({ output: script });
-  // for each pubkey in order of p2ms script
-  return p2ms.pubkeys
-    .map(pk => {
-      // filter partialSig array by pubkey being equal
-      return (
-        partialSig.filter(ps => {
-          return ps.pubkey.equals(pk);
-        })[0] || {}
-      ).signature;
-      // Any pubkey without a match will return undefined
-      // this last filter removes all the undefined items in the array.
-    })
-    .filter(v => !!v);
-}
-function scriptWitnessToWitnessStack(buffer) {
-  let offset = 0;
-  function readSlice(n) {
-    offset += n;
-    return buffer.slice(offset - n, offset);
-  }
-  function readVarInt() {
-    const vi = varuint.decode(buffer, offset);
-    offset += varuint.decode.bytes;
-    return vi;
-  }
-  function readVarSlice() {
-    return readSlice(readVarInt());
-  }
-  function readVector() {
-    const count = readVarInt();
-    const vector = [];
-    for (let i = 0; i < count; i++) vector.push(readVarSlice());
-    return vector;
-  }
-  return readVector();
-}
-function sighashTypeToString(sighashType) {
-  let text =
-    sighashType & transaction_1.Transaction.SIGHASH_ANYONECANPAY
-      ? 'SIGHASH_ANYONECANPAY | '
-      : '';
-  const sigMod = sighashType & 0x1f;
-  switch (sigMod) {
-    case transaction_1.Transaction.SIGHASH_ALL:
-      text += 'SIGHASH_ALL';
-      break;
-    case transaction_1.Transaction.SIGHASH_SINGLE:
-      text += 'SIGHASH_SINGLE';
-      break;
-    case transaction_1.Transaction.SIGHASH_NONE:
-      text += 'SIGHASH_NONE';
-      break;
-  }
-  return text;
-}
-function witnessStackToScriptWitness(witness) {
-  let buffer = Buffer.allocUnsafe(0);
-  function writeSlice(slice) {
-    buffer = Buffer.concat([buffer, Buffer.from(slice)]);
-  }
-  function writeVarInt(i) {
-    const currentLen = buffer.length;
-    const varintLen = varuint.encodingLength(i);
-    buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]);
-    varuint.encode(i, buffer, currentLen);
-  }
-  function writeVarSlice(slice) {
-    writeVarInt(slice.length);
-    writeSlice(slice);
-  }
-  function writeVector(vector) {
-    writeVarInt(vector.length);
-    vector.forEach(writeVarSlice);
-  }
-  writeVector(witness);
-  return buffer;
-}
-function addNonWitnessTxCache(cache, input, inputIndex) {
-  cache.__NON_WITNESS_UTXO_BUF_CACHE[inputIndex] = input.nonWitnessUtxo;
-  const tx = transaction_1.Transaction.fromBuffer(input.nonWitnessUtxo);
-  cache.__NON_WITNESS_UTXO_TX_CACHE[inputIndex] = tx;
-  const self = cache;
-  const selfIndex = inputIndex;
-  delete input.nonWitnessUtxo;
-  Object.defineProperty(input, 'nonWitnessUtxo', {
-    enumerable: true,
-    get() {
-      const buf = self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex];
-      const txCache = self.__NON_WITNESS_UTXO_TX_CACHE[selfIndex];
-      if (buf !== undefined) {
-        return buf;
-      } else {
-        const newBuf = txCache.toBuffer();
-        self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex] = newBuf;
-        return newBuf;
-      }
-    },
-    set(data) {
-      self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex] = data;
-    },
-  });
-}
-function inputFinalizeGetAmts(inputs, tx, cache, mustFinalize) {
-  let inputAmount = 0;
-  inputs.forEach((input, idx) => {
-    if (mustFinalize && input.finalScriptSig)
-      tx.ins[idx].script = input.finalScriptSig;
-    if (mustFinalize && input.finalScriptWitness) {
-      tx.ins[idx].witness = scriptWitnessToWitnessStack(
-        input.finalScriptWitness,
-      );
-    }
-    if (input.witnessUtxo) {
-      inputAmount += input.witnessUtxo.value;
-    } else if (input.nonWitnessUtxo) {
-      const nwTx = nonWitnessUtxoTxFromCache(cache, input, idx);
-      const vout = tx.ins[idx].index;
-      const out = nwTx.outs[vout];
-      inputAmount += out.value;
-    }
-  });
-  const outputAmount = tx.outs.reduce((total, o) => total + o.value, 0);
-  const fee = inputAmount - outputAmount;
-  if (fee < 0) {
-    throw new Error('Outputs are spending more than Inputs');
-  }
-  const bytes = tx.virtualSize();
-  cache.__FEE = fee;
-  cache.__EXTRACTED_TX = tx;
-  cache.__FEE_RATE = Math.floor(fee / bytes);
-}
-function nonWitnessUtxoTxFromCache(cache, input, inputIndex) {
-  const c = cache.__NON_WITNESS_UTXO_TX_CACHE;
-  if (!c[inputIndex]) {
-    addNonWitnessTxCache(cache, input, inputIndex);
-  }
-  return c[inputIndex];
-}
-function getScriptFromUtxo(inputIndex, input, cache) {
-  if (input.witnessUtxo !== undefined) {
-    return input.witnessUtxo.script;
-  } else if (input.nonWitnessUtxo !== undefined) {
-    const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
-      cache,
-      input,
-      inputIndex,
-    );
-    return nonWitnessUtxoTx.outs[cache.__TX.ins[inputIndex].index].script;
-  } else {
-    throw new Error("Can't find pubkey in input without Utxo data");
-  }
-}
-function pubkeyInInput(pubkey, input, inputIndex, cache) {
-  const script = getScriptFromUtxo(inputIndex, input, cache);
-  const { meaningfulScript } = getMeaningfulScript(
-    script,
-    inputIndex,
-    'input',
-    input.redeemScript,
-    input.witnessScript,
-  );
-  return pubkeyInScript(pubkey, meaningfulScript);
-}
-function pubkeyInOutput(pubkey, output, outputIndex, cache) {
-  const script = cache.__TX.outs[outputIndex].script;
-  const { meaningfulScript } = getMeaningfulScript(
-    script,
-    outputIndex,
-    'output',
-    output.redeemScript,
-    output.witnessScript,
-  );
-  return pubkeyInScript(pubkey, meaningfulScript);
-}
-function redeemFromFinalScriptSig(finalScript) {
-  if (!finalScript) return;
-  const decomp = bscript.decompile(finalScript);
-  if (!decomp) return;
-  const lastItem = decomp[decomp.length - 1];
-  if (
-    !Buffer.isBuffer(lastItem) ||
-    isPubkeyLike(lastItem) ||
-    isSigLike(lastItem)
-  )
-    return;
-  const sDecomp = bscript.decompile(lastItem);
-  if (!sDecomp) return;
-  return lastItem;
-}
-function redeemFromFinalWitnessScript(finalScript) {
-  if (!finalScript) return;
-  const decomp = scriptWitnessToWitnessStack(finalScript);
-  const lastItem = decomp[decomp.length - 1];
-  if (isPubkeyLike(lastItem)) return;
-  const sDecomp = bscript.decompile(lastItem);
-  if (!sDecomp) return;
-  return lastItem;
-}
-function compressPubkey(pubkey) {
-  if (pubkey.length === 65) {
-    const parity = pubkey[64] & 1;
-    const newKey = pubkey.slice(0, 33);
-    newKey[0] = 2 | parity;
-    return newKey;
-  }
-  return pubkey.slice();
-}
-function isPubkeyLike(buf) {
-  return buf.length === 33 && bscript.isCanonicalPubKey(buf);
-}
-function isSigLike(buf) {
-  return bscript.isCanonicalScriptSignature(buf);
-}
-function getMeaningfulScript(
-  script,
-  index,
-  ioType,
-  redeemScript,
-  witnessScript,
-) {
-  const isP2SH = isP2SHScript(script);
-  const isP2SHP2WSH = isP2SH && redeemScript && isP2WSHScript(redeemScript);
-  const isP2WSH = isP2WSHScript(script);
-  if (isP2SH && redeemScript === undefined)
-    throw new Error('scriptPubkey is P2SH but redeemScript missing');
-  if ((isP2WSH || isP2SHP2WSH) && witnessScript === undefined)
-    throw new Error(
-      'scriptPubkey or redeemScript is P2WSH but witnessScript missing',
-    );
-  let meaningfulScript;
-  if (isP2SHP2WSH) {
-    meaningfulScript = witnessScript;
-    checkRedeemScript(index, script, redeemScript, ioType);
-    checkWitnessScript(index, redeemScript, witnessScript, ioType);
-    checkInvalidP2WSH(meaningfulScript);
-  } else if (isP2WSH) {
-    meaningfulScript = witnessScript;
-    checkWitnessScript(index, script, witnessScript, ioType);
-    checkInvalidP2WSH(meaningfulScript);
-  } else if (isP2SH) {
-    meaningfulScript = redeemScript;
-    checkRedeemScript(index, script, redeemScript, ioType);
-  } else {
-    meaningfulScript = script;
-  }
-  return {
-    meaningfulScript,
-    type: isP2SHP2WSH
-      ? 'p2sh-p2wsh'
-      : isP2SH
-      ? 'p2sh'
-      : isP2WSH
-      ? 'p2wsh'
-      : 'raw',
-  };
-}
-function checkInvalidP2WSH(script) {
-  if (isP2WPKH(script) || isP2SHScript(script)) {
-    throw new Error('P2WPKH or P2SH can not be contained within P2WSH');
-  }
-}
-function pubkeyInScript(pubkey, script) {
-  const pubkeyHash = (0, crypto_1.hash160)(pubkey);
-  const decompiled = bscript.decompile(script);
-  if (decompiled === null) throw new Error('Unknown script error');
-  return decompiled.some(element => {
-    if (typeof element === 'number') return false;
-    return element.equals(pubkey) || element.equals(pubkeyHash);
-  });
-}
-function classifyScript(script) {
-  if (isP2WPKH(script)) return 'witnesspubkeyhash';
-  if (isP2PKH(script)) return 'pubkeyhash';
-  if (isP2MS(script)) return 'multisig';
-  if (isP2PK(script)) return 'pubkey';
-  return 'nonstandard';
-}
-function range(n) {
-  return [...Array(n).keys()];
-}
diff --git a/src/push_data.d.ts b/src/push_data.d.ts
deleted file mode 100644
index 07c2f91..0000000
--- a/src/push_data.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/// <reference types="node" />
-export declare function encodingLength(i: number): number;
-export declare function encode(buffer: Buffer, num: number, offset: number): number;
-export declare function decode(buffer: Buffer, offset: number): {
-    opcode: number;
-    number: number;
-    size: number;
-} | null;
diff --git a/src/push_data.js b/src/push_data.js
deleted file mode 100644
index 16b6147..0000000
--- a/src/push_data.js
+++ /dev/null
@@ -1,61 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.decode = exports.encode = exports.encodingLength = void 0;
-const ops_1 = require('./ops');
-function encodingLength(i) {
-  return i < ops_1.OPS.OP_PUSHDATA1 ? 1 : i <= 0xff ? 2 : i <= 0xffff ? 3 : 5;
-}
-exports.encodingLength = encodingLength;
-function encode(buffer, num, offset) {
-  const size = encodingLength(num);
-  // ~6 bit
-  if (size === 1) {
-    buffer.writeUInt8(num, offset);
-    // 8 bit
-  } else if (size === 2) {
-    buffer.writeUInt8(ops_1.OPS.OP_PUSHDATA1, offset);
-    buffer.writeUInt8(num, offset + 1);
-    // 16 bit
-  } else if (size === 3) {
-    buffer.writeUInt8(ops_1.OPS.OP_PUSHDATA2, offset);
-    buffer.writeUInt16LE(num, offset + 1);
-    // 32 bit
-  } else {
-    buffer.writeUInt8(ops_1.OPS.OP_PUSHDATA4, offset);
-    buffer.writeUInt32LE(num, offset + 1);
-  }
-  return size;
-}
-exports.encode = encode;
-function decode(buffer, offset) {
-  const opcode = buffer.readUInt8(offset);
-  let num;
-  let size;
-  // ~6 bit
-  if (opcode < ops_1.OPS.OP_PUSHDATA1) {
-    num = opcode;
-    size = 1;
-    // 8 bit
-  } else if (opcode === ops_1.OPS.OP_PUSHDATA1) {
-    if (offset + 2 > buffer.length) return null;
-    num = buffer.readUInt8(offset + 1);
-    size = 2;
-    // 16 bit
-  } else if (opcode === ops_1.OPS.OP_PUSHDATA2) {
-    if (offset + 3 > buffer.length) return null;
-    num = buffer.readUInt16LE(offset + 1);
-    size = 3;
-    // 32 bit
-  } else {
-    if (offset + 5 > buffer.length) return null;
-    if (opcode !== ops_1.OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode');
-    num = buffer.readUInt32LE(offset + 1);
-    size = 5;
-  }
-  return {
-    opcode,
-    number: num,
-    size,
-  };
-}
-exports.decode = decode;
diff --git a/src/script.d.ts b/src/script.d.ts
deleted file mode 100644
index 261ecf4..0000000
--- a/src/script.d.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/// <reference types="node" />
-import { OPS } from './ops';
-import { Stack } from './payments';
-import * as scriptNumber from './script_number';
-import * as scriptSignature from './script_signature';
-export { OPS };
-export declare function isPushOnly(value: Stack): boolean;
-export declare function compile(chunks: Buffer | Stack): Buffer;
-export declare function decompile(buffer: Buffer | Array<number | Buffer>): Array<number | Buffer> | null;
-export declare function toASM(chunks: Buffer | Array<number | Buffer>): string;
-export declare function fromASM(asm: string): Buffer;
-export declare function toStack(chunks: Buffer | Array<number | Buffer>): Buffer[];
-export declare function isCanonicalPubKey(buffer: Buffer): boolean;
-export declare function isDefinedHashType(hashType: number): boolean;
-export declare function isCanonicalScriptSignature(buffer: Buffer): boolean;
-export declare const number: typeof scriptNumber;
-export declare const signature: typeof scriptSignature;
diff --git a/src/script.js b/src/script.js
index 5e5e17b..1335f5d 100644
--- a/src/script.js
+++ b/src/script.js
@@ -1,182 +1,214 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.signature = exports.number = exports.isCanonicalScriptSignature = exports.isDefinedHashType = exports.isCanonicalPubKey = exports.toStack = exports.fromASM = exports.toASM = exports.decompile = exports.compile = exports.isPushOnly = exports.OPS = void 0;
-const bip66 = require('./bip66');
-const ops_1 = require('./ops');
-Object.defineProperty(exports, 'OPS', {
-  enumerable: true,
-  get: function() {
-    return ops_1.OPS;
-  },
-});
-const pushdata = require('./push_data');
-const scriptNumber = require('./script_number');
-const scriptSignature = require('./script_signature');
-const types = require('./types');
-const { typeforce } = types;
-const OP_INT_BASE = ops_1.OPS.OP_RESERVED; // OP_1 - 1
-function isOPInt(value) {
-  return (
-    types.Number(value) &&
-    (value === ops_1.OPS.OP_0 ||
-      (value >= ops_1.OPS.OP_1 && value <= ops_1.OPS.OP_16) ||
-      value === ops_1.OPS.OP_1NEGATE)
-  );
+var Buffer = require('safe-buffer').Buffer
+var bip66 = require('bip66')
+var pushdata = require('pushdata-bitcoin')
+var typeforce = require('typeforce')
+var types = require('./types')
+var scriptNumber = require('./script_number')
+
+var OPS = require('bitcoin-ops')
+var REVERSE_OPS = require('bitcoin-ops/map')
+var OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1
+
+function isOPInt (value) {
+  return types.Number(value) &&
+    ((value === OPS.OP_0) ||
+    (value >= OPS.OP_1 && value <= OPS.OP_16) ||
+    (value === OPS.OP_1NEGATE))
 }
-function isPushOnlyChunk(value) {
-  return types.Buffer(value) || isOPInt(value);
+
+function isPushOnlyChunk (value) {
+  return types.Buffer(value) || isOPInt(value)
 }
-function isPushOnly(value) {
-  return types.Array(value) && value.every(isPushOnlyChunk);
+
+function isPushOnly (value) {
+  return types.Array(value) && value.every(isPushOnlyChunk)
 }
-exports.isPushOnly = isPushOnly;
-function asMinimalOP(buffer) {
-  if (buffer.length === 0) return ops_1.OPS.OP_0;
-  if (buffer.length !== 1) return;
-  if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0];
-  if (buffer[0] === 0x81) return ops_1.OPS.OP_1NEGATE;
+
+function asMinimalOP (buffer) {
+  if (buffer.length === 0) return OPS.OP_0
+  if (buffer.length !== 1) return
+  if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0]
+  if (buffer[0] === 0x81) return OPS.OP_1NEGATE
 }
-function chunksIsBuffer(buf) {
-  return Buffer.isBuffer(buf);
-}
-function chunksIsArray(buf) {
-  return types.Array(buf);
-}
-function singleChunkIsBuffer(buf) {
-  return Buffer.isBuffer(buf);
-}
-function compile(chunks) {
+
+function compile (chunks) {
   // TODO: remove me
-  if (chunksIsBuffer(chunks)) return chunks;
-  typeforce(types.Array, chunks);
-  const bufferSize = chunks.reduce((accum, chunk) => {
+  if (Buffer.isBuffer(chunks)) return chunks
+
+  typeforce(types.Array, chunks)
+
+  var bufferSize = chunks.reduce(function (accum, chunk) {
     // data chunk
-    if (singleChunkIsBuffer(chunk)) {
+    if (Buffer.isBuffer(chunk)) {
       // adhere to BIP62.3, minimal push policy
       if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) {
-        return accum + 1;
+        return accum + 1
       }
-      return accum + pushdata.encodingLength(chunk.length) + chunk.length;
+
+      return accum + pushdata.encodingLength(chunk.length) + chunk.length
     }
+
     // opcode
-    return accum + 1;
-  }, 0.0);
-  const buffer = Buffer.allocUnsafe(bufferSize);
-  let offset = 0;
-  chunks.forEach(chunk => {
+    return accum + 1
+  }, 0.0)
+
+  var buffer = Buffer.allocUnsafe(bufferSize)
+  var offset = 0
+
+  chunks.forEach(function (chunk) {
     // data chunk
-    if (singleChunkIsBuffer(chunk)) {
+    if (Buffer.isBuffer(chunk)) {
       // adhere to BIP62.3, minimal push policy
-      const opcode = asMinimalOP(chunk);
+      var opcode = asMinimalOP(chunk)
       if (opcode !== undefined) {
-        buffer.writeUInt8(opcode, offset);
-        offset += 1;
-        return;
+        buffer.writeUInt8(opcode, offset)
+        offset += 1
+        return
       }
-      offset += pushdata.encode(buffer, chunk.length, offset);
-      chunk.copy(buffer, offset);
-      offset += chunk.length;
-      // opcode
+
+      offset += pushdata.encode(buffer, chunk.length, offset)
+      chunk.copy(buffer, offset)
+      offset += chunk.length
+
+    // opcode
     } else {
-      buffer.writeUInt8(chunk, offset);
-      offset += 1;
+      buffer.writeUInt8(chunk, offset)
+      offset += 1
     }
-  });
-  if (offset !== buffer.length) throw new Error('Could not decode chunks');
-  return buffer;
+  })
+
+  if (offset !== buffer.length) throw new Error('Could not decode chunks')
+  return buffer
 }
-exports.compile = compile;
-function decompile(buffer) {
+
+function decompile (buffer) {
   // TODO: remove me
-  if (chunksIsArray(buffer)) return buffer;
-  typeforce(types.Buffer, buffer);
-  const chunks = [];
-  let i = 0;
+  if (types.Array(buffer)) return buffer
+
+  typeforce(types.Buffer, buffer)
+
+  var chunks = []
+  var i = 0
+
   while (i < buffer.length) {
-    const opcode = buffer[i];
+    var opcode = buffer[i]
+
     // data chunk
-    if (opcode > ops_1.OPS.OP_0 && opcode <= ops_1.OPS.OP_PUSHDATA4) {
-      const d = pushdata.decode(buffer, i);
-      // did reading a pushDataInt fail?
-      if (d === null) return null;
-      i += d.size;
-      // attempt to read too much data?
-      if (i + d.number > buffer.length) return null;
-      const data = buffer.slice(i, i + d.number);
-      i += d.number;
+    if ((opcode > OPS.OP_0) && (opcode <= OPS.OP_PUSHDATA4)) {
+      var d = pushdata.decode(buffer, i)
+
+      // did reading a pushDataInt fail? empty script
+      if (d === null) return []
+      i += d.size
+
+      // attempt to read too much data? empty script
+      if (i + d.number > buffer.length) return []
+
+      var data = buffer.slice(i, i + d.number)
+      i += d.number
+
       // decompile minimally
-      const op = asMinimalOP(data);
+      var op = asMinimalOP(data)
       if (op !== undefined) {
-        chunks.push(op);
+        chunks.push(op)
       } else {
-        chunks.push(data);
+        chunks.push(data)
       }
-      // opcode
+
+    // opcode
     } else {
-      chunks.push(opcode);
-      i += 1;
+      chunks.push(opcode)
+
+      i += 1
     }
   }
-  return chunks;
-}
-exports.decompile = decompile;
-function toASM(chunks) {
-  if (chunksIsBuffer(chunks)) {
-    chunks = decompile(chunks);
-  }
+
   return chunks
-    .map(chunk => {
-      // data?
-      if (singleChunkIsBuffer(chunk)) {
-        const op = asMinimalOP(chunk);
-        if (op === undefined) return chunk.toString('hex');
-        chunk = op;
-      }
-      // opcode!
-      return ops_1.REVERSE_OPS[chunk];
-    })
-    .join(' ');
 }
-exports.toASM = toASM;
-function fromASM(asm) {
-  typeforce(types.String, asm);
-  return compile(
-    asm.split(' ').map(chunkStr => {
-      // opcode?
-      if (ops_1.OPS[chunkStr] !== undefined) return ops_1.OPS[chunkStr];
-      typeforce(types.Hex, chunkStr);
-      // data!
-      return Buffer.from(chunkStr, 'hex');
-    }),
-  );
+
+function toASM (chunks) {
+  if (Buffer.isBuffer(chunks)) {
+    chunks = decompile(chunks)
+  }
+
+  return chunks.map(function (chunk) {
+    // data?
+    if (Buffer.isBuffer(chunk)) {
+      var op = asMinimalOP(chunk)
+      if (op === undefined) return chunk.toString('hex')
+      chunk = op
+    }
+
+    // opcode!
+    return REVERSE_OPS[chunk]
+  }).join(' ')
 }
-exports.fromASM = fromASM;
-function toStack(chunks) {
-  chunks = decompile(chunks);
-  typeforce(isPushOnly, chunks);
-  return chunks.map(op => {
-    if (singleChunkIsBuffer(op)) return op;
-    if (op === ops_1.OPS.OP_0) return Buffer.allocUnsafe(0);
-    return scriptNumber.encode(op - OP_INT_BASE);
-  });
+
+function fromASM (asm) {
+  typeforce(types.String, asm)
+
+  return compile(asm.split(' ').map(function (chunkStr) {
+    // opcode?
+    if (OPS[chunkStr] !== undefined) return OPS[chunkStr]
+    typeforce(types.Hex, chunkStr)
+
+    // data!
+    return Buffer.from(chunkStr, 'hex')
+  }))
 }
-exports.toStack = toStack;
-function isCanonicalPubKey(buffer) {
-  return types.isPoint(buffer);
+
+function toStack (chunks) {
+  chunks = decompile(chunks)
+  typeforce(isPushOnly, chunks)
+
+  return chunks.map(function (op) {
+    if (Buffer.isBuffer(op)) return op
+    if (op === OPS.OP_0) return Buffer.allocUnsafe(0)
+
+    return scriptNumber.encode(op - OP_INT_BASE)
+  })
 }
-exports.isCanonicalPubKey = isCanonicalPubKey;
-function isDefinedHashType(hashType) {
-  const hashTypeMod = hashType & ~0x80;
-  // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE
-  return hashTypeMod > 0x00 && hashTypeMod < 0x04;
+
+function isCanonicalPubKey (buffer) {
+  if (!Buffer.isBuffer(buffer)) return false
+  if (buffer.length < 33) return false
+
+  switch (buffer[0]) {
+    case 0x02:
+    case 0x03:
+      return buffer.length === 33
+    case 0x04:
+      return buffer.length === 65
+  }
+
+  return false
 }
-exports.isDefinedHashType = isDefinedHashType;
-function isCanonicalScriptSignature(buffer) {
-  if (!Buffer.isBuffer(buffer)) return false;
-  if (!isDefinedHashType(buffer[buffer.length - 1])) return false;
-  return bip66.check(buffer.slice(0, -1));
+
+function isDefinedHashType (hashType) {
+  var hashTypeMod = hashType & ~0x80
+
+// return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE
+  return hashTypeMod > 0x00 && hashTypeMod < 0x04
+}
+
+function isCanonicalSignature (buffer) {
+  if (!Buffer.isBuffer(buffer)) return false
+  if (!isDefinedHashType(buffer[buffer.length - 1])) return false
+
+  return bip66.check(buffer.slice(0, -1))
+}
+
+module.exports = {
+  compile: compile,
+  decompile: decompile,
+  fromASM: fromASM,
+  toASM: toASM,
+  toStack: toStack,
+
+  number: require('./script_number'),
+
+  isCanonicalPubKey: isCanonicalPubKey,
+  isCanonicalSignature: isCanonicalSignature,
+  isPushOnly: isPushOnly,
+  isDefinedHashType: isDefinedHashType
 }
-exports.isCanonicalScriptSignature = isCanonicalScriptSignature;
-// tslint:disable-next-line variable-name
-exports.number = scriptNumber;
-exports.signature = scriptSignature;
diff --git a/src/script_number.d.ts b/src/script_number.d.ts
deleted file mode 100644
index 015bb89..0000000
--- a/src/script_number.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-/// <reference types="node" />
-export declare function decode(buffer: Buffer, maxLength?: number, minimal?: boolean): number;
-export declare function encode(_number: number): Buffer;
diff --git a/src/script_number.js b/src/script_number.js
index 8220a10..44f4bec 100644
--- a/src/script_number.js
+++ b/src/script_number.js
@@ -1,62 +1,68 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.encode = exports.decode = void 0;
-function decode(buffer, maxLength, minimal) {
-  maxLength = maxLength || 4;
-  minimal = minimal === undefined ? true : minimal;
-  const length = buffer.length;
-  if (length === 0) return 0;
-  if (length > maxLength) throw new TypeError('Script number overflow');
+var Buffer = require('safe-buffer').Buffer
+
+function decode (buffer, maxLength, minimal) {
+  maxLength = maxLength || 4
+  minimal = minimal === undefined ? true : minimal
+
+  var length = buffer.length
+  if (length === 0) return 0
+  if (length > maxLength) throw new TypeError('Script number overflow')
   if (minimal) {
     if ((buffer[length - 1] & 0x7f) === 0) {
-      if (length <= 1 || (buffer[length - 2] & 0x80) === 0)
-        throw new Error('Non-minimally encoded script number');
+      if (length <= 1 || (buffer[length - 2] & 0x80) === 0) throw new Error('Non-minimally encoded script number')
     }
   }
+
   // 40-bit
   if (length === 5) {
-    const a = buffer.readUInt32LE(0);
-    const b = buffer.readUInt8(4);
-    if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a);
-    return b * 0x100000000 + a;
+    var a = buffer.readUInt32LE(0)
+    var b = buffer.readUInt8(4)
+
+    if (b & 0x80) return -(((b & ~0x80) * 0x100000000) + a)
+    return (b * 0x100000000) + a
   }
+
+  var result = 0
+
   // 32-bit / 24-bit / 16-bit / 8-bit
-  let result = 0;
-  for (let i = 0; i < length; ++i) {
-    result |= buffer[i] << (8 * i);
+  for (var i = 0; i < length; ++i) {
+    result |= buffer[i] << (8 * i)
   }
-  if (buffer[length - 1] & 0x80)
-    return -(result & ~(0x80 << (8 * (length - 1))));
-  return result;
+
+  if (buffer[length - 1] & 0x80) return -(result & ~(0x80 << (8 * (length - 1))))
+  return result
 }
-exports.decode = decode;
-function scriptNumSize(i) {
-  return i > 0x7fffffff
-    ? 5
-    : i > 0x7fffff
-    ? 4
-    : i > 0x7fff
-    ? 3
-    : i > 0x7f
-    ? 2
-    : i > 0x00
-    ? 1
-    : 0;
+
+function scriptNumSize (i) {
+  return i > 0x7fffffff ? 5
+  : i > 0x7fffff ? 4
+  : i > 0x7fff ? 3
+  : i > 0x7f ? 2
+  : i > 0x00 ? 1
+  : 0
 }
-function encode(_number) {
-  let value = Math.abs(_number);
-  const size = scriptNumSize(value);
-  const buffer = Buffer.allocUnsafe(size);
-  const negative = _number < 0;
-  for (let i = 0; i < size; ++i) {
-    buffer.writeUInt8(value & 0xff, i);
-    value >>= 8;
+
+function encode (number) {
+  var value = Math.abs(number)
+  var size = scriptNumSize(value)
+  var buffer = Buffer.allocUnsafe(size)
+  var negative = number < 0
+
+  for (var i = 0; i < size; ++i) {
+    buffer.writeUInt8(value & 0xff, i)
+    value >>= 8
   }
+
   if (buffer[size - 1] & 0x80) {
-    buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1);
+    buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1)
   } else if (negative) {
-    buffer[size - 1] |= 0x80;
+    buffer[size - 1] |= 0x80
   }
-  return buffer;
+
+  return buffer
+}
+
+module.exports = {
+  decode: decode,
+  encode: encode
 }
-exports.encode = encode;
diff --git a/src/script_signature.d.ts b/src/script_signature.d.ts
deleted file mode 100644
index 2057dd9..0000000
--- a/src/script_signature.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/// <reference types="node" />
-interface ScriptSignature {
-    signature: Buffer;
-    hashType: number;
-}
-export declare function decode(buffer: Buffer): ScriptSignature;
-export declare function encode(signature: Buffer, hashType: number): Buffer;
-export {};
diff --git a/src/script_signature.js b/src/script_signature.js
deleted file mode 100644
index 638e5f2..0000000
--- a/src/script_signature.js
+++ /dev/null
@@ -1,53 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.encode = exports.decode = void 0;
-const bip66 = require('./bip66');
-const types = require('./types');
-const { typeforce } = types;
-const ZERO = Buffer.alloc(1, 0);
-function toDER(x) {
-  let i = 0;
-  while (x[i] === 0) ++i;
-  if (i === x.length) return ZERO;
-  x = x.slice(i);
-  if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length);
-  return x;
-}
-function fromDER(x) {
-  if (x[0] === 0x00) x = x.slice(1);
-  const buffer = Buffer.alloc(32, 0);
-  const bstart = Math.max(0, 32 - x.length);
-  x.copy(buffer, bstart);
-  return buffer;
-}
-// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed)
-function decode(buffer) {
-  const hashType = buffer.readUInt8(buffer.length - 1);
-  const hashTypeMod = hashType & ~0x80;
-  if (hashTypeMod <= 0 || hashTypeMod >= 4)
-    throw new Error('Invalid hashType ' + hashType);
-  const decoded = bip66.decode(buffer.slice(0, -1));
-  const r = fromDER(decoded.r);
-  const s = fromDER(decoded.s);
-  const signature = Buffer.concat([r, s], 64);
-  return { signature, hashType };
-}
-exports.decode = decode;
-function encode(signature, hashType) {
-  typeforce(
-    {
-      signature: types.BufferN(64),
-      hashType: types.UInt8,
-    },
-    { signature, hashType },
-  );
-  const hashTypeMod = hashType & ~0x80;
-  if (hashTypeMod <= 0 || hashTypeMod >= 4)
-    throw new Error('Invalid hashType ' + hashType);
-  const hashTypeBuffer = Buffer.allocUnsafe(1);
-  hashTypeBuffer.writeUInt8(hashType, 0);
-  const r = toDER(signature.slice(0, 32));
-  const s = toDER(signature.slice(32, 64));
-  return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]);
-}
-exports.encode = encode;
diff --git a/src/templates/index.js b/src/templates/index.js
new file mode 100644
index 0000000..4916c78
--- /dev/null
+++ b/src/templates/index.js
@@ -0,0 +1,74 @@
+var decompile = require('../script').decompile
+var multisig = require('./multisig')
+var nullData = require('./nulldata')
+var pubKey = require('./pubkey')
+var pubKeyHash = require('./pubkeyhash')
+var scriptHash = require('./scripthash')
+var witnessPubKeyHash = require('./witnesspubkeyhash')
+var witnessScriptHash = require('./witnessscripthash')
+var witnessCommitment = require('./witnesscommitment')
+
+var types = {
+  MULTISIG: 'multisig',
+  NONSTANDARD: 'nonstandard',
+  NULLDATA: 'nulldata',
+  P2PK: 'pubkey',
+  P2PKH: 'pubkeyhash',
+  P2SH: 'scripthash',
+  P2WPKH: 'witnesspubkeyhash',
+  P2WSH: 'witnessscripthash',
+  WITNESS_COMMITMENT: 'witnesscommitment'
+}
+
+function classifyOutput (script) {
+  if (witnessPubKeyHash.output.check(script)) return types.P2WPKH
+  if (witnessScriptHash.output.check(script)) return types.P2WSH
+  if (pubKeyHash.output.check(script)) return types.P2PKH
+  if (scriptHash.output.check(script)) return types.P2SH
+
+  // XXX: optimization, below functions .decompile before use
+  var chunks = decompile(script)
+  if (multisig.output.check(chunks)) return types.MULTISIG
+  if (pubKey.output.check(chunks)) return types.P2PK
+  if (witnessCommitment.output.check(chunks)) return types.WITNESS_COMMITMENT
+  if (nullData.output.check(chunks)) return types.NULLDATA
+
+  return types.NONSTANDARD
+}
+
+function classifyInput (script, allowIncomplete) {
+  // XXX: optimization, below functions .decompile before use
+  var chunks = decompile(script)
+
+  if (pubKeyHash.input.check(chunks)) return types.P2PKH
+  if (scriptHash.input.check(chunks, allowIncomplete)) return types.P2SH
+  if (multisig.input.check(chunks, allowIncomplete)) return types.MULTISIG
+  if (pubKey.input.check(chunks)) return types.P2PK
+
+  return types.NONSTANDARD
+}
+
+function classifyWitness (script, allowIncomplete) {
+  // XXX: optimization, below functions .decompile before use
+  var chunks = decompile(script)
+
+  if (witnessPubKeyHash.input.check(chunks)) return types.P2WPKH
+  if (witnessScriptHash.input.check(chunks, allowIncomplete)) return types.P2WSH
+
+  return types.NONSTANDARD
+}
+
+module.exports = {
+  classifyInput: classifyInput,
+  classifyOutput: classifyOutput,
+  classifyWitness: classifyWitness,
+  multisig: multisig,
+  nullData: nullData,
+  pubKey: pubKey,
+  pubKeyHash: pubKeyHash,
+  scriptHash: scriptHash,
+  witnessPubKeyHash: witnessPubKeyHash,
+  witnessScriptHash: witnessScriptHash,
+  witnessCommitment: witnessCommitment,
+  types: types
+}
diff --git a/src/templates/multisig/index.js b/src/templates/multisig/index.js
new file mode 100644
index 0000000..46863d6
--- /dev/null
+++ b/src/templates/multisig/index.js
@@ -0,0 +1,4 @@
+module.exports = {
+  input: require('./input'),
+  output: require('./output')
+}
diff --git a/src/templates/multisig/input.js b/src/templates/multisig/input.js
new file mode 100644
index 0000000..a0b2eee
--- /dev/null
+++ b/src/templates/multisig/input.js
@@ -0,0 +1,72 @@
+// OP_0 [signatures ...]
+
+var Buffer = require('safe-buffer').Buffer
+var bscript = require('../../script')
+var p2mso = require('./output')
+var typeforce = require('typeforce')
+var OPS = require('bitcoin-ops')
+
+function partialSignature (value) {
+  return value === OPS.OP_0 || bscript.isCanonicalSignature(value)
+}
+
+function check (script, allowIncomplete) {
+  var chunks = bscript.decompile(script)
+  if (chunks.length < 2) return false
+  if (chunks[0] !== OPS.OP_0) return false
+
+  if (allowIncomplete) {
+    return chunks.slice(1).every(partialSignature)
+  }
+
+  return chunks.slice(1).every(bscript.isCanonicalSignature)
+}
+check.toJSON = function () { return 'multisig input' }
+
+var EMPTY_BUFFER = Buffer.allocUnsafe(0)
+
+function encodeStack (signatures, scriptPubKey) {
+  typeforce([partialSignature], signatures)
+
+  if (scriptPubKey) {
+    var scriptData = p2mso.decode(scriptPubKey)
+
+    if (signatures.length < scriptData.m) {
+      throw new TypeError('Not enough signatures provided')
+    }
+
+    if (signatures.length > scriptData.pubKeys.length) {
+      throw new TypeError('Too many signatures provided')
+    }
+  }
+
+  return [].concat(EMPTY_BUFFER, signatures.map(function (sig) {
+    if (sig === OPS.OP_0) {
+      return EMPTY_BUFFER
+    }
+    return sig
+  }))
+}
+
+function encode (signatures, scriptPubKey) {
+  return bscript.compile(encodeStack(signatures, scriptPubKey))
+}
+
+function decodeStack (stack, allowIncomplete) {
+  typeforce(typeforce.Array, stack)
+  typeforce(check, stack, allowIncomplete)
+  return stack.slice(1)
+}
+
+function decode (buffer, allowIncomplete) {
+  var stack = bscript.decompile(buffer)
+  return decodeStack(stack, allowIncomplete)
+}
+
+module.exports = {
+  check: check,
+  decode: decode,
+  decodeStack: decodeStack,
+  encode: encode,
+  encodeStack: encodeStack
+}
diff --git a/src/templates/multisig/output.js b/src/templates/multisig/output.js
new file mode 100644
index 0000000..70e8488
--- /dev/null
+++ b/src/templates/multisig/output.js
@@ -0,0 +1,64 @@
+// m [pubKeys ...] n OP_CHECKMULTISIG
+
+var bscript = require('../../script')
+var types = require('../../types')
+var typeforce = require('typeforce')
+var OPS = require('bitcoin-ops')
+var OP_INT_BASE = OPS.OP_RESERVED // OP_1 - 1
+
+function check (script, allowIncomplete) {
+  var chunks = bscript.decompile(script)
+
+  if (chunks.length < 4) return false
+  if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG) return false
+  if (!types.Number(chunks[0])) return false
+  if (!types.Number(chunks[chunks.length - 2])) return false
+  var m = chunks[0] - OP_INT_BASE
+  var n = chunks[chunks.length - 2] - OP_INT_BASE
+
+  if (m <= 0) return false
+  if (n > 16) return false
+  if (m > n) return false
+  if (n !== chunks.length - 3) return false
+  if (allowIncomplete) return true
+
+  var keys = chunks.slice(1, -2)
+  return keys.every(bscript.isCanonicalPubKey)
+}
+check.toJSON = function () { return 'multi-sig output' }
+
+function encode (m, pubKeys) {
+  typeforce({
+    m: types.Number,
+    pubKeys: [bscript.isCanonicalPubKey]
+  }, {
+    m: m,
+    pubKeys: pubKeys
+  })
+
+  var n = pubKeys.length
+  if (n < m) throw new TypeError('Not enough pubKeys provided')
+
+  return bscript.compile([].concat(
+    OP_INT_BASE + m,
+    pubKeys,
+    OP_INT_BASE + n,
+    OPS.OP_CHECKMULTISIG
+  ))
+}
+
+function decode (buffer, allowIncomplete) {
+  var chunks = bscript.decompile(buffer)
+  typeforce(check, chunks, allowIncomplete)
+
+  return {
+    m: chunks[0] - OP_INT_BASE,
+    pubKeys: chunks.slice(1, -2)
+  }
+}
+
+module.exports = {
+  check: check,
+  decode: decode,
+  encode: encode
+}
diff --git a/src/templates/nulldata.js b/src/templates/nulldata.js
new file mode 100644
index 0000000..107aaeb
--- /dev/null
+++ b/src/templates/nulldata.js
@@ -0,0 +1,34 @@
+// OP_RETURN {data}
+
+var bscript = require('../script')
+var types = require('../types')
+var typeforce = require('typeforce')
+var OPS = require('bitcoin-ops')
+
+function check (script) {
+  var buffer = bscript.compile(script)
+
+  return buffer.length > 1 &&
+    buffer[0] === OPS.OP_RETURN
+}
+check.toJSON = function () { return 'null data output' }
+
+function encode (data) {
+  typeforce(types.Buffer, data)
+
+  return bscript.compile([OPS.OP_RETURN, data])
+}
+
+function decode (buffer) {
+  typeforce(check, buffer)
+
+  return buffer.slice(2)
+}
+
+module.exports = {
+  output: {
+    check: check,
+    decode: decode,
+    encode: encode
+  }
+}
diff --git a/src/templates/pubkey/index.js b/src/templates/pubkey/index.js
new file mode 100644
index 0000000..46863d6
--- /dev/null
+++ b/src/templates/pubkey/index.js
@@ -0,0 +1,4 @@
+module.exports = {
+  input: require('./input'),
+  output: require('./output')
+}
diff --git a/src/templates/pubkey/input.js b/src/templates/pubkey/input.js
new file mode 100644
index 0000000..4c61664
--- /dev/null
+++ b/src/templates/pubkey/input.js
@@ -0,0 +1,40 @@
+// {signature}
+
+var bscript = require('../../script')
+var typeforce = require('typeforce')
+
+function check (script) {
+  var chunks = bscript.decompile(script)
+
+  return chunks.length === 1 &&
+    bscript.isCanonicalSignature(chunks[0])
+}
+check.toJSON = function () { return 'pubKey input' }
+
+function encodeStack (signature) {
+  typeforce(bscript.isCanonicalSignature, signature)
+  return [signature]
+}
+
+function encode (signature) {
+  return bscript.compile(encodeStack(signature))
+}
+
+function decodeStack (stack) {
+  typeforce(typeforce.Array, stack)
+  typeforce(check, stack)
+  return stack[0]
+}
+
+function decode (buffer) {
+  var stack = bscript.decompile(buffer)
+  return decodeStack(stack)
+}
+
+module.exports = {
+  check: check,
+  decode: decode,
+  decodeStack: decodeStack,
+  encode: encode,
+  encodeStack: encodeStack
+}
diff --git a/src/templates/pubkey/output.js b/src/templates/pubkey/output.js
new file mode 100644
index 0000000..69a747f
--- /dev/null
+++ b/src/templates/pubkey/output.js
@@ -0,0 +1,33 @@
+// {pubKey} OP_CHECKSIG
+
+var bscript = require('../../script')
+var typeforce = require('typeforce')
+var OPS = require('bitcoin-ops')
+
+function check (script) {
+  var chunks = bscript.decompile(script)
+
+  return chunks.length === 2 &&
+    bscript.isCanonicalPubKey(chunks[0]) &&
+    chunks[1] === OPS.OP_CHECKSIG
+}
+check.toJSON = function () { return 'pubKey output' }
+
+function encode (pubKey) {
+  typeforce(bscript.isCanonicalPubKey, pubKey)
+
+  return bscript.compile([pubKey, OPS.OP_CHECKSIG])
+}
+
+function decode (buffer) {
+  var chunks = bscript.decompile(buffer)
+  typeforce(check, chunks)
+
+  return chunks[0]
+}
+
+module.exports = {
+  check: check,
+  decode: decode,
+  encode: encode
+}
diff --git a/src/templates/pubkeyhash/index.js b/src/templates/pubkeyhash/index.js
new file mode 100644
index 0000000..46863d6
--- /dev/null
+++ b/src/templates/pubkeyhash/index.js
@@ -0,0 +1,4 @@
+module.exports = {
+  input: require('./input'),
+  output: require('./output')
+}
diff --git a/src/templates/pubkeyhash/input.js b/src/templates/pubkeyhash/input.js
new file mode 100644
index 0000000..ae1d758
--- /dev/null
+++ b/src/templates/pubkeyhash/input.js
@@ -0,0 +1,52 @@
+// {signature} {pubKey}
+
+var bscript = require('../../script')
+var typeforce = require('typeforce')
+
+function check (script) {
+  var chunks = bscript.decompile(script)
+
+  return chunks.length === 2 &&
+    bscript.isCanonicalSignature(chunks[0]) &&
+    bscript.isCanonicalPubKey(chunks[1])
+}
+check.toJSON = function () { return 'pubKeyHash input' }
+
+function encodeStack (signature, pubKey) {
+  typeforce({
+    signature: bscript.isCanonicalSignature,
+    pubKey: bscript.isCanonicalPubKey
+  }, {
+    signature: signature,
+    pubKey: pubKey
+  })
+
+  return [signature, pubKey]
+}
+
+function encode (signature, pubKey) {
+  return bscript.compile(encodeStack(signature, pubKey))
+}
+
+function decodeStack (stack) {
+  typeforce(typeforce.Array, stack)
+  typeforce(check, stack)
+
+  return {
+    signature: stack[0],
+    pubKey: stack[1]
+  }
+}
+
+function decode (buffer) {
+  var stack = bscript.decompile(buffer)
+  return decodeStack(stack)
+}
+
+module.exports = {
+  check: check,
+  decode: decode,
+  decodeStack: decodeStack,
+  encode: encode,
+  encodeStack: encodeStack
+}
diff --git a/src/templates/pubkeyhash/output.js b/src/templates/pubkeyhash/output.js
new file mode 100644
index 0000000..2a7c4ab
--- /dev/null
+++ b/src/templates/pubkeyhash/output.js
@@ -0,0 +1,42 @@
+// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
+
+var bscript = require('../../script')
+var types = require('../../types')
+var typeforce = require('typeforce')
+var OPS = require('bitcoin-ops')
+
+function check (script) {
+  var buffer = bscript.compile(script)
+
+  return buffer.length === 25 &&
+    buffer[0] === OPS.OP_DUP &&
+    buffer[1] === OPS.OP_HASH160 &&
+    buffer[2] === 0x14 &&
+    buffer[23] === OPS.OP_EQUALVERIFY &&
+    buffer[24] === OPS.OP_CHECKSIG
+}
+check.toJSON = function () { return 'pubKeyHash output' }
+
+function encode (pubKeyHash) {
+  typeforce(types.Hash160bit, pubKeyHash)
+
+  return bscript.compile([
+    OPS.OP_DUP,
+    OPS.OP_HASH160,
+    pubKeyHash,
+    OPS.OP_EQUALVERIFY,
+    OPS.OP_CHECKSIG
+  ])
+}
+
+function decode (buffer) {
+  typeforce(check, buffer)
+
+  return buffer.slice(3, 23)
+}
+
+module.exports = {
+  check: check,
+  decode: decode,
+  encode: encode
+}
diff --git a/src/templates/scripthash/index.js b/src/templates/scripthash/index.js
new file mode 100644
index 0000000..46863d6
--- /dev/null
+++ b/src/templates/scripthash/index.js
@@ -0,0 +1,4 @@
+module.exports = {
+  input: require('./input'),
+  output: require('./output')
+}
diff --git a/src/templates/scripthash/input.js b/src/templates/scripthash/input.js
new file mode 100644
index 0000000..cc5bb74
--- /dev/null
+++ b/src/templates/scripthash/input.js
@@ -0,0 +1,85 @@
+// <scriptSig> {serialized scriptPubKey script}
+
+var Buffer = require('safe-buffer').Buffer
+var bscript = require('../../script')
+var typeforce = require('typeforce')
+
+var p2ms = require('../multisig/')
+var p2pk = require('../pubkey/')
+var p2pkh = require('../pubkeyhash/')
+var p2wpkho = require('../witnesspubkeyhash/output')
+var p2wsho = require('../witnessscripthash/output')
+
+function check (script, allowIncomplete) {
+  var chunks = bscript.decompile(script)
+  if (chunks.length < 1) return false
+
+  var lastChunk = chunks[chunks.length - 1]
+  if (!Buffer.isBuffer(lastChunk)) return false
+
+  var scriptSigChunks = bscript.decompile(bscript.compile(chunks.slice(0, -1)))
+  var redeemScriptChunks = bscript.decompile(lastChunk)
+
+  // is redeemScript a valid script?
+  if (redeemScriptChunks.length === 0) return false
+
+  // is redeemScriptSig push only?
+  if (!bscript.isPushOnly(scriptSigChunks)) return false
+
+  // is witness?
+  if (chunks.length === 1) {
+    return p2wsho.check(redeemScriptChunks) ||
+      p2wpkho.check(redeemScriptChunks)
+  }
+
+  // match types
+  if (p2pkh.input.check(scriptSigChunks) &&
+    p2pkh.output.check(redeemScriptChunks)) return true
+
+  if (p2ms.input.check(scriptSigChunks, allowIncomplete) &&
+    p2ms.output.check(redeemScriptChunks)) return true
+
+  if (p2pk.input.check(scriptSigChunks) &&
+    p2pk.output.check(redeemScriptChunks)) return true
+
+  return false
+}
+check.toJSON = function () { return 'scriptHash input' }
+
+function encodeStack (redeemScriptStack, redeemScript) {
+  var serializedScriptPubKey = bscript.compile(redeemScript)
+
+  return [].concat(redeemScriptStack, serializedScriptPubKey)
+}
+
+function encode (redeemScriptSig, redeemScript) {
+  var redeemScriptStack = bscript.decompile(redeemScriptSig)
+
+  return bscript.compile(encodeStack(redeemScriptStack, redeemScript))
+}
+
+function decodeStack (stack) {
+  typeforce(typeforce.Array, stack)
+  typeforce(check, stack)
+
+  return {
+    redeemScriptStack: stack.slice(0, -1),
+    redeemScript: stack[stack.length - 1]
+  }
+}
+
+function decode (buffer) {
+  var stack = bscript.decompile(buffer)
+  var result = decodeStack(stack)
+  result.redeemScriptSig = bscript.compile(result.redeemScriptStack)
+  delete result.redeemScriptStack
+  return result
+}
+
+module.exports = {
+  check: check,
+  decode: decode,
+  decodeStack: decodeStack,
+  encode: encode,
+  encodeStack: encodeStack
+}
diff --git a/src/templates/scripthash/output.js b/src/templates/scripthash/output.js
new file mode 100644
index 0000000..83d2501
--- /dev/null
+++ b/src/templates/scripthash/output.js
@@ -0,0 +1,34 @@
+// OP_HASH160 {scriptHash} OP_EQUAL
+
+var bscript = require('../../script')
+var types = require('../../types')
+var typeforce = require('typeforce')
+var OPS = require('bitcoin-ops')
+
+function check (script) {
+  var buffer = bscript.compile(script)
+
+  return buffer.length === 23 &&
+    buffer[0] === OPS.OP_HASH160 &&
+    buffer[1] === 0x14 &&
+    buffer[22] === OPS.OP_EQUAL
+}
+check.toJSON = function () { return 'scriptHash output' }
+
+function encode (scriptHash) {
+  typeforce(types.Hash160bit, scriptHash)
+
+  return bscript.compile([OPS.OP_HASH160, scriptHash, OPS.OP_EQUAL])
+}
+
+function decode (buffer) {
+  typeforce(check, buffer)
+
+  return buffer.slice(2, 22)
+}
+
+module.exports = {
+  check: check,
+  decode: decode,
+  encode: encode
+}
diff --git a/src/templates/witnesscommitment/index.js b/src/templates/witnesscommitment/index.js
new file mode 100644
index 0000000..d459038
--- /dev/null
+++ b/src/templates/witnesscommitment/index.js
@@ -0,0 +1,3 @@
+module.exports = {
+  output: require('./output')
+}
diff --git a/src/templates/witnesscommitment/output.js b/src/templates/witnesscommitment/output.js
new file mode 100644
index 0000000..3984ea5
--- /dev/null
+++ b/src/templates/witnesscommitment/output.js
@@ -0,0 +1,42 @@
+// OP_RETURN {aa21a9ed} {commitment}
+
+var Buffer = require('safe-buffer').Buffer
+var bscript = require('../../script')
+var types = require('../../types')
+var typeforce = require('typeforce')
+var OPS = require('bitcoin-ops')
+
+var HEADER = Buffer.from('aa21a9ed', 'hex')
+
+function check (script) {
+  var buffer = bscript.compile(script)
+
+  return buffer.length > 37 &&
+    buffer[0] === OPS.OP_RETURN &&
+    buffer[1] === 0x24 &&
+    buffer.slice(2, 6).equals(HEADER)
+}
+
+check.toJSON = function () { return 'Witness commitment output' }
+
+function encode (commitment) {
+  typeforce(types.Hash256bit, commitment)
+
+  var buffer = Buffer.allocUnsafe(36)
+  HEADER.copy(buffer, 0)
+  commitment.copy(buffer, 4)
+
+  return bscript.compile([OPS.OP_RETURN, buffer])
+}
+
+function decode (buffer) {
+  typeforce(check, buffer)
+
+  return bscript.decompile(buffer)[1].slice(4, 36)
+}
+
+module.exports = {
+  check: check,
+  decode: decode,
+  encode: encode
+}
diff --git a/src/templates/witnesspubkeyhash/index.js b/src/templates/witnesspubkeyhash/index.js
new file mode 100644
index 0000000..46863d6
--- /dev/null
+++ b/src/templates/witnesspubkeyhash/index.js
@@ -0,0 +1,4 @@
+module.exports = {
+  input: require('./input'),
+  output: require('./output')
+}
diff --git a/src/templates/witnesspubkeyhash/input.js b/src/templates/witnesspubkeyhash/input.js
new file mode 100644
index 0000000..d61c426
--- /dev/null
+++ b/src/templates/witnesspubkeyhash/input.js
@@ -0,0 +1,45 @@
+// {signature} {pubKey}
+
+var bscript = require('../../script')
+var typeforce = require('typeforce')
+
+function isCompressedCanonicalPubKey (pubKey) {
+  return bscript.isCanonicalPubKey(pubKey) && pubKey.length === 33
+}
+
+function check (script) {
+  var chunks = bscript.decompile(script)
+
+  return chunks.length === 2 &&
+    bscript.isCanonicalSignature(chunks[0]) &&
+    isCompressedCanonicalPubKey(chunks[1])
+}
+check.toJSON = function () { return 'witnessPubKeyHash input' }
+
+function encodeStack (signature, pubKey) {
+  typeforce({
+    signature: bscript.isCanonicalSignature,
+    pubKey: isCompressedCanonicalPubKey
+  }, {
+    signature: signature,
+    pubKey: pubKey
+  })
+
+  return [signature, pubKey]
+}
+
+function decodeStack (stack) {
+  typeforce(typeforce.Array, stack)
+  typeforce(check, stack)
+
+  return {
+    signature: stack[0],
+    pubKey: stack[1]
+  }
+}
+
+module.exports = {
+  check: check,
+  decodeStack: decodeStack,
+  encodeStack: encodeStack
+}
diff --git a/src/templates/witnesspubkeyhash/output.js b/src/templates/witnesspubkeyhash/output.js
new file mode 100644
index 0000000..ebcb185
--- /dev/null
+++ b/src/templates/witnesspubkeyhash/output.js
@@ -0,0 +1,33 @@
+// OP_0 {pubKeyHash}
+
+var bscript = require('../../script')
+var types = require('../../types')
+var typeforce = require('typeforce')
+var OPS = require('bitcoin-ops')
+
+function check (script) {
+  var buffer = bscript.compile(script)
+
+  return buffer.length === 22 &&
+    buffer[0] === OPS.OP_0 &&
+    buffer[1] === 0x14
+}
+check.toJSON = function () { return 'Witness pubKeyHash output' }
+
+function encode (pubKeyHash) {
+  typeforce(types.Hash160bit, pubKeyHash)
+
+  return bscript.compile([OPS.OP_0, pubKeyHash])
+}
+
+function decode (buffer) {
+  typeforce(check, buffer)
+
+  return buffer.slice(2)
+}
+
+module.exports = {
+  check: check,
+  decode: decode,
+  encode: encode
+}
diff --git a/src/templates/witnessscripthash/index.js b/src/templates/witnessscripthash/index.js
new file mode 100644
index 0000000..46863d6
--- /dev/null
+++ b/src/templates/witnessscripthash/index.js
@@ -0,0 +1,4 @@
+module.exports = {
+  input: require('./input'),
+  output: require('./output')
+}
diff --git a/src/templates/witnessscripthash/input.js b/src/templates/witnessscripthash/input.js
new file mode 100644
index 0000000..d6e85f5
--- /dev/null
+++ b/src/templates/witnessscripthash/input.js
@@ -0,0 +1,64 @@
+// <scriptSig> {serialized scriptPubKey script}
+
+var bscript = require('../../script')
+var types = require('../../types')
+var typeforce = require('typeforce')
+
+var p2ms = require('../multisig/')
+var p2pk = require('../pubkey/')
+var p2pkh = require('../pubkeyhash/')
+
+function check (chunks, allowIncomplete) {
+  typeforce(types.Array, chunks)
+  if (chunks.length < 1) return false
+
+  var witnessScript = chunks[chunks.length - 1]
+  if (!Buffer.isBuffer(witnessScript)) return false
+
+  var witnessScriptChunks = bscript.decompile(witnessScript)
+
+  // is witnessScript a valid script?
+  if (witnessScriptChunks.length === 0) return false
+
+  var witnessRawScriptSig = bscript.compile(chunks.slice(0, -1))
+
+  // match types
+  if (p2pkh.input.check(witnessRawScriptSig) &&
+    p2pkh.output.check(witnessScriptChunks)) return true
+
+  if (p2ms.input.check(witnessRawScriptSig, allowIncomplete) &&
+    p2ms.output.check(witnessScriptChunks)) return true
+
+  if (p2pk.input.check(witnessRawScriptSig) &&
+    p2pk.output.check(witnessScriptChunks)) return true
+
+  return false
+}
+check.toJSON = function () { return 'witnessScriptHash input' }
+
+function encodeStack (witnessData, witnessScript) {
+  typeforce({
+    witnessData: [types.Buffer],
+    witnessScript: types.Buffer
+  }, {
+    witnessData: witnessData,
+    witnessScript: witnessScript
+  })
+
+  return [].concat(witnessData, witnessScript)
+}
+
+function decodeStack (stack) {
+  typeforce(typeforce.Array, stack)
+  typeforce(check, stack)
+  return {
+    witnessData: stack.slice(0, -1),
+    witnessScript: stack[stack.length - 1]
+  }
+}
+
+module.exports = {
+  check: check,
+  decodeStack: decodeStack,
+  encodeStack: encodeStack
+}
diff --git a/src/templates/witnessscripthash/output.js b/src/templates/witnessscripthash/output.js
new file mode 100644
index 0000000..f1656b5
--- /dev/null
+++ b/src/templates/witnessscripthash/output.js
@@ -0,0 +1,33 @@
+// OP_0 {scriptHash}
+
+var bscript = require('../../script')
+var types = require('../../types')
+var typeforce = require('typeforce')
+var OPS = require('bitcoin-ops')
+
+function check (script) {
+  var buffer = bscript.compile(script)
+
+  return buffer.length === 34 &&
+    buffer[0] === OPS.OP_0 &&
+    buffer[1] === 0x20
+}
+check.toJSON = function () { return 'Witness scriptHash output' }
+
+function encode (scriptHash) {
+  typeforce(types.Hash256bit, scriptHash)
+
+  return bscript.compile([OPS.OP_0, scriptHash])
+}
+
+function decode (buffer) {
+  typeforce(check, buffer)
+
+  return buffer.slice(2)
+}
+
+module.exports = {
+  check: check,
+  decode: decode,
+  encode: encode
+}
diff --git a/src/transaction.d.ts b/src/transaction.d.ts
deleted file mode 100644
index 613706b..0000000
--- a/src/transaction.d.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/// <reference types="node" />
-export interface Output {
-    script: Buffer;
-    value: number;
-}
-export interface Input {
-    hash: Buffer;
-    index: number;
-    script: Buffer;
-    sequence: number;
-    witness: Buffer[];
-}
-export declare class Transaction {
-    static readonly DEFAULT_SEQUENCE = 4294967295;
-    static readonly SIGHASH_DEFAULT = 0;
-    static readonly SIGHASH_ALL = 1;
-    static readonly SIGHASH_NONE = 2;
-    static readonly SIGHASH_SINGLE = 3;
-    static readonly SIGHASH_ANYONECANPAY = 128;
-    static readonly SIGHASH_OUTPUT_MASK = 3;
-    static readonly SIGHASH_INPUT_MASK = 128;
-    static readonly ADVANCED_TRANSACTION_MARKER = 0;
-    static readonly ADVANCED_TRANSACTION_FLAG = 1;
-    static fromBuffer(buffer: Buffer, _NO_STRICT?: boolean): Transaction;
-    static fromHex(hex: string): Transaction;
-    static isCoinbaseHash(buffer: Buffer): boolean;
-    version: number;
-    locktime: number;
-    ins: Input[];
-    outs: Output[];
-    isCoinbase(): boolean;
-    addInput(hash: Buffer, index: number, sequence?: number, scriptSig?: Buffer): number;
-    addOutput(scriptPubKey: Buffer, value: number): number;
-    hasWitnesses(): boolean;
-    weight(): number;
-    virtualSize(): number;
-    byteLength(_ALLOW_WITNESS?: boolean): number;
-    clone(): Transaction;
-    /**
-     * Hash transaction for signing a specific input.
-     *
-     * Bitcoin uses a different hash for each signed transaction input.
-     * This method copies the transaction, makes the necessary changes based on the
-     * hashType, and then hashes the result.
-     * This hash can then be used to sign the provided transaction input.
-     */
-    hashForSignature(inIndex: number, prevOutScript: Buffer, hashType: number): Buffer;
-    hashForWitnessV1(inIndex: number, prevOutScripts: Buffer[], values: number[], hashType: number, leafHash?: Buffer, annex?: Buffer): Buffer;
-    hashForWitnessV0(inIndex: number, prevOutScript: Buffer, value: number, hashType: number): Buffer;
-    getHash(forWitness?: boolean): Buffer;
-    getId(): string;
-    toBuffer(buffer?: Buffer, initialOffset?: number): Buffer;
-    toHex(): string;
-    setInputScript(index: number, scriptSig: Buffer): void;
-    setWitness(index: number, witness: Buffer[]): void;
-    private __toBuffer;
-}
diff --git a/src/transaction.js b/src/transaction.js
index 6f1382c..86cccea 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -1,542 +1,492 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.Transaction = void 0;
-const bufferutils_1 = require('./bufferutils');
-const bcrypto = require('./crypto');
-const bscript = require('./script');
-const script_1 = require('./script');
-const types = require('./types');
-const { typeforce } = types;
-function varSliceSize(someScript) {
-  const length = someScript.length;
-  return bufferutils_1.varuint.encodingLength(length) + length;
+var Buffer = require('safe-buffer').Buffer
+var bcrypto = require('./crypto')
+var bscript = require('./script')
+var bufferutils = require('./bufferutils')
+var opcodes = require('bitcoin-ops')
+var typeforce = require('typeforce')
+var types = require('./types')
+var varuint = require('varuint-bitcoin')
+
+function varSliceSize (someScript) {
+  var length = someScript.length
+
+  return varuint.encodingLength(length) + length
 }
-function vectorSize(someVector) {
-  const length = someVector.length;
+
+function vectorSize (someVector) {
+  var length = someVector.length
+
+  return varuint.encodingLength(length) + someVector.reduce(function (sum, witness) {
+    return sum + varSliceSize(witness)
+  }, 0)
+}
+
+function Transaction () {
+  this.version = 1
+  this.locktime = 0
+  this.ins = []
+  this.outs = []
+}
+
+Transaction.DEFAULT_SEQUENCE = 0xffffffff
+Transaction.SIGHASH_ALL = 0x01
+Transaction.SIGHASH_NONE = 0x02
+Transaction.SIGHASH_SINGLE = 0x03
+Transaction.SIGHASH_ANYONECANPAY = 0x80
+Transaction.ADVANCED_TRANSACTION_MARKER = 0x00
+Transaction.ADVANCED_TRANSACTION_FLAG = 0x01
+
+var EMPTY_SCRIPT = Buffer.allocUnsafe(0)
+var EMPTY_WITNESS = []
+var ZERO = Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex')
+var ONE = Buffer.from('0000000000000000000000000000000000000000000000000000000000000001', 'hex')
+var VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex')
+var BLANK_OUTPUT = {
+  script: EMPTY_SCRIPT,
+  valueBuffer: VALUE_UINT64_MAX
+}
+
+Transaction.fromBuffer = function (buffer, __noStrict) {
+  var offset = 0
+  function readSlice (n) {
+    offset += n
+    return buffer.slice(offset - n, offset)
+  }
+
+  function readUInt32 () {
+    var i = buffer.readUInt32LE(offset)
+    offset += 4
+    return i
+  }
+
+  function readInt32 () {
+    var i = buffer.readInt32LE(offset)
+    offset += 4
+    return i
+  }
+
+  function readUInt64 () {
+    var i = bufferutils.readUInt64LE(buffer, offset)
+    offset += 8
+    return i
+  }
+
+  function readVarInt () {
+    var vi = varuint.decode(buffer, offset)
+    offset += varuint.decode.bytes
+    return vi
+  }
+
+  function readVarSlice () {
+    return readSlice(readVarInt())
+  }
+
+  function readVector () {
+    var count = readVarInt()
+    var vector = []
+    for (var i = 0; i < count; i++) vector.push(readVarSlice())
+    return vector
+  }
+
+  var tx = new Transaction()
+  tx.version = readInt32()
+
+  var marker = buffer.readUInt8(offset)
+  var flag = buffer.readUInt8(offset + 1)
+
+  var hasWitnesses = false
+  if (marker === Transaction.ADVANCED_TRANSACTION_MARKER &&
+      flag === Transaction.ADVANCED_TRANSACTION_FLAG) {
+    offset += 2
+    hasWitnesses = true
+  }
+
+  var vinLen = readVarInt()
+  for (var i = 0; i < vinLen; ++i) {
+    tx.ins.push({
+      hash: readSlice(32),
+      index: readUInt32(),
+      script: readVarSlice(),
+      sequence: readUInt32(),
+      witness: EMPTY_WITNESS
+    })
+  }
+
+  var voutLen = readVarInt()
+  for (i = 0; i < voutLen; ++i) {
+    tx.outs.push({
+      value: readUInt64(),
+      script: readVarSlice()
+    })
+  }
+
+  if (hasWitnesses) {
+    for (i = 0; i < vinLen; ++i) {
+      tx.ins[i].witness = readVector()
+    }
+
+    // was this pointless?
+    if (!tx.hasWitnesses()) throw new Error('Transaction has superfluous witness data')
+  }
+
+  tx.locktime = readUInt32()
+
+  if (__noStrict) return tx
+  if (offset !== buffer.length) throw new Error('Transaction has unexpected data')
+
+  return tx
+}
+
+Transaction.fromHex = function (hex) {
+  return Transaction.fromBuffer(Buffer.from(hex, 'hex'))
+}
+
+Transaction.isCoinbaseHash = function (buffer) {
+  typeforce(types.Hash256bit, buffer)
+  for (var i = 0; i < 32; ++i) {
+    if (buffer[i] !== 0) return false
+  }
+  return true
+}
+
+Transaction.prototype.isCoinbase = function () {
+  return this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash)
+}
+
+Transaction.prototype.addInput = function (hash, index, sequence, scriptSig) {
+  typeforce(types.tuple(
+    types.Hash256bit,
+    types.UInt32,
+    types.maybe(types.UInt32),
+    types.maybe(types.Buffer)
+  ), arguments)
+
+  if (types.Null(sequence)) {
+    sequence = Transaction.DEFAULT_SEQUENCE
+  }
+
+  // Add the input and return the input's index
+  return (this.ins.push({
+    hash: hash,
+    index: index,
+    script: scriptSig || EMPTY_SCRIPT,
+    sequence: sequence,
+    witness: EMPTY_WITNESS
+  }) - 1)
+}
+
+Transaction.prototype.addOutput = function (scriptPubKey, value) {
+  typeforce(types.tuple(types.Buffer, types.Satoshi), arguments)
+
+  // Add the output and return the output's index
+  return (this.outs.push({
+    script: scriptPubKey,
+    value: value
+  }) - 1)
+}
+
+Transaction.prototype.hasWitnesses = function () {
+  return this.ins.some(function (x) {
+    return x.witness.length !== 0
+  })
+}
+
+Transaction.prototype.weight = function () {
+  var base = this.__byteLength(false)
+  var total = this.__byteLength(true)
+  return base * 3 + total
+}
+
+Transaction.prototype.virtualSize = function () {
+  return Math.ceil(this.weight() / 4)
+}
+
+Transaction.prototype.byteLength = function () {
+  return this.__byteLength(true)
+}
+
+Transaction.prototype.__byteLength = function (__allowWitness) {
+  var hasWitnesses = __allowWitness && this.hasWitnesses()
+
   return (
-    bufferutils_1.varuint.encodingLength(length) +
-    someVector.reduce((sum, witness) => {
-      return sum + varSliceSize(witness);
+    (hasWitnesses ? 10 : 8) +
+    varuint.encodingLength(this.ins.length) +
+    varuint.encodingLength(this.outs.length) +
+    this.ins.reduce(function (sum, input) { return sum + 40 + varSliceSize(input.script) }, 0) +
+    this.outs.reduce(function (sum, output) { return sum + 8 + varSliceSize(output.script) }, 0) +
+    (hasWitnesses ? this.ins.reduce(function (sum, input) { return sum + vectorSize(input.witness) }, 0) : 0)
+  )
+}
+
+Transaction.prototype.clone = function () {
+  var newTx = new Transaction()
+  newTx.version = this.version
+  newTx.locktime = this.locktime
+
+  newTx.ins = this.ins.map(function (txIn) {
+    return {
+      hash: txIn.hash,
+      index: txIn.index,
+      script: txIn.script,
+      sequence: txIn.sequence,
+      witness: txIn.witness
+    }
+  })
+
+  newTx.outs = this.outs.map(function (txOut) {
+    return {
+      script: txOut.script,
+      value: txOut.value
+    }
+  })
+
+  return newTx
+}
+
+/**
+ * Hash transaction for signing a specific input.
+ *
+ * Bitcoin uses a different hash for each signed transaction input.
+ * This method copies the transaction, makes the necessary changes based on the
+ * hashType, and then hashes the result.
+ * This hash can then be used to sign the provided transaction input.
+ */
+Transaction.prototype.hashForSignature = function (inIndex, prevOutScript, hashType) {
+  typeforce(types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number), arguments)
+
+  // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29
+  if (inIndex >= this.ins.length) return ONE
+
+  // ignore OP_CODESEPARATOR
+  var ourScript = bscript.compile(bscript.decompile(prevOutScript).filter(function (x) {
+    return x !== opcodes.OP_CODESEPARATOR
+  }))
+
+  var txTmp = this.clone()
+
+  // SIGHASH_NONE: ignore all outputs? (wildcard payee)
+  if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) {
+    txTmp.outs = []
+
+    // ignore sequence numbers (except at inIndex)
+    txTmp.ins.forEach(function (input, i) {
+      if (i === inIndex) return
+
+      input.sequence = 0
+    })
+
+  // SIGHASH_SINGLE: ignore all outputs, except at the same index?
+  } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) {
+    // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60
+    if (inIndex >= this.outs.length) return ONE
+
+    // truncate outputs after
+    txTmp.outs.length = inIndex + 1
+
+    // "blank" outputs before
+    for (var i = 0; i < inIndex; i++) {
+      txTmp.outs[i] = BLANK_OUTPUT
+    }
+
+    // ignore sequence numbers (except at inIndex)
+    txTmp.ins.forEach(function (input, y) {
+      if (y === inIndex) return
+
+      input.sequence = 0
+    })
+  }
+
+  // SIGHASH_ANYONECANPAY: ignore inputs entirely?
+  if (hashType & Transaction.SIGHASH_ANYONECANPAY) {
+    txTmp.ins = [txTmp.ins[inIndex]]
+    txTmp.ins[0].script = ourScript
+
+  // SIGHASH_ALL: only ignore input scripts
+  } else {
+    // "blank" others input scripts
+    txTmp.ins.forEach(function (input) { input.script = EMPTY_SCRIPT })
+    txTmp.ins[inIndex].script = ourScript
+  }
+
+  // serialize and hash
+  var buffer = Buffer.allocUnsafe(txTmp.__byteLength(false) + 4)
+  buffer.writeInt32LE(hashType, buffer.length - 4)
+  txTmp.__toBuffer(buffer, 0, false)
+
+  return bcrypto.hash256(buffer)
+}
+
+Transaction.prototype.hashForWitnessV0 = function (inIndex, prevOutScript, value, hashType) {
+  typeforce(types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32), arguments)
+
+  var tbuffer, toffset
+  function writeSlice (slice) { toffset += slice.copy(tbuffer, toffset) }
+  function writeUInt32 (i) { toffset = tbuffer.writeUInt32LE(i, toffset) }
+  function writeUInt64 (i) { toffset = bufferutils.writeUInt64LE(tbuffer, i, toffset) }
+  function writeVarInt (i) {
+    varuint.encode(i, tbuffer, toffset)
+    toffset += varuint.encode.bytes
+  }
+  function writeVarSlice (slice) { writeVarInt(slice.length); writeSlice(slice) }
+
+  var hashOutputs = ZERO
+  var hashPrevouts = ZERO
+  var hashSequence = ZERO
+
+  if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) {
+    tbuffer = Buffer.allocUnsafe(36 * this.ins.length)
+    toffset = 0
+
+    this.ins.forEach(function (txIn) {
+      writeSlice(txIn.hash)
+      writeUInt32(txIn.index)
+    })
+
+    hashPrevouts = bcrypto.hash256(tbuffer)
+  }
+
+  if (!(hashType & Transaction.SIGHASH_ANYONECANPAY) &&
+       (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE &&
+       (hashType & 0x1f) !== Transaction.SIGHASH_NONE) {
+    tbuffer = Buffer.allocUnsafe(4 * this.ins.length)
+    toffset = 0
+
+    this.ins.forEach(function (txIn) {
+      writeUInt32(txIn.sequence)
+    })
+
+    hashSequence = bcrypto.hash256(tbuffer)
+  }
+
+  if ((hashType & 0x1f) !== Transaction.SIGHASH_SINGLE &&
+      (hashType & 0x1f) !== Transaction.SIGHASH_NONE) {
+    var txOutsSize = this.outs.reduce(function (sum, output) {
+      return sum + 8 + varSliceSize(output.script)
     }, 0)
-  );
+
+    tbuffer = Buffer.allocUnsafe(txOutsSize)
+    toffset = 0
+
+    this.outs.forEach(function (out) {
+      writeUInt64(out.value)
+      writeVarSlice(out.script)
+    })
+
+    hashOutputs = bcrypto.hash256(tbuffer)
+  } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE && inIndex < this.outs.length) {
+    var output = this.outs[inIndex]
+
+    tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script))
+    toffset = 0
+    writeUInt64(output.value)
+    writeVarSlice(output.script)
+
+    hashOutputs = bcrypto.hash256(tbuffer)
+  }
+
+  tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript))
+  toffset = 0
+
+  var input = this.ins[inIndex]
+  writeUInt32(this.version)
+  writeSlice(hashPrevouts)
+  writeSlice(hashSequence)
+  writeSlice(input.hash)
+  writeUInt32(input.index)
+  writeVarSlice(prevOutScript)
+  writeUInt64(value)
+  writeUInt32(input.sequence)
+  writeSlice(hashOutputs)
+  writeUInt32(this.locktime)
+  writeUInt32(hashType)
+  return bcrypto.hash256(tbuffer)
 }
-const EMPTY_BUFFER = Buffer.allocUnsafe(0);
-const EMPTY_WITNESS = [];
-const ZERO = Buffer.from(
-  '0000000000000000000000000000000000000000000000000000000000000000',
-  'hex',
-);
-const ONE = Buffer.from(
-  '0000000000000000000000000000000000000000000000000000000000000001',
-  'hex',
-);
-const VALUE_UINT64_MAX = Buffer.from('ffffffffffffffff', 'hex');
-const BLANK_OUTPUT = {
-  script: EMPTY_BUFFER,
-  valueBuffer: VALUE_UINT64_MAX,
-};
-function isOutput(out) {
-  return out.value !== undefined;
+
+Transaction.prototype.getHash = function () {
+  return bcrypto.hash256(this.__toBuffer(undefined, undefined, false))
 }
-class Transaction {
-  constructor() {
-    this.version = 1;
-    this.locktime = 0;
-    this.ins = [];
-    this.outs = [];
-  }
-  static fromBuffer(buffer, _NO_STRICT) {
-    const bufferReader = new bufferutils_1.BufferReader(buffer);
-    const tx = new Transaction();
-    tx.version = bufferReader.readInt32();
-    const marker = bufferReader.readUInt8();
-    const flag = bufferReader.readUInt8();
-    let hasWitnesses = false;
-    if (
-      marker === Transaction.ADVANCED_TRANSACTION_MARKER &&
-      flag === Transaction.ADVANCED_TRANSACTION_FLAG
-    ) {
-      hasWitnesses = true;
-    } else {
-      bufferReader.offset -= 2;
-    }
-    const vinLen = bufferReader.readVarInt();
-    for (let i = 0; i < vinLen; ++i) {
-      tx.ins.push({
-        hash: bufferReader.readSlice(32),
-        index: bufferReader.readUInt32(),
-        script: bufferReader.readVarSlice(),
-        sequence: bufferReader.readUInt32(),
-        witness: EMPTY_WITNESS,
-      });
-    }
-    const voutLen = bufferReader.readVarInt();
-    for (let i = 0; i < voutLen; ++i) {
-      tx.outs.push({
-        value: bufferReader.readUInt64(),
-        script: bufferReader.readVarSlice(),
-      });
-    }
-    if (hasWitnesses) {
-      for (let i = 0; i < vinLen; ++i) {
-        tx.ins[i].witness = bufferReader.readVector();
-      }
-      // was this pointless?
-      if (!tx.hasWitnesses())
-        throw new Error('Transaction has superfluous witness data');
-    }
-    tx.locktime = bufferReader.readUInt32();
-    if (_NO_STRICT) return tx;
-    if (bufferReader.offset !== buffer.length)
-      throw new Error('Transaction has unexpected data');
-    return tx;
-  }
-  static fromHex(hex) {
-    return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false);
-  }
-  static isCoinbaseHash(buffer) {
-    typeforce(types.Hash256bit, buffer);
-    for (let i = 0; i < 32; ++i) {
-      if (buffer[i] !== 0) return false;
-    }
-    return true;
-  }
-  isCoinbase() {
-    return (
-      this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash)
-    );
-  }
-  addInput(hash, index, sequence, scriptSig) {
-    typeforce(
-      types.tuple(
-        types.Hash256bit,
-        types.UInt32,
-        types.maybe(types.UInt32),
-        types.maybe(types.Buffer),
-      ),
-      arguments,
-    );
-    if (types.Null(sequence)) {
-      sequence = Transaction.DEFAULT_SEQUENCE;
-    }
-    // Add the input and return the input's index
-    return (
-      this.ins.push({
-        hash,
-        index,
-        script: scriptSig || EMPTY_BUFFER,
-        sequence: sequence,
-        witness: EMPTY_WITNESS,
-      }) - 1
-    );
-  }
-  addOutput(scriptPubKey, value) {
-    typeforce(types.tuple(types.Buffer, types.Satoshi), arguments);
-    // Add the output and return the output's index
-    return (
-      this.outs.push({
-        script: scriptPubKey,
-        value,
-      }) - 1
-    );
-  }
-  hasWitnesses() {
-    return this.ins.some(x => {
-      return x.witness.length !== 0;
-    });
-  }
-  weight() {
-    const base = this.byteLength(false);
-    const total = this.byteLength(true);
-    return base * 3 + total;
-  }
-  virtualSize() {
-    return Math.ceil(this.weight() / 4);
-  }
-  byteLength(_ALLOW_WITNESS = true) {
-    const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses();
-    return (
-      (hasWitnesses ? 10 : 8) +
-      bufferutils_1.varuint.encodingLength(this.ins.length) +
-      bufferutils_1.varuint.encodingLength(this.outs.length) +
-      this.ins.reduce((sum, input) => {
-        return sum + 40 + varSliceSize(input.script);
-      }, 0) +
-      this.outs.reduce((sum, output) => {
-        return sum + 8 + varSliceSize(output.script);
-      }, 0) +
-      (hasWitnesses
-        ? this.ins.reduce((sum, input) => {
-            return sum + vectorSize(input.witness);
-          }, 0)
-        : 0)
-    );
-  }
-  clone() {
-    const newTx = new Transaction();
-    newTx.version = this.version;
-    newTx.locktime = this.locktime;
-    newTx.ins = this.ins.map(txIn => {
-      return {
-        hash: txIn.hash,
-        index: txIn.index,
-        script: txIn.script,
-        sequence: txIn.sequence,
-        witness: txIn.witness,
-      };
-    });
-    newTx.outs = this.outs.map(txOut => {
-      return {
-        script: txOut.script,
-        value: txOut.value,
-      };
-    });
-    return newTx;
-  }
-  /**
-   * Hash transaction for signing a specific input.
-   *
-   * Bitcoin uses a different hash for each signed transaction input.
-   * This method copies the transaction, makes the necessary changes based on the
-   * hashType, and then hashes the result.
-   * This hash can then be used to sign the provided transaction input.
-   */
-  hashForSignature(inIndex, prevOutScript, hashType) {
-    typeforce(
-      types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number),
-      arguments,
-    );
-    // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29
-    if (inIndex >= this.ins.length) return ONE;
-    // ignore OP_CODESEPARATOR
-    const ourScript = bscript.compile(
-      bscript.decompile(prevOutScript).filter(x => {
-        return x !== script_1.OPS.OP_CODESEPARATOR;
-      }),
-    );
-    const txTmp = this.clone();
-    // SIGHASH_NONE: ignore all outputs? (wildcard payee)
-    if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) {
-      txTmp.outs = [];
-      // ignore sequence numbers (except at inIndex)
-      txTmp.ins.forEach((input, i) => {
-        if (i === inIndex) return;
-        input.sequence = 0;
-      });
-      // SIGHASH_SINGLE: ignore all outputs, except at the same index?
-    } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) {
-      // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60
-      if (inIndex >= this.outs.length) return ONE;
-      // truncate outputs after
-      txTmp.outs.length = inIndex + 1;
-      // "blank" outputs before
-      for (let i = 0; i < inIndex; i++) {
-        txTmp.outs[i] = BLANK_OUTPUT;
-      }
-      // ignore sequence numbers (except at inIndex)
-      txTmp.ins.forEach((input, y) => {
-        if (y === inIndex) return;
-        input.sequence = 0;
-      });
-    }
-    // SIGHASH_ANYONECANPAY: ignore inputs entirely?
-    if (hashType & Transaction.SIGHASH_ANYONECANPAY) {
-      txTmp.ins = [txTmp.ins[inIndex]];
-      txTmp.ins[0].script = ourScript;
-      // SIGHASH_ALL: only ignore input scripts
-    } else {
-      // "blank" others input scripts
-      txTmp.ins.forEach(input => {
-        input.script = EMPTY_BUFFER;
-      });
-      txTmp.ins[inIndex].script = ourScript;
-    }
-    // serialize and hash
-    const buffer = Buffer.allocUnsafe(txTmp.byteLength(false) + 4);
-    buffer.writeInt32LE(hashType, buffer.length - 4);
-    txTmp.__toBuffer(buffer, 0, false);
-    return bcrypto.hash256(buffer);
-  }
-  hashForWitnessV1(inIndex, prevOutScripts, values, hashType, leafHash, annex) {
-    // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message
-    typeforce(
-      types.tuple(
-        types.UInt32,
-        typeforce.arrayOf(types.Buffer),
-        typeforce.arrayOf(types.Satoshi),
-        types.UInt32,
-      ),
-      arguments,
-    );
-    if (
-      values.length !== this.ins.length ||
-      prevOutScripts.length !== this.ins.length
-    ) {
-      throw new Error('Must supply prevout script and value for all inputs');
-    }
-    const outputType =
-      hashType === Transaction.SIGHASH_DEFAULT
-        ? Transaction.SIGHASH_ALL
-        : hashType & Transaction.SIGHASH_OUTPUT_MASK;
-    const inputType = hashType & Transaction.SIGHASH_INPUT_MASK;
-    const isAnyoneCanPay = inputType === Transaction.SIGHASH_ANYONECANPAY;
-    const isNone = outputType === Transaction.SIGHASH_NONE;
-    const isSingle = outputType === Transaction.SIGHASH_SINGLE;
-    let hashPrevouts = EMPTY_BUFFER;
-    let hashAmounts = EMPTY_BUFFER;
-    let hashScriptPubKeys = EMPTY_BUFFER;
-    let hashSequences = EMPTY_BUFFER;
-    let hashOutputs = EMPTY_BUFFER;
-    if (!isAnyoneCanPay) {
-      let bufferWriter = bufferutils_1.BufferWriter.withCapacity(
-        36 * this.ins.length,
-      );
-      this.ins.forEach(txIn => {
-        bufferWriter.writeSlice(txIn.hash);
-        bufferWriter.writeUInt32(txIn.index);
-      });
-      hashPrevouts = bcrypto.sha256(bufferWriter.end());
-      bufferWriter = bufferutils_1.BufferWriter.withCapacity(
-        8 * this.ins.length,
-      );
-      values.forEach(value => bufferWriter.writeUInt64(value));
-      hashAmounts = bcrypto.sha256(bufferWriter.end());
-      bufferWriter = bufferutils_1.BufferWriter.withCapacity(
-        prevOutScripts.map(varSliceSize).reduce((a, b) => a + b),
-      );
-      prevOutScripts.forEach(prevOutScript =>
-        bufferWriter.writeVarSlice(prevOutScript),
-      );
-      hashScriptPubKeys = bcrypto.sha256(bufferWriter.end());
-      bufferWriter = bufferutils_1.BufferWriter.withCapacity(
-        4 * this.ins.length,
-      );
-      this.ins.forEach(txIn => bufferWriter.writeUInt32(txIn.sequence));
-      hashSequences = bcrypto.sha256(bufferWriter.end());
-    }
-    if (!(isNone || isSingle)) {
-      const txOutsSize = this.outs
-        .map(output => 8 + varSliceSize(output.script))
-        .reduce((a, b) => a + b);
-      const bufferWriter = bufferutils_1.BufferWriter.withCapacity(txOutsSize);
-      this.outs.forEach(out => {
-        bufferWriter.writeUInt64(out.value);
-        bufferWriter.writeVarSlice(out.script);
-      });
-      hashOutputs = bcrypto.sha256(bufferWriter.end());
-    } else if (isSingle && inIndex < this.outs.length) {
-      const output = this.outs[inIndex];
-      const bufferWriter = bufferutils_1.BufferWriter.withCapacity(
-        8 + varSliceSize(output.script),
-      );
-      bufferWriter.writeUInt64(output.value);
-      bufferWriter.writeVarSlice(output.script);
-      hashOutputs = bcrypto.sha256(bufferWriter.end());
-    }
-    const spendType = (leafHash ? 2 : 0) + (annex ? 1 : 0);
-    // Length calculation from:
-    // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-14
-    // With extension from:
-    // https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#signature-validation
-    const sigMsgSize =
-      174 -
-      (isAnyoneCanPay ? 49 : 0) -
-      (isNone ? 32 : 0) +
-      (annex ? 32 : 0) +
-      (leafHash ? 37 : 0);
-    const sigMsgWriter = bufferutils_1.BufferWriter.withCapacity(sigMsgSize);
-    sigMsgWriter.writeUInt8(hashType);
-    // Transaction
-    sigMsgWriter.writeInt32(this.version);
-    sigMsgWriter.writeUInt32(this.locktime);
-    sigMsgWriter.writeSlice(hashPrevouts);
-    sigMsgWriter.writeSlice(hashAmounts);
-    sigMsgWriter.writeSlice(hashScriptPubKeys);
-    sigMsgWriter.writeSlice(hashSequences);
-    if (!(isNone || isSingle)) {
-      sigMsgWriter.writeSlice(hashOutputs);
-    }
-    // Input
-    sigMsgWriter.writeUInt8(spendType);
-    if (isAnyoneCanPay) {
-      const input = this.ins[inIndex];
-      sigMsgWriter.writeSlice(input.hash);
-      sigMsgWriter.writeUInt32(input.index);
-      sigMsgWriter.writeUInt64(values[inIndex]);
-      sigMsgWriter.writeVarSlice(prevOutScripts[inIndex]);
-      sigMsgWriter.writeUInt32(input.sequence);
-    } else {
-      sigMsgWriter.writeUInt32(inIndex);
-    }
-    if (annex) {
-      const bufferWriter = bufferutils_1.BufferWriter.withCapacity(
-        varSliceSize(annex),
-      );
-      bufferWriter.writeVarSlice(annex);
-      sigMsgWriter.writeSlice(bcrypto.sha256(bufferWriter.end()));
-    }
-    // Output
-    if (isSingle) {
-      sigMsgWriter.writeSlice(hashOutputs);
-    }
-    // BIP342 extension
-    if (leafHash) {
-      sigMsgWriter.writeSlice(leafHash);
-      sigMsgWriter.writeUInt8(0);
-      sigMsgWriter.writeUInt32(0xffffffff);
-    }
-    // Extra zero byte because:
-    // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19
-    return bcrypto.taggedHash(
-      'TapSighash',
-      Buffer.concat([Buffer.of(0x00), sigMsgWriter.end()]),
-    );
-  }
-  hashForWitnessV0(inIndex, prevOutScript, value, hashType) {
-    typeforce(
-      types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32),
-      arguments,
-    );
-    let tbuffer = Buffer.from([]);
-    let bufferWriter;
-    let hashOutputs = ZERO;
-    let hashPrevouts = ZERO;
-    let hashSequence = ZERO;
-    if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) {
-      tbuffer = Buffer.allocUnsafe(36 * this.ins.length);
-      bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0);
-      this.ins.forEach(txIn => {
-        bufferWriter.writeSlice(txIn.hash);
-        bufferWriter.writeUInt32(txIn.index);
-      });
-      hashPrevouts = bcrypto.hash256(tbuffer);
-    }
-    if (
-      !(hashType & Transaction.SIGHASH_ANYONECANPAY) &&
-      (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE &&
-      (hashType & 0x1f) !== Transaction.SIGHASH_NONE
-    ) {
-      tbuffer = Buffer.allocUnsafe(4 * this.ins.length);
-      bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0);
-      this.ins.forEach(txIn => {
-        bufferWriter.writeUInt32(txIn.sequence);
-      });
-      hashSequence = bcrypto.hash256(tbuffer);
-    }
-    if (
-      (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE &&
-      (hashType & 0x1f) !== Transaction.SIGHASH_NONE
-    ) {
-      const txOutsSize = this.outs.reduce((sum, output) => {
-        return sum + 8 + varSliceSize(output.script);
-      }, 0);
-      tbuffer = Buffer.allocUnsafe(txOutsSize);
-      bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0);
-      this.outs.forEach(out => {
-        bufferWriter.writeUInt64(out.value);
-        bufferWriter.writeVarSlice(out.script);
-      });
-      hashOutputs = bcrypto.hash256(tbuffer);
-    } else if (
-      (hashType & 0x1f) === Transaction.SIGHASH_SINGLE &&
-      inIndex < this.outs.length
-    ) {
-      const output = this.outs[inIndex];
-      tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script));
-      bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0);
-      bufferWriter.writeUInt64(output.value);
-      bufferWriter.writeVarSlice(output.script);
-      hashOutputs = bcrypto.hash256(tbuffer);
-    }
-    tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript));
-    bufferWriter = new bufferutils_1.BufferWriter(tbuffer, 0);
-    const input = this.ins[inIndex];
-    bufferWriter.writeInt32(this.version);
-    bufferWriter.writeSlice(hashPrevouts);
-    bufferWriter.writeSlice(hashSequence);
-    bufferWriter.writeSlice(input.hash);
-    bufferWriter.writeUInt32(input.index);
-    bufferWriter.writeVarSlice(prevOutScript);
-    bufferWriter.writeUInt64(value);
-    bufferWriter.writeUInt32(input.sequence);
-    bufferWriter.writeSlice(hashOutputs);
-    bufferWriter.writeUInt32(this.locktime);
-    bufferWriter.writeUInt32(hashType);
-    return bcrypto.hash256(tbuffer);
-  }
-  getHash(forWitness) {
-    // wtxid for coinbase is always 32 bytes of 0x00
-    if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0);
-    return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness));
-  }
-  getId() {
-    // transaction hash's are displayed in reverse order
-    return (0, bufferutils_1.reverseBuffer)(this.getHash(false)).toString(
-      'hex',
-    );
-  }
-  toBuffer(buffer, initialOffset) {
-    return this.__toBuffer(buffer, initialOffset, true);
-  }
-  toHex() {
-    return this.toBuffer(undefined, undefined).toString('hex');
-  }
-  setInputScript(index, scriptSig) {
-    typeforce(types.tuple(types.Number, types.Buffer), arguments);
-    this.ins[index].script = scriptSig;
-  }
-  setWitness(index, witness) {
-    typeforce(types.tuple(types.Number, [types.Buffer]), arguments);
-    this.ins[index].witness = witness;
-  }
-  __toBuffer(buffer, initialOffset, _ALLOW_WITNESS = false) {
-    if (!buffer) buffer = Buffer.allocUnsafe(this.byteLength(_ALLOW_WITNESS));
-    const bufferWriter = new bufferutils_1.BufferWriter(
-      buffer,
-      initialOffset || 0,
-    );
-    bufferWriter.writeInt32(this.version);
-    const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses();
-    if (hasWitnesses) {
-      bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER);
-      bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG);
-    }
-    bufferWriter.writeVarInt(this.ins.length);
-    this.ins.forEach(txIn => {
-      bufferWriter.writeSlice(txIn.hash);
-      bufferWriter.writeUInt32(txIn.index);
-      bufferWriter.writeVarSlice(txIn.script);
-      bufferWriter.writeUInt32(txIn.sequence);
-    });
-    bufferWriter.writeVarInt(this.outs.length);
-    this.outs.forEach(txOut => {
-      if (isOutput(txOut)) {
-        bufferWriter.writeUInt64(txOut.value);
-      } else {
-        bufferWriter.writeSlice(txOut.valueBuffer);
-      }
-      bufferWriter.writeVarSlice(txOut.script);
-    });
-    if (hasWitnesses) {
-      this.ins.forEach(input => {
-        bufferWriter.writeVector(input.witness);
-      });
-    }
-    bufferWriter.writeUInt32(this.locktime);
-    // avoid slicing unless necessary
-    if (initialOffset !== undefined)
-      return buffer.slice(initialOffset, bufferWriter.offset);
-    return buffer;
-  }
+
+Transaction.prototype.getId = function () {
+  // transaction hash's are displayed in reverse order
+  return this.getHash().reverse().toString('hex')
 }
-exports.Transaction = Transaction;
-Transaction.DEFAULT_SEQUENCE = 0xffffffff;
-Transaction.SIGHASH_DEFAULT = 0x00;
-Transaction.SIGHASH_ALL = 0x01;
-Transaction.SIGHASH_NONE = 0x02;
-Transaction.SIGHASH_SINGLE = 0x03;
-Transaction.SIGHASH_ANYONECANPAY = 0x80;
-Transaction.SIGHASH_OUTPUT_MASK = 0x03;
-Transaction.SIGHASH_INPUT_MASK = 0x80;
-Transaction.ADVANCED_TRANSACTION_MARKER = 0x00;
-Transaction.ADVANCED_TRANSACTION_FLAG = 0x01;
+
+Transaction.prototype.toBuffer = function (buffer, initialOffset) {
+  return this.__toBuffer(buffer, initialOffset, true)
+}
+
+Transaction.prototype.__toBuffer = function (buffer, initialOffset, __allowWitness) {
+  if (!buffer) buffer = Buffer.allocUnsafe(this.__byteLength(__allowWitness))
+
+  var offset = initialOffset || 0
+  function writeSlice (slice) { offset += slice.copy(buffer, offset) }
+  function writeUInt8 (i) { offset = buffer.writeUInt8(i, offset) }
+  function writeUInt32 (i) { offset = buffer.writeUInt32LE(i, offset) }
+  function writeInt32 (i) { offset = buffer.writeInt32LE(i, offset) }
+  function writeUInt64 (i) { offset = bufferutils.writeUInt64LE(buffer, i, offset) }
+  function writeVarInt (i) {
+    varuint.encode(i, buffer, offset)
+    offset += varuint.encode.bytes
+  }
+  function writeVarSlice (slice) { writeVarInt(slice.length); writeSlice(slice) }
+  function writeVector (vector) { writeVarInt(vector.length); vector.forEach(writeVarSlice) }
+
+  writeInt32(this.version)
+
+  var hasWitnesses = __allowWitness && this.hasWitnesses()
+
+  if (hasWitnesses) {
+    writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER)
+    writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG)
+  }
+
+  writeVarInt(this.ins.length)
+
+  this.ins.forEach(function (txIn) {
+    writeSlice(txIn.hash)
+    writeUInt32(txIn.index)
+    writeVarSlice(txIn.script)
+    writeUInt32(txIn.sequence)
+  })
+
+  writeVarInt(this.outs.length)
+  this.outs.forEach(function (txOut) {
+    if (!txOut.valueBuffer) {
+      writeUInt64(txOut.value)
+    } else {
+      writeSlice(txOut.valueBuffer)
+    }
+
+    writeVarSlice(txOut.script)
+  })
+
+  if (hasWitnesses) {
+    this.ins.forEach(function (input) {
+      writeVector(input.witness)
+    })
+  }
+
+  writeUInt32(this.locktime)
+
+  // avoid slicing unless necessary
+  if (initialOffset !== undefined) return buffer.slice(initialOffset, offset)
+  return buffer
+}
+
+Transaction.prototype.toHex = function () {
+  return this.toBuffer().toString('hex')
+}
+
+Transaction.prototype.setInputScript = function (index, scriptSig) {
+  typeforce(types.tuple(types.Number, types.Buffer), arguments)
+
+  this.ins[index].script = scriptSig
+}
+
+Transaction.prototype.setWitness = function (index, witness) {
+  typeforce(types.tuple(types.Number, [types.Buffer]), arguments)
+
+  this.ins[index].witness = witness
+}
+
+module.exports = Transaction
diff --git a/src/transaction_builder.js b/src/transaction_builder.js
new file mode 100644
index 0000000..d1e8587
--- /dev/null
+++ b/src/transaction_builder.js
@@ -0,0 +1,784 @@
+var Buffer = require('safe-buffer').Buffer
+var baddress = require('./address')
+var bcrypto = require('./crypto')
+var bscript = require('./script')
+var btemplates = require('./templates')
+var networks = require('./networks')
+var ops = require('bitcoin-ops')
+var typeforce = require('typeforce')
+var types = require('./types')
+var scriptTypes = btemplates.types
+var SIGNABLE = [btemplates.types.P2PKH, btemplates.types.P2PK, btemplates.types.MULTISIG]
+var P2SH = SIGNABLE.concat([btemplates.types.P2WPKH, btemplates.types.P2WSH])
+
+var ECPair = require('./ecpair')
+var ECSignature = require('./ecsignature')
+var Transaction = require('./transaction')
+
+function supportedType (type) {
+  return SIGNABLE.indexOf(type) !== -1
+}
+
+function supportedP2SHType (type) {
+  return P2SH.indexOf(type) !== -1
+}
+
+function extractChunks (type, chunks, script) {
+  var pubKeys = []
+  var signatures = []
+  switch (type) {
+    case scriptTypes.P2PKH:
+      // if (redeemScript) throw new Error('Nonstandard... P2SH(P2PKH)')
+      pubKeys = chunks.slice(1)
+      signatures = chunks.slice(0, 1)
+      break
+
+    case scriptTypes.P2PK:
+      pubKeys[0] = script ? btemplates.pubKey.output.decode(script) : undefined
+      signatures = chunks.slice(0, 1)
+      break
+
+    case scriptTypes.MULTISIG:
+      if (script) {
+        var multisig = btemplates.multisig.output.decode(script)
+        pubKeys = multisig.pubKeys
+      }
+
+      signatures = chunks.slice(1).map(function (chunk) {
+        return chunk.length === 0 ? undefined : chunk
+      })
+      break
+  }
+
+  return {
+    pubKeys: pubKeys,
+    signatures: signatures
+  }
+}
+function expandInput (scriptSig, witnessStack) {
+  if (scriptSig.length === 0 && witnessStack.length === 0) return {}
+
+  var prevOutScript
+  var prevOutType
+  var scriptType
+  var script
+  var redeemScript
+  var witnessScript
+  var witnessScriptType
+  var redeemScriptType
+  var witness = false
+  var p2wsh = false
+  var p2sh = false
+  var witnessProgram
+  var chunks
+
+  var scriptSigChunks = bscript.decompile(scriptSig)
+  var sigType = btemplates.classifyInput(scriptSigChunks, true)
+  if (sigType === scriptTypes.P2SH) {
+    p2sh = true
+    redeemScript = scriptSigChunks[scriptSigChunks.length - 1]
+    redeemScriptType = btemplates.classifyOutput(redeemScript)
+    prevOutScript = btemplates.scriptHash.output.encode(bcrypto.hash160(redeemScript))
+    prevOutType = scriptTypes.P2SH
+    script = redeemScript
+  }
+
+  var classifyWitness = btemplates.classifyWitness(witnessStack, true)
+  if (classifyWitness === scriptTypes.P2WSH) {
+    witnessScript = witnessStack[witnessStack.length - 1]
+    witnessScriptType = btemplates.classifyOutput(witnessScript)
+    p2wsh = true
+    witness = true
+    if (scriptSig.length === 0) {
+      prevOutScript = btemplates.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript))
+      prevOutType = scriptTypes.P2WSH
+      if (redeemScript !== undefined) {
+        throw new Error('Redeem script given when unnecessary')
+      }
+      // bare witness
+    } else {
+      if (!redeemScript) {
+        throw new Error('No redeemScript provided for P2WSH, but scriptSig non-empty')
+      }
+      witnessProgram = btemplates.witnessScriptHash.output.encode(bcrypto.sha256(witnessScript))
+      if (!redeemScript.equals(witnessProgram)) {
+        throw new Error('Redeem script didn\'t match witnessScript')
+      }
+    }
+
+    if (!supportedType(btemplates.classifyOutput(witnessScript))) {
+      throw new Error('unsupported witness script')
+    }
+
+    script = witnessScript
+    scriptType = witnessScriptType
+    chunks = witnessStack.slice(0, -1)
+  } else if (classifyWitness === scriptTypes.P2WPKH) {
+    witness = true
+    var key = witnessStack[witnessStack.length - 1]
+    var keyHash = bcrypto.hash160(key)
+    if (scriptSig.length === 0) {
+      prevOutScript = btemplates.witnessPubKeyHash.output.encode(keyHash)
+      prevOutType = scriptTypes.P2WPKH
+      if (typeof redeemScript !== 'undefined') {
+        throw new Error('Redeem script given when unnecessary')
+      }
+    } else {
+      if (!redeemScript) {
+        throw new Error('No redeemScript provided for P2WPKH, but scriptSig wasn\'t empty')
+      }
+      witnessProgram = btemplates.witnessPubKeyHash.output.encode(keyHash)
+      if (!redeemScript.equals(witnessProgram)) {
+        throw new Error('Redeem script did not have the right witness program')
+      }
+    }
+
+    scriptType = scriptTypes.P2PKH
+    chunks = witnessStack
+  } else if (redeemScript) {
+    if (!supportedP2SHType(redeemScriptType)) {
+      throw new Error('Bad redeemscript!')
+    }
+
+    script = redeemScript
+    scriptType = redeemScriptType
+    chunks = scriptSigChunks.slice(0, -1)
+  } else {
+    prevOutType = scriptType = btemplates.classifyInput(scriptSig)
+    chunks = scriptSigChunks
+  }
+
+  var expanded = extractChunks(scriptType, chunks, script)
+
+  var result = {
+    pubKeys: expanded.pubKeys,
+    signatures: expanded.signatures,
+    prevOutScript: prevOutScript,
+    prevOutType: prevOutType,
+    signType: scriptType,
+    signScript: script,
+    witness: Boolean(witness)
+  }
+
+  if (p2sh) {
+    result.redeemScript = redeemScript
+    result.redeemScriptType = redeemScriptType
+  }
+
+  if (p2wsh) {
+    result.witnessScript = witnessScript
+    result.witnessScriptType = witnessScriptType
+  }
+
+  return result
+}
+
+// could be done in expandInput, but requires the original Transaction for hashForSignature
+function fixMultisigOrder (input, transaction, vin) {
+  if (input.redeemScriptType !== scriptTypes.MULTISIG || !input.redeemScript) return
+  if (input.pubKeys.length === input.signatures.length) return
+
+  var unmatched = input.signatures.concat()
+
+  input.signatures = input.pubKeys.map(function (pubKey) {
+    var keyPair = ECPair.fromPublicKeyBuffer(pubKey)
+    var match
+
+    // check for a signature
+    unmatched.some(function (signature, i) {
+      // skip if undefined || OP_0
+      if (!signature) return false
+
+      // TODO: avoid O(n) hashForSignature
+      var parsed = ECSignature.parseScriptSignature(signature)
+      var hash = transaction.hashForSignature(vin, input.redeemScript, parsed.hashType)
+
+      // skip if signature does not match pubKey
+      if (!keyPair.verify(hash, parsed.signature)) return false
+
+      // remove matched signature from unmatched
+      unmatched[i] = undefined
+      match = signature
+
+      return true
+    })
+
+    return match
+  })
+}
+
+function expandOutput (script, scriptType, ourPubKey) {
+  typeforce(types.Buffer, script)
+
+  var scriptChunks = bscript.decompile(script)
+  if (!scriptType) {
+    scriptType = btemplates.classifyOutput(script)
+  }
+
+  var pubKeys = []
+
+  switch (scriptType) {
+    // does our hash160(pubKey) match the output scripts?
+    case scriptTypes.P2PKH:
+      if (!ourPubKey) break
+
+      var pkh1 = scriptChunks[2]
+      var pkh2 = bcrypto.hash160(ourPubKey)
+      if (pkh1.equals(pkh2)) pubKeys = [ourPubKey]
+      break
+
+    // does our hash160(pubKey) match the output scripts?
+    case scriptTypes.P2WPKH:
+      if (!ourPubKey) break
+
+      var wpkh1 = scriptChunks[1]
+      var wpkh2 = bcrypto.hash160(ourPubKey)
+      if (wpkh1.equals(wpkh2)) pubKeys = [ourPubKey]
+      break
+
+    case scriptTypes.P2PK:
+      pubKeys = scriptChunks.slice(0, 1)
+      break
+
+    case scriptTypes.MULTISIG:
+      pubKeys = scriptChunks.slice(1, -2)
+      break
+
+    default: return { scriptType: scriptType }
+  }
+
+  return {
+    pubKeys: pubKeys,
+    scriptType: scriptType,
+    signatures: pubKeys.map(function () { return undefined })
+  }
+}
+
+function checkP2SHInput (input, redeemScriptHash) {
+  if (input.prevOutType) {
+    if (input.prevOutType !== scriptTypes.P2SH) throw new Error('PrevOutScript must be P2SH')
+
+    var prevOutScriptScriptHash = bscript.decompile(input.prevOutScript)[1]
+    if (!prevOutScriptScriptHash.equals(redeemScriptHash)) throw new Error('Inconsistent hash160(redeemScript)')
+  }
+}
+
+function checkP2WSHInput (input, witnessScriptHash) {
+  if (input.prevOutType) {
+    if (input.prevOutType !== scriptTypes.P2WSH) throw new Error('PrevOutScript must be P2WSH')
+
+    var scriptHash = bscript.decompile(input.prevOutScript)[1]
+    if (!scriptHash.equals(witnessScriptHash)) throw new Error('Inconsistent sha256(witnessScript)')
+  }
+}
+
+function prepareInput (input, kpPubKey, redeemScript, witnessValue, witnessScript) {
+  var expanded
+  var prevOutType
+  var prevOutScript
+
+  var p2sh = false
+  var p2shType
+  var redeemScriptHash
+
+  var witness = false
+  var p2wsh = false
+  var witnessType
+  var witnessScriptHash
+
+  var signType
+  var signScript
+
+  if (redeemScript && witnessScript) {
+    redeemScriptHash = bcrypto.hash160(redeemScript)
+    witnessScriptHash = bcrypto.sha256(witnessScript)
+    checkP2SHInput(input, redeemScriptHash)
+
+    if (!redeemScript.equals(btemplates.witnessScriptHash.output.encode(witnessScriptHash))) throw new Error('Witness script inconsistent with redeem script')
+
+    expanded = expandOutput(witnessScript, undefined, kpPubKey)
+    if (!expanded.pubKeys) throw new Error(expanded.scriptType + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')')
+
+    prevOutType = btemplates.types.P2SH
+    prevOutScript = btemplates.scriptHash.output.encode(redeemScriptHash)
+    p2sh = witness = p2wsh = true
+    p2shType = btemplates.types.P2WSH
+    signType = witnessType = expanded.scriptType
+    signScript = witnessScript
+  } else if (redeemScript) {
+    redeemScriptHash = bcrypto.hash160(redeemScript)
+    checkP2SHInput(input, redeemScriptHash)
+
+    expanded = expandOutput(redeemScript, undefined, kpPubKey)
+    if (!expanded.pubKeys) throw new Error(expanded.scriptType + ' not supported as redeemScript (' + bscript.toASM(redeemScript) + ')')
+
+    prevOutType = btemplates.types.P2SH
+    prevOutScript = btemplates.scriptHash.output.encode(redeemScriptHash)
+    p2sh = true
+    signType = p2shType = expanded.scriptType
+    signScript = redeemScript
+    witness = signType === btemplates.types.P2WPKH
+  } else if (witnessScript) {
+    witnessScriptHash = bcrypto.sha256(witnessScript)
+    checkP2WSHInput(input, witnessScriptHash)
+
+    expanded = expandOutput(witnessScript, undefined, kpPubKey)
+    if (!expanded.pubKeys) throw new Error(expanded.scriptType + ' not supported as witnessScript (' + bscript.toASM(witnessScript) + ')')
+
+    prevOutType = btemplates.types.P2WSH
+    prevOutScript = btemplates.witnessScriptHash.output.encode(witnessScriptHash)
+    witness = p2wsh = true
+    signType = witnessType = expanded.scriptType
+    signScript = witnessScript
+  } else if (input.prevOutType) {
+    // embedded scripts are not possible without a redeemScript
+    if (input.prevOutType === scriptTypes.P2SH) {
+      throw new Error('PrevOutScript is ' + input.prevOutType + ', requires redeemScript')
+    }
+
+    if (input.prevOutType === scriptTypes.P2WSH) {
+      throw new Error('PrevOutScript is ' + input.prevOutType + ', requires witnessScript')
+    }
+
+    prevOutType = input.prevOutType
+    prevOutScript = input.prevOutScript
+    expanded = expandOutput(input.prevOutScript, input.prevOutType, kpPubKey)
+    if (!expanded.pubKeys) return
+
+    witness = (input.prevOutType === scriptTypes.P2WPKH)
+    signType = prevOutType
+    signScript = prevOutScript
+  } else {
+    prevOutScript = btemplates.pubKeyHash.output.encode(bcrypto.hash160(kpPubKey))
+    expanded = expandOutput(prevOutScript, scriptTypes.P2PKH, kpPubKey)
+
+    prevOutType = scriptTypes.P2PKH
+    witness = false
+    signType = prevOutType
+    signScript = prevOutScript
+  }
+
+  if (signType === scriptTypes.P2WPKH) {
+    signScript = btemplates.pubKeyHash.output.encode(btemplates.witnessPubKeyHash.output.decode(signScript))
+  }
+
+  if (p2sh) {
+    input.redeemScript = redeemScript
+    input.redeemScriptType = p2shType
+  }
+
+  if (p2wsh) {
+    input.witnessScript = witnessScript
+    input.witnessScriptType = witnessType
+  }
+
+  input.pubKeys = expanded.pubKeys
+  input.signatures = expanded.signatures
+  input.signScript = signScript
+  input.signType = signType
+  input.prevOutScript = prevOutScript
+  input.prevOutType = prevOutType
+  input.witness = witness
+}
+
+function buildStack (type, signatures, pubKeys, allowIncomplete) {
+  if (type === scriptTypes.P2PKH) {
+    if (signatures.length === 1 && Buffer.isBuffer(signatures[0]) && pubKeys.length === 1) return btemplates.pubKeyHash.input.encodeStack(signatures[0], pubKeys[0])
+  } else if (type === scriptTypes.P2PK) {
+    if (signatures.length === 1 && Buffer.isBuffer(signatures[0])) return btemplates.pubKey.input.encodeStack(signatures[0])
+  } else if (type === scriptTypes.MULTISIG) {
+    if (signatures.length > 0) {
+      signatures = signatures.map(function (signature) {
+        return signature || ops.OP_0
+      })
+      if (!allowIncomplete) {
+        // remove blank signatures
+        signatures = signatures.filter(function (x) { return x !== ops.OP_0 })
+      }
+
+      return btemplates.multisig.input.encodeStack(signatures)
+    }
+  } else {
+    throw new Error('Not yet supported')
+  }
+
+  if (!allowIncomplete) throw new Error('Not enough signatures provided')
+  return []
+}
+
+function buildInput (input, allowIncomplete) {
+  var scriptType = input.prevOutType
+  var sig = []
+  var witness = []
+
+  if (supportedType(scriptType)) {
+    sig = buildStack(scriptType, input.signatures, input.pubKeys, allowIncomplete)
+  }
+
+  var p2sh = false
+  if (scriptType === btemplates.types.P2SH) {
+    // We can remove this error later when we have a guarantee prepareInput
+    // rejects unsignable scripts - it MUST be signable at this point.
+    if (!allowIncomplete && !supportedP2SHType(input.redeemScriptType)) {
+      throw new Error('Impossible to sign this type')
+    }
+
+    if (supportedType(input.redeemScriptType)) {
+      sig = buildStack(input.redeemScriptType, input.signatures, input.pubKeys, allowIncomplete)
+    }
+
+    // If it wasn't SIGNABLE, it's witness, defer to that
+    if (input.redeemScriptType) {
+      p2sh = true
+      scriptType = input.redeemScriptType
+    }
+  }
+
+  switch (scriptType) {
+    // P2WPKH is a special case of P2PKH
+    case btemplates.types.P2WPKH:
+      witness = buildStack(btemplates.types.P2PKH, input.signatures, input.pubKeys, allowIncomplete)
+      break
+
+    case btemplates.types.P2WSH:
+      // We can remove this check later
+      if (!allowIncomplete && !supportedType(input.witnessScriptType)) {
+        throw new Error('Impossible to sign this type')
+      }
+
+      if (supportedType(input.witnessScriptType)) {
+        witness = buildStack(input.witnessScriptType, input.signatures, input.pubKeys, allowIncomplete)
+        witness.push(input.witnessScript)
+        scriptType = input.witnessScriptType
+      }
+
+      break
+  }
+
+  // append redeemScript if necessary
+  if (p2sh) {
+    sig.push(input.redeemScript)
+  }
+
+  return {
+    type: scriptType,
+    script: bscript.compile(sig),
+    witness: witness
+  }
+}
+
+function TransactionBuilder (network, maximumFeeRate) {
+  this.prevTxMap = {}
+  this.network = network || networks.bitcoin
+
+  // WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth)
+  this.maximumFeeRate = maximumFeeRate || 2500
+
+  this.inputs = []
+  this.tx = new Transaction()
+}
+
+TransactionBuilder.prototype.setLockTime = function (locktime) {
+  typeforce(types.UInt32, locktime)
+
+  // if any signatures exist, throw
+  if (this.inputs.some(function (input) {
+    if (!input.signatures) return false
+
+    return input.signatures.some(function (s) { return s })
+  })) {
+    throw new Error('No, this would invalidate signatures')
+  }
+
+  this.tx.locktime = locktime
+}
+
+TransactionBuilder.prototype.setVersion = function (version) {
+  typeforce(types.UInt32, version)
+
+  // XXX: this might eventually become more complex depending on what the versions represent
+  this.tx.version = version
+}
+
+TransactionBuilder.fromTransaction = function (transaction, network) {
+  var txb = new TransactionBuilder(network)
+
+  // Copy transaction fields
+  txb.setVersion(transaction.version)
+  txb.setLockTime(transaction.locktime)
+
+  // Copy outputs (done first to avoid signature invalidation)
+  transaction.outs.forEach(function (txOut) {
+    txb.addOutput(txOut.script, txOut.value)
+  })
+
+  // Copy inputs
+  transaction.ins.forEach(function (txIn) {
+    txb.__addInputUnsafe(txIn.hash, txIn.index, {
+      sequence: txIn.sequence,
+      script: txIn.script,
+      witness: txIn.witness
+    })
+  })
+
+  // fix some things not possible through the public API
+  txb.inputs.forEach(function (input, i) {
+    fixMultisigOrder(input, transaction, i)
+  })
+
+  return txb
+}
+
+TransactionBuilder.prototype.addInput = function (txHash, vout, sequence, prevOutScript) {
+  if (!this.__canModifyInputs()) {
+    throw new Error('No, this would invalidate signatures')
+  }
+
+  var value
+
+  // is it a hex string?
+  if (typeof txHash === 'string') {
+    // transaction hashs's are displayed in reverse order, un-reverse it
+    txHash = Buffer.from(txHash, 'hex').reverse()
+
+  // is it a Transaction object?
+  } else if (txHash instanceof Transaction) {
+    var txOut = txHash.outs[vout]
+    prevOutScript = txOut.script
+    value = txOut.value
+
+    txHash = txHash.getHash()
+  }
+
+  return this.__addInputUnsafe(txHash, vout, {
+    sequence: sequence,
+    prevOutScript: prevOutScript,
+    value: value
+  })
+}
+
+TransactionBuilder.prototype.__addInputUnsafe = function (txHash, vout, options) {
+  if (Transaction.isCoinbaseHash(txHash)) {
+    throw new Error('coinbase inputs not supported')
+  }
+
+  var prevTxOut = txHash.toString('hex') + ':' + vout
+  if (this.prevTxMap[prevTxOut] !== undefined) throw new Error('Duplicate TxOut: ' + prevTxOut)
+
+  var input = {}
+
+  // derive what we can from the scriptSig
+  if (options.script !== undefined) {
+    input = expandInput(options.script, options.witness || [])
+  }
+
+  // if an input value was given, retain it
+  if (options.value !== undefined) {
+    input.value = options.value
+  }
+
+  // derive what we can from the previous transactions output script
+  if (!input.prevOutScript && options.prevOutScript) {
+    var prevOutType
+
+    if (!input.pubKeys && !input.signatures) {
+      var expanded = expandOutput(options.prevOutScript)
+
+      if (expanded.pubKeys) {
+        input.pubKeys = expanded.pubKeys
+        input.signatures = expanded.signatures
+      }
+
+      prevOutType = expanded.scriptType
+    }
+
+    input.prevOutScript = options.prevOutScript
+    input.prevOutType = prevOutType || btemplates.classifyOutput(options.prevOutScript)
+  }
+
+  var vin = this.tx.addInput(txHash, vout, options.sequence, options.scriptSig)
+  this.inputs[vin] = input
+  this.prevTxMap[prevTxOut] = vin
+  return vin
+}
+
+TransactionBuilder.prototype.addOutput = function (scriptPubKey, value) {
+  if (!this.__canModifyOutputs()) {
+    throw new Error('No, this would invalidate signatures')
+  }
+
+  // Attempt to get a script if it's a base58 or bech32 address string
+  if (typeof scriptPubKey === 'string') {
+    scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network)
+  }
+
+  return this.tx.addOutput(scriptPubKey, value)
+}
+
+TransactionBuilder.prototype.build = function () {
+  return this.__build(false)
+}
+TransactionBuilder.prototype.buildIncomplete = function () {
+  return this.__build(true)
+}
+
+TransactionBuilder.prototype.__build = function (allowIncomplete) {
+  if (!allowIncomplete) {
+    if (!this.tx.ins.length) throw new Error('Transaction has no inputs')
+    if (!this.tx.outs.length) throw new Error('Transaction has no outputs')
+  }
+
+  var tx = this.tx.clone()
+  // Create script signatures from inputs
+  this.inputs.forEach(function (input, i) {
+    var scriptType = input.witnessScriptType || input.redeemScriptType || input.prevOutType
+    if (!scriptType && !allowIncomplete) throw new Error('Transaction is not complete')
+    var result = buildInput(input, allowIncomplete)
+
+    // skip if no result
+    if (!allowIncomplete) {
+      if (!supportedType(result.type) && result.type !== btemplates.types.P2WPKH) {
+        throw new Error(result.type + ' not supported')
+      }
+    }
+
+    tx.setInputScript(i, result.script)
+    tx.setWitness(i, result.witness)
+  })
+
+  if (!allowIncomplete) {
+    // do not rely on this, its merely a last resort
+    if (this.__overMaximumFees(tx.virtualSize())) {
+      throw new Error('Transaction has absurd fees')
+    }
+  }
+
+  return tx
+}
+
+function canSign (input) {
+  return input.prevOutScript !== undefined &&
+    input.signScript !== undefined &&
+    input.pubKeys !== undefined &&
+    input.signatures !== undefined &&
+    input.signatures.length === input.pubKeys.length &&
+    input.pubKeys.length > 0 &&
+    (
+      input.witness === false ||
+      (input.witness === true && input.value !== undefined)
+    )
+}
+
+TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashType, witnessValue, witnessScript) {
+  // TODO: remove keyPair.network matching in 4.0.0
+  if (keyPair.network && keyPair.network !== this.network) throw new TypeError('Inconsistent network')
+  if (!this.inputs[vin]) throw new Error('No input at index: ' + vin)
+  hashType = hashType || Transaction.SIGHASH_ALL
+
+  var input = this.inputs[vin]
+
+  // if redeemScript was previously provided, enforce consistency
+  if (input.redeemScript !== undefined &&
+      redeemScript &&
+      !input.redeemScript.equals(redeemScript)) {
+    throw new Error('Inconsistent redeemScript')
+  }
+
+  var kpPubKey = keyPair.publicKey || keyPair.getPublicKeyBuffer()
+  if (!canSign(input)) {
+    if (witnessValue !== undefined) {
+      if (input.value !== undefined && input.value !== witnessValue) throw new Error('Input didn\'t match witnessValue')
+      typeforce(types.Satoshi, witnessValue)
+      input.value = witnessValue
+    }
+
+    if (!canSign(input)) prepareInput(input, kpPubKey, redeemScript, witnessValue, witnessScript)
+    if (!canSign(input)) throw Error(input.prevOutType + ' not supported')
+  }
+
+  // ready to sign
+  var signatureHash
+  if (input.witness) {
+    signatureHash = this.tx.hashForWitnessV0(vin, input.signScript, input.value, hashType)
+  } else {
+    signatureHash = this.tx.hashForSignature(vin, input.signScript, hashType)
+  }
+
+  // enforce in order signing of public keys
+  var signed = input.pubKeys.some(function (pubKey, i) {
+    if (!kpPubKey.equals(pubKey)) return false
+    if (input.signatures[i]) throw new Error('Signature already exists')
+
+    if (kpPubKey.length !== 33 && (
+      input.signType === scriptTypes.P2WPKH ||
+      input.redeemScriptType === scriptTypes.P2WSH ||
+      input.prevOutType === scriptTypes.P2WSH
+    )) throw new Error('BIP143 rejects uncompressed public keys in P2WPKH or P2WSH')
+
+    var signature = keyPair.sign(signatureHash)
+    if (Buffer.isBuffer(signature)) signature = ECSignature.fromRSBuffer(signature)
+
+    input.signatures[i] = signature.toScriptSignature(hashType)
+    return true
+  })
+
+  if (!signed) throw new Error('Key pair cannot sign for this input')
+}
+
+function signatureHashType (buffer) {
+  return buffer.readUInt8(buffer.length - 1)
+}
+
+TransactionBuilder.prototype.__canModifyInputs = function () {
+  return this.inputs.every(function (input) {
+    // any signatures?
+    if (input.signatures === undefined) return true
+
+    return input.signatures.every(function (signature) {
+      if (!signature) return true
+      var hashType = signatureHashType(signature)
+
+      // if SIGHASH_ANYONECANPAY is set, signatures would not
+      // be invalidated by more inputs
+      return hashType & Transaction.SIGHASH_ANYONECANPAY
+    })
+  })
+}
+
+TransactionBuilder.prototype.__canModifyOutputs = function () {
+  var nInputs = this.tx.ins.length
+  var nOutputs = this.tx.outs.length
+
+  return this.inputs.every(function (input) {
+    if (input.signatures === undefined) return true
+
+    return input.signatures.every(function (signature) {
+      if (!signature) return true
+      var hashType = signatureHashType(signature)
+
+      var hashTypeMod = hashType & 0x1f
+      if (hashTypeMod === Transaction.SIGHASH_NONE) return true
+      if (hashTypeMod === Transaction.SIGHASH_SINGLE) {
+        // if SIGHASH_SINGLE is set, and nInputs > nOutputs
+        // some signatures would be invalidated by the addition
+        // of more outputs
+        return nInputs <= nOutputs
+      }
+    })
+  })
+}
+
+TransactionBuilder.prototype.__overMaximumFees = function (bytes) {
+  // not all inputs will have .value defined
+  var incoming = this.inputs.reduce(function (a, x) { return a + (x.value >>> 0) }, 0)
+
+  // but all outputs do, and if we have any input value
+  // we can immediately determine if the outputs are too small
+  var outgoing = this.tx.outs.reduce(function (a, x) { return a + x.value }, 0)
+  var fee = incoming - outgoing
+  var feeRate = fee / bytes
+
+  return feeRate > this.maximumFeeRate
+}
+
+module.exports = TransactionBuilder
diff --git a/src/types.d.ts b/src/types.d.ts
deleted file mode 100644
index 5a8505d..0000000
--- a/src/types.d.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/// <reference types="node" />
-export declare const typeforce: any;
-export declare function isPoint(p: Buffer | number | undefined | null): boolean;
-export declare function UInt31(value: number): boolean;
-export declare function BIP32Path(value: string): boolean;
-export declare namespace BIP32Path {
-    var toJSON: () => string;
-}
-export declare function Signer(obj: any): boolean;
-export declare function Satoshi(value: number): boolean;
-export declare const ECPoint: any;
-export declare const Network: any;
-export declare const Buffer256bit: any;
-export declare const Hash160bit: any;
-export declare const Hash256bit: any;
-export declare const Number: any;
-export declare const Array: any;
-export declare const Boolean: any;
-export declare const String: any;
-export declare const Buffer: any;
-export declare const Hex: any;
-export declare const maybe: any;
-export declare const tuple: any;
-export declare const UInt8: any;
-export declare const UInt32: any;
-export declare const Function: any;
-export declare const BufferN: any;
-export declare const Null: any;
-export declare const oneOf: any;
diff --git a/src/types.js b/src/types.js
index a6d1efa..c1e5fb1 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,87 +1,53 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.typeforce = void 0;
-const buffer_1 = require('buffer');
-exports.typeforce = require('typeforce');
-const ZERO32 = buffer_1.Buffer.alloc(32, 0);
-const EC_P = buffer_1.Buffer.from(
-  'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
-  'hex',
-);
-function isPoint(p) {
-  if (!buffer_1.Buffer.isBuffer(p)) return false;
-  if (p.length < 33) return false;
-  const t = p[0];
-  const x = p.slice(1, 33);
-  if (x.compare(ZERO32) === 0) return false;
-  if (x.compare(EC_P) >= 0) return false;
-  if ((t === 0x02 || t === 0x03) && p.length === 33) {
-    return true;
-  }
-  const y = p.slice(33);
-  if (y.compare(ZERO32) === 0) return false;
-  if (y.compare(EC_P) >= 0) return false;
-  if (t === 0x04 && p.length === 65) return true;
-  return false;
+var typeforce = require('typeforce')
+
+var UINT31_MAX = Math.pow(2, 31) - 1
+function UInt31 (value) {
+  return typeforce.UInt32(value) && value <= UINT31_MAX
 }
-exports.isPoint = isPoint;
-const UINT31_MAX = Math.pow(2, 31) - 1;
-function UInt31(value) {
-  return exports.typeforce.UInt32(value) && value <= UINT31_MAX;
+
+function BIP32Path (value) {
+  return typeforce.String(value) && value.match(/^(m\/)?(\d+'?\/)*\d+'?$/)
 }
-exports.UInt31 = UInt31;
-function BIP32Path(value) {
-  return (
-    exports.typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/)
-  );
+BIP32Path.toJSON = function () { return 'BIP32 derivation path' }
+
+var SATOSHI_MAX = 21 * 1e14
+function Satoshi (value) {
+  return typeforce.UInt53(value) && value <= SATOSHI_MAX
 }
-exports.BIP32Path = BIP32Path;
-BIP32Path.toJSON = () => {
-  return 'BIP32 derivation path';
-};
-function Signer(obj) {
-  return (
-    (exports.typeforce.Buffer(obj.publicKey) ||
-      typeof obj.getPublicKey === 'function') &&
-    typeof obj.sign === 'function'
-  );
-}
-exports.Signer = Signer;
-const SATOSHI_MAX = 21 * 1e14;
-function Satoshi(value) {
-  return exports.typeforce.UInt53(value) && value <= SATOSHI_MAX;
-}
-exports.Satoshi = Satoshi;
+
 // external dependent types
-exports.ECPoint = exports.typeforce.quacksLike('Point');
+var BigInt = typeforce.quacksLike('BigInteger')
+var ECPoint = typeforce.quacksLike('Point')
+
 // exposed, external API
-exports.Network = exports.typeforce.compile({
-  messagePrefix: exports.typeforce.oneOf(
-    exports.typeforce.Buffer,
-    exports.typeforce.String,
-  ),
+var ECSignature = typeforce.compile({ r: BigInt, s: BigInt })
+var Network = typeforce.compile({
+  messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String),
   bip32: {
-    public: exports.typeforce.UInt32,
-    private: exports.typeforce.UInt32,
+    public: typeforce.UInt32,
+    private: typeforce.UInt32
   },
-  pubKeyHash: exports.typeforce.UInt8,
-  scriptHash: exports.typeforce.UInt8,
-  wif: exports.typeforce.UInt8,
-});
-exports.Buffer256bit = exports.typeforce.BufferN(32);
-exports.Hash160bit = exports.typeforce.BufferN(20);
-exports.Hash256bit = exports.typeforce.BufferN(32);
-exports.Number = exports.typeforce.Number; // tslint:disable-line variable-name
-exports.Array = exports.typeforce.Array;
-exports.Boolean = exports.typeforce.Boolean; // tslint:disable-line variable-name
-exports.String = exports.typeforce.String; // tslint:disable-line variable-name
-exports.Buffer = exports.typeforce.Buffer;
-exports.Hex = exports.typeforce.Hex;
-exports.maybe = exports.typeforce.maybe;
-exports.tuple = exports.typeforce.tuple;
-exports.UInt8 = exports.typeforce.UInt8;
-exports.UInt32 = exports.typeforce.UInt32;
-exports.Function = exports.typeforce.Function;
-exports.BufferN = exports.typeforce.BufferN;
-exports.Null = exports.typeforce.Null;
-exports.oneOf = exports.typeforce.oneOf;
+  pubKeyHash: typeforce.UInt8,
+  scriptHash: typeforce.UInt8,
+  wif: typeforce.UInt8
+})
+
+// extend typeforce types with ours
+var types = {
+  BigInt: BigInt,
+  BIP32Path: BIP32Path,
+  Buffer256bit: typeforce.BufferN(32),
+  ECPoint: ECPoint,
+  ECSignature: ECSignature,
+  Hash160bit: typeforce.BufferN(20),
+  Hash256bit: typeforce.BufferN(32),
+  Network: Network,
+  Satoshi: Satoshi,
+  UInt31: UInt31
+}
+
+for (var typeName in typeforce) {
+  types[typeName] = typeforce[typeName]
+}
+
+module.exports = types
diff --git a/test/address.js b/test/address.js
new file mode 100644
index 0000000..e9c8a80
--- /dev/null
+++ b/test/address.js
@@ -0,0 +1,124 @@
+/* global describe, it */
+
+var assert = require('assert')
+var baddress = require('../src/address')
+var networks = require('../src/networks')
+var bscript = require('../src/script')
+var fixtures = require('./fixtures/address.json')
+
+describe('address', function () {
+  describe('fromBase58Check', function () {
+    fixtures.standard.forEach(function (f) {
+      if (!f.base58check) return
+
+      it('decodes ' + f.base58check, function () {
+        var decode = baddress.fromBase58Check(f.base58check)
+
+        assert.strictEqual(decode.version, f.version)
+        assert.strictEqual(decode.hash.toString('hex'), f.hash)
+      })
+    })
+
+    fixtures.invalid.fromBase58Check.forEach(function (f) {
+      it('throws on ' + f.exception, function () {
+        assert.throws(function () {
+          baddress.fromBase58Check(f.address)
+        }, new RegExp(f.address + ' ' + f.exception))
+      })
+    })
+  })
+
+  describe('fromBech32', function () {
+    fixtures.standard.forEach((f) => {
+      if (!f.bech32) return
+
+      it('decodes ' + f.bech32, function () {
+        var actual = baddress.fromBech32(f.bech32)
+
+        assert.strictEqual(actual.version, f.version)
+        assert.strictEqual(actual.prefix, networks[f.network].bech32)
+        assert.strictEqual(actual.data.toString('hex'), f.data)
+      })
+    })
+
+    fixtures.invalid.bech32.forEach((f, i) => {
+      it('decode fails for ' + f.bech32 + '(' + f.exception + ')', function () {
+        assert.throws(function () {
+          baddress.fromBech32(f.address)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('fromOutputScript', function () {
+    fixtures.standard.forEach(function (f) {
+      it('encodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', function () {
+        var script = bscript.fromASM(f.script)
+        var address = baddress.fromOutputScript(script, networks[f.network])
+
+        assert.strictEqual(address, f.base58check || f.bech32.toLowerCase())
+      })
+    })
+
+    fixtures.invalid.fromOutputScript.forEach(function (f) {
+      it('throws when ' + f.script.slice(0, 30) + '... ' + f.exception, function () {
+        var script = bscript.fromASM(f.script)
+
+        assert.throws(function () {
+          baddress.fromOutputScript(script)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('toBase58Check', function () {
+    fixtures.standard.forEach(function (f) {
+      if (!f.base58check) return
+
+      it('encodes ' + f.hash + ' (' + f.network + ')', function () {
+        var address = baddress.toBase58Check(Buffer.from(f.hash, 'hex'), f.version)
+
+        assert.strictEqual(address, f.base58check)
+      })
+    })
+  })
+
+  describe('toBech32', function () {
+    fixtures.bech32.forEach((f, i) => {
+      if (!f.bech32) return
+      var data = Buffer.from(f.data, 'hex')
+
+      it('encode ' + f.address, function () {
+        assert.deepEqual(baddress.toBech32(data, f.version, f.prefix), f.address)
+      })
+    })
+
+    fixtures.invalid.bech32.forEach((f, i) => {
+      if (!f.prefix || f.version === undefined || f.data === undefined) return
+
+      it('encode fails (' + f.exception, function () {
+        assert.throws(function () {
+          baddress.toBech32(Buffer.from(f.data, 'hex'), f.version, f.prefix)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('toOutputScript', function () {
+    fixtures.standard.forEach(function (f) {
+      it('decodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', function () {
+        var script = baddress.toOutputScript(f.base58check || f.bech32, networks[f.network])
+
+        assert.strictEqual(bscript.toASM(script), f.script)
+      })
+    })
+
+    fixtures.invalid.toOutputScript.forEach(function (f) {
+      it('throws when ' + f.exception, function () {
+        assert.throws(function () {
+          baddress.toOutputScript(f.address, f.network)
+        }, new RegExp(f.address + ' ' + f.exception))
+      })
+    })
+  })
+})
diff --git a/test/address.spec.ts b/test/address.spec.ts
deleted file mode 100644
index b1304c3..0000000
--- a/test/address.spec.ts
+++ /dev/null
@@ -1,148 +0,0 @@
-import * as assert from 'assert';
-import { describe, it } from 'mocha';
-import * as baddress from '../src/address';
-import * as bscript from '../src/script';
-import * as fixtures from './fixtures/address.json';
-
-const NETWORKS = Object.assign(
-  {
-    litecoin: {
-      messagePrefix: '\x19Litecoin Signed Message:\n',
-      bip32: {
-        public: 0x019da462,
-        private: 0x019d9cfe,
-      },
-      pubKeyHash: 0x30,
-      scriptHash: 0x32,
-      wif: 0xb0,
-    },
-  },
-  require('../src/networks'),
-);
-
-describe('address', () => {
-  describe('fromBase58Check', () => {
-    fixtures.standard.forEach(f => {
-      if (!f.base58check) return;
-
-      it('decodes ' + f.base58check, () => {
-        const decode = baddress.fromBase58Check(f.base58check);
-
-        assert.strictEqual(decode.version, f.version);
-        assert.strictEqual(decode.hash.toString('hex'), f.hash);
-      });
-    });
-
-    fixtures.invalid.fromBase58Check.forEach(f => {
-      it('throws on ' + f.exception, () => {
-        assert.throws(() => {
-          baddress.fromBase58Check(f.address);
-        }, new RegExp(f.address + ' ' + f.exception));
-      });
-    });
-  });
-
-  describe('fromBech32', () => {
-    fixtures.standard.forEach(f => {
-      if (!f.bech32) return;
-
-      it('decodes ' + f.bech32, () => {
-        const actual = baddress.fromBech32(f.bech32);
-
-        assert.strictEqual(actual.version, f.version);
-        assert.strictEqual(actual.prefix, NETWORKS[f.network].bech32);
-        assert.strictEqual(actual.data.toString('hex'), f.data);
-      });
-    });
-
-    fixtures.invalid.bech32.forEach(f => {
-      it('decode fails for ' + f.address + '(' + f.exception + ')', () => {
-        assert.throws(() => {
-          baddress.fromBech32(f.address);
-        }, new RegExp(f.exception));
-      });
-    });
-  });
-
-  describe('fromOutputScript', () => {
-    fixtures.standard.forEach(f => {
-      it('encodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', () => {
-        const script = bscript.fromASM(f.script);
-        const address = baddress.fromOutputScript(script, NETWORKS[f.network]);
-
-        assert.strictEqual(address, f.base58check || f.bech32!.toLowerCase());
-      });
-    });
-
-    fixtures.invalid.fromOutputScript.forEach(f => {
-      it('throws when ' + f.script.slice(0, 30) + '... ' + f.exception, () => {
-        const script = bscript.fromASM(f.script);
-
-        assert.throws(() => {
-          baddress.fromOutputScript(script);
-        }, new RegExp(f.exception));
-      });
-    });
-  });
-
-  describe('toBase58Check', () => {
-    fixtures.standard.forEach(f => {
-      if (!f.base58check) return;
-
-      it('encodes ' + f.hash + ' (' + f.network + ')', () => {
-        const address = baddress.toBase58Check(
-          Buffer.from(f.hash, 'hex'),
-          f.version,
-        );
-
-        assert.strictEqual(address, f.base58check);
-      });
-    });
-  });
-
-  describe('toBech32', () => {
-    fixtures.bech32.forEach(f => {
-      if (!f.address) return;
-      const data = Buffer.from(f.data, 'hex');
-
-      it('encode ' + f.address, () => {
-        assert.deepStrictEqual(
-          baddress.toBech32(data, f.version, f.prefix),
-          f.address.toLowerCase(),
-        );
-      });
-    });
-
-    // TODO: These fixtures (according to TypeScript) have none of the data used below
-    fixtures.invalid.bech32.forEach((f: any) => {
-      if (!f.prefix || f.version === undefined || f.data === undefined) return;
-
-      it('encode fails (' + f.exception, () => {
-        assert.throws(() => {
-          baddress.toBech32(Buffer.from(f.data, 'hex'), f.version, f.prefix);
-        }, new RegExp(f.exception));
-      });
-    });
-  });
-
-  describe('toOutputScript', () => {
-    fixtures.standard.forEach(f => {
-      it('decodes ' + f.script.slice(0, 30) + '... (' + f.network + ')', () => {
-        const script = baddress.toOutputScript(
-          (f.base58check || f.bech32)!,
-          NETWORKS[f.network],
-        );
-
-        assert.strictEqual(bscript.toASM(script), f.script);
-      });
-    });
-
-    fixtures.invalid.toOutputScript.forEach(f => {
-      it('throws when ' + f.exception, () => {
-        assert.throws(() => {
-          baddress.toOutputScript(f.address, f.network as any);
-        }, new RegExp(f.address + ' ' + f.exception));
-      });
-    });
-  });
-});
diff --git a/test/bitcoin.core.js b/test/bitcoin.core.js
new file mode 100644
index 0000000..2eab7de
--- /dev/null
+++ b/test/bitcoin.core.js
@@ -0,0 +1,226 @@
+/* global describe, it */
+
+var assert = require('assert')
+var base58 = require('bs58')
+var bitcoin = require('../')
+
+var base58EncodeDecode = require('./fixtures/core/base58_encode_decode.json')
+var base58KeysInvalid = require('./fixtures/core/base58_keys_invalid.json')
+var base58KeysValid = require('./fixtures/core/base58_keys_valid.json')
+var blocksValid = require('./fixtures/core/blocks.json')
+var sigCanonical = require('./fixtures/core/sig_canonical.json')
+var sigHash = require('./fixtures/core/sighash.json')
+var sigNoncanonical = require('./fixtures/core/sig_noncanonical.json')
+var txValid = require('./fixtures/core/tx_valid.json')
+
+describe('Bitcoin-core', function () {
+  // base58EncodeDecode
+  describe('base58', function () {
+    base58EncodeDecode.forEach(function (f) {
+      var fhex = f[0]
+      var fb58 = f[1]
+
+      it('can decode ' + fb58, function () {
+        var buffer = base58.decode(fb58)
+        var actual = buffer.toString('hex')
+
+        assert.strictEqual(actual, fhex)
+      })
+
+      it('can encode ' + fhex, function () {
+        var buffer = Buffer.from(fhex, 'hex')
+        var actual = base58.encode(buffer)
+
+        assert.strictEqual(actual, fb58)
+      })
+    })
+  })
+
+  // base58KeysValid
+  describe('address.toBase58Check', function () {
+    var typeMap = {
+      'pubkey': 'pubKeyHash',
+      'script': 'scriptHash'
+    }
+
+    base58KeysValid.forEach(function (f) {
+      var expected = f[0]
+      var hash = Buffer.from(f[1], 'hex')
+      var params = f[2]
+
+      if (params.isPrivkey) return
+
+      var network = params.isTestnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin
+      var version = network[typeMap[params.addrType]]
+
+      it('can export ' + expected, function () {
+        assert.strictEqual(bitcoin.address.toBase58Check(hash, version), expected)
+      })
+    })
+  })
+
+  // base58KeysInvalid
+  describe('address.fromBase58Check', function () {
+    var allowedNetworks = [
+      bitcoin.networks.bitcoin.pubkeyhash,
+      bitcoin.networks.bitcoin.scripthash,
+      bitcoin.networks.testnet.pubkeyhash,
+      bitcoin.networks.testnet.scripthash
+    ]
+
+    base58KeysInvalid.forEach(function (f) {
+      var string = f[0]
+
+      it('throws on ' + string, function () {
+        assert.throws(function () {
+          var address = bitcoin.address.fromBase58Check(string)
+
+          assert.notEqual(allowedNetworks.indexOf(address.version), -1, 'Invalid network')
+        }, /(Invalid (checksum|network))|(too (short|long))/)
+      })
+    })
+  })
+
+  // base58KeysValid
+  describe('ECPair', function () {
+    base58KeysValid.forEach(function (f) {
+      var string = f[0]
+      var hex = f[1]
+      var params = f[2]
+
+      if (!params.isPrivkey) return
+
+      var network = params.isTestnet ? bitcoin.networks.testnet : bitcoin.networks.bitcoin
+      var keyPair = bitcoin.ECPair.fromWIF(string, network)
+
+      it('fromWIF imports ' + string, function () {
+        assert.strictEqual(keyPair.d.toHex(), hex)
+        assert.strictEqual(keyPair.compressed, params.isCompressed)
+      })
+
+      it('toWIF exports ' + hex + ' to ' + string, function () {
+        assert.strictEqual(keyPair.toWIF(), string)
+      })
+    })
+  })
+
+  // base58KeysInvalid
+  describe('ECPair.fromWIF', function () {
+    var allowedNetworks = [
+      bitcoin.networks.bitcoin,
+      bitcoin.networks.testnet
+    ]
+
+    base58KeysInvalid.forEach(function (f) {
+      var string = f[0]
+
+      it('throws on ' + string, function () {
+        assert.throws(function () {
+          bitcoin.ECPair.fromWIF(string, allowedNetworks)
+        }, /(Invalid|Unknown) (checksum|compression flag|network version|WIF length)/)
+      })
+    })
+  })
+
+  describe('Block.fromHex', function () {
+    blocksValid.forEach(function (f) {
+      it('can parse ' + f.id, function () {
+        var block = bitcoin.Block.fromHex(f.hex)
+
+        assert.strictEqual(block.getId(), f.id)
+        assert.strictEqual(block.transactions.length, f.transactions)
+      })
+    })
+  })
+
+  // txValid
+  describe('Transaction.fromHex', function () {
+    txValid.forEach(function (f) {
+      // Objects that are only a single string are ignored
+      if (f.length === 1) return
+
+      var inputs = f[0]
+      var fhex = f[1]
+      //      var verifyFlags = f[2] // TODO: do we need to test this?
+
+      it('can decode ' + fhex, function () {
+        var transaction = bitcoin.Transaction.fromHex(fhex)
+
+        transaction.ins.forEach(function (txIn, i) {
+          var input = inputs[i]
+
+          // reverse because test data is reversed
+          var prevOutHash = Buffer.from(input[0], 'hex').reverse()
+          var prevOutIndex = input[1]
+
+          assert.deepEqual(txIn.hash, prevOutHash)
+
+          // we read UInt32, not Int32
+          assert.strictEqual(txIn.index & 0xffffffff, prevOutIndex)
+        })
+      })
+    })
+  })
+
+  // sighash
+  describe('Transaction', function () {
+    sigHash.forEach(function (f) {
+      // Objects that are only a single string are ignored
+      if (f.length === 1) return
+
+      var txHex = f[0]
+      var scriptHex = f[1]
+      var inIndex = f[2]
+      var hashType = f[3]
+      var expectedHash = f[4]
+
+      var hashTypes = []
+      if ((hashType & 0x1f) === bitcoin.Transaction.SIGHASH_NONE) hashTypes.push('SIGHASH_NONE')
+      else if ((hashType & 0x1f) === bitcoin.Transaction.SIGHASH_SINGLE) hashTypes.push('SIGHASH_SINGLE')
+      else hashTypes.push('SIGHASH_ALL')
+      if (hashType & bitcoin.Transaction.SIGHASH_ANYONECANPAY) hashTypes.push('SIGHASH_ANYONECANPAY')
+
+      var hashTypeName = hashTypes.join(' | ')
+
+      it('should hash ' + txHex.slice(0, 40) + '... (' + hashTypeName + ')', function () {
+        var transaction = bitcoin.Transaction.fromHex(txHex)
+        assert.strictEqual(transaction.toHex(), txHex)
+
+        var script = Buffer.from(scriptHex, 'hex')
+        var scriptChunks = bitcoin.script.decompile(script)
+        assert.strictEqual(bitcoin.script.compile(scriptChunks).toString('hex'), scriptHex)
+
+        var hash = transaction.hashForSignature(inIndex, script, hashType)
+
+        // reverse because test data is reversed
+        assert.equal(hash.reverse().toString('hex'), expectedHash)
+      })
+    })
+  })
+
+  describe('ECSignature.parseScriptSignature', function () {
+    sigCanonical.forEach(function (hex) {
+      var buffer = Buffer.from(hex, 'hex')
+
+      it('can parse ' + hex, function () {
+        var parsed = bitcoin.ECSignature.parseScriptSignature(buffer)
+        var actual = parsed.signature.toScriptSignature(parsed.hashType)
+        assert.strictEqual(actual.toString('hex'), hex)
+      })
+    })
+
+    sigNoncanonical.forEach(function (hex, i) {
+      if (i === 0) return
+      if (i % 2 !== 0) return
+
+      var description = sigNoncanonical[i - 1].slice(0, -1)
+      var buffer = Buffer.from(hex, 'hex')
+
+      it('throws on ' + description, function () {
+        assert.throws(function () {
+          bitcoin.ECSignature.parseScriptSignature(buffer)
+        }, /Expected DER (integer|sequence)|(R|S) value (excessively padded|is negative)|(R|S|DER sequence) length is (zero|too short|too long|invalid)|Invalid hashType/)
+      })
+    })
+  })
+})
diff --git a/test/bitcoin.core.spec.ts b/test/bitcoin.core.spec.ts
deleted file mode 100644
index 9040416..0000000
--- a/test/bitcoin.core.spec.ts
+++ /dev/null
@@ -1,223 +0,0 @@
-import * as assert from 'assert';
-import * as base58 from 'bs58';
-import { describe, it } from 'mocha';
-import * as bitcoin from '..';
-import * as base58EncodeDecode from './fixtures/core/base58_encode_decode.json';
-import * as base58KeysInvalid from './fixtures/core/base58_keys_invalid.json';
-import * as base58KeysValid from './fixtures/core/base58_keys_valid.json';
-import * as blocksValid from './fixtures/core/blocks.json';
-import * as sigCanonical from './fixtures/core/sig_canonical.json';
-import * as sigNoncanonical from './fixtures/core/sig_noncanonical.json';
-import * as sigHash from './fixtures/core/sighash.json';
-import * as txValid from './fixtures/core/tx_valid.json';
-
-describe('Bitcoin-core', () => {
-  // base58EncodeDecode
-  describe('base58', () => {
-    base58EncodeDecode.forEach(f => {
-      const fhex = f[0];
-      const fb58 = f[1];
-
-      it('can decode ' + fb58, () => {
-        const buffer = base58.decode(fb58);
-        const actual = buffer.toString('hex');
-
-        assert.strictEqual(actual, fhex);
-      });
-
-      it('can encode ' + fhex, () => {
-        const buffer = Buffer.from(fhex, 'hex');
-        const actual = base58.encode(buffer);
-
-        assert.strictEqual(actual, fb58);
-      });
-    });
-  });
-
-  // base58KeysValid
-  describe('address.toBase58Check', () => {
-    const typeMap: any = {
-      pubkey: 'pubKeyHash',
-      script: 'scriptHash',
-    };
-
-    base58KeysValid.forEach(f => {
-      const expected = f[0];
-      const hash = Buffer.from(f[1] as any, 'hex');
-      const params = f[2] as any;
-
-      if (params.isPrivkey) return;
-
-      const network: any = params.isTestnet
-        ? bitcoin.networks.testnet
-        : bitcoin.networks.bitcoin;
-      const version = network[typeMap[params.addrType]];
-
-      it('can export ' + expected, () => {
-        assert.strictEqual(
-          bitcoin.address.toBase58Check(hash, version),
-          expected,
-        );
-      });
-    });
-  });
-
-  // base58KeysInvalid
-  describe('address.fromBase58Check', () => {
-    const allowedNetworks = [
-      bitcoin.networks.bitcoin.pubKeyHash,
-      bitcoin.networks.bitcoin.scriptHash,
-      bitcoin.networks.testnet.pubKeyHash,
-      bitcoin.networks.testnet.scriptHash,
-    ];
-
-    base58KeysInvalid.forEach(f => {
-      const strng = f[0];
-
-      it('throws on ' + strng, () => {
-        assert.throws(() => {
-          const address = bitcoin.address.fromBase58Check(strng);
-
-          assert.notStrictEqual(
-            allowedNetworks.indexOf(address.version),
-            -1,
-            'Invalid network',
-          );
-        }, /(Invalid (checksum|network))|(too (short|long))/);
-      });
-    });
-  });
-
-  describe('Block.fromHex', () => {
-    blocksValid.forEach(f => {
-      it('can parse ' + f.id, () => {
-        const block = bitcoin.Block.fromHex(f.hex);
-
-        assert.strictEqual(block.getId(), f.id);
-        assert.strictEqual(block.transactions!.length, f.transactions);
-      });
-    });
-  });
-
-  // txValid
-  describe('Transaction.fromHex', () => {
-    txValid.forEach(f => {
-      // Objects that are only a single string are ignored
-      if (f.length === 1) return;
-
-      const inputs = f[0];
-      const fhex = f[1];
-      //      const verifyFlags = f[2] // TODO: do we need to test this?
-
-      it('can decode ' + fhex, () => {
-        const transaction = bitcoin.Transaction.fromHex(fhex as string);
-
-        transaction.ins.forEach((txIn, i) => {
-          const input = inputs[i];
-
-          // reverse because test data is reversed
-          const prevOutHash = Buffer.from(input[0] as string, 'hex').reverse();
-          const prevOutIndex = input[1];
-
-          assert.deepStrictEqual(txIn.hash, prevOutHash);
-
-          // we read UInt32, not Int32
-          assert.strictEqual(txIn.index & 0xffffffff, prevOutIndex);
-        });
-      });
-    });
-  });
-
-  // sighash
-  describe('Transaction', () => {
-    sigHash.forEach(f => {
-      // Objects that are only a single string are ignored
-      if (f.length === 1) return;
-
-      const txHex = f[0] as string;
-      const scriptHex = f[1] as string;
-      const inIndex = f[2] as number;
-      const hashType = f[3] as number;
-      const expectedHash = f[4];
-
-      const hashTypes = [];
-      if ((hashType & 0x1f) === bitcoin.Transaction.SIGHASH_NONE)
-        hashTypes.push('SIGHASH_NONE');
-      else if ((hashType & 0x1f) === bitcoin.Transaction.SIGHASH_SINGLE)
-        hashTypes.push('SIGHASH_SINGLE');
-      else hashTypes.push('SIGHASH_ALL');
-      if (hashType & bitcoin.Transaction.SIGHASH_ANYONECANPAY)
-        hashTypes.push('SIGHASH_ANYONECANPAY');
-
-      const hashTypeName = hashTypes.join(' | ');
-
-      it(
-        'should hash ' + txHex.slice(0, 40) + '... (' + hashTypeName + ')',
-        () => {
-          const transaction = bitcoin.Transaction.fromHex(txHex);
-          assert.strictEqual(transaction.toHex(), txHex);
-
-          const script = Buffer.from(scriptHex, 'hex');
-          const scriptChunks = bitcoin.script.decompile(script);
-          assert.strictEqual(
-            bitcoin.script.compile(scriptChunks!).toString('hex'),
-            scriptHex,
-          );
-
-          const hash = transaction.hashForSignature(inIndex, script, hashType);
-
-          // reverse because test data is reversed
-          assert.strictEqual(
-            (hash.reverse() as Buffer).toString('hex'),
-            expectedHash,
-          );
-
-          assert.doesNotThrow(() =>
-            transaction.hashForWitnessV0(
-              inIndex,
-              script,
-              0,
-              // convert to UInt32
-              hashType < 0 ? 0x100000000 + hashType : hashType,
-            ),
-          );
-        },
-      );
-    });
-  });
-
-  describe('script.signature.decode', () => {
-    sigCanonical.forEach(hex => {
-      const buffer = Buffer.from(hex, 'hex');
-
-      it('can parse ' + hex, () => {
-        const parsed = bitcoin.script.signature.decode(buffer);
-        const actual = bitcoin.script.signature.encode(
-          parsed.signature,
-          parsed.hashType,
-        );
-
-        assert.strictEqual(actual.toString('hex'), hex);
-      });
-    });
-
-    sigNoncanonical.forEach((hex, i) => {
-      if (i === 0) return;
-      if (i % 2 !== 0) return;
-
-      const description = sigNoncanonical[i - 1].slice(0, -1);
-      const buffer = Buffer.from(hex, 'hex');
-
-      it('throws on ' + description, () => {
-        const reg = new RegExp(
-          'Expected DER (integer|sequence)|(R|S) value (excessively ' +
-            'padded|is negative)|(R|S|DER sequence) length is (zero|too ' +
-            'short|too long|invalid)|Invalid hashType',
-        );
-        assert.throws(() => {
-          bitcoin.script.signature.decode(buffer);
-        }, reg);
-      });
-    });
-  });
-});
diff --git a/test/block.js b/test/block.js
new file mode 100644
index 0000000..19866e5
--- /dev/null
+++ b/test/block.js
@@ -0,0 +1,149 @@
+/* global describe, it, beforeEach */
+
+var assert = require('assert')
+var Block = require('../src/block')
+
+var fixtures = require('./fixtures/block')
+
+describe('Block', function () {
+  describe('version', function () {
+    it('should be interpreted as an int32le', function () {
+      var blockHex = 'ffffffff0000000000000000000000000000000000000000000000000000000000000000414141414141414141414141414141414141414141414141414141414141414101000000020000000300000000'
+      var block = Block.fromHex(blockHex)
+      assert.equal(-1, block.version)
+      assert.equal(1, block.timestamp)
+    })
+  })
+
+  describe('calculateTarget', function () {
+    fixtures.targets.forEach(function (f) {
+      it('returns ' + f.expected + ' for 0x' + f.bits, function () {
+        var bits = parseInt(f.bits, 16)
+
+        assert.equal(Block.calculateTarget(bits).toString('hex'), f.expected)
+      })
+    })
+  })
+
+  describe('fromBuffer/fromHex', function () {
+    fixtures.valid.forEach(function (f) {
+      it('imports ' + f.description, function () {
+        var block = Block.fromHex(f.hex)
+
+        assert.strictEqual(block.version, f.version)
+        assert.strictEqual(block.prevHash.toString('hex'), f.prevHash)
+        assert.strictEqual(block.merkleRoot.toString('hex'), f.merkleRoot)
+        assert.strictEqual(block.timestamp, f.timestamp)
+        assert.strictEqual(block.bits, f.bits)
+        assert.strictEqual(block.nonce, f.nonce)
+        assert.strictEqual(!block.transactions, f.hex.length === 160)
+      })
+    })
+
+    fixtures.invalid.forEach(function (f) {
+      it('throws on ' + f.exception, function () {
+        assert.throws(function () {
+          Block.fromHex(f.hex)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('toBuffer/toHex', function () {
+    fixtures.valid.forEach(function (f) {
+      var block
+
+      beforeEach(function () {
+        block = Block.fromHex(f.hex)
+      })
+
+      it('exports ' + f.description, function () {
+        assert.strictEqual(block.toHex(true), f.hex.slice(0, 160))
+        assert.strictEqual(block.toHex(), f.hex)
+      })
+    })
+  })
+
+  describe('getHash/getId', function () {
+    fixtures.valid.forEach(function (f) {
+      var block
+
+      beforeEach(function () {
+        block = Block.fromHex(f.hex)
+      })
+
+      it('returns ' + f.id + ' for ' + f.description, function () {
+        assert.strictEqual(block.getHash().toString('hex'), f.hash)
+        assert.strictEqual(block.getId(), f.id)
+      })
+    })
+  })
+
+  describe('getUTCDate', function () {
+    fixtures.valid.forEach(function (f) {
+      var block
+
+      beforeEach(function () {
+        block = Block.fromHex(f.hex)
+      })
+
+      it('returns UTC date of ' + f.id, function () {
+        var utcDate = block.getUTCDate().getTime()
+
+        assert.strictEqual(utcDate, f.timestamp * 1e3)
+      })
+    })
+  })
+
+  describe('calculateMerkleRoot', function () {
+    it('should throw on zero-length transaction array', function () {
+      assert.throws(function () {
+        Block.calculateMerkleRoot([])
+      }, /Cannot compute merkle root for zero transactions/)
+    })
+
+    fixtures.valid.forEach(function (f) {
+      if (f.hex.length === 160) return
+
+      var block
+
+      beforeEach(function () {
+        block = Block.fromHex(f.hex)
+      })
+
+      it('returns ' + f.merkleRoot + ' for ' + f.id, function () {
+        assert.strictEqual(Block.calculateMerkleRoot(block.transactions).toString('hex'), f.merkleRoot)
+      })
+    })
+  })
+
+  describe('checkMerkleRoot', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.hex.length === 160) return
+
+      var block
+
+      beforeEach(function () {
+        block = Block.fromHex(f.hex)
+      })
+
+      it('returns ' + f.valid + ' for ' + f.id, function () {
+        assert.strictEqual(block.checkMerkleRoot(), true)
+      })
+    })
+  })
+
+  describe('checkProofOfWork', function () {
+    fixtures.valid.forEach(function (f) {
+      var block
+
+      beforeEach(function () {
+        block = Block.fromHex(f.hex)
+      })
+
+      it('returns ' + f.valid + ' for ' + f.id, function () {
+        assert.strictEqual(block.checkProofOfWork(), f.valid)
+      })
+    })
+  })
+})
diff --git a/test/block.spec.ts b/test/block.spec.ts
deleted file mode 100644
index e93420c..0000000
--- a/test/block.spec.ts
+++ /dev/null
@@ -1,179 +0,0 @@
-import * as assert from 'assert';
-import { beforeEach, describe, it } from 'mocha';
-import { Block } from '..';
-
-import * as fixtures from './fixtures/block.json';
-
-describe('Block', () => {
-  describe('version', () => {
-    it('should be interpreted as an int32le', () => {
-      const blockHex =
-        'ffffffff000000000000000000000000000000000000000000000000000000000000' +
-        '00004141414141414141414141414141414141414141414141414141414141414141' +
-        '01000000020000000300000000';
-      const block = Block.fromHex(blockHex);
-      assert.strictEqual(-1, block.version);
-      assert.strictEqual(1, block.timestamp);
-    });
-  });
-
-  describe('calculateTarget', () => {
-    fixtures.targets.forEach(f => {
-      it('returns ' + f.expected + ' for 0x' + f.bits, () => {
-        const bits = parseInt(f.bits, 16);
-
-        assert.strictEqual(
-          Block.calculateTarget(bits).toString('hex'),
-          f.expected,
-        );
-      });
-    });
-  });
-
-  describe('fromBuffer/fromHex', () => {
-    fixtures.valid.forEach(f => {
-      it('imports ' + f.description, () => {
-        const block = Block.fromHex(f.hex);
-
-        assert.strictEqual(block.version, f.version);
-        assert.strictEqual(block.prevHash!.toString('hex'), f.prevHash);
-        assert.strictEqual(block.merkleRoot!.toString('hex'), f.merkleRoot);
-        if (block.witnessCommit) {
-          assert.strictEqual(
-            block.witnessCommit.toString('hex'),
-            f.witnessCommit,
-          );
-        }
-        assert.strictEqual(block.timestamp, f.timestamp);
-        assert.strictEqual(block.bits, f.bits);
-        assert.strictEqual(block.nonce, f.nonce);
-        assert.strictEqual(!block.transactions, f.hex.length === 160);
-        if (f.size && f.strippedSize && f.weight) {
-          assert.strictEqual(block.byteLength(false, true), f.size);
-          assert.strictEqual(block.byteLength(false, false), f.strippedSize);
-          assert.strictEqual(block.weight(), f.weight);
-        }
-      });
-    });
-
-    fixtures.invalid.forEach(f => {
-      it('throws on ' + f.exception, () => {
-        assert.throws(() => {
-          Block.fromHex(f.hex);
-        }, new RegExp(f.exception));
-      });
-    });
-  });
-
-  describe('toBuffer/toHex', () => {
-    fixtures.valid.forEach(f => {
-      let block: Block;
-
-      beforeEach(() => {
-        block = Block.fromHex(f.hex);
-      });
-
-      it('exports ' + f.description, () => {
-        assert.strictEqual(block.toHex(true), f.hex.slice(0, 160));
-        assert.strictEqual(block.toHex(), f.hex);
-      });
-    });
-  });
-
-  describe('getHash/getId', () => {
-    fixtures.valid.forEach(f => {
-      let block: Block;
-
-      beforeEach(() => {
-        block = Block.fromHex(f.hex);
-      });
-
-      it('returns ' + f.id + ' for ' + f.description, () => {
-        assert.strictEqual(block.getHash().toString('hex'), f.hash);
-        assert.strictEqual(block.getId(), f.id);
-      });
-    });
-  });
-
-  describe('getUTCDate', () => {
-    fixtures.valid.forEach(f => {
-      let block: Block;
-
-      beforeEach(() => {
-        block = Block.fromHex(f.hex);
-      });
-
-      it('returns UTC date of ' + f.id, () => {
-        const utcDate = block.getUTCDate().getTime();
-
-        assert.strictEqual(utcDate, f.timestamp * 1e3);
-      });
-    });
-  });
-
-  describe('calculateMerkleRoot', () => {
-    it('should throw on zero-length transaction array', () => {
-      assert.throws(() => {
-        Block.calculateMerkleRoot([]);
-      }, /Cannot compute merkle root for zero transactions/);
-    });
-
-    fixtures.valid.forEach(f => {
-      if (f.hex.length === 160) return;
-
-      let block: Block;
-
-      beforeEach(() => {
-        block = Block.fromHex(f.hex);
-      });
-
-      it('returns ' + f.merkleRoot + ' for ' + f.id, () => {
-        assert.strictEqual(
-          Block.calculateMerkleRoot(block.transactions!).toString('hex'),
-          f.merkleRoot,
-        );
-      });
-
-      if (f.witnessCommit) {
-        it('returns witness commit ' + f.witnessCommit + ' for ' + f.id, () => {
-          assert.strictEqual(
-            Block.calculateMerkleRoot(block.transactions!, true).toString(
-              'hex',
-            ),
-            f.witnessCommit,
-          );
-        });
-      }
-    });
-  });
-
-  describe('checkTxRoots', () => {
-    fixtures.valid.forEach(f => {
-      if (f.hex.length === 160) return;
-
-      let block: Block;
-
-      beforeEach(() => {
-        block = Block.fromHex(f.hex);
-      });
-
-      it('returns ' + f.valid + ' for ' + f.id, () => {
-        assert.strictEqual(block.checkTxRoots(), true);
-      });
-    });
-  });
-
-  describe('checkProofOfWork', () => {
-    fixtures.valid.forEach(f => {
-      let block: Block;
-
-      beforeEach(() => {
-        block = Block.fromHex(f.hex);
-      });
-
-      it('returns ' + f.valid + ' for ' + f.id, () => {
-        assert.strictEqual(block.checkProofOfWork(), f.valid);
-      });
-    });
-  });
-});
diff --git a/test/bufferutils.js b/test/bufferutils.js
new file mode 100644
index 0000000..6efbb9f
--- /dev/null
+++ b/test/bufferutils.js
@@ -0,0 +1,165 @@
+/* global describe, it */
+
+var assert = require('assert')
+var bufferutils = require('../src/bufferutils')
+
+var fixtures = require('./fixtures/bufferutils.json')
+
+describe('bufferutils', function () {
+  describe('pushDataSize', function () {
+    fixtures.valid.forEach(function (f) {
+      it('determines the pushDataSize of ' + f.dec + ' correctly', function () {
+        if (!f.hexPD) return
+
+        var size = bufferutils.pushDataSize(f.dec)
+
+        assert.strictEqual(size, f.hexPD.length / 2)
+      })
+    })
+  })
+
+  describe('readPushDataInt', function () {
+    fixtures.valid.forEach(function (f) {
+      if (!f.hexPD) return
+
+      it('decodes ' + f.hexPD + ' correctly', function () {
+        var buffer = Buffer.from(f.hexPD, 'hex')
+        var d = bufferutils.readPushDataInt(buffer, 0)
+        var fopcode = parseInt(f.hexPD.substr(0, 2), 16)
+
+        assert.strictEqual(d.opcode, fopcode)
+        assert.strictEqual(d.number, f.dec)
+        assert.strictEqual(d.size, buffer.length)
+      })
+    })
+
+    fixtures.invalid.readPushDataInt.forEach(function (f) {
+      if (!f.hexPD) return
+
+      it('decodes ' + f.hexPD + ' as null', function () {
+        var buffer = Buffer.from(f.hexPD, 'hex')
+
+        var n = bufferutils.readPushDataInt(buffer, 0)
+        assert.strictEqual(n, null)
+      })
+    })
+  })
+
+  describe('readUInt64LE', function () {
+    fixtures.valid.forEach(function (f) {
+      it('decodes ' + f.hex64 + ' correctly', function () {
+        var buffer = Buffer.from(f.hex64, 'hex')
+        var number = bufferutils.readUInt64LE(buffer, 0)
+
+        assert.strictEqual(number, f.dec)
+      })
+    })
+
+    fixtures.invalid.readUInt64LE.forEach(function (f) {
+      it('throws on ' + f.description, function () {
+        var buffer = Buffer.from(f.hex64, 'hex')
+
+        assert.throws(function () {
+          bufferutils.readUInt64LE(buffer, 0)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('readVarInt', function () {
+    fixtures.valid.forEach(function (f) {
+      it('decodes ' + f.hexVI + ' correctly', function () {
+        var buffer = Buffer.from(f.hexVI, 'hex')
+        var d = bufferutils.readVarInt(buffer, 0)
+
+        assert.strictEqual(d.number, f.dec)
+        assert.strictEqual(d.size, buffer.length)
+      })
+    })
+
+    fixtures.invalid.readUInt64LE.forEach(function (f) {
+      it('throws on ' + f.description, function () {
+        var buffer = Buffer.from(f.hexVI, 'hex')
+
+        assert.throws(function () {
+          bufferutils.readVarInt(buffer, 0)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('varIntBuffer', function () {
+    fixtures.valid.forEach(function (f) {
+      it('encodes ' + f.dec + ' correctly', function () {
+        var buffer = bufferutils.varIntBuffer(f.dec)
+
+        assert.strictEqual(buffer.toString('hex'), f.hexVI)
+      })
+    })
+  })
+
+  describe('varIntSize', function () {
+    fixtures.valid.forEach(function (f) {
+      it('determines the varIntSize of ' + f.dec + ' correctly', function () {
+        var size = bufferutils.varIntSize(f.dec)
+
+        assert.strictEqual(size, f.hexVI.length / 2)
+      })
+    })
+  })
+
+  describe('writePushDataInt', function () {
+    fixtures.valid.forEach(function (f) {
+      if (!f.hexPD) return
+
+      it('encodes ' + f.dec + ' correctly', function () {
+        var buffer = Buffer.alloc(5, 0)
+
+        var n = bufferutils.writePushDataInt(buffer, f.dec, 0)
+        assert.strictEqual(buffer.slice(0, n).toString('hex'), f.hexPD)
+      })
+    })
+  })
+
+  describe('writeUInt64LE', function () {
+    fixtures.valid.forEach(function (f) {
+      it('encodes ' + f.dec + ' correctly', function () {
+        var buffer = Buffer.alloc(8, 0)
+
+        bufferutils.writeUInt64LE(buffer, f.dec, 0)
+        assert.strictEqual(buffer.toString('hex'), f.hex64)
+      })
+    })
+
+    fixtures.invalid.readUInt64LE.forEach(function (f) {
+      it('throws on ' + f.description, function () {
+        var buffer = Buffer.alloc(8, 0)
+
+        assert.throws(function () {
+          bufferutils.writeUInt64LE(buffer, f.dec, 0)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('writeVarInt', function () {
+    fixtures.valid.forEach(function (f) {
+      it('encodes ' + f.dec + ' correctly', function () {
+        var buffer = Buffer.alloc(9, 0)
+
+        var n = bufferutils.writeVarInt(buffer, f.dec, 0)
+        assert.strictEqual(buffer.slice(0, n).toString('hex'), f.hexVI)
+      })
+    })
+
+    fixtures.invalid.readUInt64LE.forEach(function (f) {
+      it('throws on ' + f.description, function () {
+        var buffer = Buffer.alloc(9, 0)
+
+        assert.throws(function () {
+          bufferutils.writeVarInt(buffer, f.dec, 0)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+})
diff --git a/test/bufferutils.spec.ts b/test/bufferutils.spec.ts
deleted file mode 100644
index 0f1f1a9..0000000
--- a/test/bufferutils.spec.ts
+++ /dev/null
@@ -1,512 +0,0 @@
-import * as assert from 'assert';
-import { describe, it } from 'mocha';
-import * as bufferutils from '../src/bufferutils';
-import { BufferReader, BufferWriter } from '../src/bufferutils';
-
-import * as fixtures from './fixtures/bufferutils.json';
-const varuint = require('varuint-bitcoin');
-
-describe('bufferutils', () => {
-  function concatToBuffer(values: number[][]): Buffer {
-    return Buffer.concat(values.map(data => Buffer.from(data)));
-  }
-
-  describe('readUInt64LE', () => {
-    fixtures.valid.forEach(f => {
-      it('decodes ' + f.hex, () => {
-        const buffer = Buffer.from(f.hex, 'hex');
-        const num = bufferutils.readUInt64LE(buffer, 0);
-
-        assert.strictEqual(num, f.dec);
-      });
-    });
-
-    fixtures.invalid.readUInt64LE.forEach(f => {
-      it('throws on ' + f.description, () => {
-        const buffer = Buffer.from(f.hex, 'hex');
-
-        assert.throws(() => {
-          bufferutils.readUInt64LE(buffer, 0);
-        }, new RegExp(f.exception));
-      });
-    });
-  });
-
-  describe('writeUInt64LE', () => {
-    fixtures.valid.forEach(f => {
-      it('encodes ' + f.dec, () => {
-        const buffer = Buffer.alloc(8, 0);
-
-        bufferutils.writeUInt64LE(buffer, f.dec, 0);
-        assert.strictEqual(buffer.toString('hex'), f.hex);
-      });
-    });
-
-    fixtures.invalid.writeUInt64LE.forEach(f => {
-      it('throws on ' + f.description, () => {
-        const buffer = Buffer.alloc(8, 0);
-
-        assert.throws(() => {
-          bufferutils.writeUInt64LE(buffer, f.dec, 0);
-        }, new RegExp(f.exception));
-      });
-    });
-  });
-
-  describe('BufferWriter', () => {
-    function testBuffer(
-      bufferWriter: BufferWriter,
-      expectedBuffer: Buffer,
-      expectedOffset: number = expectedBuffer.length,
-    ): void {
-      assert.strictEqual(bufferWriter.offset, expectedOffset);
-      assert.deepStrictEqual(
-        bufferWriter.buffer.slice(0, expectedOffset),
-        expectedBuffer.slice(0, expectedOffset),
-      );
-    }
-
-    it('withCapacity', () => {
-      const expectedBuffer = Buffer.from('04030201', 'hex');
-      const withCapacity = BufferWriter.withCapacity(4);
-      withCapacity.writeInt32(0x01020304);
-      testBuffer(withCapacity, expectedBuffer);
-    });
-
-    it('writeUint8', () => {
-      const values = [0, 1, 254, 255];
-      const expectedBuffer = Buffer.from([0, 1, 0xfe, 0xff]);
-      const bufferWriter = new BufferWriter(
-        Buffer.allocUnsafe(expectedBuffer.length),
-      );
-      values.forEach((v: number) => {
-        const expectedOffset = bufferWriter.offset + 1;
-        bufferWriter.writeUInt8(v);
-        testBuffer(bufferWriter, expectedBuffer, expectedOffset);
-      });
-      testBuffer(bufferWriter, expectedBuffer);
-    });
-
-    it('writeInt32', () => {
-      const values = [
-        0,
-        1,
-        Math.pow(2, 31) - 2,
-        Math.pow(2, 31) - 1,
-        -1,
-        -Math.pow(2, 31),
-      ];
-      const expectedBuffer = concatToBuffer([
-        [0, 0, 0, 0],
-        [1, 0, 0, 0],
-        [0xfe, 0xff, 0xff, 0x7f],
-        [0xff, 0xff, 0xff, 0x7f],
-        [0xff, 0xff, 0xff, 0xff],
-        [0x00, 0x00, 0x00, 0x80],
-      ]);
-      const bufferWriter = new BufferWriter(
-        Buffer.allocUnsafe(expectedBuffer.length),
-      );
-      values.forEach((value: number) => {
-        const expectedOffset = bufferWriter.offset + 4;
-        bufferWriter.writeInt32(value);
-        testBuffer(bufferWriter, expectedBuffer, expectedOffset);
-      });
-      testBuffer(bufferWriter, expectedBuffer);
-    });
-
-    it('writeUInt32', () => {
-      const maxUInt32 = Math.pow(2, 32) - 1;
-      const values = [0, 1, Math.pow(2, 16), maxUInt32];
-      const expectedBuffer = concatToBuffer([
-        [0, 0, 0, 0],
-        [1, 0, 0, 0],
-        [0, 0, 1, 0],
-        [0xff, 0xff, 0xff, 0xff],
-      ]);
-      const bufferWriter = new BufferWriter(
-        Buffer.allocUnsafe(expectedBuffer.length),
-      );
-      values.forEach((value: number) => {
-        const expectedOffset = bufferWriter.offset + 4;
-        bufferWriter.writeUInt32(value);
-        testBuffer(bufferWriter, expectedBuffer, expectedOffset);
-      });
-      testBuffer(bufferWriter, expectedBuffer);
-    });
-
-    it('writeUInt64', () => {
-      const values = [
-        0,
-        1,
-        Math.pow(2, 32),
-        Number.MAX_SAFE_INTEGER /* 2^53 - 1 */,
-      ];
-      const expectedBuffer = concatToBuffer([
-        [0, 0, 0, 0, 0, 0, 0, 0],
-        [1, 0, 0, 0, 0, 0, 0, 0],
-        [0, 0, 0, 0, 1, 0, 0, 0],
-        [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00],
-      ]);
-      const bufferWriter = new BufferWriter(
-        Buffer.allocUnsafe(expectedBuffer.length),
-      );
-      values.forEach((value: number) => {
-        const expectedOffset = bufferWriter.offset + 8;
-        bufferWriter.writeUInt64(value);
-        testBuffer(bufferWriter, expectedBuffer, expectedOffset);
-      });
-      testBuffer(bufferWriter, expectedBuffer);
-    });
-
-    it('writeVarInt', () => {
-      const values = [
-        0,
-        1,
-        252,
-        253,
-        254,
-        255,
-        256,
-        Math.pow(2, 16) - 2,
-        Math.pow(2, 16) - 1,
-        Math.pow(2, 16),
-        Math.pow(2, 32) - 2,
-        Math.pow(2, 32) - 1,
-        Math.pow(2, 32),
-        Number.MAX_SAFE_INTEGER,
-      ];
-      const expectedBuffer = concatToBuffer([
-        [0x00],
-        [0x01],
-        [0xfc],
-        [0xfd, 0xfd, 0x00],
-        [0xfd, 0xfe, 0x00],
-        [0xfd, 0xff, 0x00],
-        [0xfd, 0x00, 0x01],
-        [0xfd, 0xfe, 0xff],
-        [0xfd, 0xff, 0xff],
-        [0xfe, 0x00, 0x00, 0x01, 0x00],
-        [0xfe, 0xfe, 0xff, 0xff, 0xff],
-        [0xfe, 0xff, 0xff, 0xff, 0xff],
-        [0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00],
-        [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00],
-      ]);
-      const bufferWriter = new BufferWriter(
-        Buffer.allocUnsafe(expectedBuffer.length),
-      );
-      values.forEach((value: number) => {
-        const expectedOffset =
-          bufferWriter.offset + varuint.encodingLength(value);
-        bufferWriter.writeVarInt(value);
-        testBuffer(bufferWriter, expectedBuffer, expectedOffset);
-      });
-      testBuffer(bufferWriter, expectedBuffer);
-    });
-
-    it('writeSlice', () => {
-      const values = [[], [1], [1, 2, 3, 4], [254, 255]];
-      const expectedBuffer = concatToBuffer(values);
-      const bufferWriter = new BufferWriter(
-        Buffer.allocUnsafe(expectedBuffer.length),
-      );
-      values.forEach((v: number[]) => {
-        const expectedOffset = bufferWriter.offset + v.length;
-        bufferWriter.writeSlice(Buffer.from(v));
-        testBuffer(bufferWriter, expectedBuffer, expectedOffset);
-      });
-      testBuffer(bufferWriter, expectedBuffer);
-      assert.throws(() => {
-        bufferWriter.writeSlice(Buffer.from([0, 0]));
-      }, /^Error: Cannot write slice out of bounds$/);
-    });
-
-    it('writeVarSlice', () => {
-      const values = [
-        Buffer.alloc(1, 1),
-        Buffer.alloc(252, 2),
-        Buffer.alloc(253, 3),
-      ];
-      const expectedBuffer = Buffer.concat([
-        Buffer.from([0x01, 0x01]),
-        Buffer.from([0xfc]),
-        Buffer.alloc(252, 0x02),
-        Buffer.from([0xfd, 0xfd, 0x00]),
-        Buffer.alloc(253, 0x03),
-      ]);
-      const bufferWriter = new BufferWriter(
-        Buffer.allocUnsafe(expectedBuffer.length),
-      );
-      values.forEach((value: Buffer) => {
-        const expectedOffset =
-          bufferWriter.offset +
-          varuint.encodingLength(value.length) +
-          value.length;
-        bufferWriter.writeVarSlice(value);
-        testBuffer(bufferWriter, expectedBuffer, expectedOffset);
-      });
-      testBuffer(bufferWriter, expectedBuffer);
-    });
-
-    it('writeVector', () => {
-      const values = [
-        [Buffer.alloc(1, 4), Buffer.alloc(253, 5)],
-        Array(253).fill(Buffer.alloc(1, 6)),
-      ];
-      const expectedBuffer = Buffer.concat([
-        Buffer.from([0x02]),
-        Buffer.from([0x01, 0x04]),
-        Buffer.from([0xfd, 0xfd, 0x00]),
-        Buffer.alloc(253, 5),
-
-        Buffer.from([0xfd, 0xfd, 0x00]),
-        Buffer.concat(
-          Array(253)
-            .fill(0)
-            .map(() => Buffer.from([0x01, 0x06])),
-        ),
-      ]);
-
-      const bufferWriter = new BufferWriter(
-        Buffer.allocUnsafe(expectedBuffer.length),
-      );
-      values.forEach((value: Buffer[]) => {
-        const expectedOffset =
-          bufferWriter.offset +
-          varuint.encodingLength(value.length) +
-          value.reduce(
-            (sum: number, v) =>
-              sum + varuint.encodingLength(v.length) + v.length,
-            0,
-          );
-        bufferWriter.writeVector(value);
-        testBuffer(bufferWriter, expectedBuffer, expectedOffset);
-      });
-      testBuffer(bufferWriter, expectedBuffer);
-    });
-
-    it('end', () => {
-      const expected = Buffer.from('0403020108070605', 'hex');
-      const bufferWriter = BufferWriter.withCapacity(8);
-      bufferWriter.writeUInt32(0x01020304);
-      bufferWriter.writeUInt32(0x05060708);
-      const result = bufferWriter.end();
-      testBuffer(bufferWriter, result);
-      testBuffer(bufferWriter, expected);
-    });
-  });
-
-  describe('BufferReader', () => {
-    function testValue(
-      bufferReader: BufferReader,
-      value: Buffer | number,
-      expectedValue: Buffer | number,
-      expectedOffset: number = Buffer.isBuffer(expectedValue)
-        ? expectedValue.length
-        : 0,
-    ): void {
-      assert.strictEqual(bufferReader.offset, expectedOffset);
-      if (Buffer.isBuffer(expectedValue)) {
-        assert.deepStrictEqual(
-          (value as Buffer).slice(0, expectedOffset),
-          expectedValue.slice(0, expectedOffset),
-        );
-      } else {
-        assert.strictEqual(value as number, expectedValue);
-      }
-    }
-
-    it('readUint8', () => {
-      const values = [0, 1, 0xfe, 0xff];
-      const buffer = Buffer.from([0, 1, 0xfe, 0xff]);
-      const bufferReader = new BufferReader(buffer);
-      values.forEach((v: number) => {
-        const expectedOffset = bufferReader.offset + 1;
-        const val = bufferReader.readUInt8();
-        testValue(bufferReader, val, v, expectedOffset);
-      });
-    });
-
-    it('readInt32', () => {
-      const values = [
-        0,
-        1,
-        Math.pow(2, 31) - 2,
-        Math.pow(2, 31) - 1,
-        -1,
-        -Math.pow(2, 31),
-      ];
-      const buffer = concatToBuffer([
-        [0, 0, 0, 0],
-        [1, 0, 0, 0],
-        [0xfe, 0xff, 0xff, 0x7f],
-        [0xff, 0xff, 0xff, 0x7f],
-        [0xff, 0xff, 0xff, 0xff],
-        [0x00, 0x00, 0x00, 0x80],
-      ]);
-      const bufferReader = new BufferReader(buffer);
-      values.forEach((value: number) => {
-        const expectedOffset = bufferReader.offset + 4;
-        const val = bufferReader.readInt32();
-        testValue(bufferReader, val, value, expectedOffset);
-      });
-    });
-
-    it('readUInt32', () => {
-      const maxUInt32 = Math.pow(2, 32) - 1;
-      const values = [0, 1, Math.pow(2, 16), maxUInt32];
-      const buffer = concatToBuffer([
-        [0, 0, 0, 0],
-        [1, 0, 0, 0],
-        [0, 0, 1, 0],
-        [0xff, 0xff, 0xff, 0xff],
-      ]);
-      const bufferReader = new BufferReader(buffer);
-      values.forEach((value: number) => {
-        const expectedOffset = bufferReader.offset + 4;
-        const val = bufferReader.readUInt32();
-        testValue(bufferReader, val, value, expectedOffset);
-      });
-    });
-
-    it('readUInt64', () => {
-      const values = [
-        0,
-        1,
-        Math.pow(2, 32),
-        Number.MAX_SAFE_INTEGER /* 2^53 - 1 */,
-      ];
-      const buffer = concatToBuffer([
-        [0, 0, 0, 0, 0, 0, 0, 0],
-        [1, 0, 0, 0, 0, 0, 0, 0],
-        [0, 0, 0, 0, 1, 0, 0, 0],
-        [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00],
-      ]);
-      const bufferReader = new BufferReader(buffer);
-      values.forEach((value: number) => {
-        const expectedOffset = bufferReader.offset + 8;
-        const val = bufferReader.readUInt64();
-        testValue(bufferReader, val, value, expectedOffset);
-      });
-    });
-
-    it('readVarInt', () => {
-      const values = [
-        0,
-        1,
-        252,
-        253,
-        254,
-        255,
-        256,
-        Math.pow(2, 16) - 2,
-        Math.pow(2, 16) - 1,
-        Math.pow(2, 16),
-        Math.pow(2, 32) - 2,
-        Math.pow(2, 32) - 1,
-        Math.pow(2, 32),
-        Number.MAX_SAFE_INTEGER,
-      ];
-      const buffer = concatToBuffer([
-        [0x00],
-        [0x01],
-        [0xfc],
-        [0xfd, 0xfd, 0x00],
-        [0xfd, 0xfe, 0x00],
-        [0xfd, 0xff, 0x00],
-        [0xfd, 0x00, 0x01],
-        [0xfd, 0xfe, 0xff],
-        [0xfd, 0xff, 0xff],
-        [0xfe, 0x00, 0x00, 0x01, 0x00],
-        [0xfe, 0xfe, 0xff, 0xff, 0xff],
-        [0xfe, 0xff, 0xff, 0xff, 0xff],
-        [0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00],
-        [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00],
-      ]);
-      const bufferReader = new BufferReader(buffer);
-      values.forEach((value: number) => {
-        const expectedOffset =
-          bufferReader.offset + varuint.encodingLength(value);
-        const val = bufferReader.readVarInt();
-        testValue(bufferReader, val, value, expectedOffset);
-      });
-    });
-
-    it('readSlice', () => {
-      const values = [[1], [1, 2, 3, 4], [254, 255]];
-      const buffer = concatToBuffer(values);
-      const bufferReader = new BufferReader(buffer);
-      values.forEach((v: number[]) => {
-        const expectedOffset = bufferReader.offset + v.length;
-        const val = bufferReader.readSlice(v.length);
-        testValue(bufferReader, val, Buffer.from(v), expectedOffset);
-      });
-      assert.throws(() => {
-        bufferReader.readSlice(2);
-      }, /^Error: Cannot read slice out of bounds$/);
-    });
-
-    it('readVarSlice', () => {
-      const values = [
-        Buffer.alloc(1, 1),
-        Buffer.alloc(252, 2),
-        Buffer.alloc(253, 3),
-      ];
-      const buffer = Buffer.concat([
-        Buffer.from([0x01, 0x01]),
-        Buffer.from([0xfc]),
-        Buffer.alloc(252, 0x02),
-        Buffer.from([0xfd, 0xfd, 0x00]),
-        Buffer.alloc(253, 0x03),
-      ]);
-      const bufferReader = new BufferReader(buffer);
-      values.forEach((value: Buffer) => {
-        const expectedOffset =
-          bufferReader.offset +
-          varuint.encodingLength(value.length) +
-          value.length;
-        const val = bufferReader.readVarSlice();
-        testValue(bufferReader, val, value, expectedOffset);
-      });
-    });
-
-    it('readVector', () => {
-      const values = [
-        [Buffer.alloc(1, 4), Buffer.alloc(253, 5)],
-        Array(253).fill(Buffer.alloc(1, 6)),
-      ];
-      const buffer = Buffer.concat([
-        Buffer.from([0x02]),
-        Buffer.from([0x01, 0x04]),
-        Buffer.from([0xfd, 0xfd, 0x00]),
-        Buffer.alloc(253, 5),
-
-        Buffer.from([0xfd, 0xfd, 0x00]),
-        Buffer.concat(
-          Array(253)
-            .fill(0)
-            .map(() => Buffer.from([0x01, 0x06])),
-        ),
-      ]);
-
-      const bufferReader = new BufferReader(buffer);
-      values.forEach((value: Buffer[]) => {
-        const expectedOffset =
-          bufferReader.offset +
-          varuint.encodingLength(value.length) +
-          value.reduce(
-            (sum: number, v) =>
-              sum + varuint.encodingLength(v.length) + v.length,
-            0,
-          );
-        const val = bufferReader.readVector();
-        testValue(
-          bufferReader,
-          Buffer.concat(val),
-          Buffer.concat(value),
-          expectedOffset,
-        );
-      });
-    });
-  });
-});
diff --git a/test/crypto.js b/test/crypto.js
new file mode 100644
index 0000000..0fcc24b
--- /dev/null
+++ b/test/crypto.js
@@ -0,0 +1,24 @@
+/* global describe, it */
+
+var assert = require('assert')
+var bcrypto = require('../src/crypto')
+
+var fixtures = require('./fixtures/crypto')
+
+describe('crypto', function () {
+  ['hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(function (algorithm) {
+    describe(algorithm, function () {
+      fixtures.forEach(function (f) {
+        var fn = bcrypto[algorithm]
+        var expected = f[algorithm]
+
+        it('returns ' + expected + ' for ' + f.hex, function () {
+          var data = Buffer.from(f.hex, 'hex')
+          var actual = fn(data).toString('hex')
+
+          assert.strictEqual(actual, expected)
+        })
+      })
+    })
+  })
+})
diff --git a/test/crypto.spec.ts b/test/crypto.spec.ts
deleted file mode 100644
index 0482ec9..0000000
--- a/test/crypto.spec.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import * as assert from 'assert';
-import { describe, it } from 'mocha';
-import { crypto as bcrypto, TaggedHashPrefix } from '..';
-import * as fixtures from './fixtures/crypto.json';
-
-describe('crypto', () => {
-  ['hash160', 'hash256', 'ripemd160', 'sha1', 'sha256'].forEach(algorithm => {
-    describe(algorithm, () => {
-      fixtures.hashes.forEach(f => {
-        const fn = (bcrypto as any)[algorithm];
-        const expected = (f as any)[algorithm];
-
-        it('returns ' + expected + ' for ' + f.hex, () => {
-          const data = Buffer.from(f.hex, 'hex');
-          const actual = fn(data).toString('hex');
-
-          assert.strictEqual(actual, expected);
-        });
-      });
-    });
-  });
-
-  describe('taggedHash', () => {
-    fixtures.taggedHash.forEach(f => {
-      const bytes = Buffer.from(f.hex, 'hex');
-      const expected = Buffer.from(f.result, 'hex');
-      it(`returns ${f.result} for taggedHash "${f.tag}" of ${f.hex}`, () => {
-        const actual = bcrypto.taggedHash(f.tag as TaggedHashPrefix, bytes);
-        assert.strictEqual(actual.toString('hex'), expected.toString('hex'));
-      });
-    });
-  });
-});
diff --git a/test/ecdsa.js b/test/ecdsa.js
new file mode 100644
index 0000000..8d8b17c
--- /dev/null
+++ b/test/ecdsa.js
@@ -0,0 +1,137 @@
+/* global describe, it */
+
+var assert = require('assert')
+var bcrypto = require('../src/crypto')
+var ecdsa = require('../src/ecdsa')
+var sinon = require('sinon')
+var sinonTest = require('sinon-test')
+var setupTest = sinonTest(sinon)
+
+var BigInteger = require('bigi')
+var ECSignature = require('../src/ecsignature')
+
+var curve = ecdsa.__curve
+
+var fixtures = require('./fixtures/ecdsa.json')
+
+describe('ecdsa', function () {
+  describe('deterministicGenerateK', function () {
+    function checkSig () {
+      return true
+    }
+
+    fixtures.valid.ecdsa.forEach(function (f) {
+      it('for "' + f.message + '"', function () {
+        var x = BigInteger.fromHex(f.d).toBuffer(32)
+        var h1 = bcrypto.sha256(f.message)
+
+        var k = ecdsa.deterministicGenerateK(h1, x, checkSig)
+        assert.strictEqual(k.toHex(), f.k)
+      })
+    })
+
+    it('loops until an appropriate k value is found', setupTest(function () {
+      this.mock(BigInteger).expects('fromBuffer')
+        .exactly(3)
+        .onCall(0).returns(new BigInteger('0')) // < 1
+        .onCall(1).returns(curve.n) // > n-1
+        .onCall(2).returns(new BigInteger('42')) // valid
+
+      var x = new BigInteger('1').toBuffer(32)
+      var h1 = Buffer.alloc(32)
+      var k = ecdsa.deterministicGenerateK(h1, x, checkSig)
+
+      assert.strictEqual(k.toString(), '42')
+    }))
+
+    it('loops until a suitable signature is found', setupTest(function () {
+      this.mock(BigInteger).expects('fromBuffer')
+        .exactly(4)
+        .onCall(0).returns(new BigInteger('0')) // < 1
+        .onCall(1).returns(curve.n) // > n-1
+        .onCall(2).returns(new BigInteger('42')) // valid, but 'bad' signature
+        .onCall(3).returns(new BigInteger('53')) // valid, good signature
+
+      var mockCheckSig = this.mock()
+      mockCheckSig.exactly(2)
+      mockCheckSig.onCall(0).returns(false) // bad signature
+      mockCheckSig.onCall(1).returns(true) // good signature
+
+      var x = new BigInteger('1').toBuffer(32)
+      var h1 = Buffer.alloc(32)
+      var k = ecdsa.deterministicGenerateK(h1, x, mockCheckSig)
+
+      assert.strictEqual(k.toString(), '53')
+    }))
+
+    fixtures.valid.rfc6979.forEach(function (f) {
+      it('produces the expected k values for ' + f.message + " if k wasn't suitable", function () {
+        var x = BigInteger.fromHex(f.d).toBuffer(32)
+        var h1 = bcrypto.sha256(f.message)
+
+        var results = []
+        ecdsa.deterministicGenerateK(h1, x, function (k) {
+          results.push(k)
+
+          return results.length === 16
+        })
+
+        assert.strictEqual(results[0].toHex(), f.k0)
+        assert.strictEqual(results[1].toHex(), f.k1)
+        assert.strictEqual(results[15].toHex(), f.k15)
+      })
+    })
+  })
+
+  describe('sign', function () {
+    fixtures.valid.ecdsa.forEach(function (f) {
+      it('produces a deterministic signature for "' + f.message + '"', function () {
+        var d = BigInteger.fromHex(f.d)
+        var hash = bcrypto.sha256(f.message)
+        var signature = ecdsa.sign(hash, d).toDER()
+
+        assert.strictEqual(signature.toString('hex'), f.signature)
+      })
+    })
+
+    it('should sign with low S value', function () {
+      var hash = bcrypto.sha256('Vires in numeris')
+      var sig = ecdsa.sign(hash, BigInteger.ONE)
+
+      // See BIP62 for more information
+      var N_OVER_TWO = curve.n.shiftRight(1)
+      assert(sig.s.compareTo(N_OVER_TWO) <= 0)
+    })
+  })
+
+  describe('verify', function () {
+    fixtures.valid.ecdsa.forEach(function (f) {
+      it('verifies a valid signature for "' + f.message + '"', function () {
+        var d = BigInteger.fromHex(f.d)
+        var H = bcrypto.sha256(f.message)
+        var signature = ECSignature.fromDER(Buffer.from(f.signature, 'hex'))
+        var Q = curve.G.multiply(d)
+
+        assert(ecdsa.verify(H, signature, Q))
+      })
+    })
+
+    fixtures.invalid.verify.forEach(function (f) {
+      it('fails to verify with ' + f.description, function () {
+        var H = bcrypto.sha256(f.message)
+        var d = BigInteger.fromHex(f.d)
+
+        var signature
+        if (f.signature) {
+          signature = ECSignature.fromDER(Buffer.from(f.signature, 'hex'))
+        } else if (f.signatureRaw) {
+          signature = new ECSignature(new BigInteger(f.signatureRaw.r, 16), new BigInteger(f.signatureRaw.s, 16))
+        }
+
+        var Q = curve.G.multiply(d)
+
+        assert.strictEqual(ecdsa.verify(H, signature, Q), false)
+      })
+    })
+  })
+})
diff --git a/test/ecpair.js b/test/ecpair.js
new file mode 100644
index 0000000..7972585
--- /dev/null
+++ b/test/ecpair.js
@@ -0,0 +1,251 @@
+/* global describe, it, beforeEach */
+/* eslint-disable no-new */
+
+var assert = require('assert')
+var ecdsa = require('../src/ecdsa')
+var ecurve = require('ecurve')
+var proxyquire = require('proxyquire')
+var sinon = require('sinon')
+var sinonTest = require('sinon-test')
+var setupTest = sinonTest(sinon)
+
+var BigInteger = require('bigi')
+var ECPair = require('../src/ecpair')
+
+var fixtures = require('./fixtures/ecpair.json')
+var curve = ecdsa.__curve
+
+var NETWORKS = require('../src/networks')
+var NETWORKS_LIST = [] // Object.values(NETWORKS)
+for (var networkName in NETWORKS) {
+  NETWORKS_LIST.push(NETWORKS[networkName])
+}
+
+describe('ECPair', function () {
+  describe('constructor', function () {
+    it('defaults to compressed', function () {
+      var keyPair = new ECPair(BigInteger.ONE)
+
+      assert.strictEqual(keyPair.compressed, true)
+    })
+
+    it('supports the uncompressed option', function () {
+      var keyPair = new ECPair(BigInteger.ONE, null, {
+        compressed: false
+      })
+
+      assert.strictEqual(keyPair.compressed, false)
+    })
+
+    it('supports the network option', function () {
+      var keyPair = new ECPair(BigInteger.ONE, null, {
+        compressed: false,
+        network: NETWORKS.testnet
+      })
+
+      assert.strictEqual(keyPair.network, NETWORKS.testnet)
+    })
+
+    fixtures.valid.forEach(function (f) {
+      it('calculates the public point for ' + f.WIF, function () {
+        var d = new BigInteger(f.d)
+        var keyPair = new ECPair(d, null, {
+          compressed: f.compressed
+        })
+
+        assert.strictEqual(keyPair.getPublicKeyBuffer().toString('hex'), f.Q)
+      })
+    })
+
+    fixtures.invalid.constructor.forEach(function (f) {
+      it('throws ' + f.exception, function () {
+        var d = f.d && new BigInteger(f.d)
+        var Q = f.Q && ecurve.Point.decodeFrom(curve, Buffer.from(f.Q, 'hex'))
+
+        assert.throws(function () {
+          new ECPair(d, Q, f.options)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('getPublicKeyBuffer', function () {
+    var keyPair
+
+    beforeEach(function () {
+      keyPair = new ECPair(BigInteger.ONE)
+    })
+
+    it('wraps Q.getEncoded', setupTest(function () {
+      this.mock(keyPair.Q).expects('getEncoded')
+        .once().withArgs(keyPair.compressed)
+
+      keyPair.getPublicKeyBuffer()
+    }))
+  })
+
+  describe('fromWIF', function () {
+    fixtures.valid.forEach(function (f) {
+      it('imports ' + f.WIF + ' (' + f.network + ')', function () {
+        var network = NETWORKS[f.network]
+        var keyPair = ECPair.fromWIF(f.WIF, network)
+
+        assert.strictEqual(keyPair.d.toString(), f.d)
+        assert.strictEqual(keyPair.compressed, f.compressed)
+        assert.strictEqual(keyPair.network, network)
+      })
+    })
+
+    fixtures.valid.forEach(function (f) {
+      it('imports ' + f.WIF + ' (via list of networks)', function () {
+        var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
+
+        assert.strictEqual(keyPair.d.toString(), f.d)
+        assert.strictEqual(keyPair.compressed, f.compressed)
+        assert.strictEqual(keyPair.network, NETWORKS[f.network])
+      })
+    })
+
+    fixtures.invalid.fromWIF.forEach(function (f) {
+      it('throws on ' + f.WIF, function () {
+        assert.throws(function () {
+          var networks = f.network ? NETWORKS[f.network] : NETWORKS_LIST
+
+          ECPair.fromWIF(f.WIF, networks)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('toWIF', function () {
+    fixtures.valid.forEach(function (f) {
+      it('exports ' + f.WIF, function () {
+        var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
+        var result = keyPair.toWIF()
+
+        assert.strictEqual(result, f.WIF)
+      })
+    })
+  })
+
+  describe('makeRandom', function () {
+    var d = Buffer.from('0404040404040404040404040404040404040404040404040404040404040404', 'hex')
+    var exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv'
+
+    describe('uses randombytes RNG', function () {
+      it('generates a ECPair', function () {
+        var stub = { randombytes: function () { return d } }
+        var ProxiedECPair = proxyquire('../src/ecpair', stub)
+
+        var keyPair = ProxiedECPair.makeRandom()
+        assert.strictEqual(keyPair.toWIF(), exWIF)
+      })
+    })
+
+    it('allows a custom RNG to be used', function () {
+      var keyPair = ECPair.makeRandom({
+        rng: function (size) { return d.slice(0, size) }
+      })
+
+      assert.strictEqual(keyPair.toWIF(), exWIF)
+    })
+
+    it('retains the same defaults as ECPair constructor', function () {
+      var keyPair = ECPair.makeRandom()
+
+      assert.strictEqual(keyPair.compressed, true)
+      assert.strictEqual(keyPair.network, NETWORKS.bitcoin)
+    })
+
+    it('supports the options parameter', function () {
+      var keyPair = ECPair.makeRandom({
+        compressed: false,
+        network: NETWORKS.testnet
+      })
+
+      assert.strictEqual(keyPair.compressed, false)
+      assert.strictEqual(keyPair.network, NETWORKS.testnet)
+    })
+
+    it('loops until d is within interval [1, n - 1] : 1', setupTest(function () {
+      var rng = this.mock()
+      rng.exactly(2)
+      rng.onCall(0).returns(BigInteger.ZERO.toBuffer(32)) // invalid length
+      rng.onCall(1).returns(BigInteger.ONE.toBuffer(32)) // === 1
+
+      ECPair.makeRandom({ rng: rng })
+    }))
+
+    it('loops until d is within interval [1, n - 1] : n - 1', setupTest(function () {
+      var rng = this.mock()
+      rng.exactly(3)
+      rng.onCall(0).returns(BigInteger.ZERO.toBuffer(32)) // < 1
+      rng.onCall(1).returns(curve.n.toBuffer(32)) // > n-1
+      rng.onCall(2).returns(curve.n.subtract(BigInteger.ONE).toBuffer(32)) // === n-1
+
+      ECPair.makeRandom({ rng: rng })
+    }))
+  })
+
+  describe('getAddress', function () {
+    fixtures.valid.forEach(function (f) {
+      it('returns ' + f.address + ' for ' + f.WIF, function () {
+        var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
+
+        assert.strictEqual(keyPair.getAddress(), f.address)
+      })
+    })
+  })
+
+  describe('getNetwork', function () {
+    fixtures.valid.forEach(function (f) {
+      it('returns ' + f.network + ' for ' + f.WIF, function () {
+        var network = NETWORKS[f.network]
+        var keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST)
+
+        assert.strictEqual(keyPair.getNetwork(), network)
+      })
+    })
+  })
+
+  describe('ecdsa wrappers', function () {
+    var keyPair, hash
+
+    beforeEach(function () {
+      keyPair = ECPair.makeRandom()
+      hash = Buffer.alloc(32)
+    })
+
+    describe('signing', function () {
+      it('wraps ecdsa.sign', setupTest(function () {
+        this.mock(ecdsa).expects('sign')
+          .once().withArgs(hash, keyPair.d)
+
+        keyPair.sign(hash)
+      }))
+
+      it('throws if no private key is found', function () {
+        keyPair.d = null
+
+        assert.throws(function () {
+          keyPair.sign(hash)
+        }, /Missing private key/)
+      })
+    })
+
+    describe('verify', function () {
+      var signature
+
+      beforeEach(function () {
+        signature = keyPair.sign(hash)
+      })
+
+      it('wraps ecdsa.verify', setupTest(function () {
+        this.mock(ecdsa).expects('verify')
+          .once().withArgs(hash, signature, keyPair.Q)
+
+        keyPair.verify(hash, signature)
+      }))
+    })
+  })
+})
diff --git a/test/ecsignature.js b/test/ecsignature.js
new file mode 100644
index 0000000..d0bc15d
--- /dev/null
+++ b/test/ecsignature.js
@@ -0,0 +1,122 @@
+/* global describe, it */
+
+var assert = require('assert')
+
+var BigInteger = require('bigi')
+var ECSignature = require('../src/ecsignature')
+
+var fixtures = require('./fixtures/ecsignature.json')
+
+describe('ECSignature', function () {
+  describe('toCompact', function () {
+    fixtures.valid.forEach(function (f) {
+      it('exports ' + f.compact.hex + ' correctly', function () {
+        var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
+
+        var buffer = signature.toCompact(f.compact.i, f.compact.compressed)
+        assert.strictEqual(buffer.toString('hex'), f.compact.hex)
+      })
+    })
+  })
+
+  describe('parseCompact', function () {
+    fixtures.valid.forEach(function (f) {
+      it('imports ' + f.compact.hex + ' correctly', function () {
+        var buffer = Buffer.from(f.compact.hex, 'hex')
+        var parsed = ECSignature.parseCompact(buffer)
+
+        assert.strictEqual(parsed.compressed, f.compact.compressed)
+        assert.strictEqual(parsed.i, f.compact.i)
+        assert.strictEqual(parsed.signature.r.toString(), f.signature.r)
+        assert.strictEqual(parsed.signature.s.toString(), f.signature.s)
+      })
+    })
+
+    fixtures.invalid.compact.forEach(function (f) {
+      it('throws on ' + f.hex, function () {
+        var buffer = Buffer.from(f.hex, 'hex')
+
+        assert.throws(function () {
+          ECSignature.parseCompact(buffer)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('toDER', function () {
+    fixtures.valid.forEach(function (f) {
+      it('exports ' + f.DER + ' correctly', function () {
+        var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
+
+        var DER = signature.toDER()
+        assert.strictEqual(DER.toString('hex'), f.DER)
+      })
+    })
+  })
+
+  describe('fromDER', function () {
+    fixtures.valid.forEach(function (f) {
+      it('imports ' + f.DER + ' correctly', function () {
+        var buffer = Buffer.from(f.DER, 'hex')
+        var signature = ECSignature.fromDER(buffer)
+
+        assert.strictEqual(signature.r.toString(), f.signature.r)
+        assert.strictEqual(signature.s.toString(), f.signature.s)
+      })
+    })
+
+    fixtures.invalid.DER.forEach(function (f) {
+      it('throws "' + f.exception + '" for ' + f.hex, function () {
+        var buffer = Buffer.from(f.hex, 'hex')
+
+        assert.throws(function () {
+          ECSignature.fromDER(buffer)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('toScriptSignature', function () {
+    fixtures.valid.forEach(function (f) {
+      it('exports ' + f.scriptSignature.hex + ' correctly', function () {
+        var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
+
+        var scriptSignature = signature.toScriptSignature(f.scriptSignature.hashType)
+        assert.strictEqual(scriptSignature.toString('hex'), f.scriptSignature.hex)
+      })
+    })
+
+    fixtures.invalid.scriptSignature.forEach(function (f) {
+      it('throws ' + f.exception, function () {
+        var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
+
+        assert.throws(function () {
+          signature.toScriptSignature(f.hashType)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('parseScriptSignature', function () {
+    fixtures.valid.forEach(function (f) {
+      it('imports ' + f.scriptSignature.hex + ' correctly', function () {
+        var buffer = Buffer.from(f.scriptSignature.hex, 'hex')
+        var parsed = ECSignature.parseScriptSignature(buffer)
+
+        assert.strictEqual(parsed.signature.r.toString(), f.signature.r)
+        assert.strictEqual(parsed.signature.s.toString(), f.signature.s)
+        assert.strictEqual(parsed.hashType, f.scriptSignature.hashType)
+      })
+    })
+
+    fixtures.invalid.scriptSignature.forEach(function (f) {
+      it('throws on ' + f.hex, function () {
+        var buffer = Buffer.from(f.hex, 'hex')
+
+        assert.throws(function () {
+          ECSignature.parseScriptSignature(buffer)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+})
diff --git a/test/fixtures/address.json b/test/fixtures/address.json
index 765ea8a..2b7e5fa 100644
--- a/test/fixtures/address.json
+++ b/test/fixtures/address.json
@@ -63,72 +63,23 @@
       "bech32": "tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy",
       "data": "000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",
       "script": "OP_0 000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433"
-    },
-    {
-      "network": "regtest",
-      "version": 0,
-      "bech32": "bcrt1qjh3dnrafy8f2zszh5sdqn6c3ycfljh930yza9nt72v30dkw8mlvscn82zx",
-      "data": "95e2d98fa921d2a14057a41a09eb112613f95cb17905d2cd7e5322f6d9c7dfd9",
-      "script": "OP_0 95e2d98fa921d2a14057a41a09eb112613f95cb17905d2cd7e5322f6d9c7dfd9"
-    },
-    {
-      "network": "regtest",
-      "version": 0,
-      "bech32": "bcrt1qqqqqqqqqqqqqqahrwf6d62emdxmpq8gu3xe9au9fjwc9sxxn4k2qujfh7u",
-      "data": "000000000000000076e37274dd2b3b69b6101d1c89b25ef0a993b05818d3ad94",
-      "script": "OP_0 000000000000000076e37274dd2b3b69b6101d1c89b25ef0a993b05818d3ad94"
-    },
-    {
-      "network": "bitcoin",
-      "bech32": "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y",
-      "version": 1,
-      "data": "751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6",
-      "script": "OP_1 751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6"
-    },
-    {
-      "network": "bitcoin",
-      "bech32": "BC1SW50QGDZ25J",
-      "version": 16,
-      "data": "751e",
-      "script": "OP_16 751e"
-    },
-    {
-      "network": "bitcoin",
-      "bech32": "bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs",
-      "version": 2,
-      "data": "751e76e8199196d454941c45d1b3a323",
-      "script": "OP_2 751e76e8199196d454941c45d1b3a323" 
-    },
-    {
-      "network": "testnet",
-      "bech32": "tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c",
-      "version": 1,
-      "data": "000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433",
-      "script": "OP_1 000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433" 
-    },
-    {
-      "network": "bitcoin",
-      "bech32": "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0",
-      "version": 1,
-      "data": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
-      "script": "OP_1 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" 
     }
   ],
   "bech32": [
     {
-      "address": "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y",
+      "address": "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx",
       "version": 1,
       "prefix": "bc",
       "data": "751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6"
     },
     {
-      "address": "bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs",
+      "address": "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj",
       "version": 2,
       "prefix": "bc",
       "data": "751e76e8199196d454941c45d1b3a323"
     },
     {
-      "address": "BC1SW50QGDZ25J",
+      "address": "BC1SW50QA3JX3S",
       "version": 16,
       "prefix": "bc",
       "data": "751e"
@@ -145,24 +96,16 @@
         "exception": "Mixed-case string"
       },
       {
-        "address": "tb1pw508d6qejxtdg4y5r3zarquvzkan",
+        "address": "tb1pw508d6qejxtdg4y5r3zarqfsj6c3",
         "exception": "Excess padding"
       },
       {
-        "address": "bc1zw508d6qejxtdg4y5r3zarvaryvq37eag7",
+        "address": "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du",
         "exception": "Excess padding"
       },
       {
         "address": "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv",
         "exception": "Non-zero padding"
-      },
-      {
-        "address": "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du",
-        "exception": "uses wrong encoding"
-      },
-      {
-        "address": "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd",
-        "exception": "uses wrong encoding"
       }
     ],
     "fromBase58Check": [
@@ -204,7 +147,7 @@
       },
       {
         "exception": "has an invalid prefix",
-        "address": "BC1SW50QGDZ25J",
+        "address": "BC1SW50QA3JX3S",
         "network": {
           "bech32": "foo"
         }
@@ -213,6 +156,18 @@
         "exception": "has no matching Script",
         "address": "bc1rw5uspcuh"
       },
+      {
+        "exception": "has no matching Script",
+        "address": "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx"
+      },
+      {
+        "exception": "has no matching Script",
+        "address": "bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj"
+      },
+      {
+        "exception": "has no matching Script",
+        "address": "BC1SW50QA3JX3S"
+      },
       {
         "exception": "has no matching Script",
         "address": "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90"
@@ -220,84 +175,8 @@
       {
         "exception": "has no matching Script",
         "address": "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2"
-      },
-      {
-        "exception": "has no matching Script",
-        "address": "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5"
-      },
-      {
-        "exception": "has no matching Script",
-        "address": "bc1qqqqqqqqqqv9qus"
-      },
-      {
-        "address": "tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut",
-        "exception": "has an invalid prefix"
-      },
-      {
-        "address": "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd",
-        "exception": "has no matching Script"
-      },
-      {
-        "address": "tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf",
-        "exception": "has no matching Script",
-        "network": {
-          "bech32": "tb"
-        }
-      },
-      {
-        "address": "BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL",
-        "exception": "has no matching Script"
-      },
-      {
-        "address": "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh",
-        "exception": "has no matching Script"
-      },
-      {
-        "address": "tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47",
-        "exception": "has no matching Script",
-        "network": {
-          "bech32": "tb"
-        }
-      },
-      {
-        "address": "bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4",
-        "exception": "has no matching Script"
-      },
-      {
-        "address": "BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R",
-        "exception": "has no matching Script"
-      },
-      {
-        "address": "bc1pw5dgrnzv",
-        "exception": "has no matching Script"
-      },
-      {
-        "address": "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav",
-        "exception": "has no matching Script"
-      },
-      {
-        "address": "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P",
-        "exception": "has no matching Script"
-      },
-      {
-        "address": "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq",
-        "exception": "has no matching Script",
-        "network": {
-          "bech32": "tb"
-        }
-      },
-      {
-        "address": "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf",
-        "exception": "has no matching Script"
-      },
-      {
-        "address": "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j",
-        "exception": "has no matching Script"
-      },
-      {
-        "address": "bc1gmk9yu",
-        "exception": "has no matching Script"
       }
     ]
   }
 }
+
diff --git a/test/fixtures/block.json b/test/fixtures/block.json
index 8ea521c..c7aa5f7 100644
--- a/test/fixtures/block.json
+++ b/test/fixtures/block.json
@@ -19,10 +19,6 @@
     {
       "bits": "cffca00",
       "expected": "00000000000000000000000000000000000000007fca00000000000000000000"
-    },
-    {
-      "bits": "207fffff",
-      "expected": "7fffff0000000000000000000000000000000000000000000000000000000000"
     }
   ],
   "valid": [
@@ -119,24 +115,6 @@
       "timestamp": 1231006505,
       "valid": true,
       "version": 1
-    },
-    {
-      "description": "Block with witness commit",
-      "bits": 388503969,
-      "hash": "ec61d8d62a4945034a1df40dd3dfda364221c0562c3a14000000000000000000",
-      "height": 542213,
-      "hex": "000000208980ebb11236bacc66c447d5ad961bc546c0f9cc385a08000000000000000000135e9b653aee9a70028aff2db53d4f43f4484ad52558c3ae300410b79cb6a864df50a35ba11928171396e30104010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff5003054608174d696e656420627920416e74506f6f6c393b205ba350dffabe6d6d3a3e92d9efff857664de632e89fa3182f1e793d00be2e71a117b273145945a810400000000000000db250000acba0500ffffffff028a8f814a000000001976a914edf10a7fac6b32e24daa5305c723f3de58db1bc888ac0000000000000000266a24aa21a9ed4a657fcaa2149342376247e2e283a55a6b92dcc35d4d89e4ac7b74488cb63be201200000000000000000000000000000000000000000000000000000000000000000000000000100000001b898273f98d49399ecb5194ffdb1ed15c2fb37cf6d7696b4389bc7d1b76b63db010000006b483045022100e2e9bc1f6bae2deed086e935bb49fd6ac1e13dc3a44c36cd8b9a6f4257efb70d022076537c7021f12d761e1202796029f13798503bc22ab8c2ee8cb98207cbfeb414012102071c2c88e4560b47a03c033c736149a2ddd6071aea54ab85c5169cee156712f8ffffffff02b0710b00000000001976a914849a95fc65eeaa2ac47b6b6fc1f1883edb2c6c9788ace6b62501000000001976a9142964198f7ae9f7b920a2ab7c0b96b90e4ec9b14d88ac000000000100000000010152405e2660055b3540f63424a1b0b3b7bb9bbef10ceec970cd18f6f86f84a7880000000017160014dde2f1a9a4bfda011ba9ec4062990c7e1a531585ffffffff0266d418000000000017a914adc5ec550548f087371e645047170864d5fbdc03877e0400000000000016001441f6746110cc0fec102e83053d4c0ae56fab1bdd02483045022100f93bd5d3529418f60dddd477f169c32ea5ab340c99573438ee7c40d705db9ba20220323f1b4d8840098b1271c95365cdc7e8f81d0bf1fcc568c68fc7de8b871b4bee012103211d047d92547bca4aa116bc51ec4b09188e5991f69f0432fe1b5dfd8947859700000000010000000ac1a19854e5b92792ae96d08eb9f7fc016fb57c51a9047161c342e6b8de8ce721000000006b483045022100fa00a6651015ac807b03d8d54559831db40d80329f46a886b93ca6b3996daf9b02201d0fafccc88c4654a9c3d205ef0828e32376ecb42f79587615203f23fc8f2d42012102a2cda42f6954605e40cbc5601f65673621c057f8c12f16149fbbf632e8be8ed8ffffffffda16ff4a7324f78f16d5e5d4a740168de9df426cf53df569c9a33d1b94e2c25f000000006a4730440220167b4777a23db304f50ac75febfae5db0b1578c90d85769bc76e0f5458484319022023f763e95ea7771c15ea0df91c17519014b2223cd726a3b0a8b1a6f67f99b2bf012103b9492a823f03b70a1750e0fac44f58f5c81e09f4c18d0b28755b44c911ffab5ffffffffff1533f2ea34b859d2be05bbb6859d6105ad4389c911545487187437acae21b70000000006b483045022100be0b8dc174f4136e3fb4f3ccf1a2be67a44d2086179c5726c61a1af010d5232f02205c0fb4cdd7c9cb8698ceed05e688e10a0cbdd0ee5db1a0a2ef92f322e1a60e9f0121020b9f404317cc6ab5a699f607a9bb0acd0bf5588777672f8f7f4c1a13304e9f76ffffffff1395191837aa5b1cfa4cc2a79d6d6bda7d198e8a795a0f7a85f556c446119572000000006b483045022100ef3c61b5ba155b94fd02a96bf788e9a9be2de0ee53e3fe1fa6c24dd9d9aaee12022044c07be54a9c59fed96dfb778da0079f6753ab634d1920bf0fac25ebf7ac49d0012103f93e29be8b393773228f704151964662a91df4c1a3e15364e4cfb38a8cacbda9ffffffff55120f684d5fbb845fd0198cd734e46fc29f40dc8f906bf36743d7f740f5fd7c000000006a4730440220421aef290bbd39a18d1281ecfbb420b43daf2cc1c315b6bb44c895f88cb3cfcc022007a512c65b7768b1505f789b6d78479063d04ffb243072f2061eeb66fb1ade81012102712eea19c72fd644b2698c5480ebe77ce6face0bed64238a34a32085567f2f8efffffffff3553d19ce3156464e9cfa06a5260f9d9d01b16ccad6e2ebaab233ba10472ba6000000006b483045022100a29aea775d2c46028f40dceb1707b23e720bb314cef455854313569200c83162022009d0cdcef2e1f0a9217794991fa838fe6ce2bdc6e3c04ad490343c7e4a0ee7d3012102ed59ec6d98f9c2a4dd1324d46d74c56ff7e15935925f69799e547969a523ea98ffffffff530ab6d95f0d83669bfb12cbe983febe6ca638255139ce2ba0e35887f2fe3db6000000006b483045022100fad9f10989ab4ab019da4f6e430f9fe9ebe76941a9200d7346447358e93b1dce0220756c864b029a64ed9d6eedc13cf8b7d602572fcd7a3d3cb528350bb032d7e3ec012102e3e0c78d034627b1616cf196aa69bfaf20009ba9ebf09cf069453cc0423239e2ffffffff4b8e70824941d965df99703cacadfabcf79bc040029e528ff931e9ba4a7ee4d8000000006b48304502210095f37fb2700c9f96d5e5c02d4b043a7cd804f79dd071d8b221b7ae781f0f5b4e02200ae3135b8bebf813449956ae19e7c02db5eff2472da023afa8b8d4e9baba0cdd01210226cc53dfc0a41cc0cf7117dfd406db2b87161e89e2bab9908a2382173fc6dbe1ffffffff5262129e9881722b217f7e4882ed2b83ee53d9e23b9bc647494c9487ae9fabdf000000006a473044022032361f724fe006079cf37b3df61cb6c51cb0c5fd77f29b61a318134ca4948d0e02202fbe6d484a78730899230244f3662fd5578b87e9eaaccdf9bf8f05d23917de8301210254e84223b3d7f7cfd14315be8fa0c7d7eb1a1a34a672f08e2b8ec134472a66d4ffffffff067040e03288282ebe5db7b705130849c9984458b13ea7ca3c755f07b9d1b9f4000000006b483045022100b78b9c24f5f3e950aba637b827d5b11615c17ae2f43105941d172cc4a8b73c80022064998c17becd06abbcfde47c91b9d87da5ac67873ed9a412010b08b954e0b5cd01210329a0acc2b0d60dd243eef46073a672ed0caf467c92f63ef7293f2036a3851a1effffffff02027f0000000000001976a914c6a396ae979670eeaa6929df3dd1c2d8fba31c3d88ac85a19b020000000017a914409dbd0e9a1ab27853186367130e6aab2509e47f8700000000",
-      "id": "000000000000000000143a2c56c0214236dadfd30df41d4a0345492ad6d861ec",
-      "merkleRoot": "135e9b653aee9a70028aff2db53d4f43f4484ad52558c3ae300410b79cb6a864",
-      "witnessCommit": "4a657fcaa2149342376247e2e283a55a6b92dcc35d4d89e4ac7b74488cb63be2",
-      "nonce": 31692307,
-      "prevHash": "8980ebb11236bacc66c447d5ad961bc546c0f9cc385a08000000000000000000",
-      "timestamp": 1537429727,
-      "valid": true,
-      "version": 536870912,
-      "size": 2355,
-      "strippedSize": 2209,
-      "weight": 8982
     }
   ],
   "invalid": [
diff --git a/test/fixtures/bufferutils.json b/test/fixtures/bufferutils.json
index 0f046bc..2b884cf 100644
--- a/test/fixtures/bufferutils.json
+++ b/test/fixtures/bufferutils.json
@@ -2,59 +2,84 @@
   "valid": [
     {
       "dec": 0,
-      "hex": "0000000000000000"
+      "hex64": "0000000000000000",
+      "hexVI": "00",
+      "hexPD": "00"
     },
     {
       "dec": 1,
-      "hex": "0100000000000000"
+      "hex64": "0100000000000000",
+      "hexVI": "01",
+      "hexPD": "01"
     },
     {
       "dec": 252,
-      "hex": "fc00000000000000"
+      "hex64": "fc00000000000000",
+      "hexVI": "fc",
+      "hexPD": "4cfc"
     },
     {
       "dec": 253,
-      "hex": "fd00000000000000"
+      "hex64": "fd00000000000000",
+      "hexVI": "fdfd00",
+      "hexPD": "4cfd"
     },
     {
       "dec": 254,
-      "hex": "fe00000000000000"
+      "hex64": "fe00000000000000",
+      "hexVI": "fdfe00",
+      "hexPD": "4cfe"
     },
     {
       "dec": 255,
-      "hex": "ff00000000000000"
+      "hex64": "ff00000000000000",
+      "hexVI": "fdff00",
+      "hexPD": "4cff"
     },
     {
       "dec": 65534,
-      "hex": "feff000000000000"
+      "hex64": "feff000000000000",
+      "hexVI": "fdfeff",
+      "hexPD": "4dfeff"
     },
     {
       "dec": 65535,
-      "hex": "ffff000000000000"
+      "hex64": "ffff000000000000",
+      "hexVI": "fdffff",
+      "hexPD": "4dffff"
     },
     {
       "dec": 65536,
-      "hex": "0000010000000000"
+      "hex64": "0000010000000000",
+      "hexVI": "fe00000100",
+      "hexPD": "4e00000100"
     },
     {
       "dec": 65537,
-      "hex": "0100010000000000"
+      "hex64": "0100010000000000",
+      "hexVI": "fe01000100",
+      "hexPD": "4e01000100"
     },
     {
       "dec": 4294967295,
-      "hex": "ffffffff00000000"
+      "hex64": "ffffffff00000000",
+      "hexVI": "feffffffff",
+      "hexPD": "4effffffff"
     },
     {
       "dec": 4294967296,
-      "hex": "0000000001000000"
+      "hex64": "0000000001000000",
+      "hexVI": "ff0000000001000000"
     },
     {
       "dec": 4294967297,
-      "hex": "0100000001000000"
+      "hex64": "0100000001000000",
+      "hexVI": "ff0100000001000000"
     },
     {
       "dec": 9007199254740991,
-      "hex": "ffffffffffff1f00"
+      "hex64": "ffffffffffff1f00",
+      "hexVI": "ffffffffffffff1f00"
     }
   ],
   "invalid": {
@@ -62,40 +87,30 @@
       {
         "description": "n === 2^53",
         "exception": "RangeError: value out of range",
-        "hex": "0000000000002000",
+        "hex64": "0000000000002000",
+        "hexVI": "ff0000000000000020",
         "dec": 9007199254740992
       },
       {
         "description": "n > 2^53",
         "exception": "RangeError: value out of range",
-        "hex": "0100000000002000",
+        "hex64": "0100000000002000",
+        "hexVI": "ff0100000000000020",
         "dec": 9007199254740993
       }
     ],
-    "writeUInt64LE": [
+    "readPushDataInt": [
       {
-        "description": "n === 2^53",
-        "exception": "RangeError: value out of range",
-        "hex": "0000000000002000",
-        "dec": 9007199254740992
+        "description": "OP_PUSHDATA1, no size",
+        "hexPD": "4c"
       },
       {
-        "description": "n > 2^53",
-        "exception": "RangeError: value out of range",
-        "hex": "0100000000002000",
-        "dec": 9007199254740993
+        "description": "OP_PUSHDATA2, no size",
+        "hexPD": "4d"
       },
       {
-        "description": "n < 0",
-        "exception": "specified a negative value for writing an unsigned value",
-        "hex": "",
-        "dec": -1
-      },
-      {
-        "description": "0 < n < 1",
-        "exception": "value has a fractional component",
-        "hex": "",
-        "dec": 0.1
+        "description": "OP_PUSHDATA4, no size",
+        "hexPD": "4e"
       }
     ]
   }
diff --git a/test/fixtures/crypto.json b/test/fixtures/crypto.json
index 1d1976b..102b50a 100644
--- a/test/fixtures/crypto.json
+++ b/test/fixtures/crypto.json
@@ -1,43 +1,34 @@
-{
-  "hashes": [
-    {
-      "hex": "0000000000000001",
-      "hash160": "cdb00698f02afd929ffabea308340fa99ac2afa8",
-      "hash256": "3ae5c198d17634e79059c2cd735491553d22c4e09d1d9fea3ecf214565df2284",
-      "ripemd160": "8d1a05d1bc08870968eb8a81ad4393fd3aac6633",
-      "sha1": "cb473678976f425d6ec1339838f11011007ad27d",
-      "sha256": "cd2662154e6d76b2b2b92e70c0cac3ccf534f9b74eb5b89819ec509083d00a50"
-    },
-    {
-      "hex": "0101010101010101",
-      "hash160": "abaf1119f83e384210fe8e222eac76e2f0da39dc",
-      "hash256": "728338d99f356175c4945ef5cccfa61b7b56143cbbf426ddd0e0fc7cfe8c3c23",
-      "ripemd160": "5825701b4b9767fd35063b286dca3582853e0630",
-      "sha1": "c0357a32ed1f6a03be92dd094476f7f1a2e214ec",
-      "sha256": "04abc8821a06e5a30937967d11ad10221cb5ac3b5273e434f1284ee87129a061"
-    },
-    {
-      "hex": "ffffffffffffffff",
-      "hash160": "f86221f5a1fca059a865c0b7d374dfa9d5f3aeb4",
-      "hash256": "752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad",
-      "ripemd160": "cb760221600ed34337ca3ab70016b5f58c838120",
-      "sha1": "be673e8a56eaa9d8c1d35064866701c11ef8e089",
-      "sha256": "12a3ae445661ce5dee78d0650d33362dec29c4f82af05e7e57fb595bbbacf0ca"
-    },
-    {
-      "hex": "4c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e65632061742066617563696275732073617069656e2c2076656c20666163696c6973697320617263752e20536564207574206d61737361206e6962682e205574206d6f6c6c69732070756c76696e6172206d617373612e20557420756c6c616d636f7270657220646f6c6f7220656e696d2c20696e206d6f6c657374696520656e696d20636f6e64696d656e74756d2061632e20416c697175616d206572617420766f6c75747061742e204e756c6c6120736f64616c657320617420647569206e656320",
-      "hash160": "9763e6b367c363bd6b88a7b361c98e6beee243a5",
-      "hash256": "033588797115feb3545052670cac2a46584ab3cb460de63756ee0275e66b5799",
-      "ripemd160": "cad8593dcdef12ee334c97bab9787f07b3f3a1a5",
-      "sha1": "10d96fb43aca84e342206887bbeed3065d4e4344",
-      "sha256": "a7fb8276035057ed6479c5f2305a96da100ac43f0ac10f277e5ab8c5457429da"
-    }
-  ],
-  "taggedHash": [
-    {
-      "tag": "TapTweak",
-      "hex": "0101010101010101",
-      "result": "71ae15bad52efcecf4c9f672bfbded68a4adb8258f1b95f0d06aefdb5ebd14e9"
-    }
-  ]
-}
\ No newline at end of file
+[
+  {
+    "hex": "0000000000000001",
+    "hash160": "cdb00698f02afd929ffabea308340fa99ac2afa8",
+    "hash256": "3ae5c198d17634e79059c2cd735491553d22c4e09d1d9fea3ecf214565df2284",
+    "ripemd160": "8d1a05d1bc08870968eb8a81ad4393fd3aac6633",
+    "sha1": "cb473678976f425d6ec1339838f11011007ad27d",
+    "sha256": "cd2662154e6d76b2b2b92e70c0cac3ccf534f9b74eb5b89819ec509083d00a50"
+  },
+  {
+    "hex": "0101010101010101",
+    "hash160": "abaf1119f83e384210fe8e222eac76e2f0da39dc",
+    "hash256": "728338d99f356175c4945ef5cccfa61b7b56143cbbf426ddd0e0fc7cfe8c3c23",
+    "ripemd160": "5825701b4b9767fd35063b286dca3582853e0630",
+    "sha1": "c0357a32ed1f6a03be92dd094476f7f1a2e214ec",
+    "sha256": "04abc8821a06e5a30937967d11ad10221cb5ac3b5273e434f1284ee87129a061"
+  },
+  {
+    "hex": "ffffffffffffffff",
+    "hash160": "f86221f5a1fca059a865c0b7d374dfa9d5f3aeb4",
+    "hash256": "752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad",
+    "ripemd160": "cb760221600ed34337ca3ab70016b5f58c838120",
+    "sha1": "be673e8a56eaa9d8c1d35064866701c11ef8e089",
+    "sha256": "12a3ae445661ce5dee78d0650d33362dec29c4f82af05e7e57fb595bbbacf0ca"
+  },
+  {
+    "hex": "4c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20446f6e65632061742066617563696275732073617069656e2c2076656c20666163696c6973697320617263752e20536564207574206d61737361206e6962682e205574206d6f6c6c69732070756c76696e6172206d617373612e20557420756c6c616d636f7270657220646f6c6f7220656e696d2c20696e206d6f6c657374696520656e696d20636f6e64696d656e74756d2061632e20416c697175616d206572617420766f6c75747061742e204e756c6c6120736f64616c657320617420647569206e656320",
+    "hash160": "9763e6b367c363bd6b88a7b361c98e6beee243a5",
+    "hash256": "033588797115feb3545052670cac2a46584ab3cb460de63756ee0275e66b5799",
+    "ripemd160": "cad8593dcdef12ee334c97bab9787f07b3f3a1a5",
+    "sha1": "10d96fb43aca84e342206887bbeed3065d4e4344",
+    "sha256": "a7fb8276035057ed6479c5f2305a96da100ac43f0ac10f277e5ab8c5457429da"
+  }
+]
diff --git a/test/fixtures/ecdsa.json b/test/fixtures/ecdsa.json
index 780ad74..bd2fc3c 100644
--- a/test/fixtures/ecdsa.json
+++ b/test/fixtures/ecdsa.json
@@ -5,64 +5,50 @@
         "d": "01",
         "k": "ec633bd56a5774a0940cb97e27a9e4e51dc94af737596a0c5cbb3d30332d92a5",
         "message": "Everything should be made as simple as possible, but not simpler.",
-        "signature": {
-          "r": "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c9",
-          "s": "6f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"
-        }
+        "i": 0,
+        "signature": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"
       },
       {
         "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
         "k": "9dc74cbfd383980fb4ae5d2680acddac9dac956dca65a28c80ac9c847c2374e4",
         "message": "Equations are more important to me, because politics is for the present, but an equation is something for eternity.",
-        "signature": {
-          "r": "54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed",
-          "s": "07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
-        }
+        "i": 0,
+        "signature": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
       },
       {
         "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
         "k": "fd27071f01648ebbdd3e1cfbae48facc9fa97edc43bbbc9a7fdc28eae13296f5",
         "message": "Not only is the Universe stranger than we think, it is stranger than we can think.",
-        "signature": {
-          "r": "ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd0",
-          "s": "6fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283"
-        }
+        "i": 0,
+        "signature": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283"
       },
       {
         "d": "0000000000000000000000000000000000000000000000000000000000000001",
         "k": "f0cd2ba5fc7c183de589f6416220a36775a146740798756d8d949f7166dcc87f",
         "message": "How wonderful that we have met with a paradox. Now we have some hope of making progress.",
-        "signature": {
-          "r": "c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3",
-          "s": "75afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3"
-        }
+        "i": 1,
+        "signature": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3"
       },
       {
         "d": "69ec59eaa1f4f2e36b639716b7c30ca86d9a5375c7b38d8918bd9c0ebc80ba64",
         "k": "6bb4a594ad57c1aa22dbe991a9d8501daf4688bf50a4892ef21bd7c711afda97",
         "message": "Computer science is no more about computers than astronomy is about telescopes.",
-        "signature": {
-          "r": "7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d",
-          "s": "0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6"
-        }
+        "i": 0,
+        "signature": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6"
       },
       {
         "d": "00000000000000000000000000007246174ab1e92e9149c6e446fe194d072637",
         "k": "097b5c8ee22c3ea78a4d3635e0ff6fe85a1eb92ce317ded90b9e71aab2b861cb",
         "message": "...if you aren't, at any given time, scandalized by code you wrote five or even three years ago, you're not learning anywhere near enough",
-        "signature": {
-          "r": "fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda487",
-          "s": "0e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37"
-        }
+        "i": 1,
+        "signature": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37"
       },
       {
         "d": "000000000000000000000000000000000000000000056916d0f9b31dc9b637f3",
         "k": "19355c36c8cbcdfb2382e23b194b79f8c97bf650040fc7728dfbf6b39a97c25b",
         "message": "The question of whether computers can think is like the question of whether submarines can swim.",
-        "signature": {
-          "r": "cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9",
-          "s": "06ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef"
-        }
+        "i": 1,
+        "signature": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef"
       }
     ],
     "rfc6979": [
@@ -144,16 +130,13 @@
         "description": "The wrong signature",
         "d": "01",
         "message": "foo",
-        "signature": {
-          "r": "54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed",
-          "s": "07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
-        }
+        "signature": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
       },
       {
         "description": "Invalid r value (< 0)",
         "d": "01",
         "message": "foo",
-        "signature": {
+        "signatureRaw": {
           "r": "-01",
           "s": "02"
         }
@@ -162,7 +145,7 @@
         "description": "Invalid r value (== 0)",
         "d": "01",
         "message": "foo",
-        "signature": {
+        "signatureRaw": {
           "r": "00",
           "s": "02"
         }
@@ -171,7 +154,7 @@
         "description": "Invalid r value (>= n)",
         "d": "01",
         "message": "foo",
-        "signature": {
+        "signatureRaw": {
           "r": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
           "s": "02"
         }
@@ -180,7 +163,7 @@
         "description": "Invalid s value (< 0)",
         "d": "01",
         "message": "foo",
-        "signature": {
+        "signatureRaw": {
           "r": "02",
           "s": "-01"
         }
@@ -189,7 +172,7 @@
         "description": "Invalid s value (== 0)",
         "d": "01",
         "message": "foo",
-        "signature": {
+        "signatureRaw": {
           "r": "02",
           "s": "00"
         }
@@ -198,7 +181,7 @@
         "description": "Invalid s value (>= n)",
         "d": "01",
         "message": "foo",
-        "signature": {
+        "signatureRaw": {
           "r": "02",
           "s": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
         }
@@ -207,7 +190,7 @@
         "description": "Invalid r, s values (r = s = -n)",
         "d": "01",
         "message": "foo",
-        "signature": {
+        "signatureRaw": {
           "r": "-fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
           "s": "-fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
         }
diff --git a/test/fixtures/ecpair.json b/test/fixtures/ecpair.json
index cd83544..6f0a1a2 100644
--- a/test/fixtures/ecpair.json
+++ b/test/fixtures/ecpair.json
@@ -1,7 +1,7 @@
 {
   "valid": [
     {
-      "d": "0000000000000000000000000000000000000000000000000000000000000001",
+      "d": "1",
       "Q": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
       "compressed": true,
       "network": "bitcoin",
@@ -9,7 +9,7 @@
       "WIF": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
     },
     {
-      "d": "0000000000000000000000000000000000000000000000000000000000000001",
+      "d": "1",
       "Q": "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
       "compressed": false,
       "network": "bitcoin",
@@ -17,7 +17,7 @@
       "WIF": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf"
     },
     {
-      "d": "2bfe58ab6d9fd575bdc3a624e4825dd2b375d64ac033fbc46ea79dbab4f69a3e",
+      "d": "19898843618908353587043383062236220484949425084007183071220218307100305431102",
       "Q": "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
       "compressed": true,
       "network": "bitcoin",
@@ -25,7 +25,7 @@
       "WIF": "KxhEDBQyyEFymvfJD96q8stMbJMbZUb6D1PmXqBWZDU2WvbvVs9o"
     },
     {
-      "d": "6c4313b03f2e7324d75e642f0ab81b734b724e13fec930f309e222470236d66b",
+      "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
       "Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34",
       "compressed": true,
       "network": "bitcoin",
@@ -33,7 +33,7 @@
       "WIF": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx"
     },
     {
-      "d": "6c4313b03f2e7324d75e642f0ab81b734b724e13fec930f309e222470236d66b",
+      "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
       "Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6",
       "compressed": false,
       "network": "bitcoin",
@@ -41,7 +41,7 @@
       "WIF": "5JdxzLtFPHNe7CAL8EBC6krdFv9pwPoRo4e3syMZEQT9srmK8hh"
     },
     {
-      "d": "6c4313b03f2e7324d75e642f0ab81b734b724e13fec930f309e222470236d66b",
+      "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
       "Q": "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34",
       "compressed": true,
       "network": "testnet",
@@ -49,7 +49,7 @@
       "WIF": "cRD9b1m3vQxmwmjSoJy7Mj56f4uNFXjcWMCzpQCEmHASS4edEwXv"
     },
     {
-      "d": "6c4313b03f2e7324d75e642f0ab81b734b724e13fec930f309e222470236d66b",
+      "d": "48968302285117906840285529799176770990048954789747953886390402978935544927851",
       "Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6",
       "compressed": false,
       "network": "testnet",
@@ -57,7 +57,7 @@
       "WIF": "92Qba5hnyWSn5Ffcka56yMQauaWY6ZLd91Vzxbi4a9CCetaHtYj"
     },
     {
-      "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140",
+      "d": "115792089237316195423570985008687907852837564279074904382605163141518161494336",
       "Q": "0379be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
       "compressed": true,
       "network": "bitcoin",
@@ -66,53 +66,43 @@
     }
   ],
   "invalid": {
-    "fromPrivateKey": [
+    "constructor": [
       {
-        "exception": "Private key not in range \\[1, n\\)",
-        "d": "0000000000000000000000000000000000000000000000000000000000000000"
+        "exception": "Private key must be greater than 0",
+        "d": "-1"
       },
       {
-        "exception": "Private key not in range \\[1, n\\)",
-        "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
+        "exception": "Private key must be greater than 0",
+        "d": "0"
       },
       {
-        "exception": "Private key not in range \\[1, n\\)",
-        "d": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142"
+        "exception": "Private key must be less than the curve order",
+        "d": "115792089237316195423570985008687907852837564279074904382605163141518161494337"
+      },
+      {
+        "exception": "Private key must be less than the curve order",
+        "d": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
       },
       {
         "exception": "Expected property \"compressed\" of type \\?Boolean, got Number 2",
-        "d": "0000000000000000000000000000000000000000000000000000000000000001",
+        "d": "1",
         "options": {
           "compressed": 2
         }
       },
+      {
+        "exception": "Unexpected publicKey parameter",
+        "d": "1",
+        "Q": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
+      },
       {
         "exception": "Expected property \"network.messagePrefix\" of type Buffer|String, got undefined",
-        "d": "0000000000000000000000000000000000000000000000000000000000000001",
+        "d": "1",
         "options": {
           "network": {}
         }
       }
-    ],
-    "fromPublicKey": [
-      {
-        "exception": "Expected isPoint, got Buffer",
-        "Q": "",
-        "options": {}
-      },
-      {
-        "exception": "Expected property \"network.messagePrefix\" of type Buffer|String, got undefined",
-        "Q": "044289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34cec320a0565fb7caf11b1ca2f445f9b7b012dda5718b3cface369ee3a034ded6",
-        "options": {
-          "network": {}
-        }
-      },
-      {
-        "description": "Bad X coordinate (== P)",
-        "exception": "Expected isPoint, got Buffer",
-        "Q": "040000000000000000000000000000000000000000000000000000000000000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
-        "options": {}
-      }
+
     ],
     "fromWIF": [
       {
diff --git a/test/fixtures/ecsignature.json b/test/fixtures/ecsignature.json
new file mode 100644
index 0000000..ee948ad
--- /dev/null
+++ b/test/fixtures/ecsignature.json
@@ -0,0 +1,214 @@
+{
+  "valid": [
+    {
+      "compact": {
+        "hex": "1f33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c96f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262",
+        "compressed": true,
+        "i": 0
+      },
+      "scriptSignature": {
+        "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226201",
+        "hashType": 1
+      },
+      "DER": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262",
+      "signature": {
+        "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
+        "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
+      }
+    },
+    {
+      "compact": {
+        "hex": "1b54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5",
+        "compressed": false,
+        "i": 0
+      },
+      "DER": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5",
+      "scriptSignature": {
+        "hex": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a502",
+        "hashType": 2
+      },
+      "signature": {
+        "r": "38341707918488238920692284707283974715538935465589664377561695343399725051885",
+        "s": "3180566392414476763164587487324397066658063772201694230600609996154610926757"
+      }
+    },
+    {
+      "compact": {
+        "hex": "1fff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd06fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283",
+        "compressed": true,
+        "i": 0
+      },
+      "scriptSignature": {
+        "hex": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b28303",
+        "hashType": 3
+      },
+      "DER": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283",
+      "signature": {
+        "r": "115464191557905790016094131873849783294273568009648050793030031933291767741904",
+        "s": "50562520307781850052192542766631199590053690478900449960232079510155113443971"
+      }
+    },
+    {
+      "compact": {
+        "hex": "1cc0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d375afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3",
+        "compressed": false,
+        "i": 1
+      },
+      "scriptSignature": {
+        "hex": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d381",
+        "hashType": 129
+      },
+      "DER": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3",
+      "signature": {
+        "r": "87230998027579607140680851455601772643840468630989315269459846730712163783123",
+        "s": "53231320085894623106179381504478252331065330583563809963303318469380290929875"
+      }
+    },
+    {
+      "compact": {
+        "hex": "1f7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6",
+        "compressed": true,
+        "i": 0
+      },
+      "scriptSignature": {
+        "hex": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df682",
+        "hashType": 130
+      },
+      "DER": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6",
+      "signature": {
+        "r": "51348483531757779992459563033975330355971795607481991320287437101831125115997",
+        "s": "6277080015686056199074771961940657638578000617958603212944619747099038735862"
+      }
+    },
+    {
+      "compact": {
+        "hex": "1cfbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda4870e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37",
+        "compressed": false,
+        "i": 1
+      },
+      "scriptSignature": {
+        "hex": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd3783",
+        "hashType": 131
+      },
+      "DER": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37",
+      "signature": {
+        "r": "113979859486826658566290715281614250298918272782414232881639314569529560769671",
+        "s": "6517071009538626957379450615706485096874328019806177698938278220732027419959"
+      }
+    },
+    {
+      "compact": {
+        "hex": "20cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf906ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef",
+        "compressed": true,
+        "i": 1
+      },
+      "scriptSignature": {
+        "hex": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef81",
+        "hashType": 129
+      },
+      "DER": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef",
+      "signature": {
+        "r": "93122007060065279508564838030979550535085999589142852106617159184757394422777",
+        "s": "3078539468410661027472930027406594684630312677495124015420811882501887769839"
+      }
+    }
+  ],
+  "invalid": {
+    "compact": [
+      {
+        "exception": "Invalid signature parameter",
+        "hex": "23987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e93791d7629795b62"
+      },
+      {
+        "exception": "Expected Buffer\\(Length: 65\\), got Buffer\\(Length: 68\\)",
+        "hex": "1c987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e93791d7629795b62000000"
+      },
+      {
+        "exception": "Expected Buffer\\(Length: 65\\), got Buffer\\(Length: 59\\)",
+        "hex": "1c987ceade6a304fc5823ab38f99fc3c5f772a2d3e89ea05931e2726105fc53b9e601fc3231f35962c714fcbce5c95b427496edc7ae8b3d12e9379"
+      }
+    ],
+    "DER": [
+      {
+        "exception": "DER sequence length is too short",
+        "hex": "ffffffffffffff"
+      },
+      {
+        "exception": "DER sequence length is too long",
+        "hex": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+      },
+      {
+        "exception": "Expected DER sequence",
+        "hex": "00ffff0400ffffff020400ffffff"
+      },
+      {
+        "exception": "DER sequence length is invalid",
+        "hex": "30ff020400ffffff020400ffffff"
+      },
+      {
+        "exception": "DER sequence length is invalid",
+        "hex": "300c030400ffffff030400ffffff0000"
+      },
+      {
+        "exception": "Expected DER integer",
+        "hex": "300cff0400ffffff020400ffffff"
+      },
+      {
+        "exception": "Expected DER integer \\(2\\)",
+        "hex": "300c020200ffffff020400ffffff"
+      },
+      {
+        "exception": "R length is zero",
+        "hex": "30080200020400ffffff"
+      },
+      {
+        "exception": "S length is zero",
+        "hex": "3008020400ffffff0200"
+      },
+      {
+        "exception": "R length is too long",
+        "hex": "300c02dd00ffffff020400ffffff"
+      },
+      {
+        "exception": "S length is invalid",
+        "hex": "300c020400ffffff02dd00ffffff"
+      },
+      {
+        "exception": "R value is negative",
+        "hex": "300c020480000000020400ffffff"
+      },
+      {
+        "exception": "S value is negative",
+        "hex": "300c020400ffffff020480000000"
+      },
+      {
+        "exception": "R value excessively padded",
+        "hex": "300c02040000ffff020400ffffff"
+      },
+      {
+        "exception": "S value excessively padded",
+        "hex": "300c020400ffffff02040000ffff"
+      }
+    ],
+    "scriptSignature": [
+      {
+        "exception": "Invalid hashType 7",
+        "hashType": 7,
+        "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226207",
+        "signature": {
+          "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
+          "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
+        }
+      },
+      {
+        "exception": "Invalid hashType 140",
+        "hashType": 140,
+        "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa543422628c",
+        "signature": {
+          "r": "23362334225185207751494092901091441011938859014081160902781146257181456271561",
+          "s": "50433721247292933944369538617440297985091596895097604618403996029256432099938"
+        }
+      }
+    ]
+  }
+}
diff --git a/test/fixtures/embed.json b/test/fixtures/embed.json
deleted file mode 100644
index 3ab2ddf..0000000
--- a/test/fixtures/embed.json
+++ /dev/null
@@ -1,102 +0,0 @@
-{
-  "valid": [
-    {
-      "description": "output from output",
-      "arguments": {
-        "output": "OP_RETURN a3b147dbe4a85579fc4b5a1811e76620560e07267e62b9a0d6858f9127735cadd82f67e06c24dbc4"
-      },
-      "options": {},
-      "expected": {
-        "data": [
-          "a3b147dbe4a85579fc4b5a1811e76620560e07267e62b9a0d6858f9127735cadd82f67e06c24dbc4"
-        ],
-        "output": "OP_RETURN a3b147dbe4a85579fc4b5a1811e76620560e07267e62b9a0d6858f9127735cadd82f67e06c24dbc4",
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "output from data",
-      "arguments": {
-        "data": [
-          "a3b147dbe4a85579fc4b5a1811e76620560e07267e62b9a0d6858f9127735cadd82f67e06c24dbc4"
-        ]
-      },
-      "expected": {
-        "data": [
-          "a3b147dbe4a85579fc4b5a1811e76620560e07267e62b9a0d6858f9127735cadd82f67e06c24dbc4"
-        ],
-        "output": "OP_RETURN a3b147dbe4a85579fc4b5a1811e76620560e07267e62b9a0d6858f9127735cadd82f67e06c24dbc4",
-        "input": null,
-        "witness": null
-      }
-    }
-  ],
-  "invalid": [
-    {
-      "exception": "Not enough data",
-      "arguments": {}
-    },
-    {
-      "description": "First OP is not OP_RETURN",
-      "exception": "Output is invalid",
-      "options": {},
-      "arguments": {
-        "output": "OP_1 OP_2 OP_ADD"
-      }
-    },
-    {
-      "description": "Return value and data do not match",
-      "exception": "Data mismatch",
-      "options": {},
-      "arguments": {
-        "output": "OP_RETURN a3b147dbe4a85579fc4b5a1811e76620560e07267e62b9a0d6858f9127735cadd82f67e06c24dbc4",
-        "data": [
-          "a3b147dbe4a85579fc4b5a1855555555555555555555555555555555555555555555555555555555"
-        ]
-      }
-    },
-    {
-      "description": "Script length incorrect",
-      "exception": "Data mismatch",
-      "options": {},
-      "arguments": {
-        "output": "OP_RETURN a3b1 47db",
-        "data": [
-          "a3b1"
-        ]
-      }
-    },
-    {
-      "description": "Return data is not buffer",
-      "exception": "Output is invalid",
-      "options": {},
-      "arguments": {
-        "output": "OP_RETURN OP_1"
-      }
-    }
-  ],
-  "dynamic": {
-    "depends": {
-      "data": [ "data", "output" ],
-      "output": [ "output", "data" ]
-    },
-    "details": [
-      {
-        "description": "embed",
-        "data": [
-          "a3b147dbe4a85579fc4b5a1811e76620560e07267e62b9a0d6858f9127735cadd82f67e06c24dbc4"
-        ],
-        "output": "OP_RETURN a3b147dbe4a85579fc4b5a1811e76620560e07267e62b9a0d6858f9127735cadd82f67e06c24dbc4"
-      },
-      {
-        "description": "embed",
-        "data": [
-          "a3b147dbe4a85579fc4b5a1811e76620560e0726",
-          "7e62b9a0d6858f9127735cadd82f67e06c24dbc4"
-        ],
-        "output": "OP_RETURN a3b147dbe4a85579fc4b5a1811e76620560e0726 7e62b9a0d6858f9127735cadd82f67e06c24dbc4"
-      }
-    ]
-  }
-}
diff --git a/test/fixtures/hdnode.json b/test/fixtures/hdnode.json
new file mode 100644
index 0000000..56e97d6
--- /dev/null
+++ b/test/fixtures/hdnode.json
@@ -0,0 +1,327 @@
+{
+  "valid": [
+    {
+      "network": "bitcoin",
+      "master": {
+        "seed": "000102030405060708090a0b0c0d0e0f",
+        "wif": "L52XzL2cMkHxqxBXRyEpnPQZGUs3uKiL3R11XbAdHigRzDozKZeW",
+        "pubKey": "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2",
+        "chainCode": "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508",
+        "base58": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8",
+        "base58Priv": "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
+        "identifier": "3442193e1bb70916e914552172cd4e2dbc9df811",
+        "fingerprint": "3442193e",
+        "address": "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma"
+      },
+      "children": [
+        {
+          "path": "m/0'",
+          "m": 0,
+          "hardened": true,
+          "wif": "L5BmPijJjrKbiUfG4zbiFKNqkvuJ8usooJmzuD7Z8dkRoTThYnAT",
+          "pubKey": "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56",
+          "chainCode": "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141",
+          "base58": "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw",
+          "base58Priv": "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7",
+          "identifier": "5c1bd648ed23aa5fd50ba52b2457c11e9e80a6a7",
+          "fingerprint": "5c1bd648",
+          "address": "19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh",
+          "index": 2147483648,
+          "depth": 1
+        },
+        {
+          "path": "m/0'/1",
+          "m": 1,
+          "wif": "KyFAjQ5rgrKvhXvNMtFB5PCSKUYD1yyPEe3xr3T34TZSUHycXtMM",
+          "pubKey": "03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c",
+          "chainCode": "2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19",
+          "base58": "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ",
+          "base58Priv": "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs",
+          "identifier": "bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe",
+          "fingerprint": "bef5a2f9",
+          "address": "1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj",
+          "index": 1,
+          "depth": 2
+        },
+        {
+          "path": "m/0'/1/2'",
+          "m": 2,
+          "hardened": true,
+          "wif": "L43t3od1Gh7Lj55Bzjj1xDAgJDcL7YFo2nEcNaMGiyRZS1CidBVU",
+          "pubKey": "0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2",
+          "chainCode": "04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f",
+          "base58": "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5",
+          "base58Priv": "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM",
+          "identifier": "ee7ab90cde56a8c0e2bb086ac49748b8db9dce72",
+          "fingerprint": "ee7ab90c",
+          "address": "1NjxqbA9aZWnh17q1UW3rB4EPu79wDXj7x",
+          "index": 2147483650,
+          "depth": 3
+        },
+        {
+          "path": "m/0'/1/2'/2",
+          "m": 2,
+          "wif": "KwjQsVuMjbCP2Zmr3VaFaStav7NvevwjvvkqrWd5Qmh1XVnCteBR",
+          "pubKey": "02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29",
+          "chainCode": "cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd",
+          "base58": "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV",
+          "base58Priv": "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334",
+          "identifier": "d880d7d893848509a62d8fb74e32148dac68412f",
+          "fingerprint": "d880d7d8",
+          "address": "1LjmJcdPnDHhNTUgrWyhLGnRDKxQjoxAgt",
+          "index": 2,
+          "depth": 4
+        },
+        {
+          "path": "m/0'/1/2'/2/1000000000",
+          "m": 1000000000,
+          "wif": "Kybw8izYevo5xMh1TK7aUr7jHFCxXS1zv8p3oqFz3o2zFbhRXHYs",
+          "pubKey": "022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011",
+          "chainCode": "c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e",
+          "base58": "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy",
+          "base58Priv": "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76",
+          "identifier": "d69aa102255fed74378278c7812701ea641fdf32",
+          "fingerprint": "d69aa102",
+          "address": "1LZiqrop2HGR4qrH1ULZPyBpU6AUP49Uam",
+          "index": 1000000000,
+          "depth": 5
+        }
+      ]
+    },
+    {
+      "network": "bitcoin",
+      "master": {
+        "seed": "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542",
+        "wif": "KyjXhyHF9wTphBkfpxjL8hkDXDUSbE3tKANT94kXSyh6vn6nKaoy",
+        "pubKey": "03cbcaa9c98c877a26977d00825c956a238e8dddfbd322cce4f74b0b5bd6ace4a7",
+        "chainCode": "60499f801b896d83179a4374aeb7822aaeaceaa0db1f85ee3e904c4defbd9689",
+        "base58": "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB",
+        "base58Priv": "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U",
+        "identifier": "bd16bee53961a47d6ad888e29545434a89bdfe95",
+        "fingerprint": "bd16bee5",
+        "address": "1JEoxevbLLG8cVqeoGKQiAwoWbNYSUyYjg"
+      },
+      "children": [
+        {
+          "path": "m/0",
+          "m": 0,
+          "wif": "L2ysLrR6KMSAtx7uPqmYpoTeiRzydXBattRXjXz5GDFPrdfPzKbj",
+          "pubKey": "02fc9e5af0ac8d9b3cecfe2a888e2117ba3d089d8585886c9c826b6b22a98d12ea",
+          "chainCode": "f0909affaa7ee7abe5dd4e100598d4dc53cd709d5a5c2cac40e7412f232f7c9c",
+          "base58": "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH",
+          "base58Priv": "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt",
+          "identifier": "5a61ff8eb7aaca3010db97ebda76121610b78096",
+          "fingerprint": "5a61ff8e",
+          "address": "19EuDJdgfRkwCmRzbzVBHZWQG9QNWhftbZ",
+          "index": 0,
+          "depth": 1
+        },
+        {
+          "path": "m/0/2147483647'",
+          "m": 2147483647,
+          "hardened": true,
+          "wif": "L1m5VpbXmMp57P3knskwhoMTLdhAAaXiHvnGLMribbfwzVRpz2Sr",
+          "pubKey": "03c01e7425647bdefa82b12d9bad5e3e6865bee0502694b94ca58b666abc0a5c3b",
+          "chainCode": "be17a268474a6bb9c61e1d720cf6215e2a88c5406c4aee7b38547f585c9a37d9",
+          "base58": "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a",
+          "base58Priv": "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9",
+          "identifier": "d8ab493736da02f11ed682f88339e720fb0379d1",
+          "fingerprint": "d8ab4937",
+          "address": "1Lke9bXGhn5VPrBuXgN12uGUphrttUErmk",
+          "index": 4294967295,
+          "depth": 2
+        },
+        {
+          "path": "m/0/2147483647'/1",
+          "m": 1,
+          "wif": "KzyzXnznxSv249b4KuNkBwowaN3akiNeEHy5FWoPCJpStZbEKXN2",
+          "pubKey": "03a7d1d856deb74c508e05031f9895dab54626251b3806e16b4bd12e781a7df5b9",
+          "chainCode": "f366f48f1ea9f2d1d3fe958c95ca84ea18e4c4ddb9366c336c927eb246fb38cb",
+          "base58": "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon",
+          "base58Priv": "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef",
+          "identifier": "78412e3a2296a40de124307b6485bd19833e2e34",
+          "fingerprint": "78412e3a",
+          "address": "1BxrAr2pHpeBheusmd6fHDP2tSLAUa3qsW",
+          "index": 1,
+          "depth": 3
+        },
+        {
+          "path": "m/0/2147483647'/1/2147483646'",
+          "m": 2147483646,
+          "hardened": true,
+          "wif": "L5KhaMvPYRW1ZoFmRjUtxxPypQ94m6BcDrPhqArhggdaTbbAFJEF",
+          "pubKey": "02d2b36900396c9282fa14628566582f206a5dd0bcc8d5e892611806cafb0301f0",
+          "chainCode": "637807030d55d01f9a0cb3a7839515d796bd07706386a6eddf06cc29a65a0e29",
+          "base58": "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL",
+          "base58Priv": "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc",
+          "identifier": "31a507b815593dfc51ffc7245ae7e5aee304246e",
+          "fingerprint": "31a507b8",
+          "address": "15XVotxCAV7sRx1PSCkQNsGw3W9jT9A94R",
+          "index": 4294967294,
+          "depth": 4
+        },
+        {
+          "path": "m/0/2147483647'/1/2147483646'/2",
+          "m": 2,
+          "wif": "L3WAYNAZPxx1fr7KCz7GN9nD5qMBnNiqEJNJMU1z9MMaannAt4aK",
+          "pubKey": "024d902e1a2fc7a8755ab5b694c575fce742c48d9ff192e63df5193e4c7afe1f9c",
+          "chainCode": "9452b549be8cea3ecb7a84bec10dcfd94afe4d129ebfd3b3cb58eedf394ed271",
+          "base58": "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt",
+          "base58Priv": "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j",
+          "identifier": "26132fdbe7bf89cbc64cf8dafa3f9f88b8666220",
+          "fingerprint": "26132fdb",
+          "address": "14UKfRV9ZPUp6ZC9PLhqbRtxdihW9em3xt",
+          "index": 2,
+          "depth": 5
+        }
+      ]
+    },
+    {
+      "comment": "Private key has leading zeros, see PR #673",
+      "network": "bitcoin",
+      "master": {
+        "seed": "d13de7bd1e54422d1a3b3b699a27fb460de2849e7e66a005c647e8e4a54075cb",
+        "wif": "KwDiCU5bs8xQwsRgxjhkcJcVuR7NE4Mei8X9uSAVviVTE7JmMoS6",
+        "pubKey": "0298ccc720d5dea817c7077605263bae52bca083cf8888fee77ff4c1b4797ee180",
+        "chainCode": "c23ab32b36ddff49fae350a1bed8ec6b4d9fc252238dd789b7273ba4416054eb",
+        "base58": "xpub661MyMwAqRbcGUbHLLJ5n2DzFAt8mmaDxbmbdimh68m8EiXGEQPiJya4BJat5yMzy4e68VSUoLGCu5uvzf8dUoGvwuJsLE6F1cibmWsxFNn",
+        "base58Priv": "xprv9s21ZrQH143K3zWpEJm5QtHFh93eNJrNbNqzqLN5XoE9MvC7gs5TmBFaL2PpaXpDc8FBYVe5EChc73ApjSQ5fWsXS7auHy1MmG6hdpywE1q",
+        "identifier": "1a87677be6f73cc9655e8b4c5d2fd0aeeb1b23c7",
+        "fingerprint": "1a87677b",
+        "address": "KyDarNhq8WK8rSU36UY7bDv9MAwdpKFZYKPN89Geh2dUwHjTqVh5"
+      },
+      "children": [
+        {
+          "path": "m/44'/0'/0'/0/0'",
+          "wif": "L3z3MSqZtDQ1FPHKi7oWf1nc9rMEGFtZUDCoFa7n4F695g5qZiSu",
+          "pubKey": "027c3591221e28939e45f8ea297d62c3640ebb09d7058b01d09c963d984a40ad49",
+          "chainCode": "ca27553aa89617e982e621637d6478f564b32738f8bbe2e48d0a58a8e0f6da40",
+          "base58": "xpub6GcBnm7FfDg5ERWACCvtuotN6Tdoc37r3SZ1asBHvCWzPkqWn3MVKPWKzy6GsfmdMUGanR3D12dH1cp5tJauuubwc4FAJDn67SH2uUjwAT1",
+          "base58Priv": "xprvA3cqPFaMpr7n1wRh6BPtYfwdYRoKCaPzgDdQnUmgMrz1WxWNEW3EmbBr9ieh9BJAsRGKFPLvotb4p4Aq79jddUVKPVJt7exVzLHcv777JVf",
+          "identifier": "e371d69b5dae6eacee832a130ee9f55545275a09",
+          "fingerprint": "e371d69b",
+          "address": "1MjcmArHeqorgm9uJi4kPNQ6CbsrmCtASH",
+          "index": 2147483648,
+          "depth": 5
+        }
+      ]
+    },
+    {
+      "network": "litecoin",
+      "master": {
+        "seed": "000102030405060708090a0b0c0d0e0f",
+        "wif": "TAroS5Knm8GZcnpPycBgzjwwDLWMyQjDrcuGPPoArgrbW7Ln22qp",
+        "pubKey": "0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2",
+        "chainCode": "873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508",
+        "base58": "Ltub2SSUS19CirucWFod2ZsYA2J4v4U76YiCXHdcQttnoiy5aGanFHCPDBX7utfG6f95u1cUbZJNafmvzNCzZZJTw1EmyFoL8u1gJbGM8ipu491",
+        "base58Priv": "Ltpv71G8qDifUiNetP6nmxPA5STrUVmv2J9YSmXajv8VsYBUyuPhvN9xCaQrfX2wo5xxJNtEazYCFRUu5FmokYMM79pcqz8pcdo4rNXAFPgyB4k",
+        "identifier": "3442193e1bb70916e914552172cd4e2dbc9df811",
+        "fingerprint": "3442193e",
+        "address": "LPzGaoLUtXFkmNo3u1chDxGxDnSaBQTTxm"
+      },
+      "children": [
+        {
+          "path": "m/0'",
+          "m": 0,
+          "hardened": true,
+          "wif": "TB22qU2V9EJCVKJ8cdYaTfvDhnYcCzthcWgFm1k6hbvbKM1NLxoL",
+          "pubKey": "035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56",
+          "chainCode": "47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141",
+          "base58": "Ltub2UhtRiSfp82berwLEKkB34QBEt2TUdCDCu4WNzGumvAMwYsxfWjULKsXhADxqy3cuDu3TnqoKJr1xmB8Wb2qzthWAtbb4CutpXPuSU1YMgG",
+          "base58Priv": "Ltpv73XYpw28ZyVe2zEVyiFnxUZxoKLGQNdZ8NxUi1WcqjNmMBgtLbh3KimGSnPHCoLv1RmvxHs4dnKmo1oXQ8dXuDu8uroxrbVxZPA1gXboYvx",
+          "identifier": "5c1bd648ed23aa5fd50ba52b2457c11e9e80a6a7",
+          "fingerprint": "5c1bd648",
+          "address": "LTcyn1jun6g9hvxtsT7cqMRSyix7AULC76",
+          "index": 2147483648,
+          "depth": 1
+        }
+      ]
+    }
+  ],
+  "invalid": {
+    "fromBase58": [
+      {
+        "exception": "Invalid checksum",
+        "string": "xprvQQQQQQQQQQQQQQQQCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"
+      },
+      {
+        "exception": "Invalid buffer length",
+        "network": "bitcoin",
+        "string": "HAsbc6CgKmTYEQg2CTz7m5STEPAB"
+      },
+      {
+        "exception": "Invalid parent fingerprint",
+        "network": "bitcoin",
+        "string": "xprv9tnJFvAXAXPfPnMTKfwpwnkty7MzJwELVgp4NTBquaKXy4RndyfJJCJJf7zNaVpBpzrwVRutZNLRCVLEcZHcvuCNG3zGbGBcZn57FbNnmSP"
+      },
+      {
+        "exception": "Invalid private key",
+        "network": "bitcoin",
+        "string": "xprv9s21ZrQH143K3yLysFvsu3n1dMwhNusmNHr7xArzAeCc7MQYqDBBStmqnZq6WLi668siBBNs3SjiyaexduHu9sXT9ixTsqptL67ADqcaBdm"
+      },
+      {
+        "exception": "Invalid index",
+        "network": "bitcoin",
+        "string": "xprv9s21ZrQYdgnodnKW4Drm1Qg7poU6Gf2WUDsjPxvYiK7iLBMrsjbnF1wsZZQgmXNeMSG3s7jmHk1b3JrzhG5w8mwXGxqFxfrweico7k8DtxR"
+      },
+      {
+        "exception": "Unknown network version",
+        "string": "1111111111111adADjFaSNPxwXqLjHLj4mBfYxuewDPbw9hEj1uaXCzMxRPXDFF3cUoezTFYom4sEmEVSQmENPPR315cFk9YUFVek73wE9"
+      },
+      {
+        "exception": "Invalid network version",
+        "network": "bitcoin",
+        "string": "Ltpv73XYpw28ZyVe2zEVyiFnxUZxoKLGQNdZ8NxUi1WcqjNmMBgtLbh3KimGSnPHCoLv1RmvxHs4dnKmo1oXQ8dXuDu8uroxrbVxZPA1gXboYvx"
+      },
+      {
+        "exception": "Invalid buffer length",
+        "string": "9XpNiB4DberdMn4jZiMhNGtuZUd7xUrCEGw4MG967zsVNvUKBEC9XLrmVmFasanWGp15zXfTNw4vW4KdvUAynEwyKjdho9QdLMPA2H5uyt"
+      },
+      {
+        "exception": "Invalid buffer length",
+        "string": "7JJikZQ2NUXjSAnAF2SjFYE3KXbnnVxzRBNddFE1DjbDEHVGEJzYC7zqSgPoauBJS3cWmZwsER94oYSFrW9vZ4Ch5FtGeifdzmtS3FGYDB1vxFZsYKgMc"
+      },
+      {
+        "exception": "Invalid parent fingerprint",
+        "string": "xpub67tVq9SuNQCfm2PXBqjGRAtNZ935kx2uHJaURePth4JBpMfEy6jum7Euj7FTpbs7fnjhfZcNEktCucWHcJf74dbKLKNSTZCQozdDVwvkJhs"
+      },
+      {
+        "exception": "Invalid index",
+        "string": "xpub661MyMwTWkfYZq6BEh3ywGVXFvNj5hhzmWMhFBHSqmub31B1LZ9wbJ3DEYXZ8bHXGqnHKfepTud5a2XxGdnnePzZa2m2DyzTnFGBUXtaf9M"
+      },
+      {
+        "exception": "Unknown network version",
+        "string": "8FH81Rao5EgGmdScoN66TJAHsQP7phEMeyMTku9NBJd7hXgaj3HTvSNjqJjoqBpxdbuushwPEM5otvxXt2p9dcw33AqNKzZEPMqGHmz7Dpayi6Vb"
+      },
+      {
+        "exception": "Point is not on the curve",
+        "string": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gYymDsxxRe3WWeZQ7TadaLSdKUffezzczTCpB8j3JP96UwE2n6w1"
+      }
+    ],
+    "deriveHardened": [
+      2147483648,
+      null,
+      "foo",
+      -1
+    ],
+    "derive": [
+      4294967296,
+      null,
+      "foo",
+      -1
+    ],
+    "derivePath": [
+      2,
+      [
+        2,
+        3,
+        4
+      ],
+      "/",
+      "m/m/123",
+      "a/0/1/2",
+      "m/0/  1  /2",
+      "m/0/1.5/2"
+    ]
+  }
+}
diff --git a/test/fixtures/p2ms.json b/test/fixtures/p2ms.json
deleted file mode 100644
index f84b4d5..0000000
--- a/test/fixtures/p2ms.json
+++ /dev/null
@@ -1,403 +0,0 @@
-{
-  "valid": [
-    {
-      "description": "output from output",
-      "arguments": {
-        "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG"
-      },
-      "options": {},
-      "expected": {
-        "m": 2,
-        "n": 2,
-        "name": "p2ms(2 of 2)",
-        "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG",
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000002"
-        ],
-        "signatures": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "output from m/pubkeys",
-      "arguments": {
-        "m": 1,
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000002"
-        ]
-      },
-      "expected": {
-        "m": 1,
-        "n": 2,
-        "name": "p2ms(1 of 2)",
-        "output": "OP_1 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG",
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000002"
-        ],
-        "signatures": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "input/output from m/pubkeys/signatures",
-      "arguments": {
-        "m": 2,
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000002",
-          "030000000000000000000000000000000000000000000000000000000000000003"
-        ],
-        "signatures": [
-          "300602010002010001",
-          "300602010102010001"
-        ]
-      },
-      "expected": {
-        "m": 2,
-        "n": 3,
-        "name": "p2ms(2 of 3)",
-        "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 OP_3 OP_CHECKMULTISIG",
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000002",
-          "030000000000000000000000000000000000000000000000000000000000000003"
-        ],
-        "signatures": [
-          "300602010002010001",
-          "300602010102010001"
-        ],
-        "input": "OP_0 300602010002010001 300602010102010001",
-        "witness": []
-      }
-    },
-    {
-      "description": "input/output from output/signatures",
-      "arguments": {
-        "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 OP_3 OP_CHECKMULTISIG",
-        "signatures": [
-          "300602010002010001",
-          "300602010102010001"
-        ]
-      },
-      "expected": {
-        "m": 2,
-        "n": 3,
-        "name": "p2ms(2 of 3)",
-        "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 OP_3 OP_CHECKMULTISIG",
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000002",
-          "030000000000000000000000000000000000000000000000000000000000000003"
-        ],
-        "signatures": [
-          "300602010002010001",
-          "300602010102010001"
-        ],
-        "input": "OP_0 300602010002010001 300602010102010001",
-        "witness": []
-      }
-    },
-    {
-      "description": "input/output from input/output",
-      "arguments": {
-        "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 OP_3 OP_CHECKMULTISIG",
-        "input": "OP_0 300602010002010001 300602010102010001"
-      },
-      "expected": {
-        "m": 2,
-        "n": 3,
-        "name": "p2ms(2 of 3)",
-        "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 OP_3 OP_CHECKMULTISIG",
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000002",
-          "030000000000000000000000000000000000000000000000000000000000000003"
-        ],
-        "signatures": [
-          "300602010002010001",
-          "300602010102010001"
-        ],
-        "input": "OP_0 300602010002010001 300602010102010001",
-        "witness": []
-      }
-    },
-    {
-      "description": "input/output from input/output, even if incomplete",
-      "arguments": {
-        "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG",
-        "input": "OP_0 OP_0 300602010102010001"
-      },
-      "options": {
-        "allowIncomplete": true
-      },
-      "expected": {
-        "m": 2,
-        "n": 2,
-        "name": "p2ms(2 of 2)",
-        "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG",
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000002"
-        ],
-        "signatures": [
-          0,
-          "300602010102010001"
-        ],
-        "input": "OP_0 OP_0 300602010102010001",
-        "witness": []
-      }
-    },
-    {
-      "description": "input/output from output/signatures, even if incomplete",
-      "arguments": {
-        "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG",
-        "signatures": [
-          0,
-          "300602010102010001"
-        ]
-      },
-      "options": {
-        "allowIncomplete": true
-      },
-      "expected": {
-        "m": 2,
-        "n": 2,
-        "name": "p2ms(2 of 2)",
-        "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 OP_2 OP_CHECKMULTISIG",
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000002"
-        ],
-        "signatures": [
-          0,
-          "300602010102010001"
-        ],
-        "input": "OP_0 OP_0 300602010102010001",
-        "witness": []
-      }
-    }
-  ],
-  "invalid": [
-    {
-      "exception": "Not enough data",
-      "arguments": {}
-    },
-    {
-      "exception": "Not enough data",
-      "arguments": {
-        "m": 2
-      }
-    },
-    {
-      "exception": "Not enough data",
-      "arguments": {
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000002"
-        ]
-      }
-    },
-    {
-      "description": "Non OP_INT chunk (m)",
-      "exception": "Output is invalid",
-      "arguments": {
-        "output": "OP_RESERVED"
-      }
-    },
-    {
-      "description": "Non OP_INT chunk (n)",
-      "exception": "Output is invalid",
-      "arguments": {
-        "output": "OP_1 OP_RESERVED"
-      }
-    },
-    {
-      "description": "Missing OP_CHECKMULTISIG",
-      "exception": "Output is invalid",
-      "arguments": {
-        "output": "OP_1 OP_2 OP_RESERVED"
-      }
-    },
-    {
-      "description": "m is 0",
-      "exception": "Output is invalid",
-      "arguments": {
-        "output": "OP_0 OP_2 OP_CHECKMULTISIG"
-      }
-    },
-    {
-      "description": "n is 0 (m > n)",
-      "exception": "Output is invalid",
-      "arguments": {
-        "output": "OP_2 OP_0 OP_CHECKMULTISIG"
-      }
-    },
-    {
-      "description": "m > n",
-      "exception": "Output is invalid",
-      "arguments": {
-        "output": "OP_3 OP_2 OP_CHECKMULTISIG"
-      }
-    },
-    {
-      "description": "n !== output pubkeys",
-      "exception": "Output is invalid",
-      "options": {},
-      "arguments": {
-        "output": "OP_1 030000000000000000000000000000000000000000000000000000000000000001 OP_2 OP_CHECKMULTISIG"
-      }
-    },
-    {
-      "description": "Non-canonical output public key",
-      "exception": "Output is invalid",
-      "arguments": {
-        "output": "OP_1 ffff OP_1 OP_CHECKMULTISIG"
-      }
-    },
-    {
-      "exception": "n mismatch",
-      "arguments": {
-        "n": 2,
-        "output": "OP_1 030000000000000000000000000000000000000000000000000000000000000001 OP_1 OP_CHECKMULTISIG"
-      }
-    },
-    {
-      "exception": "m mismatch",
-      "arguments": {
-        "m": 2,
-        "output": "OP_1 030000000000000000000000000000000000000000000000000000000000000001 OP_1 OP_CHECKMULTISIG"
-      }
-    },
-    {
-      "exception": "Pubkeys mismatch",
-      "options": {},
-      "arguments": {
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ],
-        "output": "OP_1 030000000000000000000000000000000000000000000000000000000000000002 OP_1 OP_CHECKMULTISIG"
-      }
-    },
-    {
-      "exception": "Pubkey count mismatch",
-      "arguments": {
-        "m": 2,
-        "n": 3,
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000002"
-        ]
-      }
-    },
-    {
-      "exception": "Pubkey count cannot be less than m",
-      "arguments": {
-        "m": 4,
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ]
-      }
-    },
-    {
-      "exception": "Not enough signatures provided",
-      "arguments": {
-        "m": 2,
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ],
-        "signatures": [
-          "300602010002010001"
-        ]
-      }
-    },
-    {
-      "exception": "Signature mismatch",
-      "arguments": {
-        "m": 1,
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ],
-        "signatures": [
-          "300602010002010001"
-        ],
-        "input": "OP_0 300602010002010101"
-      }
-    },
-    {
-      "exception": "Too many signatures provided",
-      "arguments": {
-        "m": 2,
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ],
-        "signatures": [
-          "300602010002010001",
-          "300602010002010001",
-          "300602010002010001"
-        ]
-      }
-    },
-    {
-      "description": "Missing OP_0",
-      "exception": "Input is invalid",
-      "options": {},
-      "arguments": {
-        "m": 2,
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ],
-        "input": "OP_RESERVED"
-      }
-    },
-    {
-      "exception": "Input has invalid signature\\(s\\)",
-      "arguments": {
-        "m": 1,
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ],
-        "input": "OP_0 ffffffffffffffff"
-      }
-    }
-  ],
-  "dynamic": {
-    "depends": {
-      "m": [ "output" ],
-      "n": [ "output", [ "m", "pubkeys" ] ],
-      "output": [ "output", [ "m", "pubkeys" ] ],
-      "pubkeys": [ "output" ],
-      "signatures": [ ["input", "output"] ],
-      "input": [ ["signatures", "output"] ],
-      "witness": [ ["input", "output"] ]
-    },
-    "details": [
-      {
-        "description": "p2ms",
-        "m": 2,
-        "n": 3,
-        "output": "OP_2 030000000000000000000000000000000000000000000000000000000000000001 030000000000000000000000000000000000000000000000000000000000000002 030000000000000000000000000000000000000000000000000000000000000003 OP_3 OP_CHECKMULTISIG",
-        "pubkeys": [
-          "030000000000000000000000000000000000000000000000000000000000000001",
-          "030000000000000000000000000000000000000000000000000000000000000002",
-          "030000000000000000000000000000000000000000000000000000000000000003"
-        ],
-        "signatures": [
-          "300602010002010001",
-          "300602010102010001"
-        ],
-        "input": "OP_0 300602010002010001 300602010102010001",
-        "witness": []
-      }
-    ]
-  }
-}
diff --git a/test/fixtures/p2pk.json b/test/fixtures/p2pk.json
deleted file mode 100644
index f3982d3..0000000
--- a/test/fixtures/p2pk.json
+++ /dev/null
@@ -1,160 +0,0 @@
-{
-  "valid": [
-    {
-      "description": "output from output",
-      "arguments": {
-        "output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG"
-      },
-      "options": {},
-      "expected": {
-        "name": "p2pk",
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "signature": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "output from pubkey",
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001"
-      },
-      "expected": {
-        "name": "p2pk",
-        "output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG",
-        "signature": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "input/output from output/signature",
-      "arguments": {
-        "output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG",
-        "signature": "300602010002010001"
-      },
-      "expected": {
-        "name": "p2pk",
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "input": "300602010002010001",
-        "witness": []
-      }
-    },
-    {
-      "description": "input/output from pubkey/signature",
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "signature": "300602010002010001"
-      },
-      "expected": {
-        "name": "p2pk",
-        "output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG",
-        "input": "300602010002010001",
-        "witness": []
-      }
-    },
-    {
-      "description": "input/output from input/output",
-      "arguments": {
-        "output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG",
-        "input": "300602010002010001"
-      },
-      "expected": {
-        "name": "p2pk",
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "signature": "300602010002010001",
-        "witness": []
-      }
-    }
-  ],
-  "invalid": [
-    {
-      "exception": "Not enough data",
-      "arguments": {}
-    },
-    {
-      "description": "Non-canonical signature",
-      "exception": "Expected property \"signature\" of type \\?isCanonicalScriptSignature, got Buffer",
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "signature": "3044"
-      }
-    },
-    {
-      "description": "Unexpected OP_RESERVED",
-      "exception": "Output is invalid",
-      "arguments": {
-        "output": "OP_RESERVED"
-      }
-    },
-    {
-      "description": "Non-canonical output public key",
-      "exception": "Output pubkey is invalid",
-      "arguments": {
-        "output": "ffff OP_CHECKSIG"
-      }
-    },
-    {
-      "description": "Unexpected OP_0 (at end)",
-      "exception": "Output is invalid",
-      "arguments": {
-        "output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG OP_0"
-      }
-    },
-    {
-      "exception": "Pubkey mismatch",
-      "options": {},
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "output": "030000000000000000000000000000000000000000000000000000000000000002 OP_CHECKSIG"
-      }
-    },
-    {
-      "description": "Too many chunks",
-      "exception": "Input is invalid",
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "input": "300602010002010001 OP_RESERVED"
-      }
-    },
-    {
-      "exception": "Input has invalid signature",
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "input": "ffffffffffffffff"
-      }
-    },
-    {
-      "exception": "Input has invalid signature",
-      "arguments": {
-        "input": "30060201ff0201ff01"
-      }
-    },
-    {
-      "exception": "Signature mismatch",
-      "arguments": {
-        "signature": "300602010002010001",
-        "input": "300602010302010301"
-      }
-    }
-  ],
-  "dynamic": {
-    "depends": {
-      "output":  [ "pubkey" ],
-      "pubkey": [ "output" ],
-      "signature": [ ["input", "output"] ],
-      "input": [ ["signature", "output"] ],
-      "witness": [ ["input", "output"] ]
-    },
-    "details": [
-      {
-        "description": "p2pk",
-        "output": "030000000000000000000000000000000000000000000000000000000000000001 OP_CHECKSIG",
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "signature": "300602010002010001",
-        "input": "300602010002010001",
-        "witness": []
-      }
-    ]
-  }
-}
diff --git a/test/fixtures/p2pkh.json b/test/fixtures/p2pkh.json
deleted file mode 100644
index 4efbb59..0000000
--- a/test/fixtures/p2pkh.json
+++ /dev/null
@@ -1,247 +0,0 @@
-{
-  "valid": [
-    {
-      "description": "output from address",
-      "arguments": {
-        "address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh"
-      },
-      "options": {},
-      "expected": {
-        "name": "p2pkh",
-        "hash": "168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG",
-        "signature": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "output from hash",
-      "arguments": {
-        "hash": "168b992bcfc44050310b3a94bd0771136d0b28d1"
-      },
-      "expected": {
-        "name": "p2pkh",
-        "address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
-        "output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG",
-        "signature": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "output from output",
-      "arguments": {
-        "output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG"
-      },
-      "expected": {
-        "name": "p2pkh",
-        "address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
-        "hash": "168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "signature": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "output from pubkey",
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001"
-      },
-      "expected": {
-        "name": "p2pkh",
-        "address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
-        "hash": "168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG",
-        "signature": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "input/output from pubkey/signature",
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "signature": "300602010002010001"
-      },
-      "expected": {
-        "name": "p2pkh",
-        "address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
-        "hash": "168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG",
-        "input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000001",
-        "witness": []
-      }
-    },
-    {
-      "description": "input/output from input",
-      "arguments": {
-        "input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000001"
-      },
-      "expected": {
-        "name": "p2pkh",
-        "address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
-        "hash": "168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG",
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "signature": "300602010002010001",
-        "witness": []
-      }
-    }
-  ],
-  "invalid": [
-    {
-      "exception": "Not enough data",
-      "arguments": {}
-    },
-    {
-      "exception": "Not enough data",
-      "arguments": {
-        "signature": "300602010002010001"
-      }
-    },
-    {
-      "description": "Unexpected OP_RESERVED",
-      "exception": "Output is invalid",
-      "arguments": {
-        "output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_RESERVED"
-      }
-    },
-    {
-      "description": "Unexpected OP_DUP",
-      "exception": "Output is invalid",
-      "options": {},
-      "arguments": {
-        "output": "OP_DUP OP_DUP 168b992bcfc44050310b3a94bd0771136d0b28d137 OP_EQUALVERIFY"
-      }
-    },
-    {
-      "description": "Hash too short (too many chunks)",
-      "exception": "Output is invalid",
-      "arguments": {
-        "output": "OP_DUP OP_DUP 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_TRUE OP_EQUALVERIFY"
-      }
-    },
-    {
-      "description": "Non-minimally encoded (non BIP62 compliant)",
-      "exception": "Expected property \"output\" of type Buffer\\(Length: 25\\), got Buffer\\(Length: 26\\)",
-      "arguments": {
-        "outputHex": "76a94c14aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac"
-      }
-    },
-    {
-      "exception": "Invalid version or Network mismatch",
-      "arguments": {
-        "address": "3LRW7jeCvQCRdPF8S3yUCfRAx4eqXFmdcr"
-      }
-    },
-    {
-      "exception": "Invalid address",
-      "arguments": {
-        "address": "111111111111111111117K4nzc"
-      }
-    },
-    {
-      "exception": "Invalid address",
-      "arguments": {
-        "address": "111111111111111111111111133izVn"
-      }
-    },
-    {
-      "exception": "Pubkey mismatch",
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000002"
-      }
-    },
-    {
-      "exception": "Input has invalid signature",
-      "arguments": {
-        "input": "ffffffffffffffffff 030000000000000000000000000000000000000000000000000000000000000001"
-      }
-    },
-    {
-      "exception": "Input has invalid pubkey",
-      "arguments": {
-        "input": "300602010002010001 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
-      }
-    },
-    {
-      "description": "Input has unexpected data",
-      "exception": "Input is invalid",
-      "arguments": {
-        "input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000001 ffff"
-      }
-    },
-    {
-      "description": "H(pubkey) != H",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "hash": "ffffffffffffffffffffffffffffffffffffffff"
-      }
-    },
-    {
-      "description": "address.hash != H",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
-        "hash": "ffffffffffffffffffffffffffffffffffffffff"
-      }
-    },
-    {
-      "description": "address.hash != output.hash",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
-        "output": "OP_DUP OP_HASH160 ffffffffffffffffffffffffffffffffffffffff OP_EQUALVERIFY OP_CHECKSIG"
-      }
-    },
-    {
-      "description": "output.hash != H",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG",
-        "hash": "ffffffffffffffffffffffffffffffffffffffff"
-      }
-    },
-    {
-      "description": "H(input.pubkey) != H",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "hash": "ffffffffffffffffffffffffffffffffffffffff",
-        "input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000001"
-      }
-    },
-    {
-      "exception": "Signature mismatch",
-      "arguments": {
-        "signature": "300602010002010001",
-        "input": "300602010302010301 030000000000000000000000000000000000000000000000000000000000000001"
-      }
-    }
-  ],
-  "dynamic": {
-    "depends": {
-      "address": [ "address", "output", "hash", "pubkey", "input" ],
-      "hash": [ "address", "output", "hash", "pubkey", "input" ],
-      "output": [ "address", "output", "hash", "pubkey", "input" ],
-      "pubkey": [ "input" ],
-      "signature": [ "input" ],
-      "input": [ [ "pubkey", "signature" ] ],
-      "witness": [ "input" ]
-    },
-    "details": [
-      {
-        "description": "p2pkh",
-        "address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh",
-        "hash": "168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "output": "OP_DUP OP_HASH160 168b992bcfc44050310b3a94bd0771136d0b28d1 OP_EQUALVERIFY OP_CHECKSIG",
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "signature": "300602010002010001",
-        "input": "300602010002010001 030000000000000000000000000000000000000000000000000000000000000001",
-        "witness": []
-      }
-    ]
-  }
-}
diff --git a/test/fixtures/p2sh.json b/test/fixtures/p2sh.json
deleted file mode 100644
index 8a1f9f6..0000000
--- a/test/fixtures/p2sh.json
+++ /dev/null
@@ -1,448 +0,0 @@
-{
-  "valid": [
-    {
-      "description": "p2sh-*, out (from address)",
-      "arguments": {
-        "address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT"
-      },
-      "options": {},
-      "expected": {
-        "name": "p2sh",
-        "hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086",
-        "output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL",
-        "redeem": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "p2sh-*, out (from hash)",
-      "arguments": {
-        "hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086"
-      },
-      "expected": {
-        "name": "p2sh",
-        "address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT",
-        "output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL",
-        "redeem": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "p2sh-*, out (from output)",
-      "arguments": {
-        "output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL"
-      },
-      "expected": {
-        "name": "p2sh",
-        "address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT",
-        "hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086",
-        "redeem": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "p2sh-p2pkh, out (from redeem)",
-      "arguments": {
-        "redeem": {
-          "address": "this is P2PKH context, unknown and ignored by P2SH",
-          "output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG"
-        }
-      },
-      "expected": {
-        "name": "p2sh",
-        "address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT",
-        "hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086",
-        "output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL",
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "p2sh-p2wpkh, out (from redeem)",
-      "arguments": {
-        "redeem": {
-          "hash": "this is P2WPKH context, unknown and ignored by P2SH",
-          "output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400"
-        }
-      },
-      "expected": {
-        "name": "p2sh",
-        "address": "325CuTNSYmvurXaBmhNFer5zDkKnDXZggu",
-        "hash": "0432515d8fe8de31be8207987fc6d67b29d5e7cc",
-        "output": "OP_HASH160 0432515d8fe8de31be8207987fc6d67b29d5e7cc OP_EQUAL",
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "p2sh-p2pk, out (from redeem)",
-      "arguments": {
-        "redeem": {
-          "output": "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 OP_CHECKSIG",
-          "pubkey": "this is P2WPKH context, unknown and ignored by P2SH"
-        }
-      },
-      "expected": {
-        "name": "p2sh",
-        "address": "36TibC8RrPB9WrBdPoGXhHqDHJosyFVtVQ",
-        "hash": "3454c084887afe854e80221c69d6282926f809c4",
-        "output": "OP_HASH160 3454c084887afe854e80221c69d6282926f809c4 OP_EQUAL",
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "p2sh-p2pkh, in and out (from redeem)",
-      "arguments": {
-        "redeem": {
-          "output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG",
-          "input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058"
-        }
-      },
-      "expected": {
-        "name": "p2sh",
-        "address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT",
-        "hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086",
-        "output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL",
-        "input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 76a914c30afa58ae0673b00a45b5c17dff4633780f140088ac",
-        "witness": []
-      }
-    },
-    {
-      "description": "p2sh-p2wpkh, in and out (from redeem w/ witness)",
-      "arguments": {
-        "redeem": {
-          "output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400",
-          "input": "",
-          "witness": [
-            "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-            "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058"
-          ]
-        }
-      },
-      "expected": {
-        "name": "p2sh",
-        "address": "325CuTNSYmvurXaBmhNFer5zDkKnDXZggu",
-        "hash": "0432515d8fe8de31be8207987fc6d67b29d5e7cc",
-        "output": "OP_HASH160 0432515d8fe8de31be8207987fc6d67b29d5e7cc OP_EQUAL",
-        "input": "0014c30afa58ae0673b00a45b5c17dff4633780f1400",
-        "witness": [
-          "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-          "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058"
-        ]
-      }
-    },
-    {
-      "description": "p2sh-p2pk, in and out (from input)",
-      "arguments": {
-        "input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 2103e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058ac"
-      },
-      "expected": {
-        "name": "p2sh",
-        "address": "36TibC8RrPB9WrBdPoGXhHqDHJosyFVtVQ",
-        "hash": "3454c084887afe854e80221c69d6282926f809c4",
-        "output": "OP_HASH160 3454c084887afe854e80221c69d6282926f809c4 OP_EQUAL",
-        "redeem": {
-          "output": "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 OP_CHECKSIG",
-          "input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-          "witness": []
-        },
-        "witness": []
-      }
-    },
-    {
-      "description": "p2sh-p2wpkh, in and out (from input AND witness)",
-      "arguments": {
-        "input": "0014c30afa58ae0673b00a45b5c17dff4633780f1400",
-        "witness": [
-          "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-          "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058"
-        ]
-      },
-      "expected": {
-        "name": "p2sh",
-        "address": "325CuTNSYmvurXaBmhNFer5zDkKnDXZggu",
-        "hash": "0432515d8fe8de31be8207987fc6d67b29d5e7cc",
-        "output": "OP_HASH160 0432515d8fe8de31be8207987fc6d67b29d5e7cc OP_EQUAL",
-        "redeem": {
-          "output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400",
-          "input": "",
-          "witness": [
-            "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-            "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058"
-          ]
-        }
-      }
-    },
-    {
-      "description": "p2sh-p2pkh, out (network derived from redeem)",
-      "arguments": {
-        "redeem": {
-          "address": "this is P2PKH context, unknown and ignored by P2SH",
-          "output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG",
-          "network": "testnet"
-        }
-      },
-      "expected": {
-        "name": "p2sh",
-        "address": "2N7nfc7zeWuADtpdR4MrR7Wq3dzr7LxTCgS",
-        "hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086",
-        "output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL",
-        "input": null,
-        "witness": null,
-        "network": "testnet"
-      }
-    }
-  ],
-  "invalid": [
-    {
-      "exception": "Not enough data",
-      "arguments": {}
-    },
-    {
-      "description": "Non-minimally encoded (non BIP62 compliant)",
-      "exception": "Expected property \"output\" of type Buffer\\(Length: 23\\), got Buffer\\(Length: 24\\)",
-      "arguments": {
-        "outputHex": "a94c14c286a1af0947f58d1ad787385b1c2c4a976f9e7187"
-      }
-    },
-    {
-      "description": "Expected OP_HASH160",
-      "exception": "Output is invalid",
-      "options": {},
-      "arguments": {
-        "output": "OP_HASH256 ffffffffffffffffffffffffffffffffffffffff OP_EQUAL"
-      }
-    },
-    {
-      "description": "Unexpected OP_RESERVED",
-      "exception": "Output is invalid",
-      "arguments": {
-        "output": "OP_HASH256 ffffffffffffffffffffffffffffffffffffff OP_EQUAL OP_RESERVED"
-      }
-    },
-    {
-      "description": "address.hash != H",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "address": "325CuTNSYmvurXaBmhNFer5zDkKnDXZggu",
-        "hash": "ffffffffffffffffffffffffffffffffffffffff"
-      }
-    },
-    {
-      "description": "address.hash != output.hash",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "address": "325CuTNSYmvurXaBmhNFer5zDkKnDXZggu",
-        "output": "OP_HASH160 ffffffffffffffffffffffffffffffffffffffff OP_EQUAL"
-      }
-    },
-    {
-      "description": "output.hash != H",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "hash": "ffffffffffffffffffffffffffffffffffffffff",
-        "output": "OP_HASH160 0432515d8fe8de31be8207987fc6d67b29d5e7cc OP_EQUAL"
-      }
-    },
-    {
-      "description": "H(redeem.output) != H",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "hash": "ffffffffffffffffffffffffffffffffffffffff",
-        "redeem": {
-          "output": "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 OP_CHECKSIG"
-        }
-      }
-    },
-    {
-      "exception": "Invalid version or Network mismatch",
-      "arguments": {
-        "address": "134D6gYy8DsR5m4416BnmgASuMBqKvogQh"
-      }
-    },
-    {
-      "exception": "Invalid address",
-      "arguments": {
-        "address": "TYPjCiGbKiwP6r12cdkmVjySbQr7mb3r"
-      }
-    },
-    {
-      "exception": "Invalid address",
-      "arguments": {
-        "address": "EDaBpuERpLssFzbCV1kgy8tKJsHrcwmzY7HDMF2"
-      }
-    },
-    {
-      "exception": "Input too short",
-      "arguments": {
-        "input": ""
-      }
-    },
-    {
-      "exception": "Input too short",
-      "arguments": {
-        "inputHex": "01ff02ff"
-      }
-    },
-    {
-      "exception": "Input is invalid",
-      "arguments": {
-        "input": "OP_0 OP_0"
-      }
-    },
-    {
-      "exception": "Redeem.input mismatch",
-      "arguments": {
-        "input": "OP_0 02ffff",
-        "redeem": {
-          "input": "OP_CHECKSIG",
-          "output": "ffff"
-        }
-      }
-    },
-    {
-      "exception": "Redeem.output mismatch",
-      "arguments": {
-        "input": "OP_0 02ffff",
-        "redeem": {
-          "input": "OP_0",
-          "output": "fff3"
-        }
-      }
-    },
-    {
-      "exception": "Redeem.output too short",
-      "arguments": {
-        "redeem": {
-          "input": "OP_0",
-          "output": ""
-        }
-      }
-    },
-    {
-      "exception": "Input and witness provided",
-      "arguments": {
-        "redeem": {
-          "input": "OP_0",
-          "witness": [
-            "030000000000000000000000000000000000000000000000000000000000000001"
-          ]
-        }
-      }
-    },
-    {
-      "exception": "Non push-only scriptSig",
-      "arguments": {
-        "redeem": {
-          "input": "OP_RETURN",
-          "output": "OP_1"
-        }
-      }
-    },
-    {
-      "exception": "Redeem.output too short",
-      "arguments": {
-        "inputHex": "021000"
-      }
-    },
-    {
-      "exception": "Witness and redeem.witness mismatch",
-      "arguments": {
-        "witness": [
-          "3045ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ],
-        "redeem": {
-          "witness": [
-            "3045dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
-            "030000000000000000000000000000000000000000000000000000000000000001"
-          ]
-        }
-      }
-    },
-    {
-      "exception": "Hash mismatch",
-      "arguments": {
-        "hash": "ffffffffffffffffffffffffffffffffffffffff",
-        "redeem": {
-          "input": "OP_0",
-          "output": "ffff"
-        }
-      }
-    },
-    {
-      "exception": "Network mismatch",
-      "arguments": {
-        "network": "bitcoin",
-        "redeem": {
-          "network": "testnet"
-        }
-      }
-    },
-    {
-      "exception": "Network mismatch",
-      "arguments": {
-        "network": "testnet",
-        "redeem": {
-          "network": "bitcoin"
-        }
-      }
-    },
-    {
-      "exception": "Empty input",
-      "arguments": {
-        "inputHex": "01ff"
-      }
-    }
-  ],
-  "dynamic": {
-    "depends": {
-      "address": [ "address", "output", "hash", "redeem.output", [ "input", "witness" ] ],
-      "hash": [ "address", "output", "hash", "redeem.output", [ "input", "witness" ] ],
-      "output":  [ "address", "output", "hash", "redeem.output", [ "input", "witness" ] ],
-      "redeem.output": [ [ "input", "witness" ] ],
-      "redeem.input": [ [ "input", "witness" ] ],
-      "redeem.witness": [ [ "input", "witness" ] ],
-      "input": [ "redeem" ],
-      "witness": [ "redeem" ]
-    },
-    "details": [
-      {
-        "description": "p2sh-p2pkh",
-        "address": "3GETYP4cuSesh2zsPEEYVZqnRedwe4FwUT",
-        "hash": "9f840a5fc02407ef0ad499c2ec0eb0b942fb0086",
-        "output": "OP_HASH160 9f840a5fc02407ef0ad499c2ec0eb0b942fb0086 OP_EQUAL",
-        "redeem": {
-          "output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG",
-          "input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058",
-          "witness": []
-        },
-        "input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 76a914c30afa58ae0673b00a45b5c17dff4633780f140088ac",
-        "witness": []
-      },
-      {
-        "description": "p2sh-p2wpkh",
-        "address": "325CuTNSYmvurXaBmhNFer5zDkKnDXZggu",
-        "hash": "0432515d8fe8de31be8207987fc6d67b29d5e7cc",
-        "output": "OP_HASH160 0432515d8fe8de31be8207987fc6d67b29d5e7cc OP_EQUAL",
-        "redeem": {
-          "output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400",
-          "input": "",
-          "witness": [
-            "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-            "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058"
-          ]
-        },
-        "input": "0014c30afa58ae0673b00a45b5c17dff4633780f1400",
-        "witness": [
-          "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-          "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058"
-        ]
-      }
-    ]
-  }
-}
diff --git a/test/fixtures/p2wpkh.json b/test/fixtures/p2wpkh.json
deleted file mode 100644
index ad0d595..0000000
--- a/test/fixtures/p2wpkh.json
+++ /dev/null
@@ -1,261 +0,0 @@
-{
-  "valid": [
-    {
-      "description": "output from address",
-      "arguments": {
-        "address": "bc1qafk4yhqvj4wep57m62dgrmutldusqde8adh20d"
-      },
-      "options": {},
-      "expected": {
-        "name": "p2wpkh",
-        "hash": "ea6d525c0c955d90d3dbd29a81ef8bfb79003727",
-        "output": "OP_0 ea6d525c0c955d90d3dbd29a81ef8bfb79003727",
-        "signature": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "output from hash",
-      "arguments": {
-        "hash": "ea6d525c0c955d90d3dbd29a81ef8bfb79003727"
-      },
-      "expected": {
-        "name": "p2wpkh",
-        "address": "bc1qafk4yhqvj4wep57m62dgrmutldusqde8adh20d",
-        "output": "OP_0 ea6d525c0c955d90d3dbd29a81ef8bfb79003727",
-        "signature": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "output from output",
-      "arguments": {
-        "output": "OP_0 ea6d525c0c955d90d3dbd29a81ef8bfb79003727"
-      },
-      "expected": {
-        "name": "p2wpkh",
-        "address": "bc1qafk4yhqvj4wep57m62dgrmutldusqde8adh20d",
-        "hash": "ea6d525c0c955d90d3dbd29a81ef8bfb79003727",
-        "signature": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "output from pubkey",
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001"
-      },
-      "expected": {
-        "name": "p2wpkh",
-        "address": "bc1qz69ej270c3q9qvgt822t6pm3zdksk2x35j2jlm",
-        "hash": "168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "output": "OP_0 168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "signature": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "witness/output from pubkey/signature",
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "signature": "300602010002010001"
-      },
-      "expected": {
-        "name": "p2wpkh",
-        "address": "bc1qz69ej270c3q9qvgt822t6pm3zdksk2x35j2jlm",
-        "hash": "168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "output": "OP_0 168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "input": "",
-        "witness": [
-          "300602010002010001",
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ]
-      }
-    },
-    {
-      "description": "witness/output from witness",
-      "arguments": {
-        "witness": [
-          "300602010002010001",
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ]
-      },
-      "expected": {
-        "name": "p2wpkh",
-        "address": "bc1qz69ej270c3q9qvgt822t6pm3zdksk2x35j2jlm",
-        "hash": "168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "output": "OP_0 168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "signature": "300602010002010001",
-        "input": ""
-      }
-    }
-  ],
-  "invalid": [
-    {
-      "exception": "Not enough data",
-      "arguments": {}
-    },
-    {
-      "exception": "Not enough data",
-      "arguments": {
-        "signature": "300602010002010001"
-      }
-    },
-    {
-      "exception": "Output is invalid",
-      "description": "Unexpected OP",
-      "arguments": {
-        "output": "OP_RESERVED ea6d525c0c955d90d3dbd29a81ef8bfb79003727"
-      }
-    },
-    {
-      "exception": "Invalid pubkey for p2wpkh",
-      "description": "Uncompressed pubkey in pubkey",
-      "arguments": {
-        "pubkey": "049fa211b0fca342589ca381cc96520c3d0e3924832158d9f29891936cac091e80687acdca51868ee1f89a3bb36bb16f186262938e1f94c1e7692924935b9b1457"
-      }
-    },
-    {
-      "exception": "Witness has invalid pubkey",
-      "description": "Uncompressed pubkey in witness",
-      "arguments": {
-        "witness": [
-          "300602010002010001",
-          "049fa211b0fca342589ca381cc96520c3d0e3924832158d9f29891936cac091e80687acdca51868ee1f89a3bb36bb16f186262938e1f94c1e7692924935b9b1457"
-        ]
-      }
-    },
-    {
-      "exception": "Pubkey mismatch",
-      "options": {},
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "witness": [
-          "300602010002010001",
-          "030000000000000000000000000000000000000000000000000000000000000002"
-        ]
-      }
-    },
-    {
-      "exception": "Signature mismatch",
-      "arguments": {
-        "signature": "300602010002010002",
-        "witness": [
-          "300602010002010001",
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ]
-      }
-    },
-    {
-      "exception": "Invalid prefix or Network mismatch",
-      "arguments": {
-        "address": "foo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqs30dvv"
-      }
-    },
-    {
-      "exception": "Invalid address version",
-      "arguments": {
-        "address": "bc1pqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq5us4ke"
-      }
-    },
-    {
-      "exception": "Invalid address data",
-      "arguments": {
-        "address": "bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8"
-      }
-    },
-    {
-      "exception": "Hash mismatch",
-      "arguments": {
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "hash": "ffffffffffffffffffffffffffffffffffffffff"
-      }
-    },
-    {
-      "exception": "Hash mismatch",
-      "arguments": {
-        "address": "bc1qafk4yhqvj4wep57m62dgrmutldusqde8adh20d",
-        "hash": "ffffffffffffffffffffffffffffffffffffffff"
-      }
-    },
-    {
-      "exception": "Hash mismatch",
-      "arguments": {
-        "output": "OP_0 ea6d525c0c955d90d3dbd29a81ef8bfb79003727",
-        "hash": "ffffffffffffffffffffffffffffffffffffffff"
-      }
-    },
-    {
-      "exception": "Hash mismatch",
-      "arguments": {
-        "hash": "ffffffffffffffffffffffffffffffffffffffff",
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001"
-      }
-    },
-    {
-      "exception": "Hash mismatch",
-      "arguments": {
-        "hash": "ffffffffffffffffffffffffffffffffffffffff",
-        "witness": [
-          "300602010002010001",
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ]
-      }
-    },
-    {
-      "exception": "Witness is invalid",
-      "arguments": {
-        "witness": []
-      }
-    },
-    {
-      "exception": "Witness has invalid signature",
-      "arguments": {
-        "witness": [
-          "ffffffffffffffffff",
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ]
-      }
-    },
-    {
-      "exception": "Witness has invalid pubkey",
-      "arguments": {
-        "witness": [
-          "300602010002010001",
-          "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
-        ]
-      }
-    }
-  ],
-  "dynamic": {
-    "depends": {
-      "address": [ "address", "output", "hash", "pubkey", "witness" ],
-      "hash": [ "address", "output", "hash", "pubkey", "witness" ],
-      "output": [ "address", "output", "hash", "pubkey", "witness" ],
-      "pubkey": [ "witness" ],
-      "signature": [ "witness" ],
-      "input": [ "witness" ],
-      "witness": [ [ "pubkey", "signature" ] ]
-    },
-    "details": [
-      {
-        "description": "p2wpkh",
-        "address": "bc1qz69ej270c3q9qvgt822t6pm3zdksk2x35j2jlm",
-        "hash": "168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "output": "OP_0 168b992bcfc44050310b3a94bd0771136d0b28d1",
-        "pubkey": "030000000000000000000000000000000000000000000000000000000000000001",
-        "signature": "300602010002010001",
-        "input": "",
-        "witness": [
-          "300602010002010001",
-          "030000000000000000000000000000000000000000000000000000000000000001"
-        ]
-      }
-    ]
-  }
-}
diff --git a/test/fixtures/p2wsh.json b/test/fixtures/p2wsh.json
deleted file mode 100644
index 03fb01d..0000000
--- a/test/fixtures/p2wsh.json
+++ /dev/null
@@ -1,443 +0,0 @@
-{
-  "valid": [
-    {
-      "description": "p2wsh-*, out (from address)",
-      "arguments": {
-        "address": "bc1q6rgl33d3s9dugudw7n68yrryajkr3ha9q8q24j20zs62se4q9tsqdy0t2q"
-      },
-      "options": {},
-      "expected": {
-        "name": "p2wsh",
-        "hash": "d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0",
-        "output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0",
-        "redeem": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "p2wsh-*, out (from hash)",
-      "arguments": {
-        "hash": "d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0"
-      },
-      "expected": {
-        "name": "p2wsh",
-        "address": "bc1q6rgl33d3s9dugudw7n68yrryajkr3ha9q8q24j20zs62se4q9tsqdy0t2q",
-        "output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0",
-        "redeem": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "p2wsh-*, out (from output)",
-      "arguments": {
-        "output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0"
-      },
-      "expected": {
-        "name": "p2wsh",
-        "address": "bc1q6rgl33d3s9dugudw7n68yrryajkr3ha9q8q24j20zs62se4q9tsqdy0t2q",
-        "hash": "d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0",
-        "redeem": null,
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "p2wsh-p2pkh, out (from redeem)",
-      "arguments": {
-        "redeem": {
-          "address": "this is P2PKH context, unknown and ignored by p2wsh",
-          "output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG"
-        }
-      },
-      "expected": {
-        "name": "p2wsh",
-        "address": "bc1qusxlgq9quu27ucxs7a2fg8nv0pycdzvxsjk9npyupupxw3y892ss2cq5ar",
-        "hash": "e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1",
-        "output": "OP_0 e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1",
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "p2wsh-p2wpkh, out (from redeem)",
-      "arguments": {
-        "redeem": {
-          "hash": "this is P2WPKH context, unknown and ignored by p2wsh",
-          "output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400"
-        }
-      },
-      "expected": {
-        "name": "p2wsh",
-        "address": "bc1qpsl7el8wcx22f3fpdt3lm2wmzug7yyx2q3n8wzgtf37kps9tqy7skc7m3e",
-        "hash": "0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d",
-        "output": "OP_0 0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d",
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "p2wsh-p2pk, out (from redeem)",
-      "arguments": {
-        "redeem": {
-          "output": "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 OP_CHECKSIG",
-          "pubkey": "this is P2WPKH context, unknown and ignored by p2wsh"
-        }
-      },
-      "expected": {
-        "name": "p2wsh",
-        "address": "bc1q6rgl33d3s9dugudw7n68yrryajkr3ha9q8q24j20zs62se4q9tsqdy0t2q",
-        "hash": "d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0",
-        "output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0",
-        "input": null,
-        "witness": null
-      }
-    },
-    {
-      "description": "p2wsh-p2pkh, in and out (from redeem, transformed to witness)",
-      "arguments": {
-        "redeem": {
-          "output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG",
-          "input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058"
-        }
-      },
-      "expected": {
-        "name": "p2wsh",
-        "address": "bc1qusxlgq9quu27ucxs7a2fg8nv0pycdzvxsjk9npyupupxw3y892ss2cq5ar",
-        "hash": "e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1",
-        "output": "OP_0 e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1",
-        "redeem": {
-          "input": ""
-        },
-        "input": "",
-        "witness": [
-          "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-          "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058",
-          "76a914c30afa58ae0673b00a45b5c17dff4633780f140088ac"
-        ]
-      }
-    },
-    {
-      "description": "p2wsh-p2wpkh, in and out (from redeem w/ witness)",
-      "arguments": {
-        "redeem": {
-          "output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400",
-          "input": "",
-          "witness": [
-            "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-            "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058"
-          ]
-        }
-      },
-      "expected": {
-        "name": "p2wsh",
-        "address": "bc1qpsl7el8wcx22f3fpdt3lm2wmzug7yyx2q3n8wzgtf37kps9tqy7skc7m3e",
-        "hash": "0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d",
-        "output": "OP_0 0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d",
-        "input": "",
-        "witness": [
-          "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-          "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058",
-          "0014c30afa58ae0673b00a45b5c17dff4633780f1400"
-        ]
-      }
-    },
-    {
-      "description": "p2wsh-p2pk, in and out (from witness)",
-      "arguments": {
-        "witness": [
-          "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-          "2103e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058ac"
-        ]
-      },
-      "expected": {
-        "name": "p2wsh",
-        "address": "bc1q6rgl33d3s9dugudw7n68yrryajkr3ha9q8q24j20zs62se4q9tsqdy0t2q",
-        "hash": "d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0",
-        "output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0",
-        "redeem": {
-          "output": "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 OP_CHECKSIG",
-          "input": "",
-          "witness": [
-            "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501"
-          ]
-        },
-        "input": ""
-      }
-    },
-    {
-      "description": "p2wsh-p2wpkh, in and out (from witness)",
-      "arguments": {
-        "witness": [
-          "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-          "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058",
-          "0014c30afa58ae0673b00a45b5c17dff4633780f1400"
-        ]
-      },
-      "expected": {
-        "name": "p2wsh",
-        "address": "bc1qpsl7el8wcx22f3fpdt3lm2wmzug7yyx2q3n8wzgtf37kps9tqy7skc7m3e",
-        "hash": "0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d",
-        "output": "OP_0 0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d",
-        "redeem": {
-          "output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400",
-          "input": "",
-          "witness": [
-            "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-            "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058"
-          ]
-        }
-      }
-    },
-    {
-      "description": "p2wsh-p2pkh, out (network derived from redeem)",
-      "arguments": {
-        "redeem": {
-          "address": "this is P2PKH context, unknown and ignored by p2wsh",
-          "output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG",
-          "network": "testnet"
-        }
-      },
-      "expected": {
-        "name": "p2wsh",
-        "address": "tb1qusxlgq9quu27ucxs7a2fg8nv0pycdzvxsjk9npyupupxw3y892ssaskm8v",
-        "hash": "e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1",
-        "output": "OP_0 e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1",
-        "input": null,
-        "witness": null,
-        "network": "testnet"
-      }
-    }
-  ],
-  "invalid": [
-    {
-      "exception": "Not enough data",
-      "arguments": {}
-    },
-    {
-      "description": "address.hash != H",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "address": "bc1qpsl7el8wcx22f3fpdt3lm2wmzug7yyx2q3n8wzgtf37kps9tqy7skc7m3e",
-        "hash": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
-      }
-    },
-    {
-      "description": "address.hash != output.hash",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "address": "bc1qpsl7el8wcx22f3fpdt3lm2wmzug7yyx2q3n8wzgtf37kps9tqy7skc7m3e",
-        "output": "OP_0 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
-      }
-    },
-    {
-      "description": "output.hash != H",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "hash": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-        "output": "OP_0 d0d1f8c5b1815bc471aef4f4720c64ecac38dfa501c0aac94f1434a866a02ae0"
-      }
-    },
-    {
-      "description": "H(redeem.output) != H",
-      "exception": "Hash mismatch",
-      "arguments": {
-        "hash": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-        "redeem": {
-          "output": "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058 OP_CHECKSIG"
-        }
-      }
-    },
-    {
-      "exception": "Output is invalid",
-      "options": {},
-      "arguments": {
-        "output": "OP_HASH256 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff OP_EQUAL"
-      }
-    },
-    {
-      "exception": "Redeem.output is invalid",
-      "arguments": {
-        "redeem": {
-          "output": ""
-        }
-      }
-    },
-    {
-      "exception": "Non push-only scriptSig",
-      "arguments": {
-        "redeem": {
-          "output": "OP_TRUE",
-          "input": "OP_HASH256"
-        }
-      }
-    },
-    {
-      "exception": "Witness and redeem.output mismatch",
-      "arguments": {
-        "redeem": {
-          "output": "OP_TRUE",
-          "input": "OP_0"
-        },
-        "witness": [
-          "02ffff"
-        ]
-      }
-    },
-    {
-      "exception": "Witness and redeem.witness mismatch",
-      "arguments": {
-        "redeem": {
-          "output": "OP_TRUE",
-          "witness": [
-            "01"
-          ]
-        },
-        "witness": [
-          "00",
-          "02ffff"
-        ]
-      }
-    },
-    {
-      "exception": "Witness and redeem.witness mismatch",
-      "arguments": {
-        "redeem": {
-          "output": "OP_TRUE",
-          "witness": [
-            "04000000ff"
-          ]
-        },
-        "witness": [
-          "04000000ee"
-        ]
-      }
-    },
-    {
-      "exception": "Ambiguous witness source",
-      "arguments": {
-        "redeem": {
-          "output": "OP_TRUE",
-          "input": "01",
-          "witness": [
-            "01"
-          ]
-        }
-      }
-    },
-    {
-      "exception": "Network mismatch",
-      "arguments": {
-        "network": "bitcoin",
-        "redeem": {
-          "network": "testnet"
-        }
-      }
-    },
-    {
-      "exception": "Network mismatch",
-      "arguments": {
-        "network": "testnet",
-        "redeem": {
-          "network": "bitcoin"
-        }
-      }
-    },
-    {
-      "exception": "redeem.input or redeem.output contains uncompressed pubkey",
-      "arguments": {
-        "redeem": {
-          "output": "049fa211b0fca342589ca381cc96520c3d0e3924832158d9f29891936cac091e80687acdca51868ee1f89a3bb36bb16f186262938e1f94c1e7692924935b9b1457 OP_CHECKSIG"
-        }
-      }
-    },
-    {
-      "exception": "redeem.input or redeem.output contains uncompressed pubkey",
-      "arguments": {
-        "redeem": {
-          "input": "049fa211b0fca342589ca381cc96520c3d0e3924832158d9f29891936cac091e80687acdca51868ee1f89a3bb36bb16f186262938e1f94c1e7692924935b9b1457"
-        }
-      }
-    },
-    {
-      "exception": "Witness contains uncompressed pubkey",
-      "arguments": {
-        "witness": [
-          "049fa211b0fca342589ca381cc96520c3d0e3924832158d9f29891936cac091e80687acdca51868ee1f89a3bb36bb16f186262938e1f94c1e7692924935b9b1457"
-        ]
-      }
-    },
-    {
-      "exception": "Invalid prefix or Network mismatch",
-      "arguments": {
-        "address": "foo1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqs30dvv"
-      }
-    },
-    {
-      "exception": "Invalid address version",
-      "arguments": {
-        "address": "bc1pqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq5us4ke"
-      }
-    },
-    {
-      "exception": "Invalid address data",
-      "arguments": {
-        "address": "bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8"
-      }
-    }
-  ],
-  "dynamic": {
-    "depends": {
-      "address": [ "address", "output", "hash", "redeem.output", "witness" ],
-      "hash": [ "address", "output", "hash", "redeem.output", "witness" ],
-      "output":  [ "address", "output", "hash", "redeem.output", "witness" ],
-      "redeem.output": [ "witness" ],
-      "redeem.input": [ [ "input", "witness" ], "witness" ],
-      "input": [ "witness" ],
-      "witness": [ "redeem" ]
-    },
-    "details": [
-      {
-        "description": "p2wsh-p2pkh",
-        "disabled": [
-          "redeem.input"
-        ],
-        "address": "bc1qusxlgq9quu27ucxs7a2fg8nv0pycdzvxsjk9npyupupxw3y892ss2cq5ar",
-        "hash": "e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1",
-        "output": "OP_0 e40df400a0e715ee60d0f754941e6c784986898684ac59849c0f026744872aa1",
-        "redeem": {
-          "output": "OP_DUP OP_HASH160 c30afa58ae0673b00a45b5c17dff4633780f1400 OP_EQUALVERIFY OP_CHECKSIG",
-          "input": "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501 03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058",
-          "witness": null
-        },
-        "input": "",
-        "witness": [
-          "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-          "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058",
-          "76a914c30afa58ae0673b00a45b5c17dff4633780f140088ac"
-        ]
-      },
-      {
-        "description": "p2wsh-p2wpkh",
-        "address": "bc1qpsl7el8wcx22f3fpdt3lm2wmzug7yyx2q3n8wzgtf37kps9tqy7skc7m3e",
-        "hash": "0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d",
-        "output": "OP_0 0c3fecfceec194a4c5216ae3fda9db1711e210ca046677090b4c7d60c0ab013d",
-        "redeem": {
-          "output": "OP_0 c30afa58ae0673b00a45b5c17dff4633780f1400",
-          "input": "",
-          "witness": [
-            "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-            "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058"
-          ]
-        },
-        "input": "",
-        "witness": [
-          "3045022100e4fce9ec72b609a2df1dc050c20dcf101d27faefb3e686b7a4cb067becdd5e8e022071287fced53806b08cf39b5ad58bbe614775b3776e98a9f8760af0d4d1d47a9501",
-          "03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058",
-          "0014c30afa58ae0673b00a45b5c17dff4633780f1400"
-        ]
-      }
-    ]
-  }
-}
diff --git a/test/fixtures/psbt.json b/test/fixtures/psbt.json
deleted file mode 100644
index 0e51d57..0000000
--- a/test/fixtures/psbt.json
+++ /dev/null
@@ -1,568 +0,0 @@
-{
-  "bip174": {
-    "invalid": [
-      {
-        "description": "Network transaction, not PSBT format",
-        "errorMessage": "Format Error: Invalid Magic Number",
-        "psbt": "AgAAAAEmgXE3Ht/yhek3re6ks3t4AAwFZsuzrWRkFxPKQhcb9gAAAABqRzBEAiBwsiRRI+a/R01gxbUMBD1MaRpdJDXwmjSnZiqdwlF5CgIgATKcqdrPKAvfMHQOwDkEIkIsgctFg5RXrrdvwS7dlbMBIQJlfRGNM1e44PTCzUbbezn22cONmnCry5st5dyNv+TOMf7///8C09/1BQAAAAAZdqkU0MWZA8W6woaHYOkP1SGkZlqnZSCIrADh9QUAAAAAF6kUNUXm4zuDLEcFDyTT7rk8nAOUi8eHsy4TAA=="
-      },
-      {
-        "description": "PSBT missing outputs",
-        "errorMessage": "Format Error: Unexpected End of PSBT",
-        "psbt": "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA=="
-      },
-      {
-        "description": "PSBT where one input has a filled scriptSig in the unsigned tx",
-        "errorMessage": "Format Error: Transaction ScriptSigs are not empty",
-        "psbt": "cHNidP8BAP0KAQIAAAACqwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QAAAAAakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpL+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAABASAA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHhwEEFgAUhdE1N/LiZUBaNNuvqePdoB+4IwgAAAA="
-      },
-      {
-        "description": "PSBT where inputs and outputs are provided but without an unsigned tx",
-        "errorMessage": "Format Error: Only one UNSIGNED_TX allowed",
-        "psbt": "cHNidP8AAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA=="
-      },
-      {
-        "description": "PSBT with duplicate keys in an input",
-        "errorMessage": "Format Error: Keys must be unique for each input: input index 0 key 00",
-        "psbt": "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQA/AgAAAAH//////////////////////////////////////////wAAAAAA/////wEAAAAAAAAAAANqAQAAAAAAAAAA"
-      },
-      {
-        "description": "PSBT With invalid global transaction typed key",
-        "errorMessage": "Format Error: Invalid global key: 0001",
-        "psbt": "cHNidP8CAAFVAgAAAAEnmiMjpd+1H8RfIg+liw/BPh4zQnkqhdfjbNYzO1y8OQAAAAAA/////wGgWuoLAAAAABl2qRT/6cAGEJfMO2NvLLBGD6T8Qn0rRYisAAAAAAABASCVXuoLAAAAABepFGNFIA9o0YnhrcDfHE0W6o8UwNvrhyICA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GRjBDAiAEJLWO/6qmlOFVnqXJO7/UqJBkIkBVzfBwtncUaUQtBwIfXI6w/qZRbWC4rLM61k7eYOh4W/s6qUuZvfhhUduamgEBBCIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA"
-      },
-      {
-        "description": "PSBT With invalid input witness utxo typed key",
-        "errorMessage": "Format Error: Invalid input key: 0100",
-        "psbt": "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAIBACCVXuoLAAAAABepFGNFIA9o0YnhrcDfHE0W6o8UwNvrhyICA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GRjBDAiAEJLWO/6qmlOFVnqXJO7/UqJBkIkBVzfBwtncUaUQtBwIfXI6w/qZRbWC4rLM61k7eYOh4W/s6qUuZvfhhUduamgEBBCIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA"
-      },
-      {
-        "description": "PSBT With invalid pubkey length for input partial signature typed key",
-        "errorMessage": "Format Error: invalid pubkey in key 0x0203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd",
-        "psbt": "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIQIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYwQwIgBCS1jv+qppThVZ6lyTu/1KiQZCJAVc3wcLZ3FGlELQcCH1yOsP6mUW1guKyzOtZO3mDoeFv7OqlLmb34YVHbmpoBAQQiACB3H9GK1FlmbdSfPVZOPbxC9MhHdONgraFoFqjtSI1WgQEFR1IhA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GIQPeVdHh2sgF4/iljB+/m5TALz26r+En/vykmV8m+CCDvVKuIgYDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYQtKa6ZwAAAIAAAACABAAAgCIGA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9ELSmumcAAACAAAAAgAUAAIAAAA=="
-      },
-      {
-        "description": "PSBT With invalid redeemscript typed key",
-        "errorMessage": "Format Error: Invalid input key: 0400",
-        "psbt": "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQIEACIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA"
-      },
-      {
-        "description": "PSBT With invalid witnessscript typed key",
-        "errorMessage": "Format Error: Invalid input key: 0500",
-        "psbt": "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoECBQBHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA"
-      },
-      {
-        "description": "PSBT With invalid bip32 typed key",
-        "errorMessage": "Format Error: invalid pubkey in key 0x0603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd",
-        "psbt": "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoEBBUdSIQOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RiED3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg71SriEGA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb0QtKa6ZwAAAIAAAACABAAAgCIGA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9ELSmumcAAACAAAAAgAUAAIAAAA=="
-      },
-      {
-        "description": "PSBT With invalid non-witness utxo typed key",
-        "errorMessage": "Format Error: Invalid input key: 0000",
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAIAALsCAAAAAarXOTEBi9JfhK5AC2iEi+CdtwbqwqwYKYur7nGrZW+LAAAAAEhHMEQCIFj2/HxqM+GzFUjUgcgmwBW9MBNarULNZ3kNq2bSrSQ7AiBKHO0mBMZzW2OT5bQWkd14sA8MWUL7n3UYVvqpOBV9ugH+////AoDw+gIAAAAAF6kUD7lGNCFpa4LIM68kHHjBfdveSTSH0PIKJwEAAAAXqRQpynT4oI+BmZQoGFyXtdhS5AY/YYdlAAAAAQfaAEcwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAUgwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gFHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4AAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IcBByMiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEI2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
-      },
-      {
-        "description": "PSBT With invalid final scriptsig typed key",
-        "errorMessage": "Format Error: Invalid input key: 0700",
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAACBwDaAEcwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAUgwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gFHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4AAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IcBByMiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEI2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
-      },
-      {
-        "description": "PSBT With invalid final script witness typed key",
-        "errorMessage": "Format Error: Invalid input key: 0800",
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAggA2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
-      },
-      {
-        "description": "PSBT With invalid pubkey in output BIP 32 derivation paths typed key",
-        "errorMessage": "Format Error: invalid pubkey in key 0x0203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca587",
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIQIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1PtnuylhxDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA"
-      },
-      {
-        "description": "PSBT With invalid input sighash type typed key",
-        "errorMessage": "Format Error: Invalid input key: 0300",
-        "psbt": "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wCAwABAAAAAAEAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A"
-      },
-      {
-        "description": "PSBT With invalid output redeemScript typed key",
-        "errorMessage": "Format Error: Invalid output key: 0000",
-        "psbt": "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAgAAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A"
-      },
-      {
-        "description": "PSBT With invalid output witnessScript typed key",
-        "errorMessage": "Format Error: Unexpected End of PSBT",
-        "psbt": "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A"
-      }
-    ],
-    "valid": [
-      {
-        "description": "PSBT with one P2PKH input. Outputs are empty",
-        "psbt": "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA"
-      },
-      {
-        "description": "PSBT with one P2PKH input and one P2SH-P2WPKH input. First input is signed and finalized. Outputs are empty",
-        "psbt": "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEHakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpIAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIAAAA"
-      },
-      {
-        "description": "PSBT with one P2PKH input which has a non-final scriptSig and has a sighash type specified. Outputs are empty",
-        "psbt": "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQMEAQAAAAAAAA=="
-      },
-      {
-        "description": "PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled.",
-        "psbt": "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="
-      },
-      {
-        "description": "PSBT with one P2SH-P2WSH input of a 2-of-2 multisig, redeemScript, witnessScript, and keypaths are available. Contains one signature.",
-        "psbt": "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoEBBUdSIQOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RiED3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg71SriIGA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GELSmumcAAACAAAAAgAQAAIAiBgPeVdHh2sgF4/iljB+/m5TALz26r+En/vykmV8m+CCDvRC0prpnAAAAgAAAAIAFAACAAAA="
-      },
-      {
-        "description": "PSBT with unknown types in the inputs.",
-        "psbt": "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAA="
-      }
-    ],
-    "failSignChecks": [
-      {
-        "description": "A Witness UTXO is provided for a non-witness input",
-        "errorMessage": "Input #0 has witnessUtxo but non-segwit script",
-        "psbt": "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEBItPf9QUAAAAAGXapFNSO0xELlAFMsRS9Mtb00GbcdCVriKwAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=",
-        "inputToCheck": 0
-      },
-      {
-        "description": "redeemScript with non-witness UTXO does not match the scriptPubKey",
-        "errorMessage": "Redeem script for input #0 doesn't match the scriptPubKey in the prevout",
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq8iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
-        "inputToCheck": 0
-      },
-      {
-        "description": "redeemScript with witness UTXO does not match the scriptPubKey",
-        "errorMessage": "Redeem script for input #1 doesn't match the scriptPubKey in the prevout",
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQABBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
-        "inputToCheck": 1
-      },
-      {
-        "description": "witnessScript with witness UTXO does not match the redeemScript",
-        "errorMessage": "Witness script for input #1 doesn't match the scriptPubKey in the prevout",
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSrSIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA=",
-        "inputToCheck": 1
-      }
-    ],
-    "creator": [
-      {
-        "inputs": [
-          {
-            "hash": "75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858",
-            "index": 0
-          },
-          {
-            "hash": "1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83",
-            "index": 1
-          }
-        ],
-        "outputs": [
-          {
-            "script": "0014d85c2b71d0060b09c9886aeb815e50991dda124d",
-            "value": 149990000
-          },
-          {
-            "script": "001400aea9a2e5f0f876a588df5546e8742d1d87008f",
-            "value": 100000000
-          }
-        ],
-        "result": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAAAAAA="
-      }
-    ],
-    "updater": [
-      {
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAAAAAA=",
-        "inputData": [
-          {
-            "nonWitnessUtxo": "Buffer.from('0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000', 'hex')",
-            "redeemScript": "Buffer.from('5221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae', 'hex')",
-            "bip32Derivation": [
-              {
-                "masterFingerprint": "Buffer.from('d90c6a4f', 'hex')",
-                "pubkey": "Buffer.from('029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f', 'hex')",
-                "path": "m/0'/0'/0'"
-              },
-              {
-                "masterFingerprint": "Buffer.from('d90c6a4f', 'hex')",
-                "pubkey": "Buffer.from('02dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7', 'hex')",
-                "path": "m/0'/0'/1'"
-              }
-            ]
-          },
-          {
-            "witnessUtxo": {
-              "script": "Buffer.from('a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887', 'hex')",
-              "value": 200000000
-            },
-            "redeemScript": "Buffer.from('00208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903', 'hex')",
-            "witnessScript": "Buffer.from('522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae', 'hex')",
-            "bip32Derivation": [
-              {
-                "masterFingerprint": "Buffer.from('d90c6a4f', 'hex')",
-                "pubkey": "Buffer.from('023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73', 'hex')",
-                "path": "m/0'/0'/3'"
-              },
-              {
-                "masterFingerprint": "Buffer.from('d90c6a4f', 'hex')",
-                "pubkey": "Buffer.from('03089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc', 'hex')",
-                "path": "m/0'/0'/2'"
-              }
-            ]
-          }
-        ],
-        "outputData": [
-          {
-            "bip32Derivation": [
-              {
-                "masterFingerprint": "Buffer.from('d90c6a4f', 'hex')",
-                "pubkey": "Buffer.from('03a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca58771', 'hex')",
-                "path": "m/0'/0'/4'"
-              }
-            ]
-          },
-          {
-            "bip32Derivation": [
-              {
-                "masterFingerprint": "Buffer.from('d90c6a4f', 'hex')",
-                "pubkey": "Buffer.from('027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b50051096', 'hex')",
-                "path": "m/0'/0'/5'"
-              }
-            ]
-          }
-        ],
-        "result": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
-      },
-      {
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==",
-        "inputData": [
-          {
-            "sighashType": 1
-          },
-          {
-            "sighashType": 1
-          }
-        ],
-        "result": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA"
-      }
-    ],
-    "signer": [
-      {
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
-        "keys": [
-          {
-            "inputToSign": 0,
-            "WIF": "cP53pDbR5WtAD8dYAW9hhTjuvvTVaEiQBdrz9XPrgLBeRFiyCbQr"
-          },
-          {
-            "inputToSign": 1,
-            "WIF": "cR6SXDoyfQrcp4piaiHE97Rsgta9mNhGTen9XeonVgwsh4iSgw6d"
-          }
-        ],
-        "result": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
-      },
-      {
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
-        "keys": [
-          {
-            "inputToSign": 0,
-            "WIF": "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au"
-          },
-          {
-            "inputToSign": 1,
-            "WIF": "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE"
-          }
-        ],
-        "result": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
-      }
-    ],
-    "combiner": [
-      {
-        "psbts": [
-          "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEBAwQBAAAAAQQiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEFR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuIgYCOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnMQ2QxqTwAAAIAAAACAAwAAgCIGAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcENkMak8AAACAAAAAgAIAAIAAIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==",
-          "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU210gwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gEBAwQBAAAAAQRHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4iBgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfxDZDGpPAAAAgAAAAIAAAACAIgYC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtcQ2QxqTwAAAIAAAACAAQAAgAABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohyICAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBAQMEAQAAAAEEIgAgjCNTFzdDtZXftKB7crqOQuN5fadOh/59nXSX47ICiQMBBUdSIQMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3CECOt2QTz1tz1nduQaw3uI1Kbf/ue1Q5ehhUZJoYCIfDnNSriIGAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zENkMak8AAACAAAAAgAMAAIAiBgMIncEMesbbVPkTKa9hczPbOIzq0MIx9yM3nRuZAwsC3BDZDGpPAAAAgAAAAIACAACAACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="
-        ],
-        "result": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEiAgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc0cwRAIgZfRbpZmLWaJ//hp77QFq8fH5DVSzqo90UKpfVqJRA70CIH9yRwOtHtuWaAsoS1bU/8uI9/t1nqu+CKow8puFE4PSAQEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA"
-      },
-      {
-        "psbts": [
-          "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAKDwECAwQFBgcICQ8BAgMEBQYHCAkKCwwNDg8ACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAoPAQIDBAUGBwgJDwECAwQFBgcICQoLDA0ODwA=",
-          "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAKDwECAwQFBgcIEA8BAgMEBQYHCAkKCwwNDg8ACg8BAgMEBQYHCBAPAQIDBAUGBwgJCgsMDQ4PAAoPAQIDBAUGBwgQDwECAwQFBgcICQoLDA0ODwA="
-        ],
-        "result": "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAKDwECAwQFBgcICQ8BAgMEBQYHCAkKCwwNDg8KDwECAwQFBgcIEA8BAgMEBQYHCAkKCwwNDg8ACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PCg8BAgMEBQYHCBAPAQIDBAUGBwgJCgsMDQ4PAAoPAQIDBAUGBwgJDwECAwQFBgcICQoLDA0ODwoPAQIDBAUGBwgQDwECAwQFBgcICQoLDA0ODwA="
-      }
-    ],
-    "finalizer": [
-      {
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEiAgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc0cwRAIgZfRbpZmLWaJ//hp77QFq8fH5DVSzqo90UKpfVqJRA70CIH9yRwOtHtuWaAsoS1bU/8uI9/t1nqu+CKow8puFE4PSAQEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
-        "result": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA=="
-      }
-    ],
-    "extractor": [
-      {
-        "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIgIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1Ptnuylh3EQ2QxqTwAAAIAAAACABAAAgAAiAgJ/Y5l1fS7/VaE2rQLGhLGDi2VW5fG2s0KCqUtrUAUQlhDZDGpPAAAAgAAAAIAFAACAAA==",
-        "transaction": "0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000"
-      }
-    ]
-  },
-  "addInput": {
-    "checks": [
-      {
-        "description": "checks for hash and index",
-        "inputData": {
-          "hash": 42
-        },
-        "exception": "Invalid arguments for Psbt\\.addInput\\. Requires single object with at least \\[hash\\] and \\[index\\]"
-      },
-      {
-        "description": "checks for invalid p2wsh witnessScript",
-        "inputData": {
-          "hash": "Buffer.from('000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f', 'hex')",
-          "index": 0,
-          "witnessScript": "Buffer.from('0014000102030405060708090a0b0c0d0e0f00010203', 'hex')"
-        },
-        "exception": "P2WPKH or P2SH can not be contained within P2WSH"
-      },
-      {
-        "description": "checks for invalid p2wsh witnessScript",
-        "inputData": {
-          "hash": "Buffer.from('000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f', 'hex')",
-          "index": 0,
-          "witnessScript": "Buffer.from('a914000102030405060708090a0b0c0d0e0f0001020387', 'hex')"
-        },
-        "exception": "P2WPKH or P2SH can not be contained within P2WSH"
-      },
-      {
-        "description": "should be equal",
-        "inputData": {
-          "hash": "Buffer.from('000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f', 'hex')",
-          "index": 2
-        },
-        "equals": "cHNidP8BADMCAAAAAQABAgMEBQYHCAkKCwwNDg8AAQIDBAUGBwgJCgsMDQ4PAgAAAAD/////AAAAAAAAAAA="
-      }
-    ]
-  },
-  "addOutput": {
-    "checks": [
-      {
-        "description": "Checks value is number",
-        "outputData": {
-          "address": "1P2NFEBp32V2arRwZNww6tgXEV58FG94mr",
-          "value": "xyz"
-        },
-        "exception": "Error adding output."
-      },
-      {
-        "description": "Adds output normally",
-        "outputData": {
-          "address": "1P2NFEBp32V2arRwZNww6tgXEV58FG94mr",
-          "value": 42
-        }
-      }
-    ]
-  },
-  "signInput": {
-    "checks": [
-      {
-        "description": "checks the input exists",
-        "shouldSign": {
-          "psbt": "cHNidP8BADMBAAAAAXVa+rWvBGNyifYXEMlTten9+qC0xuHcAMxQYrQTwX1dAAAAAAD/////AAAAAAAAAQDAAgAAAAH//////////////////////////////////////////wAAAABrSDBFAiEAjtCPUj0vx3I5HFQKAUWHN0vCnT17jd41/omb4nobq/sCIAilSeQVi4mqykgBbs+Wz6PyqdMThi2gT463v4kPWk6cASECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWH/////AQDh9QUAAAAAGXapFC8spHIOpiw9giaEPd5RGkMYvXRHiKwAAAAAAAA=",
-          "inputToCheck": 0,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        },
-        "shouldThrow": {
-          "errorMessage": "No input #1",
-          "psbt": "cHNidP8BADMBAAAAAXVa+rWvBGNyifYXEMlTten9+qC0xuHcAMxQYrQTwX1dAAAAAAD/////AAAAAAAAAQDAAgAAAAH//////////////////////////////////////////wAAAABrSDBFAiEAjtCPUj0vx3I5HFQKAUWHN0vCnT17jd41/omb4nobq/sCIAilSeQVi4mqykgBbs+Wz6PyqdMThi2gT463v4kPWk6cASECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWH/////AQDh9QUAAAAAGXapFC8spHIOpiw9giaEPd5RGkMYvXRHiKwAAAAAAAA=",
-          "inputToCheck": 1,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        }
-      },
-      {
-        "description": "checks a UTXO value exists for the input",
-        "shouldSign": {
-          "psbt": "cHNidP8BADMBAAAAAXVa+rWvBGNyifYXEMlTten9+qC0xuHcAMxQYrQTwX1dAAAAAAD/////AAAAAAAAAQDAAgAAAAH//////////////////////////////////////////wAAAABrSDBFAiEAjtCPUj0vx3I5HFQKAUWHN0vCnT17jd41/omb4nobq/sCIAilSeQVi4mqykgBbs+Wz6PyqdMThi2gT463v4kPWk6cASECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWH/////AQDh9QUAAAAAGXapFC8spHIOpiw9giaEPd5RGkMYvXRHiKwAAAAAAAA=",
-          "inputToCheck": 0,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        },
-        "shouldThrow": {
-          "errorMessage": "Need a Utxo input item for signing",
-          "psbt": "cHNidP8BADMBAAAAAXVa+rWvBGNyifYXEMlTten9+qC0xuHcAMxQYrQTwX1dAAAAAAD/////AAAAAAAAAAA=",
-          "inputToCheck": 0,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        }
-      },
-      {
-        "description": "checks privkey matches the input it's signing",
-        "shouldSign": {
-          "psbt": "cHNidP8BADMBAAAAAXVa+rWvBGNyifYXEMlTten9+qC0xuHcAMxQYrQTwX1dAAAAAAD/////AAAAAAAAAQDAAgAAAAH//////////////////////////////////////////wAAAABrSDBFAiEAjtCPUj0vx3I5HFQKAUWHN0vCnT17jd41/omb4nobq/sCIAilSeQVi4mqykgBbs+Wz6PyqdMThi2gT463v4kPWk6cASECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWH/////AQDh9QUAAAAAGXapFC8spHIOpiw9giaEPd5RGkMYvXRHiKwAAAAAAAA=",
-          "inputToCheck": 0,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        },
-        "shouldThrow": {
-          "errorMessage": "Can not sign for this input with the key 02e717fee6be913148f9fd676c0876b7e4574118542c6758b4a9fb9f38f171842b",
-          "psbt": "cHNidP8BADMBAAAAAXVa+rWvBGNyifYXEMlTten9+qC0xuHcAMxQYrQTwX1dAAAAAAD/////AAAAAAAAAQDAAgAAAAH//////////////////////////////////////////wAAAABrSDBFAiEAjtCPUj0vx3I5HFQKAUWHN0vCnT17jd41/omb4nobq/sCIAilSeQVi4mqykgBbs+Wz6PyqdMThi2gT463v4kPWk6cASECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWH/////AQDh9QUAAAAAGXapFC8spHIOpiw9giaEPd5RGkMYvXRHiKwAAAAAAAA=",
-          "inputToCheck": 0,
-          "WIF": "Kz4mjzErKCH5eQ97RXNQd3Wv7WsLA83BjynfQk4N7BB8J5xuUjAv"
-        }
-      },
-      {
-        "description": "checks non-witness UTXO matches the hash specified in the prevout",
-        "shouldSign": {
-          "psbt": "cHNidP8BADMBAAAAAXVa+rWvBGNyifYXEMlTten9+qC0xuHcAMxQYrQTwX1dAAAAAAD/////AAAAAAAAAQDAAgAAAAH//////////////////////////////////////////wAAAABrSDBFAiEAjtCPUj0vx3I5HFQKAUWHN0vCnT17jd41/omb4nobq/sCIAilSeQVi4mqykgBbs+Wz6PyqdMThi2gT463v4kPWk6cASECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWH/////AQDh9QUAAAAAGXapFC8spHIOpiw9giaEPd5RGkMYvXRHiKwAAAAAAAA=",
-          "inputToCheck": 0,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        },
-        "shouldThrow": {
-          "errorMessage": "Non-witness UTXO hash for input #0 doesn't match the hash specified in the prevout",
-          "psbt": "cHNidP8BADMBAAAAAXVa+rWvBGNyifYXEMlTten9+qC0xuHcAMxQYrQTwX1dAAAAAAD/////AAAAAAAAAQD4AQAAAAABAbD7u8z1SxTjfvhwmkQQvdbbWA+n3GKBBmGecSIAaM5jBQAAABcWABS0SqIhdn2LbW4TAJc3GVh7SnD/eP////8CNg8AAAAAAAAWABSmNm8WWVF+wq+QAeRo9d763jEXhRAnAAAAAAAAGXapFNpkc+03Pgj0bdgAP8p7py++nFVeiKwCRzBEAiB/u0BLwdeerqWf0JH33wwMv8Nn3sKblFvj+CntdC4B9gIgKVVHBH1c9ewnzkuyW6dnz1YARujBJnle1eBNSBAJD9IBIQOmYxHmd2Yz53FpC9+nv+pKdM+5OyEAW3BAN2cccQ0LkgAAAAAAAA==",
-          "inputToCheck": 0,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        }
-      },
-      {
-        "description": "checks redeem script matches the scriptPubKey in a non-witness prevout",
-        "shouldSign": {
-          "psbt": "cHNidP8BADMBAAAAAR2dq8JwBaxnbWHZGw0HdxuUGFcg6dvx3pgjWMm+Pzf2AAAAAAD/////AAAAAAAAAQC9AgAAAAH//////////////////////////////////////////wAAAABqRzBEAiAf7N+IK1uuxTxvEOoVGabNsiT7jMlfSDCd0VYxv+sQTQIgQVYM7ig9TIx1LzrX2RXgw2zW2fMKuRs/bT9eZx6jmYwBIQJpKKFOB6PrPJhRAtaQ+cHHryY5QYIi5dxZtkMwCtuFYf////8BAOH1BQAAAAAXqRRdh8wk5NRiF7VGQ4Zb4i8Vl1YFMocAAAAAAQRpUiECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWEhAgHGF3SgP82qhvqMptNluTLHhLtzDsmc0pNWEDETNj/rIQIFIl+T3Z90vBFGN8uYJHCrUO4DvrOGVWkVDsBeEzBUi1OuAAA=",
-          "inputToCheck": 0,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        },
-        "shouldThrow": {
-          "errorMessage": "Redeem script for input #0 doesn't match the scriptPubKey in the prevout",
-          "psbt": "cHNidP8BADMBAAAAAR2dq8JwBaxnbWHZGw0HdxuUGFcg6dvx3pgjWMm+Pzf2AAAAAAD/////AAAAAAAAAQC9AgAAAAH//////////////////////////////////////////wAAAABqRzBEAiAf7N+IK1uuxTxvEOoVGabNsiT7jMlfSDCd0VYxv+sQTQIgQVYM7ig9TIx1LzrX2RXgw2zW2fMKuRs/bT9eZx6jmYwBIQJpKKFOB6PrPJhRAtaQ+cHHryY5QYIi5dxZtkMwCtuFYf////8BAOH1BQAAAAAXqRRdh8wk5NRiF7VGQ4Zb4i8Vl1YFMocAAAAAAQRpUiEDGMZFrWWJBIIu33FdV9Q+Zit0fcoBOdgS7ooA2h2QlbAhAuAzQeDZh730hBbfTPzlaXJgCh2Jyui/ufS0k8wqJ55FIQKMg6lgEnyRnGIZ90eP4MmuRdT3EcO4+irJEm5yTCiko1OuAAA=",
-          "inputToCheck": 0,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        }
-      },
-      {
-        "description": "checks redeem script matches the scriptPubKey in a witness prevout",
-        "shouldSign": {
-          "psbt": "cHNidP8BADMBAAAAAYaq+PdOUY2PnV9kZKa82XlqrPByOqwH2TRg2+LQdqs2AAAAAAD/////AAAAAAAAAQEgAOH1BQAAAAAXqRSTNeWHqa9INvSnQ120SZeJc+6JSocBBBYAFC8spHIOpiw9giaEPd5RGkMYvXRHAAA=",
-          "inputToCheck": 0,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        },
-        "shouldThrow": {
-          "errorMessage": "Redeem script for input #0 doesn't match the scriptPubKey in the prevout",
-          "psbt": "cHNidP8BADMBAAAAAYaq+PdOUY2PnV9kZKa82XlqrPByOqwH2TRg2+LQdqs2AAAAAAD/////AAAAAAAAAQEgAOH1BQAAAAAXqRSTNeWHqa9INvSnQ120SZeJc+6JSocBBBYAFA3zpl6FMnlgCviVJgbcnBj01iLgAAA=",
-          "inputToCheck": 0,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        }
-      },
-      {
-        "description": "checks the sighash type",
-        "shouldThrow": {
-          "errorMessage": "Sighash type is not allowed. Retry the sign method passing the sighashTypes array of whitelisted types. Sighash type: SIGHASH_ANYONECANPAY | SIGHASH_ALL",
-          "psbt": "cHNidP8BADMBAAAAAYaq+PdOUY2PnV9kZKa82XlqrPByOqwH2TRg2+LQdqs2AAAAAAD/////AAAAAAAAAQEgAOH1BQAAAAAXqRSTNeWHqa9INvSnQ120SZeJc+6JSocBAwSBAAAAAQQWABQvLKRyDqYsPYImhD3eURpDGL10RwAA",
-          "inputToCheck": 0,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        }
-      },
-      {
-        "description": "allows signing non-whitelisted sighashtype when explicitly passed in",
-        "shouldSign": {
-          "psbt": "cHNidP8BADMBAAAAAYaq+PdOUY2PnV9kZKa82XlqrPByOqwH2TRg2+LQdqs2AAAAAAD/////AAAAAAAAAQEgAOH1BQAAAAAXqRSTNeWHqa9INvSnQ120SZeJc+6JSocBAwSBAAAAAQQWABQvLKRyDqYsPYImhD3eURpDGL10RwAA",
-          "sighashTypes": [129],
-          "inputToCheck": 0,
-          "WIF": "KxnAnQh6UJBxLF8Weup77yn8tWhLHhDhnXeyJuzmmcZA5aRdMJni"
-        }
-      }
-    ]
-  },
-  "signInputHD": {
-    "checks": [
-      {
-        "description": "checks the bip32Derivation exists",
-        "shouldSign": {
-          "psbt": "cHNidP8BADMBAAAAARtEptsZNydT9Bh9A5ptwIZz87yH8NXwzr1bjJorAZEAAAAAAAD/////AAAAAAAAAQDAAgAAAAH//////////////////////////////////////////wAAAABrSDBFAiEAjtCPUj0vx3I5HFQKAUWHN0vCnT17jd41/omb4nobq/sCIAilSeQVi4mqykgBbs+Wz6PyqdMThi2gT463v4kPWk6cASECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWH/////AQDh9QUAAAAAGXapFJWXNY2Vp7E5pNOey64rnhhgUlohiKwAAAAAIgYDn85vSg5rlR25fd4MOU2ANsFoO+q828zuOI/5b8tj89kYBCppsiwAAIAAAACAAAAAgAAAAAAAAAAAAAA=",
-          "inputToCheck": 0,
-          "xprv": "xprv9s21ZrQH143K2XNCa3o3tii6nbyJAET6GjTfzcF6roTjAMzLUBe8nt7QHNYqKah8JBv8V67MTWBCqPptRr6khjTSvCUVru78KHW13Viwnev"
-        },
-        "shouldThrow": {
-          "errorMessage": "Need bip32Derivation to sign with HD",
-          "psbt": "cHNidP8BADMBAAAAAXVa+rWvBGNyifYXEMlTten9+qC0xuHcAMxQYrQTwX1dAAAAAAD/////AAAAAAAAAQDAAgAAAAH//////////////////////////////////////////wAAAABrSDBFAiEAjtCPUj0vx3I5HFQKAUWHN0vCnT17jd41/omb4nobq/sCIAilSeQVi4mqykgBbs+Wz6PyqdMThi2gT463v4kPWk6cASECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWH/////AQDh9QUAAAAAGXapFC8spHIOpiw9giaEPd5RGkMYvXRHiKwAAAAAAAA=",
-          "inputToCheck": 0,
-          "xprv": "xprv9s21ZrQH143K2XNCa3o3tii6nbyJAET6GjTfzcF6roTjAMzLUBe8nt7QHNYqKah8JBv8V67MTWBCqPptRr6khjTSvCUVru78KHW13Viwnev"
-        }
-      },
-      {
-        "description": "checks the bip32Derivation exists",
-        "shouldSign": {
-          "psbt": "cHNidP8BADMBAAAAARtEptsZNydT9Bh9A5ptwIZz87yH8NXwzr1bjJorAZEAAAAAAAD/////AAAAAAAAAQDAAgAAAAH//////////////////////////////////////////wAAAABrSDBFAiEAjtCPUj0vx3I5HFQKAUWHN0vCnT17jd41/omb4nobq/sCIAilSeQVi4mqykgBbs+Wz6PyqdMThi2gT463v4kPWk6cASECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWH/////AQDh9QUAAAAAGXapFJWXNY2Vp7E5pNOey64rnhhgUlohiKwAAAAAIgYDn85vSg5rlR25fd4MOU2ANsFoO+q828zuOI/5b8tj89kYBCppsiwAAIAAAACAAAAAgAAAAAAAAAAAAAA=",
-          "inputToCheck": 0,
-          "xprv": "xprv9s21ZrQH143K2XNCa3o3tii6nbyJAET6GjTfzcF6roTjAMzLUBe8nt7QHNYqKah8JBv8V67MTWBCqPptRr6khjTSvCUVru78KHW13Viwnev"
-        },
-        "shouldThrow": {
-          "errorMessage": "Need one bip32Derivation masterFingerprint to match the HDSigner fingerprint",
-          "psbt": "cHNidP8BADMBAAAAARtEptsZNydT9Bh9A5ptwIZz87yH8NXwzr1bjJorAZEAAAAAAAD/////AAAAAAAAAQDAAgAAAAH//////////////////////////////////////////wAAAABrSDBFAiEAjtCPUj0vx3I5HFQKAUWHN0vCnT17jd41/omb4nobq/sCIAilSeQVi4mqykgBbs+Wz6PyqdMThi2gT463v4kPWk6cASECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWH/////AQDh9QUAAAAAGXapFJWXNY2Vp7E5pNOey64rnhhgUlohiKwAAAAAIgYD/85vSg5rlR25fd4MOU2ANsFoO+q828zuOI/5b8tj89kY/////ywAAIAAAACAAAAAgAAAAAAAAAAAAAA=",
-          "inputToCheck": 0,
-          "xprv": "xprv9s21ZrQH143K2XNCa3o3tii6nbyJAET6GjTfzcF6roTjAMzLUBe8nt7QHNYqKah8JBv8V67MTWBCqPptRr6khjTSvCUVru78KHW13Viwnev"
-        }
-      },
-      {
-        "description": "checks the bip32Derivation exists",
-        "shouldSign": {
-          "psbt": "cHNidP8BADMBAAAAARtEptsZNydT9Bh9A5ptwIZz87yH8NXwzr1bjJorAZEAAAAAAAD/////AAAAAAAAAQDAAgAAAAH//////////////////////////////////////////wAAAABrSDBFAiEAjtCPUj0vx3I5HFQKAUWHN0vCnT17jd41/omb4nobq/sCIAilSeQVi4mqykgBbs+Wz6PyqdMThi2gT463v4kPWk6cASECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWH/////AQDh9QUAAAAAGXapFJWXNY2Vp7E5pNOey64rnhhgUlohiKwAAAAAIgYDn85vSg5rlR25fd4MOU2ANsFoO+q828zuOI/5b8tj89kYBCppsiwAAIAAAACAAAAAgAAAAAAAAAAAAAA=",
-          "inputToCheck": 0,
-          "xprv": "xprv9s21ZrQH143K2XNCa3o3tii6nbyJAET6GjTfzcF6roTjAMzLUBe8nt7QHNYqKah8JBv8V67MTWBCqPptRr6khjTSvCUVru78KHW13Viwnev"
-        },
-        "shouldThrow": {
-          "errorMessage": "pubkey did not match bip32Derivation",
-          "psbt": "cHNidP8BADMBAAAAARtEptsZNydT9Bh9A5ptwIZz87yH8NXwzr1bjJorAZEAAAAAAAD/////AAAAAAAAAQDAAgAAAAH//////////////////////////////////////////wAAAABrSDBFAiEAjtCPUj0vx3I5HFQKAUWHN0vCnT17jd41/omb4nobq/sCIAilSeQVi4mqykgBbs+Wz6PyqdMThi2gT463v4kPWk6cASECaSihTgej6zyYUQLWkPnBx68mOUGCIuXcWbZDMArbhWH/////AQDh9QUAAAAAGXapFJWXNY2Vp7E5pNOey64rnhhgUlohiKwAAAAAIgYD/85vSg5rlR25fd4MOU2ANsFoO+q828zuOI/5b8tj89kYBCppsiwAAIAAAACAAAAAgAAAAAAAAAAAAAA=",
-          "inputToCheck": 0,
-          "xprv": "xprv9s21ZrQH143K2XNCa3o3tii6nbyJAET6GjTfzcF6roTjAMzLUBe8nt7QHNYqKah8JBv8V67MTWBCqPptRr6khjTSvCUVru78KHW13Viwnev"
-        }
-      }
-    ]
-  },
-  "finalizeAllInputs": [
-    {
-      "type": "P2PK",
-      "psbt": "cHNidP8BAFUCAAAAAZfdvR7JvbVsuXunG1P19tTYi8Z0l6WHiz+0jpzTNTt+AAAAAAD/////AYA4AQAAAAAAGXapFMjtQ0xCK7OPd32ZJTY2UcdpFIaJiKwAAAAAAAEAygIAAAABb7TMmNs5UwEEpccLHlaaM0w3HEHhh85NjrUObLDMuZsBAAAAa0gwRQIhANWUevBBcqfRpH67rDuFqI+KHqxViKXxmSM+6/jE5ZHjAiBgO/vQg2EsYhaOD5lQbmZYaymRLukA6SCoXhkN21hiOwEhAoKzWGkj1LJ2iOt5wj6jMOtAMGJH50ZjAYZU81uUu6y+/////wGQXwEAAAAAACMhAzpK4NeYX+xyBOKynjD3BEPDq7EN8brZXje488gxshXwrAAAAAAiAgM6SuDXmF/scgTisp4w9wRDw6uxDfG62V43uPPIMbIV8EgwRQIhAL3H/XEPRAZEbpjBwkuLqUKBSu1Inpb2rganXNFcY2JsAiASrXTM2xODEKp7m7RTzYqBchqlvbl88zO/CGW9SePj2gEAAA==",
-      "result": "cHNidP8BAFUCAAAAAZfdvR7JvbVsuXunG1P19tTYi8Z0l6WHiz+0jpzTNTt+AAAAAAD/////AYA4AQAAAAAAGXapFMjtQ0xCK7OPd32ZJTY2UcdpFIaJiKwAAAAAAAEAygIAAAABb7TMmNs5UwEEpccLHlaaM0w3HEHhh85NjrUObLDMuZsBAAAAa0gwRQIhANWUevBBcqfRpH67rDuFqI+KHqxViKXxmSM+6/jE5ZHjAiBgO/vQg2EsYhaOD5lQbmZYaymRLukA6SCoXhkN21hiOwEhAoKzWGkj1LJ2iOt5wj6jMOtAMGJH50ZjAYZU81uUu6y+/////wGQXwEAAAAAACMhAzpK4NeYX+xyBOKynjD3BEPDq7EN8brZXje488gxshXwrAAAAAABB0lIMEUCIQC9x/1xD0QGRG6YwcJLi6lCgUrtSJ6W9q4Gp1zRXGNibAIgEq10zNsTgxCqe5u0U82KgXIapb25fPMzvwhlvUnj49oBAAA="
-    },
-    {
-      "type": "P2PKH",
-      "psbt": "cHNidP8BAFUCAAAAAaTbj9mE+B5Z8PLsuGUNGOzDqrtwdB08vvSccSCrezh+AAAAAAD/////AYA4AQAAAAAAGXapFDuK+0mR+qtL9tyadI72bKMwH+vuiKwAAAAAAAEAwAIAAAABks7XL87tkSusFA3L2u2CdJeNkqTMobehPNm/wkGQUzoBAAAAa0gwRQIhAMtzqC7axSA7/7nbio9NKQZz2ePuKeaF5T4c8JSXWEdgAiAID39I05hbJMNGSomrF7XVWEsEEHHzX/lkL3vnOOu4cAEhAvu+bfurbDCzxfOLxEhvz9ZyxPLdI1h9wMT8gl2nyLYV/////wGQXwEAAAAAABl2qRTH5239BfS9zrbwUtvpATwjua4LGYisAAAAACICA1oNX0U/6GwAuVI7JHhneD94sm/o+YrfTnRAhdRUMjoISDBFAiEAhk+HbvY6YShBCUmBVCk42sFWH9LTwUv2wbRC/tIuEAwCIED/UkklY3fpdDBN7qSBHFDyEOeHMUzXD0bvtFTAiKP7AQAA",
-      "result": "cHNidP8BAFUCAAAAAaTbj9mE+B5Z8PLsuGUNGOzDqrtwdB08vvSccSCrezh+AAAAAAD/////AYA4AQAAAAAAGXapFDuK+0mR+qtL9tyadI72bKMwH+vuiKwAAAAAAAEAwAIAAAABks7XL87tkSusFA3L2u2CdJeNkqTMobehPNm/wkGQUzoBAAAAa0gwRQIhAMtzqC7axSA7/7nbio9NKQZz2ePuKeaF5T4c8JSXWEdgAiAID39I05hbJMNGSomrF7XVWEsEEHHzX/lkL3vnOOu4cAEhAvu+bfurbDCzxfOLxEhvz9ZyxPLdI1h9wMT8gl2nyLYV/////wGQXwEAAAAAABl2qRTH5239BfS9zrbwUtvpATwjua4LGYisAAAAAAEHa0gwRQIhAIZPh272OmEoQQlJgVQpONrBVh/S08FL9sG0Qv7SLhAMAiBA/1JJJWN36XQwTe6kgRxQ8hDnhzFM1w9G77RUwIij+wEhA1oNX0U/6GwAuVI7JHhneD94sm/o+YrfTnRAhdRUMjoIAAA="
-    },
-    {
-      "type": "P2MS",
-      "psbt": "cHNidP8BAFUCAAAAAbmLTo7GeyF7IT5PJznDiTVjhv5pQKcKe8Qa+8rqUpXuAAAAAAD/////AYA4AQAAAAAAGXapFF2G82oAzUpx/kcDUPy58goX16gkiKwAAAAAAAEAvgIAAAABMBwIKVKOFbas6tBD24LPchtrweE2jiXkPgSHdJndEfoAAAAAa0gwRQIhAJNchwx4je/ZqtZXSCD6BKJBQkpkTBGGdLoFZTcPKlDtAiAZefY/giaVw5rcEoJk4TRnFCyMG0dYLV5IVnFWkR38fQEhAi5yX8RMW6plVrMY26hithJ6j1w2mgqh/bOCAEVnbn/Z/////wGQXwEAAAAAABepFIoQ3seh+nGYzkI7MDw5zuSCIxEyhwAAAAAiAgLFmuo7gG8OjgmaO5AHuC/1OvDarQt16R7VEKU8dkRRCEgwRQIhAOqqlnUwmc+PqKZVwAAMLPNCKskHhVgk1pXR9d7nmB6SAiA0C24idVdtgl9+sIBR8A3Za5WcswNJ3i8PWTMWR10C4QEiAgPnartRgvSQnSJ2ydRuwSPXDdU3P1YQwhYsK7XzfGuUREgwRQIhANnDBUQWjS8hDTPidRZ95rGZK3LWCLIZB1NYx9++eBT8AiASupLR+KNa1Se7eoBkWQcDny+BaBfMQ+p1RTCAXd7/GAEBBItSIQLFmuo7gG8OjgmaO5AHuC/1OvDarQt16R7VEKU8dkRRCCEC4X74b+vRF3XLgyXyGejmE5VB1f3RY/IReUggyNHgdLYhA+dqu1GC9JCdInbJ1G7BI9cN1Tc/VhDCFiwrtfN8a5REIQO94OZv6yPD4kEZSZBquYA7FPsABZZ6UAteVuEw7fVxzlSuAAA=",
-      "result": "cHNidP8BAFUCAAAAAbmLTo7GeyF7IT5PJznDiTVjhv5pQKcKe8Qa+8rqUpXuAAAAAAD/////AYA4AQAAAAAAGXapFF2G82oAzUpx/kcDUPy58goX16gkiKwAAAAAAAEAvgIAAAABMBwIKVKOFbas6tBD24LPchtrweE2jiXkPgSHdJndEfoAAAAAa0gwRQIhAJNchwx4je/ZqtZXSCD6BKJBQkpkTBGGdLoFZTcPKlDtAiAZefY/giaVw5rcEoJk4TRnFCyMG0dYLV5IVnFWkR38fQEhAi5yX8RMW6plVrMY26hithJ6j1w2mgqh/bOCAEVnbn/Z/////wGQXwEAAAAAABepFIoQ3seh+nGYzkI7MDw5zuSCIxEyhwAAAAABB/0gAQBIMEUCIQDqqpZ1MJnPj6imVcAADCzzQirJB4VYJNaV0fXe55gekgIgNAtuInVXbYJffrCAUfAN2WuVnLMDSd4vD1kzFkddAuEBSDBFAiEA2cMFRBaNLyENM+J1Fn3msZkrctYIshkHU1jH3754FPwCIBK6ktH4o1rVJ7t6gGRZBwOfL4FoF8xD6nVFMIBd3v8YAUyLUiECxZrqO4BvDo4JmjuQB7gv9Trw2q0Ldeke1RClPHZEUQghAuF++G/r0Rd1y4Ml8hno5hOVQdX90WPyEXlIIMjR4HS2IQPnartRgvSQnSJ2ydRuwSPXDdU3P1YQwhYsK7XzfGuURCEDveDmb+sjw+JBGUmQarmAOxT7AAWWelALXlbhMO31cc5UrgAA"
-    },
-    {
-      "type": "P2SH-P2WPKH",
-      "psbt": "cHNidP8BAFUCAAAAATIK6DMTn8bbrG7ZdiiVU3/YAgzyk3dwa56En58YfXbDAAAAAAD/////AYA4AQAAAAAAGXapFNU4SHWUW9ZNz+BcxCiuU/7UtJoMiKwAAAAAAAEAvgIAAAABly2BCiYZ3slqurlLwE7b8UXINYKfrJ9sQlBovzBAwFsBAAAAa0gwRQIhAJJ+Hyniw+KneWomeQYrP1duH7cfQ3j8GN6/RshZCfuvAiBux7Uu/5QqmSmL+LjoWZY2b9TWdluY6zLTkQWIornmYwEhAvUo9Sy7Pu44z84ZZPrQMQxBPpDJyy9WlLQMGdGIuUy7/////wGQXwEAAAAAABepFPwojcWCH2oE9dUjMmLC3bdK/xeWhwAAAAAiAgKj88rhJwk3Zxm0p0Rp+xC/6cxmj+I741DHPWPWN7iA+0cwRAIgTRhd9WUpoHYl9tUVmoJ336fJAJInIjdYsoatvRiW8hgCIGOYMlpKRHiHA428Sfa2CdAIIGGQCGhuIgIzj2FN6USnAQEEFgAU4sZupXPxqhcsOB1ghJxBvH4XcesAAA==",
-      "result": "cHNidP8BAFUCAAAAATIK6DMTn8bbrG7ZdiiVU3/YAgzyk3dwa56En58YfXbDAAAAAAD/////AYA4AQAAAAAAGXapFNU4SHWUW9ZNz+BcxCiuU/7UtJoMiKwAAAAAAAEAvgIAAAABly2BCiYZ3slqurlLwE7b8UXINYKfrJ9sQlBovzBAwFsBAAAAa0gwRQIhAJJ+Hyniw+KneWomeQYrP1duH7cfQ3j8GN6/RshZCfuvAiBux7Uu/5QqmSmL+LjoWZY2b9TWdluY6zLTkQWIornmYwEhAvUo9Sy7Pu44z84ZZPrQMQxBPpDJyy9WlLQMGdGIuUy7/////wGQXwEAAAAAABepFPwojcWCH2oE9dUjMmLC3bdK/xeWhwAAAAABBxcWABTixm6lc/GqFyw4HWCEnEG8fhdx6wEIawJHMEQCIE0YXfVlKaB2JfbVFZqCd9+nyQCSJyI3WLKGrb0YlvIYAiBjmDJaSkR4hwONvEn2tgnQCCBhkAhobiICM49hTelEpwEhAqPzyuEnCTdnGbSnRGn7EL/pzGaP4jvjUMc9Y9Y3uID7AAA="
-    },
-    {
-      "type": "P2WPKH",
-      "psbt": "cHNidP8BAFICAAAAAb5UIQFSoXPjqxSmuiSZkM5PjaycnrXQ6VB+u2+MzbSGAAAAAAD/////ASBOAAAAAAAAFgAUXsVBEaHSlhycDORbHHtBKwDo4zIAAAAAAAEBHzB1AAAAAAAAFgAUvIgag7HZu7Rjd/ugmJC/MHlZmAYiAgLN1zezMD4c4uegTbgfJ1GCtN5/hlJYaJt7e8mt1BVzIEcwRAIgXhgL5G81tXP7MAaKJtA0QaFu17bLocOGqxXmDoIfYUACIAOIynpoPS/dTz9Omg2h7v5kiql7ab0SPzWDdxpvpsUcAQAA",
-      "result": "cHNidP8BAFICAAAAAb5UIQFSoXPjqxSmuiSZkM5PjaycnrXQ6VB+u2+MzbSGAAAAAAD/////ASBOAAAAAAAAFgAUXsVBEaHSlhycDORbHHtBKwDo4zIAAAAAAAEBHzB1AAAAAAAAFgAUvIgag7HZu7Rjd/ugmJC/MHlZmAYBCGsCRzBEAiBeGAvkbzW1c/swBoom0DRBoW7Xtsuhw4arFeYOgh9hQAIgA4jKemg9L91PP06aDaHu/mSKqXtpvRI/NYN3Gm+mxRwBIQLN1zezMD4c4uegTbgfJ1GCtN5/hlJYaJt7e8mt1BVzIAAA"
-    },
-    {
-      "type": "P2WSH-P2PK",
-      "psbt": "cHNidP8BAKYCAAAAAlwKQ3suPWwEJ/zQ9sZsIioOcHKU1KoLMxlMNSXVIkEWAAAAAAD/////YYDJMap+mYgbTrCNAdpWHN+EkKvl+XYao/6co/EQfwMAAAAAAP////8CkF8BAAAAAAAWABRnPBAmVHz2HL+8/1U+QG5L2thjmjhKAAAAAAAAIgAg700yfFRyhWzQnPHIUb/XQqsjlpf4A0uw682pCVWuQ8IAAAAAAAEBKzB1AAAAAAAAIgAgth9oE4cDfC5aV58VgkW5CptHsIxppYzJV8C5kT6aTo8iAgNfNgnFnEPS9s4PY/I5bezpWiAEzQ4DRTASgdSdeMM06UgwRQIhALO0xRpuqP3aVkm+DPykrtqe6fPNSgNblp9K9MAwmtHJAiAHV5ZvZN8Vi49n/o9ISFyvtHsPXXPKqBxC9m2m2HlpYgEBBSMhA182CcWcQ9L2zg9j8jlt7OlaIATNDgNFMBKB1J14wzTprAABASuAOAEAAAAAACIAILYfaBOHA3wuWlefFYJFuQqbR7CMaaWMyVfAuZE+mk6PIgIDXzYJxZxD0vbOD2PyOW3s6VogBM0OA0UwEoHUnXjDNOlIMEUCIQC6XN6tpo9mYlZej4BXSSh5D1K6aILBfQ4WBWXUrISx6wIgVaxFUsz8y59xJ1V4sZ1qarHX9pZ+MJmLKbl2ZSadisoBAQUjIQNfNgnFnEPS9s4PY/I5bezpWiAEzQ4DRTASgdSdeMM06awAAAA=",
-      "result": "cHNidP8BAKYCAAAAAlwKQ3suPWwEJ/zQ9sZsIioOcHKU1KoLMxlMNSXVIkEWAAAAAAD/////YYDJMap+mYgbTrCNAdpWHN+EkKvl+XYao/6co/EQfwMAAAAAAP////8CkF8BAAAAAAAWABRnPBAmVHz2HL+8/1U+QG5L2thjmjhKAAAAAAAAIgAg700yfFRyhWzQnPHIUb/XQqsjlpf4A0uw682pCVWuQ8IAAAAAAAEBKzB1AAAAAAAAIgAgth9oE4cDfC5aV58VgkW5CptHsIxppYzJV8C5kT6aTo8BCG4CSDBFAiEAs7TFGm6o/dpWSb4M/KSu2p7p881KA1uWn0r0wDCa0ckCIAdXlm9k3xWLj2f+j0hIXK+0ew9dc8qoHEL2babYeWliASMhA182CcWcQ9L2zg9j8jlt7OlaIATNDgNFMBKB1J14wzTprAABASuAOAEAAAAAACIAILYfaBOHA3wuWlefFYJFuQqbR7CMaaWMyVfAuZE+mk6PAQhuAkgwRQIhALpc3q2mj2ZiVl6PgFdJKHkPUrpogsF9DhYFZdSshLHrAiBVrEVSzPzLn3EnVXixnWpqsdf2ln4wmYspuXZlJp2KygEjIQNfNgnFnEPS9s4PY/I5bezpWiAEzQ4DRTASgdSdeMM06awAAAA="
-    }
-  ],
-  "validateSignaturesOfInput": {
-    "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEiAgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc0cwRAIgZfRbpZmLWaJ//hp77QFq8fH5DVSzqo90UKpfVqJRA70CIH9yRwOtHtuWaAsoS1bU/8uI9/t1nqu+CKow8puFE4PSAQEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
-    "index": 0,
-    "pubkey": "Buffer.from('029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f', 'hex')",
-    "incorrectPubkey": "Buffer.from('029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e02a', 'hex')",
-    "nonExistantIndex": 42
-  },
-  "getFeeRate": {
-    "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAAiAgKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgf0cwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMASICAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAQEDBAEAAAABBEdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSriIGApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/ENkMak8AAACAAAAAgAAAAIAiBgLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU21xDZDGpPAAAAgAAAAIABAACAAAEBIADC6wsAAAAAF6kUt/X69A49QKWkWbHbNTXyty+pIeiHIgIDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtxHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwEiAgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc0cwRAIgZfRbpZmLWaJ//hp77QFq8fH5DVSzqo90UKpfVqJRA70CIH9yRwOtHtuWaAsoS1bU/8uI9/t1nqu+CKow8puFE4PSAQEDBAEAAAABBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
-    "fee": 21
-  },
-  "cache": {
-    "nonWitnessUtxo": {
-      "psbt": "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEER1IhApWDvzmuCmCXR60Zmt3WNPphCFWdbFzTm0whg/GrluB/IQLath/0mhTban0CsM0fu3j8SxgxK1tOVNrk26L7/vU211KuIgYClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8Q2QxqTwAAAIAAAACAAAAAgCIGAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXENkMak8AAACAAAAAgAEAAIAAAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IcBBCIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQVHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4iBgI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8OcxDZDGpPAAAAgAAAAIADAACAIgYDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwQ2QxqTwAAAIAAAACAAgAAgAAiAgOppMN/WZbTqiXbrGtXCvBlA5RJKUJGCzVHU+2e7KWHcRDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA",
-      "nonWitnessUtxo": "Buffer.from('0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000', 'hex')",
-      "inputIndex": 0
-    }
-  },
-  "clone": {
-    "psbt": "cHNidP8BAKYCAAAAAlwKQ3suPWwEJ/zQ9sZsIioOcHKU1KoLMxlMNSXVIkEWAAAAAAD/////YYDJMap+mYgbTrCNAdpWHN+EkKvl+XYao/6co/EQfwMAAAAAAP////8CkF8BAAAAAAAWABRnPBAmVHz2HL+8/1U+QG5L2thjmjhKAAAAAAAAIgAg700yfFRyhWzQnPHIUb/XQqsjlpf4A0uw682pCVWuQ8IAAAAAAAEBKzB1AAAAAAAAIgAgth9oE4cDfC5aV58VgkW5CptHsIxppYzJV8C5kT6aTo8iAgNfNgnFnEPS9s4PY/I5bezpWiAEzQ4DRTASgdSdeMM06UgwRQIhALO0xRpuqP3aVkm+DPykrtqe6fPNSgNblp9K9MAwmtHJAiAHV5ZvZN8Vi49n/o9ISFyvtHsPXXPKqBxC9m2m2HlpYgEBBSMhA182CcWcQ9L2zg9j8jlt7OlaIATNDgNFMBKB1J14wzTprAABASuAOAEAAAAAACIAILYfaBOHA3wuWlefFYJFuQqbR7CMaaWMyVfAuZE+mk6PIgIDXzYJxZxD0vbOD2PyOW3s6VogBM0OA0UwEoHUnXjDNOlIMEUCIQC6XN6tpo9mYlZej4BXSSh5D1K6aILBfQ4WBWXUrISx6wIgVaxFUsz8y59xJ1V4sZ1qarHX9pZ+MJmLKbl2ZSadisoBAQUjIQNfNgnFnEPS9s4PY/I5bezpWiAEzQ4DRTASgdSdeMM06awAAAA="
-  }
-}
diff --git a/test/fixtures/script.json b/test/fixtures/script.json
index 545c8f3..3ba8bc3 100644
--- a/test/fixtures/script.json
+++ b/test/fixtures/script.json
@@ -95,10 +95,6 @@
       "asm": "OP_RETURN deadffffffffffffffffffffffffffffffffbeef",
       "script": "6a14deadffffffffffffffffffffffffffffffffbeef"
     },
-    {
-      "asm": "OP_RETURN deadffffffffffffffffffffffffffffffffbeef deadffffffffffffffffffffffffffffffffbeef",
-      "script": "6a14deadffffffffffffffffffffffffffffffffbeef14deadffffffffffffffffffffffffffffffffbeef"
-    },
     {
       "asm": "OP_0 OP_0 3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901 3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01",
       "script": "0000473044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901483045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01",
@@ -175,263 +171,6 @@
       "script": "6a24aa21a9ed4db4fb830efe3e804337413ffe8ad7393af301e0ec8e71b6e6f2b860a56f4dcd"
     }
   ],
-  "valid2": [
-    {
-      "type": "pubkey",
-      "pubKey": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
-      "signature": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
-      "output": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 OP_CHECKSIG",
-      "input": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
-      "inputHex": "47304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
-      "outputHex": "2102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1ac",
-      "inputStack": [
-        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801"
-      ]
-    },
-    {
-      "type": "pubkeyhash",
-      "pubKey": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
-      "signature": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
-      "output": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
-      "input": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
-      "inputHex": "47304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca28012102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
-      "outputHex": "76a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac",
-      "inputStack": [
-        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
-        "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1"
-      ]
-    },
-    {
-      "type": "multisig",
-      "pubKeys": [
-        "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
-        "0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a"
-      ],
-      "signatures": [
-        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
-        "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501"
-      ],
-      "output": "OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG",
-      "input": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
-      "inputHex": "0047304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801483045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
-      "outputHex": "522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae",
-      "inputStack": [
-        "",
-        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
-        "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501"
-      ]
-    },
-    {
-      "type": "multisig",
-      "pubKeys": [
-        "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
-        "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
-        "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34"
-      ],
-      "signatures": [
-        "3045022100fe324541215798b2df68cbd44039615e23c506d4ec1a05572064392a98196b82022068c849fa6699206da2fc6d7848efc1d3804a5816d6293615fe34c1a7f34e1c2f01",
-        "3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901",
-        "3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01"
-      ],
-      "output": "OP_3 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_3 OP_CHECKMULTISIG",
-      "input": "OP_0 3045022100fe324541215798b2df68cbd44039615e23c506d4ec1a05572064392a98196b82022068c849fa6699206da2fc6d7848efc1d3804a5816d6293615fe34c1a7f34e1c2f01 3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901 3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01",
-      "inputHex": "00483045022100fe324541215798b2df68cbd44039615e23c506d4ec1a05572064392a98196b82022068c849fa6699206da2fc6d7848efc1d3804a5816d6293615fe34c1a7f34e1c2f01473044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901483045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01",
-      "outputHex": "53210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817982102b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f84834021024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a3453ae",
-      "inputStack": [
-        "",
-        "3045022100fe324541215798b2df68cbd44039615e23c506d4ec1a05572064392a98196b82022068c849fa6699206da2fc6d7848efc1d3804a5816d6293615fe34c1a7f34e1c2f01",
-        "3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901",
-        "3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01"
-      ]
-    },
-    {
-      "type": "scripthash",
-      "redeemScript": "OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG",
-      "redeemScriptSig": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
-      "input": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501 522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae",
-      "output": "OP_HASH160 722ff0bc2c3f47b35c20df646c395594da24e90e OP_EQUAL",
-      "inputHex": "0047304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801483045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d14050147522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae",
-      "outputHex": "a914722ff0bc2c3f47b35c20df646c395594da24e90e87",
-      "inputStack": [
-        "",
-        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
-        "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
-        "522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae"
-      ]
-    },
-    {
-      "type": "witnesspubkeyhash",
-      "pubKey": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
-      "signature": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
-      "output": "OP_0 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5",
-      "outputHex": "0014aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5",
-      "inputStack": [
-        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
-        "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1"
-      ]
-    },
-    {
-      "type": "witnessscripthash",
-      "witnessScript": "OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG",
-      "witnessData": [
-        "",
-        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
-        "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501"
-      ],
-      "output": "OP_0 32447752937d355ca2defddcd1f6b4fc53d182f8901cebbcff42f5e381bf0b80",
-      "outputHex": "002032447752937d355ca2defddcd1f6b4fc53d182f8901cebbcff42f5e381bf0b80",
-      "inputStack": [
-        "",
-        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
-        "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
-        "522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae"
-      ]
-    },
-    {
-      "type": "nulldata",
-      "data": [
-        "06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474"
-      ],
-      "output": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474",
-      "outputHex": "6a2606deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474"
-    },
-    {
-      "type": "nulldata",
-      "data": [
-        "deadffffffffffffffffffffffffffffffffbeef",
-        "deadffffffffffffffffffffffffffffffffbeef"
-      ],
-      "output": "OP_RETURN deadffffffffffffffffffffffffffffffffbeef deadffffffffffffffffffffffffffffffffbeef",
-      "outputHex": "6a14deadffffffffffffffffffffffffffffffffbeef14deadffffffffffffffffffffffffffffffffbeef"
-    },
-    {
-      "type": "nulldata",
-      "data": [
-        "deadffffffffffffffffffffffffffffffffbeef"
-      ],
-      "output": "OP_RETURN deadffffffffffffffffffffffffffffffffbeef",
-      "outputHex": "6a14deadffffffffffffffffffffffffffffffffbeef"
-    },
-    {
-      "type": "nonstandard",
-      "typeIncomplete": "multisig",
-      "pubKeys": [
-        "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
-        "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
-        "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34"
-      ],
-      "signatures": [
-        null,
-        "3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901",
-        "3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01"
-      ],
-      "input": "OP_0 OP_0 3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901 3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01",
-      "inputHex": "0000473044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901483045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01",
-      "inputStack": [
-        "",
-        "",
-        "3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901",
-        "3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01"
-      ]
-    },
-    {
-      "type": "nonstandard",
-      "typeIncomplete": "multisig",
-      "pubKeys": [
-        "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
-        "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
-        "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34"
-      ],
-      "signatures": [
-        null,
-        null,
-        null
-      ],
-      "input": "OP_0 OP_0 OP_0 OP_0",
-      "inputHex": "00000000",
-      "inputStack": [
-        "",
-        "",
-        "",
-        ""
-      ]
-    },
-    {
-      "type": "scripthash",
-      "redeemScript": "OP_2 0327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a49372 03251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f 02cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde47 OP_3 OP_CHECKMULTISIG",
-      "redeemScriptSig": "OP_0 304502210093efc26facedc5f51e304aa270a7b4f1a911b2d912c3674e5c6e2ad4ac7a410402201cf0b62c240461902f9f16d8a0bc3a210b7bfcd2c06523dd4b4b63be22e8525201",
-      "input": "OP_0 304502210093efc26facedc5f51e304aa270a7b4f1a911b2d912c3674e5c6e2ad4ac7a410402201cf0b62c240461902f9f16d8a0bc3a210b7bfcd2c06523dd4b4b63be22e8525201 52210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753ae",
-      "inputHex": "0048304502210093efc26facedc5f51e304aa270a7b4f1a911b2d912c3674e5c6e2ad4ac7a410402201cf0b62c240461902f9f16d8a0bc3a210b7bfcd2c06523dd4b4b63be22e85252014c6952210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753ae",
-      "output": "OP_HASH160 fcc42dd4aa770d75cb6796bbd7853a325e746659 OP_EQUAL",
-      "outputHex": "a914fcc42dd4aa770d75cb6796bbd7853a325e74665987"
-    },
-    {
-      "type": "nonstandard",
-      "typeIncomplete": "scripthash",
-      "pubKeys": [
-        "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
-        "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a"
-      ],
-      "signatures": [
-        null,
-        "30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801"
-      ],
-      "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
-      "redeemScriptSig": "OP_0 OP_0 30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801",
-      "input": "OP_0 OP_0 30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae",
-      "inputHex": "00004830450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a8014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae",
-      "inputStack": [
-        "",
-        "",
-        "30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801",
-        "52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
-      ]
-    },
-    {
-      "type": "nonstandard",
-      "output": "OP_HASH256 6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000 OP_EQUAL",
-      "outputHex": "aa206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000087"
-    },
-    {
-      "type": "nonstandard",
-      "output": "OP_0 OP_0 OP_0 OP_CHECKMULTISIG",
-      "outputHex": "000000ae"
-    },
-    {
-      "type": "nonstandard",
-      "output": "OP_0",
-      "outputHex": "00"
-    },
-    {
-      "type": "nonstandard",
-      "input": "OP_0 00",
-      "inputHex": "000100",
-      "inputStack": [
-        "",
-        "00"
-      ]
-    },
-    {
-      "type": "nonstandard",
-      "input": "OP_6",
-      "inputHex": "56",
-      "nonstandard": {
-        "input": "06",
-        "inputHex": "0106"
-      },
-      "inputStack": [
-        "06"
-      ]
-    },
-    {
-      "type": "nonstandard",
-      "input": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
-      "inputHex": "4cff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
-      "inputStack": [
-        "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
-      ]
-    }
-  ],
   "invalid": {
     "decompile": [
       {
diff --git a/test/fixtures/signature.json b/test/fixtures/signature.json
deleted file mode 100644
index e7949c5..0000000
--- a/test/fixtures/signature.json
+++ /dev/null
@@ -1,140 +0,0 @@
-{
-  "valid": [
-    {
-      "hashType": 1,
-      "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226201",
-      "raw": {
-        "r": "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c9",
-        "s": "6f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"
-      }
-    },
-    {
-      "hashType": 2,
-      "hex": "3044022054c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed022007082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a502",
-      "raw": {
-        "r": "54c4a33c6423d689378f160a7ff8b61330444abb58fb470f96ea16d99d4a2fed",
-        "s": "07082304410efa6b2943111b6a4e0aaa7b7db55a07e9861d1fb3cb1f421044a5"
-      }
-    },
-    {
-      "hashType": 3,
-      "hex": "3045022100ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd002206fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b28303",
-      "raw": {
-        "r": "ff466a9f1b7b273e2f4c3ffe032eb2e814121ed18ef84665d0f515360dab3dd0",
-        "s": "6fc95f5132e5ecfdc8e5e6e616cc77151455d46ed48f5589b7db7771a332b283"
-      }
-    },
-    {
-      "hashType": 129,
-      "hex": "3045022100c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3022075afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d381",
-      "raw": {
-        "r": "c0dafec8251f1d5010289d210232220b03202cba34ec11fec58b3e93a85b91d3",
-        "s": "75afdc06b7d6322a590955bf264e7aaa155847f614d80078a90292fe205064d3"
-      }
-    },
-    {
-      "hashType": 130,
-      "hex": "304402207186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d02200de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df682",
-      "raw": {
-        "r": "7186363571d65e084e7f02b0b77c3ec44fb1b257dee26274c38c928986fea45d",
-        "s": "0de0b38e06807e46bda1f1e293f4f6323e854c86d58abdd00c46c16441085df6"
-      }
-    },
-    {
-      "hashType": 131,
-      "hex": "3045022100fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda48702200e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd3783",
-      "raw": {
-        "r": "fbfe5076a15860ba8ed00e75e9bd22e05d230f02a936b653eb55b61c99dda487",
-        "s": "0e68880ebb0050fe4312b1b1eb0899e1b82da89baa5b895f612619edf34cbd37"
-      }
-    },
-    {
-      "hashType": 129,
-      "hex": "3045022100cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9022006ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef81",
-      "raw": {
-        "r": "cde1302d83f8dd835d89aef803c74a119f561fbaef3eb9129e45f30de86abbf9",
-        "s": "06ce643f5049ee1f27890467b77a6a8e11ec4661cc38cd8badf90115fbd03cef"
-      }
-    }
-  ],
-  "invalid": [
-    {
-      "exception": "DER sequence length is too short",
-      "hex": "ffffffffffffff01"
-    },
-    {
-      "exception": "DER sequence length is too long",
-      "hex": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01"
-    },
-    {
-      "exception": "Expected DER sequence",
-      "hex": "00ffff0400ffffff020400ffffff01"
-    },
-    {
-      "exception": "DER sequence length is invalid",
-      "hex": "30ff020400ffffff020400ffffff01"
-    },
-    {
-      "exception": "DER sequence length is invalid",
-      "hex": "300c030400ffffff030400ffffff000001"
-    },
-    {
-      "exception": "Expected DER integer",
-      "hex": "300cff0400ffffff020400ffffff01"
-    },
-    {
-      "exception": "Expected DER integer \\(2\\)",
-      "hex": "300c020200ffffff020400ffffff01"
-    },
-    {
-      "exception": "R length is zero",
-      "hex": "30080200020400ffffff01"
-    },
-    {
-      "exception": "S length is zero",
-      "hex": "3008020400ffffff020001"
-    },
-    {
-      "exception": "R length is too long",
-      "hex": "300c02dd00ffffff020400ffffff01"
-    },
-    {
-      "exception": "S length is invalid",
-      "hex": "300c020400ffffff02dd00ffffff01"
-    },
-    {
-      "exception": "R value is negative",
-      "hex": "300c020480000000020400ffffff01"
-    },
-    {
-      "exception": "S value is negative",
-      "hex": "300c020400ffffff02048000000001"
-    },
-    {
-      "exception": "R value excessively padded",
-      "hex": "300c02040000ffff020400ffffff01"
-    },
-    {
-      "exception": "S value excessively padded",
-      "hex": "300c020400ffffff02040000ffff01"
-    },
-    {
-      "exception": "Invalid hashType 7",
-      "hashType": 7,
-      "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa5434226207",
-      "raw": {
-        "r": "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c9",
-        "s": "6f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"
-      }
-    },
-    {
-      "exception": "Invalid hashType 140",
-      "hashType": 140,
-      "hex": "3044022033a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c902206f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa543422628c",
-      "raw": {
-        "r": "33a69cd2065432a30f3d1ce4eb0d59b8ab58c74f27c41a7fdb5696ad4e6108c9",
-        "s": "6f807982866f785d3f6418d24163ddae117b7db4d5fdf0071de069fa54342262"
-      }
-    }
-  ]
-}
diff --git a/test/fixtures/templates.json b/test/fixtures/templates.json
new file mode 100644
index 0000000..0cba6c6
--- /dev/null
+++ b/test/fixtures/templates.json
@@ -0,0 +1,517 @@
+{
+  "valid": [
+    {
+      "type": "pubkey",
+      "pubKey": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
+      "signature": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+      "output": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 OP_CHECKSIG",
+      "input": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+      "inputHex": "47304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+      "outputHex": "2102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1ac",
+      "inputStack": [
+        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801"
+      ]
+    },
+    {
+      "type": "pubkeyhash",
+      "pubKey": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
+      "signature": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+      "output": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+      "input": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
+      "inputHex": "47304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca28012102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
+      "outputHex": "76a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac",
+      "inputStack": [
+        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+        "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1"
+      ]
+    },
+    {
+      "type": "multisig",
+      "pubKeys": [
+        "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
+        "0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a"
+      ],
+      "signatures": [
+        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+        "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501"
+      ],
+      "output": "OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG",
+      "input": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
+      "inputHex": "0047304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801483045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
+      "outputHex": "522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae",
+      "inputStack": [
+        "",
+        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+        "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501"
+      ]
+    },
+    {
+      "type": "multisig",
+      "pubKeys": [
+        "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+        "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
+        "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34"
+      ],
+      "signatures": [
+        "3045022100fe324541215798b2df68cbd44039615e23c506d4ec1a05572064392a98196b82022068c849fa6699206da2fc6d7848efc1d3804a5816d6293615fe34c1a7f34e1c2f01",
+        "3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901",
+        "3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01"
+      ],
+      "output": "OP_3 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_3 OP_CHECKMULTISIG",
+      "input": "OP_0 3045022100fe324541215798b2df68cbd44039615e23c506d4ec1a05572064392a98196b82022068c849fa6699206da2fc6d7848efc1d3804a5816d6293615fe34c1a7f34e1c2f01 3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901 3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01",
+      "inputHex": "00483045022100fe324541215798b2df68cbd44039615e23c506d4ec1a05572064392a98196b82022068c849fa6699206da2fc6d7848efc1d3804a5816d6293615fe34c1a7f34e1c2f01473044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901483045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01",
+      "outputHex": "53210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817982102b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f84834021024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a3453ae",
+      "inputStack": [
+        "",
+        "3045022100fe324541215798b2df68cbd44039615e23c506d4ec1a05572064392a98196b82022068c849fa6699206da2fc6d7848efc1d3804a5816d6293615fe34c1a7f34e1c2f01",
+        "3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901",
+        "3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01"
+      ]
+    },
+    {
+      "type": "scripthash",
+      "redeemScript": "OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG",
+      "redeemScriptSig": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
+      "input": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501 522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae",
+      "output": "OP_HASH160 722ff0bc2c3f47b35c20df646c395594da24e90e OP_EQUAL",
+      "inputHex": "0047304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801483045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d14050147522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae",
+      "outputHex": "a914722ff0bc2c3f47b35c20df646c395594da24e90e87",
+      "inputStack": [
+        "",
+        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+        "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
+        "522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae"
+      ]
+    },
+    {
+      "type": "witnesspubkeyhash",
+      "pubKey": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1",
+      "signature": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+      "output": "OP_0 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5",
+      "outputHex": "0014aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5",
+      "inputStack": [
+        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+        "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1"
+      ]
+    },
+    {
+      "type": "witnessscripthash",
+      "witnessScript": "OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG",
+      "witnessData": [
+        "",
+        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+        "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501"
+      ],
+      "output": "OP_0 32447752937d355ca2defddcd1f6b4fc53d182f8901cebbcff42f5e381bf0b80",
+      "outputHex": "002032447752937d355ca2defddcd1f6b4fc53d182f8901cebbcff42f5e381bf0b80",
+      "inputStack": [
+        "",
+        "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+        "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
+        "522102359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1210395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a52ae"
+      ]
+    },
+    {
+      "type": "nulldata",
+      "data": "06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474",
+      "output": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474",
+      "outputHex": "6a2606deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474"
+    },
+    {
+      "type": "nulldata",
+      "data": "deadffffffffffffffffffffffffffffffffbeef",
+      "output": "OP_RETURN deadffffffffffffffffffffffffffffffffbeef",
+      "outputHex": "6a14deadffffffffffffffffffffffffffffffffbeef"
+    },
+    {
+      "type": "nonstandard",
+      "typeIncomplete": "multisig",
+      "pubKeys": [
+        "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+        "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
+        "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34"
+      ],
+      "signatures": [
+        null,
+        "3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901",
+        "3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01"
+      ],
+      "input": "OP_0 OP_0 3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901 3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01",
+      "inputHex": "0000473044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901483045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01",
+      "inputStack": [
+        "",
+        "",
+        "3044022001ab168e80b863fdec694350b587339bb72a37108ac3c989849251444d13ebba02201811272023e3c1038478eb972a82d3ad431bfc2408e88e4da990f1a7ecbb263901",
+        "3045022100aaeb7204c17eee2f2c4ff1c9f8b39b79e75e7fbf33e92cc67ac51be8f15b75f90220659eee314a4943a6384d2b154fa5821ef7a084814d7ee2c6f9f7f0ffb53be34b01"
+      ]
+    },
+    {
+      "type": "nonstandard",
+      "typeIncomplete": "multisig",
+      "pubKeys": [
+        "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+        "02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340",
+        "024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34"
+      ],
+      "signatures": [
+        null,
+        null,
+        null
+      ],
+      "input": "OP_0 OP_0 OP_0 OP_0",
+      "inputHex": "00000000",
+      "inputStack": [
+        "",
+        "",
+        "",
+        ""
+      ]
+    },
+    {
+      "type": "scripthash",
+      "redeemScript": "OP_2 0327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a49372 03251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f 02cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde47 OP_3 OP_CHECKMULTISIG",
+      "redeemScriptSig": "OP_0 304502210093efc26facedc5f51e304aa270a7b4f1a911b2d912c3674e5c6e2ad4ac7a410402201cf0b62c240461902f9f16d8a0bc3a210b7bfcd2c06523dd4b4b63be22e8525201",
+      "input": "OP_0 304502210093efc26facedc5f51e304aa270a7b4f1a911b2d912c3674e5c6e2ad4ac7a410402201cf0b62c240461902f9f16d8a0bc3a210b7bfcd2c06523dd4b4b63be22e8525201 52210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753ae",
+      "inputHex": "0048304502210093efc26facedc5f51e304aa270a7b4f1a911b2d912c3674e5c6e2ad4ac7a410402201cf0b62c240461902f9f16d8a0bc3a210b7bfcd2c06523dd4b4b63be22e85252014c6952210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753ae",
+      "output": "OP_HASH160 fcc42dd4aa770d75cb6796bbd7853a325e746659 OP_EQUAL",
+      "outputHex": "a914fcc42dd4aa770d75cb6796bbd7853a325e74665987"
+    },
+    {
+      "type": "nonstandard",
+      "typeIncomplete": "scripthash",
+      "pubKeys": [
+        "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
+        "04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a"
+      ],
+      "signatures": [
+        null,
+        "30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801"
+      ],
+      "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
+      "redeemScriptSig": "OP_0 OP_0 30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801",
+      "input": "OP_0 OP_0 30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae",
+      "inputHex": "00004830450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a8014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae",
+      "inputStack": [
+        "",
+        "",
+        "30450221009c92c1ae1767ac04e424da7f6db045d979b08cde86b1ddba48621d59a109d818022004f5bb21ad72255177270abaeb2d7940ac18f1e5ca1f53db4f3fd1045647a8a801",
+        "52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
+      ]
+    },
+    {
+      "type": "nonstandard",
+      "output": "OP_HASH256 6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000 OP_EQUAL",
+      "outputHex": "aa206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000087"
+    },
+    {
+      "type": "nonstandard",
+      "output": "OP_0 OP_0 OP_0 OP_CHECKMULTISIG",
+      "outputHex": "000000ae"
+    },
+    {
+      "type": "nonstandard",
+      "output": "OP_0",
+      "outputHex": "00"
+    },
+    {
+      "type": "nonstandard",
+      "input": "OP_0 00",
+      "inputHex": "000100",
+      "inputStack": [
+        "",
+        "00"
+      ]
+    },
+    {
+      "type": "nonstandard",
+      "input": "OP_6",
+      "inputHex": "56",
+      "nonstandard": {
+        "input": "06",
+        "inputHex": "0106"
+      },
+      "inputStack": [
+        "06"
+      ]
+    },
+    {
+      "type": "nonstandard",
+      "input": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+      "inputHex": "4cff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+      "inputStack": [
+        "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+      ]
+    }
+  ],
+  "invalid": {
+    "pubKey": {
+      "inputs": [
+        {
+          "description": "non-canonical signature (too short)",
+          "input": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf7593"
+        },
+        {
+          "description": "non-canonical signature (too long)",
+          "input": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca28ffffffff01"
+        },
+        {
+          "description": "non-canonical signature (invalid hashType)",
+          "input": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca28ff"
+        }
+      ],
+      "outputs": [
+        {
+          "description": "non-canonical pubkey (too short)",
+          "output": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce OP_CHECKSIG"
+        },
+        {
+          "description": "non-canonical pubkey (too long)",
+          "output": "02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1ffffff OP_CHECKSIG"
+        },
+        {
+          "description": "last operator is wrong for pubkey-output",
+          "outputHex": "21027a71801ab59336de37785c50005b6abd8ea859eecce1edbe8e81afa74ee5c752ae"
+        },
+        {
+          "description": "missing OP_CHECKSIG",
+          "outputHex": "21027a71801ab59336de37785c50005b6abd8ea859eecce1edbe8e81afa74ee5c752"
+        },
+        {
+          "description": "non-canonical pubkey (bad prefix)",
+          "output": "427a71801ab59336de37785c50005b6abd8ea859eecce1edbe8e81afa74ee5c752 OP_CHECKSIG"
+        },
+        {
+          "description": "has extra opcode at the end isPubKeyOutput",
+          "output": "027a71801ab59336de37785c50005b6abd8ea859eecce1edbe8e81afa74ee5c752 OP_CHECKSIG OP_0"
+        }
+      ]
+    },
+    "pubKeyHash": {
+      "inputs": [
+        {
+          "description": "pubKeyHash input : extraneous data",
+          "input": "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 ffffffff"
+        }
+      ],
+      "outputs": [
+        {
+          "description": "non-minimal encoded isPubKeyHashOutput (non BIP62 compliant)",
+          "outputHex": "76a94c14aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac"
+        },
+        {
+          "description": "bad OP_DUP isPubKeyHashOutput",
+          "outputHex": "aca914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac"
+        },
+        {
+          "description": "bad OP_HASH160 isPubKeyHashOutput",
+          "outputHex": "76ac14aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac"
+        },
+        {
+          "description": "bad OP_EQUALVERIFY isPubKeyHashOutput",
+          "outputHex": "76a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5acac"
+        },
+        {
+          "description": "bad OP_CHECKSIG isPubKeyHashOutput",
+          "outputHex": "76a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c58888"
+        },
+        {
+          "description": "bad length isPubKeyHashOutput",
+          "outputHex": "76a920aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac"
+        },
+        {
+          "description": "has something at the end isPubKeyHashOutput",
+          "outputHex": "76a920aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00"
+        },
+        {
+          "exception": "Expected Buffer\\(Length: 20\\), got Buffer\\(Length: 2\\)",
+          "hash": "ffff"
+        }
+      ]
+    },
+    "scriptHash": {
+      "inputs": [
+        {
+          "description": "redeemScript not data",
+          "input": "OP_0 304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801 3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501 OP_RESERVED"
+        },
+        {
+          "description": "redeemScript is a signature, therefore not a valid script",
+          "input": "OP_0 3045022100e12b17b3a4c80c401a1687487bd2bafee9e5f1f8f1ffc6180ce186672ad7b43a02205e316d1e5e71822f5ef301b694e578fa9c94af4f5f098c952c833f4691307f4e01"
+        }
+      ],
+      "outputs": [
+        {
+          "description": "non-minimal encoded isScriptHashOutput (non BIP62 compliant)",
+          "outputHex": "a94c14c286a1af0947f58d1ad787385b1c2c4a976f9e7187"
+        },
+        {
+          "description": "wrong OP_HASH160 opcode",
+          "outputHex": "ac4c14c286a1af0947f58d1ad787385b1c2c4a976f9e7187"
+        },
+        {
+          "description": "wrong length marker",
+          "outputHex": "a916c286a1af0947f58d1ad787385b1c2c4a976f9e7187"
+        },
+        {
+          "description": "wrong OP_EQUAL opcode",
+          "outputHex": "a914c286a1af0947f58d1ad787385b1c2c4a976f9e7188"
+        },
+        {
+          "exception": "Expected Buffer\\(Length: 20\\), got Buffer\\(Length: 3\\)",
+          "hash": "ffffff"
+        }
+      ]
+    },
+    "multisig": {
+      "inputs": [
+        {
+          "description": "Not enough signatures provided",
+          "type": "multisig",
+          "output": "OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_CHECKMULTISIG",
+          "signatures": []
+        },
+        {
+          "exception": "Not enough signatures provided",
+          "output": "OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG",
+          "signatures": [
+            "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801"
+          ]
+        },
+        {
+          "exception": "Too many signatures provided",
+          "output": "OP_2 02359c6e3f04cefbf089cf1d6670dc47c3fb4df68e2bad1fa5a369f9ce4b42bbd1 0395a9d84d47d524548f79f435758c01faec5da2b7e551d3b8c995b7e06326ae4a OP_2 OP_CHECKMULTISIG",
+          "signatures": [
+            "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801",
+            "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501",
+            "3045022100ef253c1faa39e65115872519e5f0a33bbecf430c0f35cf562beabbad4da24d8d02201742be8ee49812a73adea3007c9641ce6725c32cd44ddb8e3a3af460015d140501"
+          ]
+        }
+      ],
+      "outputs": [
+        {
+          "description": "OP_CHECKMULTISIG not found",
+          "output": "OP_0 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_HASH160"
+        },
+        {
+          "description": "less than 4 chunks",
+          "output": "OP_0 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 OP_HASH160"
+        },
+        {
+          "description": "m === 0",
+          "output": "OP_0 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_CHECKMULTISIG"
+        },
+        {
+          "description": "m < OP_1",
+          "output": "OP_1NEGATE 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_CHECKMULTISIG"
+        },
+        {
+          "description": "m > OP_16",
+          "output": "OP_NOP 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_2 OP_CHECKMULTISIG"
+        },
+        {
+          "description": "n === 0",
+          "output": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_0 OP_CHECKMULTISIG"
+        },
+        {
+          "description": "n < OP_1",
+          "output": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_1NEGATE OP_CHECKMULTISIG"
+        },
+        {
+          "description": "n > OP_16",
+          "output": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_NOP OP_CHECKMULTISIG"
+        },
+        {
+          "description": "n < m",
+          "output": "OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 OP_1 OP_CHECKMULTISIG"
+        },
+        {
+          "description": "n < len(pubKeys)",
+          "output": "OP_2 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 02b80011a883a0fd621ad46dfc405df1e74bf075cbaf700fd4aebef6e96f848340 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_2 OP_CHECKMULTISIG"
+        },
+        {
+          "description": "n > len(pubKeys)",
+          "output": "OP_1 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_2 OP_CHECKMULTISIG"
+        },
+        {
+          "description": "m is data",
+          "output": "ffff 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 OP_1 OP_CHECKMULTISIG"
+        },
+        {
+          "description": "n is data",
+          "output": "OP_1 024289801366bcee6172b771cf5a7f13aaecd237a0b9a1ff9d769cabc2e6b70a34 ffff OP_CHECKMULTISIG"
+        },
+        {
+          "description": "non-canonical pubKey (bad length)",
+          "output": "OP_1 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffff OP_1 OP_CHECKMULTISIG"
+        },
+        {
+          "exception": "Not enough pubKeys provided",
+          "m": 4,
+          "pubKeys": [
+            "02ea1297665dd733d444f31ec2581020004892cdaaf3dd6c0107c615afb839785f",
+            "02fab2dea1458990793f56f42e4a47dbf35a12a351f26fa5d7e0cc7447eaafa21f",
+            "036c6802ce7e8113723dd92cdb852e492ebb157a871ca532c3cb9ed08248ff0e19"
+          ],
+          "signatures": [
+            "304402207515cf147d201f411092e6be5a64a6006f9308fad7b2a8fdaab22cd86ce764c202200974b8aca7bf51dbf54150d3884e1ae04f675637b926ec33bf75939446f6ca2801"
+          ]
+        }
+      ]
+    },
+    "witnessPubKeyHash": {
+      "inputs": [],
+      "outputs": [
+        {
+          "description": "wrong version",
+          "outputHex": "51149090909090909090909090909090909090909090"
+        },
+        {
+          "description": "wrong length marker",
+          "outputHex": "00209090909090909090909090909090909090909090"
+        },
+        {
+          "exception": "Expected Buffer\\(Length: 20\\), got Buffer\\(Length: 3\\)",
+          "hash": "ffffff"
+        }
+      ]
+    },
+    "witnessScriptHash": {
+      "inputs": [],
+      "outputs": [
+        {
+          "description": "wrong version",
+          "outputHex": "51209090909090909090909090909090909090909090909090909090909090909090"
+        },
+        {
+          "description": "wrong length marker",
+          "outputHex": "00219090909090909090909090909090909090909090909090909090909090909090"
+        },
+        {
+          "exception": "Expected Buffer\\(Length: 32\\), got Buffer\\(Length: 3\\)",
+          "hash": "ffffff"
+        }
+      ]
+    },
+    "witnessCommitment": {
+      "inputs": [],
+      "outputs": [
+        {
+          "exception": "",
+          "commitment": "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd"
+        },
+        {
+          "description": "wrong OPCODE at the start",
+          "scriptPubKeyHex": "6024aa21a9ed4db4fb830efe3e804337413ffe8ad7393af301e0ec8e71b6e6f2b860a56f4dcd"
+        },
+        {
+          "description": "wrong length marker",
+          "scriptPubKeyHex": "6a23aa21a9ed4db4fb830efe3e804337413ffe8ad7393af301e0ec8e71b6e6f2b860a56f4dcd"
+        },
+        {
+          "description": "commitment of wrong length",
+          "scriptPubKeyHex": "6a23aa21a9ed4db4fb830efe3e804337413ffe8ad7393af301e0ec8e71b6e6f2b860a56f4d"
+        }
+      ]
+    }
+  }
+}
diff --git a/test/fixtures/transaction.json b/test/fixtures/transaction.json
index 979549a..6bf6090 100644
--- a/test/fixtures/transaction.json
+++ b/test/fixtures/transaction.json
@@ -808,87 +808,6 @@
       "value": 987654321
     }
   ],
-  "taprootSigning": [
-    {
-      "description": "P2TR key path",
-      "utxos": [
-        {
-          "scriptHex": "512053a1f6e454df1aa2776a2814a721372d6258050de330b3c6d10ee8f4e0dda343",
-          "value": 420000000
-        },
-        {
-          "scriptHex": "5120147c9c57132f6e7ecddba9800bb0c4449251c92a1e60371ee77557b6620f3ea3",
-          "value": 462000000
-        },
-        {
-          "scriptHex": "76a914751e76e8199196d454941c45d1b3a323f1433bd688ac",
-          "value": 294000000
-        },
-        {
-          "scriptHex": "5120e4d810fd50586274face62b8a807eb9719cef49c04177cc6b76a9a4251d5450e",
-          "value": 504000000
-        },
-        {
-          "scriptHex": "512091b64d5324723a985170e4dc5a0f84c041804f2cd12660fa5dec09fc21783605",
-          "value": 630000000
-        },
-        {
-          "scriptHex": "00147dd65592d0ab2fe0d0257d571abf032cd9db93dc",
-          "value": 378000000
-        },
-        {
-          "scriptHex": "512075169f4001aa68f15bbed28b218df1d0a62cbbcf1188c6665110c293c907b831",
-          "value": 672000000
-        },
-        {
-          "scriptHex": "51200f63ca2c7639b9bb4be0465cc0aa3ee78a0761ba5f5f7d6ff8eab340f09da561",
-          "value": 546000000
-        },
-        {
-          "scriptHex": "5120053690babeabbb7850c32eead0acf8df990ced79f7a31e358fabf2658b4bc587",
-          "value": 588000000
-        }
-      ],
-      "txHex": "02000000097de20cbff686da83a54981d2b9bab3586f4ca7e48f57f5b55963115f3b334e9c010000000000000000d7b7cab57b1393ace2d064f4d4a2cb8af6def61273e127517d44759b6dafdd990000000000fffffffff8e1f583384333689228c5d28eac13366be082dc57441760d957275419a418420000000000fffffffff0689180aa63b30cb162a73c6d2a38b7eeda2a83ece74310fda0843ad604853b0100000000feffffff0c638ca38362001f5e128a01ae2b379288eb22cfaf903652b2ec1c88588f487a0000000000feffffff956149bdc66faa968eb2be2d2faa29718acbfe3941215893a2a3446d32acd05000000000000000000081efa267f1f0e46e054ecec01773de7c844721e010c2db5d5864a6a6b53e013a010000000000000000a690669c3c4a62507d93609810c6de3f99d1a6e311fe39dd23683d695c07bdee0000000000ffffffff727ab5f877438496f8613ca84002ff38e8292f7bd11f0a9b9b83ebd16779669e0100000000ffffffff0200ca9a3b000000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac807840cb0000000020ac9a87f5594be208f8532db38cff670c450ed2fea8fcdefcc9a663f78bab962b0065cd1d",
-      "cases": [
-        {
-          "vin": 0,
-          "typeHex": "03",
-          "hash": "7e584883b084ace0469c6962a9a7d2a9060e1f3c218ab40d32c77651482122bc"
-        },
-        {
-          "vin": 1,
-          "typeHex": "83",
-          "hash": "325a644af47e8a5a2591cda0ab0723978537318f10e6a63d4eed783b96a71a4d"
-        },
-        {
-          "vin": 3,
-          "typeHex": "01",
-          "hash": "6ffd256e108685b41831385f57eebf2fca041bc6b5e607ea11b3e03d4cf9d9ba"
-        },
-        {
-          "vin": 4,
-          "typeHex": "00",
-          "hash": "9f90136737540ccc18707e1fd398ad222a1a7e4dd65cbfd22dbe4660191efa58"
-        },
-        {
-          "vin": 6,
-          "typeHex": "02",
-          "hash": "835c9ab6084ed9a8ae9b7cda21e0aa797aca3b76a54bd1e3c7db093f6c57e23f"
-        },
-        {
-          "vin": 7,
-          "typeHex": "82",
-          "hash": "df1cca638283c667084b8ffe6bf6e116cc5a53cf7ae1202c5fee45a9085f1ba5"
-        },
-        {
-          "vin": 8,
-          "typeHex": "81",
-          "hash": "30319859ca79ea1b7a9782e9daebc46e4ca4ca2bc04c9c53b2ec87fa83a526bd"
-        }
-      ]
-    }
-  ],
   "invalid": {
     "addInput": [
       {
diff --git a/test/fixtures/transaction_builder.json b/test/fixtures/transaction_builder.json
new file mode 100644
index 0000000..1475c97
--- /dev/null
+++ b/test/fixtures/transaction_builder.json
@@ -0,0 +1,2267 @@
+{
+  "valid": {
+    "build": [
+      {
+        "description": "Transaction w/ P2PKH -> P2PKH",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000006b483045022100a3b254e1c10b5d039f36c05f323995d6e5a367d98dd78a13d5bbc3991b35720e022022fccea3897d594de0689601fbd486588d5bfa6915be2386db0397ee9a6e80b601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2PK -> P2PKH",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000494830450221009833abb3ab49d7004c06bcc79eafd6905ada3eee91f3376ad388548034acd9a702202e84dda6ef2678c82256afcfc459aaa68e179b2bb0e6b2dc3f1410e132c5e6c301ffffffff0100f90295000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "prevTxScript": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 OP_CHECKSIG",
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 2500000000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2SH(P2PKH) -> P2PKH",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000085483045022100a3b254e1c10b5d039f36c05f323995d6e5a367d98dd78a13d5bbc3991b35720e022022fccea3897d594de0689601fbd486588d5bfa6915be2386db0397ee9a6e80b601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817981976a914751e76e8199196d454941c45d1b3a323f1433bd688acffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
+                "redeemScript": "OP_DUP OP_HASH160 751e76e8199196d454941c45d1b3a323f1433bd6 OP_EQUALVERIFY OP_CHECKSIG"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2SH(P2MS 2/2) -> P2PKH",
+        "network": "testnet",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000fd1b0100483045022100b7a9bab60c4307349de9571ce0bd26ebb9d68d4e9ab3f9173e1f736f1390a04a022020931ff70e87033cdd94bdf434e865993b2258065c5c222a53f29d077bcfa4480147304402206d79ad83f1ab12fc9feee9e66412de842fcbf8de0632beb4433d469f24f0fb4e022079e6df186582f2686a3292bde8e50dac36cb9bec3991995fe331e1daef7df8a4014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0110270000000000001976a914faf1d99bf040ea9c7f8cc9f14ac6733ad75ce24688ac00000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+                "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG"
+              },
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 faf1d99bf040ea9c7f8cc9f14ac6733ad75ce246 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2MS 2/2 -> P2PKH",
+        "network": "testnet",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000009200483045022100b7a9bab60c4307349de9571ce0bd26ebb9d68d4e9ab3f9173e1f736f1390a04a022020931ff70e87033cdd94bdf434e865993b2258065c5c222a53f29d077bcfa4480147304402206d79ad83f1ab12fc9feee9e66412de842fcbf8de0632beb4433d469f24f0fb4e022079e6df186582f2686a3292bde8e50dac36cb9bec3991995fe331e1daef7df8a401ffffffff0110270000000000001976a914faf1d99bf040ea9c7f8cc9f14ac6733ad75ce24688ac00000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "prevTxScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
+            "signs": [
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx"
+              },
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 faf1d99bf040ea9c7f8cc9f14ac6733ad75ce246 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2MS 2/3 -> P2PKH",
+        "network": "testnet",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000910047304402206b2fc7d3182e2853cab5bcffb85c3ef5470d2d05c496295538c9947af3bfd0ec0220300aa705a985c74f76c26c6d68da9b61b5c4cd5432e8c6a54623f376c8bf8cde01473044022031059c4dd6a97d84e3a4eb1ca21a9870bd1762fbd5db7c1932d75e56da78794502200f22d85be3c5f7035e89a147ee2619a066df19aff14a62e6bb3f649b6da19edf01ffffffff0110270000000000001976a914faf1d99bf040ea9c7f8cc9f14ac6733ad75ce24688ac00000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "prevTxScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG",
+            "signs": [
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx"
+              },
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 faf1d99bf040ea9c7f8cc9f14ac6733ad75ce246 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2MS 2/2 (reverse order) -> P2PKH",
+        "network": "testnet",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000009200483045022100b7a9bab60c4307349de9571ce0bd26ebb9d68d4e9ab3f9173e1f736f1390a04a022020931ff70e87033cdd94bdf434e865993b2258065c5c222a53f29d077bcfa4480147304402206d79ad83f1ab12fc9feee9e66412de842fcbf8de0632beb4433d469f24f0fb4e022079e6df186582f2686a3292bde8e50dac36cb9bec3991995fe331e1daef7df8a401ffffffff0110270000000000001976a914faf1d99bf040ea9c7f8cc9f14ac6733ad75ce24688ac00000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "prevTxScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
+            "signs": [
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT"
+              },
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 faf1d99bf040ea9c7f8cc9f14ac6733ad75ce246 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2SH(P2MS 2/3)",
+        "network": "testnet",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000fd5e0100483045022100eec19e061cad41610f9b42d2b06638b6b0fec3da0de9c6858e7f8c06053979900220622936dd47e202b2ad17639cda680e52334d407149252959936bb1f38e4acc52014830450221009aac215157a74a18234fd06be27448dccee809986bbf93be457a9262f0c69a9402203ff41d7c757f0e8951e4471f205087ecff499f986400ab18210eaad9a628e33c014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+                "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG"
+              },
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2SH(P2MS 2/3), different hash types",
+        "network": "testnet",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000fd5e0100483045022100eec19e061cad41610f9b42d2b06638b6b0fec3da0de9c6858e7f8c06053979900220622936dd47e202b2ad17639cda680e52334d407149252959936bb1f38e4acc5201483045022100d404fb6de6cf42efb9d7948d2e8fb6618f8eba55ecd25907d18d576d9aa6f39d02205ec2e7fa7c5f8a9793732ca9d2f9aba3b2bb04ca6d467ba36940e0f695e48de5024cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+                "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG",
+                "hashType": 1
+              },
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
+                "hashType": 2
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2SH(P2PK) -> P2PKH",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000006c47304402201115644b134932c8a7a8e925769d130a801288d477130e2bf6fadda20b33754d02202ecefbf63844d7cb2d5868539c39f973fe019f72e5c31a707836c0d61ef317db012321033e29aea1168a835d5e386c292082db7b7807172a10ec634ad34226f36d79e70facffffffff0100f90295000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "prevTxScript": "OP_HASH160 e89677d91455e541630d62c63718bef738b478b1 OP_EQUAL",
+            "signs": [
+              {
+                "keyPair": "KxLDMPtVM7sLSu2v5n1LybDibw6P9FFbL4pUwJ51UDm7rp5AmXWW",
+                "redeemScript": "033e29aea1168a835d5e386c292082db7b7807172a10ec634ad34226f36d79e70f OP_CHECKSIG"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 2500000000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ non-zero vin inputs",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000006a47304402205c80bbb5125b35d5e5a8324b1336832d29a6fc004859c8a9ff6bef47ba7fc348022018612216e57a521b2c4543f1f4fd738a76814c37c074e88adfe12464fff31cf901210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ non-default input sequence numbers, version and locktime",
+        "txHex": "0400000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000006a47304402200e7c0330f39c04e3c1b9e3daf71d106c7129c095f6ebb494d06f0ef8013b74ea022003fc0fe05e71a2a4f8434feb0632cdb6883676d0ccb9b19d7a8a9e5fc02a616401210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798b9c220000110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac09990400",
+        "version": 4,
+        "locktime": 301321,
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 2,
+            "sequence": 2147001,
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ nLockTime, P2PKH -> P2PKH",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000006b483045022100e31ef1bcc6f060cb6a53675a11606b9180f4f8b1ec823113fb4c0bf1c5b99b8e02204234690c19cd89e544002d26dbcbd49bf9d1b4cfc5a617fd8ab2607acfd869b001210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588acffff0000",
+        "locktime": 65535,
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ 1 P2PKH transaction input (Issue #644)",
+        "network": "testnet",
+        "txHex": "010000000132595835c74fccf097db4ccae9dc2de621e58e0d3f697a27b469b61c7a223b39000000006a47304402202fd41f18f1d7915bc811610236e1d708f9cd3515734abd5db7ac607f030728af02206bee7d163f04c470ce55561523824eb8b3abce80c214aabf7dfb78a073ea4a70012103f29374a4c2c218a4077db9ba0b9d674cde3719560460af4eb3190d512dd5de92ffffffff01808d5b00000000001976a914ff99e06c1a4ac394b4e1cb3d3a4b2b47749e339a88ac00000000",
+        "inputs": [
+          {
+            "txHex": "0100000001f7e6430096cd2790bac115aaab22c0a50fb0a1794305302e1a399e81d8d354f4020000006a47304402205793a862d193264afc32713e2e14541e1ff9ebb647dd7e7e6a0051d0faa87de302205216653741ecbbed573ea2fc053209dd6980616701c27be5b958a159fc97f45a012103e877e7deb32d19250dcfe534ea82c99ad739800295cd5429a7f69e2896c36fcdfeffffff0340420f00000000001976a9145c7b8d623fba952d2387703d051d8e931a6aa0a188ac8bda2702000000001976a9145a0ef60784137d03e7868d063b05424f2f43799f88ac40420f00000000001976a9145c7b8d623fba952d2387703d051d8e931a6aa0a188ac2fcc0e00",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "cQ6483mDWwoG8o4tn6nU9Jg52RKMjPUWXSY1vycAyPRXQJ1Pn2Rq"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 ff99e06c1a4ac394b4e1cb3d3a4b2b47749e339a OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 6000000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2PKH -> P2WPKH",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000006b4830450221009a524a3257b8bd0c77ba4cba65fc00954f2030243f2eb16571838a3b951c8c07022008f5af9de672b365fd257377db1cf6da4da1b49b9637ceb651ac0eb4181dc3ca01210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff011027000000000000160014aa4d7985c57e011a8b3dd8e0e5a73aaef41629c500000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_0 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2PKH -> P2WSH",
+        "txHex": "0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000006a473044022056c99ba23eb15b3e666b188f87b04d5ef23eeda5298939cdaec35a3bddf3835602205887a5a460f299819b0c93948fafab8b2d64d8c051934431e3bb9acebef5d1b001210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff01102700000000000022002032447752937d355ca2defddcd1f6b4fc53d182f8901cebbcff42f5e381bf0b8000000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_0 32447752937d355ca2defddcd1f6b4fc53d182f8901cebbcff42f5e381bf0b80",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2WPKH -> P2WPKH",
+        "txHex": "01000000000101ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff011027000000000000160014aa4d7985c57e011a8b3dd8e0e5a73aaef41629c502483045022100a8fc5e4c6d7073474eff2af5d756966e75be0cdfbba299518526080ce8b584be02200f26d41082764df89e3c815b8eaf51034a3b68a25f1be51208f54222c1bb6c1601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179800000000",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "prevTxScript": "OP_0 751e76e8199196d454941c45d1b3a323f1433bd6",
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
+                "value": 10000
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_0 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2WSH(P2PK) -> P2PKH",
+        "txHex": "010000000001014533a3bc1e039bd787656068e135aaee10aee95a64776bfc047ee6a7c1ebdd2f0000000000ffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac02473044022039725bb7291a14dd182dafdeaf3ea0d5c05c34f4617ccbaa46522ca913995c4e02203b170d072ed2e489e7424ad96d8fa888deb530be2d4c5d9aaddf111a7efdb2d3012321038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2bac00000000",
+        "inputs": [
+          {
+            "txId": "2fddebc1a7e67e04fc6b77645ae9ae10eeaa35e168606587d79b031ebca33345",
+            "vout": 0,
+            "prevTxScript": "OP_0 0f9ea7bae7166c980169059e39443ed13324495b0d6678ce716262e879591210",
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "witnessScript": "038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b OP_CHECKSIG",
+                "value": 80000
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 60000
+          }
+        ]
+      },
+      {
+        "description": "Sighash: SINGLE (random)",
+        "txHex": "01000000012ffb29d53528ad30c37c267fbbeda3c6fce08f5f6f5d3b1eab22193599a3612a010000006b483045022100f963f1d9564075a934d7c3cfa333bd1378859b84cba947e149926fc9ec89b5ae02202b5b912e507bae65002aff972f9752e2aeb2e22c5fdbaaad672090378184df37032102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff0260a62f01000000001976a9140de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b888ac80969800000000001976a91454d0e925d5ee0ee26768a237067dee793d01a70688ac00000000",
+        "inputs": [
+          {
+            "txId": "2a61a399351922ab1e3b5d6f5f8fe0fcc6a3edbb7f267cc330ad2835d529fb2f",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 3,
+                "value": 30000000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 19900000,
+            "script": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 10000000,
+            "script": "OP_DUP OP_HASH160 54d0e925d5ee0ee26768a237067dee793d01a706 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ]
+      },
+      {
+        "description": "Sighash: ALL",
+        "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006a47304402206abb0622b8b6ca83f1f4de84830cf38bf4615dc9e47a7dcdcc489905f26aa9cb02201d2d8a7815242b88e4cd66390ca46da802238f9b1395e0d118213d30dad38184012102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006b483045022100de13b42804f87a09bb46def12ab4608108d8c2db41db4bc09064f9c46fcf493102205e5c759ab7b2895c9b0447e56029f6895ff7bb20e0847c564a88a3cfcf080c4f012102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006b4830450221009100a3f5b30182d1cb0172792af6947b6d8d42badb0539f2c209aece5a0628f002200ae91702ca63347e344c85fcb536f30ee97b75cdf4900de534ed5e040e71a548012102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000",
+        "inputs": [
+          {
+            "txId": "043f61697d1b48d69394879a3e94a2957a7d1a21a38df2ddd6de45a3b2f0b77d",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 1,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "txId": "057ef664f0e1108f270729e53a62e4cb1a7480d9a87f543c6a1a785a1e492c65",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 1,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "txId": "35db95c66634c3497a277c1f08ed71a0cb53195ffecbf9798cdde4a30f27fab9",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 1,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 20000,
+            "script": "OP_DUP OP_HASH160 9ed1f577c60e4be1dbf35318ec12f51d25e85773 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 30000,
+            "script": "OP_DUP OP_HASH160 fb407e88c48921d5547d899e18a7c0a36919f54d OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 50000,
+            "script": "OP_DUP OP_HASH160 04ccb4eed8cfa9f6e394e945178960f5ccddb387 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ]
+      },
+      {
+        "description": "Sighash: ALL | ANYONECANPAY",
+        "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006b483045022100bd2829550e9b3a081747281029b5f5a96bbd83bb6a92fa2f8310f1bd0d53abc90220071b469417c55cdb3b04171fd7900d2768981b7ab011553d84d24ea85d277079812102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006a47304402206295e17c45c6356ffb20365b696bcbb869db7e8697f4b8a684098ee2bff85feb02202905c441abe39ec9c480749236b84fdd3ebd91ecd25b559136370aacfcf2815c812102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006b483045022100f58e7c98ac8412944d575bcdece0e5966d4018f05988b5b60b6f46b8cb7a543102201c5854d3361e29b58123f34218cec2c722f5ec7a08235ebd007ec637b07c193a812102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000",
+        "inputs": [
+          {
+            "txId": "043f61697d1b48d69394879a3e94a2957a7d1a21a38df2ddd6de45a3b2f0b77d",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 129,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "txId": "057ef664f0e1108f270729e53a62e4cb1a7480d9a87f543c6a1a785a1e492c65",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 129,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "txId": "35db95c66634c3497a277c1f08ed71a0cb53195ffecbf9798cdde4a30f27fab9",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 129,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 20000,
+            "script": "OP_DUP OP_HASH160 9ed1f577c60e4be1dbf35318ec12f51d25e85773 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 30000,
+            "script": "OP_DUP OP_HASH160 fb407e88c48921d5547d899e18a7c0a36919f54d OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 50000,
+            "script": "OP_DUP OP_HASH160 04ccb4eed8cfa9f6e394e945178960f5ccddb387 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ]
+      },
+      {
+        "description": "Sighash: SINGLE",
+        "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006b483045022100e822f152bb15a1d623b91913cd0fb915e9f85a8dc6c26d51948208bbc0218e800220255f78549d9614c88eac9551429bc00224f22cdcb41a3af70d52138f7e98d333032102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006a47304402206f37f79adeb86e0e2da679f79ff5c3ba206c6d35cd9a21433f0de34ee83ddbc00220118cabbac5d83b3aa4c2dc01b061e4b2fe83750d85a72ae6a1752300ee5d9aff032102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006a473044022042ac843d220a56b3de05f24c85a63e71efa7e5fc7c2ec766a2ffae82a88572b0022051a816b317313ea8d90010a77c3e02d41da4a500e67e6a5347674f836f528d82032102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000",
+        "inputs": [
+          {
+            "txId": "043f61697d1b48d69394879a3e94a2957a7d1a21a38df2ddd6de45a3b2f0b77d",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 3,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "txId": "057ef664f0e1108f270729e53a62e4cb1a7480d9a87f543c6a1a785a1e492c65",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 3,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "txId": "35db95c66634c3497a277c1f08ed71a0cb53195ffecbf9798cdde4a30f27fab9",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 3,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 20000,
+            "script": "OP_DUP OP_HASH160 9ed1f577c60e4be1dbf35318ec12f51d25e85773 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 30000,
+            "script": "OP_DUP OP_HASH160 fb407e88c48921d5547d899e18a7c0a36919f54d OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 50000,
+            "script": "OP_DUP OP_HASH160 04ccb4eed8cfa9f6e394e945178960f5ccddb387 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ]
+      },
+      {
+        "description": "Sighash: SINGLE|ANYONECANPAY",
+        "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006b483045022100d05a3b6cf2f0301000b0e45c09054f2c61570ce8798ebf571eef72da3b1c94a1022016d7ef3c133fa703bae2c75158ea08d335ac698506f99b3c369c37a9e8fc4beb832102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006b483045022100ee6bf07b051001dcbfa062692a40adddd070303286b714825b3fb4693dd8fcdb022056610885e5053e5d47f2be3433051305abe7978ead8f7cf2d0368947aff6b307832102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006b483045022100cfc930d5b5272d0220d9da98fabec97b9e66306f735efa837f43f6adc675cad902202f9dff76b8b9ec8f613d46094f17f64d875804292d8804aa59fd295b6fc1416b832102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000",
+        "inputs": [
+          {
+            "txId": "043f61697d1b48d69394879a3e94a2957a7d1a21a38df2ddd6de45a3b2f0b77d",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 131,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "txId": "057ef664f0e1108f270729e53a62e4cb1a7480d9a87f543c6a1a785a1e492c65",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 131,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "txId": "35db95c66634c3497a277c1f08ed71a0cb53195ffecbf9798cdde4a30f27fab9",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 131,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 20000,
+            "script": "OP_DUP OP_HASH160 9ed1f577c60e4be1dbf35318ec12f51d25e85773 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 30000,
+            "script": "OP_DUP OP_HASH160 fb407e88c48921d5547d899e18a7c0a36919f54d OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 50000,
+            "script": "OP_DUP OP_HASH160 04ccb4eed8cfa9f6e394e945178960f5ccddb387 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ]
+      },
+      {
+        "description": "Sighash: NONE",
+        "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006b483045022100e7f0a1ddd2c0b81e093e029b8a503afa27fe43549b0668d2141abf35eb3a63be022037f12d12cd50fc94a135f933406a8937557de9b9566a8841ff1548c1b6984531022102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006a473044022008451123ec2535dab545ade9d697519e63b28df5e311ea05e0ce28d39877a7c8022061ce5dbfb7ab478dd9e05b0acfd959ac3eb2641f61958f5d352f37621073d7c0022102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006a47304402205c001bcdfb35c70d8aa3bdbc75399afb72eb7cf1926ca7c1dfcddcb4d4d3e0f8022028992fffdcd4e9f34ab726f97c24157917641c2ef99361f588e3d4147d46eea5022102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000",
+        "inputs": [
+          {
+            "txId": "043f61697d1b48d69394879a3e94a2957a7d1a21a38df2ddd6de45a3b2f0b77d",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 2,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "txId": "057ef664f0e1108f270729e53a62e4cb1a7480d9a87f543c6a1a785a1e492c65",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 2,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "txId": "35db95c66634c3497a277c1f08ed71a0cb53195ffecbf9798cdde4a30f27fab9",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 2,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 20000,
+            "script": "OP_DUP OP_HASH160 9ed1f577c60e4be1dbf35318ec12f51d25e85773 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 30000,
+            "script": "OP_DUP OP_HASH160 fb407e88c48921d5547d899e18a7c0a36919f54d OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 50000,
+            "script": "OP_DUP OP_HASH160 04ccb4eed8cfa9f6e394e945178960f5ccddb387 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ]
+      },
+      {
+        "description": "Sighash: NONE | ANYONECANPAY",
+        "txHex": "01000000037db7f0b2a345ded6ddf28da3211a7d7a95a2943e9a879493d6481b7d69613f04010000006a47304402204ed272952177aaa5a1b171c2ca5a7a3d300ffcd7e04b040c0baaa4e3561862a502207e65a5b8f99c8a632b186c8a60496a12bf3116f51909b7497413aefdc3be7bf6822102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff652c491e5a781a6a3c547fa8d980741acbe4623ae52907278f10e1f064f67e05000000006a47304402203ec365300cc67602f4cc5be027959d3667b48db34c6c87d267c94a7e210d5c1f02204843350311c0a9711cad1960b17ce9e323a1ce6f37deefc3ffe63082d480be92822102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffffb9fa270fa3e4dd8c79f9cbfe5f1953cba071ed081f7c277a49c33466c695db35000000006b48304502210084f86f905c36372eff9c54ccd509a519a3325bcace8abfeed7ed3f0d579979e902201ff330dd2402e5ca9989a8a294fa36d6cf3a093edb18d29c9d9644186a3efeb4822102f1c7eac9200f8dee7e34e59318ff2076c8b3e3ac7f43121e57569a1aec1803d4ffffffff03204e0000000000001976a9149ed1f577c60e4be1dbf35318ec12f51d25e8577388ac30750000000000001976a914fb407e88c48921d5547d899e18a7c0a36919f54d88ac50c30000000000001976a91404ccb4eed8cfa9f6e394e945178960f5ccddb38788ac00000000",
+        "inputs": [
+          {
+            "txId": "043f61697d1b48d69394879a3e94a2957a7d1a21a38df2ddd6de45a3b2f0b77d",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 130,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "txId": "057ef664f0e1108f270729e53a62e4cb1a7480d9a87f543c6a1a785a1e492c65",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 130,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "txId": "35db95c66634c3497a277c1f08ed71a0cb53195ffecbf9798cdde4a30f27fab9",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzRGFiqhXB7SyX6idHQkt77B8mX7adnujdg3VG47jdVK2x4wbUYg",
+                "hashType": 130,
+                "value": 40000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 0de1f9b92d2ab6d8ead83f9a0ff5cf518dcb03b8 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 20000,
+            "script": "OP_DUP OP_HASH160 9ed1f577c60e4be1dbf35318ec12f51d25e85773 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 30000,
+            "script": "OP_DUP OP_HASH160 fb407e88c48921d5547d899e18a7c0a36919f54d OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 50000,
+            "script": "OP_DUP OP_HASH160 04ccb4eed8cfa9f6e394e945178960f5ccddb387 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ]
+      },
+      {
+        "description": "Sighash V1: ALL",
+        "txHex": "01000000000102fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f00000000484730440220691a19d365c8d75f921346c70271506bde136f13a4b566dd796902c262e2ec6d02202b00c4aa030eedf294552bdfc163936d2f4e91c59e7798c4471250cf07cb859501eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff0230f45e13000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac00e9a435000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac0002483045022100fddd014889f18d489b5400bfa8cb0a32301a768d934b1a0e2b55398119f26cab02207676c64c16ffa7ffaaf8e16b3b74e916687eebdfdb36b9b7997e838384d464640121025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee635711000000",
+        "inputs": [
+          {
+            "txId": "9f96ade4b41d5433f4eda31e1738ec2b36f6e7d1420d94a6af99801a88f7f7ff",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L3Wh2WPg21MWqzMFYsVC7PeBXcq1ow32KRccRihnTUnAhJaZUvg1",
+                "hashType": 1,
+                "value": 625000000
+              }
+            ],
+            "sequence": 4294967278,
+            "prevTxScript": "03c9f4836b9a4f77fc0d81f7bcb01b7f1b35916864b9476c241ce9fc198bd25432 OP_CHECKSIG"
+          },
+          {
+            "txId": "8ac60eb9575db5b2d987e29f301b5b819ea83a5c6579d282d189cc04b8e151ef",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KzVTBhbMaKrAYagJ11VdTaBrb6yzLykLGyuMBkf9sCFPDxdT8shL",
+                "hashType": 1,
+                "value": 600000000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_0 1d0f172a0ecb48aee1be1f2687d2963ae33f71a1"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 324990000,
+            "script": "OP_DUP OP_HASH160 8280b37df378db99f66f85c95a783a76ac7a6d59 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 900000000,
+            "script": "OP_DUP OP_HASH160 3bde42dbee7e4dbe6a21b2d50ce2f0167faa8159 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 17
+      },
+      {
+        "description": "Sighash V1: ALL 2",
+        "txHex": "01000000000101db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477010000001716001479091972186c449eb1ded22b78e40d009bdf0089feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac02473044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb012103ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a2687392040000",
+        "inputs": [
+          {
+            "txId": "77541aeb3c4dac9260b68f74f44c973081a9d4cb2ebe8038b2d70faa201b6bdb",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "L57KYn5isHFThD4cohjJgLTZA2vaxnMMKWngnzbttF159yH9dARf",
+                "hashType": 1,
+                "redeemScript": "OP_0 79091972186c449eb1ded22b78e40d009bdf0089",
+                "value": 1000000000
+              }
+            ],
+            "sequence": 4294967294,
+            "prevTxScript": "OP_HASH160 4733f37cf4db86fbc2efed2500b4f4e49f312023 OP_EQUAL"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 199996600,
+            "script": "OP_DUP OP_HASH160 a457b684d7f0d539a46a45bbc043f35b59d0d963 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 800000000,
+            "script": "OP_DUP OP_HASH160 fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 1170
+      },
+      {
+        "description": "Sighash V1: P2MS 6/6",
+        "txHex": "0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff02e6312761010000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688ac583e0f00000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac0800483045022100f902f491c4df15199e584790ae8c7202569a977accac0a09fa3f4f3b6ec3517602205961a951c4a12fa966da67b6fd75975b9de156b9895f8ab5f289ecaee12b9b3501473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502483045022100bd5294e145d729e9593f49079b74e6e4b8aeba63440408595ce0949d5c6450a702207f9c9fb45907fe0180d3f4bee499006007bb90894b5f824a26dfa5d3afec543303483045022100febf9409d7f3c091ddc4d296a483aae7b3d2a91d38f6ea2a153f7ff085fe7766022078d11972c74cd78f816152463a5e1a5d986dfb94b55cf5f7242e4f6d5df000ff81483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a088247304402201a0e125aed6a700e45d6c86017d5a9d2264c8079319d868f3f163f5d63cb5bfe02200887608f2322ca0d82df67316275371028b0b21750417d594117963fe23b67ec83cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000",
+        "inputs": [
+          {
+            "txId": "6eb98797a21c6c10aa74edf29d618be109f48a8e94c694f3701e08ca69186436",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "L15NqbRvcqso8ZCqD8aFaZV3CTypw6svjk8oCWsAfMmNViahS2Mw",
+                "hashType": 1,
+                "witnessScript": "OP_6 0307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba3 03b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b 034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a 033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f4 03a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac16 02d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b OP_6 OP_CHECKMULTISIG",
+                "redeemScript": "OP_0 a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54",
+                "value": 987654321
+              },
+              {
+                "keyPair": "Kwpf3fycToLH1ymZUkezFrYwTjhKaucHD861Ft5A4Tih855LBxVx",
+                "hashType": 2,
+                "witnessScript": "OP_6 0307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba3 03b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b 034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a 033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f4 03a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac16 02d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b OP_6 OP_CHECKMULTISIG",
+                "redeemScript": "OP_0 a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54",
+                "value": 987654321
+              },
+              {
+                "keyPair": "L1EV111k2WzNTapY2etd1TaB2aWbjUgouko9YyipS2S8H8WdGkQi",
+                "hashType": 3,
+                "witnessScript": "OP_6 0307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba3 03b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b 034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a 033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f4 03a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac16 02d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b OP_6 OP_CHECKMULTISIG",
+                "redeemScript": "OP_0 a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54",
+                "value": 987654321
+              },
+              {
+                "keyPair": "KwuvEmpBtJaw8SQLnpi3CoEHZJvv33EnYBHn13VcDuwprJqmkfSH",
+                "hashType": 129,
+                "witnessScript": "OP_6 0307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba3 03b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b 034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a 033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f4 03a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac16 02d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b OP_6 OP_CHECKMULTISIG",
+                "redeemScript": "OP_0 a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54",
+                "value": 987654321
+              },
+              {
+                "keyPair": "L5kdM8eWyfj8pdRDWA8j5SmBwAQt2yyhqjb2ZZQxtRGJfCquC6TB",
+                "hashType": 130,
+                "witnessScript": "OP_6 0307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba3 03b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b 034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a 033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f4 03a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac16 02d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b OP_6 OP_CHECKMULTISIG",
+                "redeemScript": "OP_0 a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54",
+                "value": 987654321
+              },
+              {
+                "keyPair": "KyT4JbJVRy5FZ6ZEZhkaocP2JSBXiF7X3Cx6DBAGLrydR9fiXQUK",
+                "hashType": 131,
+                "witnessScript": "OP_6 0307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba3 03b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b 034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a 033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f4 03a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac16 02d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b OP_6 OP_CHECKMULTISIG",
+                "redeemScript": "OP_0 a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54",
+                "value": 987654321
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_HASH160 9993a429037b5d912407a71c252019287b8d27a5 OP_EQUAL"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 5924925926,
+            "script": "OP_DUP OP_HASH160 389ffce9cd9ae88dcc0631e88a821ffdbe9bfe26 OP_EQUALVERIFY OP_CHECKSIG"
+          },
+          {
+            "value": 999000,
+            "script": "OP_DUP OP_HASH160 7480a33f950689af511e6e84c138dbbd3c3ee415 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2PK",
+        "txHex": "010000000193aef40ae141694895e99e18e49d0181b086dd7c011c0241175c6eaf320099970000000049483045022100e57eba5380dcc8a7bdb5370b423dadd43070e1ca268f94bc97b2ded55ca45e9502206a43151c8af03a00f0ac86526d07981e303fc0daea8c6ed435abe8961533046d01ffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac00000000",
+        "inputs": [
+          {
+            "txId": "97990032af6e5c1741021c017cdd86b081019de4189ee995486941e10af4ae93",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b OP_CHECKSIG"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2SH(P2PK)",
+        "txHex": "0100000001a30e865fa60f6c25a8b218bb5a6b9acc7cf3f1db2f2e3a7114b51af5d6ae811f000000006c473044022026d2b56b6cb0269bf4e80dd655b9e917019e2ccef57f4b858d03bb45a2da59d9022010519a7f327f03e7c9613e0694f929544af29d3682e7ec8f19147e7a86651ecd012321038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2bacffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac00000000",
+        "inputs": [
+          {
+            "txId": "1f81aed6f51ab514713a2e2fdbf1f37ccc9a6b5abb18b2a8256c0fa65f860ea3",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "redeemScript": "038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b OP_CHECKSIG",
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_HASH160 c99d9ebb5a4828e4e1b606dd6a51a2babebbdc09 OP_EQUAL"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2WSH(P2PK)",
+        "txHex": "010000000001014533a3bc1e039bd787656068e135aaee10aee95a64776bfc047ee6a7c1ebdd2f0000000000ffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac02473044022039725bb7291a14dd182dafdeaf3ea0d5c05c34f4617ccbaa46522ca913995c4e02203b170d072ed2e489e7424ad96d8fa888deb530be2d4c5d9aaddf111a7efdb2d3012321038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2bac00000000",
+        "inputs": [
+          {
+            "txId": "2fddebc1a7e67e04fc6b77645ae9ae10eeaa35e168606587d79b031ebca33345",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "witnessScript": "038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b OP_CHECKSIG",
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_0 0f9ea7bae7166c980169059e39443ed13324495b0d6678ce716262e879591210"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2SH(P2WSH(P2PK))",
+        "txHex": "01000000000101e0779d448aaa203a96b3de14d0482e26dd75a4278ae5bb6d7cc18e6874f3866000000000232200200f9ea7bae7166c980169059e39443ed13324495b0d6678ce716262e879591210ffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac024730440220014207a5f0601ed7b3c3f9d82309b32e8f76dd6776a55cb5f8684b9ff029e0850220693afd7b69471b51d9354cc1a956b68b8d48e32f6b0ad7a19bb5dd3e4499179a012321038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2bac00000000",
+        "inputs": [
+          {
+            "txId": "6086f374688ec17c6dbbe58a27a475dd262e48d014deb3963a20aa8a449d77e0",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "redeemScript": "OP_0 0f9ea7bae7166c980169059e39443ed13324495b0d6678ce716262e879591210",
+                "witnessScript": "038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b OP_CHECKSIG",
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_HASH160 6d185c7042d01ea8276dc6be6603101dc441d8a4 OP_EQUAL"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2PKH",
+        "txHex": "010000000176d7b05b96e69d9760bacf14e496ea01085eff32be8f4e08b299eb92057826e5000000006b4830450221009bd6ff2561437155913c289923175d3f114cca1c0e2bc5989315d5261502c2c902201b71ad90dce076a5eb872330ed729e7c2c4bc2d0513efff099dbefb3b62eab4f0121038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2bffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac00000000",
+        "inputs": [
+          {
+            "txId": "e526780592eb99b2084e8fbe32ff5e0801ea96e414cfba60979de6965bb0d776",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2SH(P2PKH)",
+        "txHex": "01000000014b9ffc17c3cce03ee66980bf32d36aaa13462980c3af9d9d29ec6b97ab1c91650000000084473044022003d738d855d0c54a419ac62ebe1a1c0bf2dc6993c9585adb9a8666736658107002204d57ff62ee7efae6df73430bba62494faeba8c125a4abcf2488757a4f8877dd50121038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b1976a914851a33a5ef0d4279bd5854949174e2c65b1d450088acffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac00000000",
+        "inputs": [
+          {
+            "txId": "65911cab976bec299d9dafc380294613aa6ad332bf8069e63ee0ccc317fc9f4b",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "redeemScript": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG",
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_HASH160 2162ff7c23d47a0c331f95c67d7c3e22abb12a02 OP_EQUAL"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2WSH(P2PKH)",
+        "txHex": "0100000000010123539877e39a273819006de1c433e09f9e9af201fc178dd0f2cf2eaa5ad53b480000000000ffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac03483045022100f02a82b0a94a5d5dc4d2127ac34be62cb066713d71d56bdf5ef7810ab57a157302205f24abdde1dab554a02edcf378e98828024e57272e5e474a5b04accdca080a030121038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b1976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac00000000",
+        "inputs": [
+          {
+            "txId": "483bd55aaa2ecff2d08d17fc01f29a9e9fe033c4e16d001938279ae377985323",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "witnessScript": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG",
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_0 578db4b54a6961060b71385c17d3280379a557224c52b11b19a3a1c1eef606a0"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2SH(P2WSH(P2PKH))",
+        "txHex": "01000000000101363dfbfe2566db77e3b1195bedf1d0daeb9ce526cd7611ba81759b2654ce415c0000000023220020578db4b54a6961060b71385c17d3280379a557224c52b11b19a3a1c1eef606a0ffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac03483045022100c8bd5ebb26ba6719158650c3e7c5e80be4c886ba025c44cc41f5149b3114705a02203ac6e1f38f6c081d506f28f1b5e38ebec9e0f0fa911d0e3f68d48d8b0e77b34b0121038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b1976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac00000000",
+        "inputs": [
+          {
+            "txId": "5c41ce54269b7581ba1176cd26e59cebdad0f1ed5b19b1e377db6625fefb3d36",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "witnessScript": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG",
+                "redeemScript": "OP_0 578db4b54a6961060b71385c17d3280379a557224c52b11b19a3a1c1eef606a0",
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_HASH160 44a641c4e06eb6118c99e5ed29954b705b50fb6a OP_EQUAL"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2MS 1/1",
+        "txHex": "010000000179310ec46e734b3490ee839c5ae4a09d28561ee9fff2d051f733d201f958d6d2000000004a00483045022100d269531f120f377ed2f94f42bef893ff2fe6544ac97fb477fa291bc6cfb7647e02200983f6a5bbd4ce6cf97f571995634805a7324cc5d8353ed954fa62477b0fcd0901ffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac00000000",
+        "inputs": [
+          {
+            "txId": "d2d658f901d233f751d0f2ffe91e56289da0e45a9c83ee90344b736ec40e3179",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_1 038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b OP_1 OP_CHECKMULTISIG"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2SH(P2MS)",
+        "txHex": "010000000152882c661c49dd2f53bd9ced7e9f44b184888ad2fe7d86737f0efaa7aecdced1000000006f00473044022025f2e161f0a97888df948f4dcc7c04fe502510b8d8260ca9920f38d55e4d17720220271b6843224b3a34542a4df31781d048da56ee46b8c5fb99043e30abd527b2d801255121038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b51aeffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac00000000",
+        "inputs": [
+          {
+            "txId": "d1cecdaea7fa0e7f73867dfed28a8884b1449f7eed9cbd532fdd491c662c8852",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "redeemScript": "OP_1 038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b OP_1 OP_CHECKMULTISIG",
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_HASH160 38c064c6387d1071eeb5c3d90350054aea0b3fc1 OP_EQUAL"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2WSH(P2MS)",
+        "txHex": "01000000000101c1eced6216de0889d4629ff64a8af8e8ec6d0b414de0c57b46c02cc303d321fe0000000000ffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac0300483045022100d4c0cbdb45915b8a3162362fa5f74556de919aeda5337fc44a7fb000e833460d022017742c37d7a061e2ae3a086c7c585c9c85e5d31af468d3e00045c0f35b8f8eb601255121038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b51ae00000000",
+        "inputs": [
+          {
+            "txId": "fe21d303c32cc0467bc5e04d410b6dece8f88a4af69f62d48908de1662edecc1",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "witnessScript": "OP_1 038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b OP_1 OP_CHECKMULTISIG",
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_0 1b8c0c2878c5634c3ce738cdc568c592e99783dbd28ff4c6cb5b7b4675d9ee99"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2SH(P2WSH(P2MS))",
+        "txHex": "010000000001013a5a2ab0223d3b504b52af76d650329750666fbf1be13d4cb08d0d9fc550a47d00000000232200201b8c0c2878c5634c3ce738cdc568c592e99783dbd28ff4c6cb5b7b4675d9ee99ffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac0300483045022100c97a5e205ce0023d3d44f846abf1f0e21b6f2646bd2496bbe92e4333fe4401be02201247e047d669f713582713e35d2eba430abc3d75a924bb500362bf47d6234ed501255121038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b51ae00000000",
+        "inputs": [
+          {
+            "txId": "7da450c59f0d8db04c3de11bbf6f6650973250d676af524b503b3d22b02a5a3a",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "witnessScript": "OP_1 038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b OP_1 OP_CHECKMULTISIG",
+                "redeemScript": "OP_0 1b8c0c2878c5634c3ce738cdc568c592e99783dbd28ff4c6cb5b7b4675d9ee99",
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_HASH160 cc6ea17c33de7996471e40892acdd6e5f61b9b6f OP_EQUAL"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2WKH",
+        "txHex": "0100000000010133defbe3e28860007ff3e21222774c220cb35d554fa3e3796d25bf8ee983e1080000000000ffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac0248304502210097c3006f0b390982eb47f762b2853773c6cedf83668a22d710f4c13c4fd6b15502205e26ef16a81fc818a37f3a34fc6d0700e61100ea6c6773907c9c046042c440340121038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b00000000",
+        "inputs": [
+          {
+            "txId": "08e183e98ebf256d79e3a34f555db30c224c772212e2f37f006088e2e3fbde33",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_0 851a33a5ef0d4279bd5854949174e2c65b1d4500"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2SH(P2WKH)",
+        "txHex": "010000000001015df9a0b9ade2d835881704e0f53b51a4b19ecfc794ea1f3555783dd7f68659ce0000000017160014851a33a5ef0d4279bd5854949174e2c65b1d4500ffffffff0160ea0000000000001976a914851a33a5ef0d4279bd5854949174e2c65b1d450088ac02483045022100cb3929c128fec5108071b662e5af58e39ac8708882753a421455ca80462956f6022030c0f4738dd1a13fc7a34393002d25c6e8a6399f29c7db4b98f53a9475d94ca20121038de63cf582d058a399a176825c045672d5ff8ea25b64d28d4375dcdb14c02b2b00000000",
+        "inputs": [
+          {
+            "txId": "ce5986f6d73d7855351fea94c7cf9eb1a4513bf5e004178835d8e2adb9a0f95d",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "L2FroWqrUgsPpTMhpXcAFnVDLPTToDbveh3bhDaU4jhe7Cw6YujN",
+                "hashType": 1,
+                "redeemScript": "OP_0 851a33a5ef0d4279bd5854949174e2c65b1d4500",
+                "value": 80000
+              }
+            ],
+            "sequence": 4294967295,
+            "prevTxScript": "OP_HASH160 0d061ae2c8ad224a81142a2e02181f5173b576b3 OP_EQUAL"
+          }
+        ],
+        "outputs": [
+          {
+            "value": 60000,
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "locktime": 0
+      },
+      {
+        "description": "P2SH(P2WSH(P2MS 2/2)), incomplete",
+        "network": "testnet",
+        "txHex": "010000000001012915794541ffa77ca795ec7c23ee989a63ccd1a71fab73e1c27ed20c4b6c69a4010000002322002024376a0a9abab599d0e028248d48ebe817bc899efcffa1cd2984d67289daf5afffffffff01b8820100000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac040047304402203b334650f1f13574a1c2edc76421867f7252950968bf0293c8b3ed086ab89e3d0220565cafab0a5044617e94756b948241525b2483a52504e1064d29f641fb18129e010047522102bbbd6eb01efcbe4bd9664b886f26f69de5afcb2e479d72596c8bf21929e352e22102d9c3f7180ef13ec5267723c9c2ffab56a4215241f837502ea8977c8532b9ea1952ae00000000",
+        "incomplete": true,
+        "inputs": [
+          {
+            "txId": "a4696c4b0cd27ec2e173ab1fa7d1cc639a98ee237cec95a77ca7ff4145791529",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "cRAwuVuVSBZMPu7hdrYvMCZ8eevzmkExjFbaBLhqnDdrezxN3nTS",
+                "witnessScript": "OP_2 02bbbd6eb01efcbe4bd9664b886f26f69de5afcb2e479d72596c8bf21929e352e2 02d9c3f7180ef13ec5267723c9c2ffab56a4215241f837502ea8977c8532b9ea19 OP_2 OP_CHECKMULTISIG",
+                "redeemScript": "OP_0 24376a0a9abab599d0e028248d48ebe817bc899efcffa1cd2984d67289daf5af",
+                "value": 100000
+              }
+            ],
+            "prevTxScript": "OP_HASH160 b64f1a3eacc1c8515592a6f10457e8ff90e4db6a OP_EQUAL"
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 99000
+          }
+        ]
+      },
+      {
+        "description": "P2SH(P2WSH(P2MS 2/2))",
+        "network": "testnet",
+        "txHex": "010000000001012915794541ffa77ca795ec7c23ee989a63ccd1a71fab73e1c27ed20c4b6c69a4010000002322002024376a0a9abab599d0e028248d48ebe817bc899efcffa1cd2984d67289daf5afffffffff01b8820100000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac040047304402203b334650f1f13574a1c2edc76421867f7252950968bf0293c8b3ed086ab89e3d0220565cafab0a5044617e94756b948241525b2483a52504e1064d29f641fb18129e0148304502210096e859827fb629b6547658c613f7c8298de151513d74b224560aa8608d521d600220736fb5564322237716ec940de44c67c428198adf5dedfda183c17aa77cd28d640147522102bbbd6eb01efcbe4bd9664b886f26f69de5afcb2e479d72596c8bf21929e352e22102d9c3f7180ef13ec5267723c9c2ffab56a4215241f837502ea8977c8532b9ea1952ae00000000",
+        "incomplete": true,
+        "inputs": [
+          {
+            "txId": "a4696c4b0cd27ec2e173ab1fa7d1cc639a98ee237cec95a77ca7ff4145791529",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "cRAwuVuVSBZMPu7hdrYvMCZ8eevzmkExjFbaBLhqnDdrezxN3nTS",
+                "witnessScript": "OP_2 02bbbd6eb01efcbe4bd9664b886f26f69de5afcb2e479d72596c8bf21929e352e2 02d9c3f7180ef13ec5267723c9c2ffab56a4215241f837502ea8977c8532b9ea19 OP_2 OP_CHECKMULTISIG",
+                "redeemScript": "OP_0 24376a0a9abab599d0e028248d48ebe817bc899efcffa1cd2984d67289daf5af",
+                "value": 100000
+              },
+              {
+                "keyPair": "cTUFsNeVd8TKU4yREN8nMdViNnHyNvCCYVRmRUmkMLgomiMWTiii",
+                "witnessScript": "OP_2 02bbbd6eb01efcbe4bd9664b886f26f69de5afcb2e479d72596c8bf21929e352e2 02d9c3f7180ef13ec5267723c9c2ffab56a4215241f837502ea8977c8532b9ea19 OP_2 OP_CHECKMULTISIG",
+                "redeemScript": "OP_0 24376a0a9abab599d0e028248d48ebe817bc899efcffa1cd2984d67289daf5af",
+                "value": 100000
+              }
+            ],
+            "prevTxScript": "OP_HASH160 b64f1a3eacc1c8515592a6f10457e8ff90e4db6a OP_EQUAL"
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 99000
+          }
+        ]
+      },
+      {
+        "description": "P2WSH(P2MS 2/3) -> P2PKH",
+        "network": "testnet",
+        "txHex": "01000000000101ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01000000232200201b48bf145648b9492ecd6d76754ea3def4b90e22e4ef7aee9ca291b2de455701ffffffff01f07e0e00000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac0400473044022036c9ecb03cb04c09be1f52766725dcfe9a815973bd2f34ce19a345f2d925a45502207b90737852d2508db104ad17612de473687e67928c045555a1ed8d495c0570d901483045022100aec0e58e4e597b35ca5a727702a0da3d4f2ef4759914da7fc80aecb3c479a6d902201ec27ea8dcca4b73ee81e4b627f52f9e627c3497f61e4beeb98f86e02979640a0169522103c411cf39aca4395c81c35921dc832a0d1585d652ab1b52ccc619ff9fbbc5787721020636d944458a4663b75a912c37dc1cd59b11f9a00106783a65ba230d929b96b02102d1448cbf19528a1a27e5958ba73d930b5b3facdbe5c30c7094951a287fcc914953ae00000000",
+        "stages":  [
+          "01000000000101ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01000000232200201b48bf145648b9492ecd6d76754ea3def4b90e22e4ef7aee9ca291b2de455701ffffffff01f07e0e00000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac0500473044022036c9ecb03cb04c09be1f52766725dcfe9a815973bd2f34ce19a345f2d925a45502207b90737852d2508db104ad17612de473687e67928c045555a1ed8d495c0570d901000069522103c411cf39aca4395c81c35921dc832a0d1585d652ab1b52ccc619ff9fbbc5787721020636d944458a4663b75a912c37dc1cd59b11f9a00106783a65ba230d929b96b02102d1448cbf19528a1a27e5958ba73d930b5b3facdbe5c30c7094951a287fcc914953ae00000000"
+        ],
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "cUxccFVBdJRq6HnyxiFMd8Z15GLThXaNLcnPBgoXLEv9iX6wuV2b",
+                "witnessScript": "OP_2 03c411cf39aca4395c81c35921dc832a0d1585d652ab1b52ccc619ff9fbbc57877 020636d944458a4663b75a912c37dc1cd59b11f9a00106783a65ba230d929b96b0 02d1448cbf19528a1a27e5958ba73d930b5b3facdbe5c30c7094951a287fcc9149 OP_3 OP_CHECKMULTISIG",
+                "redeemScript": "OP_0 1b48bf145648b9492ecd6d76754ea3def4b90e22e4ef7aee9ca291b2de455701",
+                "value": 1000000,
+                "stage": true
+              },
+              {
+                "keyPair": "cVSNe9ZdZRsRvEBL8YRR7YiZmH4cLsf5FthgERWkZezJVrGseaXy",
+                "witnessScript": "OP_2 03c411cf39aca4395c81c35921dc832a0d1585d652ab1b52ccc619ff9fbbc57877 020636d944458a4663b75a912c37dc1cd59b11f9a00106783a65ba230d929b96b0 02d1448cbf19528a1a27e5958ba73d930b5b3facdbe5c30c7094951a287fcc9149 OP_3 OP_CHECKMULTISIG",
+                "redeemScript": "OP_0 1b48bf145648b9492ecd6d76754ea3def4b90e22e4ef7aee9ca291b2de455701",
+                "value": 1000000
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 950000
+          }
+        ]
+      }
+    ],
+    "fromTransaction": [
+      {
+        "description": "Transaction w/ P2SH(P2MS 2/2) -> OP_RETURN | 1 OP_0, no signatures",
+        "network": "testnet",
+        "incomplete": true,
+        "inputs": [
+          {
+            "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+            "vout": 0,
+            "scriptSig": "OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae",
+            "scriptSigAfter": "OP_0 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2SH(P2MS 2/2) -> OP_RETURN | missing OP_0, 1 signature",
+        "network": "testnet",
+        "incomplete": true,
+        "inputs": [
+          {
+            "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+            "vout": 0,
+            "scriptSig": "OP_0 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae",
+            "scriptSigAfter": "OP_0 OP_0 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2SH(P2MS 2/2) -> OP_RETURN | no OP_0, 2 signatures",
+        "network": "testnet",
+        "inputs": [
+          {
+            "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+            "vout": 0,
+            "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae",
+            "scriptSigAfter": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      }
+    ],
+    "classification": {
+      "hex": "01000000059c06fb641a8cd69be81ca91e68d8a115cb698396876ecd77120ec1e4ab9002279f000000b500483045022100d58f828ab39cfac592f89fe372fb520992975218698c683a893f29e39cf0080302207cc0485dab5ce621089bdd15e1f15db0ecbde8dd4bb661bcf0e3af6ecab075e6014c6952210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753aeffffffff0821dc00213d2b7993f8f2a1553800c6f2f31106da176505d0ade467b68401d795000000b400473044022028e937a7bba888fe3428f442f6e22d92ce2ddba01548c38780d40890fa6cc305022043204d0bcfb1150b045d54cf9b13462e44e2ef47fee03d3cea08e84a8060fc30014c6952210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753aeffffffffaa997ac385dc666af1f5947ef615431024eb314cac2308d5e1b903e28ca466f499000000b50048304502210093efc26facedc5f51e304aa270a7b4f1a911b2d912c3674e5c6e2ad4ac7a410402201cf0b62c240461902f9f16d8a0bc3a210b7bfcd2c06523dd4b4b63be22e85252014c6952210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753aeffffffffd9f61bf98a021ee144f33ba5a6b04274de8fcb5c05f1ff7c12367fb7a608b2dd9e000000b4004730440220456e1201c1fa727288cba7fa0054dc02d8dd6c7418cae1e97006ef0652891c9202201192d0fbf3a9c00afb99a415f2bf515509e1150805acd8de95c496c27cb6570f014c6952210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753aeffffffff1f8119e3bc7c2f451feaa79f42ec5a63502afb425c253c935e43d217d5c29bdea1000000b500483045022100f669004f770490093eba4ac4903cb7581f7d18ea9245c538585ef5367e520e4702205485fafe0be178563a599d41e0cc172bb01314ed65d0e48df19a5258f17bdbc4014c6952210327e023a353d111808f61d554c2e1934721eaf87f33b7a771e807006908a493722103251670bb6a179a0d43b75476c7e580c0ba274378a18077e8de0832c870e5381f2102cca7f9a64425a0466d26d5c7e9eb3ad6b64cd48ea89edb38bc08f58a792dde4753aeffffffff0380f0fa02000000001976a91439692085cf9d27e8c1cf63e76bd32d9bd15cab8b88ac50c300000000000017a9147204bb26950ce1595255897f63d205779f033f3e875b5409000000000017a9142538893d984a4b5695e4bfde1a90a9f02fabf8e38700000000"
+    },
+    "multisig": [
+      {
+        "description": "P2SH(P2MS 2/2), signed in correct order",
+        "network": "testnet",
+        "inputs": [
+          {
+            "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+            "vout": 0,
+            "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
+            "signs": [
+              {
+                "pubKeyIndex": 0,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+                "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
+              },
+              {
+                "pubKeyIndex": 1,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
+                "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ],
+        "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+      },
+      {
+        "description": "P2SH(P2MS 2/2), signed in shuffled order",
+        "network": "testnet",
+        "inputs": [
+          {
+            "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+            "vout": 0,
+            "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
+            "signs": [
+              {
+                "pubKeyIndex": 1,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
+                "scriptSig": "OP_0 OP_0 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
+              },
+              {
+                "pubKeyIndex": 0,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+                "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ],
+        "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+      },
+      {
+        "description": "P2SH(P2MS 2/2), manually messed up order of signatures",
+        "network": "testnet",
+        "inputs": [
+          {
+            "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+            "vout": 0,
+            "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
+            "signs": [
+              {
+                "pubKeyIndex": 0,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+                "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
+              },
+              {
+                "pubKeyIndex": 1,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
+                "scriptSig": "OP_0 3045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001 3045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b0657601 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52ae"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ],
+        "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd1c0100483045022100e37e33a4fe5fccfb87afb0e951e83fcea4820d73b327d21edc1adec3b916c437022061c5786908b674e323a1863cc2feeb60e1679f1892c10ee08ac21e51fd50ba9001483045022100aa0c323bc639d3d71591be98ccaf7b8cb8c86aa95f060aef5e36fc3f04c4d029022010e2b18de17e307a12ae7e0e88518fe814f18a0ca1ee4510ba23a65628b06576014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+      },
+      {
+        "description": "P2SH(P2MS 2/3), signed by key 1 and 2",
+        "network": "testnet",
+        "inputs": [
+          {
+            "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+            "vout": 0,
+            "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG",
+            "signs": [
+              {
+                "pubKeyIndex": 0,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+                "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
+              },
+              {
+                "pubKeyIndex": 1,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
+                "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 3045022100ae06d8269b79b5cfa0297d1d88261b0061e52fc2814948c3aa05fa78ee76894302206e0c79a5c90569d8c72a542ef9a06471cbbcd2c651b312339983dfba4f8ff46301 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ],
+        "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100ae06d8269b79b5cfa0297d1d88261b0061e52fc2814948c3aa05fa78ee76894302206e0c79a5c90569d8c72a542ef9a06471cbbcd2c651b312339983dfba4f8ff463014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+      },
+      {
+        "description": "P2SH(P2MS 2/3), signed by key 1 and 3",
+        "network": "testnet",
+        "inputs": [
+          {
+            "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+            "vout": 0,
+            "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG",
+            "signs": [
+              {
+                "pubKeyIndex": 0,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+                "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
+              },
+              {
+                "pubKeyIndex": 2,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
+                "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ],
+        "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+      },
+      {
+        "description": "P2SH(P2MS 2/3), signed by key 3 and 1",
+        "network": "testnet",
+        "inputs": [
+          {
+            "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+            "vout": 0,
+            "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG",
+            "signs": [
+              {
+                "pubKeyIndex": 2,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
+                "scriptSig": "OP_0 OP_0 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
+              },
+              {
+                "pubKeyIndex": 0,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+                "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ],
+        "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+      },
+      {
+        "description": "P2SH(P2MS 2/3), signed by key 1 and 3, manually messed up order of signatures",
+        "network": "testnet",
+        "inputs": [
+          {
+            "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+            "vout": 0,
+            "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG",
+            "signs": [
+              {
+                "pubKeyIndex": 0,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+                "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 OP_0 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
+              },
+              {
+                "pubKeyIndex": 2,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
+                "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ],
+        "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+      },
+      {
+        "description": "P2SH(P2MS 2/3), signed by key 3 and 1, manually removing OP_0s",
+        "network": "testnet",
+        "inputs": [
+          {
+            "txId": "4971f016798a167331bcbc67248313fbc444c6e92e4416efd06964425588f5cf",
+            "vout": 0,
+            "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG",
+            "signs": [
+              {
+                "pubKeyIndex": 2,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe",
+                "scriptSig": "OP_0 OP_0 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
+              },
+              {
+                "filterOP_0": true,
+                "pubKeyIndex": 0,
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+                "scriptSig": "OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae",
+                "scriptSigFiltered": "OP_0 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ],
+        "txHex": "0100000001cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f0714900000000fd5e0100483045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01483045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af0014cc952410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253aeffffffff01e8030000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+      }
+    ]
+  },
+  "invalid": {
+    "build": [
+      {
+        "exception": "Transaction has no inputs",
+        "inputs": [],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "exception": "Transaction has no outputs",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0
+          }
+        ],
+        "outputs": []
+      },
+      {
+        "exception": "Transaction has absurd fees",
+        "inputs": [
+          {
+            "txRaw": {
+              "inputs": [],
+              "outputs": [
+                {
+                  "address": "1C5XhB1UkFuyCV1CG9dmXaXGu3xDL4nAjv",
+                  "value": 1000000000
+                }
+              ],
+              "incomplete": true
+            },
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KzBQVXYUGDAvqG7VeU3C7ZMRYiwtsxSVVFcYGzKU9E4aUVDUquZU"
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 ff99e06c1a4ac394b4e1cb3d3a4b2b47749e339a OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 200000
+          }
+        ]
+      },
+      {
+        "description": "Incomplete transaction, nothing assumed",
+        "exception": "Transaction is not complete",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "description": "Incomplete transaction, known prevTxScript, thereby throws for missing signatures",
+        "exception": "Not enough signatures provided",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+              }
+            ]
+          },
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 1,
+            "prevTxScript": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG"
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "description": "Duplicate transaction outs",
+        "exception": "Duplicate TxOut: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff:0",
+        "incomplete": true,
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0
+          },
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "description": "Complete transaction w/ non-standard inputs",
+        "exception": "nonstandard not supported",
+        "txHex": "010000000100000000171a0000e028f2000000000050178500000000000d0000000e000000000000002009f691b2263260e71f363d1db51ff3100d285956a40cc0e4f8c8c2c4a80559b1ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+      }
+    ],
+    "sign": [
+      {
+        "description": "Transaction w/ witness value mismatch",
+        "exception": "Input didn\\'t match witnessValue",
+        "network": "testnet",
+        "inputs": [
+          {
+            "txHex": "0100000001f7e6430096cd2790bac115aaab22c0a50fb0a1794305302e1a399e81d8d354f4020000006a47304402205793a862d193264afc32713e2e14541e1ff9ebb647dd7e7e6a0051d0faa87de302205216653741ecbbed573ea2fc053209dd6980616701c27be5b958a159fc97f45a012103e877e7deb32d19250dcfe534ea82c99ad739800295cd5429a7f69e2896c36fcdfeffffff0340420f00000000001976a9145c7b8d623fba952d2387703d051d8e931a6aa0a188ac8bda2702000000001976a9145a0ef60784137d03e7868d063b05424f2f43799f88ac40420f00000000001976a9145c7b8d623fba952d2387703d051d8e931a6aa0a188ac2fcc0e00",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "cQ6483mDWwoG8o4tn6nU9Jg52RKMjPUWXSY1vycAyPRXQJ1Pn2Rq",
+                "throws": true,
+                "value": 22500000000
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 ff99e06c1a4ac394b4e1cb3d3a4b2b47749e339a OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 6000000
+          }
+        ]
+      },
+      {
+        "description": "Too many signatures - P2PKH",
+        "exception": "Signature already exists",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
+              },
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2WPKH, signing with uncompressed public key",
+        "exception": "BIP143 rejects uncompressed public keys in P2WPKH or P2WSH",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "prevTxScript": "OP_0 15a71ffa7b5bb70cddefcf364494071022efe390",
+            "signs": [
+              {
+                "keyPair": "5JiHJJjdufSiMxbvnyNcKtQNLYH6SvUpQnRv9yZENFDWTQKQkzC",
+                "value": 10000,
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_0 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2WSH(P2PK), signing with uncompressed public key",
+        "exception": "BIP143 rejects uncompressed public keys in P2WPKH or P2WSH",
+        "inputs": [
+          {
+            "txId": "2fddebc1a7e67e04fc6b77645ae9ae10eeaa35e168606587d79b031ebca33345",
+            "vout": 0,
+            "prevTxScript": "OP_0 5339df4de3854c4208376443ed075014ad996aa349ad6b5abf6c4d20f604d348",
+            "signs": [
+              {
+                "keyPair": "5JiHJJjdufSiMxbvnyNcKtQNLYH6SvUpQnRv9yZENFDWTQKQkzC",
+                "witnessScript": "04f56d09b32cefc818735150bf8560eefdaf30d2edb3fe557bf27682aedaed81bf9aaff7eeb496e088058ec548826c12b521dbb566a862d9b67677910c2b421e06 OP_CHECKSIG",
+                "value": 80000,
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 60000
+          }
+        ]
+      },
+      {
+        "description": "Transaction w/ P2SH(P2WSH(P2PK)), signing with uncompressed public key",
+        "exception": "BIP143 rejects uncompressed public keys in P2WPKH or P2WSH",
+        "inputs": [
+          {
+            "txId": "2fddebc1a7e67e04fc6b77645ae9ae10eeaa35e168606587d79b031ebca33345",
+            "vout": 0,
+            "prevTxScript": "OP_HASH160 5afe12b2827e3eac05fe3f17c59406ef262aa177 OP_EQUAL",
+            "signs": [
+              {
+                "keyPair": "5JiHJJjdufSiMxbvnyNcKtQNLYH6SvUpQnRv9yZENFDWTQKQkzC",
+                "redeemScript": "OP_0 5339df4de3854c4208376443ed075014ad996aa349ad6b5abf6c4d20f604d348",
+                "witnessScript": "04f56d09b32cefc818735150bf8560eefdaf30d2edb3fe557bf27682aedaed81bf9aaff7eeb496e088058ec548826c12b521dbb566a862d9b67677910c2b421e06 OP_CHECKSIG",
+                "value": 80000,
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 851a33a5ef0d4279bd5854949174e2c65b1d4500 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 60000
+          }
+        ]
+      },
+      {
+        "exception": "nulldata not supported as redeemScript \\(OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474\\)",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
+                "redeemScript": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474",
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "exception": "PrevOutScript is scripthash, requires redeemScript",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 1,
+            "prevTxScript": "OP_HASH160 7f67f0521934a57d3039f77f9f32cf313f3ac74b OP_EQUAL",
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "exception": "PrevOutScript is witnessscripthash, requires witnessScript",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 1,
+            "prevTxScript": "OP_0 0f9ea7bae7166c980169059e39443ed13324495b0d6678ce716262e879591210",
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "exception": "Inconsistent redeemScript",
+        "network": "testnet",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "signs": [
+              {
+                "redeemScript": "OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx"
+              },
+              {
+                "redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a OP_2 OP_CHECKMULTISIG",
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT",
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "description": "Inconsistent RedeemScript hash",
+        "exception": "Inconsistent hash160",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "prevTxScript": "OP_HASH160 ffffffffffffffffffffffffffffffffffffffff OP_EQUAL",
+            "signs": [
+              {
+                "keyPair": "5JiHJJjdufSiMxbvnyNcKtQNLYH6SvUpQnRv9yZENFDWTQKQkzC",
+                "redeemScript": "OP_1",
+                "value": 10000,
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_0 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "description": "Inconsistent WitnessScript hash",
+        "exception": "Inconsistent sha256",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "prevTxScript": "OP_0 ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "signs": [
+              {
+                "keyPair": "5JiHJJjdufSiMxbvnyNcKtQNLYH6SvUpQnRv9yZENFDWTQKQkzC",
+                "witnessScript": "OP_1",
+                "value": 10000,
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_0 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5",
+            "value": 10000
+          }
+        ]
+      },
+      {
+        "exception": "scripthash not supported as redeemScript \\(OP_HASH160 7f67f0521934a57d3039f77f9f32cf313f3ac74b OP_EQUAL\\)",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
+                "redeemScript": "OP_HASH160 7f67f0521934a57d3039f77f9f32cf313f3ac74b OP_EQUAL",
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "exception": "PrevOutScript must be P2SH",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 1,
+            "prevTxScript": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "signs": [
+              {
+                "keyPair": "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn",
+                "redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 OP_1 OP_CHECKMULTISIG",
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "description": "Too many signatures - P2SH(P2MS 1/1)",
+        "exception": "Signature already exists",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf",
+                "redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 OP_1 OP_CHECKMULTISIG"
+              },
+              {
+                "keyPair": "5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf",
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "description": "Wrong network for keyPair",
+        "exception": "Inconsistent network",
+        "network": "bitcoin",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "signs": [
+              {
+                "keyPair": "91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx",
+                "network": "testnet",
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "description": "Wrong key pair for P2MS redeemScript",
+        "exception": "Key pair cannot sign for this input",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 1,
+            "signs": [
+              {
+                "keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx",
+                "redeemScript": "OP_1 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 OP_1 OP_CHECKMULTISIG",
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      },
+      {
+        "exception": "nulldata not supported",
+        "inputs": [
+          {
+            "txId": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+            "vout": 0,
+            "prevTxScript": "OP_RETURN 06deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474",
+            "signs": [
+              {
+                "keyPair": "KzrA86mCVMGWnLGBQu9yzQa32qbxb5dvSK4XhyjjGAWSBKYX4rHx",
+                "throws": true
+              }
+            ]
+          }
+        ],
+        "outputs": [
+          {
+            "script": "OP_DUP OP_HASH160 aa4d7985c57e011a8b3dd8e0e5a73aaef41629c5 OP_EQUALVERIFY OP_CHECKSIG",
+            "value": 1000
+          }
+        ]
+      }
+    ],
+    "fromTransaction": [
+      {
+        "exception": "coinbase inputs not supported",
+        "txHex": "01000000010000000000000000000000000000000000000000000000000000000000000000000000006b483045022100a3b254e1c10b5d039f36c05f323995d6e5a367d98dd78a13d5bbc3991b35720e022022fccea3897d594de0689601fbd486588d5bfa6915be2386db0397ee9a6e80b601210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0110270000000000001976a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac00000000"
+      }
+    ]
+  }
+}
diff --git a/test/hdaddress.js b/test/hdaddress.js
new file mode 100644
index 0000000..59b84ab
--- /dev/null
+++ b/test/hdaddress.js
@@ -0,0 +1,95 @@
+/* global describe, it */
+/* eslint-disable no-new */
+
+var assert = require('assert')
+var HDNode = require('../src/hdnode')
+var bnetwork = require('../src/networks')
+
+describe('bip44', function () {
+  it('works without a ScriptFactory', function () {
+    // mnemonic: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
+    var seed = '5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4'
+    var network = bnetwork.bitcoin
+
+    var root = HDNode.fromSeedHex(seed, network)
+    assert.equal(
+      root.toBase58(),
+      'xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu'
+    )
+
+    var account = root.derivePath('44\'/0\'/0\'')
+    assert.equal(
+      account.toBase58(),
+      'xprv9xpXFhFpqdQK3TmytPBqXtGSwS3DLjojFhTGht8gwAAii8py5X6pxeBnQ6ehJiyJ6nDjWGJfZ95WxByFXVkDxHXrqu53WCRGypk2ttuqncb'
+    )
+    assert.equal(
+      'xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj',
+      account.neutered().toBase58()
+    )
+
+    var key = account.derivePath('0/0')
+    assert.equal('1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA', key.getAddress())
+  })
+
+  it('works with a prefix', function () {
+    // mnemonic: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
+    var seed = '5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4'
+    var network = bnetwork.bitcoin
+
+    var root = HDNode.fromSeedHex(seed, network, network.bip32)
+    var account = root.derivePath('44\'/0\'/0\'')
+    assert.equal(
+      account.toBase58(),
+      'xprv9xpXFhFpqdQK3TmytPBqXtGSwS3DLjojFhTGht8gwAAii8py5X6pxeBnQ6ehJiyJ6nDjWGJfZ95WxByFXVkDxHXrqu53WCRGypk2ttuqncb'
+    )
+    assert.equal(
+      'xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj',
+      account.neutered().toBase58()
+    )
+
+    var key = account.derivePath('0/0')
+    assert.equal('1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA', key.getAddress())
+  })
+})
+
+describe('bip49', function () {
+  it('serialization and address', function () {
+    // mnemonic: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
+    var seed = '5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4'
+    var network = bnetwork.bitcoin
+    var root = HDNode.fromSeedHex(seed, network, network.bip49)
+    var account = root.derivePath('49\'/0\'/0\'')
+    assert.equal(
+      account.toBase58(),
+      'yprvAHwhK6RbpuS3dgCYHM5jc2ZvEKd7Bi61u9FVhYMpgMSuZS613T1xxQeKTffhrHY79hZ5PsskBjcc6C2V7DrnsMsNaGDaWev3GLRQRgV7hxF'
+    )
+    assert.equal(
+      'ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP',
+      account.neutered().toBase58()
+    )
+
+    var key = account.derivePath('0/0')
+    assert.equal('37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf', key.getAddress())
+  })
+})
+
+describe('bip84', function () {
+  it('serialization and address', function () {
+    // mnemonic: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
+    var seed = '5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4'
+    var network = bnetwork.bitcoin
+    var root = HDNode.fromSeedHex(seed, network, network.bip84)
+    var account = root.derivePath('84\'/0\'/0\'')
+    assert.equal(
+      account.toBase58(),
+      'zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE'
+    )
+    assert.equal(
+      'zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs',
+      account.neutered().toBase58()
+    )
+
+    var key = account.derivePath('0/0')
+    assert.equal('bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu', key.getAddress())
+  })
+})
diff --git a/test/hdnode.js b/test/hdnode.js
new file mode 100644
index 0000000..23cd042
--- /dev/null
+++ b/test/hdnode.js
@@ -0,0 +1,388 @@
+/* global describe, it, beforeEach */
+/* eslint-disable no-new */
+
+var assert = require('assert')
+var ecdsa = require('../src/ecdsa')
+var sinon = require('sinon')
+var sinonTest = require('sinon-test')
+var setupTest = sinonTest(sinon)
+
+var BigInteger = require('bigi')
+var ECPair = require('../src/ecpair')
+var HDNode = require('../src/hdnode')
+
+var fixtures = require('./fixtures/hdnode.json')
+var curve = ecdsa.__curve
+
+var NETWORKS = require('../src/networks')
+var NETWORKS_LIST = [] // Object.values(NETWORKS)
+for (var networkName in NETWORKS) {
+  NETWORKS_LIST.push(NETWORKS[networkName])
+}
+
+var validAll = []
+fixtures.valid.forEach(function (f) {
+  function addNetwork (n) {
+    n.network = f.network
+    return n
+  }
+
+  validAll = validAll.concat(addNetwork(f.master), f.children.map(addNetwork))
+})
+
+describe('HDNode', function () {
+  describe('Constructor', function () {
+    var keyPair, chainCode
+
+    beforeEach(function () {
+      var d = BigInteger.ONE
+
+      keyPair = new ECPair(d, null)
+      chainCode = Buffer.alloc(32, 1)
+    })
+
+    it('stores the keyPair/chainCode directly', function () {
+      var hd = new HDNode(keyPair, chainCode)
+
+      assert.strictEqual(hd.keyPair, keyPair)
+      assert.strictEqual(hd.chainCode, chainCode)
+    })
+
+    it('has a default depth/index of 0', function () {
+      var hd = new HDNode(keyPair, chainCode)
+      assert.strictEqual(hd.depth, 0)
+      assert.strictEqual(hd.index, 0)
+    })
+
+    it('throws on uncompressed keyPair', function () {
+      keyPair.compressed = false
+
+      assert.throws(function () {
+        new HDNode(keyPair, chainCode)
+      }, /BIP32 only allows compressed keyPairs/)
+    })
+
+    it('throws when an invalid length chain code is given', function () {
+      assert.throws(function () {
+        new HDNode(keyPair, Buffer.alloc(20))
+      }, /Expected property "1" of type Buffer\(Length: 32\), got Buffer\(Length: 20\)/)
+    })
+  })
+
+  describe('fromSeed*', function () {
+    fixtures.valid.forEach(function (f) {
+      it('calculates privKey and chainCode for ' + f.master.fingerprint, function () {
+        var network = NETWORKS[f.network]
+        var hd = HDNode.fromSeedHex(f.master.seed, network)
+
+        assert.strictEqual(hd.keyPair.toWIF(), f.master.wif)
+        assert.strictEqual(hd.chainCode.toString('hex'), f.master.chainCode)
+      })
+    })
+
+    it('throws if IL is not within interval [1, n - 1] | IL === 0', setupTest(function () {
+      this.mock(BigInteger).expects('fromBuffer')
+        .once().returns(BigInteger.ZERO)
+
+      assert.throws(function () {
+        HDNode.fromSeedHex('ffffffffffffffffffffffffffffffff')
+      }, /Private key must be greater than 0/)
+    }))
+
+    it('throws if IL is not within interval [1, n - 1] | IL === n', setupTest(function () {
+      this.mock(BigInteger).expects('fromBuffer')
+        .once().returns(curve.n)
+
+      assert.throws(function () {
+        HDNode.fromSeedHex('ffffffffffffffffffffffffffffffff')
+      }, /Private key must be less than the curve order/)
+    }))
+
+    it('throws on low entropy seed', function () {
+      assert.throws(function () {
+        HDNode.fromSeedHex('ffffffffff')
+      }, /Seed should be at least 128 bits/)
+    })
+
+    it('throws on too high entropy seed', function () {
+      assert.throws(function () {
+        HDNode.fromSeedHex('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
+      }, /Seed should be at most 512 bits/)
+    })
+  })
+
+  describe('ECPair wrappers', function () {
+    var keyPair, hd, hash
+
+    beforeEach(function () {
+      keyPair = ECPair.makeRandom()
+      hash = Buffer.alloc(32)
+
+      var chainCode = Buffer.alloc(32)
+      hd = new HDNode(keyPair, chainCode)
+    })
+
+    describe('getAddress', function () {
+      // it('wraps keyPair.getAddress', setupTest(function () {
+      //   this.mock(keyPair).expects('getAddress')
+      //     .once().withArgs().returns('foobar')
+      //
+      //   assert.strictEqual(hd.getAddress(), 'foobar')
+      // }))
+    })
+
+    describe('getNetwork', function () {
+      it('wraps keyPair.getNetwork', setupTest(function () {
+        this.mock(keyPair).expects('getNetwork')
+          .once().withArgs().returns('network')
+
+        assert.strictEqual(hd.getNetwork(), 'network')
+      }))
+    })
+
+    describe('getPublicKeyBuffer', function () {
+      it('wraps keyPair.getPublicKeyBuffer', setupTest(function () {
+        this.mock(keyPair).expects('getPublicKeyBuffer')
+          .once().withArgs().returns('pubKeyBuffer')
+
+        assert.strictEqual(hd.getPublicKeyBuffer(), 'pubKeyBuffer')
+      }))
+    })
+
+    describe('sign', function () {
+      it('wraps keyPair.sign', setupTest(function () {
+        this.mock(keyPair).expects('sign')
+          .once().withArgs(hash).returns('signed')
+
+        assert.strictEqual(hd.sign(hash), 'signed')
+      }))
+    })
+
+    describe('verify', function () {
+      var signature
+
+      beforeEach(function () {
+        signature = hd.sign(hash)
+      })
+
+      it('wraps keyPair.verify', setupTest(function () {
+        this.mock(keyPair).expects('verify')
+          .once().withArgs(hash, signature).returns('verified')
+
+        assert.strictEqual(hd.verify(hash, signature), 'verified')
+      }))
+    })
+  })
+
+  describe('fromBase58 / toBase58', function () {
+    validAll.forEach(function (f) {
+      it('exports ' + f.base58 + ' (public) correctly', function () {
+        var hd = HDNode.fromBase58(f.base58, NETWORKS_LIST)
+
+        assert.strictEqual(hd.toBase58(), f.base58)
+        assert.throws(function () { hd.keyPair.toWIF() }, /Missing private key/)
+      })
+    })
+
+    validAll.forEach(function (f) {
+      it('exports ' + f.base58Priv + ' (private) correctly', function () {
+        var hd = HDNode.fromBase58(f.base58Priv, NETWORKS_LIST)
+
+        assert.strictEqual(hd.toBase58(), f.base58Priv)
+        assert.strictEqual(hd.keyPair.toWIF(), f.wif)
+      })
+    })
+
+    fixtures.invalid.fromBase58.forEach(function (f) {
+      it('throws on ' + f.string, function () {
+        assert.throws(function () {
+          var networks = f.network ? NETWORKS[f.network] : NETWORKS_LIST
+
+          HDNode.fromBase58(f.string, networks)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('getIdentifier', function () {
+    validAll.forEach(function (f) {
+      it('returns the identifier for ' + f.fingerprint, function () {
+        var hd = HDNode.fromBase58(f.base58, NETWORKS_LIST)
+
+        assert.strictEqual(hd.getIdentifier().toString('hex'), f.identifier)
+      })
+    })
+  })
+
+  describe('getFingerprint', function () {
+    validAll.forEach(function (f) {
+      it('returns the fingerprint for ' + f.fingerprint, function () {
+        var hd = HDNode.fromBase58(f.base58, NETWORKS_LIST)
+
+        assert.strictEqual(hd.getFingerprint().toString('hex'), f.fingerprint)
+      })
+    })
+  })
+
+  describe('neutered / isNeutered', function () {
+    validAll.forEach(function (f) {
+      it('drops the private key for ' + f.fingerprint, function () {
+        var hd = HDNode.fromBase58(f.base58Priv, NETWORKS_LIST)
+        var hdn = hd.neutered()
+
+        assert.notEqual(hdn.keyPair, hd.keyPair)
+        assert.throws(function () { hdn.keyPair.toWIF() }, /Missing private key/)
+        assert.strictEqual(hdn.toBase58(), f.base58)
+        assert.strictEqual(hdn.chainCode, hd.chainCode)
+        assert.strictEqual(hdn.depth, f.depth >>> 0)
+        assert.strictEqual(hdn.index, f.index >>> 0)
+        assert.strictEqual(hdn.isNeutered(), true)
+
+        // does not modify the original
+        assert.strictEqual(hd.toBase58(), f.base58Priv)
+        assert.strictEqual(hd.isNeutered(), false)
+      })
+    })
+  })
+
+  describe('derive', function () {
+    function verifyVector (hd, v) {
+      if (hd.isNeutered()) {
+        assert.strictEqual(hd.toBase58(), v.base58)
+      } else {
+        assert.strictEqual(hd.neutered().toBase58(), v.base58)
+        assert.strictEqual(hd.toBase58(), v.base58Priv)
+      }
+
+      assert.strictEqual(hd.getFingerprint().toString('hex'), v.fingerprint)
+      assert.strictEqual(hd.getIdentifier().toString('hex'), v.identifier)
+      assert.strictEqual(hd.getAddress(), v.address)
+      assert.strictEqual(hd.keyPair.toWIF(), v.wif)
+      assert.strictEqual(hd.keyPair.getPublicKeyBuffer().toString('hex'), v.pubKey)
+      assert.strictEqual(hd.chainCode.toString('hex'), v.chainCode)
+      assert.strictEqual(hd.depth, v.depth >>> 0)
+      assert.strictEqual(hd.index, v.index >>> 0)
+    }
+
+    fixtures.valid.forEach(function (f) {
+      var network = NETWORKS[f.network]
+      var hd = HDNode.fromSeedHex(f.master.seed, network)
+      var master = hd
+
+      // testing deriving path from master
+      f.children.forEach(function (c) {
+        it(c.path + ' from ' + f.master.fingerprint + ' by path', function () {
+          var child = master.derivePath(c.path)
+          var childNoM = master.derivePath(c.path.slice(2)) // no m/ on path
+
+          verifyVector(child, c)
+          verifyVector(childNoM, c)
+        })
+      })
+
+      // testing deriving path from children
+      f.children.forEach(function (c, i) {
+        var cn = master.derivePath(c.path)
+
+        f.children.slice(i + 1).forEach(function (cc) {
+          it(cc.path + ' from ' + c.fingerprint + ' by path', function () {
+            var ipath = cc.path.slice(2).split('/').slice(i + 1).join('/')
+            var child = cn.derivePath(ipath)
+            verifyVector(child, cc)
+
+            assert.throws(function () {
+              cn.derivePath('m/' + ipath)
+            }, /Not a master node/)
+          })
+        })
+      })
+
+      // FIXME: test data is only testing Private -> private for now
+      f.children.forEach(function (c) {
+        if (c.m === undefined) return
+
+        it(c.path + ' from ' + f.master.fingerprint, function () {
+          if (c.hardened) {
+            hd = hd.deriveHardened(c.m)
+          } else {
+            hd = hd.derive(c.m)
+          }
+
+          verifyVector(hd, c)
+        })
+      })
+    })
+
+    it('works for Private -> public (neutered)', function () {
+      var f = fixtures.valid[1]
+      var c = f.children[0]
+
+      var master = HDNode.fromBase58(f.master.base58Priv, NETWORKS_LIST)
+      var child = master.derive(c.m).neutered()
+
+      assert.strictEqual(child.toBase58(), c.base58)
+    })
+
+    it('works for Private -> public (neutered, hardened)', function () {
+      var f = fixtures.valid[0]
+      var c = f.children[0]
+
+      var master = HDNode.fromBase58(f.master.base58Priv, NETWORKS_LIST)
+      var child = master.deriveHardened(c.m).neutered()
+
+      assert.strictEqual(c.base58, child.toBase58())
+    })
+
+    it('works for Public -> public', function () {
+      var f = fixtures.valid[1]
+      var c = f.children[0]
+
+      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
+      var child = master.derive(c.m)
+
+      assert.strictEqual(c.base58, child.toBase58())
+    })
+
+    it('throws on Public -> public (hardened)', function () {
+      var f = fixtures.valid[0]
+      var c = f.children[0]
+
+      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
+
+      assert.throws(function () {
+        master.deriveHardened(c.m)
+      }, /Could not derive hardened child key/)
+    })
+
+    it('throws on wrong types', function () {
+      var f = fixtures.valid[0]
+      var master = HDNode.fromBase58(f.master.base58, NETWORKS_LIST)
+
+      fixtures.invalid.derive.forEach(function (fx) {
+        assert.throws(function () {
+          master.derive(fx)
+        }, /Expected UInt32/)
+      })
+
+      fixtures.invalid.deriveHardened.forEach(function (fx) {
+        assert.throws(function () {
+          master.deriveHardened(fx)
+        }, /Expected UInt31/)
+      })
+
+      fixtures.invalid.derivePath.forEach(function (fx) {
+        assert.throws(function () {
+          master.derivePath(fx)
+        }, /Expected BIP32 derivation path/)
+      })
+    })
+
+    it('works when private key has leading zeros', function () {
+      var key = 'xprv9s21ZrQH143K3ckY9DgU79uMTJkQRLdbCCVDh81SnxTgPzLLGax6uHeBULTtaEtcAvKjXfT7ZWtHzKjTpujMkUd9dDb8msDeAfnJxrgAYhr'
+      var hdkey = HDNode.fromBase58(key)
+      assert.strictEqual(hdkey.keyPair.d.toBuffer(32).toString('hex'), '00000055378cf5fafb56c711c674143f9b0ee82ab0ba2924f19b64f5ae7cdbfd')
+      var child = hdkey.derivePath('m/44\'/0\'/0\'/0/0\'')
+      assert.strictEqual(child.keyPair.d.toBuffer().toString('hex'), '3348069561d2a0fb925e74bf198762acc47dce7db27372257d2d959a9e6f8aeb')
+    })
+  })
+})
diff --git a/test/integration/_regtest.js b/test/integration/_regtest.js
new file mode 100644
index 0000000..0bb1a40
--- /dev/null
+++ b/test/integration/_regtest.js
@@ -0,0 +1,87 @@
+var assert = require('assert')
+var bitcoin = require('../../')
+var dhttp = require('dhttp/200')
+
+var APIPASS = process.env.APIPASS || 'satoshi'
+var APIURL = 'https://api.dcousens.cloud/1'
+
+function broadcast (txHex, callback) {
+  dhttp({
+    method: 'PUT',
+    url: APIURL + '/t/push',
+    body: txHex
+  }, callback)
+}
+
+function mine (count, callback) {
+  dhttp({
+    method: 'POST',
+    url: APIURL + '/r/generate?count=' + count + '&key=' + APIPASS
+  }, callback)
+}
+
+function height (callback) {
+  dhttp({
+    method: 'GET',
+    url: APIURL + '/b/best/height'
+  }, callback)
+}
+
+function faucet (address, value, callback) {
+  dhttp({
+    method: 'POST',
+    url: APIURL + '/r/faucet?address=' + address + '&value=' + value + '&key=' + APIPASS
+  }, function (err, txId) {
+    if (err) return callback(err)
+
+    unspents(address, function (err, results) {
+      if (err) return callback(err)
+
+      callback(null, results.filter(x => x.txId === txId).pop())
+    })
+  })
+}
+
+function fetch (txId, callback) {
+  dhttp({
+    method: 'GET',
+    url: APIURL + '/t/' + txId + '/json'
+  }, callback)
+}
+
+function unspents (address, callback) {
+  dhttp({
+    method: 'GET',
+    url: APIURL + '/a/' + address + '/unspents'
+  }, callback)
+}
+
+function verify (txo, callback) {
+  fetch(txo.txId, function (err, tx) {
+    if (err) return callback(err)
+
+    var txoActual = tx.outs[txo.vout]
+    if (txo.address) assert.strictEqual(txoActual.address, txo.address)
+    if (txo.value) assert.strictEqual(txoActual.value, txo.value)
+    callback()
+  })
+}
+
+function randomAddress () {
+  return bitcoin.ECPair.makeRandom({
+    network: bitcoin.networks.testnet
+  }).getAddress()
+}
+
+module.exports = {
+  broadcast: broadcast,
+  faucet: faucet,
+  fetch: fetch,
+  height: height,
+  mine: mine,
+  network: bitcoin.networks.testnet,
+  unspents: unspents,
+  verify: verify,
+  randomAddress: randomAddress,
+  RANDOM_ADDRESS: randomAddress()
+}
diff --git a/test/integration/_regtest.ts b/test/integration/_regtest.ts
deleted file mode 100644
index 52a6be8..0000000
--- a/test/integration/_regtest.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { RegtestUtils } from 'regtest-client';
-
-const APIPASS = process.env.APIPASS || 'satoshi';
-const APIURL = process.env.APIURL || 'https://regtest.bitbank.cc/1';
-
-export const regtestUtils = new RegtestUtils({ APIPASS, APIURL });
diff --git a/test/integration/addresses.js b/test/integration/addresses.js
new file mode 100644
index 0000000..74cd487
--- /dev/null
+++ b/test/integration/addresses.js
@@ -0,0 +1,140 @@
+/* global describe, it */
+
+var assert = require('assert')
+var bigi = require('bigi')
+var bitcoin = require('../../')
+var dhttp = require('dhttp/200')
+
+// deterministic RNG for testing only
+function rng () { return Buffer.from('zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz') }
+
+describe('bitcoinjs-lib (addresses)', function () {
+  it('can generate a random address', function () {
+    var keyPair = bitcoin.ECPair.makeRandom({ rng: rng })
+    var address = keyPair.getAddress()
+
+    assert.strictEqual(address, '1F5VhMHukdnUES9kfXqzPzMeF1GPHKiF64')
+  })
+
+  it('can generate an address from a SHA256 hash', function () {
+    var hash = bitcoin.crypto.sha256(Buffer.from('correct horse battery staple'))
+    var d = bigi.fromBuffer(hash)
+
+    var keyPair = new bitcoin.ECPair(d)
+    var address = keyPair.getAddress()
+
+    assert.strictEqual(address, '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8')
+  })
+
+  it('can import an address via WIF', function () {
+    var keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
+    var address = keyPair.getAddress()
+
+    assert.strictEqual(address, '19AAjaTUbRjQCMuVczepkoPswiZRhjtg31')
+  })
+
+  it('can generate a 2-of-3 multisig P2SH address', function () {
+    var pubKeys = [
+      '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
+      '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
+      '03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9'
+    ].map(function (hex) { return Buffer.from(hex, 'hex') })
+
+    var redeemScript = bitcoin.script.multisig.output.encode(2, pubKeys) // 2 of 3
+    var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript))
+    var address = bitcoin.address.fromOutputScript(scriptPubKey)
+
+    assert.strictEqual(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7')
+  })
+
+  it('can generate a SegWit address', function () {
+    var keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
+    var pubKey = keyPair.getPublicKeyBuffer()
+
+    var scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(pubKey))
+    var address = bitcoin.address.fromOutputScript(scriptPubKey)
+
+    assert.strictEqual(address, 'bc1qt97wqg464zrhnx23upykca5annqvwkwujjglky')
+  })
+
+  it('can generate a SegWit address (via P2SH)', function () {
+    var keyPair = bitcoin.ECPair.fromWIF('Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct')
+    var pubKey = keyPair.getPublicKeyBuffer()
+
+    var redeemScript = bitcoin.script.witnessPubKeyHash.output.encode(bitcoin.crypto.hash160(pubKey))
+    var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript))
+    var address = bitcoin.address.fromOutputScript(scriptPubKey)
+
+    assert.strictEqual(address, '34AgLJhwXrvmkZS1o5TrcdeevMt22Nar53')
+  })
+
+  it('can generate a SegWit 3-of-4 multisig address', function () {
+    var pubKeys = [
+      '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
+      '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
+      '023e4740d0ba639e28963f3476157b7cf2fb7c6fdf4254f97099cf8670b505ea59',
+      '03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9'
+    ].map(function (hex) { return Buffer.from(hex, 'hex') })
+
+    var witnessScript = bitcoin.script.multisig.output.encode(3, pubKeys) // 3 of 4
+    var scriptPubKey = bitcoin.script.witnessScriptHash.output.encode(bitcoin.crypto.sha256(witnessScript))
+    var address = bitcoin.address.fromOutputScript(scriptPubKey)
+
+    assert.strictEqual(address, 'bc1q75f6dv4q8ug7zhujrsp5t0hzf33lllnr3fe7e2pra3v24mzl8rrqtp3qul')
+  })
+
+  it('can generate a SegWit 2-of-2 multisig address (via P2SH)', function () {
+    var pubKeys = [
+      '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
+      '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9'
+    ].map(function (hex) { return Buffer.from(hex, 'hex') })
+
+    var witnessScript = bitcoin.script.multisig.output.encode(2, pubKeys) // 2 of 2
+    var redeemScript = bitcoin.script.witnessScriptHash.output.encode(bitcoin.crypto.sha256(witnessScript))
+    var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript))
+    var address = bitcoin.address.fromOutputScript(scriptPubKey)
+
+    assert.strictEqual(address, '3P4mrxQfmExfhxqjLnR2Ah4WES5EB1KBrN')
+  })
+
+  it('can support the retrieval of transactions for an address (via 3PBP)', function (done) {
+    var keyPair = bitcoin.ECPair.makeRandom()
+    var address = keyPair.getAddress()
+
+    dhttp({
+      method: 'POST',
+      url: 'https://api.ei8ht.com.au/3/addrtxs',
+      body: {
+        addrs: [address],
+        height: 0
+      }
+    }, function (err, transactions) {
+      if (err) return done(err)
+
+      // random private keys [probably] have no transactions
+      assert.strictEqual(Object.keys(transactions).length, 0)
+      done()
+    })
+  })
+
+  // other networks
+  it('can generate a Testnet address', function () {
+    var testnet = bitcoin.networks.testnet
+    var keyPair = bitcoin.ECPair.makeRandom({ network: testnet, rng: rng })
+    var wif = keyPair.toWIF()
+    var address = keyPair.getAddress()
+
+    assert.strictEqual(address, 'mubSzQNtZfDj1YdNP6pNDuZy6zs6GDn61L')
+    assert.strictEqual(wif, 'cRgnQe9MUu1JznntrLaoQpB476M8PURvXVQB5R2eqms5tXnzNsrr')
+  })
+
+  it('can generate a Litecoin address', function () {
+    var litecoin = bitcoin.networks.litecoin
+    var keyPair = bitcoin.ECPair.makeRandom({ network: litecoin, rng: rng })
+    var wif = keyPair.toWIF()
+    var address = keyPair.getAddress()
+
+    assert.strictEqual(address, 'LZJSxZbjqJ2XVEquqfqHg1RQTDdfST5PTn')
+    assert.strictEqual(wif, 'T7A4PUSgTDHecBxW1ZiYFrDNRih2o7M8Gf9xpoCgudPF9gDiNvuS')
+  })
+})
diff --git a/test/integration/addresses.spec.ts b/test/integration/addresses.spec.ts
deleted file mode 100644
index d6e758b..0000000
--- a/test/integration/addresses.spec.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-import * as assert from 'assert';
-import ECPairFactory from 'ecpair';
-import * as ecc from 'tiny-secp256k1';
-import { describe, it } from 'mocha';
-import * as bitcoin from '../..';
-import { regtestUtils } from './_regtest';
-
-const ECPair = ECPairFactory(ecc);
-const dhttp = regtestUtils.dhttp;
-const TESTNET = bitcoin.networks.testnet;
-
-describe('bitcoinjs-lib (addresses)', () => {
-  it(
-    'can generate a random address [and support the retrieval of ' +
-      'transactions for that address (via 3PBP)]',
-    async () => {
-      const keyPair = ECPair.makeRandom();
-      const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey });
-
-      // bitcoin P2PKH addresses start with a '1'
-      assert.strictEqual(address!.startsWith('1'), true);
-
-      const result = await dhttp({
-        method: 'GET',
-        url: 'https://blockchain.info/rawaddr/' + address,
-      });
-
-      // random private keys [probably!] have no transactions
-      assert.strictEqual((result as any).n_tx, 0);
-      assert.strictEqual((result as any).total_received, 0);
-      assert.strictEqual((result as any).total_sent, 0);
-    },
-  );
-
-  it('can import an address via WIF', () => {
-    const keyPair = ECPair.fromWIF(
-      'KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn',
-    );
-    const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey });
-
-    assert.strictEqual(address, '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH');
-  });
-
-  it('can generate a P2SH, pay-to-multisig (2-of-3) address', () => {
-    const pubkeys = [
-      '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
-      '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
-      '03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9',
-    ].map(hex => Buffer.from(hex, 'hex'));
-    const { address } = bitcoin.payments.p2sh({
-      redeem: bitcoin.payments.p2ms({ m: 2, pubkeys }),
-    });
-
-    assert.strictEqual(address, '36NUkt6FWUi3LAWBqWRdDmdTWbt91Yvfu7');
-  });
-
-  it('can generate a SegWit address', () => {
-    const keyPair = ECPair.fromWIF(
-      'KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn',
-    );
-    const { address } = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey });
-
-    assert.strictEqual(address, 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4');
-  });
-
-  it('can generate a SegWit address (via P2SH)', () => {
-    const keyPair = ECPair.fromWIF(
-      'KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn',
-    );
-    const { address } = bitcoin.payments.p2sh({
-      redeem: bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey }),
-    });
-
-    assert.strictEqual(address, '3JvL6Ymt8MVWiCNHC7oWU6nLeHNJKLZGLN');
-  });
-
-  it('can generate a P2WSH (SegWit), pay-to-multisig (3-of-4) address', () => {
-    const pubkeys = [
-      '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
-      '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
-      '023e4740d0ba639e28963f3476157b7cf2fb7c6fdf4254f97099cf8670b505ea59',
-      '03c6103b3b83e4a24a0e33a4df246ef11772f9992663db0c35759a5e2ebf68d8e9',
-    ].map(hex => Buffer.from(hex, 'hex'));
-    const { address } = bitcoin.payments.p2wsh({
-      redeem: bitcoin.payments.p2ms({ m: 3, pubkeys }),
-    });
-
-    assert.strictEqual(
-      address,
-      'bc1q75f6dv4q8ug7zhujrsp5t0hzf33lllnr3fe7e2pra3v24mzl8rrqtp3qul',
-    );
-  });
-
-  it('can generate a P2SH(P2WSH(...)), pay-to-multisig (2-of-2) address', () => {
-    const pubkeys = [
-      '026477115981fe981a6918a6297d9803c4dc04f328f22041bedff886bbc2962e01',
-      '02c96db2302d19b43d4c69368babace7854cc84eb9e061cde51cfa77ca4a22b8b9',
-    ].map(hex => Buffer.from(hex, 'hex'));
-    const { address } = bitcoin.payments.p2sh({
-      redeem: bitcoin.payments.p2wsh({
-        redeem: bitcoin.payments.p2ms({ m: 2, pubkeys }),
-      }),
-    });
-
-    assert.strictEqual(address, '3P4mrxQfmExfhxqjLnR2Ah4WES5EB1KBrN');
-  });
-
-  // examples using other network information
-  it('can generate a Testnet address', () => {
-    const keyPair = ECPair.makeRandom({ network: TESTNET });
-    const { address } = bitcoin.payments.p2pkh({
-      pubkey: keyPair.publicKey,
-      network: TESTNET,
-    });
-
-    // bitcoin testnet P2PKH addresses start with a 'm' or 'n'
-    assert.strictEqual(
-      address!.startsWith('m') || address!.startsWith('n'),
-      true,
-    );
-  });
-
-  it('can generate a Litecoin address', () => {
-    // WARNING: although possible, bitcoinjs is NOT necessarily compatible with Litecoin
-    const LITECOIN = {
-      messagePrefix: '\x19Litecoin Signed Message:\n',
-      bech32: 'ltc',
-      bip32: {
-        public: 0x019da462,
-        private: 0x019d9cfe,
-      },
-      pubKeyHash: 0x30,
-      scriptHash: 0x32,
-      wif: 0xb0,
-    };
-
-    const keyPair = ECPair.makeRandom({ network: LITECOIN });
-    const { address } = bitcoin.payments.p2pkh({
-      pubkey: keyPair.publicKey,
-      network: LITECOIN,
-    });
-
-    assert.strictEqual(address!.startsWith('L'), true);
-  });
-});
diff --git a/test/integration/bip32.js b/test/integration/bip32.js
new file mode 100644
index 0000000..1908166
--- /dev/null
+++ b/test/integration/bip32.js
@@ -0,0 +1,99 @@
+/* global describe, it */
+
+var assert = require('assert')
+var bip39 = require('bip39')
+var bitcoin = require('../../')
+
+describe('bitcoinjs-lib (BIP32)', function () {
+  it('can import a BIP32 testnet xpriv and export to WIF', function () {
+    var xpriv = 'tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK'
+    var node = bitcoin.HDNode.fromBase58(xpriv, bitcoin.networks.testnet)
+
+    assert.equal(node.keyPair.toWIF(), 'cQfoY67cetFNunmBUX5wJiw3VNoYx3gG9U9CAofKE6BfiV1fSRw7')
+  })
+
+  it('can export a BIP32 xpriv, then import it', function () {
+    var mnemonic = 'praise you muffin lion enable neck grocery crumble super myself license ghost'
+    var seed = bip39.mnemonicToSeed(mnemonic)
+    var node = bitcoin.HDNode.fromSeedBuffer(seed)
+    var string = node.toBase58()
+    var restored = bitcoin.HDNode.fromBase58(string)
+
+    assert.equal(node.getAddress(), restored.getAddress()) // same public key
+    assert.equal(node.keyPair.toWIF(), restored.keyPair.toWIF()) // same private key
+  })
+
+  it('can export a BIP32 xpub', function () {
+    var mnemonic = 'praise you muffin lion enable neck grocery crumble super myself license ghost'
+    var seed = bip39.mnemonicToSeed(mnemonic)
+    var node = bitcoin.HDNode.fromSeedBuffer(seed)
+    var string = node.neutered().toBase58()
+
+    assert.equal(string, 'xpub661MyMwAqRbcGhVeaVfEBA25e3cP9DsJQZoE8iep5fZSxy3TnPBNBgWnMZx56oreNc48ZoTkQfatNJ9VWnQ7ZcLZcVStpaXLTeG8bGrzX3n')
+  })
+
+  it('can create a BIP32, bitcoin, account 0, external address', function () {
+    var path = "m/0'/0/0"
+    var root = bitcoin.HDNode.fromSeedHex('dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd')
+
+    var child1 = root.derivePath(path)
+
+    // option 2, manually
+    var child1b = root.deriveHardened(0)
+      .derive(0)
+      .derive(0)
+
+    assert.equal(child1.getAddress(), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7')
+    assert.equal(child1b.getAddress(), '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7')
+  })
+
+  it('can create a BIP44, bitcoin, account 0, external address', function () {
+    var root = bitcoin.HDNode.fromSeedHex('dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd')
+
+    var child1 = root.derivePath("m/44'/0'/0'/0/0")
+
+    // option 2, manually
+    var child1b = root.deriveHardened(44)
+      .deriveHardened(0)
+      .deriveHardened(0)
+      .derive(0)
+      .derive(0)
+
+    assert.equal(child1.getAddress(), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au')
+    assert.equal(child1b.getAddress(), '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au')
+  })
+
+  it('can create a BIP49, bitcoin testnet, account 0, external address', function () {
+    var mnemonic = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'
+    var seed = bip39.mnemonicToSeed(mnemonic)
+    var root = bitcoin.HDNode.fromSeedBuffer(seed)
+
+    var path = "m/49'/1'/0'/0/0"
+    var child = root.derivePath(path)
+
+    var keyhash = bitcoin.crypto.hash160(child.getPublicKeyBuffer())
+    var scriptSig = bitcoin.script.witnessPubKeyHash.output.encode(keyhash)
+    var addressBytes = bitcoin.crypto.hash160(scriptSig)
+    var outputScript = bitcoin.script.scriptHash.output.encode(addressBytes)
+    var address = bitcoin.address.fromOutputScript(outputScript, bitcoin.networks.testnet)
+
+    assert.equal(address, '2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2')
+  })
+
+  it('can use BIP39 to generate BIP32 addresses', function () {
+//     var mnemonic = bip39.generateMnemonic()
+    var mnemonic = 'praise you muffin lion enable neck grocery crumble super myself license ghost'
+    assert(bip39.validateMnemonic(mnemonic))
+
+    var seed = bip39.mnemonicToSeed(mnemonic)
+    var root = bitcoin.HDNode.fromSeedBuffer(seed)
+
+    // receive addresses
+    assert.strictEqual(root.derivePath("m/0'/0/0").getAddress(), '1AVQHbGuES57wD68AJi7Gcobc3RZrfYWTC')
+    assert.strictEqual(root.derivePath("m/0'/0/1").getAddress(), '1Ad6nsmqDzbQo5a822C9bkvAfrYv9mc1JL')
+
+    // change addresses
+    assert.strictEqual(root.derivePath("m/0'/1/0").getAddress(), '1349KVc5NgedaK7DvuD4xDFxL86QN1Hvdn')
+    assert.strictEqual(root.derivePath("m/0'/1/1").getAddress(), '1EAvj4edpsWcSer3duybAd4KiR4bCJW5J6')
+  })
+})
diff --git a/test/integration/bip32.spec.ts b/test/integration/bip32.spec.ts
deleted file mode 100644
index 938c281..0000000
--- a/test/integration/bip32.spec.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-import * as assert from 'assert';
-import BIP32Factory from 'bip32';
-import * as ecc from 'tiny-secp256k1';
-import * as bip39 from 'bip39';
-import { describe, it } from 'mocha';
-import * as bitcoin from '../..';
-
-const bip32 = BIP32Factory(ecc);
-
-function getAddress(node: any, network?: any): string {
-  return bitcoin.payments.p2pkh({ pubkey: node.publicKey, network }).address!;
-}
-
-describe('bitcoinjs-lib (BIP32)', () => {
-  it('can import a BIP32 testnet xpriv and export to WIF', () => {
-    const xpriv =
-      'tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK';
-    const node = bip32.fromBase58(xpriv, bitcoin.networks.testnet);
-
-    assert.strictEqual(
-      node.toWIF(),
-      'cQfoY67cetFNunmBUX5wJiw3VNoYx3gG9U9CAofKE6BfiV1fSRw7',
-    );
-  });
-
-  it('can export a BIP32 xpriv, then import it', () => {
-    const mnemonic =
-      'praise you muffin lion enable neck grocery crumble super myself license ghost';
-    const seed = bip39.mnemonicToSeedSync(mnemonic);
-    const node = bip32.fromSeed(seed);
-    const strng = node.toBase58();
-    const restored = bip32.fromBase58(strng);
-
-    assert.strictEqual(getAddress(node), getAddress(restored)); // same public key
-    assert.strictEqual(node.toWIF(), restored.toWIF()); // same private key
-  });
-
-  it('can export a BIP32 xpub', () => {
-    const mnemonic =
-      'praise you muffin lion enable neck grocery crumble super myself license ghost';
-    const seed = bip39.mnemonicToSeedSync(mnemonic);
-    const node = bip32.fromSeed(seed);
-    const strng = node.neutered().toBase58();
-
-    assert.strictEqual(
-      strng,
-      'xpub661MyMwAqRbcGhVeaVfEBA25e3cP9DsJQZoE8iep5fZSxy3TnPBNBgWnMZx56oreNc48ZoTkQfatNJ9VWnQ7ZcLZcVStpaXLTeG8bGrzX3n',
-    );
-  });
-
-  it('can create a BIP32, bitcoin, account 0, external address', () => {
-    const path = "m/0'/0/0";
-    const root = bip32.fromSeed(
-      Buffer.from(
-        'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd',
-        'hex',
-      ),
-    );
-
-    const child1 = root.derivePath(path);
-
-    // option 2, manually
-    const child1b = root
-      .deriveHardened(0)
-      .derive(0)
-      .derive(0);
-
-    assert.strictEqual(
-      getAddress(child1),
-      '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7',
-    );
-    assert.strictEqual(
-      getAddress(child1b),
-      '1JHyB1oPXufr4FXkfitsjgNB5yRY9jAaa7',
-    );
-  });
-
-  it('can create a BIP44, bitcoin, account 0, external address', () => {
-    const root = bip32.fromSeed(
-      Buffer.from(
-        'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd',
-        'hex',
-      ),
-    );
-
-    const child1 = root.derivePath("m/44'/0'/0'/0/0");
-
-    // option 2, manually
-    const child1b = root
-      .deriveHardened(44)
-      .deriveHardened(0)
-      .deriveHardened(0)
-      .derive(0)
-      .derive(0);
-
-    assert.strictEqual(
-      getAddress(child1),
-      '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au',
-    );
-    assert.strictEqual(
-      getAddress(child1b),
-      '12Tyvr1U8A3ped6zwMEU5M8cx3G38sP5Au',
-    );
-  });
-
-  it('can create a BIP49, bitcoin testnet, account 0, external address', () => {
-    const mnemonic =
-      'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
-    const seed = bip39.mnemonicToSeedSync(mnemonic);
-    const root = bip32.fromSeed(seed);
-
-    const path = "m/49'/1'/0'/0/0";
-    const child = root.derivePath(path);
-
-    const { address } = bitcoin.payments.p2sh({
-      redeem: bitcoin.payments.p2wpkh({
-        pubkey: child.publicKey,
-        network: bitcoin.networks.testnet,
-      }),
-      network: bitcoin.networks.testnet,
-    });
-    assert.strictEqual(address, '2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2');
-  });
-
-  it('can use BIP39 to generate BIP32 addresses', () => {
-    // var mnemonic = bip39.generateMnemonic()
-    const mnemonic =
-      'praise you muffin lion enable neck grocery crumble super myself license ghost';
-    assert(bip39.validateMnemonic(mnemonic));
-
-    const seed = bip39.mnemonicToSeedSync(mnemonic);
-    const root = bip32.fromSeed(seed);
-
-    // receive addresses
-    assert.strictEqual(
-      getAddress(root.derivePath("m/0'/0/0")),
-      '1AVQHbGuES57wD68AJi7Gcobc3RZrfYWTC',
-    );
-    assert.strictEqual(
-      getAddress(root.derivePath("m/0'/0/1")),
-      '1Ad6nsmqDzbQo5a822C9bkvAfrYv9mc1JL',
-    );
-
-    // change addresses
-    assert.strictEqual(
-      getAddress(root.derivePath("m/0'/1/0")),
-      '1349KVc5NgedaK7DvuD4xDFxL86QN1Hvdn',
-    );
-    assert.strictEqual(
-      getAddress(root.derivePath("m/0'/1/1")),
-      '1EAvj4edpsWcSer3duybAd4KiR4bCJW5J6',
-    );
-  });
-});
diff --git a/test/integration/blocks.js b/test/integration/blocks.js
new file mode 100644
index 0000000..58faab2
--- /dev/null
+++ b/test/integration/blocks.js
@@ -0,0 +1,22 @@
+/* global describe, it */
+'use strict'
+
+var assert = require('assert')
+var bitcoin = require('../../')
+
+describe('bitcoinjs-lib (blocks)', function () {
+  it('can extract a height from a CoinBase transaction', function () {
+    // from 00000000000000000097669cdca131f24d40c4cc7d80eaa65967a2d09acf6ce6
+    let txHex = '010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff50037f9a07174d696e656420627920416e74506f6f6c685b205a2b1f7bfabe6d6d36afe1910eca9405b66f97750940a656e38e2c0312958190ff8e98fd16761d220400000000000000aa340000d49f0000ffffffff02b07fc366000000001976a9148349212dc27ce3ab4c5b29b85c4dec643d764b1788ac0000000000000000266a24aa21a9ed72d9432948505e3d3062f1307a3f027a5dea846ff85e47159680919c12bf1e400120000000000000000000000000000000000000000000000000000000000000000000000000'
+    let tx = bitcoin.Transaction.fromHex(txHex)
+
+    assert.strictEqual(tx.ins.length, 1)
+    let script = tx.ins[0].script
+//  bitcoin.script.decompile(script) // returns [] :(
+
+    assert.strictEqual(script[0], 0x03)
+    let heightBuffer = script.slice(1, 4)
+    let height = bitcoin.script.number.decode(heightBuffer)
+    assert.strictEqual(height, 498303)
+  })
+})
diff --git a/test/integration/blocks.spec.ts b/test/integration/blocks.spec.ts
deleted file mode 100644
index a98c5eb..0000000
--- a/test/integration/blocks.spec.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as assert from 'assert';
-import { describe, it } from 'mocha';
-import * as bitcoin from '../..';
-
-describe('bitcoinjs-lib (blocks)', () => {
-  it('can extract a height from a CoinBase transaction', () => {
-    // from 00000000000000000097669cdca131f24d40c4cc7d80eaa65967a2d09acf6ce6
-    const txHex =
-      '010000000001010000000000000000000000000000000000000000000000000000000' +
-      '000000000ffffffff50037f9a07174d696e656420627920416e74506f6f6c685b205a' +
-      '2b1f7bfabe6d6d36afe1910eca9405b66f97750940a656e38e2c0312958190ff8e98f' +
-      'd16761d220400000000000000aa340000d49f0000ffffffff02b07fc3660000000019' +
-      '76a9148349212dc27ce3ab4c5b29b85c4dec643d764b1788ac0000000000000000266' +
-      'a24aa21a9ed72d9432948505e3d3062f1307a3f027a5dea846ff85e47159680919c12' +
-      'bf1e40012000000000000000000000000000000000000000000000000000000000000' +
-      '0000000000000';
-    const tx = bitcoin.Transaction.fromHex(txHex);
-
-    assert.strictEqual(tx.ins.length, 1);
-    const script = tx.ins[0].script;
-    // bitcoin.script.decompile(script) // returns [] :(
-
-    assert.strictEqual(script[0], 0x03);
-    const heightBuffer = script.slice(1, 4);
-    const height = bitcoin.script.number.decode(heightBuffer);
-    assert.strictEqual(height, 498303);
-  });
-});
diff --git a/test/integration/cltv.js b/test/integration/cltv.js
new file mode 100644
index 0000000..8f1488f
--- /dev/null
+++ b/test/integration/cltv.js
@@ -0,0 +1,213 @@
+/* global describe, it */
+
+var assert = require('assert')
+var bitcoin = require('../../')
+var regtestUtils = require('./_regtest')
+var regtest = regtestUtils.network
+var bip65 = require('bip65')
+
+var alice = bitcoin.ECPair.fromWIF('cScfkGjbzzoeewVWmU2hYPUHeVGJRDdFt7WhmrVVGkxpmPP8BHWe', regtest)
+var bob = bitcoin.ECPair.fromWIF('cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsLwjHXA9x', regtest)
+
+describe('bitcoinjs-lib (transactions w/ CLTV)', function () {
+  var hashType = bitcoin.Transaction.SIGHASH_ALL
+
+  function cltvCheckSigOutput (aQ, bQ, lockTime) {
+    return bitcoin.script.compile([
+      bitcoin.opcodes.OP_IF,
+      bitcoin.script.number.encode(lockTime),
+      bitcoin.opcodes.OP_CHECKLOCKTIMEVERIFY,
+      bitcoin.opcodes.OP_DROP,
+
+      bitcoin.opcodes.OP_ELSE,
+      bQ.getPublicKeyBuffer(),
+      bitcoin.opcodes.OP_CHECKSIGVERIFY,
+      bitcoin.opcodes.OP_ENDIF,
+
+      aQ.getPublicKeyBuffer(),
+      bitcoin.opcodes.OP_CHECKSIG
+    ])
+  }
+
+  function utcNow () {
+    return Math.floor(Date.now() / 1000)
+  }
+
+  // expiry past, {Alice's signature} OP_TRUE
+  it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the past)', function (done) {
+    this.timeout(30000)
+
+    // 3 hours ago
+    var lockTime = bip65.encode({ utc: utcNow() - (3600 * 3) })
+    var redeemScript = cltvCheckSigOutput(alice, bob, lockTime)
+    var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript))
+    var address = bitcoin.address.fromOutputScript(scriptPubKey, regtest)
+
+    // fund the P2SH(CLTV) address
+    regtestUtils.faucet(address, 1e5, function (err, unspent) {
+      if (err) return done(err)
+
+      var txb = new bitcoin.TransactionBuilder(regtest)
+      txb.setLockTime(lockTime)
+      txb.addInput(unspent.txId, unspent.vout, 0xfffffffe)
+      txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4)
+
+      // {Alice's signature} OP_TRUE
+      var tx = txb.buildIncomplete()
+      var signatureHash = tx.hashForSignature(0, redeemScript, hashType)
+      var redeemScriptSig = bitcoin.script.scriptHash.input.encode([
+        alice.sign(signatureHash).toScriptSignature(hashType),
+        bitcoin.opcodes.OP_TRUE
+      ], redeemScript)
+      tx.setInputScript(0, redeemScriptSig)
+
+      regtestUtils.broadcast(tx.toHex(), function (err) {
+        if (err) return done(err)
+
+        regtestUtils.verify({
+          txId: tx.getId(),
+          address: regtestUtils.RANDOM_ADDRESS,
+          vout: 0,
+          value: 7e4
+        }, done)
+      })
+    })
+  })
+
+  // expiry will pass, {Alice's signature} OP_TRUE
+  it('can create (and broadcast via 3PBP) a Transaction where Alice can redeem the output after the expiry (in the future)', function (done) {
+    this.timeout(30000)
+
+    regtestUtils.height(function (err, height) {
+      if (err) return done(err)
+
+      // 50 blocks from now
+      var lockTime = bip65.encode({ blocks: height + 50 })
+      var redeemScript = cltvCheckSigOutput(alice, bob, lockTime)
+      var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript))
+      var address = bitcoin.address.fromOutputScript(scriptPubKey, regtest)
+
+      // fund the P2SH(CLTV) address
+      regtestUtils.faucet(address, 1e5, function (err, unspent) {
+        if (err) return done(err)
+
+        var txb = new bitcoin.TransactionBuilder(regtest)
+        txb.setLockTime(lockTime)
+        txb.addInput(unspent.txId, unspent.vout, 0xfffffffe)
+        txb.addOutput(regtestUtils.RANDOM_ADDRESS, 7e4)
+
+        // {Alice's signature} OP_TRUE
+        var tx = txb.buildIncomplete()
+        var signatureHash = tx.hashForSignature(0, redeemScript, hashType)
+        var redeemScriptSig = bitcoin.script.scriptHash.input.encode([
+          alice.sign(signatureHash).toScriptSignature(hashType),
+          bitcoin.opcodes.OP_TRUE
+        ], redeemScript)
+        tx.setInputScript(0, redeemScriptSig)
+
+        regtestUtils.broadcast(tx.toHex(), function (err) {
+          // fails before the expiry
+          assert.throws(function () {
+            if (err) throw err
+          }, /Error: 64: non-final/)
+
+          // into the future!
+          regtestUtils.mine(51, function (err) {
+            if (err) return done(err)
+
+            regtestUtils.broadcast(tx.toHex(), function (err) {
+              if (err) return done(err)
+
+              regtestUtils.verify({
+                txId: tx.getId(),
+                address: regtestUtils.RANDOM_ADDRESS,
+                vout: 0,
+                value: 7e4
+              }, done)
+            })
+          })
+        })
+      })
+    })
+  })
+
+  // expiry ignored, {Bob's signature} {Alice's signature} OP_FALSE
+  it('can create (and broadcast via 3PBP) a Transaction where Alice and Bob can redeem the output at any time', function (done) {
+    this.timeout(30000)
+
+    // two hours ago
+    var timeUtc = utcNow() - (3600 * 2)
+    var redeemScript = cltvCheckSigOutput(alice, bob, timeUtc)
+    var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript))
+    var address = bitcoin.address.fromOutputScript(scriptPubKey, regtest)
+
+    // fund the P2SH(CLTV) address
+    regtestUtils.faucet(address, 2e5, function (err, unspent) {
+      if (err) return done(err)
+
+      var txb = new bitcoin.TransactionBuilder(regtest)
+      txb.setLockTime(timeUtc)
+      txb.addInput(unspent.txId, unspent.vout, 0xfffffffe)
+      txb.addOutput(regtestUtils.RANDOM_ADDRESS, 8e4)
+
+      // {Alice's signature} {Bob's signature} OP_FALSE
+      var tx = txb.buildIncomplete()
+      var signatureHash = tx.hashForSignature(0, redeemScript, hashType)
+      var redeemScriptSig = bitcoin.script.scriptHash.input.encode([
+        alice.sign(signatureHash).toScriptSignature(hashType),
+        bob.sign(signatureHash).toScriptSignature(hashType),
+        bitcoin.opcodes.OP_FALSE
+      ], redeemScript)
+      tx.setInputScript(0, redeemScriptSig)
+
+      regtestUtils.broadcast(tx.toHex(), function (err) {
+        if (err) return done(err)
+
+        regtestUtils.verify({
+          txId: tx.getId(),
+          address: regtestUtils.RANDOM_ADDRESS,
+          vout: 0,
+          value: 8e4
+        }, done)
+      })
+    })
+  })
+
+  // expiry in the future, {Alice's signature} OP_TRUE
+  it('can create (but fail to broadcast via 3PBP) a Transaction where Alice attempts to redeem before the expiry', function (done) {
+    this.timeout(30000)
+
+    // two hours from now
+    var timeUtc = utcNow() + (3600 * 2)
+    var redeemScript = cltvCheckSigOutput(alice, bob, timeUtc)
+    var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript))
+    var address = bitcoin.address.fromOutputScript(scriptPubKey, regtest)
+
+    // fund the P2SH(CLTV) address
+    regtestUtils.faucet(address, 2e4, function (err, unspent) {
+      if (err) return done(err)
+
+      var txb = new bitcoin.TransactionBuilder(regtest)
+      txb.setLockTime(timeUtc)
+      txb.addInput(unspent.txId, unspent.vout, 0xfffffffe)
+      txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4)
+
+      // {Alice's signature} OP_TRUE
+      var tx = txb.buildIncomplete()
+      var signatureHash = tx.hashForSignature(0, redeemScript, hashType)
+      var redeemScriptSig = bitcoin.script.scriptHash.input.encode([
+        alice.sign(signatureHash).toScriptSignature(hashType),
+        bitcoin.opcodes.OP_TRUE
+      ], redeemScript)
+      tx.setInputScript(0, redeemScriptSig)
+
+      regtestUtils.broadcast(tx.toHex(), function (err) {
+        assert.throws(function () {
+          if (err) throw err
+        }, /Error: 64: non-final/)
+
+        done()
+      })
+    })
+  })
+})
diff --git a/test/integration/cltv.spec.ts b/test/integration/cltv.spec.ts
deleted file mode 100644
index 04944eb..0000000
--- a/test/integration/cltv.spec.ts
+++ /dev/null
@@ -1,260 +0,0 @@
-import * as assert from 'assert';
-import ECPairFactory from 'ecpair';
-import * as ecc from 'tiny-secp256k1';
-import { before, describe, it } from 'mocha';
-import * as bitcoin from '../..';
-import { regtestUtils } from './_regtest';
-
-const ECPair = ECPairFactory(ecc);
-const regtest = regtestUtils.network;
-const bip65 = require('bip65');
-
-function toOutputScript(address: string): Buffer {
-  return bitcoin.address.toOutputScript(address, regtest);
-}
-
-function idToHash(txid: string): Buffer {
-  return Buffer.from(txid, 'hex').reverse();
-}
-
-const alice = ECPair.fromWIF(
-  'cScfkGjbzzoeewVWmU2hYPUHeVGJRDdFt7WhmrVVGkxpmPP8BHWe',
-  regtest,
-);
-const bob = ECPair.fromWIF(
-  'cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsLwjHXA9x',
-  regtest,
-);
-
-describe('bitcoinjs-lib (transactions w/ CLTV)', () => {
-  // force update MTP
-  before(async () => {
-    await regtestUtils.mine(11);
-  });
-
-  const hashType = bitcoin.Transaction.SIGHASH_ALL;
-
-  interface KeyPair {
-    publicKey: Buffer;
-  }
-  function cltvCheckSigOutput(
-    aQ: KeyPair,
-    bQ: KeyPair,
-    lockTime: number,
-  ): Buffer {
-    return bitcoin.script.fromASM(
-      `
-      OP_IF
-          ${bitcoin.script.number.encode(lockTime).toString('hex')}
-          OP_CHECKLOCKTIMEVERIFY
-          OP_DROP
-      OP_ELSE
-          ${bQ.publicKey.toString('hex')}
-          OP_CHECKSIGVERIFY
-      OP_ENDIF
-      ${aQ.publicKey.toString('hex')}
-      OP_CHECKSIG
-    `
-        .trim()
-        .replace(/\s+/g, ' '),
-    );
-  }
-
-  function utcNow(): number {
-    return Math.floor(Date.now() / 1000);
-  }
-
-  // expiry past, {Alice's signature} OP_TRUE
-  it(
-    'can create (and broadcast via 3PBP) a Transaction where Alice can redeem ' +
-      'the output after the expiry (in the past)',
-    async () => {
-      // 3 hours ago
-      const lockTime = bip65.encode({ utc: utcNow() - 3600 * 3 });
-      const redeemScript = cltvCheckSigOutput(alice, bob, lockTime);
-      const { address } = bitcoin.payments.p2sh({
-        redeem: { output: redeemScript, network: regtest },
-        network: regtest,
-      });
-
-      // fund the P2SH(CLTV) address
-      const unspent = await regtestUtils.faucet(address!, 1e5);
-      const tx = new bitcoin.Transaction();
-      tx.locktime = lockTime;
-      // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable.
-      tx.addInput(idToHash(unspent.txId), unspent.vout, 0xfffffffe);
-      tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 7e4);
-
-      // {Alice's signature} OP_TRUE
-      const signatureHash = tx.hashForSignature(0, redeemScript, hashType);
-      const redeemScriptSig = bitcoin.payments.p2sh({
-        redeem: {
-          input: bitcoin.script.compile([
-            bitcoin.script.signature.encode(
-              alice.sign(signatureHash),
-              hashType,
-            ),
-            bitcoin.opcodes.OP_TRUE,
-          ]),
-          output: redeemScript,
-        },
-      }).input;
-      tx.setInputScript(0, redeemScriptSig!);
-
-      await regtestUtils.broadcast(tx.toHex());
-
-      await regtestUtils.verify({
-        txId: tx.getId(),
-        address: regtestUtils.RANDOM_ADDRESS,
-        vout: 0,
-        value: 7e4,
-      });
-    },
-  );
-
-  // expiry will pass, {Alice's signature} OP_TRUE
-  it(
-    'can create (and broadcast via 3PBP) a Transaction where Alice can redeem ' +
-      'the output after the expiry (in the future)',
-    async () => {
-      const height = await regtestUtils.height();
-      // 5 blocks from now
-      const lockTime = bip65.encode({ blocks: height + 5 });
-      const redeemScript = cltvCheckSigOutput(alice, bob, lockTime);
-      const { address } = bitcoin.payments.p2sh({
-        redeem: { output: redeemScript, network: regtest },
-        network: regtest,
-      });
-
-      // fund the P2SH(CLTV) address
-      const unspent = await regtestUtils.faucet(address!, 1e5);
-      const tx = new bitcoin.Transaction();
-      tx.locktime = lockTime;
-      // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable.
-      tx.addInput(idToHash(unspent.txId), unspent.vout, 0xfffffffe);
-      tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 7e4);
-
-      // {Alice's signature} OP_TRUE
-      const signatureHash = tx.hashForSignature(0, redeemScript, hashType);
-      const redeemScriptSig = bitcoin.payments.p2sh({
-        redeem: {
-          input: bitcoin.script.compile([
-            bitcoin.script.signature.encode(
-              alice.sign(signatureHash),
-              hashType,
-            ),
-            bitcoin.opcodes.OP_TRUE,
-          ]),
-          output: redeemScript,
-        },
-      }).input;
-      tx.setInputScript(0, redeemScriptSig!);
-
-      // TODO: test that it failures _prior_ to expiry, unfortunately, race conditions when run concurrently
-      // ...
-      // into the future!
-      await regtestUtils.mine(5);
-      await regtestUtils.broadcast(tx.toHex());
-      await regtestUtils.verify({
-        txId: tx.getId(),
-        address: regtestUtils.RANDOM_ADDRESS,
-        vout: 0,
-        value: 7e4,
-      });
-    },
-  );
-
-  // expiry ignored, {Bob's signature} {Alice's signature} OP_FALSE
-  it(
-    'can create (and broadcast via 3PBP) a Transaction where Alice and Bob can ' +
-      'redeem the output at any time',
-    async () => {
-      // two hours ago
-      const lockTime = bip65.encode({ utc: utcNow() - 3600 * 2 });
-      const redeemScript = cltvCheckSigOutput(alice, bob, lockTime);
-      const { address } = bitcoin.payments.p2sh({
-        redeem: { output: redeemScript, network: regtest },
-        network: regtest,
-      });
-
-      // fund the P2SH(CLTV) address
-      const unspent = await regtestUtils.faucet(address!, 2e5);
-      const tx = new bitcoin.Transaction();
-      tx.locktime = lockTime;
-      // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable.
-      tx.addInput(idToHash(unspent.txId), unspent.vout, 0xfffffffe);
-      tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 8e4);
-
-      // {Alice's signature} {Bob's signature} OP_FALSE
-      const signatureHash = tx.hashForSignature(0, redeemScript, hashType);
-      const redeemScriptSig = bitcoin.payments.p2sh({
-        redeem: {
-          input: bitcoin.script.compile([
-            bitcoin.script.signature.encode(
-              alice.sign(signatureHash),
-              hashType,
-            ),
-            bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
-            bitcoin.opcodes.OP_FALSE,
-          ]),
-          output: redeemScript,
-        },
-      }).input;
-      tx.setInputScript(0, redeemScriptSig!);
-
-      await regtestUtils.broadcast(tx.toHex());
-      await regtestUtils.verify({
-        txId: tx.getId(),
-        address: regtestUtils.RANDOM_ADDRESS,
-        vout: 0,
-        value: 8e4,
-      });
-    },
-  );
-
-  // expiry in the future, {Alice's signature} OP_TRUE
-  it(
-    'can create (but fail to broadcast via 3PBP) a Transaction where Alice ' +
-      'attempts to redeem before the expiry',
-    async () => {
-      // two hours from now
-      const lockTime = bip65.encode({ utc: utcNow() + 3600 * 2 });
-      const redeemScript = cltvCheckSigOutput(alice, bob, lockTime);
-      const { address } = bitcoin.payments.p2sh({
-        redeem: { output: redeemScript, network: regtest },
-        network: regtest,
-      });
-
-      // fund the P2SH(CLTV) address
-      const unspent = await regtestUtils.faucet(address!, 2e4);
-      const tx = new bitcoin.Transaction();
-      tx.locktime = lockTime;
-      // Note: nSequence MUST be <= 0xfffffffe otherwise LockTime is ignored, and is immediately spendable.
-      tx.addInput(idToHash(unspent.txId), unspent.vout, 0xfffffffe);
-      tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 1e4);
-
-      // {Alice's signature} OP_TRUE
-      const signatureHash = tx.hashForSignature(0, redeemScript, hashType);
-      const redeemScriptSig = bitcoin.payments.p2sh({
-        redeem: {
-          input: bitcoin.script.compile([
-            bitcoin.script.signature.encode(
-              alice.sign(signatureHash),
-              hashType,
-            ),
-            bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
-            bitcoin.opcodes.OP_TRUE,
-          ]),
-          output: redeemScript,
-        },
-      }).input;
-      tx.setInputScript(0, redeemScriptSig!);
-
-      await regtestUtils.broadcast(tx.toHex()).catch(err => {
-        assert.throws(() => {
-          if (err) throw err;
-        }, /Error: non-final/);
-      });
-    },
-  );
-});
diff --git a/test/integration/crypto.js b/test/integration/crypto.js
new file mode 100644
index 0000000..716cb50
--- /dev/null
+++ b/test/integration/crypto.js
@@ -0,0 +1,115 @@
+/* global describe, it */
+
+var assert = require('assert')
+var bigi = require('bigi')
+var bitcoin = require('../../')
+var crypto = require('crypto')
+
+var ecurve = require('ecurve')
+var secp256k1 = ecurve.getCurveByName('secp256k1')
+
+describe('bitcoinjs-lib (crypto)', function () {
+  it('can recover a private key from duplicate R values', function () {
+    this.timeout(30000)
+
+    // https://blockchain.info/tx/f4c16475f2a6e9c602e4a287f9db3040e319eb9ece74761a4b84bc820fbeef50
+    var tx = bitcoin.Transaction.fromHex('01000000020b668015b32a6178d8524cfef6dc6fc0a4751915c2e9b2ed2d2eab02424341c8000000006a47304402205e00298dc5265b7a914974c9d0298aa0e69a0ca932cb52a360436d6a622e5cd7022024bf5f506968f5f23f1835574d5afe0e9021b4a5b65cf9742332d5e4acb68f41012103fd089f73735129f3d798a657aaaa4aa62a00fa15c76b61fc7f1b27ed1d0f35b8ffffffffa95fa69f11dc1cbb77ef64f25a95d4b12ebda57d19d843333819d95c9172ff89000000006b48304502205e00298dc5265b7a914974c9d0298aa0e69a0ca932cb52a360436d6a622e5cd7022100832176b59e8f50c56631acbc824bcba936c9476c559c42a4468be98975d07562012103fd089f73735129f3d798a657aaaa4aa62a00fa15c76b61fc7f1b27ed1d0f35b8ffffffff02b000eb04000000001976a91472956eed9a8ecb19ae7e3ebd7b06cae4668696a788ac303db000000000001976a9146c0bd55dd2592287cd9992ce3ba3fc1208fb76da88ac00000000')
+
+    tx.ins.forEach(function (input, vin) {
+      var script = input.script
+      var scriptChunks = bitcoin.script.decompile(script)
+
+      assert(bitcoin.script.pubKeyHash.input.check(scriptChunks), 'Expected pubKeyHash script')
+      var prevOutScript = bitcoin.address.toOutputScript('1ArJ9vRaQcoQ29mTWZH768AmRwzb6Zif1z')
+      var scriptSignature = bitcoin.ECSignature.parseScriptSignature(scriptChunks[0])
+      var publicKey = bitcoin.ECPair.fromPublicKeyBuffer(scriptChunks[1])
+
+      var m = tx.hashForSignature(vin, prevOutScript, scriptSignature.hashType)
+      assert(publicKey.verify(m, scriptSignature.signature), 'Invalid m')
+
+      // store the required information
+      input.signature = scriptSignature.signature
+      input.z = bigi.fromBuffer(m)
+    })
+
+    // finally, run the tasks, then on to the math
+    var n = secp256k1.n
+
+    for (var i = 0; i < tx.ins.length; ++i) {
+      for (var j = i + 1; j < tx.ins.length; ++j) {
+        var inputA = tx.ins[i]
+        var inputB = tx.ins[j]
+
+        // enforce matching r values
+        assert.strictEqual(inputA.signature.r.toString(), inputB.signature.r.toString())
+        var r = inputA.signature.r
+        var rInv = r.modInverse(n)
+
+        var s1 = inputA.signature.s
+        var s2 = inputB.signature.s
+        var z1 = inputA.z
+        var z2 = inputB.z
+
+        var zz = z1.subtract(z2).mod(n)
+        var ss = s1.subtract(s2).mod(n)
+
+        // k = (z1 - z2) / (s1 - s2)
+        // d1 = (s1 * k - z1) / r
+        // d2 = (s2 * k - z2) / r
+        var k = zz.multiply(ss.modInverse(n)).mod(n)
+        var d1 = ((s1.multiply(k).mod(n)).subtract(z1).mod(n)).multiply(rInv).mod(n)
+        var d2 = ((s2.multiply(k).mod(n)).subtract(z2).mod(n)).multiply(rInv).mod(n)
+
+        // enforce matching private keys
+        assert.strictEqual(d1.toString(), d2.toString())
+      }
+    }
+  })
+
+  it('can recover a BIP32 parent private key from the parent public key, and a derived, non-hardened child private key', function () {
+    function recoverParent (master, child) {
+      assert(!master.keyPair.d, 'You already have the parent private key')
+      assert(child.keyPair.d, 'Missing child private key')
+
+      var curve = secp256k1
+      var QP = master.keyPair.Q
+      var serQP = master.keyPair.getPublicKeyBuffer()
+
+      var d1 = child.keyPair.d
+      var d2
+      var data = Buffer.alloc(37)
+      serQP.copy(data, 0)
+
+      // search index space until we find it
+      for (var i = 0; i < bitcoin.HDNode.HIGHEST_BIT; ++i) {
+        data.writeUInt32BE(i, 33)
+
+        // calculate I
+        var I = crypto.createHmac('sha512', master.chainCode).update(data).digest()
+        var IL = I.slice(0, 32)
+        var pIL = bigi.fromBuffer(IL)
+
+        // See hdnode.js:273 to understand
+        d2 = d1.subtract(pIL).mod(curve.n)
+
+        var Qp = new bitcoin.ECPair(d2).Q
+        if (Qp.equals(QP)) break
+      }
+
+      var node = new bitcoin.HDNode(new bitcoin.ECPair(d2), master.chainCode, master.network)
+      node.depth = master.depth
+      node.index = master.index
+      node.masterFingerprint = master.masterFingerprint
+      return node
+    }
+
+    var seed = crypto.randomBytes(32)
+    var master = bitcoin.HDNode.fromSeedBuffer(seed)
+    var child = master.derive(6) // m/6
+
+    // now for the recovery
+    var neuteredMaster = master.neutered()
+    var recovered = recoverParent(neuteredMaster, child)
+    assert.strictEqual(recovered.toBase58(), master.toBase58())
+  })
+})
diff --git a/test/integration/csv.spec.ts b/test/integration/csv.spec.ts
deleted file mode 100644
index 742d68f..0000000
--- a/test/integration/csv.spec.ts
+++ /dev/null
@@ -1,518 +0,0 @@
-import * as assert from 'assert';
-import { PsbtInput } from 'bip174/src/lib/interfaces';
-import ECPairFactory from 'ecpair';
-import * as ecc from 'tiny-secp256k1';
-import { before, describe, it } from 'mocha';
-import * as bitcoin from '../..';
-import { regtestUtils } from './_regtest';
-
-const ECPair = ECPairFactory(ecc);
-const regtest = regtestUtils.network;
-const bip68 = require('bip68');
-const varuint = require('varuint-bitcoin');
-
-function toOutputScript(address: string): Buffer {
-  return bitcoin.address.toOutputScript(address, regtest);
-}
-
-function idToHash(txid: string): Buffer {
-  return Buffer.from(txid, 'hex').reverse();
-}
-
-const alice = ECPair.fromWIF(
-  'cScfkGjbzzoeewVWmU2hYPUHeVGJRDdFt7WhmrVVGkxpmPP8BHWe',
-  regtest,
-);
-const bob = ECPair.fromWIF(
-  'cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsLwjHXA9x',
-  regtest,
-);
-const charles = ECPair.fromWIF(
-  'cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsMSb4Ubnf',
-  regtest,
-);
-const dave = ECPair.fromWIF(
-  'cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsMwS4pqnx',
-  regtest,
-);
-
-describe('bitcoinjs-lib (transactions w/ CSV)', () => {
-  // force update MTP
-  before(async () => {
-    await regtestUtils.mine(11);
-  });
-
-  const hashType = bitcoin.Transaction.SIGHASH_ALL;
-
-  interface KeyPair {
-    publicKey: Buffer;
-  }
-  // IF MTP (from when confirmed) > seconds, _alice can redeem
-  function csvCheckSigOutput(
-    _alice: KeyPair,
-    _bob: KeyPair,
-    sequence: number,
-  ): Buffer {
-    return bitcoin.script.fromASM(
-      `
-      OP_IF
-          ${bitcoin.script.number.encode(sequence).toString('hex')}
-          OP_CHECKSEQUENCEVERIFY
-          OP_DROP
-      OP_ELSE
-          ${_bob.publicKey.toString('hex')}
-          OP_CHECKSIGVERIFY
-      OP_ENDIF
-      ${_alice.publicKey.toString('hex')}
-      OP_CHECKSIG
-    `
-        .trim()
-        .replace(/\s+/g, ' '),
-    );
-  }
-
-  // 2 of 3 multisig of _bob, _charles, _dave,
-  // but after sequence1 time, _alice can allow the multisig to become 1 of 3.
-  // but after sequence2 time, _alice can sign for the output all by themself.
-
-  /* tslint:disable-next-line */
-  // Ref: https://github.com/bitcoinbook/bitcoinbook/blob/f8b883dcd4e3d1b9adf40fed59b7e898fbd9241f/ch07.asciidoc#complex-script-example
-
-  // Note: bitcoinjs-lib will not offer specific support for problems with
-  //       advanced script usages such as below. Use at your own risk.
-  function complexCsvOutput(
-    _alice: KeyPair,
-    _bob: KeyPair,
-    _charles: KeyPair,
-    _dave: KeyPair,
-    sequence1: number,
-    sequence2: number,
-  ): Buffer {
-    return bitcoin.script.fromASM(
-      `
-      OP_IF
-          OP_IF
-              OP_2
-          OP_ELSE
-              ${bitcoin.script.number.encode(sequence1).toString('hex')}
-              OP_CHECKSEQUENCEVERIFY
-              OP_DROP
-              ${_alice.publicKey.toString('hex')}
-              OP_CHECKSIGVERIFY
-              OP_1
-          OP_ENDIF
-          ${_bob.publicKey.toString('hex')}
-          ${_charles.publicKey.toString('hex')}
-          ${_dave.publicKey.toString('hex')}
-          OP_3
-          OP_CHECKMULTISIG
-      OP_ELSE
-          ${bitcoin.script.number.encode(sequence2).toString('hex')}
-          OP_CHECKSEQUENCEVERIFY
-          OP_DROP
-          ${_alice.publicKey.toString('hex')}
-          OP_CHECKSIG
-      OP_ENDIF
-    `
-        .trim()
-        .replace(/\s+/g, ' '),
-    );
-  }
-
-  // expiry will pass, {Alice's signature} OP_TRUE
-  it(
-    'can create (and broadcast via 3PBP) a Transaction where Alice can redeem ' +
-      'the output after the expiry (in the future) (simple CHECKSEQUENCEVERIFY)',
-    async () => {
-      // 5 blocks from now
-      const sequence = bip68.encode({ blocks: 5 });
-      const p2sh = bitcoin.payments.p2sh({
-        redeem: {
-          output: csvCheckSigOutput(alice, bob, sequence),
-        },
-        network: regtest,
-      });
-
-      // fund the P2SH(CSV) address
-      const unspent = await regtestUtils.faucet(p2sh.address!, 1e5);
-      const utx = await regtestUtils.fetch(unspent.txId);
-      // for non segwit inputs, you must pass the full transaction buffer
-      const nonWitnessUtxo = Buffer.from(utx.txHex, 'hex');
-
-      // This is an example of using the finalizeInput second parameter to
-      // define how you finalize the inputs, allowing for any type of script.
-      const tx = new bitcoin.Psbt({ network: regtest })
-        .setVersion(2)
-        .addInput({
-          hash: unspent.txId,
-          index: unspent.vout,
-          sequence,
-          redeemScript: p2sh.redeem!.output!,
-          nonWitnessUtxo,
-        })
-        .addOutput({
-          address: regtestUtils.RANDOM_ADDRESS,
-          value: 7e4,
-        })
-        .signInput(0, alice)
-        .finalizeInput(0, csvGetFinalScripts) // See csvGetFinalScripts below
-        .extractTransaction();
-
-      // TODO: test that it failures _prior_ to expiry, unfortunately, race conditions when run concurrently
-      // ...
-      // into the future!
-      await regtestUtils.mine(10);
-
-      await regtestUtils.broadcast(tx.toHex());
-
-      await regtestUtils.verify({
-        txId: tx.getId(),
-        address: regtestUtils.RANDOM_ADDRESS,
-        vout: 0,
-        value: 7e4,
-      });
-    },
-  );
-
-  // expiry in the future, {Alice's signature} OP_TRUE
-  it(
-    'can create (but fail to broadcast via 3PBP) a Transaction where Alice ' +
-      'attempts to redeem before the expiry (simple CHECKSEQUENCEVERIFY)',
-    async () => {
-      // two hours after confirmation
-      const sequence = bip68.encode({ seconds: 7168 });
-      const p2sh = bitcoin.payments.p2sh({
-        network: regtest,
-        redeem: {
-          output: csvCheckSigOutput(alice, bob, sequence),
-        },
-      });
-
-      // fund the P2SH(CSV) address
-      const unspent = await regtestUtils.faucet(p2sh.address!, 2e4);
-
-      const tx = new bitcoin.Transaction();
-      tx.version = 2;
-      tx.addInput(idToHash(unspent.txId), unspent.vout, sequence);
-      tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 1e4);
-
-      // {Alice's signature} OP_TRUE
-      const signatureHash = tx.hashForSignature(
-        0,
-        p2sh.redeem!.output!,
-        hashType,
-      );
-      const redeemScriptSig = bitcoin.payments.p2sh({
-        network: regtest,
-        redeem: {
-          network: regtest,
-          output: p2sh.redeem!.output,
-          input: bitcoin.script.compile([
-            bitcoin.script.signature.encode(
-              alice.sign(signatureHash),
-              hashType,
-            ),
-            bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
-            bitcoin.opcodes.OP_TRUE,
-          ]),
-        },
-      }).input;
-      tx.setInputScript(0, redeemScriptSig!);
-
-      await regtestUtils.broadcast(tx.toHex()).catch(err => {
-        assert.throws(() => {
-          if (err) throw err;
-        }, /Error: non-BIP68-final/);
-      });
-    },
-  );
-
-  // Check first combination of complex CSV, 2 of 3
-  it(
-    'can create (and broadcast via 3PBP) a Transaction where Bob and Charles ' +
-      'can send (complex CHECKSEQUENCEVERIFY)',
-    async () => {
-      // 2 blocks from now
-      const sequence1 = bip68.encode({ blocks: 2 });
-      // 5 blocks from now
-      const sequence2 = bip68.encode({ blocks: 5 });
-      const p2sh = bitcoin.payments.p2sh({
-        redeem: {
-          output: complexCsvOutput(
-            alice,
-            bob,
-            charles,
-            dave,
-            sequence1,
-            sequence2,
-          ),
-        },
-        network: regtest,
-      });
-
-      // fund the P2SH(CCSV) address
-      const unspent = await regtestUtils.faucet(p2sh.address!, 1e5);
-
-      const tx = new bitcoin.Transaction();
-      tx.version = 2;
-      tx.addInput(idToHash(unspent.txId), unspent.vout);
-      tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 7e4);
-
-      // OP_0 {Bob sig} {Charles sig} OP_TRUE OP_TRUE
-      const signatureHash = tx.hashForSignature(
-        0,
-        p2sh.redeem!.output!,
-        hashType,
-      );
-      const redeemScriptSig = bitcoin.payments.p2sh({
-        network: regtest,
-        redeem: {
-          network: regtest,
-          output: p2sh.redeem!.output,
-          input: bitcoin.script.compile([
-            bitcoin.opcodes.OP_0,
-            bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
-            bitcoin.script.signature.encode(
-              charles.sign(signatureHash),
-              hashType,
-            ),
-            bitcoin.opcodes.OP_TRUE,
-            bitcoin.opcodes.OP_TRUE,
-          ]),
-        },
-      }).input;
-      tx.setInputScript(0, redeemScriptSig!);
-
-      await regtestUtils.broadcast(tx.toHex());
-
-      await regtestUtils.verify({
-        txId: tx.getId(),
-        address: regtestUtils.RANDOM_ADDRESS,
-        vout: 0,
-        value: 7e4,
-      });
-    },
-  );
-
-  // Check first combination of complex CSV, mediator + 1 of 3 after 2 blocks
-  it(
-    'can create (and broadcast via 3PBP) a Transaction where Alice (mediator) ' +
-      'and Bob can send after 2 blocks (complex CHECKSEQUENCEVERIFY)',
-    async () => {
-      // 2 blocks from now
-      const sequence1 = bip68.encode({ blocks: 2 });
-      // 5 blocks from now
-      const sequence2 = bip68.encode({ blocks: 5 });
-      const p2sh = bitcoin.payments.p2sh({
-        redeem: {
-          output: complexCsvOutput(
-            alice,
-            bob,
-            charles,
-            dave,
-            sequence1,
-            sequence2,
-          ),
-        },
-        network: regtest,
-      });
-
-      // fund the P2SH(CCSV) address
-      const unspent = await regtestUtils.faucet(p2sh.address!, 1e5);
-
-      const tx = new bitcoin.Transaction();
-      tx.version = 2;
-      tx.addInput(idToHash(unspent.txId), unspent.vout, sequence1); // Set sequence1 for input
-      tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 7e4);
-
-      // OP_0 {Bob sig} {Alice mediator sig} OP_FALSE OP_TRUE
-      const signatureHash = tx.hashForSignature(
-        0,
-        p2sh.redeem!.output!,
-        hashType,
-      );
-      const redeemScriptSig = bitcoin.payments.p2sh({
-        network: regtest,
-        redeem: {
-          network: regtest,
-          output: p2sh.redeem!.output,
-          input: bitcoin.script.compile([
-            bitcoin.opcodes.OP_0,
-            bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
-            bitcoin.script.signature.encode(
-              alice.sign(signatureHash),
-              hashType,
-            ),
-            bitcoin.opcodes.OP_0,
-            bitcoin.opcodes.OP_TRUE,
-          ]),
-        },
-      }).input;
-      tx.setInputScript(0, redeemScriptSig!);
-
-      // Wait 2 blocks
-      await regtestUtils.mine(2);
-
-      await regtestUtils.broadcast(tx.toHex());
-
-      await regtestUtils.verify({
-        txId: tx.getId(),
-        address: regtestUtils.RANDOM_ADDRESS,
-        vout: 0,
-        value: 7e4,
-      });
-    },
-  );
-
-  // Check first combination of complex CSV, mediator after 5 blocks
-  it(
-    'can create (and broadcast via 3PBP) a Transaction where Alice (mediator) ' +
-      'can send after 5 blocks (complex CHECKSEQUENCEVERIFY)',
-    async () => {
-      // 2 blocks from now
-      const sequence1 = bip68.encode({ blocks: 2 });
-      // 5 blocks from now
-      const sequence2 = bip68.encode({ blocks: 5 });
-      const p2sh = bitcoin.payments.p2sh({
-        redeem: {
-          output: complexCsvOutput(
-            alice,
-            bob,
-            charles,
-            dave,
-            sequence1,
-            sequence2,
-          ),
-        },
-        network: regtest,
-      });
-
-      // fund the P2SH(CCSV) address
-      const unspent = await regtestUtils.faucet(p2sh.address!, 1e5);
-
-      const tx = new bitcoin.Transaction();
-      tx.version = 2;
-      tx.addInput(idToHash(unspent.txId), unspent.vout, sequence2); // Set sequence2 for input
-      tx.addOutput(toOutputScript(regtestUtils.RANDOM_ADDRESS), 7e4);
-
-      // {Alice mediator sig} OP_FALSE
-      const signatureHash = tx.hashForSignature(
-        0,
-        p2sh.redeem!.output!,
-        hashType,
-      );
-      const redeemScriptSig = bitcoin.payments.p2sh({
-        network: regtest,
-        redeem: {
-          network: regtest,
-          output: p2sh.redeem!.output,
-          input: bitcoin.script.compile([
-            bitcoin.script.signature.encode(
-              alice.sign(signatureHash),
-              hashType,
-            ),
-            bitcoin.opcodes.OP_0,
-          ]),
-        },
-      }).input;
-      tx.setInputScript(0, redeemScriptSig!);
-
-      // Wait 5 blocks
-      await regtestUtils.mine(5);
-
-      await regtestUtils.broadcast(tx.toHex());
-
-      await regtestUtils.verify({
-        txId: tx.getId(),
-        address: regtestUtils.RANDOM_ADDRESS,
-        vout: 0,
-        value: 7e4,
-      });
-    },
-  );
-});
-
-// This function is used to finalize a CSV transaction using PSBT.
-// See first test above.
-function csvGetFinalScripts(
-  inputIndex: number,
-  input: PsbtInput,
-  script: Buffer,
-  isSegwit: boolean,
-  isP2SH: boolean,
-  isP2WSH: boolean,
-): {
-  finalScriptSig: Buffer | undefined;
-  finalScriptWitness: Buffer | undefined;
-} {
-  // Step 1: Check to make sure the meaningful script matches what you expect.
-  const decompiled = bitcoin.script.decompile(script);
-  // Checking if first OP is OP_IF... should do better check in production!
-  // You may even want to check the public keys in the script against a
-  // whitelist depending on the circumstances!!!
-  // You also want to check the contents of the input to see if you have enough
-  // info to actually construct the scriptSig and Witnesses.
-  if (!decompiled || decompiled[0] !== bitcoin.opcodes.OP_IF) {
-    throw new Error(`Can not finalize input #${inputIndex}`);
-  }
-
-  // Step 2: Create final scripts
-  let payment: bitcoin.Payment = {
-    network: regtest,
-    output: script,
-    // This logic should be more strict and make sure the pubkeys in the
-    // meaningful script are the ones signing in the PSBT etc.
-    input: bitcoin.script.compile([
-      input.partialSig![0].signature,
-      bitcoin.opcodes.OP_TRUE,
-    ]),
-  };
-  if (isP2WSH && isSegwit)
-    payment = bitcoin.payments.p2wsh({
-      network: regtest,
-      redeem: payment,
-    });
-  if (isP2SH)
-    payment = bitcoin.payments.p2sh({
-      network: regtest,
-      redeem: payment,
-    });
-
-  function witnessStackToScriptWitness(witness: Buffer[]): Buffer {
-    let buffer = Buffer.allocUnsafe(0);
-
-    function writeSlice(slice: Buffer): void {
-      buffer = Buffer.concat([buffer, Buffer.from(slice)]);
-    }
-
-    function writeVarInt(i: number): void {
-      const currentLen = buffer.length;
-      const varintLen = varuint.encodingLength(i);
-
-      buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]);
-      varuint.encode(i, buffer, currentLen);
-    }
-
-    function writeVarSlice(slice: Buffer): void {
-      writeVarInt(slice.length);
-      writeSlice(slice);
-    }
-
-    function writeVector(vector: Buffer[]): void {
-      writeVarInt(vector.length);
-      vector.forEach(writeVarSlice);
-    }
-
-    writeVector(witness);
-
-    return buffer;
-  }
-
-  return {
-    finalScriptSig: payment.input,
-    finalScriptWitness:
-      payment.witness && payment.witness.length > 0
-        ? witnessStackToScriptWitness(payment.witness)
-        : undefined,
-  };
-}
diff --git a/test/integration/payments.spec.ts b/test/integration/payments.spec.ts
deleted file mode 100644
index d9d7fde..0000000
--- a/test/integration/payments.spec.ts
+++ /dev/null
@@ -1,136 +0,0 @@
-import ECPairFactory from 'ecpair';
-import * as ecc from 'tiny-secp256k1';
-import { describe, it } from 'mocha';
-import * as bitcoin from '../..';
-import { regtestUtils } from './_regtest';
-
-const ECPair = ECPairFactory(ecc);
-const NETWORK = regtestUtils.network;
-const keyPairs = [
-  ECPair.makeRandom({ network: NETWORK }),
-  ECPair.makeRandom({ network: NETWORK }),
-];
-
-async function buildAndSign(
-  depends: any,
-  prevOutput: any,
-  redeemScript: any,
-  witnessScript: any,
-): Promise<null> {
-  const unspent = await regtestUtils.faucetComplex(prevOutput, 5e4);
-  const utx = await regtestUtils.fetch(unspent.txId);
-
-  const psbt = new bitcoin.Psbt({ network: NETWORK })
-    .addInput({
-      hash: unspent.txId,
-      index: unspent.vout,
-      nonWitnessUtxo: Buffer.from(utx.txHex, 'hex'),
-      ...(redeemScript ? { redeemScript } : {}),
-      ...(witnessScript ? { witnessScript } : {}),
-    })
-    .addOutput({
-      address: regtestUtils.RANDOM_ADDRESS,
-      value: 2e4,
-    });
-
-  if (depends.signatures) {
-    keyPairs.forEach(keyPair => {
-      psbt.signInput(0, keyPair);
-    });
-  } else if (depends.signature) {
-    psbt.signInput(0, keyPairs[0]);
-  }
-
-  return regtestUtils.broadcast(
-    psbt
-      .finalizeAllInputs()
-      .extractTransaction()
-      .toHex(),
-  );
-}
-
-['p2ms', 'p2pk', 'p2pkh', 'p2wpkh'].forEach(k => {
-  const fixtures = require('../fixtures/' + k);
-  const { depends } = fixtures.dynamic;
-  const fn: any = (bitcoin.payments as any)[k];
-
-  const base: any = {};
-  if (depends.pubkey) base.pubkey = keyPairs[0].publicKey;
-  if (depends.pubkeys) base.pubkeys = keyPairs.map(x => x.publicKey);
-  if (depends.m) base.m = base.pubkeys.length;
-
-  const { output } = fn(base);
-  if (!output) throw new TypeError('Missing output');
-
-  describe('bitcoinjs-lib (payments - ' + k + ')', () => {
-    it('can broadcast as an output, and be spent as an input', async () => {
-      Object.assign(depends, { prevOutScriptType: k });
-      await buildAndSign(depends, output, undefined, undefined);
-    });
-
-    it(
-      'can (as P2SH(' +
-        k +
-        ')) broadcast as an output, and be spent as an input',
-      async () => {
-        const p2sh = bitcoin.payments.p2sh({
-          redeem: { output },
-          network: NETWORK,
-        });
-        Object.assign(depends, { prevOutScriptType: 'p2sh-' + k });
-        await buildAndSign(
-          depends,
-          p2sh.output,
-          p2sh.redeem!.output,
-          undefined,
-        );
-      },
-    );
-
-    // NOTE: P2WPKH cannot be wrapped in P2WSH, consensus fail
-    if (k === 'p2wpkh') return;
-
-    it(
-      'can (as P2WSH(' +
-        k +
-        ')) broadcast as an output, and be spent as an input',
-      async () => {
-        const p2wsh = bitcoin.payments.p2wsh({
-          redeem: { output },
-          network: NETWORK,
-        });
-        Object.assign(depends, { prevOutScriptType: 'p2wsh-' + k });
-        await buildAndSign(
-          depends,
-          p2wsh.output,
-          undefined,
-          p2wsh.redeem!.output,
-        );
-      },
-    );
-
-    it(
-      'can (as P2SH(P2WSH(' +
-        k +
-        '))) broadcast as an output, and be spent as an input',
-      async () => {
-        const p2wsh = bitcoin.payments.p2wsh({
-          redeem: { output },
-          network: NETWORK,
-        });
-        const p2sh = bitcoin.payments.p2sh({
-          redeem: { output: p2wsh.output },
-          network: NETWORK,
-        });
-
-        Object.assign(depends, { prevOutScriptType: 'p2sh-p2wsh-' + k });
-        await buildAndSign(
-          depends,
-          p2sh.output,
-          p2sh.redeem!.output,
-          p2wsh.redeem!.output,
-        );
-      },
-    );
-  });
-});
diff --git a/test/integration/stealth.js b/test/integration/stealth.js
new file mode 100644
index 0000000..0eabac1
--- /dev/null
+++ b/test/integration/stealth.js
@@ -0,0 +1,166 @@
+/* global describe, it */
+
+var assert = require('assert')
+var bigi = require('bigi')
+var bitcoin = require('../../')
+
+var ecurve = require('ecurve')
+var secp256k1 = ecurve.getCurveByName('secp256k1')
+var G = secp256k1.G
+var n = secp256k1.n
+
+// vG = (dG \+ sha256(e * dG)G)
+function stealthSend (e, Q) {
+  var eQ = Q.multiply(e) // shared secret
+  var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
+  var cG = G.multiply(c)
+  var vG = new bitcoin.ECPair(null, Q.add(cG))
+
+  return vG
+}
+
+// v = (d + sha256(eG * d))
+function stealthReceive (d, eG) {
+  var eQ = eG.multiply(d) // shared secret
+  var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
+  var v = new bitcoin.ECPair(d.add(c).mod(n))
+
+  return v
+}
+
+// d = (v - sha256(e * dG))
+function stealthRecoverLeaked (v, e, Q) {
+  var eQ = Q.multiply(e) // shared secret
+  var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
+  var d = new bitcoin.ECPair(v.subtract(c).mod(n))
+
+  return d
+}
+
+// vG = (rG \+ sha256(e * dG)G)
+function stealthDualSend (e, R, Q) {
+  var eQ = Q.multiply(e) // shared secret
+  var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
+  var cG = G.multiply(c)
+  var vG = new bitcoin.ECPair(null, R.add(cG))
+
+  return vG
+}
+
+// vG = (rG \+ sha256(eG * d)G)
+function stealthDualScan (d, R, eG) {
+  var eQ = eG.multiply(d) // shared secret
+  var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
+  var cG = G.multiply(c)
+  var vG = new bitcoin.ECPair(null, R.add(cG))
+
+  return vG
+}
+
+// v = (r + sha256(eG * d))
+function stealthDualReceive (d, r, eG) {
+  var eQ = eG.multiply(d) // shared secret
+  var c = bigi.fromBuffer(bitcoin.crypto.sha256(eQ.getEncoded()))
+  var v = new bitcoin.ECPair(r.add(c).mod(n))
+
+  return v
+}
+
+describe('bitcoinjs-lib (crypto)', function () {
+  it('can generate a single-key stealth address', function () {
+    // XXX: should be randomly generated, see next test for example
+    var recipient = bitcoin.ECPair.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') // private to recipient
+    var nonce = bitcoin.ECPair.fromWIF('KxVqB96pxbw1pokzQrZkQbLfVBjjHFfp2mFfEp8wuEyGenLFJhM9') // private to sender
+
+    // ... recipient reveals public key (recipient.Q) to sender
+    var forSender = stealthSend(nonce.d, recipient.Q)
+    assert.equal(forSender.getAddress(), '1CcZWwCpACJL3AxqoDbwEt4JgDFuTHUspE')
+    assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/)
+
+    // ... sender reveals nonce public key (nonce.Q) to recipient
+    var forRecipient = stealthReceive(recipient.d, nonce.Q)
+    assert.equal(forRecipient.getAddress(), '1CcZWwCpACJL3AxqoDbwEt4JgDFuTHUspE')
+    assert.equal(forRecipient.toWIF(), 'L1yjUN3oYyCXV3LcsBrmxCNTa62bZKWCybxVJMvqjMmmfDE8yk7n')
+
+    // sender and recipient, both derived same address
+    assert.equal(forSender.getAddress(), forRecipient.getAddress())
+  })
+
+  it('can generate a single-key stealth address (randomly)', function () {
+    var recipient = bitcoin.ECPair.makeRandom() // private to recipient
+    var nonce = bitcoin.ECPair.makeRandom() // private to sender
+
+    // ... recipient reveals public key (recipient.Q) to sender
+    var forSender = stealthSend(nonce.d, recipient.Q)
+    assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/)
+
+    // ... sender reveals nonce public key (nonce.Q) to recipient
+    var forRecipient = stealthReceive(recipient.d, nonce.Q)
+    assert.doesNotThrow(function () { forRecipient.toWIF() })
+
+    // sender and recipient, both derived same address
+    assert.equal(forSender.getAddress(), forRecipient.getAddress())
+  })
+
+  it('can recover parent recipient.d, if a derived private key is leaked [and nonce was revealed]', function () {
+    var recipient = bitcoin.ECPair.makeRandom() // private to recipient
+    var nonce = bitcoin.ECPair.makeRandom() // private to sender
+
+    // ... recipient reveals public key (recipient.Q) to sender
+    var forSender = stealthSend(nonce.d, recipient.Q)
+    assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/)
+
+    // ... sender reveals nonce public key (nonce.Q) to recipient
+    var forRecipient = stealthReceive(recipient.d, nonce.Q)
+    assert.doesNotThrow(function () { forRecipient.toWIF() })
+
+    // ... recipient accidentally leaks forRecipient.d on the blockchain
+    var leaked = stealthRecoverLeaked(forRecipient.d, nonce.d, recipient.Q)
+    assert.equal(leaked.toWIF(), recipient.toWIF())
+  })
+
+  it('can generate a dual-key stealth address', function () {
+    // XXX: should be randomly generated, see next test for example
+    var recipient = bitcoin.ECPair.fromWIF('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss') // private to recipient
+    var scan = bitcoin.ECPair.fromWIF('L5DkCk3xLLoGKncqKsWQTdaPSR4V8gzc14WVghysQGkdryRudjBM') // private to scanner/recipient
+    var nonce = bitcoin.ECPair.fromWIF('KxVqB96pxbw1pokzQrZkQbLfVBjjHFfp2mFfEp8wuEyGenLFJhM9') // private to sender
+
+    // ... recipient reveals public key(s) (recipient.Q, scan.Q) to sender
+    var forSender = stealthDualSend(nonce.d, recipient.Q, scan.Q)
+    assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/)
+
+    // ... sender reveals nonce public key (nonce.Q) to scanner
+    var forScanner = stealthDualScan(scan.d, recipient.Q, nonce.Q)
+    assert.throws(function () { forScanner.toWIF() }, /Error: Missing private key/)
+
+    // ... scanner reveals relevant transaction + nonce public key (nonce.Q) to recipient
+    var forRecipient = stealthDualReceive(scan.d, recipient.d, nonce.Q)
+    assert.doesNotThrow(function () { forRecipient.toWIF() })
+
+    // scanner, sender and recipient, all derived same address
+    assert.equal(forSender.getAddress(), forScanner.getAddress())
+    assert.equal(forSender.getAddress(), forRecipient.getAddress())
+  })
+
+  it('can generate a dual-key stealth address (randomly)', function () {
+    var recipient = bitcoin.ECPair.makeRandom() // private to recipient
+    var scan = bitcoin.ECPair.makeRandom() // private to scanner/recipient
+    var nonce = bitcoin.ECPair.makeRandom() // private to sender
+
+    // ... recipient reveals public key(s) (recipient.Q, scan.Q) to sender
+    var forSender = stealthDualSend(nonce.d, recipient.Q, scan.Q)
+    assert.throws(function () { forSender.toWIF() }, /Error: Missing private key/)
+
+    // ... sender reveals nonce public key (nonce.Q) to scanner
+    var forScanner = stealthDualScan(scan.d, recipient.Q, nonce.Q)
+    assert.throws(function () { forScanner.toWIF() }, /Error: Missing private key/)
+
+    // ... scanner reveals relevant transaction + nonce public key (nonce.Q) to recipient
+    var forRecipient = stealthDualReceive(scan.d, recipient.d, nonce.Q)
+    assert.doesNotThrow(function () { forRecipient.toWIF() })
+
+    // scanner, sender and recipient, all derived same address
+    assert.equal(forSender.getAddress(), forScanner.getAddress())
+    assert.equal(forSender.getAddress(), forRecipient.getAddress())
+  })
+})
diff --git a/test/integration/taproot.md b/test/integration/taproot.md
deleted file mode 100644
index 4010340..0000000
--- a/test/integration/taproot.md
+++ /dev/null
@@ -1,156 +0,0 @@
-# Taproot
-
-A simple keyspend example that is possible with the current API is below.
-
-## Current state of taproot support
-
-- [x] segwit v1 address support via bech32m
-- [x] segwit v1 sighash calculation on Transaction class
-
-## TODO
-
-- [ ] p2tr payment API to make script spends easier
-- [ ] Support within the Psbt class
-
-## Example
-
-### Requirements
-- npm dependencies
-  - bitcoinjs-lib v6.x.x
-  - bip32 v3.x.x
-  - tiny-secp256k1 v2.x.x
-  - regtest-client vx.x.x
-- local regtest-server docker container running
-  - `docker run -d -p 8080:8080 junderw/bitcoinjs-regtest-server`
-- node >= v14
-
-```js
-// Run this whole file as async
-// Catch any errors at the bottom of the file
-// and exit the process with 1 error code
-(async () => {
-
-// Order of the curve (N) - 1
-const N_LESS_1 = Buffer.from(
-  'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140',
-  'hex'
-);
-// 1 represented as 32 bytes BE
-const ONE = Buffer.from(
-  '0000000000000000000000000000000000000000000000000000000000000001',
-  'hex'
-);
-
-const crypto = require('crypto');
-// bitcoinjs-lib v6
-const bitcoin = require('bitcoinjs-lib');
-// bip32 v3 wraps tiny-secp256k1
-const BIP32Wrapper = require('bip32').default;
-const RegtestUtils = require('regtest-client').RegtestUtils;
-// tiny-secp256k1 v2 is an ESM module, so we can't "require", and must import async
-const ecc = await import('tiny-secp256k1');
-// wrap the bip32 library
-const bip32 = BIP32Wrapper(ecc);
-// set up dependencies
-const APIPASS = process.env.APIPASS || 'satoshi';
-// docker run -d -p 8080:8080 junderw/bitcoinjs-regtest-server
-const APIURL = process.env.APIURL || 'http://127.0.0.1:8080/1';
-const regtestUtils = new RegtestUtils({ APIPASS, APIURL });
-// End imports
-
-const myKey = bip32.fromSeed(crypto.randomBytes(64), regtestUtils.network);
-
-const output = createKeySpendOutput(myKey.publicKey);
-const address = bitcoin.address.fromOutputScript(
-  output,
-  regtestUtils.network
-);
-// amount from faucet
-const amount = 42e4;
-// amount to send
-const sendAmount = amount - 1e4;
-// get faucet
-const unspent = await regtestUtils.faucetComplex(output, amount);
-
-const tx = createSigned(
-  myKey,
-  unspent.txId,
-  unspent.vout,
-  sendAmount,
-  [output],
-  [amount]
-);
-
-const hex = tx.toHex();
-console.log('Valid tx sent from:');
-console.log(address);
-console.log('tx hex:');
-console.log(hex);
-await regtestUtils.broadcast(hex);
-await regtestUtils.verify({
-  txId: tx.getId(),
-  address,
-  vout: 0,
-  value: sendAmount,
-});
-
-// Function for creating a tweaked p2tr key-spend only address
-// (This is recommended by BIP341)
-function createKeySpendOutput(publicKey) {
-  // x-only pubkey (remove 1 byte y parity)
-  const myXOnlyPubkey = publicKey.slice(1, 33);
-  const commitHash = bitcoin.crypto.taggedHash('TapTweak', myXOnlyPubkey);
-  const tweakResult = ecc.xOnlyPointAddTweak(myXOnlyPubkey, commitHash);
-  if (tweakResult === null) throw new Error('Invalid Tweak');
-  const { xOnlyPubkey: tweaked } = tweakResult;
-  // scriptPubkey
-  return Buffer.concat([
-    // witness v1, PUSH_DATA 32 bytes
-    Buffer.from([0x51, 0x20]),
-    // x-only tweaked pubkey
-    tweaked,
-  ]);
-}
-
-// Function for signing for a tweaked p2tr key-spend only address
-// (Required for the above address)
-function signTweaked(messageHash, key) {
-  const privateKey =
-    key.publicKey[0] === 2
-      ? key.privateKey
-      : ecc.privateAdd(ecc.privateSub(N_LESS_1, key.privateKey), ONE);
-  const tweakHash = bitcoin.crypto.taggedHash(
-    'TapTweak',
-    key.publicKey.slice(1, 33)
-  );
-  const newPrivateKey = ecc.privateAdd(privateKey, tweakHash);
-  if (newPrivateKey === null) throw new Error('Invalid Tweak');
-  return ecc.signSchnorr(messageHash, newPrivateKey, Buffer.alloc(32));
-}
-
-// Function for creating signed tx
-function createSigned(key, txid, vout, amountToSend, scriptPubkeys, values) {
-  const tx = new bitcoin.Transaction();
-  tx.version = 2;
-  // Add input
-  tx.addInput(Buffer.from(txid, 'hex').reverse(), vout);
-  // Add output
-  tx.addOutput(scriptPubkeys[0], amountToSend);
-  const sighash = tx.hashForWitnessV1(
-    0, // which input
-    scriptPubkeys, // All previous outputs of all inputs
-    values, // All previous values of all inputs
-    bitcoin.Transaction.SIGHASH_DEFAULT // sighash flag, DEFAULT is schnorr-only (DEFAULT == ALL)
-  );
-  const signature = Buffer.from(signTweaked(sighash, key));
-  // witness stack for keypath spend is just the signature.
-  // If sighash is not SIGHASH_DEFAULT (ALL) then you must add 1 byte with sighash value
-  tx.ins[0].witness = [signature];
-  return tx;
-}
-
-})().catch((err) => {
-  console.error(err);
-  process.exit(1);
-});
-```
\ No newline at end of file
diff --git a/test/integration/taproot.spec.ts b/test/integration/taproot.spec.ts
deleted file mode 100644
index f7b3733..0000000
--- a/test/integration/taproot.spec.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-import BIP32Factory from 'bip32';
-import * as ecc from 'tiny-secp256k1';
-import { describe, it } from 'mocha';
-import * as bitcoin from '../..';
-import { regtestUtils } from './_regtest';
-const rng = require('randombytes');
-const regtest = regtestUtils.network;
-const bip32 = BIP32Factory(ecc);
-
-describe('bitcoinjs-lib (transaction with taproot)', () => {
-  it('can create (and broadcast via 3PBP) a taproot keyspend Transaction', async () => {
-    const myKey = bip32.fromSeed(rng(64), regtest);
-
-    const output = createKeySpendOutput(myKey.publicKey);
-    const address = bitcoin.address.fromOutputScript(output, regtest);
-    // amount from faucet
-    const amount = 42e4;
-    // amount to send
-    const sendAmount = amount - 1e4;
-    // get faucet
-    const unspent = await regtestUtils.faucetComplex(output, amount);
-
-    const tx = createSigned(
-      myKey,
-      unspent.txId,
-      unspent.vout,
-      sendAmount,
-      [output],
-      [amount],
-    );
-
-    const hex = tx.toHex();
-    // console.log('Valid tx sent from:');
-    // console.log(address);
-    // console.log('tx hex:');
-    // console.log(hex);
-    await regtestUtils.broadcast(hex);
-    await regtestUtils.verify({
-      txId: tx.getId(),
-      address,
-      vout: 0,
-      value: sendAmount,
-    });
-  });
-});
-
-// Order of the curve (N) - 1
-const N_LESS_1 = Buffer.from(
-  'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140',
-  'hex',
-);
-// 1 represented as 32 bytes BE
-const ONE = Buffer.from(
-  '0000000000000000000000000000000000000000000000000000000000000001',
-  'hex',
-);
-
-// Function for creating a tweaked p2tr key-spend only address
-// (This is recommended by BIP341)
-function createKeySpendOutput(publicKey: Buffer): Buffer {
-  // x-only pubkey (remove 1 byte y parity)
-  const myXOnlyPubkey = publicKey.slice(1, 33);
-  const commitHash = bitcoin.crypto.taggedHash('TapTweak', myXOnlyPubkey);
-  const tweakResult = ecc.xOnlyPointAddTweak(myXOnlyPubkey, commitHash);
-  if (tweakResult === null) throw new Error('Invalid Tweak');
-  const { xOnlyPubkey: tweaked } = tweakResult;
-  // scriptPubkey
-  return Buffer.concat([
-    // witness v1, PUSH_DATA 32 bytes
-    Buffer.from([0x51, 0x20]),
-    // x-only tweaked pubkey
-    tweaked,
-  ]);
-}
-
-// Function for signing for a tweaked p2tr key-spend only address
-// (Required for the above address)
-interface KeyPair {
-  publicKey: Buffer;
-  privateKey?: Buffer;
-}
-function signTweaked(messageHash: Buffer, key: KeyPair): Uint8Array {
-  const privateKey =
-    key.publicKey[0] === 2
-      ? key.privateKey
-      : ecc.privateAdd(ecc.privateSub(N_LESS_1, key.privateKey!)!, ONE)!;
-  const tweakHash = bitcoin.crypto.taggedHash(
-    'TapTweak',
-    key.publicKey.slice(1, 33),
-  );
-  const newPrivateKey = ecc.privateAdd(privateKey!, tweakHash);
-  if (newPrivateKey === null) throw new Error('Invalid Tweak');
-  return ecc.signSchnorr(messageHash, newPrivateKey, Buffer.alloc(32));
-}
-
-// Function for creating signed tx
-function createSigned(
-  key: KeyPair,
-  txid: string,
-  vout: number,
-  amountToSend: number,
-  scriptPubkeys: Buffer[],
-  values: number[],
-): bitcoin.Transaction {
-  const tx = new bitcoin.Transaction();
-  tx.version = 2;
-  // Add input
-  tx.addInput(Buffer.from(txid, 'hex').reverse(), vout);
-  // Add output
-  tx.addOutput(scriptPubkeys[0], amountToSend);
-  const sighash = tx.hashForWitnessV1(
-    0, // which input
-    scriptPubkeys, // All previous outputs of all inputs
-    values, // All previous values of all inputs
-    bitcoin.Transaction.SIGHASH_DEFAULT, // sighash flag, DEFAULT is schnorr-only (DEFAULT == ALL)
-  );
-  const signature = Buffer.from(signTweaked(sighash, key));
-  // witness stack for keypath spend is just the signature.
-  // If sighash is not SIGHASH_DEFAULT (ALL) then you must add 1 byte with sighash value
-  tx.ins[0].witness = [signature];
-  return tx;
-}
diff --git a/test/integration/transactions.js b/test/integration/transactions.js
new file mode 100644
index 0000000..56ef033
--- /dev/null
+++ b/test/integration/transactions.js
@@ -0,0 +1,238 @@
+/* global describe, it */
+
+var assert = require('assert')
+var bitcoin = require('../../')
+var regtestUtils = require('./_regtest')
+var regtest = regtestUtils.network
+
+function rng () {
+  return Buffer.from('YT8dAtK4d16A3P1z+TpwB2jJ4aFH3g9M1EioIBkLEV4=', 'base64')
+}
+
+describe('bitcoinjs-lib (transactions)', function () {
+  it('can create a 1-to-1 Transaction', function () {
+    var alice = bitcoin.ECPair.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy')
+    var txb = new bitcoin.TransactionBuilder()
+
+    txb.addInput('61d520ccb74288c96bc1a2b20ea1c0d5a704776dd0164a396efec3ea7040349d', 0) // Alice's previous transaction output, has 15000 satoshis
+    txb.addOutput('1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP', 12000)
+    // (in)15000 - (out)12000 = (fee)3000, this is the miner fee
+
+    txb.sign(0, alice)
+
+    // prepare for broadcast to the Bitcoin network, see "can broadcast a Transaction" below
+    assert.strictEqual(txb.build().toHex(), '01000000019d344070eac3fe6e394a16d06d7704a7d5c0a10eb2a2c16bc98842b7cc20d561000000006b48304502210088828c0bdfcdca68d8ae0caeb6ec62cd3fd5f9b2191848edae33feb533df35d302202e0beadd35e17e7f83a733f5277028a9b453d525553e3f5d2d7a7aa8010a81d60121029f50f51d63b345039a290c94bffd3180c99ed659ff6ea6b1242bca47eb93b59fffffffff01e02e0000000000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac00000000')
+  })
+
+  it('can create a 2-to-2 Transaction', function () {
+    var alice = bitcoin.ECPair.fromWIF('L1Knwj9W3qK3qMKdTvmg3VfzUs3ij2LETTFhxza9LfD5dngnoLG1')
+    var bob = bitcoin.ECPair.fromWIF('KwcN2pT3wnRAurhy7qMczzbkpY5nXMW2ubh696UBc1bcwctTx26z')
+
+    var txb = new bitcoin.TransactionBuilder()
+    txb.addInput('b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c', 6) // Alice's previous transaction output, has 200000 satoshis
+    txb.addInput('7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730', 0) // Bob's previous transaction output, has 300000 satoshis
+    txb.addOutput('1CUNEBjYrCn2y1SdiUMohaKUi4wpP326Lb', 180000)
+    txb.addOutput('1JtK9CQw1syfWj1WtFMWomrYdV3W2tWBF9', 170000)
+    // (in)(200000 + 300000) - (out)(180000 + 170000) = (fee)150000, this is the miner fee
+
+    txb.sign(1, bob) // Bob signs his input, which was the second input (1th)
+    txb.sign(0, alice) // Alice signs her input, which was the first input (0th)
+
+    // prepare for broadcast to the Bitcoin network, see "can broadcast a Transaction" below
+    assert.strictEqual(txb.build().toHex(), '01000000024c94e48a870b85f41228d33cf25213dfcc8dd796e7211ed6b1f9a014809dbbb5060000006a473044022041450c258ce7cac7da97316bf2ea1ce66d88967c4df94f3e91f4c2a30f5d08cb02203674d516e6bb2b0afd084c3551614bd9cec3c2945231245e891b145f2d6951f0012103e05ce435e462ec503143305feb6c00e06a3ad52fbf939e85c65f3a765bb7baacffffffff3077d9de049574c3af9bc9c09a7c9db80f2d94caaf63988c9166249b955e867d000000006b483045022100aeb5f1332c79c446d3f906e4499b2e678500580a3f90329edf1ba502eec9402e022072c8b863f8c8d6c26f4c691ac9a6610aa4200edc697306648ee844cfbc089d7a012103df7940ee7cddd2f97763f67e1fb13488da3fbdd7f9c68ec5ef0864074745a289ffffffff0220bf0200000000001976a9147dd65592d0ab2fe0d0257d571abf032cd9db93dc88ac10980200000000001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac00000000')
+  })
+
+  it('can create (and broadcast via 3PBP) a typical Transaction', function (done) {
+    this.timeout(30000)
+
+    var alice1 = bitcoin.ECPair.makeRandom({ network: regtest })
+    var alice2 = bitcoin.ECPair.makeRandom({ network: regtest })
+    var aliceChange = bitcoin.ECPair.makeRandom({ network: regtest, rng: rng })
+
+    // give Alice 2 unspent outputs
+    regtestUtils.faucet(alice1.getAddress(), 5e4, function (err, unspent0) {
+      if (err) return done(err)
+
+      regtestUtils.faucet(alice2.getAddress(), 7e4, function (err, unspent1) {
+        if (err) return done(err)
+
+        var txb = new bitcoin.TransactionBuilder(regtest)
+        txb.addInput(unspent0.txId, unspent0.vout) // alice1 unspent
+        txb.addInput(unspent1.txId, unspent1.vout) // alice2 unspent
+        txb.addOutput('mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf', 8e4) // the actual "spend"
+        txb.addOutput(aliceChange.getAddress(), 1e4) // Alice's change
+        // (in)(4e4 + 2e4) - (out)(1e4 + 3e4) = (fee)2e4 = 20000, this is the miner fee
+
+        // Alice signs each input with the respective private keys
+        txb.sign(0, alice1)
+        txb.sign(1, alice2)
+
+        // build and broadcast our RegTest network
+        regtestUtils.broadcast(txb.build().toHex(), done)
+        // to build and broadcast to the actual Bitcoin network, see https://github.com/bitcoinjs/bitcoinjs-lib/issues/839
+      })
+    })
+  })
+
+  it('can create (and broadcast via 3PBP) a Transaction with an OP_RETURN output', function (done) {
+    this.timeout(30000)
+
+    var keyPair = bitcoin.ECPair.makeRandom({ network: regtest })
+
+    regtestUtils.faucet(keyPair.getAddress(), 2e5, function (err, unspent) {
+      if (err) return done(err)
+
+      var txb = new bitcoin.TransactionBuilder(regtest)
+      var data = Buffer.from('bitcoinjs-lib', 'utf8')
+      var dataScript = bitcoin.script.nullData.output.encode(data)
+
+      txb.addInput(unspent.txId, unspent.vout)
+      txb.addOutput(dataScript, 1000)
+      txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e5)
+      txb.sign(0, keyPair)
+
+      // build and broadcast to the RegTest network
+      regtestUtils.broadcast(txb.build().toHex(), done)
+    })
+  })
+
+  it('can create (and broadcast via 3PBP) a Transaction with a 2-of-4 P2SH(multisig) input', function (done) {
+    this.timeout(30000)
+
+    var keyPairs = [
+      '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgwmaKkrx',
+      '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgww7vXtT',
+      '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe',
+      '91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx9rcrL7'
+    ].map(function (wif) { return bitcoin.ECPair.fromWIF(wif, regtest) })
+    var pubKeys = keyPairs.map(function (x) { return x.getPublicKeyBuffer() })
+
+    var redeemScript = bitcoin.script.multisig.output.encode(2, pubKeys)
+    var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript))
+    var address = bitcoin.address.fromOutputScript(scriptPubKey, regtest)
+
+    regtestUtils.faucet(address, 2e4, function (err, unspent) {
+      if (err) return done(err)
+
+      var txb = new bitcoin.TransactionBuilder(regtest)
+      txb.addInput(unspent.txId, unspent.vout)
+      txb.addOutput(regtestUtils.RANDOM_ADDRESS, 1e4)
+
+      txb.sign(0, keyPairs[0], redeemScript)
+      txb.sign(0, keyPairs[2], redeemScript)
+      var tx = txb.build()
+
+      // build and broadcast to the Bitcoin RegTest network
+      regtestUtils.broadcast(tx.toHex(), function (err) {
+        if (err) return done(err)
+
+        regtestUtils.verify({
+          txId: tx.getId(),
+          address: regtestUtils.RANDOM_ADDRESS,
+          vout: 0,
+          value: 1e4
+        }, done)
+      })
+    })
+  })
+
+  it('can create (and broadcast via 3PBP) a Transaction with a SegWit P2SH(P2WPKH) input', function (done) {
+    this.timeout(30000)
+
+    var keyPair = bitcoin.ECPair.fromWIF('cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87JcbXMTcA', regtest)
+    var pubKey = keyPair.getPublicKeyBuffer()
+    var pubKeyHash = bitcoin.crypto.hash160(pubKey)
+
+    var redeemScript = bitcoin.script.witnessPubKeyHash.output.encode(pubKeyHash)
+    var redeemScriptHash = bitcoin.crypto.hash160(redeemScript)
+    var scriptPubKey = bitcoin.script.scriptHash.output.encode(redeemScriptHash)
+    var address = bitcoin.address.fromOutputScript(scriptPubKey, regtest)
+
+    regtestUtils.faucet(address, 5e4, function (err, unspent) {
+      if (err) return done(err)
+
+      var txb = new bitcoin.TransactionBuilder(regtest)
+      txb.addInput(unspent.txId, unspent.vout)
+      txb.addOutput(regtestUtils.RANDOM_ADDRESS, 2e4)
+      txb.sign(0, keyPair, redeemScript, null, unspent.value)
+
+      var tx = txb.build()
+
+      // build and broadcast to the Bitcoin RegTest network
+      regtestUtils.broadcast(tx.toHex(), function (err) {
+        if (err) return done(err)
+
+        regtestUtils.verify({
+          txId: tx.getId(),
+          address: regtestUtils.RANDOM_ADDRESS,
+          vout: 0,
+          value: 2e4
+        }, done)
+      })
+    })
+  })
+
+  it('can create (and broadcast via 3PBP) a Transaction with a SegWit 3-of-4 P2SH(P2WSH(multisig)) input', function (done) {
+    this.timeout(50000)
+
+    var keyPairs = [
+      'cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87JcbXMTcA',
+      'cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87K7XCyj5v',
+      'cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87KcLPVfXz',
+      'cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87L7FgDCKE'
+    ].map(function (wif) { return bitcoin.ECPair.fromWIF(wif, regtest) })
+    var pubKeys = keyPairs.map(function (x) { return x.getPublicKeyBuffer() })
+
+    var witnessScript = bitcoin.script.multisig.output.encode(3, pubKeys)
+    var redeemScript = bitcoin.script.witnessScriptHash.output.encode(bitcoin.crypto.sha256(witnessScript))
+    var scriptPubKey = bitcoin.script.scriptHash.output.encode(bitcoin.crypto.hash160(redeemScript))
+    var address = bitcoin.address.fromOutputScript(scriptPubKey, regtest)
+
+    regtestUtils.faucet(address, 6e4, function (err, unspent) {
+      if (err) return done(err)
+
+      var txb = new bitcoin.TransactionBuilder(regtest)
+      txb.addInput(unspent.txId, unspent.vout)
+      txb.addOutput(regtestUtils.RANDOM_ADDRESS, 3e4)
+      txb.sign(0, keyPairs[0], redeemScript, null, unspent.value, witnessScript)
+      txb.sign(0, keyPairs[2], redeemScript, null, unspent.value, witnessScript)
+      txb.sign(0, keyPairs[3], redeemScript, null, unspent.value, witnessScript)
+
+      var tx = txb.build()
+
+      // build and broadcast to the Bitcoin RegTest network
+      regtestUtils.broadcast(tx.toHex(), function (err) {
+        if (err) return done(err)
+
+        regtestUtils.verify({
+          txId: tx.getId(),
+          address: regtestUtils.RANDOM_ADDRESS,
+          vout: 0,
+          value: 3e4
+        }, done)
+      })
+    })
+  })
+
+  it('can verify Transaction signatures', function () {
+    var txHex = '010000000321c5f7e7bc98b3feda84aad36a5c99a02bcb8823a2f3eccbcd5da209698b5c20000000006b48304502210099e021772830207cf7c55b69948d3b16b4dcbf1f55a9cd80ebf8221a169735f9022064d33f11d62cd28240b3862afc0b901adc9f231c7124dd19bdb30367b61964c50121032b4c06c06c3ec0b7fa29519dfa5aae193ee2cc35ca127f29f14ec605d62fb63dffffffff8a75ce85441ddb3f342708ee33cc8ed418b07d9ba9e0e7c4e1cccfe9f52d8a88000000006946304302207916c23dae212c95a920423902fa44e939fb3d542f4478a7b46e9cde53705800021f0d74e9504146e404c1b8f9cba4dff2d4782e3075491c9ed07ce4a7d1c4461a01210216c92abe433106491bdeb4a261226f20f5a4ac86220cc6e37655aac6bf3c1f2affffffffdfef93f69fe32e944fad79fa8f882b3a155d80383252348caba1a77a5abbf7ef000000006b483045022100faa6e9ca289b46c64764a624c59ac30d9abcf1d4a04c4de9089e67cbe0d300a502206930afa683f6807502de5c2431bf9a1fd333c8a2910a76304df0f3d23d83443f0121039e05da8b8ea4f9868ecebb25998c7701542986233f4401799551fbecf316b18fffffffff01ff4b0000000000001976a9146c86476d1d85cd60116cd122a274e6a570a5a35c88acc96d0700'
+    var keyPairs = [
+      '032b4c06c06c3ec0b7fa29519dfa5aae193ee2cc35ca127f29f14ec605d62fb63d',
+      '0216c92abe433106491bdeb4a261226f20f5a4ac86220cc6e37655aac6bf3c1f2a',
+      '039e05da8b8ea4f9868ecebb25998c7701542986233f4401799551fbecf316b18f'
+    ].map(function (q) { return bitcoin.ECPair.fromPublicKeyBuffer(Buffer.from(q, 'hex')) })
+
+    var tx = bitcoin.Transaction.fromHex(txHex)
+
+    tx.ins.forEach(function (input, i) {
+      var keyPair = keyPairs[i]
+      var prevOutScript = bitcoin.address.toOutputScript(keyPair.getAddress())
+      var scriptSig = bitcoin.script.pubKeyHash.input.decode(input.script)
+      var ss = bitcoin.ECSignature.parseScriptSignature(scriptSig.signature)
+      var hash = tx.hashForSignature(i, prevOutScript, ss.hashType)
+
+      assert.strictEqual(scriptSig.pubKey.toString('hex'), keyPair.getPublicKeyBuffer().toString('hex'))
+      assert.strictEqual(keyPair.verify(hash, ss.signature), true)
+    })
+  })
+})
diff --git a/test/integration/transactions.spec.ts b/test/integration/transactions.spec.ts
deleted file mode 100644
index ba7f2fe..0000000
--- a/test/integration/transactions.spec.ts
+++ /dev/null
@@ -1,723 +0,0 @@
-import * as assert from 'assert';
-import BIP32Factory from 'bip32';
-import * as ecc from 'tiny-secp256k1';
-import ECPairFactory from 'ecpair';
-import { describe, it } from 'mocha';
-import * as bitcoin from '../..';
-import { regtestUtils } from './_regtest';
-
-const ECPair = ECPairFactory(ecc);
-const rng = require('randombytes');
-const regtest = regtestUtils.network;
-const bip32 = BIP32Factory(ecc);
-
-const validator = (
-  pubkey: Buffer,
-  msghash: Buffer,
-  signature: Buffer,
-): boolean => ECPair.fromPublicKey(pubkey).verify(msghash, signature);
-
-// See bottom of file for some helper functions used to make the payment objects needed.
-
-describe('bitcoinjs-lib (transactions with psbt)', () => {
-  it('can create a 1-to-1 Transaction', () => {
-    const alice = ECPair.fromWIF(
-      'L2uPYXe17xSTqbCjZvL2DsyXPCbXspvcu5mHLDYUgzdUbZGSKrSr',
-    );
-    const psbt = new bitcoin.Psbt();
-    psbt.setVersion(2); // These are defaults. This line is not needed.
-    psbt.setLocktime(0); // These are defaults. This line is not needed.
-    psbt.addInput({
-      // if hash is string, txid, if hash is Buffer, is reversed compared to txid
-      hash: '7d067b4a697a09d2c3cff7d4d9506c9955e93bff41bf82d439da7d030382bc3e',
-      index: 0,
-      sequence: 0xffffffff, // These are defaults. This line is not needed.
-
-      // non-segwit inputs now require passing the whole previous tx as Buffer
-      nonWitnessUtxo: Buffer.from(
-        '0200000001f9f34e95b9d5c8abcd20fc5bd4a825d1517be62f0f775e5f36da944d9' +
-          '452e550000000006b483045022100c86e9a111afc90f64b4904bd609e9eaed80d48' +
-          'ca17c162b1aca0a788ac3526f002207bb79b60d4fc6526329bf18a77135dc566020' +
-          '9e761da46e1c2f1152ec013215801210211755115eabf846720f5cb18f248666fec' +
-          '631e5e1e66009ce3710ceea5b1ad13ffffffff01' +
-          // value in satoshis (Int64LE) = 0x015f90 = 90000
-          '905f010000000000' +
-          // scriptPubkey length
-          '19' +
-          // scriptPubkey
-          '76a9148bbc95d2709c71607c60ee3f097c1217482f518d88ac' +
-          // locktime
-          '00000000',
-        'hex',
-      ),
-
-      // // If this input was segwit, instead of nonWitnessUtxo, you would add
-      // // a witnessUtxo as follows. The scriptPubkey and the value only are needed.
-      // witnessUtxo: {
-      //   script: Buffer.from(
-      //     '76a9148bbc95d2709c71607c60ee3f097c1217482f518d88ac',
-      //     'hex',
-      //   ),
-      //   value: 90000,
-      // },
-
-      // Not featured here:
-      //   redeemScript. A Buffer of the redeemScript for P2SH
-      //   witnessScript. A Buffer of the witnessScript for P2WSH
-    });
-    psbt.addOutput({
-      address: '1KRMKfeZcmosxALVYESdPNez1AP1mEtywp',
-      value: 80000,
-    });
-    psbt.signInput(0, alice);
-    psbt.validateSignaturesOfInput(0, validator);
-    psbt.finalizeAllInputs();
-    assert.strictEqual(
-      psbt.extractTransaction().toHex(),
-      '02000000013ebc8203037dda39d482bf41ff3be955996c50d9d4f7cfc3d2097a694a7' +
-        'b067d000000006b483045022100931b6db94aed25d5486884d83fc37160f37f3368c0' +
-        'd7f48c757112abefec983802205fda64cff98c849577026eb2ce916a50ea70626a766' +
-        '9f8596dd89b720a26b4d501210365db9da3f8a260078a7e8f8b708a1161468fb2323f' +
-        'fda5ec16b261ec1056f455ffffffff0180380100000000001976a914ca0d36044e0dc' +
-        '08a22724efa6f6a07b0ec4c79aa88ac00000000',
-    );
-  });
-
-  it('can create (and broadcast via 3PBP) a typical Transaction', async () => {
-    // these are { payment: Payment; keys: ECPair[] }
-    const alice1 = createPayment('p2pkh');
-    const alice2 = createPayment('p2pkh');
-
-    // give Alice 2 unspent outputs
-    const inputData1 = await getInputData(
-      5e4,
-      alice1.payment,
-      false,
-      'noredeem',
-    );
-    const inputData2 = await getInputData(
-      7e4,
-      alice2.payment,
-      false,
-      'noredeem',
-    );
-    {
-      const {
-        hash, // string of txid or Buffer of tx hash. (txid and hash are reverse order)
-        index, // the output index of the txo you are spending
-        nonWitnessUtxo, // the full previous transaction as a Buffer
-      } = inputData1;
-      assert.deepStrictEqual({ hash, index, nonWitnessUtxo }, inputData1);
-    }
-
-    // network is only needed if you pass an address to addOutput
-    // using script (Buffer of scriptPubkey) instead will avoid needed network.
-    const psbt = new bitcoin.Psbt({ network: regtest })
-      .addInput(inputData1) // alice1 unspent
-      .addInput(inputData2) // alice2 unspent
-      .addOutput({
-        address: 'mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf',
-        value: 8e4,
-      }) // the actual "spend"
-      .addOutput({
-        address: alice2.payment.address, // OR script, which is a Buffer.
-        value: 1e4,
-      }); // Alice's change
-    // (in)(5e4 + 7e4) - (out)(8e4 + 1e4) = (fee)3e4 = 30000, this is the miner fee
-
-    // Let's show a new feature with PSBT.
-    // We can have multiple signers sign in parrallel and combine them.
-    // (this is not necessary, but a nice feature)
-
-    // encode to send out to the signers
-    const psbtBaseText = psbt.toBase64();
-
-    // each signer imports
-    const signer1 = bitcoin.Psbt.fromBase64(psbtBaseText);
-    const signer2 = bitcoin.Psbt.fromBase64(psbtBaseText);
-
-    // Alice signs each input with the respective private keys
-    // signInput and signInputAsync are better
-    // (They take the input index explicitly as the first arg)
-    signer1.signAllInputs(alice1.keys[0]);
-    signer2.signAllInputs(alice2.keys[0]);
-
-    // If your signer object's sign method returns a promise, use the following
-    // await signer2.signAllInputsAsync(alice2.keys[0])
-
-    // encode to send back to combiner (signer 1 and 2 are not near each other)
-    const s1text = signer1.toBase64();
-    const s2text = signer2.toBase64();
-
-    const final1 = bitcoin.Psbt.fromBase64(s1text);
-    const final2 = bitcoin.Psbt.fromBase64(s2text);
-
-    // final1.combine(final2) would give the exact same result
-    psbt.combine(final1, final2);
-
-    // Finalizer wants to check all signatures are valid before finalizing.
-    // If the finalizer wants to check for specific pubkeys, the second arg
-    // can be passed. See the first multisig example below.
-    assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
-    assert.strictEqual(psbt.validateSignaturesOfInput(1, validator), true);
-
-    // This step it new. Since we separate the signing operation and
-    // the creation of the scriptSig and witness stack, we are able to
-    psbt.finalizeAllInputs();
-
-    // build and broadcast our RegTest network
-    await regtestUtils.broadcast(psbt.extractTransaction().toHex());
-    // to build and broadcast to the actual Bitcoin network, see https://github.com/bitcoinjs/bitcoinjs-lib/issues/839
-  });
-
-  it('can create (and broadcast via 3PBP) a Transaction with an OP_RETURN output', async () => {
-    const alice1 = createPayment('p2pkh');
-    const inputData1 = await getInputData(
-      2e5,
-      alice1.payment,
-      false,
-      'noredeem',
-    );
-
-    const data = Buffer.from('bitcoinjs-lib', 'utf8');
-    const embed = bitcoin.payments.embed({ data: [data] });
-
-    const psbt = new bitcoin.Psbt({ network: regtest })
-      .addInput(inputData1)
-      .addOutput({
-        script: embed.output!,
-        value: 1000,
-      })
-      .addOutput({
-        address: regtestUtils.RANDOM_ADDRESS,
-        value: 1e5,
-      })
-      .signInput(0, alice1.keys[0]);
-
-    assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
-    psbt.finalizeAllInputs();
-
-    // build and broadcast to the RegTest network
-    await regtestUtils.broadcast(psbt.extractTransaction().toHex());
-  });
-
-  it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2MS(2 of 4)) (multisig) input', async () => {
-    const multisig = createPayment('p2sh-p2ms(2 of 4)');
-    const inputData1 = await getInputData(2e4, multisig.payment, false, 'p2sh');
-    {
-      const {
-        hash,
-        index,
-        nonWitnessUtxo,
-        redeemScript, // NEW: P2SH needs to give redeemScript when adding an input.
-      } = inputData1;
-      assert.deepStrictEqual(
-        { hash, index, nonWitnessUtxo, redeemScript },
-        inputData1,
-      );
-    }
-
-    const psbt = new bitcoin.Psbt({ network: regtest })
-      .addInput(inputData1)
-      .addOutput({
-        address: regtestUtils.RANDOM_ADDRESS,
-        value: 1e4,
-      })
-      .signInput(0, multisig.keys[0])
-      .signInput(0, multisig.keys[2]);
-
-    assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
-    assert.strictEqual(
-      psbt.validateSignaturesOfInput(0, validator, multisig.keys[0].publicKey),
-      true,
-    );
-    assert.throws(() => {
-      psbt.validateSignaturesOfInput(0, validator, multisig.keys[3].publicKey);
-    }, new RegExp('No signatures for this pubkey'));
-    psbt.finalizeAllInputs();
-
-    const tx = psbt.extractTransaction();
-
-    // build and broadcast to the Bitcoin RegTest network
-    await regtestUtils.broadcast(tx.toHex());
-
-    await regtestUtils.verify({
-      txId: tx.getId(),
-      address: regtestUtils.RANDOM_ADDRESS,
-      vout: 0,
-      value: 1e4,
-    });
-  });
-
-  it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2WPKH) input', async () => {
-    const p2sh = createPayment('p2sh-p2wpkh');
-    const inputData = await getInputData(5e4, p2sh.payment, true, 'p2sh');
-    const inputData2 = await getInputData(5e4, p2sh.payment, true, 'p2sh');
-    {
-      const {
-        hash,
-        index,
-        witnessUtxo, // NEW: this is an object of the output being spent { script: Buffer; value: Satoshis; }
-        redeemScript,
-      } = inputData;
-      assert.deepStrictEqual(
-        { hash, index, witnessUtxo, redeemScript },
-        inputData,
-      );
-    }
-    const keyPair = p2sh.keys[0];
-    const outputData = {
-      script: p2sh.payment.output, // sending to myself for fun
-      value: 2e4,
-    };
-    const outputData2 = {
-      script: p2sh.payment.output, // sending to myself for fun
-      value: 7e4,
-    };
-
-    const tx = new bitcoin.Psbt()
-      .addInputs([inputData, inputData2])
-      .addOutputs([outputData, outputData2])
-      .signAllInputs(keyPair)
-      .finalizeAllInputs()
-      .extractTransaction();
-
-    // build and broadcast to the Bitcoin RegTest network
-    await regtestUtils.broadcast(tx.toHex());
-
-    await regtestUtils.verify({
-      txId: tx.getId(),
-      address: p2sh.payment.address,
-      vout: 0,
-      value: 2e4,
-    });
-  });
-
-  it('can create (and broadcast via 3PBP) a Transaction, w/ a P2SH(P2WPKH) input with nonWitnessUtxo', async () => {
-    // For learning purposes, ignore this test.
-    // REPEATING ABOVE BUT WITH nonWitnessUtxo by passing false to getInputData
-    const p2sh = createPayment('p2sh-p2wpkh');
-    const inputData = await getInputData(5e4, p2sh.payment, false, 'p2sh');
-    const inputData2 = await getInputData(5e4, p2sh.payment, false, 'p2sh');
-    const keyPair = p2sh.keys[0];
-    const outputData = {
-      script: p2sh.payment.output,
-      value: 2e4,
-    };
-    const outputData2 = {
-      script: p2sh.payment.output,
-      value: 7e4,
-    };
-    const tx = new bitcoin.Psbt()
-      .addInputs([inputData, inputData2])
-      .addOutputs([outputData, outputData2])
-      .signAllInputs(keyPair)
-      .finalizeAllInputs()
-      .extractTransaction();
-    await regtestUtils.broadcast(tx.toHex());
-    await regtestUtils.verify({
-      txId: tx.getId(),
-      address: p2sh.payment.address,
-      vout: 0,
-      value: 2e4,
-    });
-  });
-
-  it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input', async () => {
-    // the only thing that changes is you don't give a redeemscript for input data
-
-    const p2wpkh = createPayment('p2wpkh');
-    const inputData = await getInputData(5e4, p2wpkh.payment, true, 'noredeem');
-    {
-      const { hash, index, witnessUtxo } = inputData;
-      assert.deepStrictEqual({ hash, index, witnessUtxo }, inputData);
-    }
-
-    const psbt = new bitcoin.Psbt({ network: regtest })
-      .addInput(inputData)
-      .addOutput({
-        address: regtestUtils.RANDOM_ADDRESS,
-        value: 2e4,
-      })
-      .signInput(0, p2wpkh.keys[0]);
-
-    assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
-    psbt.finalizeAllInputs();
-
-    const tx = psbt.extractTransaction();
-
-    // build and broadcast to the Bitcoin RegTest network
-    await regtestUtils.broadcast(tx.toHex());
-
-    await regtestUtils.verify({
-      txId: tx.getId(),
-      address: regtestUtils.RANDOM_ADDRESS,
-      vout: 0,
-      value: 2e4,
-    });
-  });
-
-  it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input with nonWitnessUtxo', async () => {
-    // For learning purposes, ignore this test.
-    // REPEATING ABOVE BUT WITH nonWitnessUtxo by passing false to getInputData
-    const p2wpkh = createPayment('p2wpkh');
-    const inputData = await getInputData(
-      5e4,
-      p2wpkh.payment,
-      false,
-      'noredeem',
-    );
-    const psbt = new bitcoin.Psbt({ network: regtest })
-      .addInput(inputData)
-      .addOutput({
-        address: regtestUtils.RANDOM_ADDRESS,
-        value: 2e4,
-      })
-      .signInput(0, p2wpkh.keys[0]);
-    psbt.finalizeAllInputs();
-    const tx = psbt.extractTransaction();
-    await regtestUtils.broadcast(tx.toHex());
-    await regtestUtils.verify({
-      txId: tx.getId(),
-      address: regtestUtils.RANDOM_ADDRESS,
-      vout: 0,
-      value: 2e4,
-    });
-  });
-
-  it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WSH(P2PK) input', async () => {
-    const p2wsh = createPayment('p2wsh-p2pk');
-    const inputData = await getInputData(5e4, p2wsh.payment, true, 'p2wsh');
-    {
-      const {
-        hash,
-        index,
-        witnessUtxo,
-        witnessScript, // NEW: A Buffer of the witnessScript
-      } = inputData;
-      assert.deepStrictEqual(
-        { hash, index, witnessUtxo, witnessScript },
-        inputData,
-      );
-    }
-
-    const psbt = new bitcoin.Psbt({ network: regtest })
-      .addInput(inputData)
-      .addOutput({
-        address: regtestUtils.RANDOM_ADDRESS,
-        value: 2e4,
-      })
-      .signInput(0, p2wsh.keys[0]);
-
-    assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
-    psbt.finalizeAllInputs();
-
-    const tx = psbt.extractTransaction();
-
-    // build and broadcast to the Bitcoin RegTest network
-    await regtestUtils.broadcast(tx.toHex());
-
-    await regtestUtils.verify({
-      txId: tx.getId(),
-      address: regtestUtils.RANDOM_ADDRESS,
-      vout: 0,
-      value: 2e4,
-    });
-  });
-
-  it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WSH(P2PK) input with nonWitnessUtxo', async () => {
-    // For learning purposes, ignore this test.
-    // REPEATING ABOVE BUT WITH nonWitnessUtxo by passing false to getInputData
-    const p2wsh = createPayment('p2wsh-p2pk');
-    const inputData = await getInputData(5e4, p2wsh.payment, false, 'p2wsh');
-    const psbt = new bitcoin.Psbt({ network: regtest })
-      .addInput(inputData)
-      .addOutput({
-        address: regtestUtils.RANDOM_ADDRESS,
-        value: 2e4,
-      })
-      .signInput(0, p2wsh.keys[0]);
-    psbt.finalizeAllInputs();
-    const tx = psbt.extractTransaction();
-    await regtestUtils.broadcast(tx.toHex());
-    await regtestUtils.verify({
-      txId: tx.getId(),
-      address: regtestUtils.RANDOM_ADDRESS,
-      vout: 0,
-      value: 2e4,
-    });
-  });
-
-  it(
-    'can create (and broadcast via 3PBP) a Transaction, w/ a ' +
-      'P2SH(P2WSH(P2MS(3 of 4))) (SegWit multisig) input',
-    async () => {
-      const p2sh = createPayment('p2sh-p2wsh-p2ms(3 of 4)');
-      const inputData = await getInputData(
-        5e4,
-        p2sh.payment,
-        true,
-        'p2sh-p2wsh',
-      );
-      {
-        const {
-          hash,
-          index,
-          witnessUtxo,
-          redeemScript,
-          witnessScript,
-        } = inputData;
-        assert.deepStrictEqual(
-          { hash, index, witnessUtxo, redeemScript, witnessScript },
-          inputData,
-        );
-      }
-
-      const psbt = new bitcoin.Psbt({ network: regtest })
-        .addInput(inputData)
-        .addOutput({
-          address: regtestUtils.RANDOM_ADDRESS,
-          value: 2e4,
-        })
-        .signInput(0, p2sh.keys[0])
-        .signInput(0, p2sh.keys[2])
-        .signInput(0, p2sh.keys[3]);
-
-      assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
-      assert.strictEqual(
-        psbt.validateSignaturesOfInput(0, validator, p2sh.keys[3].publicKey),
-        true,
-      );
-      assert.throws(() => {
-        psbt.validateSignaturesOfInput(0, validator, p2sh.keys[1].publicKey);
-      }, new RegExp('No signatures for this pubkey'));
-      psbt.finalizeAllInputs();
-
-      const tx = psbt.extractTransaction();
-
-      // build and broadcast to the Bitcoin RegTest network
-      await regtestUtils.broadcast(tx.toHex());
-
-      await regtestUtils.verify({
-        txId: tx.getId(),
-        address: regtestUtils.RANDOM_ADDRESS,
-        vout: 0,
-        value: 2e4,
-      });
-    },
-  );
-
-  it(
-    'can create (and broadcast via 3PBP) a Transaction, w/ a ' +
-      'P2SH(P2WSH(P2MS(3 of 4))) (SegWit multisig) input with nonWitnessUtxo',
-    async () => {
-      // For learning purposes, ignore this test.
-      // REPEATING ABOVE BUT WITH nonWitnessUtxo by passing false to getInputData
-      const p2sh = createPayment('p2sh-p2wsh-p2ms(3 of 4)');
-      const inputData = await getInputData(
-        5e4,
-        p2sh.payment,
-        false,
-        'p2sh-p2wsh',
-      );
-      const psbt = new bitcoin.Psbt({ network: regtest })
-        .addInput(inputData)
-        .addOutput({
-          address: regtestUtils.RANDOM_ADDRESS,
-          value: 2e4,
-        })
-        .signInput(0, p2sh.keys[0])
-        .signInput(0, p2sh.keys[2])
-        .signInput(0, p2sh.keys[3]);
-      psbt.finalizeAllInputs();
-      const tx = psbt.extractTransaction();
-      await regtestUtils.broadcast(tx.toHex());
-      await regtestUtils.verify({
-        txId: tx.getId(),
-        address: regtestUtils.RANDOM_ADDRESS,
-        vout: 0,
-        value: 2e4,
-      });
-    },
-  );
-
-  it(
-    'can create (and broadcast via 3PBP) a Transaction, w/ a ' +
-      'P2SH(P2MS(2 of 2)) input with nonWitnessUtxo',
-    async () => {
-      const myKey = ECPair.makeRandom({ network: regtest });
-      const myKeys = [
-        myKey,
-        ECPair.fromPrivateKey(myKey.privateKey!, { network: regtest }),
-      ];
-      const p2sh = createPayment('p2sh-p2ms(2 of 2)', myKeys);
-      const inputData = await getInputData(5e4, p2sh.payment, false, 'p2sh');
-      const psbt = new bitcoin.Psbt({ network: regtest })
-        .addInput(inputData)
-        .addOutput({
-          address: regtestUtils.RANDOM_ADDRESS,
-          value: 2e4,
-        })
-        .signInput(0, p2sh.keys[0]);
-      psbt.finalizeAllInputs();
-      const tx = psbt.extractTransaction();
-      await regtestUtils.broadcast(tx.toHex());
-      await regtestUtils.verify({
-        txId: tx.getId(),
-        address: regtestUtils.RANDOM_ADDRESS,
-        vout: 0,
-        value: 2e4,
-      });
-    },
-  );
-
-  it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input using HD', async () => {
-    const hdRoot = bip32.fromSeed(rng(64));
-    const masterFingerprint = hdRoot.fingerprint;
-    const path = "m/84'/0'/0'/0/0";
-    const childNode = hdRoot.derivePath(path);
-    const pubkey = childNode.publicKey;
-
-    // This information should be added to your input via updateInput
-    // You can add multiple bip32Derivation objects for multisig, but
-    // each must have a unique pubkey.
-    //
-    // This is useful because as long as you store the masterFingerprint on
-    // the PSBT Creator's server, you can have the PSBT Creator do the heavy
-    // lifting with derivation from your m/84'/0'/0' xpub, (deriving only 0/0 )
-    // and your signer just needs to pass in an HDSigner interface (ie. bip32 library)
-    const updateData = {
-      bip32Derivation: [
-        {
-          masterFingerprint,
-          path,
-          pubkey,
-        },
-      ],
-    };
-    const p2wpkh = createPayment('p2wpkh', [childNode]);
-    const inputData = await getInputData(5e4, p2wpkh.payment, true, 'noredeem');
-    {
-      const { hash, index, witnessUtxo } = inputData;
-      assert.deepStrictEqual({ hash, index, witnessUtxo }, inputData);
-    }
-
-    // You can add extra attributes for updateData into the addInput(s) object(s)
-    Object.assign(inputData, updateData);
-
-    const psbt = new bitcoin.Psbt({ network: regtest })
-      .addInput(inputData)
-      // .updateInput(0, updateData) // if you didn't merge the bip32Derivation with inputData
-      .addOutput({
-        address: regtestUtils.RANDOM_ADDRESS,
-        value: 2e4,
-      })
-      .signInputHD(0, hdRoot); // must sign with root!!!
-
-    assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
-    assert.strictEqual(
-      psbt.validateSignaturesOfInput(0, validator, childNode.publicKey),
-      true,
-    );
-    psbt.finalizeAllInputs();
-
-    const tx = psbt.extractTransaction();
-
-    // build and broadcast to the Bitcoin RegTest network
-    await regtestUtils.broadcast(tx.toHex());
-
-    await regtestUtils.verify({
-      txId: tx.getId(),
-      address: regtestUtils.RANDOM_ADDRESS,
-      vout: 0,
-      value: 2e4,
-    });
-  });
-});
-
-function createPayment(_type: string, myKeys?: any[], network?: any): any {
-  network = network || regtest;
-  const splitType = _type.split('-').reverse();
-  const isMultisig = splitType[0].slice(0, 4) === 'p2ms';
-  const keys = myKeys || [];
-  let m: number | undefined;
-  if (isMultisig) {
-    const match = splitType[0].match(/^p2ms\((\d+) of (\d+)\)$/);
-    m = parseInt(match![1], 10);
-    let n = parseInt(match![2], 10);
-    if (keys.length > 0 && keys.length !== n) {
-      throw new Error('Need n keys for multisig');
-    }
-    while (!myKeys && n > 1) {
-      keys.push(ECPair.makeRandom({ network }));
-      n--;
-    }
-  }
-  if (!myKeys) keys.push(ECPair.makeRandom({ network }));
-
-  let payment: any;
-  splitType.forEach(type => {
-    if (type.slice(0, 4) === 'p2ms') {
-      payment = bitcoin.payments.p2ms({
-        m,
-        pubkeys: keys.map(key => key.publicKey).sort((a, b) => a.compare(b)),
-        network,
-      });
-    } else if (['p2sh', 'p2wsh'].indexOf(type) > -1) {
-      payment = (bitcoin.payments as any)[type]({
-        redeem: payment,
-        network,
-      });
-    } else {
-      payment = (bitcoin.payments as any)[type]({
-        pubkey: keys[0].publicKey,
-        network,
-      });
-    }
-  });
-
-  return {
-    payment,
-    keys,
-  };
-}
-
-function getWitnessUtxo(out: any): any {
-  delete out.address;
-  out.script = Buffer.from(out.script, 'hex');
-  return out;
-}
-
-async function getInputData(
-  amount: number,
-  payment: any,
-  isSegwit: boolean,
-  redeemType: string,
-): Promise<any> {
-  const unspent = await regtestUtils.faucetComplex(payment.output, amount);
-  const utx = await regtestUtils.fetch(unspent.txId);
-  // for non segwit inputs, you must pass the full transaction buffer
-  const nonWitnessUtxo = Buffer.from(utx.txHex, 'hex');
-  // for segwit inputs, you only need the output script and value as an object.
-  const witnessUtxo = getWitnessUtxo(utx.outs[unspent.vout]);
-  const mixin = isSegwit ? { witnessUtxo } : { nonWitnessUtxo };
-  const mixin2: any = {};
-  switch (redeemType) {
-    case 'p2sh':
-      mixin2.redeemScript = payment.redeem.output;
-      break;
-    case 'p2wsh':
-      mixin2.witnessScript = payment.redeem.output;
-      break;
-    case 'p2sh-p2wsh':
-      mixin2.witnessScript = payment.redeem.redeem.output;
-      mixin2.redeemScript = payment.redeem.output;
-      break;
-  }
-  return {
-    hash: unspent.txId,
-    index: unspent.vout,
-    ...mixin,
-    ...mixin2,
-  };
-}
diff --git a/test/payments.spec.ts b/test/payments.spec.ts
deleted file mode 100644
index bc123cb..0000000
--- a/test/payments.spec.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-import * as assert from 'assert';
-import { describe, it } from 'mocha';
-import { PaymentCreator } from '../src/payments';
-import * as u from './payments.utils';
-['embed', 'p2ms', 'p2pk', 'p2pkh', 'p2sh', 'p2wpkh', 'p2wsh'].forEach(p => {
-  describe(p, () => {
-    let fn: PaymentCreator;
-    const payment = require('../src/payments/' + p);
-    if (p === 'embed') {
-      fn = payment.p2data;
-    } else {
-      fn = payment[p];
-    }
-    const fixtures = require('./fixtures/' + p);
-
-    fixtures.valid.forEach((f: any) => {
-      it(f.description + ' as expected', () => {
-        const args = u.preform(f.arguments);
-        const actual = fn(args, f.options);
-
-        u.equate(actual, f.expected, f.arguments);
-      });
-
-      it(f.description + ' as expected (no validation)', () => {
-        const args = u.preform(f.arguments);
-        const actual = fn(
-          args,
-          Object.assign({}, f.options, {
-            validate: false,
-          }),
-        );
-
-        u.equate(actual, f.expected, f.arguments);
-      });
-    });
-
-    fixtures.invalid.forEach((f: any) => {
-      it(
-        'throws ' + f.exception + (f.description ? 'for ' + f.description : ''),
-        () => {
-          const args = u.preform(f.arguments);
-
-          assert.throws(() => {
-            fn(args, f.options);
-          }, new RegExp(f.exception));
-        },
-      );
-    });
-
-    if (p === 'p2sh') {
-      const p2wsh = require('../src/payments/p2wsh').p2wsh;
-      const p2pk = require('../src/payments/p2pk').p2pk;
-      it('properly assembles nested p2wsh with names', () => {
-        const actual = fn({
-          redeem: p2wsh({
-            redeem: p2pk({
-              pubkey: Buffer.from(
-                '03e15819590382a9dd878f01e2f0cbce541564eb415e43b440472d883ecd283058',
-                'hex',
-              ),
-            }),
-          }),
-        });
-        assert.strictEqual(
-          actual.address,
-          '3MGbrbye4ttNUXM8WAvBFRKry4fkS9fjuw',
-        );
-        assert.strictEqual(actual.name, 'p2sh-p2wsh-p2pk');
-        assert.strictEqual(actual.redeem!.name, 'p2wsh-p2pk');
-        assert.strictEqual(actual.redeem!.redeem!.name, 'p2pk');
-      });
-    }
-
-    // cross-verify dynamically too
-    if (!fixtures.dynamic) return;
-    const { depends, details } = fixtures.dynamic;
-
-    details.forEach((f: any) => {
-      const detail = u.preform(f);
-      const disabled: any = {};
-      if (f.disabled)
-        f.disabled.forEach((k: string) => {
-          disabled[k] = true;
-        });
-
-      for (const key in depends) {
-        if (key in disabled) continue;
-        const dependencies = depends[key];
-
-        dependencies.forEach((dependency: any) => {
-          if (!Array.isArray(dependency)) dependency = [dependency];
-
-          const args = {};
-          dependency.forEach((d: any) => {
-            u.from(d, detail, args);
-          });
-          const expected = u.from(key, detail);
-
-          it(
-            f.description +
-              ', ' +
-              key +
-              ' derives from ' +
-              JSON.stringify(dependency),
-            () => {
-              u.equate(fn(args), expected);
-            },
-          );
-        });
-      }
-    });
-  });
-});
diff --git a/test/payments.utils.ts b/test/payments.utils.ts
deleted file mode 100644
index c0635f3..0000000
--- a/test/payments.utils.ts
+++ /dev/null
@@ -1,171 +0,0 @@
-import * as t from 'assert';
-import * as BNETWORKS from '../src/networks';
-import * as bscript from '../src/script';
-
-function tryHex(x: Buffer | Buffer[]): string | string[] {
-  if (Buffer.isBuffer(x)) return x.toString('hex');
-  if (Array.isArray(x)) return x.map(tryHex) as string[];
-  return x;
-}
-
-function fromHex(x: string | string[]): Buffer | Buffer[] {
-  if (typeof x === 'string') return Buffer.from(x, 'hex');
-  if (Array.isArray(x)) return x.map(fromHex) as Buffer[];
-  return x;
-}
-function tryASM(x: Buffer): string {
-  if (Buffer.isBuffer(x)) return bscript.toASM(x);
-  return x;
-}
-function asmToBuffer(x: string): Buffer {
-  if (x === '') return Buffer.alloc(0);
-  return bscript.fromASM(x);
-}
-function carryOver(a: any, b: any): void {
-  for (const k in b) {
-    if (!k) continue;
-    if (k in a && k === 'redeem') {
-      carryOver(a[k], b[k]);
-      continue;
-    }
-
-    // don't, the value was specified
-    if (k in a) continue;
-
-    // otherwise, expect match
-    a[k] = b[k];
-  }
-}
-
-function equateBase(a: any, b: any, context: string): void {
-  if ('output' in b)
-    t.strictEqual(
-      tryASM(a.output),
-      tryASM(b.output),
-      `Inequal ${context}output`,
-    );
-  if ('input' in b)
-    t.strictEqual(tryASM(a.input), tryASM(b.input), `Inequal ${context}input`);
-  if ('witness' in b)
-    t.deepStrictEqual(
-      tryHex(a.witness),
-      tryHex(b.witness),
-      `Inequal ${context}witness`,
-    );
-}
-
-export function equate(a: any, b: any, args?: any): void {
-  b = Object.assign({}, b);
-  carryOver(b, args);
-
-  // by null, we mean 'undefined', but JSON
-  if (b.input === null) b.input = undefined;
-  if (b.output === null) b.output = undefined;
-  if (b.witness === null) b.witness = undefined;
-  if (b.redeem) {
-    if (b.redeem.input === null) b.redeem.input = undefined;
-    if (b.redeem.output === null) b.redeem.output = undefined;
-    if (b.redeem.witness === null) b.redeem.witness = undefined;
-  }
-
-  equateBase(a, b, '');
-  if (b.redeem) equateBase(a.redeem, b.redeem, 'redeem.');
-  if (b.network)
-    t.deepStrictEqual(
-      a.network,
-      (BNETWORKS as any)[b.network],
-      'Inequal *.network',
-    );
-
-  // contextual
-  if (b.signature === null) b.signature = undefined;
-  if (b.signatures === null) b.signatures = undefined;
-  if ('address' in b) t.strictEqual(a.address, b.address, 'Inequal *.address');
-  if ('name' in b) t.strictEqual(a.name, b.name, 'Inequal *.name');
-  if ('hash' in b)
-    t.strictEqual(tryHex(a.hash), tryHex(b.hash), 'Inequal *.hash');
-  if ('pubkey' in b)
-    t.strictEqual(tryHex(a.pubkey), tryHex(b.pubkey), 'Inequal *.pubkey');
-  if ('signature' in b)
-    t.strictEqual(
-      tryHex(a.signature),
-      tryHex(b.signature),
-      'Inequal signature',
-    );
-  if ('m' in b) t.strictEqual(a.m, b.m, 'Inequal *.m');
-  if ('n' in b) t.strictEqual(a.n, b.n, 'Inequal *.n');
-  if ('pubkeys' in b)
-    t.deepStrictEqual(
-      tryHex(a.pubkeys),
-      tryHex(b.pubkeys),
-      'Inequal *.pubkeys',
-    );
-  if ('signatures' in b)
-    t.deepStrictEqual(
-      tryHex(a.signatures),
-      tryHex(b.signatures),
-      'Inequal *.signatures',
-    );
-  if ('data' in b)
-    t.deepStrictEqual(tryHex(a.data), tryHex(b.data), 'Inequal *.data');
-}
-
-export function preform(x: any): any {
-  x = Object.assign({}, x);
-
-  if (x.network) x.network = (BNETWORKS as any)[x.network];
-  if (typeof x.inputHex === 'string') {
-    x.input = Buffer.from(x.inputHex, 'hex');
-    delete x.inputHex;
-  }
-  if (typeof x.outputHex === 'string') {
-    x.output = Buffer.from(x.outputHex, 'hex');
-    delete x.outputHex;
-  }
-  if (typeof x.output === 'string') x.output = asmToBuffer(x.output);
-  if (typeof x.input === 'string') x.input = asmToBuffer(x.input);
-  if (Array.isArray(x.witness)) x.witness = x.witness.map(fromHex);
-
-  if (x.data) x.data = x.data.map(fromHex);
-  if (x.hash) x.hash = Buffer.from(x.hash, 'hex');
-  if (x.pubkey) x.pubkey = Buffer.from(x.pubkey, 'hex');
-  if (x.signature) x.signature = Buffer.from(x.signature, 'hex');
-  if (x.pubkeys) x.pubkeys = x.pubkeys.map(fromHex);
-  if (x.signatures)
-    x.signatures = x.signatures.map((y: any) => {
-      return Number.isFinite(y) ? y : Buffer.from(y, 'hex');
-    });
-  if (x.redeem) {
-    x.redeem = Object.assign({}, x.redeem);
-    if (typeof x.redeem.input === 'string')
-      x.redeem.input = asmToBuffer(x.redeem.input);
-    if (typeof x.redeem.output === 'string')
-      x.redeem.output = asmToBuffer(x.redeem.output);
-    if (Array.isArray(x.redeem.witness))
-      x.redeem.witness = x.redeem.witness.map(fromHex);
-    if (x.redeem.network)
-      x.redeem.network = (BNETWORKS as any)[x.redeem.network];
-  }
-
-  return x;
-}
-
-export function from(path: string, object: any, result?: any): any {
-  const paths = path.split('.');
-  result = result || {};
-
-  let r = result;
-  paths.forEach((k, i) => {
-    if (i < paths.length - 1) {
-      r[k] = r[k] || {};
-
-      // recurse
-      r = r[k];
-      object = object[k];
-    } else {
-      r[k] = object[k];
-    }
-  });
-
-  return result;
-}
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
deleted file mode 100644
index f583e80..0000000
--- a/test/psbt.spec.ts
+++ /dev/null
@@ -1,1137 +0,0 @@
-import * as assert from 'assert';
-import BIP32Factory from 'bip32';
-import * as ecc from 'tiny-secp256k1';
-import * as crypto from 'crypto';
-import ECPairFactory from 'ecpair';
-import { describe, it } from 'mocha';
-
-const bip32 = BIP32Factory(ecc);
-const ECPair = ECPairFactory(ecc);
-
-import { networks as NETWORKS, payments, Psbt, Signer, SignerAsync } from '..';
-
-import * as preFixtures from './fixtures/psbt.json';
-
-const validator = (
-  pubkey: Buffer,
-  msghash: Buffer,
-  signature: Buffer,
-): boolean => ECPair.fromPublicKey(pubkey).verify(msghash, signature);
-
-const initBuffers = (object: any): typeof preFixtures =>
-  JSON.parse(JSON.stringify(object), (_, value) => {
-    const regex = new RegExp(/^Buffer.from\(['"](.*)['"], ['"](.*)['"]\)$/);
-    const result = regex.exec(value);
-    if (!result) return value;
-
-    const data = result[1];
-    const encoding = result[2];
-
-    return Buffer.from(data, encoding as BufferEncoding);
-  });
-
-const fixtures = initBuffers(preFixtures);
-
-const upperCaseFirstLetter = (str: string): string =>
-  str.replace(/^./, s => s.toUpperCase());
-
-const toAsyncSigner = (signer: Signer): SignerAsync => {
-  const ret: SignerAsync = {
-    publicKey: signer.publicKey,
-    sign: (hash: Buffer, lowerR: boolean | undefined): Promise<Buffer> => {
-      return new Promise(
-        (resolve, rejects): void => {
-          setTimeout(() => {
-            try {
-              const r = signer.sign(hash, lowerR);
-              resolve(r);
-            } catch (e) {
-              rejects(e);
-            }
-          }, 10);
-        },
-      );
-    },
-  };
-  return ret;
-};
-const failedAsyncSigner = (publicKey: Buffer): SignerAsync => {
-  return {
-    publicKey,
-    sign: (__: Buffer): Promise<Buffer> => {
-      return new Promise(
-        (_, reject): void => {
-          setTimeout(() => {
-            reject(new Error('sign failed'));
-          }, 10);
-        },
-      );
-    },
-  };
-};
-// const b = (hex: string) => Buffer.from(hex, 'hex');
-
-describe(`Psbt`, () => {
-  describe('BIP174 Test Vectors', () => {
-    fixtures.bip174.invalid.forEach(f => {
-      it(`Invalid: ${f.description}`, () => {
-        assert.throws(() => {
-          Psbt.fromBase64(f.psbt);
-        }, new RegExp(f.errorMessage));
-      });
-    });
-
-    fixtures.bip174.valid.forEach(f => {
-      it(`Valid: ${f.description}`, () => {
-        assert.doesNotThrow(() => {
-          Psbt.fromBase64(f.psbt);
-        });
-      });
-    });
-
-    fixtures.bip174.failSignChecks.forEach(f => {
-      const keyPair = ECPair.makeRandom();
-      it(`Fails Signer checks: ${f.description}`, () => {
-        const psbt = Psbt.fromBase64(f.psbt);
-        assert.throws(() => {
-          psbt.signInput(f.inputToCheck, keyPair);
-        }, new RegExp(f.errorMessage));
-      });
-    });
-
-    fixtures.bip174.creator.forEach(f => {
-      it('Creates expected PSBT', () => {
-        const psbt = new Psbt();
-        for (const input of f.inputs) {
-          psbt.addInput(input);
-        }
-        for (const output of f.outputs) {
-          const script = Buffer.from(output.script, 'hex');
-          psbt.addOutput({ ...output, script });
-        }
-        assert.strictEqual(psbt.toBase64(), f.result);
-      });
-    });
-
-    fixtures.bip174.updater.forEach(f => {
-      it('Updates PSBT to the expected result', () => {
-        const psbt = Psbt.fromBase64(f.psbt);
-
-        for (const inputOrOutput of ['input', 'output']) {
-          const fixtureData = (f as any)[`${inputOrOutput}Data`];
-          if (fixtureData) {
-            for (const [i, data] of fixtureData.entries()) {
-              const txt = upperCaseFirstLetter(inputOrOutput);
-              (psbt as any)[`update${txt}`](i, data);
-            }
-          }
-        }
-
-        assert.strictEqual(psbt.toBase64(), f.result);
-      });
-    });
-
-    fixtures.bip174.signer.forEach(f => {
-      it('Signs PSBT to the expected result', () => {
-        const psbt = Psbt.fromBase64(f.psbt);
-
-        f.keys.forEach(({ inputToSign, WIF }) => {
-          const keyPair = ECPair.fromWIF(WIF, NETWORKS.testnet);
-          psbt.signInput(inputToSign, keyPair);
-        });
-
-        assert.strictEqual(psbt.toBase64(), f.result);
-      });
-    });
-
-    fixtures.bip174.combiner.forEach(f => {
-      it('Combines two PSBTs to the expected result', () => {
-        const psbts = f.psbts.map(psbt => Psbt.fromBase64(psbt));
-
-        psbts[0].combine(psbts[1]);
-
-        // Produces a different Base64 string due to implemetation specific key-value ordering.
-        // That means this test will fail:
-        // assert.strictEqual(psbts[0].toBase64(), f.result)
-        // However, if we compare the actual PSBT properties we can see they are logically identical:
-        assert.deepStrictEqual(psbts[0], Psbt.fromBase64(f.result));
-      });
-    });
-
-    fixtures.bip174.finalizer.forEach(f => {
-      it('Finalizes inputs and gives the expected PSBT', () => {
-        const psbt = Psbt.fromBase64(f.psbt);
-
-        psbt.finalizeAllInputs();
-
-        assert.strictEqual(psbt.toBase64(), f.result);
-      });
-    });
-
-    fixtures.bip174.extractor.forEach(f => {
-      it('Extracts the expected transaction from a PSBT', () => {
-        const psbt1 = Psbt.fromBase64(f.psbt);
-        const transaction1 = psbt1.extractTransaction(true).toHex();
-
-        const psbt2 = Psbt.fromBase64(f.psbt);
-        const transaction2 = psbt2.extractTransaction().toHex();
-
-        assert.strictEqual(transaction1, transaction2);
-        assert.strictEqual(transaction1, f.transaction);
-
-        const psbt3 = Psbt.fromBase64(f.psbt);
-        delete psbt3.data.inputs[0].finalScriptSig;
-        delete psbt3.data.inputs[0].finalScriptWitness;
-        assert.throws(() => {
-          psbt3.extractTransaction();
-        }, new RegExp('Not finalized'));
-
-        const psbt4 = Psbt.fromBase64(f.psbt);
-        psbt4.setMaximumFeeRate(1);
-        assert.throws(() => {
-          psbt4.extractTransaction();
-        }, new RegExp('Warning: You are paying around [\\d.]+ in fees'));
-
-        const psbt5 = Psbt.fromBase64(f.psbt);
-        psbt5.extractTransaction(true);
-        const fr1 = psbt5.getFeeRate();
-        const fr2 = psbt5.getFeeRate();
-        assert.strictEqual(fr1, fr2);
-
-        const psbt6 = Psbt.fromBase64(f.psbt);
-        const f1 = psbt6.getFee();
-        const f2 = psbt6.getFee();
-        assert.strictEqual(f1, f2);
-      });
-    });
-  });
-
-  describe('signInputAsync', () => {
-    fixtures.signInput.checks.forEach(f => {
-      it(f.description, async () => {
-        if (f.shouldSign) {
-          const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt);
-          await assert.doesNotReject(async () => {
-            await psbtThatShouldsign.signInputAsync(
-              f.shouldSign.inputToCheck,
-              ECPair.fromWIF(f.shouldSign.WIF),
-              f.shouldSign.sighashTypes || undefined,
-            );
-          });
-          await assert.rejects(async () => {
-            await psbtThatShouldsign.signInputAsync(
-              f.shouldSign.inputToCheck,
-              failedAsyncSigner(ECPair.fromWIF(f.shouldSign.WIF).publicKey),
-              f.shouldSign.sighashTypes || undefined,
-            );
-          }, /sign failed/);
-        }
-
-        if (f.shouldThrow) {
-          const psbtThatShouldThrow = Psbt.fromBase64(f.shouldThrow.psbt);
-          await assert.rejects(async () => {
-            await psbtThatShouldThrow.signInputAsync(
-              f.shouldThrow.inputToCheck,
-              ECPair.fromWIF(f.shouldThrow.WIF),
-              (f.shouldThrow as any).sighashTypes || undefined,
-            );
-          }, new RegExp(f.shouldThrow.errorMessage));
-          await assert.rejects(async () => {
-            await psbtThatShouldThrow.signInputAsync(
-              f.shouldThrow.inputToCheck,
-              toAsyncSigner(ECPair.fromWIF(f.shouldThrow.WIF)),
-              (f.shouldThrow as any).sighashTypes || undefined,
-            );
-          }, new RegExp(f.shouldThrow.errorMessage));
-          await assert.rejects(async () => {
-            await (psbtThatShouldThrow.signInputAsync as any)(
-              f.shouldThrow.inputToCheck,
-            );
-          }, new RegExp('Need Signer to sign input'));
-        }
-      });
-    });
-  });
-
-  describe('signInput', () => {
-    fixtures.signInput.checks.forEach(f => {
-      it(f.description, () => {
-        if (f.shouldSign) {
-          const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt);
-          assert.doesNotThrow(() => {
-            psbtThatShouldsign.signInput(
-              f.shouldSign.inputToCheck,
-              ECPair.fromWIF(f.shouldSign.WIF),
-              f.shouldSign.sighashTypes || undefined,
-            );
-          });
-        }
-
-        if (f.shouldThrow) {
-          const psbtThatShouldThrow = Psbt.fromBase64(f.shouldThrow.psbt);
-          assert.throws(() => {
-            psbtThatShouldThrow.signInput(
-              f.shouldThrow.inputToCheck,
-              ECPair.fromWIF(f.shouldThrow.WIF),
-              (f.shouldThrow as any).sighashTypes || undefined,
-            );
-          }, new RegExp(f.shouldThrow.errorMessage));
-          assert.throws(() => {
-            (psbtThatShouldThrow.signInput as any)(f.shouldThrow.inputToCheck);
-          }, new RegExp('Need Signer to sign input'));
-        }
-      });
-    });
-  });
-
-  describe('signAllInputsAsync', () => {
-    fixtures.signInput.checks.forEach(f => {
-      if (f.description === 'checks the input exists') return;
-      it(f.description, async () => {
-        if (f.shouldSign) {
-          const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt);
-          await assert.doesNotReject(async () => {
-            await psbtThatShouldsign.signAllInputsAsync(
-              ECPair.fromWIF(f.shouldSign.WIF),
-              f.shouldSign.sighashTypes || undefined,
-            );
-          });
-        }
-
-        if (f.shouldThrow) {
-          const psbtThatShouldThrow = Psbt.fromBase64(f.shouldThrow.psbt);
-          await assert.rejects(async () => {
-            await psbtThatShouldThrow.signAllInputsAsync(
-              ECPair.fromWIF(f.shouldThrow.WIF),
-              (f.shouldThrow as any).sighashTypes || undefined,
-            );
-          }, new RegExp('No inputs were signed'));
-          await assert.rejects(async () => {
-            await (psbtThatShouldThrow.signAllInputsAsync as any)();
-          }, new RegExp('Need Signer to sign input'));
-        }
-      });
-    });
-  });
-
-  describe('signAllInputs', () => {
-    fixtures.signInput.checks.forEach(f => {
-      if (f.description === 'checks the input exists') return;
-      it(f.description, () => {
-        if (f.shouldSign) {
-          const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt);
-          assert.doesNotThrow(() => {
-            psbtThatShouldsign.signAllInputs(
-              ECPair.fromWIF(f.shouldSign.WIF),
-              f.shouldSign.sighashTypes || undefined,
-            );
-          });
-        }
-
-        if (f.shouldThrow) {
-          const psbtThatShouldThrow = Psbt.fromBase64(f.shouldThrow.psbt);
-          assert.throws(() => {
-            psbtThatShouldThrow.signAllInputs(
-              ECPair.fromWIF(f.shouldThrow.WIF),
-              (f.shouldThrow as any).sighashTypes || undefined,
-            );
-          }, new RegExp('No inputs were signed'));
-          assert.throws(() => {
-            (psbtThatShouldThrow.signAllInputs as any)();
-          }, new RegExp('Need Signer to sign input'));
-        }
-      });
-    });
-  });
-
-  describe('signInputHDAsync', () => {
-    fixtures.signInputHD.checks.forEach(f => {
-      it(f.description, async () => {
-        if (f.shouldSign) {
-          const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt);
-          await assert.doesNotReject(async () => {
-            await psbtThatShouldsign.signInputHDAsync(
-              f.shouldSign.inputToCheck,
-              bip32.fromBase58(f.shouldSign.xprv),
-              (f.shouldSign as any).sighashTypes || undefined,
-            );
-          });
-        }
-
-        if (f.shouldThrow) {
-          const psbtThatShouldThrow = Psbt.fromBase64(f.shouldThrow.psbt);
-          await assert.rejects(async () => {
-            await psbtThatShouldThrow.signInputHDAsync(
-              f.shouldThrow.inputToCheck,
-              bip32.fromBase58(f.shouldThrow.xprv),
-              (f.shouldThrow as any).sighashTypes || undefined,
-            );
-          }, new RegExp(f.shouldThrow.errorMessage));
-          await assert.rejects(async () => {
-            await (psbtThatShouldThrow.signInputHDAsync as any)(
-              f.shouldThrow.inputToCheck,
-            );
-          }, new RegExp('Need HDSigner to sign input'));
-        }
-      });
-    });
-  });
-
-  describe('signInputHD', () => {
-    fixtures.signInputHD.checks.forEach(f => {
-      it(f.description, () => {
-        if (f.shouldSign) {
-          const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt);
-          assert.doesNotThrow(() => {
-            psbtThatShouldsign.signInputHD(
-              f.shouldSign.inputToCheck,
-              bip32.fromBase58(f.shouldSign.xprv),
-              (f.shouldSign as any).sighashTypes || undefined,
-            );
-          });
-        }
-
-        if (f.shouldThrow) {
-          const psbtThatShouldThrow = Psbt.fromBase64(f.shouldThrow.psbt);
-          assert.throws(() => {
-            psbtThatShouldThrow.signInputHD(
-              f.shouldThrow.inputToCheck,
-              bip32.fromBase58(f.shouldThrow.xprv),
-              (f.shouldThrow as any).sighashTypes || undefined,
-            );
-          }, new RegExp(f.shouldThrow.errorMessage));
-          assert.throws(() => {
-            (psbtThatShouldThrow.signInputHD as any)(
-              f.shouldThrow.inputToCheck,
-            );
-          }, new RegExp('Need HDSigner to sign input'));
-        }
-      });
-    });
-  });
-
-  describe('signAllInputsHDAsync', () => {
-    fixtures.signInputHD.checks.forEach(f => {
-      it(f.description, async () => {
-        if (f.shouldSign) {
-          const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt);
-          await assert.doesNotReject(async () => {
-            await psbtThatShouldsign.signAllInputsHDAsync(
-              bip32.fromBase58(f.shouldSign.xprv),
-              (f.shouldSign as any).sighashTypes || undefined,
-            );
-          });
-        }
-
-        if (f.shouldThrow) {
-          const psbtThatShouldThrow = Psbt.fromBase64(f.shouldThrow.psbt);
-          await assert.rejects(async () => {
-            await psbtThatShouldThrow.signAllInputsHDAsync(
-              bip32.fromBase58(f.shouldThrow.xprv),
-              (f.shouldThrow as any).sighashTypes || undefined,
-            );
-          }, new RegExp('No inputs were signed'));
-          await assert.rejects(async () => {
-            await (psbtThatShouldThrow.signAllInputsHDAsync as any)();
-          }, new RegExp('Need HDSigner to sign input'));
-        }
-      });
-    });
-  });
-
-  describe('signAllInputsHD', () => {
-    fixtures.signInputHD.checks.forEach(f => {
-      it(f.description, () => {
-        if (f.shouldSign) {
-          const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt);
-          assert.doesNotThrow(() => {
-            psbtThatShouldsign.signAllInputsHD(
-              bip32.fromBase58(f.shouldSign.xprv),
-              (f.shouldSign as any).sighashTypes || undefined,
-            );
-          });
-        }
-
-        if (f.shouldThrow) {
-          const psbtThatShouldThrow = Psbt.fromBase64(f.shouldThrow.psbt);
-          assert.throws(() => {
-            psbtThatShouldThrow.signAllInputsHD(
-              bip32.fromBase58(f.shouldThrow.xprv),
-              (f.shouldThrow as any).sighashTypes || undefined,
-            );
-          }, new RegExp('No inputs were signed'));
-          assert.throws(() => {
-            (psbtThatShouldThrow.signAllInputsHD as any)();
-          }, new RegExp('Need HDSigner to sign input'));
-        }
-      });
-    });
-  });
-
-  describe('finalizeAllInputs', () => {
-    fixtures.finalizeAllInputs.forEach(f => {
-      it(`Finalizes inputs of type "${f.type}"`, () => {
-        const psbt = Psbt.fromBase64(f.psbt);
-
-        psbt.finalizeAllInputs();
-
-        assert.strictEqual(psbt.toBase64(), f.result);
-      });
-    });
-    it('fails if no script found', () => {
-      const psbt = new Psbt();
-      psbt.addInput({
-        hash:
-          '0000000000000000000000000000000000000000000000000000000000000000',
-        index: 0,
-      });
-      assert.throws(() => {
-        psbt.finalizeAllInputs();
-      }, new RegExp('No script found for input #0'));
-      psbt.updateInput(0, {
-        witnessUtxo: {
-          script: Buffer.from(
-            '0014d85c2b71d0060b09c9886aeb815e50991dda124d',
-            'hex',
-          ),
-          value: 2e5,
-        },
-      });
-      assert.throws(() => {
-        psbt.finalizeAllInputs();
-      }, new RegExp('Can not finalize input #0'));
-    });
-  });
-
-  describe('addInput', () => {
-    fixtures.addInput.checks.forEach(f => {
-      it(f.description, () => {
-        const psbt = new Psbt();
-
-        if (f.exception) {
-          assert.throws(() => {
-            psbt.addInput(f.inputData as any);
-          }, new RegExp(f.exception));
-          assert.throws(() => {
-            psbt.addInputs([f.inputData as any]);
-          }, new RegExp(f.exception));
-        } else {
-          assert.doesNotThrow(() => {
-            psbt.addInputs([f.inputData as any]);
-            if (f.equals) {
-              assert.strictEqual(psbt.toBase64(), f.equals);
-            }
-          });
-          assert.throws(() => {
-            psbt.addInput(f.inputData as any);
-          }, new RegExp('Duplicate input detected.'));
-        }
-      });
-    });
-  });
-
-  describe('addOutput', () => {
-    fixtures.addOutput.checks.forEach(f => {
-      it(f.description, () => {
-        const psbt = new Psbt();
-
-        if (f.exception) {
-          assert.throws(() => {
-            psbt.addOutput(f.outputData as any);
-          }, new RegExp(f.exception));
-          assert.throws(() => {
-            psbt.addOutputs([f.outputData as any]);
-          }, new RegExp(f.exception));
-        } else {
-          assert.doesNotThrow(() => {
-            psbt.addOutput(f.outputData as any);
-          });
-          assert.doesNotThrow(() => {
-            psbt.addOutputs([f.outputData as any]);
-          });
-        }
-      });
-    });
-  });
-
-  describe('setVersion', () => {
-    it('Sets the version value of the unsigned transaction', () => {
-      const psbt = new Psbt();
-
-      assert.strictEqual(psbt.extractTransaction().version, 2);
-      psbt.setVersion(1);
-      assert.strictEqual(psbt.extractTransaction().version, 1);
-    });
-  });
-
-  describe('setLocktime', () => {
-    it('Sets the nLockTime value of the unsigned transaction', () => {
-      const psbt = new Psbt();
-
-      assert.strictEqual(psbt.extractTransaction().locktime, 0);
-      psbt.setLocktime(1);
-      assert.strictEqual(psbt.extractTransaction().locktime, 1);
-    });
-  });
-
-  describe('setInputSequence', () => {
-    it('Sets the sequence number for a given input', () => {
-      const psbt = new Psbt();
-      psbt.addInput({
-        hash:
-          '0000000000000000000000000000000000000000000000000000000000000000',
-        index: 0,
-      });
-
-      assert.strictEqual(psbt.inputCount, 1);
-      assert.strictEqual(psbt.txInputs[0].sequence, 0xffffffff);
-      psbt.setInputSequence(0, 0);
-      assert.strictEqual(psbt.txInputs[0].sequence, 0);
-    });
-
-    it('throws if input index is too high', () => {
-      const psbt = new Psbt();
-      psbt.addInput({
-        hash:
-          '0000000000000000000000000000000000000000000000000000000000000000',
-        index: 0,
-      });
-
-      assert.throws(() => {
-        psbt.setInputSequence(1, 0);
-      }, new RegExp('Input index too high'));
-    });
-  });
-
-  describe('getInputType', () => {
-    const key = ECPair.makeRandom();
-    const { publicKey } = key;
-    const p2wpkhPub = (pubkey: Buffer): Buffer =>
-      payments.p2wpkh({
-        pubkey,
-      }).output!;
-    const p2pkhPub = (pubkey: Buffer): Buffer =>
-      payments.p2pkh({
-        pubkey,
-      }).output!;
-    const p2shOut = (output: Buffer): Buffer =>
-      payments.p2sh({
-        redeem: { output },
-      }).output!;
-    const p2wshOut = (output: Buffer): Buffer =>
-      payments.p2wsh({
-        redeem: { output },
-      }).output!;
-    const p2shp2wshOut = (output: Buffer): Buffer => p2shOut(p2wshOut(output));
-    const noOuter = (output: Buffer): Buffer => output;
-
-    function getInputTypeTest({
-      innerScript,
-      outerScript,
-      redeemGetter,
-      witnessGetter,
-      expectedType,
-      finalize,
-    }: any): void {
-      const psbt = new Psbt();
-      psbt
-        .addInput({
-          hash:
-            '0000000000000000000000000000000000000000000000000000000000000000',
-          index: 0,
-          witnessUtxo: {
-            script: outerScript(innerScript(publicKey)),
-            value: 2e3,
-          },
-          ...(redeemGetter ? { redeemScript: redeemGetter(publicKey) } : {}),
-          ...(witnessGetter ? { witnessScript: witnessGetter(publicKey) } : {}),
-        })
-        .addOutput({
-          script: Buffer.from('0014d85c2b71d0060b09c9886aeb815e50991dda124d'),
-          value: 1800,
-        });
-      if (finalize) psbt.signInput(0, key).finalizeInput(0);
-      const type = psbt.getInputType(0);
-      assert.strictEqual(type, expectedType, 'incorrect input type');
-    }
-    [
-      {
-        innerScript: p2pkhPub,
-        outerScript: noOuter,
-        redeemGetter: null,
-        witnessGetter: null,
-        expectedType: 'pubkeyhash',
-      },
-      {
-        innerScript: p2wpkhPub,
-        outerScript: noOuter,
-        redeemGetter: null,
-        witnessGetter: null,
-        expectedType: 'witnesspubkeyhash',
-      },
-      {
-        innerScript: p2pkhPub,
-        outerScript: p2shOut,
-        redeemGetter: p2pkhPub,
-        witnessGetter: null,
-        expectedType: 'p2sh-pubkeyhash',
-      },
-      {
-        innerScript: p2wpkhPub,
-        outerScript: p2shOut,
-        redeemGetter: p2wpkhPub,
-        witnessGetter: null,
-        expectedType: 'p2sh-witnesspubkeyhash',
-        finalize: true,
-      },
-      {
-        innerScript: p2pkhPub,
-        outerScript: p2wshOut,
-        redeemGetter: null,
-        witnessGetter: p2pkhPub,
-        expectedType: 'p2wsh-pubkeyhash',
-        finalize: true,
-      },
-      {
-        innerScript: p2pkhPub,
-        outerScript: p2shp2wshOut,
-        redeemGetter: (pk: Buffer): Buffer => p2wshOut(p2pkhPub(pk)),
-        witnessGetter: p2pkhPub,
-        expectedType: 'p2sh-p2wsh-pubkeyhash',
-      },
-    ].forEach(getInputTypeTest);
-  });
-
-  describe('inputHasHDKey', () => {
-    it('should return true if HD key is present', () => {
-      const root = bip32.fromSeed(crypto.randomBytes(32));
-      const root2 = bip32.fromSeed(crypto.randomBytes(32));
-      const path = "m/0'/0";
-      const psbt = new Psbt();
-      psbt.addInput({
-        hash:
-          '0000000000000000000000000000000000000000000000000000000000000000',
-        index: 0,
-        bip32Derivation: [
-          {
-            masterFingerprint: root.fingerprint,
-            path,
-            pubkey: root.derivePath(path).publicKey,
-          },
-        ],
-      });
-      assert.strictEqual(psbt.inputHasHDKey(0, root), true);
-      assert.strictEqual(psbt.inputHasHDKey(0, root2), false);
-    });
-  });
-
-  describe('inputHasPubkey', () => {
-    it('should throw', () => {
-      const psbt = new Psbt();
-      psbt.addInput({
-        hash:
-          '0000000000000000000000000000000000000000000000000000000000000000',
-        index: 0,
-      });
-
-      assert.throws(() => {
-        psbt.inputHasPubkey(0, Buffer.from([]));
-      }, new RegExp("Can't find pubkey in input without Utxo data"));
-
-      psbt.updateInput(0, {
-        witnessUtxo: {
-          value: 1337,
-          script: payments.p2sh({
-            redeem: { output: Buffer.from([0x51]) },
-          }).output!,
-        },
-      });
-
-      assert.throws(() => {
-        psbt.inputHasPubkey(0, Buffer.from([]));
-      }, new RegExp('scriptPubkey is P2SH but redeemScript missing'));
-
-      delete psbt.data.inputs[0].witnessUtxo;
-
-      psbt.updateInput(0, {
-        witnessUtxo: {
-          value: 1337,
-          script: payments.p2wsh({
-            redeem: { output: Buffer.from([0x51]) },
-          }).output!,
-        },
-      });
-
-      assert.throws(() => {
-        psbt.inputHasPubkey(0, Buffer.from([]));
-      }, new RegExp('scriptPubkey or redeemScript is P2WSH but witnessScript missing'));
-
-      delete psbt.data.inputs[0].witnessUtxo;
-
-      psbt.updateInput(0, {
-        witnessUtxo: {
-          value: 1337,
-          script: payments.p2sh({
-            redeem: payments.p2wsh({
-              redeem: { output: Buffer.from([0x51]) },
-            }),
-          }).output!,
-        },
-        redeemScript: payments.p2wsh({
-          redeem: { output: Buffer.from([0x51]) },
-        }).output!,
-      });
-
-      assert.throws(() => {
-        psbt.inputHasPubkey(0, Buffer.from([]));
-      }, new RegExp('scriptPubkey or redeemScript is P2WSH but witnessScript missing'));
-
-      psbt.updateInput(0, {
-        witnessScript: Buffer.from([0x51]),
-      });
-
-      assert.doesNotThrow(() => {
-        psbt.inputHasPubkey(0, Buffer.from([0x51]));
-      });
-    });
-  });
-
-  describe('outputHasHDKey', () => {
-    it('should return true if HD key is present', () => {
-      const root = bip32.fromSeed(crypto.randomBytes(32));
-      const root2 = bip32.fromSeed(crypto.randomBytes(32));
-      const path = "m/0'/0";
-      const psbt = new Psbt();
-      psbt
-        .addInput({
-          hash:
-            '0000000000000000000000000000000000000000000000000000000000000000',
-          index: 0,
-        })
-        .addOutput({
-          script: Buffer.from(
-            '0014000102030405060708090a0b0c0d0e0f00010203',
-            'hex',
-          ),
-          value: 2000,
-          bip32Derivation: [
-            {
-              masterFingerprint: root.fingerprint,
-              path,
-              pubkey: root.derivePath(path).publicKey,
-            },
-          ],
-        });
-      assert.strictEqual(psbt.outputHasHDKey(0, root), true);
-      assert.strictEqual(psbt.outputHasHDKey(0, root2), false);
-    });
-  });
-
-  describe('outputHasPubkey', () => {
-    it('should throw', () => {
-      const psbt = new Psbt();
-      psbt
-        .addInput({
-          hash:
-            '0000000000000000000000000000000000000000000000000000000000000000',
-          index: 0,
-        })
-        .addOutput({
-          script: payments.p2sh({
-            redeem: { output: Buffer.from([0x51]) },
-          }).output!,
-          value: 1337,
-        });
-
-      assert.throws(() => {
-        psbt.outputHasPubkey(0, Buffer.from([]));
-      }, new RegExp('scriptPubkey is P2SH but redeemScript missing'));
-
-      (psbt as any).__CACHE.__TX.outs[0].script = payments.p2wsh({
-        redeem: { output: Buffer.from([0x51]) },
-      }).output!;
-
-      assert.throws(() => {
-        psbt.outputHasPubkey(0, Buffer.from([]));
-      }, new RegExp('scriptPubkey or redeemScript is P2WSH but witnessScript missing'));
-
-      (psbt as any).__CACHE.__TX.outs[0].script = payments.p2sh({
-        redeem: payments.p2wsh({
-          redeem: { output: Buffer.from([0x51]) },
-        }),
-      }).output!;
-
-      psbt.updateOutput(0, {
-        redeemScript: payments.p2wsh({
-          redeem: { output: Buffer.from([0x51]) },
-        }).output!,
-      });
-
-      assert.throws(() => {
-        psbt.outputHasPubkey(0, Buffer.from([]));
-      }, new RegExp('scriptPubkey or redeemScript is P2WSH but witnessScript missing'));
-
-      delete psbt.data.outputs[0].redeemScript;
-
-      psbt.updateOutput(0, {
-        witnessScript: Buffer.from([0x51]),
-      });
-
-      assert.throws(() => {
-        psbt.outputHasPubkey(0, Buffer.from([]));
-      }, new RegExp('scriptPubkey is P2SH but redeemScript missing'));
-
-      psbt.updateOutput(0, {
-        redeemScript: payments.p2wsh({
-          redeem: { output: Buffer.from([0x51]) },
-        }).output!,
-      });
-
-      assert.doesNotThrow(() => {
-        psbt.outputHasPubkey(0, Buffer.from([0x51]));
-      });
-    });
-  });
-
-  describe('clone', () => {
-    it('Should clone a psbt exactly with no reference', () => {
-      const f = fixtures.clone;
-      const psbt = Psbt.fromBase64(f.psbt);
-      const notAClone = Object.assign(new Psbt(), psbt); // references still active
-      const clone = psbt.clone();
-
-      assert.strictEqual(psbt.validateSignaturesOfAllInputs(validator), true);
-
-      assert.strictEqual(clone.toBase64(), psbt.toBase64());
-      assert.strictEqual(clone.toBase64(), notAClone.toBase64());
-      assert.strictEqual(psbt.toBase64(), notAClone.toBase64());
-      (psbt as any).__CACHE.__TX.version |= 0xff0000;
-      assert.notStrictEqual(clone.toBase64(), psbt.toBase64());
-      assert.notStrictEqual(clone.toBase64(), notAClone.toBase64());
-      assert.strictEqual(psbt.toBase64(), notAClone.toBase64());
-    });
-  });
-
-  describe('setMaximumFeeRate', () => {
-    it('Sets the maximumFeeRate value', () => {
-      const psbt = new Psbt();
-
-      assert.strictEqual((psbt as any).opts.maximumFeeRate, 5000);
-      psbt.setMaximumFeeRate(6000);
-      assert.strictEqual((psbt as any).opts.maximumFeeRate, 6000);
-    });
-  });
-
-  describe('validateSignaturesOfInput', () => {
-    const f = fixtures.validateSignaturesOfInput;
-    it('Correctly validates a signature', () => {
-      const psbt = Psbt.fromBase64(f.psbt);
-
-      assert.strictEqual(
-        psbt.validateSignaturesOfInput(f.index, validator),
-        true,
-      );
-      assert.throws(() => {
-        psbt.validateSignaturesOfInput(f.nonExistantIndex, validator);
-      }, new RegExp('No signatures to validate'));
-    });
-
-    it('Correctly validates a signature against a pubkey', () => {
-      const psbt = Psbt.fromBase64(f.psbt);
-      assert.strictEqual(
-        psbt.validateSignaturesOfInput(f.index, validator, f.pubkey as any),
-        true,
-      );
-      assert.throws(() => {
-        psbt.validateSignaturesOfInput(
-          f.index,
-          validator,
-          f.incorrectPubkey as any,
-        );
-      }, new RegExp('No signatures for this pubkey'));
-    });
-  });
-
-  describe('getFeeRate', () => {
-    it('Throws error if called before inputs are finalized', () => {
-      const f = fixtures.getFeeRate;
-      const psbt = Psbt.fromBase64(f.psbt);
-
-      assert.throws(() => {
-        psbt.getFeeRate();
-      }, new RegExp('PSBT must be finalized to calculate fee rate'));
-
-      psbt.finalizeAllInputs();
-
-      assert.strictEqual(psbt.getFeeRate(), f.fee);
-      (psbt as any).__CACHE.__FEE_RATE = undefined;
-      assert.strictEqual(psbt.getFeeRate(), f.fee);
-    });
-  });
-
-  describe('create 1-to-1 transaction', () => {
-    const alice = ECPair.fromWIF(
-      'L2uPYXe17xSTqbCjZvL2DsyXPCbXspvcu5mHLDYUgzdUbZGSKrSr',
-    );
-    const psbt = new Psbt();
-    psbt.addInput({
-      hash: '7d067b4a697a09d2c3cff7d4d9506c9955e93bff41bf82d439da7d030382bc3e',
-      index: 0,
-      nonWitnessUtxo: Buffer.from(
-        '0200000001f9f34e95b9d5c8abcd20fc5bd4a825d1517be62f0f775e5f36da944d9' +
-          '452e550000000006b483045022100c86e9a111afc90f64b4904bd609e9eaed80d48' +
-          'ca17c162b1aca0a788ac3526f002207bb79b60d4fc6526329bf18a77135dc566020' +
-          '9e761da46e1c2f1152ec013215801210211755115eabf846720f5cb18f248666fec' +
-          '631e5e1e66009ce3710ceea5b1ad13ffffffff01905f0100000000001976a9148bb' +
-          'c95d2709c71607c60ee3f097c1217482f518d88ac00000000',
-        'hex',
-      ),
-      sighashType: 1,
-    });
-    psbt.addOutput({
-      address: '1KRMKfeZcmosxALVYESdPNez1AP1mEtywp',
-      value: 80000,
-    });
-    psbt.signInput(0, alice);
-    assert.throws(() => {
-      psbt.setVersion(3);
-    }, new RegExp('Can not modify transaction, signatures exist.'));
-    psbt.validateSignaturesOfInput(0, validator);
-    psbt.finalizeAllInputs();
-    assert.throws(() => {
-      psbt.setVersion(3);
-    }, new RegExp('Can not modify transaction, signatures exist.'));
-    assert.strictEqual(psbt.inputHasPubkey(0, alice.publicKey), true);
-    assert.strictEqual(psbt.outputHasPubkey(0, alice.publicKey), false);
-    assert.strictEqual(
-      psbt.extractTransaction().toHex(),
-      '02000000013ebc8203037dda39d482bf41ff3be955996c50d9d4f7cfc3d2097a694a7' +
-        'b067d000000006b483045022100931b6db94aed25d5486884d83fc37160f37f3368c0' +
-        'd7f48c757112abefec983802205fda64cff98c849577026eb2ce916a50ea70626a766' +
-        '9f8596dd89b720a26b4d501210365db9da3f8a260078a7e8f8b708a1161468fb2323f' +
-        'fda5ec16b261ec1056f455ffffffff0180380100000000001976a914ca0d36044e0dc' +
-        '08a22724efa6f6a07b0ec4c79aa88ac00000000',
-    );
-  });
-
-  describe('Method return types', () => {
-    it('fromBuffer returns Psbt type (not base class)', () => {
-      const psbt = Psbt.fromBuffer(
-        Buffer.from(
-          '70736274ff01000a01000000000000000000000000',
-          'hex', // cHNidP8BAAoBAAAAAAAAAAAAAAAA
-        ),
-      );
-      assert.strictEqual(psbt instanceof Psbt, true);
-      assert.ok((psbt as any).__CACHE.__TX);
-    });
-    it('fromBase64 returns Psbt type (not base class)', () => {
-      const psbt = Psbt.fromBase64('cHNidP8BAAoBAAAAAAAAAAAAAAAA');
-      assert.strictEqual(psbt instanceof Psbt, true);
-      assert.ok((psbt as any).__CACHE.__TX);
-    });
-    it('fromHex returns Psbt type (not base class)', () => {
-      const psbt = Psbt.fromHex('70736274ff01000a01000000000000000000000000');
-      assert.strictEqual(psbt instanceof Psbt, true);
-      assert.ok((psbt as any).__CACHE.__TX);
-    });
-  });
-
-  describe('Cache', () => {
-    it('non-witness UTXOs are cached', () => {
-      const f = fixtures.cache.nonWitnessUtxo;
-      const psbt = Psbt.fromBase64(f.psbt);
-      const index = f.inputIndex;
-
-      // Cache is empty
-      assert.strictEqual(
-        (psbt as any).__CACHE.__NON_WITNESS_UTXO_BUF_CACHE[index],
-        undefined,
-      );
-
-      // Cache is populated
-      psbt.updateInput(index, { nonWitnessUtxo: f.nonWitnessUtxo as any });
-      const value = psbt.data.inputs[index].nonWitnessUtxo;
-      assert.ok(
-        (psbt as any).__CACHE.__NON_WITNESS_UTXO_BUF_CACHE[index].equals(value),
-      );
-      assert.ok(
-        (psbt as any).__CACHE.__NON_WITNESS_UTXO_BUF_CACHE[index].equals(
-          f.nonWitnessUtxo,
-        ),
-      );
-
-      // Cache is rebuilt from internal transaction object when cleared
-      psbt.data.inputs[index].nonWitnessUtxo = Buffer.from([1, 2, 3]);
-      (psbt as any).__CACHE.__NON_WITNESS_UTXO_BUF_CACHE[index] = undefined;
-      assert.ok((psbt as any).data.inputs[index].nonWitnessUtxo.equals(value));
-    });
-  });
-
-  describe('Transaction properties', () => {
-    it('.version is exposed and is settable', () => {
-      const psbt = new Psbt();
-
-      assert.strictEqual(psbt.version, 2);
-      assert.strictEqual(psbt.version, (psbt as any).__CACHE.__TX.version);
-
-      psbt.version = 1;
-      assert.strictEqual(psbt.version, 1);
-      assert.strictEqual(psbt.version, (psbt as any).__CACHE.__TX.version);
-    });
-
-    it('.locktime is exposed and is settable', () => {
-      const psbt = new Psbt();
-
-      assert.strictEqual(psbt.locktime, 0);
-      assert.strictEqual(psbt.locktime, (psbt as any).__CACHE.__TX.locktime);
-
-      psbt.locktime = 123;
-      assert.strictEqual(psbt.locktime, 123);
-      assert.strictEqual(psbt.locktime, (psbt as any).__CACHE.__TX.locktime);
-    });
-
-    it('.txInputs is exposed as a readonly clone', () => {
-      const psbt = new Psbt();
-      const hash = Buffer.alloc(32);
-      const index = 0;
-      psbt.addInput({ hash, index });
-
-      const input = psbt.txInputs[0];
-      const internalInput = (psbt as any).__CACHE.__TX.ins[0];
-
-      assert.ok(input.hash.equals(internalInput.hash));
-      assert.strictEqual(input.index, internalInput.index);
-      assert.strictEqual(input.sequence, internalInput.sequence);
-
-      input.hash[0] = 123;
-      input.index = 123;
-      input.sequence = 123;
-
-      assert.ok(!input.hash.equals(internalInput.hash));
-      assert.notEqual(input.index, internalInput.index);
-      assert.notEqual(input.sequence, internalInput.sequence);
-    });
-
-    it('.txOutputs is exposed as a readonly clone', () => {
-      const psbt = new Psbt();
-      const address = '1LukeQU5jwebXbMLDVydeH4vFSobRV9rkj';
-      const value = 100000;
-      psbt.addOutput({ address, value });
-
-      const output = psbt.txOutputs[0];
-      const internalInput = (psbt as any).__CACHE.__TX.outs[0];
-
-      assert.strictEqual(output.address, address);
-
-      assert.ok(output.script.equals(internalInput.script));
-      assert.strictEqual(output.value, internalInput.value);
-
-      output.script[0] = 123;
-      output.value = 123;
-
-      assert.ok(!output.script.equals(internalInput.script));
-      assert.notEqual(output.value, internalInput.value);
-    });
-  });
-});
diff --git a/test/script.js b/test/script.js
new file mode 100644
index 0000000..07f907f
--- /dev/null
+++ b/test/script.js
@@ -0,0 +1,157 @@
+/* global describe, it */
+
+var assert = require('assert')
+var bscript = require('../src/script')
+var minimalData = require('minimaldata')
+
+var fixtures = require('./fixtures/script.json')
+var fixtures2 = require('./fixtures/templates.json')
+
+describe('script', function () {
+  // TODO
+  describe('isCanonicalPubKey', function () {
+    it('rejects if not provided a Buffer', function () {
+      assert.strictEqual(false, bscript.isCanonicalPubKey(0))
+    })
+    it('rejects smaller than 33', function () {
+      for (var i = 0; i < 33; i++) {
+        assert.strictEqual(false, bscript.isCanonicalPubKey(Buffer.from('', i)))
+      }
+    })
+  })
+  describe.skip('isCanonicalSignature', function () {})
+
+  describe('fromASM/toASM', function () {
+    fixtures.valid.forEach(function (f) {
+      it('encodes/decodes ' + f.asm, function () {
+        var script = bscript.fromASM(f.asm)
+        assert.strictEqual(bscript.toASM(script), f.asm)
+      })
+    })
+
+    fixtures.invalid.fromASM.forEach(function (f) {
+      it('throws ' + f.description, function () {
+        assert.throws(function () {
+          bscript.fromASM(f.script)
+        }, new RegExp(f.description))
+      })
+    })
+  })
+
+  describe('fromASM/toASM (templates)', function () {
+    fixtures2.valid.forEach(function (f) {
+      if (f.inputHex) {
+        var ih = bscript.toASM(Buffer.from(f.inputHex, 'hex'))
+
+        it('encodes/decodes ' + ih, function () {
+          var script = bscript.fromASM(f.input)
+          assert.strictEqual(script.toString('hex'), f.inputHex)
+          assert.strictEqual(bscript.toASM(script), f.input)
+        })
+      }
+
+      if (f.outputHex) {
+        it('encodes/decodes ' + f.output, function () {
+          var script = bscript.fromASM(f.output)
+          assert.strictEqual(script.toString('hex'), f.outputHex)
+          assert.strictEqual(bscript.toASM(script), f.output)
+        })
+      }
+    })
+  })
+
+  describe('isPushOnly', function () {
+    fixtures.valid.forEach(function (f) {
+      it('returns ' + !!f.stack + ' for ' + f.asm, function () {
+        var script = bscript.fromASM(f.asm)
+        var chunks = bscript.decompile(script)
+
+        assert.strictEqual(bscript.isPushOnly(chunks), !!f.stack)
+      })
+    })
+  })
+
+  describe('toStack', function () {
+    fixtures.valid.forEach(function (f) {
+      it('returns ' + !!f.stack + ' for ' + f.asm, function () {
+        if (!f.stack || !f.asm) return
+
+        var script = bscript.fromASM(f.asm)
+
+        var stack = bscript.toStack(script)
+        assert.deepEqual(stack.map(function (x) {
+          return x.toString('hex')
+        }), f.stack)
+
+        assert.equal(bscript.toASM(bscript.compile(stack)), f.asm, 'should rebuild same script from stack')
+      })
+    })
+  })
+
+  describe('compile (via fromASM)', function () {
+    fixtures.valid.forEach(function (f) {
+      it('(' + f.type + ') compiles ' + f.asm, function () {
+        var scriptSig = bscript.fromASM(f.asm)
+
+        assert.strictEqual(scriptSig.toString('hex'), f.script)
+
+        if (f.nonstandard) {
+          var scriptSigNS = bscript.fromASM(f.nonstandard.scriptSig)
+
+          assert.strictEqual(scriptSigNS.toString('hex'), f.script)
+        }
+      })
+    })
+  })
+
+  describe('decompile', function () {
+    fixtures.valid.forEach(function (f) {
+      it('decompiles ' + f.asm, function () {
+        var chunks = bscript.decompile(Buffer.from(f.script, 'hex'))
+
+        assert.strictEqual(bscript.compile(chunks).toString('hex'), f.script)
+        assert.strictEqual(bscript.toASM(chunks), f.asm)
+
+        if (f.nonstandard) {
+          var chunksNS = bscript.decompile(Buffer.from(f.nonstandard.scriptSigHex, 'hex'))
+
+          assert.strictEqual(bscript.compile(chunksNS).toString('hex'), f.script)
+
+          // toASM converts verbatim, only `compile` transforms the script to a minimalpush compliant script
+          assert.strictEqual(bscript.toASM(chunksNS), f.nonstandard.scriptSig)
+        }
+      })
+    })
+
+    fixtures.invalid.decompile.forEach(function (f) {
+      it('decompiles ' + f.script + ' to [] because of "' + f.description + '"', function () {
+        var chunks = bscript.decompile(Buffer.from(f.script, 'hex'))
+
+        assert.strictEqual(chunks.length, 0)
+      })
+    })
+  })
+
+  describe('SCRIPT_VERIFY_MINIMALDATA policy', function () {
+    fixtures.valid.forEach(function (f) {
+      it('compliant for ' + f.type + ' scriptSig ' + f.asm, function () {
+        var script = Buffer.from(f.script, 'hex')
+
+        assert(minimalData(script))
+      })
+    })
+
+    function testEncodingForSize (i) {
+      it('compliant for data PUSH of length ' + i, function () {
+        var buffer = Buffer.alloc(i)
+        var script = bscript.compile([buffer])
+
+        assert(minimalData(script), 'Failed for ' + i + ' length script: ' + script.toString('hex'))
+      })
+    }
+
+    for (var i = 0; i < 520; ++i) {
+      testEncodingForSize(i)
+    }
+  })
+})
diff --git a/test/script.spec.ts b/test/script.spec.ts
deleted file mode 100644
index d593ab1..0000000
--- a/test/script.spec.ts
+++ /dev/null
@@ -1,192 +0,0 @@
-import * as assert from 'assert';
-import { describe, it } from 'mocha';
-import * as bscript from '../src/script';
-import * as fixtures from './fixtures/script.json';
-const minimalData = require('minimaldata');
-
-describe('script', () => {
-  // TODO
-  describe('isCanonicalPubKey', () => {
-    it('rejects if not provided a Buffer', () => {
-      assert.strictEqual(false, bscript.isCanonicalPubKey(0 as any));
-    });
-    it('rejects smaller than 33', () => {
-      for (let i = 0; i < 33; i++) {
-        assert.strictEqual(
-          false,
-          bscript.isCanonicalPubKey(Buffer.allocUnsafe(i)),
-        );
-      }
-    });
-  });
-  describe.skip('isCanonicalScriptSignature', () => {
-    assert.ok(true);
-  });
-
-  describe('fromASM/toASM', () => {
-    fixtures.valid.forEach(f => {
-      it('encodes/decodes ' + f.asm, () => {
-        const script = bscript.fromASM(f.asm);
-        assert.strictEqual(bscript.toASM(script), f.asm);
-      });
-    });
-
-    fixtures.invalid.fromASM.forEach(f => {
-      it('throws ' + f.description, () => {
-        assert.throws(() => {
-          bscript.fromASM(f.script);
-        }, new RegExp(f.description));
-      });
-    });
-  });
-
-  describe('toASM', () => {
-    const OP_RETURN = bscript.OPS.OP_RETURN;
-    it('encodes empty buffer as OP_0', () => {
-      const chunks = [OP_RETURN, Buffer.from([])];
-      assert.strictEqual(bscript.toASM(chunks), 'OP_RETURN OP_0');
-    });
-
-    for (let i = 1; i <= 16; i++) {
-      it(`encodes one byte buffer [${i}] as OP_${i}`, () => {
-        const chunks = [OP_RETURN, Buffer.from([i])];
-        assert.strictEqual(bscript.toASM(chunks), 'OP_RETURN OP_' + i);
-      });
-    }
-  });
-
-  describe('fromASM/toASM (templates)', () => {
-    fixtures.valid2.forEach(f => {
-      if (f.inputHex) {
-        const ih = bscript.toASM(Buffer.from(f.inputHex, 'hex'));
-
-        it('encodes/decodes ' + ih, () => {
-          const script = bscript.fromASM(f.input);
-          assert.strictEqual(script.toString('hex'), f.inputHex);
-          assert.strictEqual(bscript.toASM(script), f.input);
-        });
-      }
-
-      if (f.outputHex) {
-        it('encodes/decodes ' + f.output, () => {
-          const script = bscript.fromASM(f.output);
-          assert.strictEqual(script.toString('hex'), f.outputHex);
-          assert.strictEqual(bscript.toASM(script), f.output);
-        });
-      }
-    });
-  });
-
-  describe('isPushOnly', () => {
-    fixtures.valid.forEach(f => {
-      it('returns ' + !!f.stack + ' for ' + f.asm, () => {
-        const script = bscript.fromASM(f.asm);
-        const chunks = bscript.decompile(script);
-
-        assert.strictEqual(bscript.isPushOnly(chunks!), !!f.stack);
-      });
-    });
-  });
-
-  describe('toStack', () => {
-    fixtures.valid.forEach(f => {
-      it('returns ' + !!f.stack + ' for ' + f.asm, () => {
-        if (!f.stack || !f.asm) return;
-
-        const script = bscript.fromASM(f.asm);
-
-        const stack = bscript.toStack(script);
-        assert.deepStrictEqual(
-          stack.map(x => {
-            return x.toString('hex');
-          }),
-          f.stack,
-        );
-
-        assert.strictEqual(
-          bscript.toASM(bscript.compile(stack)),
-          f.asm,
-          'should rebuild same script from stack',
-        );
-      });
-    });
-  });
-
-  describe('compile (via fromASM)', () => {
-    fixtures.valid.forEach(f => {
-      it('compiles ' + f.asm, () => {
-        const scriptSig = bscript.fromASM(f.asm);
-
-        assert.strictEqual(scriptSig.toString('hex'), f.script);
-
-        if (f.nonstandard) {
-          const scriptSigNS = bscript.fromASM(f.nonstandard.scriptSig);
-
-          assert.strictEqual(scriptSigNS.toString('hex'), f.script);
-        }
-      });
-    });
-  });
-
-  describe('decompile', () => {
-    fixtures.valid.forEach(f => {
-      it('decompiles ' + f.asm, () => {
-        const chunks = bscript.decompile(Buffer.from(f.script, 'hex'));
-
-        assert.strictEqual(bscript.compile(chunks!).toString('hex'), f.script);
-        assert.strictEqual(bscript.toASM(chunks!), f.asm);
-
-        if (f.nonstandard) {
-          const chunksNS = bscript.decompile(
-            Buffer.from(f.nonstandard.scriptSigHex, 'hex'),
-          );
-
-          assert.strictEqual(
-            bscript.compile(chunksNS!).toString('hex'),
-            f.script,
-          );
-
-          // toASM converts verbatim, only `compile` transforms the script to a minimalpush compliant script
-          assert.strictEqual(bscript.toASM(chunksNS!), f.nonstandard.scriptSig);
-        }
-      });
-    });
-
-    fixtures.invalid.decompile.forEach(f => {
-      it(
-        'fails to decompile ' + f.script + ',  because "' + f.description + '"',
-        () => {
-          const chunks = bscript.decompile(Buffer.from(f.script, 'hex'));
-
-          assert.strictEqual(chunks, null);
-        },
-      );
-    });
-  });
-
-  describe('SCRIPT_VERIFY_MINIMALDATA policy', () => {
-    fixtures.valid.forEach(f => {
-      it('compliant for scriptSig ' + f.asm, () => {
-        const script = Buffer.from(f.script, 'hex');
-
-        assert(minimalData(script));
-      });
-    });
-
-    function testEncodingForSize(num: number): void {
-      it('compliant for data PUSH of length ' + num, () => {
-        const buffer = Buffer.alloc(num);
-        const script = bscript.compile([buffer]);
-
-        assert(
-          minimalData(script),
-          'Failed for ' + num + ' length script: ' + script.toString('hex'),
-        );
-      });
-    }
-
-    for (let i = 0; i < 520; ++i) {
-      testEncodingForSize(i);
-    }
-  });
-});
diff --git a/test/script_number.js b/test/script_number.js
new file mode 100644
index 0000000..2aa33a7
--- /dev/null
+++ b/test/script_number.js
@@ -0,0 +1,27 @@
+/* global describe, it */
+
+var assert = require('assert')
+var scriptNumber = require('../src/script_number')
+var fixtures = require('./fixtures/script_number.json')
+
+describe('script-number', function () {
+  describe('decode', function () {
+    fixtures.forEach(function (f) {
+      it(f.hex + ' returns ' + f.number, function () {
+        var actual = scriptNumber.decode(Buffer.from(f.hex, 'hex'), f.bytes)
+
+        assert.strictEqual(actual, f.number)
+      })
+    })
+  })
+
+  describe('encode', function () {
+    fixtures.forEach(function (f) {
+      it(f.number + ' returns ' + f.hex, function () {
+        var actual = scriptNumber.encode(f.number)
+
+        assert.strictEqual(actual.toString('hex'), f.hex)
+      })
+    })
+  })
+})
diff --git a/test/script_number.spec.ts b/test/script_number.spec.ts
deleted file mode 100644
index 3b05082..0000000
--- a/test/script_number.spec.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import * as assert from 'assert';
-import { describe, it } from 'mocha';
-import * as scriptNumber from '../src/script_number';
-import * as fixtures from './fixtures/script_number.json';
-
-describe('script-number', () => {
-  describe('decode', () => {
-    fixtures.forEach(f => {
-      it(f.hex + ' returns ' + f.number, () => {
-        const actual = scriptNumber.decode(Buffer.from(f.hex, 'hex'), f.bytes);
-
-        assert.strictEqual(actual, f.number);
-      });
-    });
-  });
-
-  describe('encode', () => {
-    fixtures.forEach(f => {
-      it(f.number + ' returns ' + f.hex, () => {
-        const actual = scriptNumber.encode(f.number);
-
-        assert.strictEqual(actual.toString('hex'), f.hex);
-      });
-    });
-  });
-});
diff --git a/test/script_signature.spec.ts b/test/script_signature.spec.ts
deleted file mode 100644
index 54c416e..0000000
--- a/test/script_signature.spec.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import * as assert from 'assert';
-import { describe, it } from 'mocha';
-import { signature as bscriptSig } from '../src/script';
-import * as fixtures from './fixtures/signature.json';
-
-describe('Script Signatures', () => {
-  function fromRaw(signature: { r: string; s: string }): Buffer {
-    return Buffer.concat(
-      [Buffer.from(signature.r, 'hex'), Buffer.from(signature.s, 'hex')],
-      64,
-    );
-  }
-
-  function toRaw(
-    signature: Buffer,
-  ): {
-    r: string;
-    s: string;
-  } {
-    return {
-      r: signature.slice(0, 32).toString('hex'),
-      s: signature.slice(32, 64).toString('hex'),
-    };
-  }
-
-  describe('encode', () => {
-    fixtures.valid.forEach(f => {
-      it('encodes ' + f.hex, () => {
-        const buffer = bscriptSig.encode(fromRaw(f.raw), f.hashType);
-
-        assert.strictEqual(buffer.toString('hex'), f.hex);
-      });
-    });
-
-    fixtures.invalid.forEach(f => {
-      if (!f.raw) return;
-
-      it('throws ' + f.exception, () => {
-        const signature = fromRaw(f.raw);
-
-        assert.throws(() => {
-          bscriptSig.encode(signature, f.hashType);
-        }, new RegExp(f.exception));
-      });
-    });
-  });
-
-  describe('decode', () => {
-    fixtures.valid.forEach(f => {
-      it('decodes ' + f.hex, () => {
-        const decode = bscriptSig.decode(Buffer.from(f.hex, 'hex'));
-
-        assert.deepStrictEqual(toRaw(decode.signature), f.raw);
-        assert.strictEqual(decode.hashType, f.hashType);
-      });
-    });
-
-    fixtures.invalid.forEach(f => {
-      it('throws on ' + f.hex, () => {
-        const buffer = Buffer.from(f.hex, 'hex');
-
-        assert.throws(() => {
-          bscriptSig.decode(buffer);
-        }, new RegExp(f.exception));
-      });
-    });
-  });
-});
diff --git a/test/templates.js b/test/templates.js
new file mode 100644
index 0000000..104b326
--- /dev/null
+++ b/test/templates.js
@@ -0,0 +1,514 @@
+/* global describe, it */
+
+var assert = require('assert')
+var bcrypto = require('../src/crypto')
+var bscript = require('../src/script')
+var btemplates = require('../src/templates')
+var ops = require('bitcoin-ops')
+
+var fixtures = require('./fixtures/templates.json')
+
+function fromHex (x) { return Buffer.from(x, 'hex') }
+function toHex (x) { return x.toString('hex') }
+
+describe('script-templates', function () {
+  describe('classifyInput', function () {
+    fixtures.valid.forEach(function (f) {
+      if (!f.input) return
+
+      it('classifies ' + f.input + ' as ' + f.type, function () {
+        var input = bscript.fromASM(f.input)
+        var type = btemplates.classifyInput(input)
+
+        assert.strictEqual(type, f.type)
+      })
+    })
+
+    fixtures.valid.forEach(function (f) {
+      if (!f.input) return
+      if (!f.typeIncomplete) return
+
+      it('classifies incomplete ' + f.input + ' as ' + f.typeIncomplete, function () {
+        var input = bscript.fromASM(f.input)
+        var type = btemplates.classifyInput(input, true)
+
+        assert.strictEqual(type, f.typeIncomplete)
+      })
+    })
+  })
+
+  describe('classifyOutput', function () {
+    fixtures.valid.forEach(function (f) {
+      if (!f.output) return
+
+      it('classifies ' + f.output + ' as ' + f.type, function () {
+        var output = bscript.fromASM(f.output)
+        var type = btemplates.classifyOutput(output)
+
+        assert.strictEqual(type, f.type)
+      })
+    })
+  })
+
+  ;[
+    'pubKey',
+    'pubKeyHash',
+    'scriptHash',
+    'witnessPubKeyHash',
+    'witnessScriptHash',
+    'multisig',
+    'nullData',
+    'witnessCommitment'
+  ].forEach(function (name) {
+    var inputType = btemplates[name].input
+    var outputType = btemplates[name].output
+
+    describe(name + '.input.check', function () {
+      fixtures.valid.forEach(function (f) {
+        if (name.toLowerCase() === btemplates.types.P2WPKH) return
+        if (name.toLowerCase() === btemplates.types.P2WSH) return
+        var expected = name.toLowerCase() === f.type.toLowerCase()
+
+        if (inputType && f.input) {
+          var input = bscript.fromASM(f.input)
+
+          it('returns ' + expected + ' for ' + f.input, function () {
+            assert.strictEqual(inputType.check(input), expected)
+          })
+
+          if (f.typeIncomplete) {
+            var expectedIncomplete = name.toLowerCase() === f.typeIncomplete
+
+            it('returns ' + expected + ' for ' + f.input, function () {
+              assert.strictEqual(inputType.check(input, true), expectedIncomplete)
+            })
+          }
+        }
+      })
+
+      if (!(fixtures.invalid[name])) return
+
+      fixtures.invalid[name].inputs.forEach(function (f) {
+        if (!f.input && !f.inputHex) return
+
+        it('returns false for ' + f.description + ' (' + (f.input || f.inputHex) + ')', function () {
+          var input
+
+          if (f.input) {
+            input = bscript.fromASM(f.input)
+          } else {
+            input = Buffer.from(f.inputHex, 'hex')
+          }
+
+          assert.strictEqual(inputType.check(input), false)
+        })
+      })
+    })
+
+    describe(name + '.output.check', function () {
+      fixtures.valid.forEach(function (f) {
+        var expected = name.toLowerCase() === f.type
+
+        if (outputType && f.output) {
+          it('returns ' + expected + ' for ' + f.output, function () {
+            var output = bscript.fromASM(f.output)
+
+            if (name.toLowerCase() === 'nulldata' && f.type === btemplates.types.WITNESS_COMMITMENT) return
+            if (name.toLowerCase() === 'witnesscommitment' && f.type === btemplates.types.NULLDATA) return
+            assert.strictEqual(outputType.check(output), expected)
+          })
+        }
+      })
+
+      if (!(fixtures.invalid[name])) return
+
+      fixtures.invalid[name].outputs.forEach(function (f) {
+        if (!f.output && !f.outputHex) return
+
+        it('returns false for ' + f.description + ' (' + (f.output || f.outputHex) + ')', function () {
+          var output
+
+          if (f.output) {
+            output = bscript.fromASM(f.output)
+          } else {
+            output = Buffer.from(f.outputHex, 'hex')
+          }
+
+          assert.strictEqual(outputType.check(output), false)
+        })
+      })
+    })
+  })
+
+  describe('pubKey.input', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'pubkey') return
+
+      var signature = Buffer.from(f.signature, 'hex')
+      var input = btemplates.pubKey.input.encode(signature)
+
+      it('encodes to ' + f.input, function () {
+        assert.strictEqual(bscript.toASM(input), f.input)
+      })
+
+      it('decodes to ' + f.signature, function () {
+        assert.deepEqual(btemplates.pubKey.input.decode(input), signature)
+      })
+    })
+  })
+
+  describe('pubKey.output', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'pubkey') return
+
+      var pubKey = Buffer.from(f.pubKey, 'hex')
+      var output = btemplates.pubKey.output.encode(pubKey)
+
+      it('encodes to ' + f.output, function () {
+        assert.strictEqual(bscript.toASM(output), f.output)
+      })
+
+      it('decodes to ' + f.pubKey, function () {
+        assert.deepEqual(btemplates.pubKey.output.decode(output), pubKey)
+      })
+    })
+  })
+
+  describe('pubKeyHash.input', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'pubkeyhash') return
+
+      var pubKey = Buffer.from(f.pubKey, 'hex')
+      var signature = Buffer.from(f.signature, 'hex')
+      var input = btemplates.pubKeyHash.input.encode(signature, pubKey)
+
+      it('encodes to ' + f.input, function () {
+        assert.strictEqual(bscript.toASM(input), f.input)
+      })
+
+      it('decodes to original arguments', function () {
+        assert.deepEqual(btemplates.pubKeyHash.input.decode(input), {
+          signature: signature,
+          pubKey: pubKey
+        })
+      })
+    })
+  })
+
+  describe('pubKeyHash.output', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'pubkeyhash') return
+
+      var pubKey = Buffer.from(f.pubKey, 'hex')
+      var pubKeyHash = bcrypto.hash160(pubKey)
+      var output = btemplates.pubKeyHash.output.encode(pubKeyHash)
+
+      it('encodes to ' + f.output, function () {
+        assert.strictEqual(bscript.toASM(output), f.output)
+      })
+
+      it('decodes to ' + pubKeyHash.toString('hex'), function () {
+        assert.deepEqual(btemplates.pubKeyHash.output.decode(output), pubKeyHash)
+      })
+    })
+
+    fixtures.invalid.pubKeyHash.outputs.forEach(function (f) {
+      if (!f.hash) return
+      var hash = Buffer.from(f.hash, 'hex')
+
+      it('throws on ' + f.exception, function () {
+        assert.throws(function () {
+          btemplates.pubKeyHash.output.encode(hash)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('multisig.input', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'multisig' && f.typeIncomplete !== 'multisig') return
+      var allowIncomplete = f.typeIncomplete !== undefined
+
+      var signatures = f.signatures.map(function (signature) {
+        return signature ? Buffer.from(signature, 'hex') : ops.OP_0
+      })
+
+      var input = btemplates.multisig.input.encode(signatures)
+
+      it('encodes to ' + f.input, function () {
+        assert.strictEqual(bscript.toASM(input), f.input)
+      })
+
+      it('decodes to ' + signatures.map(function (x) { return x === ops.OP_0 ? 'OP_0' : x.toString('hex') }), function () {
+        assert.deepEqual(btemplates.multisig.input.decode(input, allowIncomplete), signatures)
+      })
+    })
+
+    fixtures.invalid.multisig.inputs.forEach(function (f) {
+      if (!f.output) return
+      var output = bscript.fromASM(f.output)
+
+      it('throws on ' + f.exception, function () {
+        var signatures = f.signatures.map(function (signature) {
+          return signature ? Buffer.from(signature, 'hex') : ops.OP_0
+        })
+
+        assert.throws(function () {
+          btemplates.multisig.input.encode(signatures, output)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('multisig.output', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'multisig') return
+
+      var pubKeys = f.pubKeys.map(function (p) { return Buffer.from(p, 'hex') })
+      var m = pubKeys.length
+
+      var output = btemplates.multisig.output.encode(m, pubKeys)
+
+      it('encodes ' + f.output, function () {
+        assert.strictEqual(bscript.toASM(output), f.output)
+      })
+
+      it('decodes to original arguments', function () {
+        assert.deepEqual(btemplates.multisig.output.decode(output), {
+          m: m,
+          pubKeys: pubKeys
+        })
+      })
+    })
+
+    fixtures.invalid.multisig.outputs.forEach(function (f) {
+      if (!f.pubKeys) return
+      var pubKeys = f.pubKeys.map(function (p) {
+        return Buffer.from(p, 'hex')
+      })
+
+      it('throws on ' + f.exception, function () {
+        assert.throws(function () {
+          btemplates.multisig.output.encode(f.m, pubKeys)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('scriptHash.input', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'scripthash') return
+
+      var redeemScriptSig = bscript.fromASM(f.redeemScriptSig)
+      var redeemScript = bscript.fromASM(f.redeemScript)
+      var input = btemplates.scriptHash.input.encode(redeemScriptSig, redeemScript)
+
+      it('encodes to ' + f.output, function () {
+        if (f.input) {
+          assert.strictEqual(bscript.toASM(input), f.input)
+        } else {
+          assert.strictEqual(input.toString('hex'), f.inputHex)
+        }
+      })
+
+      it('decodes to original arguments', function () {
+        assert.deepEqual(btemplates.scriptHash.input.decode(input), {
+          redeemScriptSig: redeemScriptSig,
+          redeemScript: redeemScript
+        })
+      })
+    })
+  })
+
+  describe('scriptHash.output', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'scripthash') return
+      if (!f.output) return
+
+      var redeemScript = bscript.fromASM(f.redeemScript)
+      var scriptHash = bcrypto.hash160(redeemScript)
+      var output = btemplates.scriptHash.output.encode(scriptHash)
+
+      it('encodes to ' + f.output, function () {
+        assert.strictEqual(bscript.toASM(output), f.output)
+      })
+
+      it('decodes to ' + scriptHash.toString('hex'), function () {
+        assert.deepEqual(btemplates.scriptHash.output.decode(output), scriptHash)
+      })
+    })
+
+    fixtures.invalid.scriptHash.outputs.forEach(function (f) {
+      if (!f.hash) return
+      var hash = Buffer.from(f.hash, 'hex')
+
+      it('throws on ' + f.exception, function () {
+        assert.throws(function () {
+          btemplates.scriptHash.output.encode(hash)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('witnessPubKeyHash.input', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'pubkeyhash' && f.type !== 'witnesspubkeyhash') return
+      if (!f.inputStack) return
+
+      var pubKey = Buffer.from(f.pubKey, 'hex')
+      var signature = Buffer.from(f.signature, 'hex')
+
+      it('encodes to ' + f.input, function () {
+        var inputStack = btemplates.witnessPubKeyHash.input.encodeStack(signature, pubKey)
+
+        assert.deepEqual(inputStack.map(toHex), f.inputStack)
+      })
+
+      it('decodes to original arguments', function () {
+        var fInputStack = f.inputStack.map(fromHex)
+
+        assert.deepEqual(btemplates.witnessPubKeyHash.input.decodeStack(fInputStack), {
+          signature: signature,
+          pubKey: pubKey
+        })
+      })
+    })
+  })
+
+  describe('witnessPubKeyHash.output', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'witnesspubkeyhash') return
+      if (!f.output) return
+
+      var pubKey = Buffer.from(f.pubKey, 'hex')
+      var pubKeyHash = bcrypto.hash160(pubKey)
+      var output = btemplates.witnessPubKeyHash.output.encode(pubKeyHash)
+
+      it('encodes to ' + f.output, function () {
+        assert.strictEqual(bscript.toASM(output), f.output)
+      })
+
+      it('decodes to ' + pubKeyHash.toString('hex'), function () {
+        assert.deepEqual(btemplates.witnessPubKeyHash.output.decode(output), pubKeyHash)
+      })
+    })
+
+    fixtures.invalid.witnessPubKeyHash.outputs.forEach(function (f) {
+      if (!f.hash) return
+      var hash = Buffer.from(f.hash, 'hex')
+
+      it('throws on ' + f.exception, function () {
+        assert.throws(function () {
+          btemplates.witnessPubKeyHash.output.encode(hash)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('witnessScriptHash.input', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'witnessscripthash') return
+      if (!f.inputStack || !f.witnessData) return
+
+      var witnessData = f.witnessData.map(fromHex)
+      var witnessScript = bscript.fromASM(f.witnessScript || f.redeemScript)
+
+      it('encodes to ' + f.input, function () {
+        var inputStack = btemplates.witnessScriptHash.input.encodeStack(witnessData, witnessScript)
+
+        assert.deepEqual(inputStack.map(toHex), f.inputStack)
+      })
+
+      it('decodes to original arguments', function () {
+        var result = btemplates.witnessScriptHash.input.decodeStack(f.inputStack.map(fromHex))
+
+        assert.deepEqual(result.witnessData.map(toHex), f.witnessData)
+        assert.strictEqual(bscript.toASM(result.witnessScript), f.witnessScript)
+      })
+    })
+  })
+
+  describe('witnessScriptHash.output', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'witnessscripthash') return
+      if (!f.output) return
+
+      var witnessScriptPubKey = bscript.fromASM(f.witnessScript)
+      var scriptHash = bcrypto.hash256(witnessScriptPubKey)
+      var output = btemplates.witnessScriptHash.output.encode(scriptHash)
+
+      it('encodes to ' + f.output, function () {
+        assert.strictEqual(bscript.toASM(output), f.output)
+      })
+
+      it('decodes to ' + scriptHash.toString('hex'), function () {
+        assert.deepEqual(btemplates.witnessScriptHash.output.decode(output), scriptHash)
+      })
+    })
+
+    fixtures.invalid.witnessScriptHash.outputs.forEach(function (f) {
+      if (!f.hash) return
+      var hash = Buffer.from(f.hash, 'hex')
+
+      it('throws on ' + f.exception, function () {
+        assert.throws(function () {
+          btemplates.witnessScriptHash.output.encode(hash)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('witnessCommitment.output', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'witnesscommitment') return
+      if (!f.scriptPubKey) return
+
+      var commitment = Buffer.from(f.witnessCommitment, 'hex')
+      var scriptPubKey = btemplates.witnessCommitment.output.encode(commitment)
+
+      it('encodes to ' + f.scriptPubKey, function () {
+        assert.strictEqual(bscript.toASM(scriptPubKey), f.scriptPubKey)
+      })
+
+      it('decodes to ' + commitment.toString('hex'), function () {
+        assert.deepEqual(btemplates.witnessCommitment.output.decode(scriptPubKey), commitment)
+      })
+    })
+
+    fixtures.invalid.witnessCommitment.outputs.forEach(function (f) {
+      if (f.commitment) {
+        var hash = Buffer.from(f.commitment, 'hex')
+        it('throws on bad encode data', function () {
+          assert.throws(function () {
+            btemplates.witnessCommitment.output.encode(hash)
+          }, new RegExp(f.exception))
+        })
+      }
+
+      if (f.scriptPubKeyHex) {
+        it('.decode throws on ' + f.description, function () {
+          assert.throws(function () {
+            btemplates.witnessCommitment.output.decode(Buffer.from(f.scriptPubKeyHex, 'hex'))
+          }, new RegExp(f.exception))
+        })
+      }
+    })
+  })
+
+  describe('nullData.output', function () {
+    fixtures.valid.forEach(function (f) {
+      if (f.type !== 'nulldata') return
+
+      var data = Buffer.from(f.data, 'hex')
+      var output = btemplates.nullData.output.encode(data)
+
+      it('encodes to ' + f.output, function () {
+        assert.strictEqual(bscript.toASM(output), f.output)
+      })
+
+      it('decodes to ' + f.data, function () {
+        assert.deepEqual(btemplates.nullData.output.decode(output), data)
+      })
+    })
+  })
+})
diff --git a/test/transaction.js b/test/transaction.js
new file mode 100644
index 0000000..62c24d0
--- /dev/null
+++ b/test/transaction.js
@@ -0,0 +1,288 @@
+/* global describe, it, beforeEach */
+
+var assert = require('assert')
+var bscript = require('../src/script')
+var fixtures = require('./fixtures/transaction')
+var Transaction = require('../src/transaction')
+
+describe('Transaction', function () {
+  function fromRaw (raw, noWitness) {
+    var tx = new Transaction()
+    tx.version = raw.version
+    tx.locktime = raw.locktime
+
+    raw.ins.forEach(function (txIn, i) {
+      var txHash = Buffer.from(txIn.hash, 'hex')
+      var scriptSig
+
+      if (txIn.data) {
+        scriptSig = Buffer.from(txIn.data, 'hex')
+      } else if (txIn.script) {
+        scriptSig = bscript.fromASM(txIn.script)
+      }
+
+      tx.addInput(txHash, txIn.index, txIn.sequence, scriptSig)
+
+      if (!noWitness && txIn.witness) {
+        var witness = txIn.witness.map(function (x) {
+          return Buffer.from(x, 'hex')
+        })
+
+        tx.setWitness(i, witness)
+      }
+    })
+
+    raw.outs.forEach(function (txOut) {
+      var script
+
+      if (txOut.data) {
+        script = Buffer.from(txOut.data, 'hex')
+      } else if (txOut.script) {
+        script = bscript.fromASM(txOut.script)
+      }
+
+      tx.addOutput(script, txOut.value)
+    })
+
+    return tx
+  }
+
+  describe('fromBuffer/fromHex', function () {
+    function importExport (f) {
+      var id = f.id || f.hash
+      var txHex = f.hex || f.txHex
+
+      it('imports ' + f.description + ' (' + id + ')', function () {
+        var actual = Transaction.fromHex(txHex)
+
+        assert.strictEqual(actual.toHex(), txHex)
+      })
+
+      if (f.whex) {
+        it('imports ' + f.description + ' (' + id + ') as witness', function () {
+          var actual = Transaction.fromHex(f.whex)
+
+          assert.strictEqual(actual.toHex(), f.whex)
+        })
+      }
+    }
+
+    fixtures.valid.forEach(importExport)
+    fixtures.hashForSignature.forEach(importExport)
+    fixtures.hashForWitnessV0.forEach(importExport)
+
+    fixtures.invalid.fromBuffer.forEach(function (f) {
+      it('throws on ' + f.exception, function () {
+        assert.throws(function () {
+          Transaction.fromHex(f.hex)
+        }, new RegExp(f.exception))
+      })
+    })
+
+    it('.version should be interpreted as an int32le', function () {
+      var txHex = 'ffffffff0000ffffffff'
+      var tx = Transaction.fromHex(txHex)
+      assert.equal(-1, tx.version)
+      assert.equal(0xffffffff, tx.locktime)
+    })
+  })
+
+  describe('toBuffer/toHex', function () {
+    fixtures.valid.forEach(function (f) {
+      it('exports ' + f.description + ' (' + f.id + ')', function () {
+        var actual = fromRaw(f.raw, true)
+        assert.strictEqual(actual.toHex(), f.hex)
+      })
+
+      if (f.whex) {
+        it('exports ' + f.description + ' (' + f.id + ') as witness', function () {
+          var wactual = fromRaw(f.raw)
+          assert.strictEqual(wactual.toHex(), f.whex)
+        })
+      }
+    })
+
+    it('accepts target Buffer and offset parameters', function () {
+      var f = fixtures.valid[0]
+      var actual = fromRaw(f.raw)
+      var byteLength = actual.byteLength()
+
+      var target = Buffer.alloc(byteLength * 2)
+      var a = actual.toBuffer(target, 0)
+      var b = actual.toBuffer(target, byteLength)
+
+      assert.strictEqual(a.length, byteLength)
+      assert.strictEqual(b.length, byteLength)
+      assert.strictEqual(a.toString('hex'), f.hex)
+      assert.strictEqual(b.toString('hex'), f.hex)
+      assert.deepEqual(a, b)
+      assert.deepEqual(a, target.slice(0, byteLength))
+      assert.deepEqual(b, target.slice(byteLength))
+    })
+  })
+
+  describe('hasWitnesses', function () {
+    fixtures.valid.forEach(function (f) {
+      it('detects if the transaction has witnesses: ' + (f.whex ? 'true' : 'false'), function () {
+        assert.strictEqual(Transaction.fromHex(f.whex ? f.whex : f.hex).hasWitnesses(), !!f.whex)
+      })
+    })
+  })
+
+  describe('weight/virtualSize', function () {
+    it('computes virtual size', function () {
+      fixtures.valid.forEach(function (f) {
+        var transaction = Transaction.fromHex(f.whex ? f.whex : f.hex)
+
+        assert.strictEqual(transaction.virtualSize(), f.virtualSize)
+      })
+    })
+
+    it('computes weight', function () {
+      fixtures.valid.forEach(function (f) {
+        var transaction = Transaction.fromHex(f.whex ? f.whex : f.hex)
+
+        assert.strictEqual(transaction.weight(), f.weight)
+      })
+    })
+  })
+
+  describe('addInput', function () {
+    var prevTxHash
+    beforeEach(function () {
+      prevTxHash = Buffer.from('ffffffff00ffff000000000000000000000000000000000000000000101010ff', 'hex')
+    })
+
+    it('returns an index', function () {
+      var tx = new Transaction()
+      assert.strictEqual(tx.addInput(prevTxHash, 0), 0)
+      assert.strictEqual(tx.addInput(prevTxHash, 0), 1)
+    })
+
+    it('defaults to empty script, witness and 0xffffffff SEQUENCE number', function () {
+      var tx = new Transaction()
+      tx.addInput(prevTxHash, 0)
+
+      assert.strictEqual(tx.ins[0].script.length, 0)
+      assert.strictEqual(tx.ins[0].witness.length, 0)
+      assert.strictEqual(tx.ins[0].sequence, 0xffffffff)
+    })
+
+    fixtures.invalid.addInput.forEach(function (f) {
+      it('throws on ' + f.exception, function () {
+        var tx = new Transaction()
+        var hash = Buffer.from(f.hash, 'hex')
+
+        assert.throws(function () {
+          tx.addInput(hash, f.index)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('addOutput', function () {
+    it('returns an index', function () {
+      var tx = new Transaction()
+      assert.strictEqual(tx.addOutput(Buffer.alloc(0), 0), 0)
+      assert.strictEqual(tx.addOutput(Buffer.alloc(0), 0), 1)
+    })
+  })
+
+  describe('clone', function () {
+    fixtures.valid.forEach(function (f) {
+      var actual, expected
+
+      beforeEach(function () {
+        expected = Transaction.fromHex(f.hex)
+        actual = expected.clone()
+      })
+
+      it('should have value equality', function () {
+        assert.deepEqual(actual, expected)
+      })
+
+      it('should not have reference equality', function () {
+        assert.notEqual(actual, expected)
+      })
+    })
+  })
+
+  describe('getHash/getId', function () {
+    function verify (f) {
+      it('should return the id for ' + f.id + '(' + f.description + ')', function () {
+        var tx = Transaction.fromHex(f.whex || f.hex)
+
+        assert.strictEqual(tx.getHash().toString('hex'), f.hash)
+        assert.strictEqual(tx.getId(), f.id)
+      })
+    }
+
+    fixtures.valid.forEach(verify)
+  })
+
+  describe('isCoinbase', function () {
+    function verify (f) {
+      it('should return ' + f.coinbase + ' for ' + f.id + '(' + f.description + ')', function () {
+        var tx = Transaction.fromHex(f.hex)
+
+        assert.strictEqual(tx.isCoinbase(), f.coinbase)
+      })
+    }
+
+    fixtures.valid.forEach(verify)
+  })
+
+  describe('hashForSignature', function () {
+    it('does not use Witness serialization', function () {
+      var randScript = Buffer.from('6a', 'hex')
+
+      var tx = new Transaction()
+      tx.addInput(Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), 0)
+      tx.addOutput(randScript, 5000000000)
+
+      var original = tx.__toBuffer
+      tx.__toBuffer = function (a, b, c) {
+        if (c !== false) throw new Error('hashForSignature MUST pass false')
+
+        return original.call(this, a, b, c)
+      }
+
+      assert.throws(function () {
+        tx.__toBuffer(undefined, undefined, true)
+      }, /hashForSignature MUST pass false/)
+
+      // assert hashForSignature does not pass false
+      assert.doesNotThrow(function () {
+        tx.hashForSignature(0, randScript, 1)
+      })
+    })
+
+    fixtures.hashForSignature.forEach(function (f) {
+      it('should return ' + f.hash + ' for ' + (f.description ? ('case "' + f.description + '"') : f.script), function () {
+        var tx = Transaction.fromHex(f.txHex)
+        var script = bscript.fromASM(f.script)
+
+        assert.strictEqual(tx.hashForSignature(f.inIndex, script, f.type).toString('hex'), f.hash)
+      })
+    })
+  })
+
+  describe('hashForWitnessV0', function () {
+    fixtures.hashForWitnessV0.forEach(function (f) {
+      it('should return ' + f.hash + ' for ' + (f.description ? ('case "' + f.description + '"') : ''), function () {
+        var tx = Transaction.fromHex(f.txHex)
+        var script = bscript.fromASM(f.script)
+
+        assert.strictEqual(tx.hashForWitnessV0(f.inIndex, script, f.value, f.type).toString('hex'), f.hash)
+      })
+    })
+  })
+
+  describe('setWitness', function () {
+    it('only accepts a a witness stack (Array of Buffers)', function () {
+      assert.throws(function () {
+        (new Transaction()).setWitness(0, 'foobar')
+      }, /Expected property "1" of type \[Buffer], got String "foobar"/)
+    })
+  })
+})
diff --git a/test/transaction.spec.ts b/test/transaction.spec.ts
deleted file mode 100644
index 13d64d1..0000000
--- a/test/transaction.spec.ts
+++ /dev/null
@@ -1,359 +0,0 @@
-import * as assert from 'assert';
-import { beforeEach, describe, it } from 'mocha';
-import { Transaction } from '..';
-import * as bscript from '../src/script';
-import * as fixtures from './fixtures/transaction.json';
-
-describe('Transaction', () => {
-  function fromRaw(raw: any, noWitness?: boolean): Transaction {
-    const tx = new Transaction();
-    tx.version = raw.version;
-    tx.locktime = raw.locktime;
-
-    raw.ins.forEach((txIn: any, i: number) => {
-      const txHash = Buffer.from(txIn.hash, 'hex');
-      let scriptSig;
-
-      if (txIn.data) {
-        scriptSig = Buffer.from(txIn.data, 'hex');
-      } else if (txIn.script) {
-        scriptSig = bscript.fromASM(txIn.script);
-      }
-
-      tx.addInput(txHash, txIn.index, txIn.sequence, scriptSig);
-
-      if (!noWitness && txIn.witness) {
-        const witness = txIn.witness.map((x: string) => {
-          return Buffer.from(x, 'hex');
-        });
-
-        tx.setWitness(i, witness);
-      }
-    });
-
-    raw.outs.forEach((txOut: any) => {
-      let script: Buffer;
-
-      if (txOut.data) {
-        script = Buffer.from(txOut.data, 'hex');
-      } else if (txOut.script) {
-        script = bscript.fromASM(txOut.script);
-      }
-
-      tx.addOutput(script!, txOut.value);
-    });
-
-    return tx;
-  }
-
-  describe('fromBuffer/fromHex', () => {
-    function importExport(f: any): void {
-      const id = f.id || f.hash;
-      const txHex = f.hex || f.txHex;
-
-      it('imports ' + f.description + ' (' + id + ')', () => {
-        const actual = Transaction.fromHex(txHex);
-
-        assert.strictEqual(actual.toHex(), txHex);
-      });
-
-      if (f.whex) {
-        it('imports ' + f.description + ' (' + id + ') as witness', () => {
-          const actual = Transaction.fromHex(f.whex);
-
-          assert.strictEqual(actual.toHex(), f.whex);
-        });
-      }
-    }
-
-    fixtures.valid.forEach(importExport);
-    fixtures.hashForSignature.forEach(importExport);
-    fixtures.hashForWitnessV0.forEach(importExport);
-
-    fixtures.invalid.fromBuffer.forEach(f => {
-      it('throws on ' + f.exception, () => {
-        assert.throws(() => {
-          Transaction.fromHex(f.hex);
-        }, new RegExp(f.exception));
-      });
-    });
-
-    it('.version should be interpreted as an int32le', () => {
-      const txHex = 'ffffffff0000ffffffff';
-      const tx = Transaction.fromHex(txHex);
-      assert.strictEqual(-1, tx.version);
-      assert.strictEqual(0xffffffff, tx.locktime);
-    });
-  });
-
-  describe('toBuffer/toHex', () => {
-    fixtures.valid.forEach(f => {
-      it('exports ' + f.description + ' (' + f.id + ')', () => {
-        const actual = fromRaw(f.raw, true);
-        assert.strictEqual(actual.toHex(), f.hex);
-      });
-
-      if (f.whex) {
-        it('exports ' + f.description + ' (' + f.id + ') as witness', () => {
-          const wactual = fromRaw(f.raw);
-          assert.strictEqual(wactual.toHex(), f.whex);
-        });
-      }
-    });
-
-    it('accepts target Buffer and offset parameters', () => {
-      const f = fixtures.valid[0];
-      const actual = fromRaw(f.raw);
-      const byteLength = actual.byteLength();
-
-      const target = Buffer.alloc(byteLength * 2);
-      const a = actual.toBuffer(target, 0);
-      const b = actual.toBuffer(target, byteLength);
-
-      assert.strictEqual(a.length, byteLength);
-      assert.strictEqual(b.length, byteLength);
-      assert.strictEqual(a.toString('hex'), f.hex);
-      assert.strictEqual(b.toString('hex'), f.hex);
-      assert.deepStrictEqual(a, b);
-      assert.deepStrictEqual(a, target.slice(0, byteLength));
-      assert.deepStrictEqual(b, target.slice(byteLength));
-    });
-  });
-
-  describe('hasWitnesses', () => {
-    fixtures.valid.forEach(f => {
-      it(
-        'detects if the transaction has witnesses: ' +
-          (f.whex ? 'true' : 'false'),
-        () => {
-          assert.strictEqual(
-            Transaction.fromHex(f.whex ? f.whex : f.hex).hasWitnesses(),
-            !!f.whex,
-          );
-        },
-      );
-    });
-  });
-
-  describe('weight/virtualSize', () => {
-    it('computes virtual size', () => {
-      fixtures.valid.forEach(f => {
-        const transaction = Transaction.fromHex(f.whex ? f.whex : f.hex);
-
-        assert.strictEqual(transaction.virtualSize(), f.virtualSize);
-      });
-    });
-
-    it('computes weight', () => {
-      fixtures.valid.forEach(f => {
-        const transaction = Transaction.fromHex(f.whex ? f.whex : f.hex);
-
-        assert.strictEqual(transaction.weight(), f.weight);
-      });
-    });
-  });
-
-  describe('addInput', () => {
-    let prevTxHash: Buffer;
-    beforeEach(() => {
-      prevTxHash = Buffer.from(
-        'ffffffff00ffff000000000000000000000000000000000000000000101010ff',
-        'hex',
-      );
-    });
-
-    it('returns an index', () => {
-      const tx = new Transaction();
-      assert.strictEqual(tx.addInput(prevTxHash, 0), 0);
-      assert.strictEqual(tx.addInput(prevTxHash, 0), 1);
-    });
-
-    it('defaults to empty script, witness and 0xffffffff SEQUENCE number', () => {
-      const tx = new Transaction();
-      tx.addInput(prevTxHash, 0);
-
-      assert.strictEqual(tx.ins[0].script.length, 0);
-      assert.strictEqual(tx.ins[0].witness.length, 0);
-      assert.strictEqual(tx.ins[0].sequence, 0xffffffff);
-    });
-
-    fixtures.invalid.addInput.forEach(f => {
-      it('throws on ' + f.exception, () => {
-        const tx = new Transaction();
-        const hash = Buffer.from(f.hash, 'hex');
-
-        assert.throws(() => {
-          tx.addInput(hash, f.index);
-        }, new RegExp(f.exception));
-      });
-    });
-  });
-
-  describe('addOutput', () => {
-    it('returns an index', () => {
-      const tx = new Transaction();
-      assert.strictEqual(tx.addOutput(Buffer.alloc(0), 0), 0);
-      assert.strictEqual(tx.addOutput(Buffer.alloc(0), 0), 1);
-    });
-  });
-
-  describe('clone', () => {
-    fixtures.valid.forEach(f => {
-      let actual: Transaction;
-      let expected: Transaction;
-
-      beforeEach(() => {
-        expected = Transaction.fromHex(f.hex);
-        actual = expected.clone();
-      });
-
-      it('should have value equality', () => {
-        assert.deepStrictEqual(actual, expected);
-      });
-
-      it('should not have reference equality', () => {
-        assert.notStrictEqual(actual, expected);
-      });
-    });
-  });
-
-  describe('getHash/getId', () => {
-    function verify(f: any): void {
-      it('should return the id for ' + f.id + '(' + f.description + ')', () => {
-        const tx = Transaction.fromHex(f.whex || f.hex);
-
-        assert.strictEqual(tx.getHash().toString('hex'), f.hash);
-        assert.strictEqual(tx.getId(), f.id);
-      });
-    }
-
-    fixtures.valid.forEach(verify);
-  });
-
-  describe('isCoinbase', () => {
-    function verify(f: any): void {
-      it(
-        'should return ' +
-          f.coinbase +
-          ' for ' +
-          f.id +
-          '(' +
-          f.description +
-          ')',
-        () => {
-          const tx = Transaction.fromHex(f.hex);
-
-          assert.strictEqual(tx.isCoinbase(), f.coinbase);
-        },
-      );
-    }
-
-    fixtures.valid.forEach(verify);
-  });
-
-  describe('hashForSignature', () => {
-    it('does not use Witness serialization', () => {
-      const randScript = Buffer.from('6a', 'hex');
-
-      const tx = new Transaction();
-      tx.addInput(
-        Buffer.from(
-          '0000000000000000000000000000000000000000000000000000000000000000',
-          'hex',
-        ),
-        0,
-      );
-      tx.addOutput(randScript, 5000000000);
-
-      const original = (tx as any).__toBuffer;
-      (tx as any).__toBuffer = function(
-        this: Transaction,
-        a: any,
-        b: any,
-        c: any,
-      ): any {
-        if (c !== false) throw new Error('hashForSignature MUST pass false');
-
-        return original.call(this, a, b, c);
-      };
-
-      assert.throws(() => {
-        (tx as any).__toBuffer(undefined, undefined, true);
-      }, /hashForSignature MUST pass false/);
-
-      // assert hashForSignature does not pass false
-      assert.doesNotThrow(() => {
-        tx.hashForSignature(0, randScript, 1);
-      });
-    });
-
-    fixtures.hashForSignature.forEach(f => {
-      it(
-        'should return ' +
-          f.hash +
-          ' for ' +
-          (f.description ? 'case "' + f.description + '"' : f.script),
-        () => {
-          const tx = Transaction.fromHex(f.txHex);
-          const script = bscript.fromASM(f.script);
-
-          assert.strictEqual(
-            tx.hashForSignature(f.inIndex, script, f.type).toString('hex'),
-            f.hash,
-          );
-        },
-      );
-    });
-  });
-
-  describe('hashForWitnessV0', () => {
-    fixtures.hashForWitnessV0.forEach(f => {
-      it(
-        'should return ' +
-          f.hash +
-          ' for ' +
-          (f.description ? 'case "' + f.description + '"' : ''),
-        () => {
-          const tx = Transaction.fromHex(f.txHex);
-          const script = bscript.fromASM(f.script);
-
-          assert.strictEqual(
-            tx
-              .hashForWitnessV0(f.inIndex, script, f.value, f.type)
-              .toString('hex'),
-            f.hash,
-          );
-        },
-      );
-    });
-  });
-
-  describe('taprootSigning', () => {
-    fixtures.taprootSigning.forEach(f => {
-      const tx = Transaction.fromHex(f.txHex);
-      const prevOutScripts = f.utxos.map(({ scriptHex }) =>
-        Buffer.from(scriptHex, 'hex'),
-      );
-      const values = f.utxos.map(({ value }) => value);
-
-      f.cases.forEach(c => {
-        let hash: Buffer;
-
-        it(`should hash to ${c.hash} for ${f.description}:${c.vin}`, () => {
-          const hashType = Buffer.from(c.typeHex, 'hex').readUInt8(0);
-
-          hash = tx.hashForWitnessV1(c.vin, prevOutScripts, values, hashType);
-          assert.strictEqual(hash.toString('hex'), c.hash);
-        });
-      });
-    });
-  });
-
-  describe('setWitness', () => {
-    it('only accepts a a witness stack (Array of Buffers)', () => {
-      assert.throws(() => {
-        (new Transaction().setWitness as any)(0, 'foobar');
-      }, /Expected property "1" of type \[Buffer], got String "foobar"/);
-    });
-  });
-});
diff --git a/test/transaction_builder.js b/test/transaction_builder.js
new file mode 100644
index 0000000..f2325a4
--- /dev/null
+++ b/test/transaction_builder.js
@@ -0,0 +1,577 @@
+/* global describe, it, beforeEach */
+
+var assert = require('assert')
+var baddress = require('../src/address')
+var bscript = require('../src/script')
+var btemplates = require('../src/templates')
+var ops = require('bitcoin-ops')
+
+var BigInteger = require('bigi')
+var ECPair = require('../src/ecpair')
+var Transaction = require('../src/transaction')
+var TransactionBuilder = require('../src/transaction_builder')
+var NETWORKS = require('../src/networks')
+
+var fixtures = require('./fixtures/transaction_builder')
+
+function construct (f, dontSign) {
+  var network = NETWORKS[f.network]
+  var txb = new TransactionBuilder(network)
+
+  if (f.version !== undefined) txb.setVersion(f.version)
+  if (f.locktime !== undefined) txb.setLockTime(f.locktime)
+
+  f.inputs.forEach(function (input) {
+    var prevTx
+    if (input.txRaw) {
+      var constructed = construct(input.txRaw)
+      if (input.txRaw.incomplete) prevTx = constructed.buildIncomplete()
+      else prevTx = constructed.build()
+    } else if (input.txHex) {
+      prevTx = Transaction.fromHex(input.txHex)
+    } else {
+      prevTx = input.txId
+    }
+
+    var prevTxScript
+    if (input.prevTxScript) {
+      prevTxScript = bscript.fromASM(input.prevTxScript)
+    }
+
+    txb.addInput(prevTx, input.vout, input.sequence, prevTxScript)
+  })
+
+  f.outputs.forEach(function (output) {
+    if (output.address) {
+      txb.addOutput(output.address, output.value)
+    } else {
+      txb.addOutput(bscript.fromASM(output.script), output.value)
+    }
+  })
+
+  if (dontSign) return txb
+
+  var stages = f.stages && f.stages.concat()
+  f.inputs.forEach(function (input, index) {
+    if (!input.signs) return
+    input.signs.forEach(function (sign) {
+      var keyPair = ECPair.fromWIF(sign.keyPair, network)
+      var redeemScript
+      var witnessScript
+      var value
+      if (sign.redeemScript) {
+        redeemScript = bscript.fromASM(sign.redeemScript)
+      }
+      if (sign.value) {
+        value = sign.value
+      }
+      if (sign.witnessScript) {
+        witnessScript = bscript.fromASM(sign.witnessScript)
+      }
+      txb.sign(index, keyPair, redeemScript, sign.hashType, value, witnessScript)
+
+      if (sign.stage) {
+        var tx = txb.buildIncomplete()
+        assert.strictEqual(tx.toHex(), stages.shift())
+        txb = TransactionBuilder.fromTransaction(tx, network)
+      }
+    })
+  })
+
+  return txb
+}
+
+describe('TransactionBuilder', function () {
+  // constants
+  var keyPair = new ECPair(BigInteger.ONE)
+  var scripts = [
+    '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH',
+    '1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP'
+  ].map(function (x) {
+    return baddress.toOutputScript(x)
+  })
+  var txHash = Buffer.from('0e7cea811c0be9f73c0aca591034396e7264473fc25c1ca45195d7417b36cbe2', 'hex')
+
+  describe('fromTransaction', function () {
+    fixtures.valid.build.forEach(function (f) {
+      it('returns TransactionBuilder, with ' + f.description, function () {
+        var network = NETWORKS[f.network || 'bitcoin']
+
+        var tx = Transaction.fromHex(f.txHex)
+        var txb = TransactionBuilder.fromTransaction(tx, network)
+        var txAfter = f.incomplete ? txb.buildIncomplete() : txb.build()
+
+        assert.strictEqual(txAfter.toHex(), f.txHex)
+        assert.strictEqual(txb.network, network)
+      })
+    })
+
+    fixtures.valid.fromTransaction.forEach(function (f) {
+      it('returns TransactionBuilder, with ' + f.description, function () {
+        var tx = new Transaction()
+
+        f.inputs.forEach(function (input) {
+          var txHash2 = Buffer.from(input.txId, 'hex').reverse()
+
+          tx.addInput(txHash2, input.vout, undefined, bscript.fromASM(input.scriptSig))
+        })
+
+        f.outputs.forEach(function (output) {
+          tx.addOutput(bscript.fromASM(output.script), output.value)
+        })
+
+        var txb = TransactionBuilder.fromTransaction(tx)
+        var txAfter = f.incomplete ? txb.buildIncomplete() : txb.build()
+
+        txAfter.ins.forEach(function (input, i) {
+          assert.equal(bscript.toASM(input.script), f.inputs[i].scriptSigAfter)
+        })
+
+        txAfter.outs.forEach(function (output, i) {
+          assert.equal(bscript.toASM(output.script), f.outputs[i].script)
+        })
+      })
+    })
+
+    it('correctly classifies transaction inputs', function () {
+      var tx = Transaction.fromHex(fixtures.valid.classification.hex)
+      var txb = TransactionBuilder.fromTransaction(tx)
+      txb.inputs.forEach(function (i) {
+        assert.strictEqual(i.prevOutType, 'scripthash')
+        assert.strictEqual(i.redeemScriptType, 'multisig')
+        assert.strictEqual(i.signType, 'multisig')
+      })
+    })
+
+    fixtures.invalid.fromTransaction.forEach(function (f) {
+      it('throws ' + f.exception, function () {
+        var tx = Transaction.fromHex(f.txHex)
+
+        assert.throws(function () {
+          TransactionBuilder.fromTransaction(tx)
+        }, new RegExp(f.exception))
+      })
+    })
+  })
+
+  describe('addInput', function () {
+    var txb
+    beforeEach(function () {
+      txb = new TransactionBuilder()
+    })
+
+    it('accepts a txHash, index [and sequence number]', function () {
+      var vin = txb.addInput(txHash, 1, 54)
+      assert.strictEqual(vin, 0)
+
+      var txIn = txb.tx.ins[0]
+      assert.strictEqual(txIn.hash, txHash)
+      assert.strictEqual(txIn.index, 1)
+      assert.strictEqual(txIn.sequence, 54)
+      assert.strictEqual(txb.inputs[0].prevOutScript, undefined)
+    })
+
+    it('accepts a txHash, index [, sequence number and scriptPubKey]', function () {
+      var vin = txb.addInput(txHash, 1, 54, scripts[1])
+      assert.strictEqual(vin, 0)
+
+      var txIn = txb.tx.ins[0]
+      assert.strictEqual(txIn.hash, txHash)
+      assert.strictEqual(txIn.index, 1)
+      assert.strictEqual(txIn.sequence, 54)
+      assert.strictEqual(txb.inputs[0].prevOutScript, scripts[1])
+    })
+
+    it('accepts a prevTx, index [and sequence number]', function () {
+      var prevTx = new Transaction()
+      prevTx.addOutput(scripts[0], 0)
+      prevTx.addOutput(scripts[1], 1)
+
+      var vin = txb.addInput(prevTx, 1, 54)
+      assert.strictEqual(vin, 0)
+
+      var txIn = txb.tx.ins[0]
+      assert.deepEqual(txIn.hash, prevTx.getHash())
+      assert.strictEqual(txIn.index, 1)
+      assert.strictEqual(txIn.sequence, 54)
+      assert.strictEqual(txb.inputs[0].prevOutScript, scripts[1])
+    })
+
+    it('returns the input index', function () {
+      assert.strictEqual(txb.addInput(txHash, 0), 0)
+      assert.strictEqual(txb.addInput(txHash, 1), 1)
+    })
+
+    it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () {
+      txb.addInput(txHash, 0)
+      txb.sign(0, keyPair)
+
+      assert.throws(function () {
+        txb.addInput(txHash, 0)
+      }, /No, this would invalidate signatures/)
+    })
+  })
+
+  describe('addOutput', function () {
+    var txb
+    beforeEach(function () {
+      txb = new TransactionBuilder()
+    })
+
+    it('accepts an address string and value', function () {
+      var vout = txb.addOutput(keyPair.getAddress(), 1000)
+      assert.strictEqual(vout, 0)
+
+      var txout = txb.tx.outs[0]
+      assert.deepEqual(txout.script, scripts[0])
+      assert.strictEqual(txout.value, 1000)
+    })
+
+    it('accepts a ScriptPubKey and value', function () {
+      var vout = txb.addOutput(scripts[0], 1000)
+      assert.strictEqual(vout, 0)
+
+      var txout = txb.tx.outs[0]
+      assert.deepEqual(txout.script, scripts[0])
+      assert.strictEqual(txout.value, 1000)
+    })
+
+    it('throws if address is of the wrong network', function () {
+      assert.throws(function () {
+        txb.addOutput('2NGHjvjw83pcVFgMcA7QvSMh2c246rxLVz9', 1000)
+      }, /2NGHjvjw83pcVFgMcA7QvSMh2c246rxLVz9 has no matching Script/)
+    })
+
+    it('add second output after signed first input with SIGHASH_NONE', function () {
+      txb.addInput(txHash, 0)
+      txb.addOutput(scripts[0], 2000)
+      txb.sign(0, keyPair, undefined, Transaction.SIGHASH_NONE)
+      assert.equal(txb.addOutput(scripts[1], 9000), 1)
+    })
+
+    it('add first output after signed first input with SIGHASH_NONE', function () {
+      txb.addInput(txHash, 0)
+      txb.sign(0, keyPair, undefined, Transaction.SIGHASH_NONE)
+      assert.equal(txb.addOutput(scripts[0], 2000), 0)
+    })
+
+    it('add second output after signed first input with SIGHASH_SINGLE', function () {
+      txb.addInput(txHash, 0)
+      txb.addOutput(scripts[0], 2000)
+      txb.sign(0, keyPair, undefined, Transaction.SIGHASH_SINGLE)
+      assert.equal(txb.addOutput(scripts[1], 9000), 1)
+    })
+
+    it('add first output after signed first input with SIGHASH_SINGLE', function () {
+      txb.addInput(txHash, 0)
+      txb.sign(0, keyPair, undefined, Transaction.SIGHASH_SINGLE)
+      assert.throws(function () {
+        txb.addOutput(scripts[0], 2000)
+      }, /No, this would invalidate signatures/)
+    })
+
+    it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () {
+      txb.addInput(txHash, 0)
+      txb.addOutput(scripts[0], 2000)
+      txb.sign(0, keyPair)
+
+      assert.throws(function () {
+        txb.addOutput(scripts[1], 9000)
+      }, /No, this would invalidate signatures/)
+    })
+  })
+
+  describe('setLockTime', function () {
+    it('throws if if there exist any scriptSigs', function () {
+      var txb = new TransactionBuilder()
+      txb.addInput(txHash, 0)
+      txb.sign(0, keyPair)
+
+      assert.throws(function () {
+        txb.setLockTime(65535)
+      }, /No, this would invalidate signatures/)
+    })
+  })
+
+  describe('sign', function () {
+    it('supports the alternative abstract interface { publicKey, sign }', function () {
+      var keyPair = {
+        publicKey: Buffer.alloc(33, 0x03),
+        sign: function (hash) { return Buffer.alloc(64) }
+      }
+
+      var txb = new TransactionBuilder()
+      txb.addInput('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 1)
+      txb.addOutput('1111111111111111111114oLvT2', 100000)
+      txb.sign(0, keyPair)
+      assert.equal(txb.build().toHex(), '0100000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000002c0930060201000201000121030303030303030303030303030303030303030303030303030303030303030303ffffffff01a0860100000000001976a914000000000000000000000000000000000000000088ac00000000')
+    })
+
+    fixtures.invalid.sign.forEach(function (f) {
+      it('throws ' + f.exception + (f.description ? ' (' + f.description + ')' : ''), function () {
+        var txb = construct(f, true)
+
+        f.inputs.forEach(function (input, index) {
+          input.signs.forEach(function (sign) {
+            var keyPairNetwork = NETWORKS[sign.network || f.network]
+            var keyPair2 = ECPair.fromWIF(sign.keyPair, keyPairNetwork)
+            var redeemScript, witnessScript
+
+            if (sign.redeemScript) {
+              redeemScript = bscript.fromASM(sign.redeemScript)
+            }
+
+            if (sign.witnessScript) {
+              witnessScript = bscript.fromASM(sign.witnessScript)
+            }
+
+            if (!sign.throws) {
+              txb.sign(index, keyPair2, redeemScript, sign.hashType, sign.value, witnessScript)
+            } else {
+              assert.throws(function () {
+                txb.sign(index, keyPair2, redeemScript, sign.hashType, sign.value, witnessScript)
+              }, new RegExp(f.exception))
+            }
+          })
+        })
+      })
+    })
+  })
+
+  describe('build', function () {
+    fixtures.valid.build.forEach(function (f) {
+      it('builds "' + f.description + '"', function () {
+        var txb = construct(f)
+        var tx = f.incomplete ? txb.buildIncomplete() : txb.build()
+
+        assert.strictEqual(tx.toHex(), f.txHex)
+      })
+    })
+
+    // TODO: remove duplicate test code
+    fixtures.invalid.build.forEach(function (f) {
+      describe('for ' + (f.description || f.exception), function () {
+        it('throws ' + f.exception, function () {
+          assert.throws(function () {
+            var txb
+            if (f.txHex) {
+              txb = TransactionBuilder.fromTransaction(Transaction.fromHex(f.txHex))
+            } else {
+              txb = construct(f)
+            }
+
+            txb.build()
+          }, new RegExp(f.exception))
+        })
+
+        // if throws on incomplete too, enforce that
+        if (f.incomplete) {
+          it('throws ' + f.exception, function () {
+            assert.throws(function () {
+              var txb
+              if (f.txHex) {
+                txb = TransactionBuilder.fromTransaction(Transaction.fromHex(f.txHex))
+              } else {
+                txb = construct(f)
+              }
+
+              txb.buildIncomplete()
+            }, new RegExp(f.exception))
+          })
+        } else {
+          it('does not throw if buildIncomplete', function () {
+            var txb
+            if (f.txHex) {
+              txb = TransactionBuilder.fromTransaction(Transaction.fromHex(f.txHex))
+            } else {
+              txb = construct(f)
+            }
+
+            txb.buildIncomplete()
+          })
+        }
+      })
+    })
+
+    it('for incomplete with 0 signatures', function () {
+      var randomTxData = '0100000000010100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100aa5d8aa40a90f23ce2c3d11bc845ca4a12acd99cbea37de6b9f6d86edebba8cb022022dedc2aa0a255f74d04c0b76ece2d7c691f9dd11a64a8ac49f62a99c3a05f9d01232103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac00000000'
+      var randomAddress = '1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH'
+
+      var randomTx = Transaction.fromHex(randomTxData)
+      var tx = new TransactionBuilder()
+      tx.addInput(randomTx, 0)
+      tx.addOutput(randomAddress, 1000)
+      tx = tx.buildIncomplete()
+      assert(tx)
+    })
+
+    it('for incomplete P2SH with 0 signatures', function () {
+      var inp = Buffer.from('010000000173120703f67318aef51f7251272a6816d3f7523bb25e34b136d80be959391c100000000000ffffffff0100c817a80400000017a91471a8ec07ff69c6c4fee489184c462a9b1b9237488700000000', 'hex') // arbitrary P2SH input
+      var inpTx = Transaction.fromBuffer(inp)
+
+      var txb = new TransactionBuilder(NETWORKS.testnet)
+      txb.addInput(inpTx, 0)
+      txb.addOutput('2NAkqp5xffoomp5RLBcakuGpZ12GU4twdz4', 1e8) // arbitrary output
+
+      txb.buildIncomplete()
+    })
+
+    it('for incomplete P2WPKH with 0 signatures', function () {
+      var inp = Buffer.from('010000000173120703f67318aef51f7251272a6816d3f7523bb25e34b136d80be959391c100000000000ffffffff0100c817a8040000001600141a15805e1f4040c9f68ccc887fca2e63547d794b00000000', 'hex')
+      var inpTx = Transaction.fromBuffer(inp)
+
+      var txb = new TransactionBuilder(NETWORKS.testnet)
+      txb.addInput(inpTx, 0)
+      txb.addOutput('2NAkqp5xffoomp5RLBcakuGpZ12GU4twdz4', 1e8) // arbitrary output
+
+      txb.buildIncomplete()
+    })
+
+    it('for incomplete P2WSH with 0 signatures', function () {
+      var inpTx = Transaction.fromBuffer(Buffer.from('010000000173120703f67318aef51f7251272a6816d3f7523bb25e34b136d80be959391c100000000000ffffffff0100c817a80400000022002072df76fcc0b231b94bdf7d8c25d7eef4716597818d211e19ade7813bff7a250200000000', 'hex'))
+
+      var txb = new TransactionBuilder(NETWORKS.testnet)
+      txb.addInput(inpTx, 0)
+      txb.addOutput('2NAkqp5xffoomp5RLBcakuGpZ12GU4twdz4', 1e8) // arbitrary output
+
+      txb.buildIncomplete()
+    })
+  })
+
+  describe('multisig', function () {
+    fixtures.valid.multisig.forEach(function (f) {
+      it(f.description, function () {
+        var txb = construct(f, true)
+        var tx
+        var network = NETWORKS[f.network]
+
+        f.inputs.forEach(function (input, i) {
+          var redeemScript = bscript.fromASM(input.redeemScript)
+
+          input.signs.forEach(function (sign) {
+            // rebuild the transaction each-time after the first
+            if (tx) {
+              // do we filter OP_0's beforehand?
+              if (sign.filterOP_0) {
+                var scriptSig = tx.ins[i].script
+
+                // ignore OP_0 on the front, ignore redeemScript
+                var signatures = bscript.decompile(scriptSig).slice(1, -1).filter(function (x) { return x !== ops.OP_0 })
+
+                // rebuild/replace the scriptSig without them
+                var replacement = btemplates.scriptHash.input.encode(btemplates.multisig.input.encode(signatures), redeemScript)
+                assert.strictEqual(bscript.toASM(replacement), sign.scriptSigFiltered)
+
+                tx.ins[i].script = replacement
+              }
+              // now import it
+              txb = TransactionBuilder.fromTransaction(tx, network)
+            }
+
+            var keyPair2 = ECPair.fromWIF(sign.keyPair, network)
+            txb.sign(i, keyPair2, redeemScript, sign.hashType)
+
+            // update the tx
+            tx = txb.buildIncomplete()
+            // now verify the serialized scriptSig is as expected
+            assert.strictEqual(bscript.toASM(tx.ins[i].script), sign.scriptSig)
+          })
+        })
+
+        tx = txb.build()
+        assert.strictEqual(tx.toHex(), f.txHex)
+      })
+    })
+  })
+
+  describe('various edge case', function () {
+    var network = NETWORKS.testnet
+
+    it('should warn of high fee for segwit transaction based on VSize, not Size', function () {
+      var rawtx = '01000000000104fdaac89627208b4733484ca56bc291f4cf4fa8d7c5f29893c52b46788a0a' +
+      '1df90000000000fffffffffdaac89627208b4733484ca56bc291f4cf4fa8d7c5f29893c52b46788a0a1df9' +
+      '0100000000ffffffffa2ef7aaab316a3e5b5b0a78d1d35c774b95a079f9f0c762277a49caf1f26bca40000' +
+      '000000ffffffffa2ef7aaab316a3e5b5b0a78d1d35c774b95a079f9f0c762277a49caf1f26bca401000000' +
+      '00ffffffff0100040000000000001976a914cf307285359ab7ef6a2daa0522c7908ddf5fe7a988ac024730' +
+      '440220113324438816338406841775e079b04c50d04f241da652a4035b1017ea1ecf5502205802191eb49c' +
+      '54bf2a5667aea72e51c3ca92085efc60f12d1ebda3a64aff343201210283409659355b6d1cc3c32decd5d5' +
+      '61abaac86c37a353b52895a5e6c196d6f44802483045022100dc2892874e6d8708e3f5a058c5c9263cdf03' +
+      '969492270f89ee4933caf6daf8bb0220391dfe61a002709b63b9d64422d3db09b727839d1287e10a128a5d' +
+      'b52a82309301210283409659355b6d1cc3c32decd5d561abaac86c37a353b52895a5e6c196d6f448024830' +
+      '450221009e3ed3a6ae93a018f443257b43e47b55cf7f7f3547d8807178072234686b22160220576121cfe6' +
+      '77c7eddf5575ea0a7c926247df6eca723c4f85df306e8bc08ea2df01210283409659355b6d1cc3c32decd5' +
+      'd561abaac86c37a353b52895a5e6c196d6f44802473044022007be81ffd4297441ab10e740fc9bab9545a2' +
+      '194a565cd6aa4cc38b8eaffa343402201c5b4b61d73fa38e49c1ee68cc0e6dfd2f5dae453dd86eb142e87a' +
+      '0bafb1bc8401210283409659355b6d1cc3c32decd5d561abaac86c37a353b52895a5e6c196d6f44800000000'
+      var txb = TransactionBuilder.fromTransaction(Transaction.fromHex(rawtx))
+      txb.inputs[0].value = 241530
+      txb.inputs[1].value = 241530
+      txb.inputs[2].value = 248920
+      txb.inputs[3].value = 248920
+
+      assert.throws(function () {
+        txb.build()
+      }, new RegExp('Transaction has absurd fees'))
+    })
+
+    it('should classify witness inputs with witness = true during multisigning', function () {
+      var keyPair = ECPair.fromWIF('cRAwuVuVSBZMPu7hdrYvMCZ8eevzmkExjFbaBLhqnDdrezxN3nTS', network)
+      var witnessScript = Buffer.from('522102bbbd6eb01efcbe4bd9664b886f26f69de5afcb2e479d72596c8bf21929e352e22102d9c3f7180ef13ec5267723c9c2ffab56a4215241f837502ea8977c8532b9ea1952ae', 'hex')
+      var redeemScript = Buffer.from('002024376a0a9abab599d0e028248d48ebe817bc899efcffa1cd2984d67289daf5af', 'hex')
+      var scriptPubKey = Buffer.from('a914b64f1a3eacc1c8515592a6f10457e8ff90e4db6a87', 'hex')
+      var txb = new TransactionBuilder(network)
+      txb.addInput('a4696c4b0cd27ec2e173ab1fa7d1cc639a98ee237cec95a77ca7ff4145791529', 1, 0xffffffff, scriptPubKey)
+      txb.addOutput(scriptPubKey, 99000)
+      txb.sign(0, keyPair, redeemScript, null, 100000, witnessScript)
+      // 2-of-2 signed only once
+      var tx = txb.buildIncomplete()
+      // Only input is segwit, so txid should be accurate with the final tx
+      assert.equal(tx.getId(), 'f15d0a65b21b4471405b21a099f8b18e1ae4d46d55efbd0f4766cf11ad6cb821')
+      var txHex = tx.toHex()
+      var newTxb = TransactionBuilder.fromTransaction(Transaction.fromHex(txHex))
+      // input should have the key 'witness' set to true
+      assert.equal(newTxb.inputs[0].witness, true)
+    })
+
+    it('should handle badly pre-filled OP_0s', function () {
+      // OP_0 is used where a signature is missing
+      var redeemScripSig = bscript.fromASM('OP_0 OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae')
+      var redeemScript = bscript.fromASM('OP_2 0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a 04f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e672 OP_3 OP_CHECKMULTISIG')
+
+      var tx = new Transaction()
+      tx.addInput(Buffer.from('cff58855426469d0ef16442ee9c644c4fb13832467bcbc3173168a7916f07149', 'hex'), 0, undefined, redeemScripSig)
+      tx.addOutput(Buffer.from('76a914aa4d7985c57e011a8b3dd8e0e5a73aaef41629c588ac', 'hex'), 1000)
+
+      // now import the Transaction
+      var txb = TransactionBuilder.fromTransaction(tx, NETWORKS.testnet)
+
+      var keyPair2 = ECPair.fromWIF('91avARGdfge8E4tZfYLoxeJ5sGBdNJQH4kvjJoQFacbgx3cTMqe', network)
+      txb.sign(0, keyPair2, redeemScript)
+
+      var tx2 = txb.build()
+      assert.equal(tx2.getId(), 'eab59618a564e361adef6d918bd792903c3d41bcf1220137364fb847880467f9')
+      assert.equal(bscript.toASM(tx2.ins[0].script), 'OP_0 3045022100daf0f4f3339d9fbab42b098045c1e4958ee3b308f4ae17be80b63808558d0adb02202f07e3d1f79dc8da285ae0d7f68083d769c11f5621ebd9691d6b48c0d4283d7d01 3045022100a346c61738304eac5e7702188764d19cdf68f4466196729db096d6c87ce18cdd022018c0e8ad03054b0e7e235cda6bedecf35881d7aa7d94ff425a8ace7220f38af001 52410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a4104f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9388f7b0f632de8140fe337e62a37f3566500a99934c2231b6cb9fd7584b8e67253ae')
+    })
+
+    it('should not classify blank scripts as nonstandard', function () {
+      var tx = new TransactionBuilder()
+      tx.addInput('aa94ab02c182214f090e99a0d57021caffd0f195a81c24602b1028b130b63e31', 0)
+
+      var incomplete = tx.buildIncomplete().toHex()
+      var keyPair = ECPair.fromWIF('L1uyy5qTuGrVXrmrsvHWHgVzW9kKdrp27wBC7Vs6nZDTF2BRUVwy')
+
+      // sign, as expected
+      tx.addOutput('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000)
+      tx.sign(0, keyPair)
+      var txId = tx.build().getId()
+      assert.equal(txId, '54f097315acbaedb92a95455da3368eb45981cdae5ffbc387a9afc872c0f29b3')
+
+      // and, repeat
+      tx = TransactionBuilder.fromTransaction(Transaction.fromHex(incomplete))
+      tx.addOutput('1Gokm82v6DmtwKEB8AiVhm82hyFSsEvBDK', 15000)
+      tx.sign(0, keyPair)
+      var txId2 = tx.build().getId()
+      assert.equal(txId, txId2)
+    })
+  })
+})
diff --git a/test/ts-node-register.js b/test/ts-node-register.js
deleted file mode 100644
index fef284d..0000000
--- a/test/ts-node-register.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// This file is required to run mocha tests on the TS files directly
-
-require("ts-node").register({
-  project: "test/tsconfig.json",
-});
diff --git a/test/tsconfig.json b/test/tsconfig.json
deleted file mode 100644
index 6752ec5..0000000
--- a/test/tsconfig.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
-  "compilerOptions": {
-    "target": "ES2020",
-    "module": "commonjs",
-    "outDir": "../",
-    "declaration": false,
-    "rootDir": "../",
-    "rootDirs": [
-      "../src",
-      "../types"
-    ],
-    "types": [
-      "node",
-      "mocha"
-    ],
-    "allowJs": false,
-    "resolveJsonModule": true,
-    "strict": true,
-    "noImplicitAny": true,
-    "strictNullChecks": true,
-    "strictFunctionTypes": true,
-    "strictBindCallApply": true,
-    "strictPropertyInitialization": true,
-    "noImplicitThis": true,
-    "alwaysStrict": true,
-    "esModuleInterop": false,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "baseUrl": ".",
-    "paths": {
-      "../src/*": ["../ts_src/*"]
-    }
-  },
-  "include": [
-      "./**/*.ts"
-  ],
-  "exclude": [
-      "../ts_src/**/*.ts"
-  ]
-}
diff --git a/test/types.js b/test/types.js
new file mode 100644
index 0000000..832b32d
--- /dev/null
+++ b/test/types.js
@@ -0,0 +1,64 @@
+/* global describe, it */
+
+var assert = require('assert')
+var types = require('../src/types')
+var typeforce = require('typeforce')
+
+describe('types', function () {
+  describe('BigInt/ECPoint', function () {
+    it('return true for duck types', function () {
+      assert(types.BigInt(new function BigInteger () {}()))
+      assert(types.ECPoint(new function Point () {}()))
+    })
+
+    it('return false for bad types', function () {
+      assert(!types.BigInt(new function NotABigInteger () {}()))
+      assert(!types.ECPoint(new function NotAPoint () {}()))
+    })
+  })
+
+  describe('Buffer Hash160/Hash256', function () {
+    var buffer20byte = Buffer.alloc(20)
+    var buffer32byte = Buffer.alloc(32)
+
+    it('return true for valid size', function () {
+      assert(types.Hash160bit(buffer20byte))
+      assert(types.Hash256bit(buffer32byte))
+    })
+
+    it('return true for oneOf', function () {
+      assert.doesNotThrow(function () {
+        typeforce(types.oneOf(types.Hash160bit, types.Hash256bit), buffer32byte)
+      })
+
+      assert.doesNotThrow(function () {
+        typeforce(types.oneOf(types.Hash256bit, types.Hash160bit), buffer32byte)
+      })
+    })
+
+    it('throws for invalid size', function () {
+      assert.throws(function () {
+        types.Hash160bit(buffer32byte)
+      }, /Expected Buffer\(Length: 20\), got Buffer\(Length: 32\)/)
+
+      assert.throws(function () {
+        types.Hash256bit(buffer20byte)
+      }, /Expected Buffer\(Length: 32\), got Buffer\(Length: 20\)/)
+    })
+  })
+
+  describe('Satoshi', function () {
+    [
+      { value: -1, result: false },
+      { value: 0, result: true },
+      { value: 1, result: true },
+      { value: 20999999 * 1e8, result: true },
+      { value: 21000000 * 1e8, result: true },
+      { value: 21000001 * 1e8, result: false }
+    ].forEach(function (f) {
+      it('returns ' + f.result + ' for valid for ' + f.value, function () {
+        assert.strictEqual(types.Satoshi(f.value), f.result)
+      })
+    })
+  })
+})
diff --git a/test/types.spec.ts b/test/types.spec.ts
deleted file mode 100644
index 478fd99..0000000
--- a/test/types.spec.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import * as assert from 'assert';
-import { describe, it } from 'mocha';
-import * as types from '../src/types';
-const typeforce = require('typeforce');
-
-describe('types', () => {
-  describe('Buffer Hash160/Hash256', () => {
-    const buffer20byte = Buffer.alloc(20);
-    const buffer32byte = Buffer.alloc(32);
-
-    it('return true for valid size', () => {
-      assert(types.Hash160bit(buffer20byte));
-      assert(types.Hash256bit(buffer32byte));
-    });
-
-    it('return true for oneOf', () => {
-      assert.doesNotThrow(() => {
-        typeforce(
-          types.oneOf(types.Hash160bit, types.Hash256bit),
-          buffer32byte,
-        );
-      });
-
-      assert.doesNotThrow(() => {
-        typeforce(
-          types.oneOf(types.Hash256bit, types.Hash160bit),
-          buffer32byte,
-        );
-      });
-    });
-
-    it('throws for invalid size', () => {
-      assert.throws(() => {
-        types.Hash160bit(buffer32byte);
-      }, /Expected Buffer\(Length: 20\), got Buffer\(Length: 32\)/);
-
-      assert.throws(() => {
-        types.Hash256bit(buffer20byte);
-      }, /Expected Buffer\(Length: 32\), got Buffer\(Length: 20\)/);
-    });
-  });
-
-  describe('Satoshi', () => {
-    [
-      { value: -1, result: false },
-      { value: 0, result: true },
-      { value: 1, result: true },
-      { value: 20999999 * 1e8, result: true },
-      { value: 21000000 * 1e8, result: true },
-      { value: 21000001 * 1e8, result: false },
-    ].forEach(f => {
-      it('returns ' + f.result + ' for valid for ' + f.value, () => {
-        assert.strictEqual(types.Satoshi(f.value), f.result);
-      });
-    });
-  });
-
-  describe('UInt31', () => {
-    const UINT31_MAX = Math.pow(2, 31) - 1;
-    it('return true for valid values', () => {
-      assert.strictEqual(types.UInt31(0), true);
-      assert.strictEqual(types.UInt31(1000), true);
-      assert.strictEqual(types.UInt31(UINT31_MAX), true);
-    });
-
-    it('return false for negative values', () => {
-      assert.strictEqual(types.UInt31(-1), false);
-      assert.strictEqual(types.UInt31(-UINT31_MAX), false);
-    });
-
-    it(`return false for value > ${UINT31_MAX}`, () => {
-      assert.strictEqual(types.UInt31(UINT31_MAX + 1), false);
-    });
-  });
-
-  describe('BIP32Path', () => {
-    it('return true for valid paths', () => {
-      assert.strictEqual(types.BIP32Path("m/0'/0'"), true);
-      assert.strictEqual(types.BIP32Path("m/0'/0"), true);
-      assert.strictEqual(types.BIP32Path("m/0'/1'/2'/3/4'"), true);
-    });
-
-    it('return false for invalid paths', () => {
-      assert.strictEqual(types.BIP32Path('m'), false);
-      assert.strictEqual(types.BIP32Path("n/0'/0'"), false);
-      assert.strictEqual(types.BIP32Path("m/0'/x"), false);
-    });
-
-    it('return "BIP32 derivation path" for JSON.strigify()', () => {
-      const toJsonValue = JSON.stringify(types.BIP32Path);
-      assert.equal(toJsonValue, '"BIP32 derivation path"');
-    });
-  });
-});
diff --git a/ts_src/address.ts b/ts_src/address.ts
deleted file mode 100644
index 753589d..0000000
--- a/ts_src/address.ts
+++ /dev/null
@@ -1,185 +0,0 @@
-import { Network } from './networks';
-import * as networks from './networks';
-import * as payments from './payments';
-import * as bscript from './script';
-import * as types from './types';
-import { bech32, bech32m } from 'bech32';
-import * as bs58check from 'bs58check';
-const { typeforce } = types;
-
-export interface Base58CheckResult {
-  hash: Buffer;
-  version: number;
-}
-
-export interface Bech32Result {
-  version: number;
-  prefix: string;
-  data: Buffer;
-}
-
-const FUTURE_SEGWIT_MAX_SIZE: number = 40;
-const FUTURE_SEGWIT_MIN_SIZE: number = 2;
-const FUTURE_SEGWIT_MAX_VERSION: number = 16;
-const FUTURE_SEGWIT_MIN_VERSION: number = 1;
-const FUTURE_SEGWIT_VERSION_DIFF: number = 0x50;
-const FUTURE_SEGWIT_VERSION_WARNING: string =
-  'WARNING: Sending to a future segwit version address can lead to loss of funds. ' +
-  'End users MUST be warned carefully in the GUI and asked if they wish to proceed ' +
-  'with caution. Wallets should verify the segwit version from the output of fromBech32, ' +
-  'then decide when it is safe to use which version of segwit.';
-
-function _toFutureSegwitAddress(output: Buffer, network: Network): string {
-  const data = output.slice(2);
-
-  if (
-    data.length < FUTURE_SEGWIT_MIN_SIZE ||
-    data.length > FUTURE_SEGWIT_MAX_SIZE
-  )
-    throw new TypeError('Invalid program length for segwit address');
-
-  const version = output[0] - FUTURE_SEGWIT_VERSION_DIFF;
-
-  if (
-    version < FUTURE_SEGWIT_MIN_VERSION ||
-    version > FUTURE_SEGWIT_MAX_VERSION
-  )
-    throw new TypeError('Invalid version for segwit address');
-
-  if (output[1] !== data.length)
-    throw new TypeError('Invalid script for segwit address');
-
-  console.warn(FUTURE_SEGWIT_VERSION_WARNING);
-
-  return toBech32(data, version, network.bech32);
-}
-
-export function fromBase58Check(address: string): Base58CheckResult {
-  const payload = bs58check.decode(address);
-
-  // TODO: 4.0.0, move to "toOutputScript"
-  if (payload.length < 21) throw new TypeError(address + ' is too short');
-  if (payload.length > 21) throw new TypeError(address + ' is too long');
-
-  const version = payload.readUInt8(0);
-  const hash = payload.slice(1);
-
-  return { version, hash };
-}
-
-export function fromBech32(address: string): Bech32Result {
-  let result;
-  let version;
-  try {
-    result = bech32.decode(address);
-  } catch (e) {}
-
-  if (result) {
-    version = result.words[0];
-    if (version !== 0) throw new TypeError(address + ' uses wrong encoding');
-  } else {
-    result = bech32m.decode(address);
-    version = result.words[0];
-    if (version === 0) throw new TypeError(address + ' uses wrong encoding');
-  }
-
-  const data = bech32.fromWords(result.words.slice(1));
-
-  return {
-    version,
-    prefix: result.prefix,
-    data: Buffer.from(data),
-  };
-}
-
-export function toBase58Check(hash: Buffer, version: number): string {
-  typeforce(types.tuple(types.Hash160bit, types.UInt8), arguments);
-
-  const payload = Buffer.allocUnsafe(21);
-  payload.writeUInt8(version, 0);
-  hash.copy(payload, 1);
-
-  return bs58check.encode(payload);
-}
-
-export function toBech32(
-  data: Buffer,
-  version: number,
-  prefix: string,
-): string {
-  const words = bech32.toWords(data);
-  words.unshift(version);
-
-  return version === 0
-    ? bech32.encode(prefix, words)
-    : bech32m.encode(prefix, words);
-}
-
-export function fromOutputScript(output: Buffer, network?: Network): string {
-  // TODO: Network
-  network = network || networks.bitcoin;
-
-  try {
-    return payments.p2pkh({ output, network }).address as string;
-  } catch (e) {}
-  try {
-    return payments.p2sh({ output, network }).address as string;
-  } catch (e) {}
-  try {
-    return payments.p2wpkh({ output, network }).address as string;
-  } catch (e) {}
-  try {
-    return payments.p2wsh({ output, network }).address as string;
-  } catch (e) {}
-  try {
-    return _toFutureSegwitAddress(output, network);
-  } catch (e) {}
-
-  throw new Error(bscript.toASM(output) + ' has no matching Address');
-}
-
-export function toOutputScript(address: string, network?: Network): Buffer {
-  network = network || networks.bitcoin;
-
-  let decodeBase58: Base58CheckResult | undefined;
-  let decodeBech32: Bech32Result | undefined;
-  try {
-    decodeBase58 = fromBase58Check(address);
-  } catch (e) {}
-
-  if (decodeBase58) {
-    if (decodeBase58.version === network.pubKeyHash)
-      return payments.p2pkh({ hash: decodeBase58.hash }).output as Buffer;
-    if (decodeBase58.version === network.scriptHash)
-      return payments.p2sh({ hash: decodeBase58.hash }).output as Buffer;
-  } else {
-    try {
-      decodeBech32 = fromBech32(address);
-    } catch (e) {}
-
-    if (decodeBech32) {
-      if (decodeBech32.prefix !== network.bech32)
-        throw new Error(address + ' has an invalid prefix');
-      if (decodeBech32.version === 0) {
-        if (decodeBech32.data.length === 20)
-          return payments.p2wpkh({ hash: decodeBech32.data }).output as Buffer;
-        if (decodeBech32.data.length === 32)
-          return payments.p2wsh({ hash: decodeBech32.data }).output as Buffer;
-      } else if (
-        decodeBech32.version >= FUTURE_SEGWIT_MIN_VERSION &&
-        decodeBech32.version <= FUTURE_SEGWIT_MAX_VERSION &&
-        decodeBech32.data.length >= FUTURE_SEGWIT_MIN_SIZE &&
-        decodeBech32.data.length <= FUTURE_SEGWIT_MAX_SIZE
-      ) {
-        console.warn(FUTURE_SEGWIT_VERSION_WARNING);
-
-        return bscript.compile([
-          decodeBech32.version + FUTURE_SEGWIT_VERSION_DIFF,
-          decodeBech32.data,
-        ]);
-      }
-    }
-  }
-
-  throw new Error(address + ' has no matching Script');
-}
diff --git a/ts_src/bip66.ts b/ts_src/bip66.ts
deleted file mode 100644
index ab76a4f..0000000
--- a/ts_src/bip66.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-// Reference https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
-// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
-// NOTE: SIGHASH byte ignored AND restricted, truncate before use
-
-export function check(buffer: Buffer): boolean {
-  if (buffer.length < 8) return false;
-  if (buffer.length > 72) return false;
-  if (buffer[0] !== 0x30) return false;
-  if (buffer[1] !== buffer.length - 2) return false;
-  if (buffer[2] !== 0x02) return false;
-
-  const lenR = buffer[3];
-  if (lenR === 0) return false;
-  if (5 + lenR >= buffer.length) return false;
-  if (buffer[4 + lenR] !== 0x02) return false;
-
-  const lenS = buffer[5 + lenR];
-  if (lenS === 0) return false;
-  if (6 + lenR + lenS !== buffer.length) return false;
-
-  if (buffer[4] & 0x80) return false;
-  if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80)) return false;
-
-  if (buffer[lenR + 6] & 0x80) return false;
-  if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
-    return false;
-  return true;
-}
-
-export function decode(buffer: Buffer): { r: Buffer; s: Buffer } {
-  if (buffer.length < 8) throw new Error('DER sequence length is too short');
-  if (buffer.length > 72) throw new Error('DER sequence length is too long');
-  if (buffer[0] !== 0x30) throw new Error('Expected DER sequence');
-  if (buffer[1] !== buffer.length - 2)
-    throw new Error('DER sequence length is invalid');
-  if (buffer[2] !== 0x02) throw new Error('Expected DER integer');
-
-  const lenR = buffer[3];
-  if (lenR === 0) throw new Error('R length is zero');
-  if (5 + lenR >= buffer.length) throw new Error('R length is too long');
-  if (buffer[4 + lenR] !== 0x02) throw new Error('Expected DER integer (2)');
-
-  const lenS = buffer[5 + lenR];
-  if (lenS === 0) throw new Error('S length is zero');
-  if (6 + lenR + lenS !== buffer.length) throw new Error('S length is invalid');
-
-  if (buffer[4] & 0x80) throw new Error('R value is negative');
-  if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80))
-    throw new Error('R value excessively padded');
-
-  if (buffer[lenR + 6] & 0x80) throw new Error('S value is negative');
-  if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
-    throw new Error('S value excessively padded');
-
-  // non-BIP66 - extract R, S values
-  return {
-    r: buffer.slice(4, 4 + lenR),
-    s: buffer.slice(6 + lenR),
-  };
-}
-
-/*
- * Expects r and s to be positive DER integers.
- *
- * The DER format uses the most significant bit as a sign bit (& 0x80).
- * If the significant bit is set AND the integer is positive, a 0x00 is prepended.
- *
- * Examples:
- *
- *      0 =>     0x00
- *      1 =>     0x01
- *     -1 =>     0xff
- *    127 =>     0x7f
- *   -127 =>     0x81
- *    128 =>   0x0080
- *   -128 =>     0x80
- *    255 =>   0x00ff
- *   -255 =>   0xff01
- *  16300 =>   0x3fac
- * -16300 =>   0xc054
- *  62300 => 0x00f35c
- * -62300 => 0xff0ca4
- */
-export function encode(r: Buffer, s: Buffer): Buffer {
-  const lenR = r.length;
-  const lenS = s.length;
-  if (lenR === 0) throw new Error('R length is zero');
-  if (lenS === 0) throw new Error('S length is zero');
-  if (lenR > 33) throw new Error('R length is too long');
-  if (lenS > 33) throw new Error('S length is too long');
-  if (r[0] & 0x80) throw new Error('R value is negative');
-  if (s[0] & 0x80) throw new Error('S value is negative');
-  if (lenR > 1 && r[0] === 0x00 && !(r[1] & 0x80))
-    throw new Error('R value excessively padded');
-  if (lenS > 1 && s[0] === 0x00 && !(s[1] & 0x80))
-    throw new Error('S value excessively padded');
-
-  const signature = Buffer.allocUnsafe(6 + lenR + lenS);
-
-  // 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
-  signature[0] = 0x30;
-  signature[1] = signature.length - 2;
-  signature[2] = 0x02;
-  signature[3] = r.length;
-  r.copy(signature, 4);
-  signature[4 + lenR] = 0x02;
-  signature[5 + lenR] = s.length;
-  s.copy(signature, 6 + lenR);
-
-  return signature;
-}
diff --git a/ts_src/block.ts b/ts_src/block.ts
deleted file mode 100644
index c73477e..0000000
--- a/ts_src/block.ts
+++ /dev/null
@@ -1,262 +0,0 @@
-import {
-  BufferReader,
-  BufferWriter,
-  reverseBuffer,
-  varuint,
-} from './bufferutils';
-import * as bcrypto from './crypto';
-import { fastMerkleRoot } from './merkle';
-import { Transaction } from './transaction';
-import * as types from './types';
-const { typeforce } = types;
-
-const errorMerkleNoTxes = new TypeError(
-  'Cannot compute merkle root for zero transactions',
-);
-const errorWitnessNotSegwit = new TypeError(
-  'Cannot compute witness commit for non-segwit block',
-);
-
-export class Block {
-  static fromBuffer(buffer: Buffer): Block {
-    if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)');
-
-    const bufferReader = new BufferReader(buffer);
-
-    const block = new Block();
-    block.version = bufferReader.readInt32();
-    block.prevHash = bufferReader.readSlice(32);
-    block.merkleRoot = bufferReader.readSlice(32);
-    block.timestamp = bufferReader.readUInt32();
-    block.bits = bufferReader.readUInt32();
-    block.nonce = bufferReader.readUInt32();
-
-    if (buffer.length === 80) return block;
-
-    const readTransaction = (): any => {
-      const tx = Transaction.fromBuffer(
-        bufferReader.buffer.slice(bufferReader.offset),
-        true,
-      );
-      bufferReader.offset += tx.byteLength();
-      return tx;
-    };
-
-    const nTransactions = bufferReader.readVarInt();
-    block.transactions = [];
-
-    for (let i = 0; i < nTransactions; ++i) {
-      const tx = readTransaction();
-      block.transactions.push(tx);
-    }
-
-    const witnessCommit = block.getWitnessCommit();
-    // This Block contains a witness commit
-    if (witnessCommit) block.witnessCommit = witnessCommit;
-
-    return block;
-  }
-
-  static fromHex(hex: string): Block {
-    return Block.fromBuffer(Buffer.from(hex, 'hex'));
-  }
-
-  static calculateTarget(bits: number): Buffer {
-    const exponent = ((bits & 0xff000000) >> 24) - 3;
-    const mantissa = bits & 0x007fffff;
-    const target = Buffer.alloc(32, 0);
-    target.writeUIntBE(mantissa, 29 - exponent, 3);
-    return target;
-  }
-
-  static calculateMerkleRoot(
-    transactions: Transaction[],
-    forWitness?: boolean,
-  ): Buffer {
-    typeforce([{ getHash: types.Function }], transactions);
-    if (transactions.length === 0) throw errorMerkleNoTxes;
-    if (forWitness && !txesHaveWitnessCommit(transactions))
-      throw errorWitnessNotSegwit;
-
-    const hashes = transactions.map(transaction =>
-      transaction.getHash(forWitness!),
-    );
-
-    const rootHash = fastMerkleRoot(hashes, bcrypto.hash256);
-
-    return forWitness
-      ? bcrypto.hash256(
-          Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]),
-        )
-      : rootHash;
-  }
-
-  version: number = 1;
-  prevHash?: Buffer = undefined;
-  merkleRoot?: Buffer = undefined;
-  timestamp: number = 0;
-  witnessCommit?: Buffer = undefined;
-  bits: number = 0;
-  nonce: number = 0;
-  transactions?: Transaction[] = undefined;
-
-  getWitnessCommit(): Buffer | null {
-    if (!txesHaveWitnessCommit(this.transactions!)) return null;
-
-    // The merkle root for the witness data is in an OP_RETURN output.
-    // There is no rule for the index of the output, so use filter to find it.
-    // The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed
-    // If multiple commits are found, the output with highest index is assumed.
-    const witnessCommits = this.transactions![0].outs.filter(out =>
-      out.script.slice(0, 6).equals(Buffer.from('6a24aa21a9ed', 'hex')),
-    ).map(out => out.script.slice(6, 38));
-    if (witnessCommits.length === 0) return null;
-    // Use the commit with the highest output (should only be one though)
-    const result = witnessCommits[witnessCommits.length - 1];
-
-    if (!(result instanceof Buffer && result.length === 32)) return null;
-    return result;
-  }
-
-  hasWitnessCommit(): boolean {
-    if (
-      this.witnessCommit instanceof Buffer &&
-      this.witnessCommit.length === 32
-    )
-      return true;
-    if (this.getWitnessCommit() !== null) return true;
-    return false;
-  }
-
-  hasWitness(): boolean {
-    return anyTxHasWitness(this.transactions!);
-  }
-
-  weight(): number {
-    const base = this.byteLength(false, false);
-    const total = this.byteLength(false, true);
-    return base * 3 + total;
-  }
-
-  byteLength(headersOnly?: boolean, allowWitness: boolean = true): number {
-    if (headersOnly || !this.transactions) return 80;
-
-    return (
-      80 +
-      varuint.encodingLength(this.transactions.length) +
-      this.transactions.reduce((a, x) => a + x.byteLength(allowWitness), 0)
-    );
-  }
-
-  getHash(): Buffer {
-    return bcrypto.hash256(this.toBuffer(true));
-  }
-
-  getId(): string {
-    return reverseBuffer(this.getHash()).toString('hex');
-  }
-
-  getUTCDate(): Date {
-    const date = new Date(0); // epoch
-    date.setUTCSeconds(this.timestamp);
-
-    return date;
-  }
-
-  // TODO: buffer, offset compatibility
-  toBuffer(headersOnly?: boolean): Buffer {
-    const buffer: Buffer = Buffer.allocUnsafe(this.byteLength(headersOnly));
-
-    const bufferWriter = new BufferWriter(buffer);
-
-    bufferWriter.writeInt32(this.version);
-    bufferWriter.writeSlice(this.prevHash!);
-    bufferWriter.writeSlice(this.merkleRoot!);
-    bufferWriter.writeUInt32(this.timestamp);
-    bufferWriter.writeUInt32(this.bits);
-    bufferWriter.writeUInt32(this.nonce);
-
-    if (headersOnly || !this.transactions) return buffer;
-
-    varuint.encode(this.transactions.length, buffer, bufferWriter.offset);
-    bufferWriter.offset += varuint.encode.bytes;
-
-    this.transactions.forEach(tx => {
-      const txSize = tx.byteLength(); // TODO: extract from toBuffer?
-      tx.toBuffer(buffer, bufferWriter.offset);
-      bufferWriter.offset += txSize;
-    });
-
-    return buffer;
-  }
-
-  toHex(headersOnly?: boolean): string {
-    return this.toBuffer(headersOnly).toString('hex');
-  }
-
-  checkTxRoots(): boolean {
-    // If the Block has segwit transactions but no witness commit,
-    // there's no way it can be valid, so fail the check.
-    const hasWitnessCommit = this.hasWitnessCommit();
-    if (!hasWitnessCommit && this.hasWitness()) return false;
-    return (
-      this.__checkMerkleRoot() &&
-      (hasWitnessCommit ? this.__checkWitnessCommit() : true)
-    );
-  }
-
-  checkProofOfWork(): boolean {
-    const hash: Buffer = reverseBuffer(this.getHash());
-    const target = Block.calculateTarget(this.bits);
-
-    return hash.compare(target) <= 0;
-  }
-
-  private __checkMerkleRoot(): boolean {
-    if (!this.transactions) throw errorMerkleNoTxes;
-
-    const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions);
-    return this.merkleRoot!.compare(actualMerkleRoot) === 0;
-  }
-
-  private __checkWitnessCommit(): boolean {
-    if (!this.transactions) throw errorMerkleNoTxes;
-    if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit;
-
-    const actualWitnessCommit = Block.calculateMerkleRoot(
-      this.transactions,
-      true,
-    );
-    return this.witnessCommit!.compare(actualWitnessCommit) === 0;
-  }
-}
-
-function txesHaveWitnessCommit(transactions: Transaction[]): boolean {
-  return (
-    transactions instanceof Array &&
-    transactions[0] &&
-    transactions[0].ins &&
-    transactions[0].ins instanceof Array &&
-    transactions[0].ins[0] &&
-    transactions[0].ins[0].witness &&
-    transactions[0].ins[0].witness instanceof Array &&
-    transactions[0].ins[0].witness.length > 0
-  );
-}
-
-function anyTxHasWitness(transactions: Transaction[]): boolean {
-  return (
-    transactions instanceof Array &&
-    transactions.some(
-      tx =>
-        typeof tx === 'object' &&
-        tx.ins instanceof Array &&
-        tx.ins.some(
-          input =>
-            typeof input === 'object' &&
-            input.witness instanceof Array &&
-            input.witness.length > 0,
-        ),
-    )
-  );
-}
diff --git a/ts_src/bufferutils.ts b/ts_src/bufferutils.ts
deleted file mode 100644
index 901d72a..0000000
--- a/ts_src/bufferutils.ts
+++ /dev/null
@@ -1,172 +0,0 @@
-import * as types from './types';
-const { typeforce } = types;
-import * as varuint from 'varuint-bitcoin';
-export { varuint };
-
-// https://github.com/feross/buffer/blob/master/index.js#L1127
-function verifuint(value: number, max: number): void {
-  if (typeof value !== 'number')
-    throw new Error('cannot write a non-number as a number');
-  if (value < 0)
-    throw new Error('specified a negative value for writing an unsigned value');
-  if (value > max) throw new Error('RangeError: value out of range');
-  if (Math.floor(value) !== value)
-    throw new Error('value has a fractional component');
-}
-
-export function readUInt64LE(buffer: Buffer, offset: number): number {
-  const a = buffer.readUInt32LE(offset);
-  let b = buffer.readUInt32LE(offset + 4);
-  b *= 0x100000000;
-
-  verifuint(b + a, 0x001fffffffffffff);
-  return b + a;
-}
-
-export function writeUInt64LE(
-  buffer: Buffer,
-  value: number,
-  offset: number,
-): number {
-  verifuint(value, 0x001fffffffffffff);
-
-  buffer.writeInt32LE(value & -1, offset);
-  buffer.writeUInt32LE(Math.floor(value / 0x100000000), offset + 4);
-  return offset + 8;
-}
-
-export function reverseBuffer(buffer: Buffer): Buffer {
-  if (buffer.length < 1) return buffer;
-  let j = buffer.length - 1;
-  let tmp = 0;
-  for (let i = 0; i < buffer.length / 2; i++) {
-    tmp = buffer[i];
-    buffer[i] = buffer[j];
-    buffer[j] = tmp;
-    j--;
-  }
-  return buffer;
-}
-
-export function cloneBuffer(buffer: Buffer): Buffer {
-  const clone = Buffer.allocUnsafe(buffer.length);
-  buffer.copy(clone);
-  return clone;
-}
-
-/**
- * Helper class for serialization of bitcoin data types into a pre-allocated buffer.
- */
-export class BufferWriter {
-  static withCapacity(size: number): BufferWriter {
-    return new BufferWriter(Buffer.alloc(size));
-  }
-
-  constructor(public buffer: Buffer, public offset: number = 0) {
-    typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]);
-  }
-
-  writeUInt8(i: number): void {
-    this.offset = this.buffer.writeUInt8(i, this.offset);
-  }
-
-  writeInt32(i: number): void {
-    this.offset = this.buffer.writeInt32LE(i, this.offset);
-  }
-
-  writeUInt32(i: number): void {
-    this.offset = this.buffer.writeUInt32LE(i, this.offset);
-  }
-
-  writeUInt64(i: number): void {
-    this.offset = writeUInt64LE(this.buffer, i, this.offset);
-  }
-
-  writeVarInt(i: number): void {
-    varuint.encode(i, this.buffer, this.offset);
-    this.offset += varuint.encode.bytes;
-  }
-
-  writeSlice(slice: Buffer): void {
-    if (this.buffer.length < this.offset + slice.length) {
-      throw new Error('Cannot write slice out of bounds');
-    }
-    this.offset += slice.copy(this.buffer, this.offset);
-  }
-
-  writeVarSlice(slice: Buffer): void {
-    this.writeVarInt(slice.length);
-    this.writeSlice(slice);
-  }
-
-  writeVector(vector: Buffer[]): void {
-    this.writeVarInt(vector.length);
-    vector.forEach((buf: Buffer) => this.writeVarSlice(buf));
-  }
-
-  end(): Buffer {
-    if (this.buffer.length === this.offset) {
-      return this.buffer;
-    }
-    throw new Error(`buffer size ${this.buffer.length}, offset ${this.offset}`);
-  }
-}
-
-/**
- * Helper class for reading of bitcoin data types from a buffer.
- */
-export class BufferReader {
-  constructor(public buffer: Buffer, public offset: number = 0) {
-    typeforce(types.tuple(types.Buffer, types.UInt32), [buffer, offset]);
-  }
-
-  readUInt8(): number {
-    const result = this.buffer.readUInt8(this.offset);
-    this.offset++;
-    return result;
-  }
-
-  readInt32(): number {
-    const result = this.buffer.readInt32LE(this.offset);
-    this.offset += 4;
-    return result;
-  }
-
-  readUInt32(): number {
-    const result = this.buffer.readUInt32LE(this.offset);
-    this.offset += 4;
-    return result;
-  }
-
-  readUInt64(): number {
-    const result = readUInt64LE(this.buffer, this.offset);
-    this.offset += 8;
-    return result;
-  }
-
-  readVarInt(): number {
-    const vi = varuint.decode(this.buffer, this.offset);
-    this.offset += varuint.decode.bytes;
-    return vi;
-  }
-
-  readSlice(n: number): Buffer {
-    if (this.buffer.length < this.offset + n) {
-      throw new Error('Cannot read slice out of bounds');
-    }
-    const result = this.buffer.slice(this.offset, this.offset + n);
-    this.offset += n;
-    return result;
-  }
-
-  readVarSlice(): Buffer {
-    return this.readSlice(this.readVarInt());
-  }
-
-  readVector(): Buffer[] {
-    const count = this.readVarInt();
-    const vector: Buffer[] = [];
-    for (let i = 0; i < count; i++) vector.push(this.readVarSlice());
-    return vector;
-  }
-}
diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts
deleted file mode 100644
index b7c355a..0000000
--- a/ts_src/crypto.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import * as createHash from 'create-hash';
-
-export function ripemd160(buffer: Buffer): Buffer {
-  try {
-    return createHash('rmd160')
-      .update(buffer)
-      .digest();
-  } catch (err) {
-    return createHash('ripemd160')
-      .update(buffer)
-      .digest();
-  }
-}
-
-export function sha1(buffer: Buffer): Buffer {
-  return createHash('sha1')
-    .update(buffer)
-    .digest();
-}
-
-export function sha256(buffer: Buffer): Buffer {
-  return createHash('sha256')
-    .update(buffer)
-    .digest();
-}
-
-export function hash160(buffer: Buffer): Buffer {
-  return ripemd160(sha256(buffer));
-}
-
-export function hash256(buffer: Buffer): Buffer {
-  return sha256(sha256(buffer));
-}
-
-const TAGS = [
-  'BIP0340/challenge',
-  'BIP0340/aux',
-  'BIP0340/nonce',
-  'TapLeaf',
-  'TapBranch',
-  'TapSighash',
-  'TapTweak',
-  'KeyAgg list',
-  'KeyAgg coefficient',
-] as const;
-export type TaggedHashPrefix = typeof TAGS[number];
-/** An object mapping tags to their tagged hash prefix of [SHA256(tag) | SHA256(tag)] */
-const TAGGED_HASH_PREFIXES = Object.fromEntries(
-  TAGS.map(tag => {
-    const tagHash = sha256(Buffer.from(tag));
-    return [tag, Buffer.concat([tagHash, tagHash])];
-  }),
-) as { [k in TaggedHashPrefix]: Buffer };
-
-export function taggedHash(prefix: TaggedHashPrefix, data: Buffer): Buffer {
-  return sha256(Buffer.concat([TAGGED_HASH_PREFIXES[prefix], data]));
-}
diff --git a/ts_src/index.ts b/ts_src/index.ts
deleted file mode 100644
index d8b8619..0000000
--- a/ts_src/index.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import * as address from './address';
-import * as crypto from './crypto';
-import * as networks from './networks';
-import * as payments from './payments';
-import * as script from './script';
-
-export { address, crypto, networks, payments, script };
-
-export { Block } from './block';
-export { TaggedHashPrefix } from './crypto';
-export {
-  Psbt,
-  PsbtTxInput,
-  PsbtTxOutput,
-  Signer,
-  SignerAsync,
-  HDSigner,
-  HDSignerAsync,
-} from './psbt';
-export { OPS as opcodes } from './ops';
-export { Transaction } from './transaction';
-
-export { Network } from './networks';
-export {
-  Payment,
-  PaymentCreator,
-  PaymentOpts,
-  Stack,
-  StackElement,
-} from './payments';
-export { Input as TxInput, Output as TxOutput } from './transaction';
diff --git a/ts_src/merkle.ts b/ts_src/merkle.ts
deleted file mode 100644
index 8ff8c3f..0000000
--- a/ts_src/merkle.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-export function fastMerkleRoot(
-  values: Buffer[],
-  digestFn: (b: Buffer) => Buffer,
-): Buffer {
-  if (!Array.isArray(values)) throw TypeError('Expected values Array');
-  if (typeof digestFn !== 'function')
-    throw TypeError('Expected digest Function');
-
-  let length = values.length;
-  const results = values.concat();
-
-  while (length > 1) {
-    let j = 0;
-
-    for (let i = 0; i < length; i += 2, ++j) {
-      const left = results[i];
-      const right = i + 1 === length ? left : results[i + 1];
-      const data = Buffer.concat([left, right]);
-
-      results[j] = digestFn(data);
-    }
-
-    length = j;
-  }
-
-  return results[0];
-}
diff --git a/ts_src/networks.ts b/ts_src/networks.ts
deleted file mode 100644
index e66b08c..0000000
--- a/ts_src/networks.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-// https://en.bitcoin.it/wiki/List_of_address_prefixes
-// Dogecoin BIP32 is a proposed standard: https://bitcointalk.org/index.php?topic=409731
-export interface Network {
-  messagePrefix: string;
-  bech32: string;
-  bip32: Bip32;
-  pubKeyHash: number;
-  scriptHash: number;
-  wif: number;
-}
-
-interface Bip32 {
-  public: number;
-  private: number;
-}
-
-export const bitcoin: Network = {
-  messagePrefix: '\x18Bitcoin Signed Message:\n',
-  bech32: 'bc',
-  bip32: {
-    public: 0x0488b21e,
-    private: 0x0488ade4,
-  },
-  pubKeyHash: 0x00,
-  scriptHash: 0x05,
-  wif: 0x80,
-};
-export const regtest: Network = {
-  messagePrefix: '\x18Bitcoin Signed Message:\n',
-  bech32: 'bcrt',
-  bip32: {
-    public: 0x043587cf,
-    private: 0x04358394,
-  },
-  pubKeyHash: 0x6f,
-  scriptHash: 0xc4,
-  wif: 0xef,
-};
-export const testnet: Network = {
-  messagePrefix: '\x18Bitcoin Signed Message:\n',
-  bech32: 'tb',
-  bip32: {
-    public: 0x043587cf,
-    private: 0x04358394,
-  },
-  pubKeyHash: 0x6f,
-  scriptHash: 0xc4,
-  wif: 0xef,
-};
diff --git a/ts_src/ops.ts b/ts_src/ops.ts
deleted file mode 100644
index 8e2c41c..0000000
--- a/ts_src/ops.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-const OPS: { [key: string]: number } = {
-  OP_FALSE: 0,
-  OP_0: 0,
-  OP_PUSHDATA1: 76,
-  OP_PUSHDATA2: 77,
-  OP_PUSHDATA4: 78,
-  OP_1NEGATE: 79,
-  OP_RESERVED: 80,
-  OP_TRUE: 81,
-  OP_1: 81,
-  OP_2: 82,
-  OP_3: 83,
-  OP_4: 84,
-  OP_5: 85,
-  OP_6: 86,
-  OP_7: 87,
-  OP_8: 88,
-  OP_9: 89,
-  OP_10: 90,
-  OP_11: 91,
-  OP_12: 92,
-  OP_13: 93,
-  OP_14: 94,
-  OP_15: 95,
-  OP_16: 96,
-
-  OP_NOP: 97,
-  OP_VER: 98,
-  OP_IF: 99,
-  OP_NOTIF: 100,
-  OP_VERIF: 101,
-  OP_VERNOTIF: 102,
-  OP_ELSE: 103,
-  OP_ENDIF: 104,
-  OP_VERIFY: 105,
-  OP_RETURN: 106,
-
-  OP_TOALTSTACK: 107,
-  OP_FROMALTSTACK: 108,
-  OP_2DROP: 109,
-  OP_2DUP: 110,
-  OP_3DUP: 111,
-  OP_2OVER: 112,
-  OP_2ROT: 113,
-  OP_2SWAP: 114,
-  OP_IFDUP: 115,
-  OP_DEPTH: 116,
-  OP_DROP: 117,
-  OP_DUP: 118,
-  OP_NIP: 119,
-  OP_OVER: 120,
-  OP_PICK: 121,
-  OP_ROLL: 122,
-  OP_ROT: 123,
-  OP_SWAP: 124,
-  OP_TUCK: 125,
-
-  OP_CAT: 126,
-  OP_SUBSTR: 127,
-  OP_LEFT: 128,
-  OP_RIGHT: 129,
-  OP_SIZE: 130,
-
-  OP_INVERT: 131,
-  OP_AND: 132,
-  OP_OR: 133,
-  OP_XOR: 134,
-  OP_EQUAL: 135,
-  OP_EQUALVERIFY: 136,
-  OP_RESERVED1: 137,
-  OP_RESERVED2: 138,
-
-  OP_1ADD: 139,
-  OP_1SUB: 140,
-  OP_2MUL: 141,
-  OP_2DIV: 142,
-  OP_NEGATE: 143,
-  OP_ABS: 144,
-  OP_NOT: 145,
-  OP_0NOTEQUAL: 146,
-  OP_ADD: 147,
-  OP_SUB: 148,
-  OP_MUL: 149,
-  OP_DIV: 150,
-  OP_MOD: 151,
-  OP_LSHIFT: 152,
-  OP_RSHIFT: 153,
-
-  OP_BOOLAND: 154,
-  OP_BOOLOR: 155,
-  OP_NUMEQUAL: 156,
-  OP_NUMEQUALVERIFY: 157,
-  OP_NUMNOTEQUAL: 158,
-  OP_LESSTHAN: 159,
-  OP_GREATERTHAN: 160,
-  OP_LESSTHANOREQUAL: 161,
-  OP_GREATERTHANOREQUAL: 162,
-  OP_MIN: 163,
-  OP_MAX: 164,
-
-  OP_WITHIN: 165,
-
-  OP_RIPEMD160: 166,
-  OP_SHA1: 167,
-  OP_SHA256: 168,
-  OP_HASH160: 169,
-  OP_HASH256: 170,
-  OP_CODESEPARATOR: 171,
-  OP_CHECKSIG: 172,
-  OP_CHECKSIGVERIFY: 173,
-  OP_CHECKMULTISIG: 174,
-  OP_CHECKMULTISIGVERIFY: 175,
-
-  OP_NOP1: 176,
-
-  OP_NOP2: 177,
-  OP_CHECKLOCKTIMEVERIFY: 177,
-
-  OP_NOP3: 178,
-  OP_CHECKSEQUENCEVERIFY: 178,
-
-  OP_NOP4: 179,
-  OP_NOP5: 180,
-  OP_NOP6: 181,
-  OP_NOP7: 182,
-  OP_NOP8: 183,
-  OP_NOP9: 184,
-  OP_NOP10: 185,
-
-  OP_PUBKEYHASH: 253,
-  OP_PUBKEY: 254,
-  OP_INVALIDOPCODE: 255,
-};
-
-const REVERSE_OPS: { [key: number]: string } = {};
-for (const op of Object.keys(OPS)) {
-  const code = OPS[op];
-  REVERSE_OPS[code] = op;
-}
-
-export { OPS, REVERSE_OPS };
diff --git a/ts_src/payments/embed.ts b/ts_src/payments/embed.ts
deleted file mode 100644
index c479b89..0000000
--- a/ts_src/payments/embed.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { bitcoin as BITCOIN_NETWORK } from '../networks';
-import * as bscript from '../script';
-import { typeforce as typef } from '../types';
-import { Payment, PaymentOpts, Stack } from './index';
-import * as lazy from './lazy';
-
-const OPS = bscript.OPS;
-
-function stacksEqual(a: Buffer[], b: Buffer[]): boolean {
-  if (a.length !== b.length) return false;
-
-  return a.every((x, i) => {
-    return x.equals(b[i]);
-  });
-}
-
-// output: OP_RETURN ...
-export function p2data(a: Payment, opts?: PaymentOpts): Payment {
-  if (!a.data && !a.output) throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-
-  typef(
-    {
-      network: typef.maybe(typef.Object),
-      output: typef.maybe(typef.Buffer),
-      data: typef.maybe(typef.arrayOf(typef.Buffer)),
-    },
-    a,
-  );
-
-  const network = a.network || BITCOIN_NETWORK;
-  const o = { name: 'embed', network } as Payment;
-
-  lazy.prop(o, 'output', () => {
-    if (!a.data) return;
-    return bscript.compile(([OPS.OP_RETURN] as Stack).concat(a.data));
-  });
-  lazy.prop(o, 'data', () => {
-    if (!a.output) return;
-    return bscript.decompile(a.output)!.slice(1);
-  });
-
-  // extended validation
-  if (opts.validate) {
-    if (a.output) {
-      const chunks = bscript.decompile(a.output);
-      if (chunks![0] !== OPS.OP_RETURN)
-        throw new TypeError('Output is invalid');
-      if (!chunks!.slice(1).every(typef.Buffer))
-        throw new TypeError('Output is invalid');
-
-      if (a.data && !stacksEqual(a.data, o.data as Buffer[]))
-        throw new TypeError('Data mismatch');
-    }
-  }
-
-  return Object.assign(o, a);
-}
diff --git a/ts_src/payments/index.ts b/ts_src/payments/index.ts
deleted file mode 100644
index 4b7f111..0000000
--- a/ts_src/payments/index.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { Network } from '../networks';
-import { p2data as embed } from './embed';
-import { p2ms } from './p2ms';
-import { p2pk } from './p2pk';
-import { p2pkh } from './p2pkh';
-import { p2sh } from './p2sh';
-import { p2wpkh } from './p2wpkh';
-import { p2wsh } from './p2wsh';
-
-export interface Payment {
-  name?: string;
-  network?: Network;
-  output?: Buffer;
-  data?: Buffer[];
-  m?: number;
-  n?: number;
-  pubkeys?: Buffer[];
-  input?: Buffer;
-  signatures?: Buffer[];
-  pubkey?: Buffer;
-  signature?: Buffer;
-  address?: string;
-  hash?: Buffer;
-  redeem?: Payment;
-  witness?: Buffer[];
-}
-
-export type PaymentCreator = (a: Payment, opts?: PaymentOpts) => Payment;
-
-export type PaymentFunction = () => Payment;
-
-export interface PaymentOpts {
-  validate?: boolean;
-  allowIncomplete?: boolean;
-}
-
-export type StackElement = Buffer | number;
-export type Stack = StackElement[];
-export type StackFunction = () => Stack;
-
-export { embed, p2ms, p2pk, p2pkh, p2sh, p2wpkh, p2wsh };
-
-// TODO
-// witness commitment
diff --git a/ts_src/payments/lazy.ts b/ts_src/payments/lazy.ts
deleted file mode 100644
index 1df181f..0000000
--- a/ts_src/payments/lazy.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-export function prop(object: {}, name: string, f: () => any): void {
-  Object.defineProperty(object, name, {
-    configurable: true,
-    enumerable: true,
-    get(): any {
-      const _value = f.call(this);
-      this[name] = _value;
-      return _value;
-    },
-    set(_value: any): void {
-      Object.defineProperty(this, name, {
-        configurable: true,
-        enumerable: true,
-        value: _value,
-        writable: true,
-      });
-    },
-  });
-}
-
-export function value<T>(f: () => T): () => T {
-  let _value: T;
-  return (): T => {
-    if (_value !== undefined) return _value;
-    _value = f();
-    return _value;
-  };
-}
diff --git a/ts_src/payments/p2ms.ts b/ts_src/payments/p2ms.ts
deleted file mode 100644
index eaa1440..0000000
--- a/ts_src/payments/p2ms.ts
+++ /dev/null
@@ -1,161 +0,0 @@
-import { bitcoin as BITCOIN_NETWORK } from '../networks';
-import * as bscript from '../script';
-import { isPoint, typeforce as typef } from '../types';
-import { Payment, PaymentOpts, Stack } from './index';
-import * as lazy from './lazy';
-const OPS = bscript.OPS;
-
-const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1
-
-function stacksEqual(a: Buffer[], b: Buffer[]): boolean {
-  if (a.length !== b.length) return false;
-
-  return a.every((x, i) => {
-    return x.equals(b[i]);
-  });
-}
-
-// input: OP_0 [signatures ...]
-// output: m [pubKeys ...] n OP_CHECKMULTISIG
-export function p2ms(a: Payment, opts?: PaymentOpts): Payment {
-  if (
-    !a.input &&
-    !a.output &&
-    !(a.pubkeys && a.m !== undefined) &&
-    !a.signatures
-  )
-    throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-
-  function isAcceptableSignature(x: Buffer | number): boolean {
-    return (
-      bscript.isCanonicalScriptSignature(x as Buffer) ||
-      (opts!.allowIncomplete && (x as number) === OPS.OP_0) !== undefined
-    );
-  }
-
-  typef(
-    {
-      network: typef.maybe(typef.Object),
-      m: typef.maybe(typef.Number),
-      n: typef.maybe(typef.Number),
-      output: typef.maybe(typef.Buffer),
-      pubkeys: typef.maybe(typef.arrayOf(isPoint)),
-
-      signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)),
-      input: typef.maybe(typef.Buffer),
-    },
-    a,
-  );
-
-  const network = a.network || BITCOIN_NETWORK;
-  const o: Payment = { network };
-
-  let chunks: Stack = [];
-  let decoded = false;
-  function decode(output: Buffer | Stack): void {
-    if (decoded) return;
-    decoded = true;
-    chunks = bscript.decompile(output) as Stack;
-    o.m = (chunks[0] as number) - OP_INT_BASE;
-    o.n = (chunks[chunks.length - 2] as number) - OP_INT_BASE;
-    o.pubkeys = chunks.slice(1, -2) as Buffer[];
-  }
-
-  lazy.prop(o, 'output', () => {
-    if (!a.m) return;
-    if (!o.n) return;
-    if (!a.pubkeys) return;
-    return bscript.compile(
-      ([] as Stack).concat(
-        OP_INT_BASE + a.m,
-        a.pubkeys,
-        OP_INT_BASE + o.n,
-        OPS.OP_CHECKMULTISIG,
-      ),
-    );
-  });
-  lazy.prop(o, 'm', () => {
-    if (!o.output) return;
-    decode(o.output);
-    return o.m;
-  });
-  lazy.prop(o, 'n', () => {
-    if (!o.pubkeys) return;
-    return o.pubkeys.length;
-  });
-  lazy.prop(o, 'pubkeys', () => {
-    if (!a.output) return;
-    decode(a.output);
-    return o.pubkeys;
-  });
-  lazy.prop(o, 'signatures', () => {
-    if (!a.input) return;
-    return bscript.decompile(a.input)!.slice(1);
-  });
-  lazy.prop(o, 'input', () => {
-    if (!a.signatures) return;
-    return bscript.compile(([OPS.OP_0] as Stack).concat(a.signatures));
-  });
-  lazy.prop(o, 'witness', () => {
-    if (!o.input) return;
-    return [];
-  });
-  lazy.prop(o, 'name', () => {
-    if (!o.m || !o.n) return;
-    return `p2ms(${o.m} of ${o.n})`;
-  });
-
-  // extended validation
-  if (opts.validate) {
-    if (a.output) {
-      decode(a.output);
-      if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid');
-      if (!typef.Number(chunks[chunks.length - 2]))
-        throw new TypeError('Output is invalid');
-      if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG)
-        throw new TypeError('Output is invalid');
-
-      if (o.m! <= 0 || o.n! > 16 || o.m! > o.n! || o.n !== chunks.length - 3)
-        throw new TypeError('Output is invalid');
-      if (!o.pubkeys!.every(x => isPoint(x)))
-        throw new TypeError('Output is invalid');
-
-      if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch');
-      if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch');
-      if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys!))
-        throw new TypeError('Pubkeys mismatch');
-    }
-
-    if (a.pubkeys) {
-      if (a.n !== undefined && a.n !== a.pubkeys.length)
-        throw new TypeError('Pubkey count mismatch');
-      o.n = a.pubkeys.length;
-
-      if (o.n < o.m!) throw new TypeError('Pubkey count cannot be less than m');
-    }
-
-    if (a.signatures) {
-      if (a.signatures.length < o.m!)
-        throw new TypeError('Not enough signatures provided');
-      if (a.signatures.length > o.m!)
-        throw new TypeError('Too many signatures provided');
-    }
-
-    if (a.input) {
-      if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid');
-      if (
-        o.signatures!.length === 0 ||
-        !o.signatures!.every(isAcceptableSignature)
-      )
-        throw new TypeError('Input has invalid signature(s)');
-
-      if (a.signatures && !stacksEqual(a.signatures, o.signatures!))
-        throw new TypeError('Signature mismatch');
-      if (a.m !== undefined && a.m !== a.signatures!.length)
-        throw new TypeError('Signature count mismatch');
-    }
-  }
-
-  return Object.assign(o, a);
-}
diff --git a/ts_src/payments/p2pk.ts b/ts_src/payments/p2pk.ts
deleted file mode 100644
index 7273f53..0000000
--- a/ts_src/payments/p2pk.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import { bitcoin as BITCOIN_NETWORK } from '../networks';
-import * as bscript from '../script';
-import { isPoint, typeforce as typef } from '../types';
-import { Payment, PaymentOpts, StackFunction } from './index';
-import * as lazy from './lazy';
-const OPS = bscript.OPS;
-
-// input: {signature}
-// output: {pubKey} OP_CHECKSIG
-export function p2pk(a: Payment, opts?: PaymentOpts): Payment {
-  if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature)
-    throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-
-  typef(
-    {
-      network: typef.maybe(typef.Object),
-      output: typef.maybe(typef.Buffer),
-      pubkey: typef.maybe(isPoint),
-
-      signature: typef.maybe(bscript.isCanonicalScriptSignature),
-      input: typef.maybe(typef.Buffer),
-    },
-    a,
-  );
-
-  const _chunks = lazy.value(() => {
-    return bscript.decompile(a.input!);
-  }) as StackFunction;
-
-  const network = a.network || BITCOIN_NETWORK;
-  const o: Payment = { name: 'p2pk', network };
-
-  lazy.prop(o, 'output', () => {
-    if (!a.pubkey) return;
-    return bscript.compile([a.pubkey, OPS.OP_CHECKSIG]);
-  });
-  lazy.prop(o, 'pubkey', () => {
-    if (!a.output) return;
-    return a.output.slice(1, -1);
-  });
-  lazy.prop(o, 'signature', () => {
-    if (!a.input) return;
-    return _chunks()[0] as Buffer;
-  });
-  lazy.prop(o, 'input', () => {
-    if (!a.signature) return;
-    return bscript.compile([a.signature]);
-  });
-  lazy.prop(o, 'witness', () => {
-    if (!o.input) return;
-    return [];
-  });
-
-  // extended validation
-  if (opts.validate) {
-    if (a.output) {
-      if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG)
-        throw new TypeError('Output is invalid');
-      if (!isPoint(o.pubkey)) throw new TypeError('Output pubkey is invalid');
-      if (a.pubkey && !a.pubkey.equals(o.pubkey!))
-        throw new TypeError('Pubkey mismatch');
-    }
-
-    if (a.signature) {
-      if (a.input && !a.input.equals(o.input!))
-        throw new TypeError('Signature mismatch');
-    }
-
-    if (a.input) {
-      if (_chunks().length !== 1) throw new TypeError('Input is invalid');
-      if (!bscript.isCanonicalScriptSignature(o.signature!))
-        throw new TypeError('Input has invalid signature');
-    }
-  }
-
-  return Object.assign(o, a);
-}
diff --git a/ts_src/payments/p2pkh.ts b/ts_src/payments/p2pkh.ts
deleted file mode 100644
index 3b5bd6f..0000000
--- a/ts_src/payments/p2pkh.ts
+++ /dev/null
@@ -1,144 +0,0 @@
-import * as bcrypto from '../crypto';
-import { bitcoin as BITCOIN_NETWORK } from '../networks';
-import * as bscript from '../script';
-import { isPoint, typeforce as typef } from '../types';
-import { Payment, PaymentOpts, StackFunction } from './index';
-import * as lazy from './lazy';
-import * as bs58check from 'bs58check';
-const OPS = bscript.OPS;
-
-// input: {signature} {pubkey}
-// output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG
-export function p2pkh(a: Payment, opts?: PaymentOpts): Payment {
-  if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input)
-    throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-
-  typef(
-    {
-      network: typef.maybe(typef.Object),
-      address: typef.maybe(typef.String),
-      hash: typef.maybe(typef.BufferN(20)),
-      output: typef.maybe(typef.BufferN(25)),
-
-      pubkey: typef.maybe(isPoint),
-      signature: typef.maybe(bscript.isCanonicalScriptSignature),
-      input: typef.maybe(typef.Buffer),
-    },
-    a,
-  );
-
-  const _address = lazy.value(() => {
-    const payload = bs58check.decode(a.address!);
-    const version = payload.readUInt8(0);
-    const hash = payload.slice(1);
-    return { version, hash };
-  });
-  const _chunks = lazy.value(() => {
-    return bscript.decompile(a.input!);
-  }) as StackFunction;
-
-  const network = a.network || BITCOIN_NETWORK;
-  const o: Payment = { name: 'p2pkh', network };
-
-  lazy.prop(o, 'address', () => {
-    if (!o.hash) return;
-
-    const payload = Buffer.allocUnsafe(21);
-    payload.writeUInt8(network.pubKeyHash, 0);
-    o.hash.copy(payload, 1);
-    return bs58check.encode(payload);
-  });
-  lazy.prop(o, 'hash', () => {
-    if (a.output) return a.output.slice(3, 23);
-    if (a.address) return _address().hash;
-    if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey! || o.pubkey!);
-  });
-  lazy.prop(o, 'output', () => {
-    if (!o.hash) return;
-    return bscript.compile([
-      OPS.OP_DUP,
-      OPS.OP_HASH160,
-      o.hash,
-      OPS.OP_EQUALVERIFY,
-      OPS.OP_CHECKSIG,
-    ]);
-  });
-  lazy.prop(o, 'pubkey', () => {
-    if (!a.input) return;
-    return _chunks()[1] as Buffer;
-  });
-  lazy.prop(o, 'signature', () => {
-    if (!a.input) return;
-    return _chunks()[0] as Buffer;
-  });
-  lazy.prop(o, 'input', () => {
-    if (!a.pubkey) return;
-    if (!a.signature) return;
-    return bscript.compile([a.signature, a.pubkey]);
-  });
-  lazy.prop(o, 'witness', () => {
-    if (!o.input) return;
-    return [];
-  });
-
-  // extended validation
-  if (opts.validate) {
-    let hash: Buffer = Buffer.from([]);
-    if (a.address) {
-      if (_address().version !== network.pubKeyHash)
-        throw new TypeError('Invalid version or Network mismatch');
-      if (_address().hash.length !== 20) throw new TypeError('Invalid address');
-      hash = _address().hash;
-    }
-
-    if (a.hash) {
-      if (hash.length > 0 && !hash.equals(a.hash))
-        throw new TypeError('Hash mismatch');
-      else hash = a.hash;
-    }
-
-    if (a.output) {
-      if (
-        a.output.length !== 25 ||
-        a.output[0] !== OPS.OP_DUP ||
-        a.output[1] !== OPS.OP_HASH160 ||
-        a.output[2] !== 0x14 ||
-        a.output[23] !== OPS.OP_EQUALVERIFY ||
-        a.output[24] !== OPS.OP_CHECKSIG
-      )
-        throw new TypeError('Output is invalid');
-
-      const hash2 = a.output.slice(3, 23);
-      if (hash.length > 0 && !hash.equals(hash2))
-        throw new TypeError('Hash mismatch');
-      else hash = hash2;
-    }
-
-    if (a.pubkey) {
-      const pkh = bcrypto.hash160(a.pubkey);
-      if (hash.length > 0 && !hash.equals(pkh))
-        throw new TypeError('Hash mismatch');
-      else hash = pkh;
-    }
-
-    if (a.input) {
-      const chunks = _chunks();
-      if (chunks.length !== 2) throw new TypeError('Input is invalid');
-      if (!bscript.isCanonicalScriptSignature(chunks[0] as Buffer))
-        throw new TypeError('Input has invalid signature');
-      if (!isPoint(chunks[1])) throw new TypeError('Input has invalid pubkey');
-
-      if (a.signature && !a.signature.equals(chunks[0] as Buffer))
-        throw new TypeError('Signature mismatch');
-      if (a.pubkey && !a.pubkey.equals(chunks[1] as Buffer))
-        throw new TypeError('Pubkey mismatch');
-
-      const pkh = bcrypto.hash160(chunks[1] as Buffer);
-      if (hash.length > 0 && !hash.equals(pkh))
-        throw new TypeError('Hash mismatch');
-    }
-  }
-
-  return Object.assign(o, a);
-}
diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts
deleted file mode 100644
index 9be5a8c..0000000
--- a/ts_src/payments/p2sh.ts
+++ /dev/null
@@ -1,218 +0,0 @@
-import * as bcrypto from '../crypto';
-import { bitcoin as BITCOIN_NETWORK } from '../networks';
-import * as bscript from '../script';
-import { typeforce as typef } from '../types';
-import {
-  Payment,
-  PaymentFunction,
-  PaymentOpts,
-  Stack,
-  StackFunction,
-} from './index';
-import * as lazy from './lazy';
-import * as bs58check from 'bs58check';
-const OPS = bscript.OPS;
-
-function stacksEqual(a: Buffer[], b: Buffer[]): boolean {
-  if (a.length !== b.length) return false;
-
-  return a.every((x, i) => {
-    return x.equals(b[i]);
-  });
-}
-
-// input: [redeemScriptSig ...] {redeemScript}
-// witness: <?>
-// output: OP_HASH160 {hash160(redeemScript)} OP_EQUAL
-export function p2sh(a: Payment, opts?: PaymentOpts): Payment {
-  if (!a.address && !a.hash && !a.output && !a.redeem && !a.input)
-    throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-
-  typef(
-    {
-      network: typef.maybe(typef.Object),
-
-      address: typef.maybe(typef.String),
-      hash: typef.maybe(typef.BufferN(20)),
-      output: typef.maybe(typef.BufferN(23)),
-
-      redeem: typef.maybe({
-        network: typef.maybe(typef.Object),
-        output: typef.maybe(typef.Buffer),
-        input: typef.maybe(typef.Buffer),
-        witness: typef.maybe(typef.arrayOf(typef.Buffer)),
-      }),
-      input: typef.maybe(typef.Buffer),
-      witness: typef.maybe(typef.arrayOf(typef.Buffer)),
-    },
-    a,
-  );
-
-  let network = a.network;
-  if (!network) {
-    network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK;
-  }
-
-  const o: Payment = { network };
-
-  const _address = lazy.value(() => {
-    const payload = bs58check.decode(a.address!);
-    const version = payload.readUInt8(0);
-    const hash = payload.slice(1);
-    return { version, hash };
-  });
-  const _chunks = lazy.value(() => {
-    return bscript.decompile(a.input!);
-  }) as StackFunction;
-  const _redeem = lazy.value(
-    (): Payment => {
-      const chunks = _chunks();
-      return {
-        network,
-        output: chunks[chunks.length - 1] as Buffer,
-        input: bscript.compile(chunks.slice(0, -1)),
-        witness: a.witness || [],
-      };
-    },
-  ) as PaymentFunction;
-
-  // output dependents
-  lazy.prop(o, 'address', () => {
-    if (!o.hash) return;
-
-    const payload = Buffer.allocUnsafe(21);
-    payload.writeUInt8(o.network!.scriptHash, 0);
-    o.hash.copy(payload, 1);
-    return bs58check.encode(payload);
-  });
-  lazy.prop(o, 'hash', () => {
-    // in order of least effort
-    if (a.output) return a.output.slice(2, 22);
-    if (a.address) return _address().hash;
-    if (o.redeem && o.redeem.output) return bcrypto.hash160(o.redeem.output);
-  });
-  lazy.prop(o, 'output', () => {
-    if (!o.hash) return;
-    return bscript.compile([OPS.OP_HASH160, o.hash, OPS.OP_EQUAL]);
-  });
-
-  // input dependents
-  lazy.prop(o, 'redeem', () => {
-    if (!a.input) return;
-    return _redeem();
-  });
-  lazy.prop(o, 'input', () => {
-    if (!a.redeem || !a.redeem.input || !a.redeem.output) return;
-    return bscript.compile(
-      ([] as Stack).concat(
-        bscript.decompile(a.redeem.input) as Stack,
-        a.redeem.output,
-      ),
-    );
-  });
-  lazy.prop(o, 'witness', () => {
-    if (o.redeem && o.redeem.witness) return o.redeem.witness;
-    if (o.input) return [];
-  });
-  lazy.prop(o, 'name', () => {
-    const nameParts = ['p2sh'];
-    if (o.redeem !== undefined && o.redeem.name !== undefined)
-      nameParts.push(o.redeem.name!);
-    return nameParts.join('-');
-  });
-
-  if (opts.validate) {
-    let hash: Buffer = Buffer.from([]);
-    if (a.address) {
-      if (_address().version !== network.scriptHash)
-        throw new TypeError('Invalid version or Network mismatch');
-      if (_address().hash.length !== 20) throw new TypeError('Invalid address');
-      hash = _address().hash;
-    }
-
-    if (a.hash) {
-      if (hash.length > 0 && !hash.equals(a.hash))
-        throw new TypeError('Hash mismatch');
-      else hash = a.hash;
-    }
-
-    if (a.output) {
-      if (
-        a.output.length !== 23 ||
-        a.output[0] !== OPS.OP_HASH160 ||
-        a.output[1] !== 0x14 ||
-        a.output[22] !== OPS.OP_EQUAL
-      )
-        throw new TypeError('Output is invalid');
-
-      const hash2 = a.output.slice(2, 22);
-      if (hash.length > 0 && !hash.equals(hash2))
-        throw new TypeError('Hash mismatch');
-      else hash = hash2;
-    }
-
-    // inlined to prevent 'no-inner-declarations' failing
-    const checkRedeem = (redeem: Payment): void => {
-      // is the redeem output empty/invalid?
-      if (redeem.output) {
-        const decompile = bscript.decompile(redeem.output);
-        if (!decompile || decompile.length < 1)
-          throw new TypeError('Redeem.output too short');
-
-        // match hash against other sources
-        const hash2 = bcrypto.hash160(redeem.output);
-        if (hash.length > 0 && !hash.equals(hash2))
-          throw new TypeError('Hash mismatch');
-        else hash = hash2;
-      }
-
-      if (redeem.input) {
-        const hasInput = redeem.input.length > 0;
-        const hasWitness = redeem.witness && redeem.witness.length > 0;
-        if (!hasInput && !hasWitness) throw new TypeError('Empty input');
-        if (hasInput && hasWitness)
-          throw new TypeError('Input and witness provided');
-        if (hasInput) {
-          const richunks = bscript.decompile(redeem.input) as Stack;
-          if (!bscript.isPushOnly(richunks))
-            throw new TypeError('Non push-only scriptSig');
-        }
-      }
-    };
-
-    if (a.input) {
-      const chunks = _chunks();
-      if (!chunks || chunks.length < 1) throw new TypeError('Input too short');
-      if (!Buffer.isBuffer(_redeem().output))
-        throw new TypeError('Input is invalid');
-
-      checkRedeem(_redeem());
-    }
-
-    if (a.redeem) {
-      if (a.redeem.network && a.redeem.network !== network)
-        throw new TypeError('Network mismatch');
-      if (a.input) {
-        const redeem = _redeem();
-        if (a.redeem.output && !a.redeem.output.equals(redeem.output!))
-          throw new TypeError('Redeem.output mismatch');
-        if (a.redeem.input && !a.redeem.input.equals(redeem.input!))
-          throw new TypeError('Redeem.input mismatch');
-      }
-
-      checkRedeem(a.redeem);
-    }
-
-    if (a.witness) {
-      if (
-        a.redeem &&
-        a.redeem.witness &&
-        !stacksEqual(a.redeem.witness, a.witness)
-      )
-        throw new TypeError('Witness and redeem.witness mismatch');
-    }
-  }
-
-  return Object.assign(o, a);
-}
diff --git a/ts_src/payments/p2wpkh.ts b/ts_src/payments/p2wpkh.ts
deleted file mode 100644
index a4497fe..0000000
--- a/ts_src/payments/p2wpkh.ts
+++ /dev/null
@@ -1,142 +0,0 @@
-import * as bcrypto from '../crypto';
-import { bitcoin as BITCOIN_NETWORK } from '../networks';
-import * as bscript from '../script';
-import { isPoint, typeforce as typef } from '../types';
-import { Payment, PaymentOpts } from './index';
-import * as lazy from './lazy';
-import { bech32 } from 'bech32';
-const OPS = bscript.OPS;
-
-const EMPTY_BUFFER = Buffer.alloc(0);
-
-// witness: {signature} {pubKey}
-// input: <>
-// output: OP_0 {pubKeyHash}
-export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment {
-  if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness)
-    throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-
-  typef(
-    {
-      address: typef.maybe(typef.String),
-      hash: typef.maybe(typef.BufferN(20)),
-      input: typef.maybe(typef.BufferN(0)),
-      network: typef.maybe(typef.Object),
-      output: typef.maybe(typef.BufferN(22)),
-      pubkey: typef.maybe(isPoint),
-      signature: typef.maybe(bscript.isCanonicalScriptSignature),
-      witness: typef.maybe(typef.arrayOf(typef.Buffer)),
-    },
-    a,
-  );
-
-  const _address = lazy.value(() => {
-    const result = bech32.decode(a.address!);
-    const version = result.words.shift();
-    const data = bech32.fromWords(result.words);
-    return {
-      version,
-      prefix: result.prefix,
-      data: Buffer.from(data),
-    };
-  });
-
-  const network = a.network || BITCOIN_NETWORK;
-  const o: Payment = { name: 'p2wpkh', network };
-
-  lazy.prop(o, 'address', () => {
-    if (!o.hash) return;
-
-    const words = bech32.toWords(o.hash);
-    words.unshift(0x00);
-    return bech32.encode(network.bech32, words);
-  });
-  lazy.prop(o, 'hash', () => {
-    if (a.output) return a.output.slice(2, 22);
-    if (a.address) return _address().data;
-    if (a.pubkey || o.pubkey) return bcrypto.hash160(a.pubkey! || o.pubkey!);
-  });
-  lazy.prop(o, 'output', () => {
-    if (!o.hash) return;
-    return bscript.compile([OPS.OP_0, o.hash]);
-  });
-  lazy.prop(o, 'pubkey', () => {
-    if (a.pubkey) return a.pubkey;
-    if (!a.witness) return;
-    return a.witness[1];
-  });
-  lazy.prop(o, 'signature', () => {
-    if (!a.witness) return;
-    return a.witness[0];
-  });
-  lazy.prop(o, 'input', () => {
-    if (!o.witness) return;
-    return EMPTY_BUFFER;
-  });
-  lazy.prop(o, 'witness', () => {
-    if (!a.pubkey) return;
-    if (!a.signature) return;
-    return [a.signature, a.pubkey];
-  });
-
-  // extended validation
-  if (opts.validate) {
-    let hash: Buffer = Buffer.from([]);
-    if (a.address) {
-      if (network && network.bech32 !== _address().prefix)
-        throw new TypeError('Invalid prefix or Network mismatch');
-      if (_address().version !== 0x00)
-        throw new TypeError('Invalid address version');
-      if (_address().data.length !== 20)
-        throw new TypeError('Invalid address data');
-      hash = _address().data;
-    }
-
-    if (a.hash) {
-      if (hash.length > 0 && !hash.equals(a.hash))
-        throw new TypeError('Hash mismatch');
-      else hash = a.hash;
-    }
-
-    if (a.output) {
-      if (
-        a.output.length !== 22 ||
-        a.output[0] !== OPS.OP_0 ||
-        a.output[1] !== 0x14
-      )
-        throw new TypeError('Output is invalid');
-      if (hash.length > 0 && !hash.equals(a.output.slice(2)))
-        throw new TypeError('Hash mismatch');
-      else hash = a.output.slice(2);
-    }
-
-    if (a.pubkey) {
-      const pkh = bcrypto.hash160(a.pubkey);
-      if (hash.length > 0 && !hash.equals(pkh))
-        throw new TypeError('Hash mismatch');
-      else hash = pkh;
-      if (!isPoint(a.pubkey) || a.pubkey.length !== 33)
-        throw new TypeError('Invalid pubkey for p2wpkh');
-    }
-
-    if (a.witness) {
-      if (a.witness.length !== 2) throw new TypeError('Witness is invalid');
-      if (!bscript.isCanonicalScriptSignature(a.witness[0]))
-        throw new TypeError('Witness has invalid signature');
-      if (!isPoint(a.witness[1]) || a.witness[1].length !== 33)
-        throw new TypeError('Witness has invalid pubkey');
-
-      if (a.signature && !a.signature.equals(a.witness[0]))
-        throw new TypeError('Signature mismatch');
-      if (a.pubkey && !a.pubkey.equals(a.witness[1]))
-        throw new TypeError('Pubkey mismatch');
-
-      const pkh = bcrypto.hash160(a.witness[1]);
-      if (hash.length > 0 && !hash.equals(pkh))
-        throw new TypeError('Hash mismatch');
-    }
-  }
-
-  return Object.assign(o, a);
-}
diff --git a/ts_src/payments/p2wsh.ts b/ts_src/payments/p2wsh.ts
deleted file mode 100644
index 00860e0..0000000
--- a/ts_src/payments/p2wsh.ts
+++ /dev/null
@@ -1,229 +0,0 @@
-import * as bcrypto from '../crypto';
-import { bitcoin as BITCOIN_NETWORK } from '../networks';
-import * as bscript from '../script';
-import { isPoint, typeforce as typef } from '../types';
-import { Payment, PaymentOpts, StackElement, StackFunction } from './index';
-import * as lazy from './lazy';
-import { bech32 } from 'bech32';
-const OPS = bscript.OPS;
-
-const EMPTY_BUFFER = Buffer.alloc(0);
-
-function stacksEqual(a: Buffer[], b: Buffer[]): boolean {
-  if (a.length !== b.length) return false;
-
-  return a.every((x, i) => {
-    return x.equals(b[i]);
-  });
-}
-
-function chunkHasUncompressedPubkey(chunk: StackElement): boolean {
-  if (
-    Buffer.isBuffer(chunk) &&
-    chunk.length === 65 &&
-    chunk[0] === 0x04 &&
-    isPoint(chunk)
-  ) {
-    return true;
-  } else {
-    return false;
-  }
-}
-
-// input: <>
-// witness: [redeemScriptSig ...] {redeemScript}
-// output: OP_0 {sha256(redeemScript)}
-export function p2wsh(a: Payment, opts?: PaymentOpts): Payment {
-  if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness)
-    throw new TypeError('Not enough data');
-  opts = Object.assign({ validate: true }, opts || {});
-
-  typef(
-    {
-      network: typef.maybe(typef.Object),
-
-      address: typef.maybe(typef.String),
-      hash: typef.maybe(typef.BufferN(32)),
-      output: typef.maybe(typef.BufferN(34)),
-
-      redeem: typef.maybe({
-        input: typef.maybe(typef.Buffer),
-        network: typef.maybe(typef.Object),
-        output: typef.maybe(typef.Buffer),
-        witness: typef.maybe(typef.arrayOf(typef.Buffer)),
-      }),
-      input: typef.maybe(typef.BufferN(0)),
-      witness: typef.maybe(typef.arrayOf(typef.Buffer)),
-    },
-    a,
-  );
-
-  const _address = lazy.value(() => {
-    const result = bech32.decode(a.address!);
-    const version = result.words.shift();
-    const data = bech32.fromWords(result.words);
-    return {
-      version,
-      prefix: result.prefix,
-      data: Buffer.from(data),
-    };
-  });
-  const _rchunks = lazy.value(() => {
-    return bscript.decompile(a.redeem!.input!);
-  }) as StackFunction;
-
-  let network = a.network;
-  if (!network) {
-    network = (a.redeem && a.redeem.network) || BITCOIN_NETWORK;
-  }
-
-  const o: Payment = { network };
-
-  lazy.prop(o, 'address', () => {
-    if (!o.hash) return;
-    const words = bech32.toWords(o.hash);
-    words.unshift(0x00);
-    return bech32.encode(network!.bech32, words);
-  });
-  lazy.prop(o, 'hash', () => {
-    if (a.output) return a.output.slice(2);
-    if (a.address) return _address().data;
-    if (o.redeem && o.redeem.output) return bcrypto.sha256(o.redeem.output);
-  });
-  lazy.prop(o, 'output', () => {
-    if (!o.hash) return;
-    return bscript.compile([OPS.OP_0, o.hash]);
-  });
-  lazy.prop(o, 'redeem', () => {
-    if (!a.witness) return;
-    return {
-      output: a.witness[a.witness.length - 1],
-      input: EMPTY_BUFFER,
-      witness: a.witness.slice(0, -1),
-    };
-  });
-  lazy.prop(o, 'input', () => {
-    if (!o.witness) return;
-    return EMPTY_BUFFER;
-  });
-  lazy.prop(o, 'witness', () => {
-    // transform redeem input to witness stack?
-    if (
-      a.redeem &&
-      a.redeem.input &&
-      a.redeem.input.length > 0 &&
-      a.redeem.output &&
-      a.redeem.output.length > 0
-    ) {
-      const stack = bscript.toStack(_rchunks());
-
-      // assign, and blank the existing input
-      o.redeem = Object.assign({ witness: stack }, a.redeem);
-      o.redeem.input = EMPTY_BUFFER;
-      return ([] as Buffer[]).concat(stack, a.redeem.output);
-    }
-
-    if (!a.redeem) return;
-    if (!a.redeem.output) return;
-    if (!a.redeem.witness) return;
-    return ([] as Buffer[]).concat(a.redeem.witness, a.redeem.output);
-  });
-  lazy.prop(o, 'name', () => {
-    const nameParts = ['p2wsh'];
-    if (o.redeem !== undefined && o.redeem.name !== undefined)
-      nameParts.push(o.redeem.name!);
-    return nameParts.join('-');
-  });
-
-  // extended validation
-  if (opts.validate) {
-    let hash: Buffer = Buffer.from([]);
-    if (a.address) {
-      if (_address().prefix !== network.bech32)
-        throw new TypeError('Invalid prefix or Network mismatch');
-      if (_address().version !== 0x00)
-        throw new TypeError('Invalid address version');
-      if (_address().data.length !== 32)
-        throw new TypeError('Invalid address data');
-      hash = _address().data;
-    }
-
-    if (a.hash) {
-      if (hash.length > 0 && !hash.equals(a.hash))
-        throw new TypeError('Hash mismatch');
-      else hash = a.hash;
-    }
-
-    if (a.output) {
-      if (
-        a.output.length !== 34 ||
-        a.output[0] !== OPS.OP_0 ||
-        a.output[1] !== 0x20
-      )
-        throw new TypeError('Output is invalid');
-      const hash2 = a.output.slice(2);
-      if (hash.length > 0 && !hash.equals(hash2))
-        throw new TypeError('Hash mismatch');
-      else hash = hash2;
-    }
-
-    if (a.redeem) {
-      if (a.redeem.network && a.redeem.network !== network)
-        throw new TypeError('Network mismatch');
-
-      // is there two redeem sources?
-      if (
-        a.redeem.input &&
-        a.redeem.input.length > 0 &&
-        a.redeem.witness &&
-        a.redeem.witness.length > 0
-      )
-        throw new TypeError('Ambiguous witness source');
-
-      // is the redeem output non-empty?
-      if (a.redeem.output) {
-        if (bscript.decompile(a.redeem.output)!.length === 0)
-          throw new TypeError('Redeem.output is invalid');
-
-        // match hash against other sources
-        const hash2 = bcrypto.sha256(a.redeem.output);
-        if (hash.length > 0 && !hash.equals(hash2))
-          throw new TypeError('Hash mismatch');
-        else hash = hash2;
-      }
-
-      if (a.redeem.input && !bscript.isPushOnly(_rchunks()))
-        throw new TypeError('Non push-only scriptSig');
-      if (
-        a.witness &&
-        a.redeem.witness &&
-        !stacksEqual(a.witness, a.redeem.witness)
-      )
-        throw new TypeError('Witness and redeem.witness mismatch');
-      if (
-        (a.redeem.input && _rchunks().some(chunkHasUncompressedPubkey)) ||
-        (a.redeem.output &&
-          (bscript.decompile(a.redeem.output) || []).some(
-            chunkHasUncompressedPubkey,
-          ))
-      ) {
-        throw new TypeError(
-          'redeem.input or redeem.output contains uncompressed pubkey',
-        );
-      }
-    }
-
-    if (a.witness && a.witness.length > 0) {
-      const wScript = a.witness[a.witness.length - 1];
-      if (a.redeem && a.redeem.output && !a.redeem.output.equals(wScript))
-        throw new TypeError('Witness and redeem.output mismatch');
-      if (
-        a.witness.some(chunkHasUncompressedPubkey) ||
-        (bscript.decompile(wScript) || []).some(chunkHasUncompressedPubkey)
-      )
-        throw new TypeError('Witness contains uncompressed pubkey');
-    }
-  }
-
-  return Object.assign(o, a);
-}
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
deleted file mode 100644
index b9af10f..0000000
--- a/ts_src/psbt.ts
+++ /dev/null
@@ -1,1858 +0,0 @@
-import { Psbt as PsbtBase } from 'bip174';
-import * as varuint from 'bip174/src/lib/converter/varint';
-import {
-  Bip32Derivation,
-  KeyValue,
-  PartialSig,
-  PsbtGlobalUpdate,
-  PsbtInput,
-  PsbtInputUpdate,
-  PsbtOutput,
-  PsbtOutputUpdate,
-  Transaction as ITransaction,
-  TransactionFromBuffer,
-} from 'bip174/src/lib/interfaces';
-import { checkForInput, checkForOutput } from 'bip174/src/lib/utils';
-import { fromOutputScript, toOutputScript } from './address';
-import { cloneBuffer, reverseBuffer } from './bufferutils';
-import { hash160 } from './crypto';
-import { bitcoin as btcNetwork, Network } from './networks';
-import * as payments from './payments';
-import * as bscript from './script';
-import { Output, Transaction } from './transaction';
-
-export interface TransactionInput {
-  hash: string | Buffer;
-  index: number;
-  sequence?: number;
-}
-
-export interface PsbtTxInput extends TransactionInput {
-  hash: Buffer;
-}
-
-export interface TransactionOutput {
-  script: Buffer;
-  value: number;
-}
-
-export interface PsbtTxOutput extends TransactionOutput {
-  address: string | undefined;
-}
-
-// msghash is 32 byte hash of preimage, signature is 64 byte compact signature (r,s 32 bytes each)
-export type ValidateSigFunction = (
-  pubkey: Buffer,
-  msghash: Buffer,
-  signature: Buffer,
-) => boolean;
-
-/**
- * These are the default arguments for a Psbt instance.
- */
-const DEFAULT_OPTS: PsbtOpts = {
-  /**
-   * A bitcoinjs Network object. This is only used if you pass an `address`
-   * parameter to addOutput. Otherwise it is not needed and can be left default.
-   */
-  network: btcNetwork,
-  /**
-   * When extractTransaction is called, the fee rate is checked.
-   * THIS IS NOT TO BE RELIED ON.
-   * It is only here as a last ditch effort to prevent sending a 500 BTC fee etc.
-   */
-  maximumFeeRate: 5000, // satoshi per byte
-};
-
-/**
- * Psbt class can parse and generate a PSBT binary based off of the BIP174.
- * There are 6 roles that this class fulfills. (Explained in BIP174)
- *
- * Creator: This can be done with `new Psbt()`
- * Updater: This can be done with `psbt.addInput(input)`, `psbt.addInputs(inputs)`,
- *   `psbt.addOutput(output)`, `psbt.addOutputs(outputs)` when you are looking to
- *   add new inputs and outputs to the PSBT, and `psbt.updateGlobal(itemObject)`,
- *   `psbt.updateInput(itemObject)`, `psbt.updateOutput(itemObject)`
- *   addInput requires hash: Buffer | string; and index: number; as attributes
- *   and can also include any attributes that are used in updateInput method.
- *   addOutput requires script: Buffer; and value: number; and likewise can include
- *   data for updateOutput.
- *   For a list of what attributes should be what types. Check the bip174 library.
- *   Also, check the integration tests for some examples of usage.
- * Signer: There are a few methods. signAllInputs and signAllInputsAsync, which will search all input
- *   information for your pubkey or pubkeyhash, and only sign inputs where it finds
- *   your info. Or you can explicitly sign a specific input with signInput and
- *   signInputAsync. For the async methods you can create a SignerAsync object
- *   and use something like a hardware wallet to sign with. (You must implement this)
- * Combiner: psbts can be combined easily with `psbt.combine(psbt2, psbt3, psbt4 ...)`
- *   the psbt calling combine will always have precedence when a conflict occurs.
- *   Combine checks if the internal bitcoin transaction is the same, so be sure that
- *   all sequences, version, locktime, etc. are the same before combining.
- * Input Finalizer: This role is fairly important. Not only does it need to construct
- *   the input scriptSigs and witnesses, but it SHOULD verify the signatures etc.
- *   Before running `psbt.finalizeAllInputs()` please run `psbt.validateSignaturesOfAllInputs()`
- *   Running any finalize method will delete any data in the input(s) that are no longer
- *   needed due to the finalized scripts containing the information.
- * Transaction Extractor: This role will perform some checks before returning a
- *   Transaction object. Such as fee rate not being larger than maximumFeeRate etc.
- */
-export class Psbt {
-  static fromBase64(data: string, opts: PsbtOptsOptional = {}): Psbt {
-    const buffer = Buffer.from(data, 'base64');
-    return this.fromBuffer(buffer, opts);
-  }
-
-  static fromHex(data: string, opts: PsbtOptsOptional = {}): Psbt {
-    const buffer = Buffer.from(data, 'hex');
-    return this.fromBuffer(buffer, opts);
-  }
-
-  static fromBuffer(buffer: Buffer, opts: PsbtOptsOptional = {}): Psbt {
-    const psbtBase = PsbtBase.fromBuffer(buffer, transactionFromBuffer);
-    const psbt = new Psbt(opts, psbtBase);
-    checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE);
-    return psbt;
-  }
-
-  private __CACHE: PsbtCache;
-  private opts: PsbtOpts;
-
-  constructor(
-    opts: PsbtOptsOptional = {},
-    readonly data: PsbtBase = new PsbtBase(new PsbtTransaction()),
-  ) {
-    // set defaults
-    this.opts = Object.assign({}, DEFAULT_OPTS, opts);
-    this.__CACHE = {
-      __NON_WITNESS_UTXO_TX_CACHE: [],
-      __NON_WITNESS_UTXO_BUF_CACHE: [],
-      __TX_IN_CACHE: {},
-      __TX: (this.data.globalMap.unsignedTx as PsbtTransaction).tx,
-      // Psbt's predecesor (TransactionBuilder - now removed) behavior
-      // was to not confirm input values  before signing.
-      // Even though we highly encourage people to get
-      // the full parent transaction to verify values, the ability to
-      // sign non-segwit inputs without the full transaction was often
-      // requested. So the only way to activate is to use @ts-ignore.
-      // We will disable exporting the Psbt when unsafe sign is active.
-      // because it is not BIP174 compliant.
-      __UNSAFE_SIGN_NONSEGWIT: false,
-    };
-    if (this.data.inputs.length === 0) this.setVersion(2);
-
-    // Make data hidden when enumerating
-    const dpew = (
-      obj: any,
-      attr: string,
-      enumerable: boolean,
-      writable: boolean,
-    ): any =>
-      Object.defineProperty(obj, attr, {
-        enumerable,
-        writable,
-      });
-    dpew(this, '__CACHE', false, true);
-    dpew(this, 'opts', false, true);
-  }
-
-  get inputCount(): number {
-    return this.data.inputs.length;
-  }
-
-  get version(): number {
-    return this.__CACHE.__TX.version;
-  }
-
-  set version(version: number) {
-    this.setVersion(version);
-  }
-
-  get locktime(): number {
-    return this.__CACHE.__TX.locktime;
-  }
-
-  set locktime(locktime: number) {
-    this.setLocktime(locktime);
-  }
-
-  get txInputs(): PsbtTxInput[] {
-    return this.__CACHE.__TX.ins.map(input => ({
-      hash: cloneBuffer(input.hash),
-      index: input.index,
-      sequence: input.sequence,
-    }));
-  }
-
-  get txOutputs(): PsbtTxOutput[] {
-    return this.__CACHE.__TX.outs.map(output => {
-      let address;
-      try {
-        address = fromOutputScript(output.script, this.opts.network);
-      } catch (_) {}
-      return {
-        script: cloneBuffer(output.script),
-        value: output.value,
-        address,
-      };
-    });
-  }
-
-  combine(...those: Psbt[]): this {
-    this.data.combine(...those.map(o => o.data));
-    return this;
-  }
-
-  clone(): Psbt {
-    // TODO: more efficient cloning
-    const res = Psbt.fromBuffer(this.data.toBuffer());
-    res.opts = JSON.parse(JSON.stringify(this.opts));
-    return res;
-  }
-
-  setMaximumFeeRate(satoshiPerByte: number): void {
-    check32Bit(satoshiPerByte); // 42.9 BTC per byte IS excessive... so throw
-    this.opts.maximumFeeRate = satoshiPerByte;
-  }
-
-  setVersion(version: number): this {
-    check32Bit(version);
-    checkInputsForPartialSig(this.data.inputs, 'setVersion');
-    const c = this.__CACHE;
-    c.__TX.version = version;
-    c.__EXTRACTED_TX = undefined;
-    return this;
-  }
-
-  setLocktime(locktime: number): this {
-    check32Bit(locktime);
-    checkInputsForPartialSig(this.data.inputs, 'setLocktime');
-    const c = this.__CACHE;
-    c.__TX.locktime = locktime;
-    c.__EXTRACTED_TX = undefined;
-    return this;
-  }
-
-  setInputSequence(inputIndex: number, sequence: number): this {
-    check32Bit(sequence);
-    checkInputsForPartialSig(this.data.inputs, 'setInputSequence');
-    const c = this.__CACHE;
-    if (c.__TX.ins.length <= inputIndex) {
-      throw new Error('Input index too high');
-    }
-    c.__TX.ins[inputIndex].sequence = sequence;
-    c.__EXTRACTED_TX = undefined;
-    return this;
-  }
-
-  addInputs(inputDatas: PsbtInputExtended[]): this {
-    inputDatas.forEach(inputData => this.addInput(inputData));
-    return this;
-  }
-
-  addInput(inputData: PsbtInputExtended): this {
-    if (
-      arguments.length > 1 ||
-      !inputData ||
-      inputData.hash === undefined ||
-      inputData.index === undefined
-    ) {
-      throw new Error(
-        `Invalid arguments for Psbt.addInput. ` +
-          `Requires single object with at least [hash] and [index]`,
-      );
-    }
-    checkInputsForPartialSig(this.data.inputs, 'addInput');
-    if (inputData.witnessScript) checkInvalidP2WSH(inputData.witnessScript);
-    const c = this.__CACHE;
-    this.data.addInput(inputData);
-    const txIn = c.__TX.ins[c.__TX.ins.length - 1];
-    checkTxInputCache(c, txIn);
-
-    const inputIndex = this.data.inputs.length - 1;
-    const input = this.data.inputs[inputIndex];
-    if (input.nonWitnessUtxo) {
-      addNonWitnessTxCache(this.__CACHE, input, inputIndex);
-    }
-    c.__FEE = undefined;
-    c.__FEE_RATE = undefined;
-    c.__EXTRACTED_TX = undefined;
-    return this;
-  }
-
-  addOutputs(outputDatas: PsbtOutputExtended[]): this {
-    outputDatas.forEach(outputData => this.addOutput(outputData));
-    return this;
-  }
-
-  addOutput(outputData: PsbtOutputExtended): this {
-    if (
-      arguments.length > 1 ||
-      !outputData ||
-      outputData.value === undefined ||
-      ((outputData as any).address === undefined &&
-        (outputData as any).script === undefined)
-    ) {
-      throw new Error(
-        `Invalid arguments for Psbt.addOutput. ` +
-          `Requires single object with at least [script or address] and [value]`,
-      );
-    }
-    checkInputsForPartialSig(this.data.inputs, 'addOutput');
-    const { address } = outputData as any;
-    if (typeof address === 'string') {
-      const { network } = this.opts;
-      const script = toOutputScript(address, network);
-      outputData = Object.assign(outputData, { script });
-    }
-    const c = this.__CACHE;
-    this.data.addOutput(outputData);
-    c.__FEE = undefined;
-    c.__FEE_RATE = undefined;
-    c.__EXTRACTED_TX = undefined;
-    return this;
-  }
-
-  extractTransaction(disableFeeCheck?: boolean): Transaction {
-    if (!this.data.inputs.every(isFinalized)) throw new Error('Not finalized');
-    const c = this.__CACHE;
-    if (!disableFeeCheck) {
-      checkFees(this, c, this.opts);
-    }
-    if (c.__EXTRACTED_TX) return c.__EXTRACTED_TX;
-    const tx = c.__TX.clone();
-    inputFinalizeGetAmts(this.data.inputs, tx, c, true);
-    return tx;
-  }
-
-  getFeeRate(): number {
-    return getTxCacheValue(
-      '__FEE_RATE',
-      'fee rate',
-      this.data.inputs,
-      this.__CACHE,
-    )!;
-  }
-
-  getFee(): number {
-    return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE)!;
-  }
-
-  finalizeAllInputs(): this {
-    checkForInput(this.data.inputs, 0); // making sure we have at least one
-    range(this.data.inputs.length).forEach(idx => this.finalizeInput(idx));
-    return this;
-  }
-
-  finalizeInput(
-    inputIndex: number,
-    finalScriptsFunc: FinalScriptsFunc = getFinalScripts,
-  ): this {
-    const input = checkForInput(this.data.inputs, inputIndex);
-    const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
-      inputIndex,
-      input,
-      this.__CACHE,
-    );
-    if (!script) throw new Error(`No script found for input #${inputIndex}`);
-
-    checkPartialSigSighashes(input);
-
-    const { finalScriptSig, finalScriptWitness } = finalScriptsFunc(
-      inputIndex,
-      input,
-      script,
-      isSegwit,
-      isP2SH,
-      isP2WSH,
-    );
-
-    if (finalScriptSig) this.data.updateInput(inputIndex, { finalScriptSig });
-    if (finalScriptWitness)
-      this.data.updateInput(inputIndex, { finalScriptWitness });
-    if (!finalScriptSig && !finalScriptWitness)
-      throw new Error(`Unknown error finalizing input #${inputIndex}`);
-
-    this.data.clearFinalizedInput(inputIndex);
-    return this;
-  }
-
-  getInputType(inputIndex: number): AllScriptType {
-    const input = checkForInput(this.data.inputs, inputIndex);
-    const script = getScriptFromUtxo(inputIndex, input, this.__CACHE);
-    const result = getMeaningfulScript(
-      script,
-      inputIndex,
-      'input',
-      input.redeemScript || redeemFromFinalScriptSig(input.finalScriptSig),
-      input.witnessScript ||
-        redeemFromFinalWitnessScript(input.finalScriptWitness),
-    );
-    const type = result.type === 'raw' ? '' : result.type + '-';
-    const mainType = classifyScript(result.meaningfulScript);
-    return (type + mainType) as AllScriptType;
-  }
-
-  inputHasPubkey(inputIndex: number, pubkey: Buffer): boolean {
-    const input = checkForInput(this.data.inputs, inputIndex);
-    return pubkeyInInput(pubkey, input, inputIndex, this.__CACHE);
-  }
-
-  inputHasHDKey(inputIndex: number, root: HDSigner): boolean {
-    const input = checkForInput(this.data.inputs, inputIndex);
-    const derivationIsMine = bip32DerivationIsMine(root);
-    return (
-      !!input.bip32Derivation && input.bip32Derivation.some(derivationIsMine)
-    );
-  }
-
-  outputHasPubkey(outputIndex: number, pubkey: Buffer): boolean {
-    const output = checkForOutput(this.data.outputs, outputIndex);
-    return pubkeyInOutput(pubkey, output, outputIndex, this.__CACHE);
-  }
-
-  outputHasHDKey(outputIndex: number, root: HDSigner): boolean {
-    const output = checkForOutput(this.data.outputs, outputIndex);
-    const derivationIsMine = bip32DerivationIsMine(root);
-    return (
-      !!output.bip32Derivation && output.bip32Derivation.some(derivationIsMine)
-    );
-  }
-
-  validateSignaturesOfAllInputs(validator: ValidateSigFunction): boolean {
-    checkForInput(this.data.inputs, 0); // making sure we have at least one
-    const results = range(this.data.inputs.length).map(idx =>
-      this.validateSignaturesOfInput(idx, validator),
-    );
-    return results.reduce((final, res) => res === true && final, true);
-  }
-
-  validateSignaturesOfInput(
-    inputIndex: number,
-    validator: ValidateSigFunction,
-    pubkey?: Buffer,
-  ): boolean {
-    const input = this.data.inputs[inputIndex];
-    const partialSig = (input || {}).partialSig;
-    if (!input || !partialSig || partialSig.length < 1)
-      throw new Error('No signatures to validate');
-    if (typeof validator !== 'function')
-      throw new Error('Need validator function to validate signatures');
-    const mySigs = pubkey
-      ? partialSig.filter(sig => sig.pubkey.equals(pubkey))
-      : partialSig;
-    if (mySigs.length < 1) throw new Error('No signatures for this pubkey');
-    const results: boolean[] = [];
-    let hashCache: Buffer;
-    let scriptCache: Buffer;
-    let sighashCache: number;
-    for (const pSig of mySigs) {
-      const sig = bscript.signature.decode(pSig.signature);
-      const { hash, script } =
-        sighashCache! !== sig.hashType
-          ? getHashForSig(
-              inputIndex,
-              Object.assign({}, input, { sighashType: sig.hashType }),
-              this.__CACHE,
-              true,
-            )
-          : { hash: hashCache!, script: scriptCache! };
-      sighashCache = sig.hashType;
-      hashCache = hash;
-      scriptCache = script;
-      checkScriptForPubkey(pSig.pubkey, script, 'verify');
-      results.push(validator(pSig.pubkey, hash, sig.signature));
-    }
-    return results.every(res => res === true);
-  }
-
-  signAllInputsHD(
-    hdKeyPair: HDSigner,
-    sighashTypes: number[] = [Transaction.SIGHASH_ALL],
-  ): this {
-    if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
-      throw new Error('Need HDSigner to sign input');
-    }
-
-    const results: boolean[] = [];
-    for (const i of range(this.data.inputs.length)) {
-      try {
-        this.signInputHD(i, hdKeyPair, sighashTypes);
-        results.push(true);
-      } catch (err) {
-        results.push(false);
-      }
-    }
-    if (results.every(v => v === false)) {
-      throw new Error('No inputs were signed');
-    }
-    return this;
-  }
-
-  signAllInputsHDAsync(
-    hdKeyPair: HDSigner | HDSignerAsync,
-    sighashTypes: number[] = [Transaction.SIGHASH_ALL],
-  ): Promise<void> {
-    return new Promise(
-      (resolve, reject): any => {
-        if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
-          return reject(new Error('Need HDSigner to sign input'));
-        }
-
-        const results: boolean[] = [];
-        const promises: Array<Promise<void>> = [];
-        for (const i of range(this.data.inputs.length)) {
-          promises.push(
-            this.signInputHDAsync(i, hdKeyPair, sighashTypes).then(
-              () => {
-                results.push(true);
-              },
-              () => {
-                results.push(false);
-              },
-            ),
-          );
-        }
-        return Promise.all(promises).then(() => {
-          if (results.every(v => v === false)) {
-            return reject(new Error('No inputs were signed'));
-          }
-          resolve();
-        });
-      },
-    );
-  }
-
-  signInputHD(
-    inputIndex: number,
-    hdKeyPair: HDSigner,
-    sighashTypes: number[] = [Transaction.SIGHASH_ALL],
-  ): this {
-    if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
-      throw new Error('Need HDSigner to sign input');
-    }
-    const signers = getSignersFromHD(
-      inputIndex,
-      this.data.inputs,
-      hdKeyPair,
-    ) as Signer[];
-    signers.forEach(signer => this.signInput(inputIndex, signer, sighashTypes));
-    return this;
-  }
-
-  signInputHDAsync(
-    inputIndex: number,
-    hdKeyPair: HDSigner | HDSignerAsync,
-    sighashTypes: number[] = [Transaction.SIGHASH_ALL],
-  ): Promise<void> {
-    return new Promise(
-      (resolve, reject): any => {
-        if (!hdKeyPair || !hdKeyPair.publicKey || !hdKeyPair.fingerprint) {
-          return reject(new Error('Need HDSigner to sign input'));
-        }
-        const signers = getSignersFromHD(
-          inputIndex,
-          this.data.inputs,
-          hdKeyPair,
-        );
-        const promises = signers.map(signer =>
-          this.signInputAsync(inputIndex, signer, sighashTypes),
-        );
-        return Promise.all(promises)
-          .then(() => {
-            resolve();
-          })
-          .catch(reject);
-      },
-    );
-  }
-
-  signAllInputs(
-    keyPair: Signer,
-    sighashTypes: number[] = [Transaction.SIGHASH_ALL],
-  ): this {
-    if (!keyPair || !keyPair.publicKey)
-      throw new Error('Need Signer to sign input');
-
-    // TODO: Add a pubkey/pubkeyhash cache to each input
-    // as input information is added, then eventually
-    // optimize this method.
-    const results: boolean[] = [];
-    for (const i of range(this.data.inputs.length)) {
-      try {
-        this.signInput(i, keyPair, sighashTypes);
-        results.push(true);
-      } catch (err) {
-        results.push(false);
-      }
-    }
-    if (results.every(v => v === false)) {
-      throw new Error('No inputs were signed');
-    }
-    return this;
-  }
-
-  signAllInputsAsync(
-    keyPair: Signer | SignerAsync,
-    sighashTypes: number[] = [Transaction.SIGHASH_ALL],
-  ): Promise<void> {
-    return new Promise(
-      (resolve, reject): any => {
-        if (!keyPair || !keyPair.publicKey)
-          return reject(new Error('Need Signer to sign input'));
-
-        // TODO: Add a pubkey/pubkeyhash cache to each input
-        // as input information is added, then eventually
-        // optimize this method.
-        const results: boolean[] = [];
-        const promises: Array<Promise<void>> = [];
-        for (const [i] of this.data.inputs.entries()) {
-          promises.push(
-            this.signInputAsync(i, keyPair, sighashTypes).then(
-              () => {
-                results.push(true);
-              },
-              () => {
-                results.push(false);
-              },
-            ),
-          );
-        }
-        return Promise.all(promises).then(() => {
-          if (results.every(v => v === false)) {
-            return reject(new Error('No inputs were signed'));
-          }
-          resolve();
-        });
-      },
-    );
-  }
-
-  signInput(
-    inputIndex: number,
-    keyPair: Signer,
-    sighashTypes: number[] = [Transaction.SIGHASH_ALL],
-  ): this {
-    if (!keyPair || !keyPair.publicKey)
-      throw new Error('Need Signer to sign input');
-    const { hash, sighashType } = getHashAndSighashType(
-      this.data.inputs,
-      inputIndex,
-      keyPair.publicKey,
-      this.__CACHE,
-      sighashTypes,
-    );
-
-    const partialSig = [
-      {
-        pubkey: keyPair.publicKey,
-        signature: bscript.signature.encode(keyPair.sign(hash), sighashType),
-      },
-    ];
-
-    this.data.updateInput(inputIndex, { partialSig });
-    return this;
-  }
-
-  signInputAsync(
-    inputIndex: number,
-    keyPair: Signer | SignerAsync,
-    sighashTypes: number[] = [Transaction.SIGHASH_ALL],
-  ): Promise<void> {
-    return Promise.resolve().then(() => {
-      if (!keyPair || !keyPair.publicKey)
-        throw new Error('Need Signer to sign input');
-      const { hash, sighashType } = getHashAndSighashType(
-        this.data.inputs,
-        inputIndex,
-        keyPair.publicKey,
-        this.__CACHE,
-        sighashTypes,
-      );
-
-      return Promise.resolve(keyPair.sign(hash)).then(signature => {
-        const partialSig = [
-          {
-            pubkey: keyPair.publicKey,
-            signature: bscript.signature.encode(signature, sighashType),
-          },
-        ];
-
-        this.data.updateInput(inputIndex, { partialSig });
-      });
-    });
-  }
-
-  toBuffer(): Buffer {
-    checkCache(this.__CACHE);
-    return this.data.toBuffer();
-  }
-
-  toHex(): string {
-    checkCache(this.__CACHE);
-    return this.data.toHex();
-  }
-
-  toBase64(): string {
-    checkCache(this.__CACHE);
-    return this.data.toBase64();
-  }
-
-  updateGlobal(updateData: PsbtGlobalUpdate): this {
-    this.data.updateGlobal(updateData);
-    return this;
-  }
-
-  updateInput(inputIndex: number, updateData: PsbtInputUpdate): this {
-    if (updateData.witnessScript) checkInvalidP2WSH(updateData.witnessScript);
-    this.data.updateInput(inputIndex, updateData);
-    if (updateData.nonWitnessUtxo) {
-      addNonWitnessTxCache(
-        this.__CACHE,
-        this.data.inputs[inputIndex],
-        inputIndex,
-      );
-    }
-    return this;
-  }
-
-  updateOutput(outputIndex: number, updateData: PsbtOutputUpdate): this {
-    this.data.updateOutput(outputIndex, updateData);
-    return this;
-  }
-
-  addUnknownKeyValToGlobal(keyVal: KeyValue): this {
-    this.data.addUnknownKeyValToGlobal(keyVal);
-    return this;
-  }
-
-  addUnknownKeyValToInput(inputIndex: number, keyVal: KeyValue): this {
-    this.data.addUnknownKeyValToInput(inputIndex, keyVal);
-    return this;
-  }
-
-  addUnknownKeyValToOutput(outputIndex: number, keyVal: KeyValue): this {
-    this.data.addUnknownKeyValToOutput(outputIndex, keyVal);
-    return this;
-  }
-
-  clearFinalizedInput(inputIndex: number): this {
-    this.data.clearFinalizedInput(inputIndex);
-    return this;
-  }
-}
-
-interface PsbtCache {
-  __NON_WITNESS_UTXO_TX_CACHE: Transaction[];
-  __NON_WITNESS_UTXO_BUF_CACHE: Buffer[];
-  __TX_IN_CACHE: { [index: string]: number };
-  __TX: Transaction;
-  __FEE_RATE?: number;
-  __FEE?: number;
-  __EXTRACTED_TX?: Transaction;
-  __UNSAFE_SIGN_NONSEGWIT: boolean;
-}
-
-interface PsbtOptsOptional {
-  network?: Network;
-  maximumFeeRate?: number;
-}
-
-interface PsbtOpts {
-  network: Network;
-  maximumFeeRate: number;
-}
-
-interface PsbtInputExtended extends PsbtInput, TransactionInput {}
-
-type PsbtOutputExtended = PsbtOutputExtendedAddress | PsbtOutputExtendedScript;
-
-interface PsbtOutputExtendedAddress extends PsbtOutput {
-  address: string;
-  value: number;
-}
-
-interface PsbtOutputExtendedScript extends PsbtOutput {
-  script: Buffer;
-  value: number;
-}
-
-interface HDSignerBase {
-  /**
-   * DER format compressed publicKey buffer
-   */
-  publicKey: Buffer;
-  /**
-   * The first 4 bytes of the sha256-ripemd160 of the publicKey
-   */
-  fingerprint: Buffer;
-}
-
-export interface HDSigner extends HDSignerBase {
-  /**
-   * The path string must match /^m(\/\d+'?)+$/
-   * ex. m/44'/0'/0'/1/23 levels with ' must be hard derivations
-   */
-  derivePath(path: string): HDSigner;
-  /**
-   * Input hash (the "message digest") for the signature algorithm
-   * Return a 64 byte signature (32 byte r and 32 byte s in that order)
-   */
-  sign(hash: Buffer): Buffer;
-}
-
-/**
- * Same as above but with async sign method
- */
-export interface HDSignerAsync extends HDSignerBase {
-  derivePath(path: string): HDSignerAsync;
-  sign(hash: Buffer): Promise<Buffer>;
-}
-
-export interface Signer {
-  publicKey: Buffer;
-  network?: any;
-  sign(hash: Buffer, lowR?: boolean): Buffer;
-  getPublicKey?(): Buffer;
-}
-
-export interface SignerAsync {
-  publicKey: Buffer;
-  network?: any;
-  sign(hash: Buffer, lowR?: boolean): Promise<Buffer>;
-  getPublicKey?(): Buffer;
-}
-
-/**
- * This function is needed to pass to the bip174 base class's fromBuffer.
- * It takes the "transaction buffer" portion of the psbt buffer and returns a
- * Transaction (From the bip174 library) interface.
- */
-const transactionFromBuffer: TransactionFromBuffer = (
-  buffer: Buffer,
-): ITransaction => new PsbtTransaction(buffer);
-
-/**
- * This class implements the Transaction interface from bip174 library.
- * It contains a bitcoinjs-lib Transaction object.
- */
-class PsbtTransaction implements ITransaction {
-  tx: Transaction;
-  constructor(buffer: Buffer = Buffer.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) {
-    this.tx = Transaction.fromBuffer(buffer);
-    checkTxEmpty(this.tx);
-    Object.defineProperty(this, 'tx', {
-      enumerable: false,
-      writable: true,
-    });
-  }
-
-  getInputOutputCounts(): {
-    inputCount: number;
-    outputCount: number;
-  } {
-    return {
-      inputCount: this.tx.ins.length,
-      outputCount: this.tx.outs.length,
-    };
-  }
-
-  addInput(input: any): void {
-    if (
-      (input as any).hash === undefined ||
-      (input as any).index === undefined ||
-      (!Buffer.isBuffer((input as any).hash) &&
-        typeof (input as any).hash !== 'string') ||
-      typeof (input as any).index !== 'number'
-    ) {
-      throw new Error('Error adding input.');
-    }
-    const hash =
-      typeof input.hash === 'string'
-        ? reverseBuffer(Buffer.from(input.hash, 'hex'))
-        : input.hash;
-    this.tx.addInput(hash, input.index, input.sequence);
-  }
-
-  addOutput(output: any): void {
-    if (
-      (output as any).script === undefined ||
-      (output as any).value === undefined ||
-      !Buffer.isBuffer((output as any).script) ||
-      typeof (output as any).value !== 'number'
-    ) {
-      throw new Error('Error adding output.');
-    }
-    this.tx.addOutput(output.script, output.value);
-  }
-
-  toBuffer(): Buffer {
-    return this.tx.toBuffer();
-  }
-}
-
-function canFinalize(
-  input: PsbtInput,
-  script: Buffer,
-  scriptType: string,
-): boolean {
-  switch (scriptType) {
-    case 'pubkey':
-    case 'pubkeyhash':
-    case 'witnesspubkeyhash':
-      return hasSigs(1, input.partialSig);
-    case 'multisig':
-      const p2ms = payments.p2ms({ output: script });
-      return hasSigs(p2ms.m!, input.partialSig, p2ms.pubkeys);
-    default:
-      return false;
-  }
-}
-
-function checkCache(cache: PsbtCache): void {
-  if (cache.__UNSAFE_SIGN_NONSEGWIT !== false) {
-    throw new Error('Not BIP174 compliant, can not export');
-  }
-}
-
-function hasSigs(
-  neededSigs: number,
-  partialSig?: any[],
-  pubkeys?: Buffer[],
-): boolean {
-  if (!partialSig) return false;
-  let sigs: any;
-  if (pubkeys) {
-    sigs = pubkeys
-      .map(pkey => {
-        const pubkey = compressPubkey(pkey);
-        return partialSig.find(pSig => pSig.pubkey.equals(pubkey));
-      })
-      .filter(v => !!v);
-  } else {
-    sigs = partialSig;
-  }
-  if (sigs.length > neededSigs) throw new Error('Too many signatures');
-  return sigs.length === neededSigs;
-}
-
-function isFinalized(input: PsbtInput): boolean {
-  return !!input.finalScriptSig || !!input.finalScriptWitness;
-}
-
-function isPaymentFactory(payment: any): (script: Buffer) => boolean {
-  return (script: Buffer): boolean => {
-    try {
-      payment({ output: script });
-      return true;
-    } catch (err) {
-      return false;
-    }
-  };
-}
-const isP2MS = isPaymentFactory(payments.p2ms);
-const isP2PK = isPaymentFactory(payments.p2pk);
-const isP2PKH = isPaymentFactory(payments.p2pkh);
-const isP2WPKH = isPaymentFactory(payments.p2wpkh);
-const isP2WSHScript = isPaymentFactory(payments.p2wsh);
-const isP2SHScript = isPaymentFactory(payments.p2sh);
-
-function bip32DerivationIsMine(
-  root: HDSigner,
-): (d: Bip32Derivation) => boolean {
-  return (d: Bip32Derivation): boolean => {
-    if (!d.masterFingerprint.equals(root.fingerprint)) return false;
-    if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false;
-    return true;
-  };
-}
-
-function check32Bit(num: number): void {
-  if (
-    typeof num !== 'number' ||
-    num !== Math.floor(num) ||
-    num > 0xffffffff ||
-    num < 0
-  ) {
-    throw new Error('Invalid 32 bit integer');
-  }
-}
-
-function checkFees(psbt: Psbt, cache: PsbtCache, opts: PsbtOpts): void {
-  const feeRate = cache.__FEE_RATE || psbt.getFeeRate();
-  const vsize = cache.__EXTRACTED_TX!.virtualSize();
-  const satoshis = feeRate * vsize;
-  if (feeRate >= opts.maximumFeeRate) {
-    throw new Error(
-      `Warning: You are paying around ${(satoshis / 1e8).toFixed(8)} in ` +
-        `fees, which is ${feeRate} satoshi per byte for a transaction ` +
-        `with a VSize of ${vsize} bytes (segwit counted as 0.25 byte per ` +
-        `byte). Use setMaximumFeeRate method to raise your threshold, or ` +
-        `pass true to the first arg of extractTransaction.`,
-    );
-  }
-}
-
-function checkInputsForPartialSig(inputs: PsbtInput[], action: string): void {
-  inputs.forEach(input => {
-    let throws = false;
-    let pSigs: PartialSig[] = [];
-    if ((input.partialSig || []).length === 0) {
-      if (!input.finalScriptSig && !input.finalScriptWitness) return;
-      pSigs = getPsigsFromInputFinalScripts(input);
-    } else {
-      pSigs = input.partialSig!;
-    }
-    pSigs.forEach(pSig => {
-      const { hashType } = bscript.signature.decode(pSig.signature);
-      const whitelist: string[] = [];
-      const isAnyoneCanPay = hashType & Transaction.SIGHASH_ANYONECANPAY;
-      if (isAnyoneCanPay) whitelist.push('addInput');
-      const hashMod = hashType & 0x1f;
-      switch (hashMod) {
-        case Transaction.SIGHASH_ALL:
-          break;
-        case Transaction.SIGHASH_SINGLE:
-        case Transaction.SIGHASH_NONE:
-          whitelist.push('addOutput');
-          whitelist.push('setInputSequence');
-          break;
-      }
-      if (whitelist.indexOf(action) === -1) {
-        throws = true;
-      }
-    });
-    if (throws) {
-      throw new Error('Can not modify transaction, signatures exist.');
-    }
-  });
-}
-
-function checkPartialSigSighashes(input: PsbtInput): void {
-  if (!input.sighashType || !input.partialSig) return;
-  const { partialSig, sighashType } = input;
-  partialSig.forEach(pSig => {
-    const { hashType } = bscript.signature.decode(pSig.signature);
-    if (sighashType !== hashType) {
-      throw new Error('Signature sighash does not match input sighash type');
-    }
-  });
-}
-
-function checkScriptForPubkey(
-  pubkey: Buffer,
-  script: Buffer,
-  action: string,
-): void {
-  if (!pubkeyInScript(pubkey, script)) {
-    throw new Error(
-      `Can not ${action} for this input with the key ${pubkey.toString('hex')}`,
-    );
-  }
-}
-
-function checkTxEmpty(tx: Transaction): void {
-  const isEmpty = tx.ins.every(
-    input =>
-      input.script &&
-      input.script.length === 0 &&
-      input.witness &&
-      input.witness.length === 0,
-  );
-  if (!isEmpty) {
-    throw new Error('Format Error: Transaction ScriptSigs are not empty');
-  }
-}
-
-function checkTxForDupeIns(tx: Transaction, cache: PsbtCache): void {
-  tx.ins.forEach(input => {
-    checkTxInputCache(cache, input);
-  });
-}
-
-function checkTxInputCache(
-  cache: PsbtCache,
-  input: { hash: Buffer; index: number },
-): void {
-  const key =
-    reverseBuffer(Buffer.from(input.hash)).toString('hex') + ':' + input.index;
-  if (cache.__TX_IN_CACHE[key]) throw new Error('Duplicate input detected.');
-  cache.__TX_IN_CACHE[key] = 1;
-}
-
-function scriptCheckerFactory(
-  payment: any,
-  paymentScriptName: string,
-): (idx: number, spk: Buffer, rs: Buffer, ioType: 'input' | 'output') => void {
-  return (
-    inputIndex: number,
-    scriptPubKey: Buffer,
-    redeemScript: Buffer,
-    ioType: 'input' | 'output',
-  ): void => {
-    const redeemScriptOutput = payment({
-      redeem: { output: redeemScript },
-    }).output as Buffer;
-
-    if (!scriptPubKey.equals(redeemScriptOutput)) {
-      throw new Error(
-        `${paymentScriptName} for ${ioType} #${inputIndex} doesn't match the scriptPubKey in the prevout`,
-      );
-    }
-  };
-}
-const checkRedeemScript = scriptCheckerFactory(payments.p2sh, 'Redeem script');
-const checkWitnessScript = scriptCheckerFactory(
-  payments.p2wsh,
-  'Witness script',
-);
-
-type TxCacheNumberKey = '__FEE_RATE' | '__FEE';
-function getTxCacheValue(
-  key: TxCacheNumberKey,
-  name: string,
-  inputs: PsbtInput[],
-  c: PsbtCache,
-): number | undefined {
-  if (!inputs.every(isFinalized))
-    throw new Error(`PSBT must be finalized to calculate ${name}`);
-  if (key === '__FEE_RATE' && c.__FEE_RATE) return c.__FEE_RATE;
-  if (key === '__FEE' && c.__FEE) return c.__FEE;
-  let tx: Transaction;
-  let mustFinalize = true;
-  if (c.__EXTRACTED_TX) {
-    tx = c.__EXTRACTED_TX;
-    mustFinalize = false;
-  } else {
-    tx = c.__TX.clone();
-  }
-  inputFinalizeGetAmts(inputs, tx, c, mustFinalize);
-  if (key === '__FEE_RATE') return c.__FEE_RATE!;
-  else if (key === '__FEE') return c.__FEE!;
-}
-
-/**
- * This function must do two things:
- * 1. Check if the `input` can be finalized. If it can not be finalized, throw.
- *   ie. `Can not finalize input #${inputIndex}`
- * 2. Create the finalScriptSig and finalScriptWitness Buffers.
- */
-type FinalScriptsFunc = (
-  inputIndex: number, // Which input is it?
-  input: PsbtInput, // The PSBT input contents
-  script: Buffer, // The "meaningful" locking script Buffer (redeemScript for P2SH etc.)
-  isSegwit: boolean, // Is it segwit?
-  isP2SH: boolean, // Is it P2SH?
-  isP2WSH: boolean, // Is it P2WSH?
-) => {
-  finalScriptSig: Buffer | undefined;
-  finalScriptWitness: Buffer | undefined;
-};
-
-function getFinalScripts(
-  inputIndex: number,
-  input: PsbtInput,
-  script: Buffer,
-  isSegwit: boolean,
-  isP2SH: boolean,
-  isP2WSH: boolean,
-): {
-  finalScriptSig: Buffer | undefined;
-  finalScriptWitness: Buffer | undefined;
-} {
-  const scriptType = classifyScript(script);
-  if (!canFinalize(input, script, scriptType))
-    throw new Error(`Can not finalize input #${inputIndex}`);
-  return prepareFinalScripts(
-    script,
-    scriptType,
-    input.partialSig!,
-    isSegwit,
-    isP2SH,
-    isP2WSH,
-  );
-}
-
-function prepareFinalScripts(
-  script: Buffer,
-  scriptType: string,
-  partialSig: PartialSig[],
-  isSegwit: boolean,
-  isP2SH: boolean,
-  isP2WSH: boolean,
-): {
-  finalScriptSig: Buffer | undefined;
-  finalScriptWitness: Buffer | undefined;
-} {
-  let finalScriptSig: Buffer | undefined;
-  let finalScriptWitness: Buffer | undefined;
-
-  // Wow, the payments API is very handy
-  const payment: payments.Payment = getPayment(script, scriptType, partialSig);
-  const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment });
-  const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment });
-
-  if (isSegwit) {
-    if (p2wsh) {
-      finalScriptWitness = witnessStackToScriptWitness(p2wsh.witness!);
-    } else {
-      finalScriptWitness = witnessStackToScriptWitness(payment.witness!);
-    }
-    if (p2sh) {
-      finalScriptSig = p2sh.input;
-    }
-  } else {
-    if (p2sh) {
-      finalScriptSig = p2sh.input;
-    } else {
-      finalScriptSig = payment.input;
-    }
-  }
-  return {
-    finalScriptSig,
-    finalScriptWitness,
-  };
-}
-
-function getHashAndSighashType(
-  inputs: PsbtInput[],
-  inputIndex: number,
-  pubkey: Buffer,
-  cache: PsbtCache,
-  sighashTypes: number[],
-): {
-  hash: Buffer;
-  sighashType: number;
-} {
-  const input = checkForInput(inputs, inputIndex);
-  const { hash, sighashType, script } = getHashForSig(
-    inputIndex,
-    input,
-    cache,
-    false,
-    sighashTypes,
-  );
-  checkScriptForPubkey(pubkey, script, 'sign');
-  return {
-    hash,
-    sighashType,
-  };
-}
-
-function getHashForSig(
-  inputIndex: number,
-  input: PsbtInput,
-  cache: PsbtCache,
-  forValidate: boolean,
-  sighashTypes?: number[],
-): {
-  script: Buffer;
-  hash: Buffer;
-  sighashType: number;
-} {
-  const unsignedTx = cache.__TX;
-  const sighashType = input.sighashType || Transaction.SIGHASH_ALL;
-  if (sighashTypes && sighashTypes.indexOf(sighashType) < 0) {
-    const str = sighashTypeToString(sighashType);
-    throw new Error(
-      `Sighash type is not allowed. Retry the sign method passing the ` +
-        `sighashTypes array of whitelisted types. Sighash type: ${str}`,
-    );
-  }
-  let hash: Buffer;
-  let prevout: Output;
-
-  if (input.nonWitnessUtxo) {
-    const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
-      cache,
-      input,
-      inputIndex,
-    );
-
-    const prevoutHash = unsignedTx.ins[inputIndex].hash;
-    const utxoHash = nonWitnessUtxoTx.getHash();
-
-    // If a non-witness UTXO is provided, its hash must match the hash specified in the prevout
-    if (!prevoutHash.equals(utxoHash)) {
-      throw new Error(
-        `Non-witness UTXO hash for input #${inputIndex} doesn't match the hash specified in the prevout`,
-      );
-    }
-
-    const prevoutIndex = unsignedTx.ins[inputIndex].index;
-    prevout = nonWitnessUtxoTx.outs[prevoutIndex] as Output;
-  } else if (input.witnessUtxo) {
-    prevout = input.witnessUtxo;
-  } else {
-    throw new Error('Need a Utxo input item for signing');
-  }
-
-  const { meaningfulScript, type } = getMeaningfulScript(
-    prevout.script,
-    inputIndex,
-    'input',
-    input.redeemScript,
-    input.witnessScript,
-  );
-
-  if (['p2sh-p2wsh', 'p2wsh'].indexOf(type) >= 0) {
-    hash = unsignedTx.hashForWitnessV0(
-      inputIndex,
-      meaningfulScript,
-      prevout.value,
-      sighashType,
-    );
-  } else if (isP2WPKH(meaningfulScript)) {
-    // P2WPKH uses the P2PKH template for prevoutScript when signing
-    const signingScript = payments.p2pkh({ hash: meaningfulScript.slice(2) })
-      .output!;
-    hash = unsignedTx.hashForWitnessV0(
-      inputIndex,
-      signingScript,
-      prevout.value,
-      sighashType,
-    );
-  } else {
-    // non-segwit
-    if (
-      input.nonWitnessUtxo === undefined &&
-      cache.__UNSAFE_SIGN_NONSEGWIT === false
-    )
-      throw new Error(
-        `Input #${inputIndex} has witnessUtxo but non-segwit script: ` +
-          `${meaningfulScript.toString('hex')}`,
-      );
-    if (!forValidate && cache.__UNSAFE_SIGN_NONSEGWIT !== false)
-      console.warn(
-        'Warning: Signing non-segwit inputs without the full parent transaction ' +
-          'means there is a chance that a miner could feed you incorrect information ' +
-          "to trick you into paying large fees. This behavior is the same as Psbt's predecesor " +
-          '(TransactionBuilder - now removed) when signing non-segwit scripts. You are not ' +
-          'able to export this Psbt with toBuffer|toBase64|toHex since it is not ' +
-          'BIP174 compliant.\n*********************\nPROCEED WITH CAUTION!\n' +
-          '*********************',
-      );
-    hash = unsignedTx.hashForSignature(
-      inputIndex,
-      meaningfulScript,
-      sighashType,
-    );
-  }
-
-  return {
-    script: meaningfulScript,
-    sighashType,
-    hash,
-  };
-}
-
-function getPayment(
-  script: Buffer,
-  scriptType: string,
-  partialSig: PartialSig[],
-): payments.Payment {
-  let payment: payments.Payment;
-  switch (scriptType) {
-    case 'multisig':
-      const sigs = getSortedSigs(script, partialSig);
-      payment = payments.p2ms({
-        output: script,
-        signatures: sigs,
-      });
-      break;
-    case 'pubkey':
-      payment = payments.p2pk({
-        output: script,
-        signature: partialSig[0].signature,
-      });
-      break;
-    case 'pubkeyhash':
-      payment = payments.p2pkh({
-        output: script,
-        pubkey: partialSig[0].pubkey,
-        signature: partialSig[0].signature,
-      });
-      break;
-    case 'witnesspubkeyhash':
-      payment = payments.p2wpkh({
-        output: script,
-        pubkey: partialSig[0].pubkey,
-        signature: partialSig[0].signature,
-      });
-      break;
-  }
-  return payment!;
-}
-
-function getPsigsFromInputFinalScripts(input: PsbtInput): PartialSig[] {
-  const scriptItems = !input.finalScriptSig
-    ? []
-    : bscript.decompile(input.finalScriptSig) || [];
-  const witnessItems = !input.finalScriptWitness
-    ? []
-    : bscript.decompile(input.finalScriptWitness) || [];
-  return scriptItems
-    .concat(witnessItems)
-    .filter(item => {
-      return Buffer.isBuffer(item) && bscript.isCanonicalScriptSignature(item);
-    })
-    .map(sig => ({ signature: sig })) as PartialSig[];
-}
-
-interface GetScriptReturn {
-  script: Buffer | null;
-  isSegwit: boolean;
-  isP2SH: boolean;
-  isP2WSH: boolean;
-}
-function getScriptFromInput(
-  inputIndex: number,
-  input: PsbtInput,
-  cache: PsbtCache,
-): GetScriptReturn {
-  const unsignedTx = cache.__TX;
-  const res: GetScriptReturn = {
-    script: null,
-    isSegwit: false,
-    isP2SH: false,
-    isP2WSH: false,
-  };
-  res.isP2SH = !!input.redeemScript;
-  res.isP2WSH = !!input.witnessScript;
-  if (input.witnessScript) {
-    res.script = input.witnessScript;
-  } else if (input.redeemScript) {
-    res.script = input.redeemScript;
-  } else {
-    if (input.nonWitnessUtxo) {
-      const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
-        cache,
-        input,
-        inputIndex,
-      );
-      const prevoutIndex = unsignedTx.ins[inputIndex].index;
-      res.script = nonWitnessUtxoTx.outs[prevoutIndex].script;
-    } else if (input.witnessUtxo) {
-      res.script = input.witnessUtxo.script;
-    }
-  }
-  if (input.witnessScript || isP2WPKH(res.script!)) {
-    res.isSegwit = true;
-  }
-  return res;
-}
-
-function getSignersFromHD(
-  inputIndex: number,
-  inputs: PsbtInput[],
-  hdKeyPair: HDSigner | HDSignerAsync,
-): Array<Signer | SignerAsync> {
-  const input = checkForInput(inputs, inputIndex);
-  if (!input.bip32Derivation || input.bip32Derivation.length === 0) {
-    throw new Error('Need bip32Derivation to sign with HD');
-  }
-  const myDerivations = input.bip32Derivation
-    .map(bipDv => {
-      if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) {
-        return bipDv;
-      } else {
-        return;
-      }
-    })
-    .filter(v => !!v);
-  if (myDerivations.length === 0) {
-    throw new Error(
-      'Need one bip32Derivation masterFingerprint to match the HDSigner fingerprint',
-    );
-  }
-  const signers: Array<Signer | SignerAsync> = myDerivations.map(bipDv => {
-    const node = hdKeyPair.derivePath(bipDv!.path);
-    if (!bipDv!.pubkey.equals(node.publicKey)) {
-      throw new Error('pubkey did not match bip32Derivation');
-    }
-    return node;
-  });
-  return signers;
-}
-
-function getSortedSigs(script: Buffer, partialSig: PartialSig[]): Buffer[] {
-  const p2ms = payments.p2ms({ output: script });
-  // for each pubkey in order of p2ms script
-  return p2ms
-    .pubkeys!.map(pk => {
-      // filter partialSig array by pubkey being equal
-      return (
-        partialSig.filter(ps => {
-          return ps.pubkey.equals(pk);
-        })[0] || {}
-      ).signature;
-      // Any pubkey without a match will return undefined
-      // this last filter removes all the undefined items in the array.
-    })
-    .filter(v => !!v);
-}
-
-function scriptWitnessToWitnessStack(buffer: Buffer): Buffer[] {
-  let offset = 0;
-
-  function readSlice(n: number): Buffer {
-    offset += n;
-    return buffer.slice(offset - n, offset);
-  }
-
-  function readVarInt(): number {
-    const vi = varuint.decode(buffer, offset);
-    offset += (varuint.decode as any).bytes;
-    return vi;
-  }
-
-  function readVarSlice(): Buffer {
-    return readSlice(readVarInt());
-  }
-
-  function readVector(): Buffer[] {
-    const count = readVarInt();
-    const vector: Buffer[] = [];
-    for (let i = 0; i < count; i++) vector.push(readVarSlice());
-    return vector;
-  }
-
-  return readVector();
-}
-
-function sighashTypeToString(sighashType: number): string {
-  let text =
-    sighashType & Transaction.SIGHASH_ANYONECANPAY
-      ? 'SIGHASH_ANYONECANPAY | '
-      : '';
-  const sigMod = sighashType & 0x1f;
-  switch (sigMod) {
-    case Transaction.SIGHASH_ALL:
-      text += 'SIGHASH_ALL';
-      break;
-    case Transaction.SIGHASH_SINGLE:
-      text += 'SIGHASH_SINGLE';
-      break;
-    case Transaction.SIGHASH_NONE:
-      text += 'SIGHASH_NONE';
-      break;
-  }
-  return text;
-}
-
-function witnessStackToScriptWitness(witness: Buffer[]): Buffer {
-  let buffer = Buffer.allocUnsafe(0);
-
-  function writeSlice(slice: Buffer): void {
-    buffer = Buffer.concat([buffer, Buffer.from(slice)]);
-  }
-
-  function writeVarInt(i: number): void {
-    const currentLen = buffer.length;
-    const varintLen = varuint.encodingLength(i);
-
-    buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]);
-    varuint.encode(i, buffer, currentLen);
-  }
-
-  function writeVarSlice(slice: Buffer): void {
-    writeVarInt(slice.length);
-    writeSlice(slice);
-  }
-
-  function writeVector(vector: Buffer[]): void {
-    writeVarInt(vector.length);
-    vector.forEach(writeVarSlice);
-  }
-
-  writeVector(witness);
-
-  return buffer;
-}
-
-function addNonWitnessTxCache(
-  cache: PsbtCache,
-  input: PsbtInput,
-  inputIndex: number,
-): void {
-  cache.__NON_WITNESS_UTXO_BUF_CACHE[inputIndex] = input.nonWitnessUtxo!;
-
-  const tx = Transaction.fromBuffer(input.nonWitnessUtxo!);
-  cache.__NON_WITNESS_UTXO_TX_CACHE[inputIndex] = tx;
-
-  const self = cache;
-  const selfIndex = inputIndex;
-  delete input.nonWitnessUtxo;
-  Object.defineProperty(input, 'nonWitnessUtxo', {
-    enumerable: true,
-    get(): Buffer {
-      const buf = self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex];
-      const txCache = self.__NON_WITNESS_UTXO_TX_CACHE[selfIndex];
-      if (buf !== undefined) {
-        return buf;
-      } else {
-        const newBuf = txCache.toBuffer();
-        self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex] = newBuf;
-        return newBuf;
-      }
-    },
-    set(data: Buffer): void {
-      self.__NON_WITNESS_UTXO_BUF_CACHE[selfIndex] = data;
-    },
-  });
-}
-
-function inputFinalizeGetAmts(
-  inputs: PsbtInput[],
-  tx: Transaction,
-  cache: PsbtCache,
-  mustFinalize: boolean,
-): void {
-  let inputAmount = 0;
-  inputs.forEach((input, idx) => {
-    if (mustFinalize && input.finalScriptSig)
-      tx.ins[idx].script = input.finalScriptSig;
-    if (mustFinalize && input.finalScriptWitness) {
-      tx.ins[idx].witness = scriptWitnessToWitnessStack(
-        input.finalScriptWitness,
-      );
-    }
-    if (input.witnessUtxo) {
-      inputAmount += input.witnessUtxo.value;
-    } else if (input.nonWitnessUtxo) {
-      const nwTx = nonWitnessUtxoTxFromCache(cache, input, idx);
-      const vout = tx.ins[idx].index;
-      const out = nwTx.outs[vout] as Output;
-      inputAmount += out.value;
-    }
-  });
-  const outputAmount = (tx.outs as Output[]).reduce(
-    (total, o) => total + o.value,
-    0,
-  );
-  const fee = inputAmount - outputAmount;
-  if (fee < 0) {
-    throw new Error('Outputs are spending more than Inputs');
-  }
-  const bytes = tx.virtualSize();
-  cache.__FEE = fee;
-  cache.__EXTRACTED_TX = tx;
-  cache.__FEE_RATE = Math.floor(fee / bytes);
-}
-
-function nonWitnessUtxoTxFromCache(
-  cache: PsbtCache,
-  input: PsbtInput,
-  inputIndex: number,
-): Transaction {
-  const c = cache.__NON_WITNESS_UTXO_TX_CACHE;
-  if (!c[inputIndex]) {
-    addNonWitnessTxCache(cache, input, inputIndex);
-  }
-  return c[inputIndex];
-}
-
-function getScriptFromUtxo(
-  inputIndex: number,
-  input: PsbtInput,
-  cache: PsbtCache,
-): Buffer {
-  if (input.witnessUtxo !== undefined) {
-    return input.witnessUtxo.script;
-  } else if (input.nonWitnessUtxo !== undefined) {
-    const nonWitnessUtxoTx = nonWitnessUtxoTxFromCache(
-      cache,
-      input,
-      inputIndex,
-    );
-    return nonWitnessUtxoTx.outs[cache.__TX.ins[inputIndex].index].script;
-  } else {
-    throw new Error("Can't find pubkey in input without Utxo data");
-  }
-}
-
-function pubkeyInInput(
-  pubkey: Buffer,
-  input: PsbtInput,
-  inputIndex: number,
-  cache: PsbtCache,
-): boolean {
-  const script = getScriptFromUtxo(inputIndex, input, cache);
-  const { meaningfulScript } = getMeaningfulScript(
-    script,
-    inputIndex,
-    'input',
-    input.redeemScript,
-    input.witnessScript,
-  );
-  return pubkeyInScript(pubkey, meaningfulScript);
-}
-
-function pubkeyInOutput(
-  pubkey: Buffer,
-  output: PsbtOutput,
-  outputIndex: number,
-  cache: PsbtCache,
-): boolean {
-  const script = cache.__TX.outs[outputIndex].script;
-  const { meaningfulScript } = getMeaningfulScript(
-    script,
-    outputIndex,
-    'output',
-    output.redeemScript,
-    output.witnessScript,
-  );
-  return pubkeyInScript(pubkey, meaningfulScript);
-}
-
-function redeemFromFinalScriptSig(
-  finalScript: Buffer | undefined,
-): Buffer | undefined {
-  if (!finalScript) return;
-  const decomp = bscript.decompile(finalScript);
-  if (!decomp) return;
-  const lastItem = decomp[decomp.length - 1];
-  if (
-    !Buffer.isBuffer(lastItem) ||
-    isPubkeyLike(lastItem) ||
-    isSigLike(lastItem)
-  )
-    return;
-  const sDecomp = bscript.decompile(lastItem);
-  if (!sDecomp) return;
-  return lastItem;
-}
-
-function redeemFromFinalWitnessScript(
-  finalScript: Buffer | undefined,
-): Buffer | undefined {
-  if (!finalScript) return;
-  const decomp = scriptWitnessToWitnessStack(finalScript);
-  const lastItem = decomp[decomp.length - 1];
-  if (isPubkeyLike(lastItem)) return;
-  const sDecomp = bscript.decompile(lastItem);
-  if (!sDecomp) return;
-  return lastItem;
-}
-
-function compressPubkey(pubkey: Buffer): Buffer {
-  if (pubkey.length === 65) {
-    const parity = pubkey[64] & 1;
-    const newKey = pubkey.slice(0, 33);
-    newKey[0] = 2 | parity;
-    return newKey;
-  }
-  return pubkey.slice();
-}
-
-function isPubkeyLike(buf: Buffer): boolean {
-  return buf.length === 33 && bscript.isCanonicalPubKey(buf);
-}
-
-function isSigLike(buf: Buffer): boolean {
-  return bscript.isCanonicalScriptSignature(buf);
-}
-
-function getMeaningfulScript(
-  script: Buffer,
-  index: number,
-  ioType: 'input' | 'output',
-  redeemScript?: Buffer,
-  witnessScript?: Buffer,
-): {
-  meaningfulScript: Buffer;
-  type: 'p2sh' | 'p2wsh' | 'p2sh-p2wsh' | 'raw';
-} {
-  const isP2SH = isP2SHScript(script);
-  const isP2SHP2WSH = isP2SH && redeemScript && isP2WSHScript(redeemScript);
-  const isP2WSH = isP2WSHScript(script);
-
-  if (isP2SH && redeemScript === undefined)
-    throw new Error('scriptPubkey is P2SH but redeemScript missing');
-  if ((isP2WSH || isP2SHP2WSH) && witnessScript === undefined)
-    throw new Error(
-      'scriptPubkey or redeemScript is P2WSH but witnessScript missing',
-    );
-
-  let meaningfulScript: Buffer;
-
-  if (isP2SHP2WSH) {
-    meaningfulScript = witnessScript!;
-    checkRedeemScript(index, script, redeemScript!, ioType);
-    checkWitnessScript(index, redeemScript!, witnessScript!, ioType);
-    checkInvalidP2WSH(meaningfulScript);
-  } else if (isP2WSH) {
-    meaningfulScript = witnessScript!;
-    checkWitnessScript(index, script, witnessScript!, ioType);
-    checkInvalidP2WSH(meaningfulScript);
-  } else if (isP2SH) {
-    meaningfulScript = redeemScript!;
-    checkRedeemScript(index, script, redeemScript!, ioType);
-  } else {
-    meaningfulScript = script;
-  }
-  return {
-    meaningfulScript,
-    type: isP2SHP2WSH
-      ? 'p2sh-p2wsh'
-      : isP2SH
-      ? 'p2sh'
-      : isP2WSH
-      ? 'p2wsh'
-      : 'raw',
-  };
-}
-
-function checkInvalidP2WSH(script: Buffer): void {
-  if (isP2WPKH(script) || isP2SHScript(script)) {
-    throw new Error('P2WPKH or P2SH can not be contained within P2WSH');
-  }
-}
-
-function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean {
-  const pubkeyHash = hash160(pubkey);
-
-  const decompiled = bscript.decompile(script);
-  if (decompiled === null) throw new Error('Unknown script error');
-
-  return decompiled.some(element => {
-    if (typeof element === 'number') return false;
-    return element.equals(pubkey) || element.equals(pubkeyHash);
-  });
-}
-
-type AllScriptType =
-  | 'witnesspubkeyhash'
-  | 'pubkeyhash'
-  | 'multisig'
-  | 'pubkey'
-  | 'nonstandard'
-  | 'p2sh-witnesspubkeyhash'
-  | 'p2sh-pubkeyhash'
-  | 'p2sh-multisig'
-  | 'p2sh-pubkey'
-  | 'p2sh-nonstandard'
-  | 'p2wsh-pubkeyhash'
-  | 'p2wsh-multisig'
-  | 'p2wsh-pubkey'
-  | 'p2wsh-nonstandard'
-  | 'p2sh-p2wsh-pubkeyhash'
-  | 'p2sh-p2wsh-multisig'
-  | 'p2sh-p2wsh-pubkey'
-  | 'p2sh-p2wsh-nonstandard';
-type ScriptType =
-  | 'witnesspubkeyhash'
-  | 'pubkeyhash'
-  | 'multisig'
-  | 'pubkey'
-  | 'nonstandard';
-function classifyScript(script: Buffer): ScriptType {
-  if (isP2WPKH(script)) return 'witnesspubkeyhash';
-  if (isP2PKH(script)) return 'pubkeyhash';
-  if (isP2MS(script)) return 'multisig';
-  if (isP2PK(script)) return 'pubkey';
-  return 'nonstandard';
-}
-
-function range(n: number): number[] {
-  return [...Array(n).keys()];
-}
diff --git a/ts_src/push_data.ts b/ts_src/push_data.ts
deleted file mode 100644
index 56bb02a..0000000
--- a/ts_src/push_data.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import { OPS } from './ops';
-
-export function encodingLength(i: number): number {
-  return i < OPS.OP_PUSHDATA1 ? 1 : i <= 0xff ? 2 : i <= 0xffff ? 3 : 5;
-}
-
-export function encode(buffer: Buffer, num: number, offset: number): number {
-  const size = encodingLength(num);
-
-  // ~6 bit
-  if (size === 1) {
-    buffer.writeUInt8(num, offset);
-
-    // 8 bit
-  } else if (size === 2) {
-    buffer.writeUInt8(OPS.OP_PUSHDATA1, offset);
-    buffer.writeUInt8(num, offset + 1);
-
-    // 16 bit
-  } else if (size === 3) {
-    buffer.writeUInt8(OPS.OP_PUSHDATA2, offset);
-    buffer.writeUInt16LE(num, offset + 1);
-
-    // 32 bit
-  } else {
-    buffer.writeUInt8(OPS.OP_PUSHDATA4, offset);
-    buffer.writeUInt32LE(num, offset + 1);
-  }
-
-  return size;
-}
-
-export function decode(
-  buffer: Buffer,
-  offset: number,
-): {
-  opcode: number;
-  number: number;
-  size: number;
-} | null {
-  const opcode = buffer.readUInt8(offset);
-  let num: number;
-  let size: number;
-
-  // ~6 bit
-  if (opcode < OPS.OP_PUSHDATA1) {
-    num = opcode;
-    size = 1;
-
-    // 8 bit
-  } else if (opcode === OPS.OP_PUSHDATA1) {
-    if (offset + 2 > buffer.length) return null;
-    num = buffer.readUInt8(offset + 1);
-    size = 2;
-
-    // 16 bit
-  } else if (opcode === OPS.OP_PUSHDATA2) {
-    if (offset + 3 > buffer.length) return null;
-    num = buffer.readUInt16LE(offset + 1);
-    size = 3;
-
-    // 32 bit
-  } else {
-    if (offset + 5 > buffer.length) return null;
-    if (opcode !== OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode');
-
-    num = buffer.readUInt32LE(offset + 1);
-    size = 5;
-  }
-
-  return {
-    opcode,
-    number: num,
-    size,
-  };
-}
diff --git a/ts_src/script.ts b/ts_src/script.ts
deleted file mode 100644
index 5d20ebc..0000000
--- a/ts_src/script.ts
+++ /dev/null
@@ -1,213 +0,0 @@
-import * as bip66 from './bip66';
-import { OPS, REVERSE_OPS } from './ops';
-import { Stack } from './payments';
-import * as pushdata from './push_data';
-import * as scriptNumber from './script_number';
-import * as scriptSignature from './script_signature';
-import * as types from './types';
-const { typeforce } = types;
-
-const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1
-export { OPS };
-
-function isOPInt(value: number): boolean {
-  return (
-    types.Number(value) &&
-    (value === OPS.OP_0 ||
-      (value >= OPS.OP_1 && value <= OPS.OP_16) ||
-      value === OPS.OP_1NEGATE)
-  );
-}
-
-function isPushOnlyChunk(value: number | Buffer): boolean {
-  return types.Buffer(value) || isOPInt(value as number);
-}
-
-export function isPushOnly(value: Stack): boolean {
-  return types.Array(value) && value.every(isPushOnlyChunk);
-}
-
-function asMinimalOP(buffer: Buffer): number | void {
-  if (buffer.length === 0) return OPS.OP_0;
-  if (buffer.length !== 1) return;
-  if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0];
-  if (buffer[0] === 0x81) return OPS.OP_1NEGATE;
-}
-
-function chunksIsBuffer(buf: Buffer | Stack): buf is Buffer {
-  return Buffer.isBuffer(buf);
-}
-
-function chunksIsArray(buf: Buffer | Stack): buf is Stack {
-  return types.Array(buf);
-}
-
-function singleChunkIsBuffer(buf: number | Buffer): buf is Buffer {
-  return Buffer.isBuffer(buf);
-}
-
-export function compile(chunks: Buffer | Stack): Buffer {
-  // TODO: remove me
-  if (chunksIsBuffer(chunks)) return chunks;
-
-  typeforce(types.Array, chunks);
-
-  const bufferSize = chunks.reduce((accum: number, chunk) => {
-    // data chunk
-    if (singleChunkIsBuffer(chunk)) {
-      // adhere to BIP62.3, minimal push policy
-      if (chunk.length === 1 && asMinimalOP(chunk) !== undefined) {
-        return accum + 1;
-      }
-
-      return accum + pushdata.encodingLength(chunk.length) + chunk.length;
-    }
-
-    // opcode
-    return accum + 1;
-  }, 0.0);
-
-  const buffer = Buffer.allocUnsafe(bufferSize);
-  let offset = 0;
-
-  chunks.forEach(chunk => {
-    // data chunk
-    if (singleChunkIsBuffer(chunk)) {
-      // adhere to BIP62.3, minimal push policy
-      const opcode = asMinimalOP(chunk);
-      if (opcode !== undefined) {
-        buffer.writeUInt8(opcode, offset);
-        offset += 1;
-        return;
-      }
-
-      offset += pushdata.encode(buffer, chunk.length, offset);
-      chunk.copy(buffer, offset);
-      offset += chunk.length;
-
-      // opcode
-    } else {
-      buffer.writeUInt8(chunk, offset);
-      offset += 1;
-    }
-  });
-
-  if (offset !== buffer.length) throw new Error('Could not decode chunks');
-  return buffer;
-}
-
-export function decompile(
-  buffer: Buffer | Array<number | Buffer>,
-): Array<number | Buffer> | null {
-  // TODO: remove me
-  if (chunksIsArray(buffer)) return buffer;
-
-  typeforce(types.Buffer, buffer);
-
-  const chunks: Array<number | Buffer> = [];
-  let i = 0;
-
-  while (i < buffer.length) {
-    const opcode = buffer[i];
-
-    // data chunk
-    if (opcode > OPS.OP_0 && opcode <= OPS.OP_PUSHDATA4) {
-      const d = pushdata.decode(buffer, i);
-
-      // did reading a pushDataInt fail?
-      if (d === null) return null;
-      i += d.size;
-
-      // attempt to read too much data?
-      if (i + d.number > buffer.length) return null;
-
-      const data = buffer.slice(i, i + d.number);
-      i += d.number;
-
-      // decompile minimally
-      const op = asMinimalOP(data);
-      if (op !== undefined) {
-        chunks.push(op);
-      } else {
-        chunks.push(data);
-      }
-
-      // opcode
-    } else {
-      chunks.push(opcode);
-
-      i += 1;
-    }
-  }
-
-  return chunks;
-}
-
-export function toASM(chunks: Buffer | Array<number | Buffer>): string {
-  if (chunksIsBuffer(chunks)) {
-    chunks = decompile(chunks) as Stack;
-  }
-
-  return chunks
-    .map(chunk => {
-      // data?
-      if (singleChunkIsBuffer(chunk)) {
-        const op = asMinimalOP(chunk);
-        if (op === undefined) return chunk.toString('hex');
-        chunk = op as number;
-      }
-
-      // opcode!
-      return REVERSE_OPS[chunk];
-    })
-    .join(' ');
-}
-
-export function fromASM(asm: string): Buffer {
-  typeforce(types.String, asm);
-
-  return compile(
-    asm.split(' ').map(chunkStr => {
-      // opcode?
-      if (OPS[chunkStr] !== undefined) return OPS[chunkStr];
-      typeforce(types.Hex, chunkStr);
-
-      // data!
-      return Buffer.from(chunkStr, 'hex');
-    }),
-  );
-}
-
-export function toStack(chunks: Buffer | Array<number | Buffer>): Buffer[] {
-  chunks = decompile(chunks) as Stack;
-  typeforce(isPushOnly, chunks);
-
-  return chunks.map(op => {
-    if (singleChunkIsBuffer(op)) return op;
-    if (op === OPS.OP_0) return Buffer.allocUnsafe(0);
-
-    return scriptNumber.encode(op - OP_INT_BASE);
-  });
-}
-
-export function isCanonicalPubKey(buffer: Buffer): boolean {
-  return types.isPoint(buffer);
-}
-
-export function isDefinedHashType(hashType: number): boolean {
-  const hashTypeMod = hashType & ~0x80;
-
-  // return hashTypeMod > SIGHASH_ALL && hashTypeMod < SIGHASH_SINGLE
-  return hashTypeMod > 0x00 && hashTypeMod < 0x04;
-}
-
-export function isCanonicalScriptSignature(buffer: Buffer): boolean {
-  if (!Buffer.isBuffer(buffer)) return false;
-  if (!isDefinedHashType(buffer[buffer.length - 1])) return false;
-
-  return bip66.check(buffer.slice(0, -1));
-}
-
-// tslint:disable-next-line variable-name
-export const number = scriptNumber;
-export const signature = scriptSignature;
diff --git a/ts_src/script_number.ts b/ts_src/script_number.ts
deleted file mode 100644
index a4c502f..0000000
--- a/ts_src/script_number.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-export function decode(
-  buffer: Buffer,
-  maxLength?: number,
-  minimal?: boolean,
-): number {
-  maxLength = maxLength || 4;
-  minimal = minimal === undefined ? true : minimal;
-
-  const length = buffer.length;
-  if (length === 0) return 0;
-  if (length > maxLength) throw new TypeError('Script number overflow');
-  if (minimal) {
-    if ((buffer[length - 1] & 0x7f) === 0) {
-      if (length <= 1 || (buffer[length - 2] & 0x80) === 0)
-        throw new Error('Non-minimally encoded script number');
-    }
-  }
-
-  // 40-bit
-  if (length === 5) {
-    const a = buffer.readUInt32LE(0);
-    const b = buffer.readUInt8(4);
-
-    if (b & 0x80) return -((b & ~0x80) * 0x100000000 + a);
-    return b * 0x100000000 + a;
-  }
-
-  // 32-bit / 24-bit / 16-bit / 8-bit
-  let result = 0;
-  for (let i = 0; i < length; ++i) {
-    result |= buffer[i] << (8 * i);
-  }
-
-  if (buffer[length - 1] & 0x80)
-    return -(result & ~(0x80 << (8 * (length - 1))));
-  return result;
-}
-
-function scriptNumSize(i: number): number {
-  return i > 0x7fffffff
-    ? 5
-    : i > 0x7fffff
-    ? 4
-    : i > 0x7fff
-    ? 3
-    : i > 0x7f
-    ? 2
-    : i > 0x00
-    ? 1
-    : 0;
-}
-
-export function encode(_number: number): Buffer {
-  let value = Math.abs(_number);
-  const size = scriptNumSize(value);
-  const buffer = Buffer.allocUnsafe(size);
-  const negative = _number < 0;
-
-  for (let i = 0; i < size; ++i) {
-    buffer.writeUInt8(value & 0xff, i);
-    value >>= 8;
-  }
-
-  if (buffer[size - 1] & 0x80) {
-    buffer.writeUInt8(negative ? 0x80 : 0x00, size - 1);
-  } else if (negative) {
-    buffer[size - 1] |= 0x80;
-  }
-
-  return buffer;
-}
diff --git a/ts_src/script_signature.ts b/ts_src/script_signature.ts
deleted file mode 100644
index df206e8..0000000
--- a/ts_src/script_signature.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import * as bip66 from './bip66';
-import * as types from './types';
-const { typeforce } = types;
-
-const ZERO = Buffer.alloc(1, 0);
-function toDER(x: Buffer): Buffer {
-  let i = 0;
-  while (x[i] === 0) ++i;
-  if (i === x.length) return ZERO;
-  x = x.slice(i);
-  if (x[0] & 0x80) return Buffer.concat([ZERO, x], 1 + x.length);
-  return x;
-}
-
-function fromDER(x: Buffer): Buffer {
-  if (x[0] === 0x00) x = x.slice(1);
-  const buffer = Buffer.alloc(32, 0);
-  const bstart = Math.max(0, 32 - x.length);
-  x.copy(buffer, bstart);
-  return buffer;
-}
-
-interface ScriptSignature {
-  signature: Buffer;
-  hashType: number;
-}
-
-// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed)
-export function decode(buffer: Buffer): ScriptSignature {
-  const hashType = buffer.readUInt8(buffer.length - 1);
-  const hashTypeMod = hashType & ~0x80;
-  if (hashTypeMod <= 0 || hashTypeMod >= 4)
-    throw new Error('Invalid hashType ' + hashType);
-
-  const decoded = bip66.decode(buffer.slice(0, -1));
-  const r = fromDER(decoded.r);
-  const s = fromDER(decoded.s);
-  const signature = Buffer.concat([r, s], 64);
-
-  return { signature, hashType };
-}
-
-export function encode(signature: Buffer, hashType: number): Buffer {
-  typeforce(
-    {
-      signature: types.BufferN(64),
-      hashType: types.UInt8,
-    },
-    { signature, hashType },
-  );
-
-  const hashTypeMod = hashType & ~0x80;
-  if (hashTypeMod <= 0 || hashTypeMod >= 4)
-    throw new Error('Invalid hashType ' + hashType);
-
-  const hashTypeBuffer = Buffer.allocUnsafe(1);
-  hashTypeBuffer.writeUInt8(hashType, 0);
-
-  const r = toDER(signature.slice(0, 32));
-  const s = toDER(signature.slice(32, 64));
-
-  return Buffer.concat([bip66.encode(r, s), hashTypeBuffer]);
-}
diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts
deleted file mode 100644
index 416f20e..0000000
--- a/ts_src/transaction.ts
+++ /dev/null
@@ -1,674 +0,0 @@
-import {
-  BufferReader,
-  BufferWriter,
-  reverseBuffer,
-  varuint,
-} from './bufferutils';
-import * as bcrypto from './crypto';
-import * as bscript from './script';
-import { OPS as opcodes } from './script';
-import * as types from './types';
-const { typeforce } = types;
-
-function varSliceSize(someScript: Buffer): number {
-  const length = someScript.length;
-
-  return varuint.encodingLength(length) + length;
-}
-
-function vectorSize(someVector: Buffer[]): number {
-  const length = someVector.length;
-
-  return (
-    varuint.encodingLength(length) +
-    someVector.reduce((sum, witness) => {
-      return sum + varSliceSize(witness);
-    }, 0)
-  );
-}
-
-const EMPTY_BUFFER: Buffer = Buffer.allocUnsafe(0);
-const EMPTY_WITNESS: Buffer[] = [];
-const ZERO: Buffer = Buffer.from(
-  '0000000000000000000000000000000000000000000000000000000000000000',
-  'hex',
-);
-const ONE: Buffer = Buffer.from(
-  '0000000000000000000000000000000000000000000000000000000000000001',
-  'hex',
-);
-const VALUE_UINT64_MAX: Buffer = Buffer.from('ffffffffffffffff', 'hex');
-const BLANK_OUTPUT = {
-  script: EMPTY_BUFFER,
-  valueBuffer: VALUE_UINT64_MAX,
-};
-
-function isOutput(out: Output): boolean {
-  return out.value !== undefined;
-}
-
-export interface Output {
-  script: Buffer;
-  value: number;
-}
-
-export interface Input {
-  hash: Buffer;
-  index: number;
-  script: Buffer;
-  sequence: number;
-  witness: Buffer[];
-}
-
-export class Transaction {
-  static readonly DEFAULT_SEQUENCE = 0xffffffff;
-  static readonly SIGHASH_DEFAULT = 0x00;
-  static readonly SIGHASH_ALL = 0x01;
-  static readonly SIGHASH_NONE = 0x02;
-  static readonly SIGHASH_SINGLE = 0x03;
-  static readonly SIGHASH_ANYONECANPAY = 0x80;
-  static readonly SIGHASH_OUTPUT_MASK = 0x03;
-  static readonly SIGHASH_INPUT_MASK = 0x80;
-  static readonly ADVANCED_TRANSACTION_MARKER = 0x00;
-  static readonly ADVANCED_TRANSACTION_FLAG = 0x01;
-
-  static fromBuffer(buffer: Buffer, _NO_STRICT?: boolean): Transaction {
-    const bufferReader = new BufferReader(buffer);
-
-    const tx = new Transaction();
-    tx.version = bufferReader.readInt32();
-
-    const marker = bufferReader.readUInt8();
-    const flag = bufferReader.readUInt8();
-
-    let hasWitnesses = false;
-    if (
-      marker === Transaction.ADVANCED_TRANSACTION_MARKER &&
-      flag === Transaction.ADVANCED_TRANSACTION_FLAG
-    ) {
-      hasWitnesses = true;
-    } else {
-      bufferReader.offset -= 2;
-    }
-
-    const vinLen = bufferReader.readVarInt();
-    for (let i = 0; i < vinLen; ++i) {
-      tx.ins.push({
-        hash: bufferReader.readSlice(32),
-        index: bufferReader.readUInt32(),
-        script: bufferReader.readVarSlice(),
-        sequence: bufferReader.readUInt32(),
-        witness: EMPTY_WITNESS,
-      });
-    }
-
-    const voutLen = bufferReader.readVarInt();
-    for (let i = 0; i < voutLen; ++i) {
-      tx.outs.push({
-        value: bufferReader.readUInt64(),
-        script: bufferReader.readVarSlice(),
-      });
-    }
-
-    if (hasWitnesses) {
-      for (let i = 0; i < vinLen; ++i) {
-        tx.ins[i].witness = bufferReader.readVector();
-      }
-
-      // was this pointless?
-      if (!tx.hasWitnesses())
-        throw new Error('Transaction has superfluous witness data');
-    }
-
-    tx.locktime = bufferReader.readUInt32();
-
-    if (_NO_STRICT) return tx;
-    if (bufferReader.offset !== buffer.length)
-      throw new Error('Transaction has unexpected data');
-
-    return tx;
-  }
-
-  static fromHex(hex: string): Transaction {
-    return Transaction.fromBuffer(Buffer.from(hex, 'hex'), false);
-  }
-
-  static isCoinbaseHash(buffer: Buffer): boolean {
-    typeforce(types.Hash256bit, buffer);
-    for (let i = 0; i < 32; ++i) {
-      if (buffer[i] !== 0) return false;
-    }
-    return true;
-  }
-
-  version: number = 1;
-  locktime: number = 0;
-  ins: Input[] = [];
-  outs: Output[] = [];
-
-  isCoinbase(): boolean {
-    return (
-      this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash)
-    );
-  }
-
-  addInput(
-    hash: Buffer,
-    index: number,
-    sequence?: number,
-    scriptSig?: Buffer,
-  ): number {
-    typeforce(
-      types.tuple(
-        types.Hash256bit,
-        types.UInt32,
-        types.maybe(types.UInt32),
-        types.maybe(types.Buffer),
-      ),
-      arguments,
-    );
-
-    if (types.Null(sequence)) {
-      sequence = Transaction.DEFAULT_SEQUENCE;
-    }
-
-    // Add the input and return the input's index
-    return (
-      this.ins.push({
-        hash,
-        index,
-        script: scriptSig || EMPTY_BUFFER,
-        sequence: sequence as number,
-        witness: EMPTY_WITNESS,
-      }) - 1
-    );
-  }
-
-  addOutput(scriptPubKey: Buffer, value: number): number {
-    typeforce(types.tuple(types.Buffer, types.Satoshi), arguments);
-
-    // Add the output and return the output's index
-    return (
-      this.outs.push({
-        script: scriptPubKey,
-        value,
-      }) - 1
-    );
-  }
-
-  hasWitnesses(): boolean {
-    return this.ins.some(x => {
-      return x.witness.length !== 0;
-    });
-  }
-
-  weight(): number {
-    const base = this.byteLength(false);
-    const total = this.byteLength(true);
-    return base * 3 + total;
-  }
-
-  virtualSize(): number {
-    return Math.ceil(this.weight() / 4);
-  }
-
-  byteLength(_ALLOW_WITNESS: boolean = true): number {
-    const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses();
-
-    return (
-      (hasWitnesses ? 10 : 8) +
-      varuint.encodingLength(this.ins.length) +
-      varuint.encodingLength(this.outs.length) +
-      this.ins.reduce((sum, input) => {
-        return sum + 40 + varSliceSize(input.script);
-      }, 0) +
-      this.outs.reduce((sum, output) => {
-        return sum + 8 + varSliceSize(output.script);
-      }, 0) +
-      (hasWitnesses
-        ? this.ins.reduce((sum, input) => {
-            return sum + vectorSize(input.witness);
-          }, 0)
-        : 0)
-    );
-  }
-
-  clone(): Transaction {
-    const newTx = new Transaction();
-    newTx.version = this.version;
-    newTx.locktime = this.locktime;
-
-    newTx.ins = this.ins.map(txIn => {
-      return {
-        hash: txIn.hash,
-        index: txIn.index,
-        script: txIn.script,
-        sequence: txIn.sequence,
-        witness: txIn.witness,
-      };
-    });
-
-    newTx.outs = this.outs.map(txOut => {
-      return {
-        script: txOut.script,
-        value: txOut.value,
-      };
-    });
-
-    return newTx;
-  }
-
-  /**
-   * Hash transaction for signing a specific input.
-   *
-   * Bitcoin uses a different hash for each signed transaction input.
-   * This method copies the transaction, makes the necessary changes based on the
-   * hashType, and then hashes the result.
-   * This hash can then be used to sign the provided transaction input.
-   */
-  hashForSignature(
-    inIndex: number,
-    prevOutScript: Buffer,
-    hashType: number,
-  ): Buffer {
-    typeforce(
-      types.tuple(types.UInt32, types.Buffer, /* types.UInt8 */ types.Number),
-      arguments,
-    );
-
-    // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29
-    if (inIndex >= this.ins.length) return ONE;
-
-    // ignore OP_CODESEPARATOR
-    const ourScript = bscript.compile(
-      bscript.decompile(prevOutScript)!.filter(x => {
-        return x !== opcodes.OP_CODESEPARATOR;
-      }),
-    );
-
-    const txTmp = this.clone();
-
-    // SIGHASH_NONE: ignore all outputs? (wildcard payee)
-    if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) {
-      txTmp.outs = [];
-
-      // ignore sequence numbers (except at inIndex)
-      txTmp.ins.forEach((input, i) => {
-        if (i === inIndex) return;
-
-        input.sequence = 0;
-      });
-
-      // SIGHASH_SINGLE: ignore all outputs, except at the same index?
-    } else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) {
-      // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60
-      if (inIndex >= this.outs.length) return ONE;
-
-      // truncate outputs after
-      txTmp.outs.length = inIndex + 1;
-
-      // "blank" outputs before
-      for (let i = 0; i < inIndex; i++) {
-        (txTmp.outs as any)[i] = BLANK_OUTPUT;
-      }
-
-      // ignore sequence numbers (except at inIndex)
-      txTmp.ins.forEach((input, y) => {
-        if (y === inIndex) return;
-
-        input.sequence = 0;
-      });
-    }
-
-    // SIGHASH_ANYONECANPAY: ignore inputs entirely?
-    if (hashType & Transaction.SIGHASH_ANYONECANPAY) {
-      txTmp.ins = [txTmp.ins[inIndex]];
-      txTmp.ins[0].script = ourScript;
-
-      // SIGHASH_ALL: only ignore input scripts
-    } else {
-      // "blank" others input scripts
-      txTmp.ins.forEach(input => {
-        input.script = EMPTY_BUFFER;
-      });
-      txTmp.ins[inIndex].script = ourScript;
-    }
-
-    // serialize and hash
-    const buffer: Buffer = Buffer.allocUnsafe(txTmp.byteLength(false) + 4);
-    buffer.writeInt32LE(hashType, buffer.length - 4);
-    txTmp.__toBuffer(buffer, 0, false);
-
-    return bcrypto.hash256(buffer);
-  }
-
-  hashForWitnessV1(
-    inIndex: number,
-    prevOutScripts: Buffer[],
-    values: number[],
-    hashType: number,
-    leafHash?: Buffer,
-    annex?: Buffer,
-  ): Buffer {
-    // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message
-    typeforce(
-      types.tuple(
-        types.UInt32,
-        typeforce.arrayOf(types.Buffer),
-        typeforce.arrayOf(types.Satoshi),
-        types.UInt32,
-      ),
-      arguments,
-    );
-
-    if (
-      values.length !== this.ins.length ||
-      prevOutScripts.length !== this.ins.length
-    ) {
-      throw new Error('Must supply prevout script and value for all inputs');
-    }
-
-    const outputType =
-      hashType === Transaction.SIGHASH_DEFAULT
-        ? Transaction.SIGHASH_ALL
-        : hashType & Transaction.SIGHASH_OUTPUT_MASK;
-
-    const inputType = hashType & Transaction.SIGHASH_INPUT_MASK;
-
-    const isAnyoneCanPay = inputType === Transaction.SIGHASH_ANYONECANPAY;
-    const isNone = outputType === Transaction.SIGHASH_NONE;
-    const isSingle = outputType === Transaction.SIGHASH_SINGLE;
-
-    let hashPrevouts = EMPTY_BUFFER;
-    let hashAmounts = EMPTY_BUFFER;
-    let hashScriptPubKeys = EMPTY_BUFFER;
-    let hashSequences = EMPTY_BUFFER;
-    let hashOutputs = EMPTY_BUFFER;
-
-    if (!isAnyoneCanPay) {
-      let bufferWriter = BufferWriter.withCapacity(36 * this.ins.length);
-      this.ins.forEach(txIn => {
-        bufferWriter.writeSlice(txIn.hash);
-        bufferWriter.writeUInt32(txIn.index);
-      });
-      hashPrevouts = bcrypto.sha256(bufferWriter.end());
-
-      bufferWriter = BufferWriter.withCapacity(8 * this.ins.length);
-      values.forEach(value => bufferWriter.writeUInt64(value));
-      hashAmounts = bcrypto.sha256(bufferWriter.end());
-
-      bufferWriter = BufferWriter.withCapacity(
-        prevOutScripts.map(varSliceSize).reduce((a, b) => a + b),
-      );
-      prevOutScripts.forEach(prevOutScript =>
-        bufferWriter.writeVarSlice(prevOutScript),
-      );
-      hashScriptPubKeys = bcrypto.sha256(bufferWriter.end());
-
-      bufferWriter = BufferWriter.withCapacity(4 * this.ins.length);
-      this.ins.forEach(txIn => bufferWriter.writeUInt32(txIn.sequence));
-      hashSequences = bcrypto.sha256(bufferWriter.end());
-    }
-
-    if (!(isNone || isSingle)) {
-      const txOutsSize = this.outs
-        .map(output => 8 + varSliceSize(output.script))
-        .reduce((a, b) => a + b);
-      const bufferWriter = BufferWriter.withCapacity(txOutsSize);
-
-      this.outs.forEach(out => {
-        bufferWriter.writeUInt64(out.value);
-        bufferWriter.writeVarSlice(out.script);
-      });
-
-      hashOutputs = bcrypto.sha256(bufferWriter.end());
-    } else if (isSingle && inIndex < this.outs.length) {
-      const output = this.outs[inIndex];
-
-      const bufferWriter = BufferWriter.withCapacity(
-        8 + varSliceSize(output.script),
-      );
-      bufferWriter.writeUInt64(output.value);
-      bufferWriter.writeVarSlice(output.script);
-      hashOutputs = bcrypto.sha256(bufferWriter.end());
-    }
-
-    const spendType = (leafHash ? 2 : 0) + (annex ? 1 : 0);
-
-    // Length calculation from:
-    // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-14
-    // With extension from:
-    // https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#signature-validation
-    const sigMsgSize =
-      174 -
-      (isAnyoneCanPay ? 49 : 0) -
-      (isNone ? 32 : 0) +
-      (annex ? 32 : 0) +
-      (leafHash ? 37 : 0);
-    const sigMsgWriter = BufferWriter.withCapacity(sigMsgSize);
-
-    sigMsgWriter.writeUInt8(hashType);
-    // Transaction
-    sigMsgWriter.writeInt32(this.version);
-    sigMsgWriter.writeUInt32(this.locktime);
-    sigMsgWriter.writeSlice(hashPrevouts);
-    sigMsgWriter.writeSlice(hashAmounts);
-    sigMsgWriter.writeSlice(hashScriptPubKeys);
-    sigMsgWriter.writeSlice(hashSequences);
-    if (!(isNone || isSingle)) {
-      sigMsgWriter.writeSlice(hashOutputs);
-    }
-    // Input
-    sigMsgWriter.writeUInt8(spendType);
-    if (isAnyoneCanPay) {
-      const input = this.ins[inIndex];
-      sigMsgWriter.writeSlice(input.hash);
-      sigMsgWriter.writeUInt32(input.index);
-      sigMsgWriter.writeUInt64(values[inIndex]);
-      sigMsgWriter.writeVarSlice(prevOutScripts[inIndex]);
-      sigMsgWriter.writeUInt32(input.sequence);
-    } else {
-      sigMsgWriter.writeUInt32(inIndex);
-    }
-    if (annex) {
-      const bufferWriter = BufferWriter.withCapacity(varSliceSize(annex));
-      bufferWriter.writeVarSlice(annex);
-      sigMsgWriter.writeSlice(bcrypto.sha256(bufferWriter.end()));
-    }
-    // Output
-    if (isSingle) {
-      sigMsgWriter.writeSlice(hashOutputs);
-    }
-    // BIP342 extension
-    if (leafHash) {
-      sigMsgWriter.writeSlice(leafHash);
-      sigMsgWriter.writeUInt8(0);
-      sigMsgWriter.writeUInt32(0xffffffff);
-    }
-
-    // Extra zero byte because:
-    // https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-19
-    return bcrypto.taggedHash(
-      'TapSighash',
-      Buffer.concat([Buffer.of(0x00), sigMsgWriter.end()]),
-    );
-  }
-
-  hashForWitnessV0(
-    inIndex: number,
-    prevOutScript: Buffer,
-    value: number,
-    hashType: number,
-  ): Buffer {
-    typeforce(
-      types.tuple(types.UInt32, types.Buffer, types.Satoshi, types.UInt32),
-      arguments,
-    );
-
-    let tbuffer: Buffer = Buffer.from([]);
-    let bufferWriter: BufferWriter;
-
-    let hashOutputs = ZERO;
-    let hashPrevouts = ZERO;
-    let hashSequence = ZERO;
-
-    if (!(hashType & Transaction.SIGHASH_ANYONECANPAY)) {
-      tbuffer = Buffer.allocUnsafe(36 * this.ins.length);
-      bufferWriter = new BufferWriter(tbuffer, 0);
-
-      this.ins.forEach(txIn => {
-        bufferWriter.writeSlice(txIn.hash);
-        bufferWriter.writeUInt32(txIn.index);
-      });
-
-      hashPrevouts = bcrypto.hash256(tbuffer);
-    }
-
-    if (
-      !(hashType & Transaction.SIGHASH_ANYONECANPAY) &&
-      (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE &&
-      (hashType & 0x1f) !== Transaction.SIGHASH_NONE
-    ) {
-      tbuffer = Buffer.allocUnsafe(4 * this.ins.length);
-      bufferWriter = new BufferWriter(tbuffer, 0);
-
-      this.ins.forEach(txIn => {
-        bufferWriter.writeUInt32(txIn.sequence);
-      });
-
-      hashSequence = bcrypto.hash256(tbuffer);
-    }
-
-    if (
-      (hashType & 0x1f) !== Transaction.SIGHASH_SINGLE &&
-      (hashType & 0x1f) !== Transaction.SIGHASH_NONE
-    ) {
-      const txOutsSize = this.outs.reduce((sum, output) => {
-        return sum + 8 + varSliceSize(output.script);
-      }, 0);
-
-      tbuffer = Buffer.allocUnsafe(txOutsSize);
-      bufferWriter = new BufferWriter(tbuffer, 0);
-
-      this.outs.forEach(out => {
-        bufferWriter.writeUInt64(out.value);
-        bufferWriter.writeVarSlice(out.script);
-      });
-
-      hashOutputs = bcrypto.hash256(tbuffer);
-    } else if (
-      (hashType & 0x1f) === Transaction.SIGHASH_SINGLE &&
-      inIndex < this.outs.length
-    ) {
-      const output = this.outs[inIndex];
-
-      tbuffer = Buffer.allocUnsafe(8 + varSliceSize(output.script));
-      bufferWriter = new BufferWriter(tbuffer, 0);
-      bufferWriter.writeUInt64(output.value);
-      bufferWriter.writeVarSlice(output.script);
-
-      hashOutputs = bcrypto.hash256(tbuffer);
-    }
-
-    tbuffer = Buffer.allocUnsafe(156 + varSliceSize(prevOutScript));
-    bufferWriter = new BufferWriter(tbuffer, 0);
-
-    const input = this.ins[inIndex];
-    bufferWriter.writeInt32(this.version);
-    bufferWriter.writeSlice(hashPrevouts);
-    bufferWriter.writeSlice(hashSequence);
-    bufferWriter.writeSlice(input.hash);
-    bufferWriter.writeUInt32(input.index);
-    bufferWriter.writeVarSlice(prevOutScript);
-    bufferWriter.writeUInt64(value);
-    bufferWriter.writeUInt32(input.sequence);
-    bufferWriter.writeSlice(hashOutputs);
-    bufferWriter.writeUInt32(this.locktime);
-    bufferWriter.writeUInt32(hashType);
-    return bcrypto.hash256(tbuffer);
-  }
-
-  getHash(forWitness?: boolean): Buffer {
-    // wtxid for coinbase is always 32 bytes of 0x00
-    if (forWitness && this.isCoinbase()) return Buffer.alloc(32, 0);
-    return bcrypto.hash256(this.__toBuffer(undefined, undefined, forWitness));
-  }
-
-  getId(): string {
-    // transaction hash's are displayed in reverse order
-    return reverseBuffer(this.getHash(false)).toString('hex');
-  }
-
-  toBuffer(buffer?: Buffer, initialOffset?: number): Buffer {
-    return this.__toBuffer(buffer, initialOffset, true);
-  }
-
-  toHex(): string {
-    return this.toBuffer(undefined, undefined).toString('hex');
-  }
-
-  setInputScript(index: number, scriptSig: Buffer): void {
-    typeforce(types.tuple(types.Number, types.Buffer), arguments);
-
-    this.ins[index].script = scriptSig;
-  }
-
-  setWitness(index: number, witness: Buffer[]): void {
-    typeforce(types.tuple(types.Number, [types.Buffer]), arguments);
-
-    this.ins[index].witness = witness;
-  }
-
-  private __toBuffer(
-    buffer?: Buffer,
-    initialOffset?: number,
-    _ALLOW_WITNESS: boolean = false,
-  ): Buffer {
-    if (!buffer)
-      buffer = Buffer.allocUnsafe(this.byteLength(_ALLOW_WITNESS)) as Buffer;
-
-    const bufferWriter = new BufferWriter(buffer, initialOffset || 0);
-
-    bufferWriter.writeInt32(this.version);
-
-    const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses();
-
-    if (hasWitnesses) {
-      bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_MARKER);
-      bufferWriter.writeUInt8(Transaction.ADVANCED_TRANSACTION_FLAG);
-    }
-
-    bufferWriter.writeVarInt(this.ins.length);
-
-    this.ins.forEach(txIn => {
-      bufferWriter.writeSlice(txIn.hash);
-      bufferWriter.writeUInt32(txIn.index);
-      bufferWriter.writeVarSlice(txIn.script);
-      bufferWriter.writeUInt32(txIn.sequence);
-    });
-
-    bufferWriter.writeVarInt(this.outs.length);
-    this.outs.forEach(txOut => {
-      if (isOutput(txOut)) {
-        bufferWriter.writeUInt64(txOut.value);
-      } else {
-        bufferWriter.writeSlice((txOut as any).valueBuffer);
-      }
-
-      bufferWriter.writeVarSlice(txOut.script);
-    });
-
-    if (hasWitnesses) {
-      this.ins.forEach(input => {
-        bufferWriter.writeVector(input.witness);
-      });
-    }
-
-    bufferWriter.writeUInt32(this.locktime);
-
-    // avoid slicing unless necessary
-    if (initialOffset !== undefined)
-      return buffer.slice(initialOffset, bufferWriter.offset);
-    return buffer;
-  }
-}
diff --git a/ts_src/types.ts b/ts_src/types.ts
deleted file mode 100644
index c035b40..0000000
--- a/ts_src/types.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import { Buffer as NBuffer } from 'buffer';
-export const typeforce = require('typeforce');
-
-const ZERO32 = NBuffer.alloc(32, 0);
-const EC_P = NBuffer.from(
-  'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
-  'hex',
-);
-export function isPoint(p: Buffer | number | undefined | null): boolean {
-  if (!NBuffer.isBuffer(p)) return false;
-  if (p.length < 33) return false;
-
-  const t = p[0];
-  const x = p.slice(1, 33);
-  if (x.compare(ZERO32) === 0) return false;
-  if (x.compare(EC_P) >= 0) return false;
-  if ((t === 0x02 || t === 0x03) && p.length === 33) {
-    return true;
-  }
-
-  const y = p.slice(33);
-  if (y.compare(ZERO32) === 0) return false;
-  if (y.compare(EC_P) >= 0) return false;
-  if (t === 0x04 && p.length === 65) return true;
-  return false;
-}
-
-const UINT31_MAX: number = Math.pow(2, 31) - 1;
-export function UInt31(value: number): boolean {
-  return typeforce.UInt32(value) && value <= UINT31_MAX;
-}
-
-export function BIP32Path(value: string): boolean {
-  return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/);
-}
-BIP32Path.toJSON = (): string => {
-  return 'BIP32 derivation path';
-};
-
-export function Signer(obj: any): boolean {
-  return (
-    (typeforce.Buffer(obj.publicKey) ||
-      typeof obj.getPublicKey === 'function') &&
-    typeof obj.sign === 'function'
-  );
-}
-
-const SATOSHI_MAX: number = 21 * 1e14;
-export function Satoshi(value: number): boolean {
-  return typeforce.UInt53(value) && value <= SATOSHI_MAX;
-}
-
-// external dependent types
-export const ECPoint = typeforce.quacksLike('Point');
-
-// exposed, external API
-export const Network = typeforce.compile({
-  messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String),
-  bip32: {
-    public: typeforce.UInt32,
-    private: typeforce.UInt32,
-  },
-  pubKeyHash: typeforce.UInt8,
-  scriptHash: typeforce.UInt8,
-  wif: typeforce.UInt8,
-});
-
-export const Buffer256bit = typeforce.BufferN(32);
-export const Hash160bit = typeforce.BufferN(20);
-export const Hash256bit = typeforce.BufferN(32);
-export const Number = typeforce.Number; // tslint:disable-line variable-name
-export const Array = typeforce.Array;
-export const Boolean = typeforce.Boolean; // tslint:disable-line variable-name
-export const String = typeforce.String; // tslint:disable-line variable-name
-export const Buffer = typeforce.Buffer;
-export const Hex = typeforce.Hex;
-export const maybe = typeforce.maybe;
-export const tuple = typeforce.tuple;
-export const UInt8 = typeforce.UInt8;
-export const UInt32 = typeforce.UInt32;
-export const Function = typeforce.Function;
-export const BufferN = typeforce.BufferN;
-export const Null = typeforce.Null;
-export const oneOf = typeforce.oneOf;
diff --git a/tsconfig.json b/tsconfig.json
deleted file mode 100644
index 25f9d61..0000000
--- a/tsconfig.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
-  "compilerOptions": {
-    "target": "ES2020",
-    "module": "commonjs",
-    "outDir": "./src",
-    "declaration": true,
-    "rootDir": "./ts_src",
-    "types": [
-      "node"
-    ],
-    "allowJs": false,
-    "strict": true,
-    "noImplicitAny": true,
-    "strictNullChecks": true,
-    "strictFunctionTypes": true,
-    "strictBindCallApply": true,
-    "strictPropertyInitialization": true,
-    "noImplicitThis": true,
-    "alwaysStrict": true,
-    "esModuleInterop": false,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true
-  },
-  "include": [
-      "ts_src/**/*.ts"
-  ],
-  "exclude": [
-      "**/*.spec.ts",
-      "node_modules/**/*"
-  ]
-}
diff --git a/tslint.json b/tslint.json
deleted file mode 100644
index 90e513d..0000000
--- a/tslint.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
-  "defaultSeverity": "error",
-  "extends": ["tslint:recommended"],
-  "rules": {
-    "array-type": false,
-    "arrow-parens": false,
-    "curly": false,
-    "indent": [
-      true,
-      "spaces",
-      2
-    ],
-    "interface-name": [false],
-    "match-default-export-name": true,
-    "max-classes-per-file": [false],
-    "member-access": [true, "no-public"],
-    "no-bitwise": false,
-    "no-console": false,
-    "no-empty": [true, "allow-empty-catch"],
-    "no-implicit-dependencies": [true, "dev"],
-    "no-return-await": true,
-    "no-var-requires": false,
-    "no-unused-expression": false,
-    "object-literal-sort-keys": false,
-    "quotemark": [true, "single", "avoid-escape"],
-    "typedef": [
-      true,
-      "call-signature",
-      "property-declaration"
-    ],
-    "variable-name": [
-      true,
-      "ban-keywords",
-      "check-format",
-      "allow-leading-underscore",
-      "allow-pascal-case"
-    ]
-  },
-  "rulesDirectory": []
-}