Compare commits

...
126 Commits
Author SHA1 Message Date
Chris Troutner 7fea5c2630 Merge pull request #79 from Permissionless-Software-Foundation/ct-test-joey-slp
Testing Joey's Updates to SLP Handling
2020-12-30 08:52:52 -08:00
Chris Troutner b297743521 feat(SLP): Improved SLP calculation to fix small burns 2020-12-30 08:24:18 -08:00
Chris Troutner 6c33222172 Merge pull request #60 from josephroyking/slp-utils-patch
Resolving correct decimal precision for slp token qty
2020-12-28 05:01:59 -08:00
Chris Troutner 9a36a8261a Merge pull request #54 from josephroyking/generateSendOpReturn-rounding-patch
Generate send op return rounding patch
2020-12-28 04:57:53 -08:00
Chris Troutner 1433c77fcc Merge pull request #78 from Permissionless-Software-Foundation/ct-unstable
feat(Blockbook): Removing support for Blockbook indexer
2020-12-24 10:18:55 -08:00
Chris Troutner b1c3311d50 feat(Blockbook): Removing support for Blockbook indexer 2020-12-24 10:16:41 -08:00
Chris Troutner b3e224e481 Cleaned up integration tests 2020-12-24 10:06:39 -08:00
Chris Troutner 06e2dad45c Ran npm audit fix 2020-12-24 09:26:36 -08:00
Chris Troutner d475f2220f feat(SLPDB status): Created bchjs.SLP.Utils.getStatus() to get health status of SLPDB 2020-12-24 09:25:35 -08:00
Chris Troutner 10520a2e08 Merge pull request #75 from Permissionless-Software-Foundation/ct-unstable
fix(tokenUtxoDetails): Renabling local caching of tx validation
2020-12-13 09:16:17 -08:00
Chris Troutner 05b654d54a fix(tokenUtxoDetails): Renabling local caching of tx validation 2020-12-13 09:14:06 -08:00
Chris Troutner 3c4051c3a5 Merge pull request #74 from Permissionless-Software-Foundation/ct-unstable
fix(tokenUtxoDetails): Updating to handle alternative output from SLPDB
2020-12-13 09:00:48 -08:00
Chris Troutner 0f3cc1e9e8 Merge branch 'master' into ct-unstable 2020-12-13 08:56:28 -08:00
Chris Troutner b9873f7ed8 Added additional corner case unit test for tokenUtxoDetails() 2020-12-13 08:56:09 -08:00
Chris Troutner 82cd9270fa fix(tokenUtxoDetails): Updating to handle alternative output from SLPDB 2020-12-13 08:51:58 -08:00
Chris Troutner ac6b45b162 Merge pull request #73 from Permissionless-Software-Foundation/ct-unstable
fix(debugging): Additional debugging
2020-12-13 07:26:07 -08:00
Chris Troutner 66a99c0560 Merge branch 'master' into ct-unstable 2020-12-13 07:20:08 -08:00
Chris Troutner 17e4a32ff4 fix(debugging): Additional debugging 2020-12-13 07:19:24 -08:00
Chris Troutner 6a430b4da6 Merge pull request #72 from Permissionless-Software-Foundation/ct-unstable
fix(debugging): Debugging problem with hydrateUtxos()
2020-12-13 06:55:48 -08:00
Chris Troutner 77ab090bc2 fix(debugging): Debugging problem with hydrateUtxos() 2020-12-13 06:51:07 -08:00
Chris Troutner fdff4a1afb Merge pull request #71 from Permissionless-Software-Foundation/ct-unstable
fix(tokenUtxoDetails): Fixing bug with fallback validators
2020-12-13 06:25:10 -08:00
Chris Troutner 12701cf3dc fix(tokenUtxoDetails): Fixing bug with fallback validators 2020-12-13 06:20:51 -08:00
Chris Troutner 1032625ac8 Merge pull request #70 from Permissionless-Software-Foundation/ct-unstable
blockbook: Removing blockbook support from testnet
2020-12-11 15:19:36 -08:00
Chris Troutner 586c2972da feat(blockbook): Removing blockbook support from testnet 2020-12-11 15:15:03 -08:00
Chris Troutner 3d41e41192 fix(testnet): Updating integration tests 2020-12-11 14:59:46 -08:00
Chris Troutner af8e0cdf45 Merge pull request #69 from Permissionless-Software-Foundation/ct-unstable
fix(testnet): Fixing testnet integration tests
2020-12-08 18:36:54 -08:00
Chris Troutner 10f6f58ec5 fix(testnet): Fixing testnet integration tests 2020-12-08 18:28:30 -08:00
Chris Troutner fd9f399f41 Merge pull request #68 from Permissionless-Software-Foundation/ct-unstable
Added test/integration/implementations/
2020-12-08 17:59:49 -08:00
Chris Troutner 98582edd0b Merge branch 'master' into ct-unstable 2020-12-08 17:56:03 -08:00
Chris Troutner 07b7cb0afd Added test/integration/implementations/ for customized integration tests for different implementations 2020-12-08 17:55:47 -08:00
Chris Troutner dda9658375 Merge pull request #67 from Permissionless-Software-Foundation/ct-unstable
Refactoring integration tests
2020-12-08 17:45:22 -08:00
Chris Troutner 358dad533d Removing old bchn integration tests 2020-12-08 17:42:31 -08:00
Chris Troutner 7a63573143 fix(integration): Refactored abc and bchn integration tests 2020-12-08 17:23:41 -08:00
Chris Troutner 333ced5c79 updating gitignore 2020-12-07 15:54:56 -08:00
Chris Troutner c6ceae1283 Merge pull request #65 from Permissionless-Software-Foundation/ct-unstable
fix(semantic-release): Updating to 17.3.0
2020-12-06 19:59:16 -08:00
Chris Troutner 4e8a376720 fix(semantic-release): Updating to 17.3.0 2020-12-06 19:54:44 -08:00
Chris Troutner cee348cb3e Merge pull request #64 from Permissionless-Software-Foundation/ct-unstable
fix(tests): Cleaning up integration tests
2020-12-06 19:44:35 -08:00
Chris Troutner 75e56e7aa7 Merge branch 'master' into ct-unstable 2020-12-06 19:39:35 -08:00
Chris Troutner d6ae6ffb6b fix(tests): Cleaning up integration tests 2020-12-06 19:39:23 -08:00
Chris Troutner 12f6547167 Merge pull request #63 from Permissionless-Software-Foundation/ct-unstable
feat(tokenUtxoDetails()): Using fallback SLP validators
2020-12-06 19:21:34 -08:00
Chris Troutner d1847d2eca feat(tokenUtxoDetails()): Using fallback SLP validators 2020-12-06 19:18:47 -08:00
Chris Troutner 1f01e6ae47 fix(tokenUtxoDetails): Catching and invalidating malformed SLP OP_RETURNs 2020-12-06 18:40:14 -08:00
Chris Troutner 1375601a81 Restored all unit tests 2020-12-06 17:41:43 -08:00
Chris Troutner e97a8e7cf5 fix(slp utils): refactoring unit tests 2020-12-06 15:41:39 -08:00
Chris Troutner 3df211301c fix(unit tests): Refactored a lot of code flow 2020-12-06 14:51:48 -08:00
Chris Troutner a81dec068c fix(address unit tests): Fixed to prevent network call 2020-12-06 13:48:06 -08:00
Chris Troutner 4af6716631 Editing slp-util unit tests 2020-12-06 13:07:35 -08:00
Chris Troutner 98f7cb8f3a encapsulating and mocking axios in the slp-utils lib and unit tests 2020-12-06 09:59:01 -08:00
Chris Troutner 348a67a79b tokenUtxoDetails: prototyped different validation methods 2020-12-06 09:49:30 -08:00
Chris Troutner a9c128f96b Merge pull request #62 from Permissionless-Software-Foundation/ct-unstable
fix(unit test): Fixing changing test
2020-12-05 21:49:27 -08:00
Chris Troutner bdf1c50c9d fix(unit test): Fixing changing test 2020-12-05 21:47:26 -08:00
Chris Troutner ccc545b1be Bumping to v4.0 2020-12-05 20:51:50 -08:00
Chris Troutner c6301055fa Merge pull request #61 from Permissionless-Software-Foundation/ct-unstable
perf(v4): Switching to bch-api v4 routes
2020-12-05 20:48:23 -08:00
Chris Troutner 13d9f89a82 Commenting out test that still needs to be mocked 2020-12-05 20:44:53 -08:00
Chris Troutner f5de593f89 fix(tests): Getting all tests passing 2020-12-05 20:42:07 -08:00
Chris Troutner 3b0ec95fba perf(v4): Switching to bch-api v4 routes 2020-12-05 19:28:33 -08:00
Chris Troutner 0a328090ea saving confused progress 2020-12-05 19:06:11 -08:00
Chris Troutner 315cb4f254 feat(whitelist): Added method for getting SLPDB whitelist 2020-12-05 14:02:39 -08:00
Chris Troutner 28f08f02ac fix(ABC): fixed integration tests that broke 2020-12-05 12:23:41 -08:00
Joey King ad5fabf2e6 Remove stub test 2020-12-03 06:57:44 -08:00
Joey King f8f6db069b Implementing BigNumber for all tokenQty calcs 2020-12-03 06:56:05 -08:00
Joey King df620e0302 stub test method 2020-12-02 16:06:10 -08:00
Joey King 19f2e87528 Resolving correct decimal precision for slp token qty 2020-12-02 16:02:07 -08:00
Chris Troutner 5949e0f6f8 Changing free-tier to bchn 2020-11-23 07:51:19 -08:00
Chris Troutner 617bb16ddb Merge pull request #59 from Permissionless-Software-Foundation/ct-unstable
fix(price): Removing documentation for deprecated endpoint
2020-11-17 17:12:45 -08:00
Chris Troutner 83f14f5522 fix(price): Removing documentation for deprecated endpoint 2020-11-17 17:09:23 -08:00
Chris Troutner b8e22e1c99 Merge pull request #58 from Permissionless-Software-Foundation/ct-unstable
fix(price): Adding BCHA price
2020-11-17 14:47:47 -08:00
Chris Troutner 72d560e407 fix(price): Adding BCHA price 2020-11-17 14:41:04 -08:00
Chris Troutner 248b2fa2a6 Merge pull request #57 from Permissionless-Software-Foundation/ct-unstable
fix(basic auth): Fixing some bugs around basic auth
2020-11-12 09:52:29 -08:00
Chris Troutner 563cb297fe fix(basic auth): Fixing some bugs around basic auth 2020-11-12 09:48:54 -08:00
Chris Troutner 4c020240e1 fix(rate limits): Updated e2e tests for post-fork servers 2020-11-11 18:39:57 -08:00
Chris Troutner e070409a95 Merge pull request #56 from Permissionless-Software-Foundation/ct-unstable
Basic Authentication
2020-11-11 18:20:09 -08:00
Chris Troutner fbbd855145 feat(Basic Authentication): Adding authPass for auth token to all libraries 2020-11-11 17:47:46 -08:00
Chris Troutner 731987b35b fix(Basic Authentication): Adding back in 2020-11-11 14:56:53 -08:00
Chris Troutner 1e8e7b79f2 Updating comments in e2e rate limit tests 2020-11-11 14:11:13 -08:00
Joey King b512b222dd Adding large test tx 2020-11-10 14:28:10 -08:00
Joey King 650e3b53fc Adding tests and checks 2020-11-10 13:38:41 -08:00
Chris Troutner 099eb25e88 Merge pull request #53 from Permissionless-Software-Foundation/ct-unstable
fix(blockbook): Removing documentation as a step towards deprecation
2020-11-10 08:44:32 -08:00
Chris Troutner 12a7c666c6 fix(blockbook): Removing documentation as a step towards deprecation 2020-11-10 08:39:26 -08:00
Chris Troutner e482e09e77 Merge pull request #52 from Permissionless-Software-Foundation/ninsight-tx-details
Add Ninsight TX Details
2020-11-10 08:27:12 -08:00
Chris Troutner 7ca6498ca0 feat(Ninsight): Adding TX Details endpoint 2020-11-10 08:24:19 -08:00
Chris Troutner f89b52ac86 Merge branch 'master' into ninsight-tx-details 2020-11-10 08:21:07 -08:00
Joey King 905658ca28 format changes take two 2020-11-10 06:19:36 -08:00
Joey King b0c91c407d matching original formatting 2020-11-10 06:13:53 -08:00
Joey King d2c68efc0c Use BigNumber to eliminate rounding error token burns 2020-11-10 06:10:38 -08:00
Stoyan Zhekov 7990d0bffd Add Ninsight TX Details 2020-11-10 19:04:16 +09:00
Chris Troutner c0eaaf77c8 fix(integration tests): Updating scripts in package.json 2020-11-09 18:17:44 -08:00
Chris Troutner f424047a69 Merge pull request #51 from Permissionless-Software-Foundation/ninsight-tx-history
Add Ninsight TX History to bch-js
2020-11-09 16:14:39 -08:00
Chris Troutner fc0d8b7f8c fix(ninsight): Adding tx history endpoint 2020-11-09 16:12:10 -08:00
Chris Troutner 4551d1ca99 Merge pull request #50 from Permissionless-Software-Foundation/ninsight-unconfirmed-utxos
Add Ninsight Unconfirmed UTXOs
2020-11-09 15:47:11 -08:00
Chris Troutner b8083c6b88 fix(ninsight): Adding unconfirmed UTXOs endpoint 2020-11-09 15:45:11 -08:00
Stoyan Zhekov 0ef8555837 Add Ninsight TX History to bch-js 2020-11-09 19:49:41 +09:00
Stoyan Zhekov a7564ce611 Add Ninsight Unconfirmed UTXOs 2020-11-09 17:44:09 +09:00
Chris Troutner 601b87cb4a Updating README 2020-11-08 19:14:43 -08:00
Chris Troutner edfcc92b7b Merge pull request #48 from Permissionless-Software-Foundation/ct-unstable
Updating README
2020-11-08 19:04:29 -08:00
Chris Troutner a32e0da9be Updating README 2020-11-08 19:02:30 -08:00
Chris Troutner a1bf617d91 Updating README 2020-11-08 18:56:48 -08:00
Chris Troutner 33d2da503d Updating READMe 2020-11-08 18:49:45 -08:00
Chris Troutner c2ff1e2d68 Updating npm lib 2020-11-08 17:46:40 -08:00
Chris Troutner cc9e8c0319 Fixing links in README 2020-11-08 17:38:11 -08:00
Chris Troutner 83389129d6 Merge pull request #47 from Permissionless-Software-Foundation/ct-unstable
fix(network): Updates for fork
2020-11-08 14:07:01 -08:00
Chris Troutner 360d56e283 fix(network): Updates for fork 2020-11-08 14:05:10 -08:00
Chris Troutner 53a0da4ef1 Merge branch 'master' into ct-unstable 2020-11-08 09:36:41 -08:00
Chris Troutner 6d4534f177 Removing test 2020-11-08 09:36:31 -08:00
Chris Troutner 90ec06adaa Merge pull request #46 from Permissionless-Software-Foundation/ct-unstable
Updating e2e rate limit tests
2020-11-08 09:33:29 -08:00
Chris Troutner a6759cdae5 Testing CI 2020-11-08 09:26:24 -08:00
Chris Troutner 078f157e4e fix(rate limits): Updating e2e rate limit tests for new bch-api rate limits 2020-11-08 09:15:53 -08:00
Chris Troutner 98029f74f8 Merge pull request #45 from Permissionless-Software-Foundation/ct-unstable
fix(integration tests): slowing down integration tests for BVT
2020-11-03 09:40:53 -08:00
Chris Troutner 9348ccb7de fix(integration tests): slowing down integration tests for BVT 2020-11-03 08:14:55 -08:00
Chris Troutner 6a6f5fa5fa Merge pull request #44 from Permissionless-Software-Foundation/ct-unstable
Updates to Integration Tests
2020-11-02 15:45:20 -08:00
Chris Troutner 9863fad6a6 fix(testnet): Updating testnet integration tests to pass BVT 2020-11-02 14:49:28 -08:00
Chris Troutner 3a2f38bcf0 fix(integration): Removed all non-integration tests from integration tests 2020-11-02 14:27:31 -08:00
Chris Troutner bc5c7052a1 Merge pull request #43 from Permissionless-Software-Foundation/ct-unstable
Ct unstable
2020-10-31 11:07:41 -07:00
Chris Troutner 89d5171e92 Merge branch 'master' into ct-unstable 2020-10-31 11:04:33 -07:00
Chris Troutner c80a0dcde4 fix(bchn): Starting separate integration tests for bchn 2020-10-30 16:05:26 -07:00
Chris Troutner a2f7ae7fb4 fix(electrumx): Updates for new abc v0.22.4 2020-10-30 15:10:55 -07:00
Chris Troutner 4c2c7a4f6f Merge pull request #42 from Permissionless-Software-Foundation/ct-unstable
fix(hydrateUtxos): Fixing integration test
2020-10-30 07:45:06 -07:00
Chris Troutner 6efb08565a fix(hydrateUtxos): Fixing integration test 2020-10-29 21:46:53 -07:00
Chris Troutner 8a8dcbe593 Merge pull request #41 from Permissionless-Software-Foundation/ct-unstable
fix(integration tests): Updating testnet integration tests
2020-10-29 08:08:17 -07:00
Chris Troutner ae58895d71 fix(integration tests): Updating testnet integration tests 2020-10-29 07:18:59 -07:00
Chris Troutner a50ace320b Merge pull request #40 from Permissionless-Software-Foundation/ct-unstable
fix(rawtransactions): Updating integration test for latest version of…
2020-10-27 19:16:41 -07:00
Chris Troutner b1d583cfe4 fix(rawtransactions): Updating integration test for latest version of ABC 2020-10-27 18:03:32 -07:00
Chris Troutner 0b86a19726 Merge pull request #39 from Permissionless-Software-Foundation/ct-unstable
fix(price): Fixing broken integration test
2020-10-20 18:34:13 -07:00
Chris Troutner eb3bc7bcff fix(price): Fixing broken integration test 2020-10-20 18:18:18 -07:00
Chris Troutner c5361e0516 Merge pull request #38 from Permissionless-Software-Foundation/ct-unstable
fix(docs): Update to price documentation
2020-10-19 19:55:57 -07:00
Chris Troutner 54d9233f41 fix(docs): Update to price documentation 2020-10-19 19:46:27 -07:00
76 changed files with 6769 additions and 4142 deletions
+1
View File
@@ -2,6 +2,7 @@ node_modules/*
.nyc_output/*
wallet-info.txt
wallet.json
integration-test-sweet.sh
docs/
coverage/
+42 -52
View File
@@ -1,68 +1,71 @@
# bch-js
[![Build Status](https://travis-ci.org/christroutner/bch-js.svg?branch=master)](https://travis-ci.org/christroutner/bch-js)
[![Version](https://img.shields.io/npm/v/@chris.troutner/bch-js)](https://www.npmjs.com/package/@chris.troutner/bch-js)
[![Downloads/week](https://img.shields.io/npm/dw/@chris.troutner/bch-js)](https://npmjs.org/package/@chris.troutner/bch-js)
[![License](https://img.shields.io/npm/l/@chris.troutner/bch-js)](https://github.com/christroutner/bch-js/blob/master/LICENSE.md)
[![Build Status](https://travis-ci.org/Permissionless-Software-Foundation/bch-js.svg?branch=master)](https://travis-ci.org/Permissionless-Software-Foundation/bch-js)
[![Version](https://img.shields.io/npm/v/@psf/bch-js)](https://www.npmjs.com/package/@psf/bch-js)
[![Downloads/week](https://img.shields.io/npm/dw/@psf/bch-js)](https://npmjs.org/package/@psf/bch-js)
[![License](https://img.shields.io/npm/l/@psf/bch-js)](https://github.com/Permissionless-Software-Foundation/bch-js/blob/master/LICENSE.md)
[bch-js](https://www.npmjs.com/package/@chris.troutner/bch-js) is a JavaScript npm library for creating web and mobile apps for interacting with the Bitcoin Cash (BCH) blockchain. It can be used for free, but requires an account on [FullStack.cash](https://fullstack.cash) for increased rate limits. Find out more from [this article](https://troutsblog.com/research/bitcoin-cash/how-to-bch-full-stack-developer).
[bch-js](https://www.npmjs.com/package/@psf/bch-js) is a JavaScript npm library for creating web and mobile apps that can interact with the Bitcoin Cash (BCH) blockchains. It can be used for free, but requires an account on [FullStack.cash](https://fullstack.cash) for increased rate limits. Learn more from [this article](https://troutsblog.com/research/bitcoin-cash/how-to-bch-full-stack-developer) about Full Stack Bitcoin Cash development.
### Quick Start Videos:
Here are two YouTube walk-through videos to help you get started:
- [Introduction to bch-js and the bch-js-examples repository](https://youtu.be/GD2i1ZUiyrk)
- [Working with the FullStack.cash JWT token](https://youtu.be/GD2i1ZUiyrk)
### Quick Links
- [npm Library](https://www.npmjs.com/package/@chris.troutner/bch-js)
- [npm Library](https://www.npmjs.com/package/@psf/bch-js)
- [Documentation](https://bchjs.fullstack.cash/)
- [Examples](https://github.com/Permissionless-Software-Foundation/bch-js-examples)
- [api.fullstack.cash](https://api.fullstack.cash) - The REST API this library talks to by default.
- [bchn.fullstack.cash](https://bchn.fullstack.cash) - The REST API this library talks to by default.
- [FullStack.cash](https://fullstack.cash) - cloud-based infrastructure for application developers.
- [FullStack.cash Account](https://fullstack.cash/login) - Get your API key to unlock increased rate limits.
- [FullStack.cash](https://fullstack.cash) - cloud-based infrastructure for application
developers.
- [Permissionless Software Foundation](https://psfoundation.cash) - The organization that maintains this library.
### Quick Notes
- Install library: `npm install @chris.troutner/bch-js`
- Install library: `npm install @psf/bch-js`
- Instantiate the library in your code:
```
const BCHJS = require("@chris.troutner/bch-js")
let bchjs = new BCHJS()
const BCHJS = require("@psf/bch-js")
let bchjs = new BCHJS() // Defaults to BCHN network.
// testnet
bchjs = new BCHJS({ restURL: 'https://tapi.fullstack.cash/v3/' })
bchjs = new BCHJS({ restURL: 'https://testnet3.fullstack.cash/v3/' })
```
This is a fork of the [BITBOX SDK](https://github.com/Bitcoin-com/bitbox-sdk) (which is maintained by Bitcoin.com). This library is intended to be paired with
the [bch-api](https://github.com/christroutner/bch-api) REST API.
This library is intended to be paired with
the [bch-api](https://github.com/Permissionless-Software-Foundation/bch-api) REST API, and the infrastructure provided by [FullStack.cash](https://fullstack.cash). The `restURL` property can be changed to work with different Bitcoin Cash networks:
If you need a backward-compatible instance of this library, you can use a
'shim'. Do it like this:
```
const BCHJS = require("@chris.troutner/bch-js")
const bitbox = BCHJS.BitboxShim({ restURL: 'https://api.fullstack.cash/v3/' })
```
- BCHN Mainnet REST API server: https://bchn.fullstack.cash/v3/
- ABC Mainnet REST API server: https://abc.fullstack.cash/v3/
- Testnet3 REST API server: https://testnet3.fullstack.cash/v3/
- Check server status: https://metrics.fullstack.cash
### API Key
The [bch-api](https://github.com/christroutner/bch-api) REST API hosted by [FullStack.cash](https://fullstack.cash) uses JWT tokens to pay for increased
rate limits when interacting with the back end server. See [this article](https://troutsblog.com/research/bitcoin-cash/how-to-bch-full-stack-developer) if you want to understand the system-as-a-whole. The JWT token can be fed to bch-js *implicitly* or *explicitly*.
- Implicitly: bch-js will detect your JWT token by setting the `BCHJSTOKEN` environment variable.
The [bch-api](https://github.com/Permissionless-Software-Foundation/bch-api) REST API hosted by [FullStack.cash](https://fullstack.cash) uses JWT tokens to pay for increased
rate limits when interacting with the back end server. See [this article](https://troutsblog.com/research/bitcoin-cash/how-to-bch-full-stack-developer) if you want to understand the system-as-a-whole. The JWT token can be fed to bch-js _implicitly_ or _explicitly_.
- Implicitly: bch-js will detect your JWT token if you set the `BCHJSTOKEN` environment variable.
- Explicitly: You can directly feed in the JWT token with the `apiToken` property when instantiating the library. Here is an example:
```
const BCHJS = require("@chris.troutner/bch-js")
const BCHJS = require("@psf/bch-js")
let bchjs = new BCHJS({
restURL: 'https://api.fullstack.cash/v3/',
restURL: 'https://bchn.fullstack.cash/v3/',
apiToken: 'eyJhbGciO...' // Your JWT token here.
})
```
### Gatsby
bch-js is included in this [gatsby-ipfs-template](https://github.com/Permissionless-Software-Foundation/gatsby-ipfs-template) for building uncensorable web apps that can interact with the blockchain. When building a Gatsby (or other front-end app that uses Webpack), you'll need to add these lines to your `gatsby-node.js` file, as per [this issue](https://github.com/gatsbyjs/gatsby/issues/564):
```
exports.onCreateWebpackConfig = ({ actions }) => {
actions.setWebpackConfig({
@@ -75,60 +78,47 @@ exports.onCreateWebpackConfig = ({ actions }) => {
This is because the new IPFS class in bch-js uses the fs library for uploading files, which is not supported by Gatsby.
We also provide [minimal-slp-wallet-web](https://www.npmjs.com/package/minimal-slp-wallet-web) as a basic Bitcoin Cash wallet with SLP support, for front end projects. bch-js is encapsulated inside the instantiation of the library Class.
## Features
This library sets itself apart from BITBOX with the following features:
- [ECMAScript 2017 standard JavaScript](https://en.wikipedia.org/wiki/ECMAScript#8th_Edition_-_ECMAScript_2017) used instead of TypeScript. Works
natively with node.js v10 or higher.
natively with node.js v10 or higher.
- Full SLP tokens support: bch-js has full support for all SLP token functionality, including send, mint, and genesis transactions. It also fully support all aspects of [non-fugible tokans (NFTs)](https://www.youtube.com/watch?v=vvlpYUx6HRs).
- [Semantic Release](https://github.com/semantic-release/semantic-release) for
continuous delivery using semantic versioning.
continuous delivery using semantic versioning.
- [Greenkeeper](https://greenkeeper.io/) automatic dependency management for
automatically maintaining the latest, most secure dependencies.
automatically maintaining the latest, most secure dependencies.
- [IPFS uploads](https://ipfs.io) of all files and dependencies, to backup
dependencies in case they are ever inaccessible from GitHub or npm.
dependencies in case they are ever inaccessible from GitHub or npm.
## Documentation:
Full documentation for this library can be found here:
- [Documentation](https://bchjs.fullstack.cash/)
Original documentation on BITBOX is available at:
- [General docs](https://developer.bitcoin.com)
- [BITBOX Introduction](https://developer.bitcoin.com/bitbox)
- [BITBOX API Reference](https://developer.bitcoin.com/bitbox/docs/getting-started)
bch-js uses [APIDOC](http://apidocjs.com/) so that documentation and working code
live in the same repository. To generate the documentation:
- `npm run docs`
- Open the generated `docs/index.html` file in a web browser.
## Support
Have questions? Need help? Join our community support
[Telegram channel](https://t.me/bch_js_toolkit)
## IPFS Releases
I will periodically publish IPFS releases of this repository, including all
dependencies in the `node_modules` folder. This ensures working copies of this
repository can be retrieved in case there is any drift in dependency files, or
if dependencies are pulled from npm or GitHub.
Copies of this repository are also published on [IPFS](https://ipfs.io).
- Initial fork on 5/9/2019:
- without node_modules folder: QmQFHfbBQdEHfhtiRLbXtX1NcgnfL45hZb7TbQimTXAuzG (4 MB)
- with node_modules folder: QmXq9Ds6Qdkg9xbRhcF8pay9KabA6QN2y7bx3wvSqiXifk (107 MB)
- v1.0.0 - refactored to pure JavaScript:
- without node_modules folder: QmNjFsiTZRMAUa9rZpXqZqivv9JLaNicwLSPHjyLB7PVDk (1 MB)
- with node_modules folder: Qma9ScApwBtuL7dpdSk7jpBFTxbqRdiR921WjyP75SU7bT (100 MB)
- v3.8.10: QmauhggzKDo9A9je5y2K6WRAp32JmGRFCw2ZFTiSnW8yot
## License
[MIT](LICENSE.md)
+816 -718
View File
File diff suppressed because it is too large Load Diff
+14 -13
View File
@@ -1,6 +1,6 @@
{
"name": "@psf/bch-js",
"version": "3.4.0",
"version": "4.0.0",
"description": "The FullStack.cash JavaScript library for Bitcoin Cash and SLP Tokens",
"author": "Chris Troutner <chris.troutner@gmail.com>",
"contributors": [
@@ -8,16 +8,16 @@
],
"main": "src/bch-js",
"scripts": {
"test": "nyc mocha --timeout 30000 test/unit/",
"test:integration": "mocha --timeout 30000 test/integration/",
"test:integration:testnet": "mocha --timeout 30000 test/integration/testnet/",
"test:integration:local": "RESTURL=http://localhost:3000/v3/ mocha --timeout 30000 test/integration",
"test:integration:testnet:local": "RESTURL=http://localhost:4000/v3/ mocha --timeout 30000 test/integration/testnet",
"test:integration:free": "bash test/integration/test-free-tier.sh",
"test:integration:free:bchn": "bash test/integration/test-free-tier-bchn.sh",
"test:integration:free:testnet": "bash test/integration/testnet/test-free-tier.sh",
"test:temp": "mocha --timeout 30000 -g '#hydrateUtxos' test/integration/",
"test:integration:api": "RESTURL=https://api.fullstack.cash/v3/ mocha --timeout 30000 test/integration",
"test": "nyc mocha --trace-warnings --unhandled-rejections=strict --timeout 30000 test/unit/",
"test:integration": "npm run test:integration:bchn",
"test:integration:abc": "export RESTURL=https://abc.fullstack.cash/v4/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/abc/",
"test:integration:bchn": "export RESTURL=https://bchn.fullstack.cash/v4/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
"test:integration:testnet": "IS_USING_FREE_TIER=true mocha --timeout 30000 test/integration/chains/testnet/",
"test:integration:local": "RESTURL=http://localhost:3000/v4/ mocha --timeout 30000 test/integration",
"test:integration:local:bchn": "RESTURL=http://localhost:3000/v4/ bash test/integration/test-bchn-integration.sh",
"test:integration:local:testnet": "RESTURL=http://localhost:4000/v4/ mocha --timeout 30000 test/integration/testnet",
"test:temp": "export RESTURL=https://bchn.fullstack.cash/v4/ && mocha --timeout 30000 -g '#getStatus' test/integration/",
"test:temp2": "mocha --timeout 30000 -g '#getStatus' test/unit/",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"coverage:report": "nyc --reporter=html mocha --timeout 25000 test/unit/",
"docs": "./node_modules/.bin/apidoc -i src/ -o docs"
@@ -59,7 +59,7 @@
"ecurve": "^1.0.6",
"figlet": "^1.2.0",
"git-clone": "^0.1.0",
"ini": "^1.3.5",
"ini": "^1.3.8",
"mkdirp": "^0.5.1",
"node-cmd": "^3.0.0",
"node-emoji": "^1.8.1",
@@ -82,12 +82,13 @@
"eslint-config-prettier": "^6.0.0",
"eslint-plugin-node": "^9.1.0",
"eslint-plugin-prettier": "^3.1.0",
"lodash.clonedeep": "^4.5.0",
"mocha": "^6.1.4",
"nock": "^10.0.6",
"node-mocks-http": "^1.7.0",
"nyc": "^14.1.0",
"prettier": "^1.18.2",
"semantic-release": "^15.13.19",
"semantic-release": "^17.3.0",
"sinon": "^7.3.2"
},
"apidoc": {
+18 -1
View File
@@ -6,11 +6,28 @@ const coininfo = require("coininfo")
class Address {
constructor(config) {
const tmp = {}
if (!config || !config.restURL) tmp.restURL = `https://api.bchjs.cash/v3/`
if (!config || !config.restURL) tmp.restURL = `https://api.bchjs.cash/v4/`
else tmp.restURL = config.restURL
this.restURL = tmp.restURL
this.apiToken = tmp.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
}
/**
+21 -10
View File
@@ -7,8 +7,8 @@
*/
// bch-api mainnet.
// const DEFAULT_REST_API = "https://api.bchjs.cash/v3/"
const DEFAULT_REST_API = "https://api.fullstack.cash/v3/"
const DEFAULT_REST_API = "https://api.fullstack.cash/v4/"
// const DEFAULT_REST_API = "http://localhost:3000/v4/"
// local deps
const BitcoinCash = require("./bitcoincash")
@@ -34,7 +34,6 @@ const IPFS = require("./ipfs")
const Encryption = require("./encryption")
// Indexers
const Blockbook = require("./blockbook")
const OpenBazaar = require("./openbazaar")
const Ninsight = require("./ninsight")
const Electrumx = require("./electrumx")
@@ -55,16 +54,31 @@ class BCHJS {
else if (process.env.BCHJSTOKEN && process.env.BCHJSTOKEN !== "")
this.apiToken = process.env.BCHJSTOKEN
// Retrieve the Basic Authentication password.
this.authPass = "" // default value.
if (config && config.authPass && config.authPass !== "")
this.authPass = config.authPass
else if (process.env.BCHJSAUTHPASS && process.env.BCHJSAUTHPASS !== "")
this.authPass = process.env.BCHJSAUTHPASS
// Generate a Basic Authentication token from an auth password
this.authToken = ""
if (this.authPass) {
// console.log(`bch-js initialized with authPass: ${this.authPass}`)
// Generate the header for Basic Authentication.
const combined = `fullstackcash:${this.authPass}`
var base64Credential = Buffer.from(combined).toString("base64")
this.authToken = `Basic ${base64Credential}`
}
const libConfig = {
restURL: this.restURL,
apiToken: this.apiToken
apiToken: this.apiToken,
authToken: this.authToken
}
// console.log(`apiToken: ${this.apiToken}`)
// Populate Blockbook endpoints.
this.Blockbook = new Blockbook(libConfig)
// Populate OpenBazaar endpoints
this.OpenBazaar = new OpenBazaar(libConfig)
@@ -176,9 +190,6 @@ class BitboxShim {
this.Mining = new Mining(libConfig)
this.RawTransactions = new RawTransactions(libConfig)
// Populate Blockbook endpoints.
this.Blockbook = new Blockbook(libConfig)
// Populate OpenBazaar endpoints
this.OpenBazaar = new OpenBazaar(libConfig)
-357
View File
@@ -1,357 +0,0 @@
/*
This library interacts with the REST API endpoints in bch-api that communicate
with the Blockbook API.
*/
const axios = require("axios")
let _this
class Blockbook {
constructor(config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
// console.log(`Blockbook apiToken: ${this.apiToken}`)
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
_this = this
}
/**
* @api Blockbook.balance() balance()
* @apiName Blockbook Balance
* @apiGroup Blockbook
* @apiDescription Return Balance about an address.
*
* @apiExample Example usage:
* (async () => {
* try {
* let balance = await bchjs.Blockbook.balance('bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c');
* console.log(balance)
* } catch(error) {
* console.error(error)
* }
* })()
*
* //{
* // "page": 1,
* // "totalPages": 1,
* // "itemsOnPage": 1000,
* // "address": "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c",
* // "balance": "6000000",
* // "totalReceived": "10185868",
* // "totalSent": "4185868",
* // "unconfirmedBalance": "0",
* // "unconfirmedTxs": 0,
* // "txs": 41,
* // "txids": [
* // "d31dc2cf66fe4d3d3ae18e1065def58a64920746b1702b52f060e5edeea9883b",
* // "41e9a118765ecf7a1ba4487c0863e23dba343cc5880381a72f0365ac2546c5fa",
* // "2f902dec880568511cefa87b9dd761563edeba9c8ba784dc9fca2f7c8c4e6f97",
* // "eea57285462dd70dadcd431fc814857b3f81fe4d0a059a8c02c12fd7d33c02d1",
* // "282b3b296b6aed7122586ed69f7a57d35584eaf94a4d1b1ad7d1b05d36cb79d1",
* // "ac444896b3e32d17824fa6573eed3b89768c5c9085b7a71f3ba88e9d5ba67355",
* // "a5f972572ee1753e2fd2457dd61ce5f40fa2f8a30173d417e49feef7542c96a1",
* // "5165dc531aad05d1149bb0f0d9b7bda99c73e2f05e314bcfb5b4bb9ca5e1af5e",
* // "54edaa42ff3d6559884a84ebb9bf5ef255635902f5f23b4854245d6b093d41d4",
* // "2b0825188e909410a20a6fbdc58ff5ccf368844273f93f551222c91e6d0fa888",
* // "7a12ea2c83d0c8a5d0f643974b0f04bc19be185c9011ed8fc33255a61d3198bb",
* // "bd6aeeb0748251bb5dba7252ac766fb208c9909d7663c099568225d3bc998a7f",
* // "7898bb1a8c5d933f9c2b24270522e8705b897c2f8d5b1c3477a6b952f2fe22ae",
* // "8d35668a6838de8faa8dff5d8dedeb114bd8ffe6ae73d926264bc8328b2c46b5",
* // "741b4692a14088438ab142cf0865fcbf3977aa7dbd2aafa9bf5f45e75e5e199a",
* // "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
* // "376de807f63253584c3edb80f92832ea90e8fdd7d8e68b2602e230d1b015e311",
* // "eb5d0902e4a303f38223ecebb06bbf14da8a07d1ebb2d77a89dfb9e00e286c10",
* // "11205c557af139f382c43f1f09f223cf28c64d939951fd569e5a30eee6178ccd",
* // "ae05a78086b8d64db26d3047de3d6959a68f2a1ed3017ddf927e2c3b20a80b31",
* // "7e0fc3cac7504d45b0f2ce68e807e592f0edf17914ab618a4cb4d93403d11c98",
* // "1cafaacdfb85b0c33f496bf2c03c4f2ede508479bbad56ae99164dfd823a823f",
* // "788add6a5cd961bdf7ca6145a3112462e0e51523d84a4a48047407a795433947",
* // "49f09b616824a05eb14ae50c9fbc5d6a0c414d66a7d0b217aa75340c00ed8b85",
* // "00f075805adf2a34563ecca33071d660a4c1e91d7d7045282c54554ee4844739",
* // "8d048fd00cf375ba9bbea43730da1ce86fc3cb4026e1dd0e751c07fa50a652c6",
* // "ac0e82ea84f93444602a99199dd80793f79a8ece5ac86156d2fff34f0bad44b2",
* // "342f6815845797e0748f4716c923a0dc9b87de649b69925b36422f6d2dc23b7f",
* // "0839a16b2411a1220c64c4d32a4c9b1e77ac5f47558921cf7c0a2adf25e0eb41",
* // "62f42995711cb0308dac4203c5deaa2985f120559131e66aebc5164426fb6cee",
* // "2ada093fe13c9c04da9582bb304923ce08312eaec92560b9128cdb9e93c5f52f",
* // "e0aadd861a06993e39af932bb0b9ad69e7b37ef5843a13c6724789e1c94f3513",
* // "925490ce60334aca204d82a61b634d89fe4cc9de429c7b6cb5ec420df3e3be5e",
* // "60cb69f29c150378abe21d157858713f82c4e2122867597a2573474763a9e94e",
* // "369a589173969c1c882cfb2d82b1e0ec90076ec827ff9d0f32ffc115690c93c3",
* // "43324ef3f5fdd55b645ba14de8c0667be9b223d60b3d1dcd76cf8fdeb0fd32e4",
* // "d2985c9b1c5c18fc2f6a963b7cb850606c4a18fcb85619057211ce3c8bcec696",
* // "dded59fe377517e52918deae8912a096658ebf5ae61992d39953c8bc3932a11b",
* // "2dc053f55a666a3d2a08b1c680b704d62a55506d14ad884add87edcc56b9277d",
* // "544c15ce35c0f2e808d28f29d6587f1ec9276233e29856b7f2938cf0daef0026",
* // "81039b1d7b855b133f359f9dc65f776bd105650153a941675fedc504228ddbd3"
* // ]
* //}
*
*(async () => {
* try {
* let balance = await bchjs.Blockbook.balance(['bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c','1BFHGm4HzqgXXyNX8n7DsQno5DAC4iLMRA']);
* console.log(balance)
* } catch(error) {
* console.error(error)
* }
* })()
*
* //[
* // {
* // "page": 1,
* // "totalPages": 1,
* // "itemsOnPage": 1000,
* // "address": "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c",
* // "balance": "6000000",
* // "totalReceived": "10185868",
* // "totalSent": "4185868",
* // "unconfirmedBalance": "0",
* // "unconfirmedTxs": 0,
* // "txs": 41,
* // "txids": [
* // "d31dc2cf66fe4d3d3ae18e1065def58a64920746b1702b52f060e5edeea9883b",
* // "41e9a118765ecf7a1ba4487c0863e23dba343cc5880381a72f0365ac2546c5fa",
* // "2f902dec880568511cefa87b9dd761563edeba9c8ba784dc9fca2f7c8c4e6f97",
* // "eea57285462dd70dadcd431fc814857b3f81fe4d0a059a8c02c12fd7d33c02d1",
* // "282b3b296b6aed7122586ed69f7a57d35584eaf94a4d1b1ad7d1b05d36cb79d1",
* // "ac444896b3e32d17824fa6573eed3b89768c5c9085b7a71f3ba88e9d5ba67355",
* // "a5f972572ee1753e2fd2457dd61ce5f40fa2f8a30173d417e49feef7542c96a1",
* // "5165dc531aad05d1149bb0f0d9b7bda99c73e2f05e314bcfb5b4bb9ca5e1af5e",
* // "54edaa42ff3d6559884a84ebb9bf5ef255635902f5f23b4854245d6b093d41d4",
* // "2b0825188e909410a20a6fbdc58ff5ccf368844273f93f551222c91e6d0fa888",
* // "7a12ea2c83d0c8a5d0f643974b0f04bc19be185c9011ed8fc33255a61d3198bb",
* // "bd6aeeb0748251bb5dba7252ac766fb208c9909d7663c099568225d3bc998a7f",
* // "7898bb1a8c5d933f9c2b24270522e8705b897c2f8d5b1c3477a6b952f2fe22ae",
* // "8d35668a6838de8faa8dff5d8dedeb114bd8ffe6ae73d926264bc8328b2c46b5",
* // "741b4692a14088438ab142cf0865fcbf3977aa7dbd2aafa9bf5f45e75e5e199a",
* // "15f6a584080b04911121fbaca7bfcf3dd64ef2bfa5a01daf31e05a296c3e5e9e",
* // "376de807f63253584c3edb80f92832ea90e8fdd7d8e68b2602e230d1b015e311",
* // "eb5d0902e4a303f38223ecebb06bbf14da8a07d1ebb2d77a89dfb9e00e286c10",
* // "11205c557af139f382c43f1f09f223cf28c64d939951fd569e5a30eee6178ccd",
* // "ae05a78086b8d64db26d3047de3d6959a68f2a1ed3017ddf927e2c3b20a80b31",
* // "7e0fc3cac7504d45b0f2ce68e807e592f0edf17914ab618a4cb4d93403d11c98",
* // "1cafaacdfb85b0c33f496bf2c03c4f2ede508479bbad56ae99164dfd823a823f",
* // "788add6a5cd961bdf7ca6145a3112462e0e51523d84a4a48047407a795433947",
* // "49f09b616824a05eb14ae50c9fbc5d6a0c414d66a7d0b217aa75340c00ed8b85",
* // "00f075805adf2a34563ecca33071d660a4c1e91d7d7045282c54554ee4844739",
* // "8d048fd00cf375ba9bbea43730da1ce86fc3cb4026e1dd0e751c07fa50a652c6",
* // "ac0e82ea84f93444602a99199dd80793f79a8ece5ac86156d2fff34f0bad44b2",
* // "342f6815845797e0748f4716c923a0dc9b87de649b69925b36422f6d2dc23b7f",
* // "0839a16b2411a1220c64c4d32a4c9b1e77ac5f47558921cf7c0a2adf25e0eb41",
* // "62f42995711cb0308dac4203c5deaa2985f120559131e66aebc5164426fb6cee",
* // "2ada093fe13c9c04da9582bb304923ce08312eaec92560b9128cdb9e93c5f52f",
* // "e0aadd861a06993e39af932bb0b9ad69e7b37ef5843a13c6724789e1c94f3513",
* // "925490ce60334aca204d82a61b634d89fe4cc9de429c7b6cb5ec420df3e3be5e",
* // "60cb69f29c150378abe21d157858713f82c4e2122867597a2573474763a9e94e",
* // "369a589173969c1c882cfb2d82b1e0ec90076ec827ff9d0f32ffc115690c93c3",
* // "43324ef3f5fdd55b645ba14de8c0667be9b223d60b3d1dcd76cf8fdeb0fd32e4",
* // "d2985c9b1c5c18fc2f6a963b7cb850606c4a18fcb85619057211ce3c8bcec696",
* // "dded59fe377517e52918deae8912a096658ebf5ae61992d39953c8bc3932a11b",
* // "2dc053f55a666a3d2a08b1c680b704d62a55506d14ad884add87edcc56b9277d",
* // "544c15ce35c0f2e808d28f29d6587f1ec9276233e29856b7f2938cf0daef0026",
* // "81039b1d7b855b133f359f9dc65f776bd105650153a941675fedc504228ddbd3"
* // ]
* // },
* // {
* // "page": 1,
* // "totalPages": 1,
* // "itemsOnPage": 1000,
* // "address": "bitcoincash:qpcxf2sv9hjw08nvpgffpamfus9nmksm3chv5zqtnz",
* // "balance": "0",
* // "totalReceived": "36781097",
* // "totalSent": "36781097",
* // "unconfirmedBalance": "0",
* // "unconfirmedTxs": 0,
* // "txs": 11,
* // "txids": [
* // "11205c557af139f382c43f1f09f223cf28c64d939951fd569e5a30eee6178ccd",
* // "ae05a78086b8d64db26d3047de3d6959a68f2a1ed3017ddf927e2c3b20a80b31",
* // "7e0fc3cac7504d45b0f2ce68e807e592f0edf17914ab618a4cb4d93403d11c98",
* // "60cb69f29c150378abe21d157858713f82c4e2122867597a2573474763a9e94e",
* // "f737485aaee3c10b13013fa109bb6294b099246134ca9885f4cc332dbc6c9bb4",
* // "decd5b9c0c959e4e543182093e8f7f8bc7a6ecd96a8a062daaeff3667f8feca7",
* // "94e69a627a34ae27fca81d15fff4323a7ce1f7c275c7485762ce018221017632",
* // "e67c70787af7f3506263c9eda007f3d2d24bd750ff95b5c50a120d9118dfd807",
* // "8e5e00704a147d54028f94d52df7730e821b9c6cd4bd29494e5636f49c199d6a",
* // "15102827c108566ea5daf725c09079c1a3f42ef99d1eb68ea8c584f7b16ab87a",
* // "cc27be8846276612dfce5924b7be96556212f0f0e62bd17641732175edb9911e"
* // ]
* // }
* //
*
*/
async balance(address) {
try {
// Handle single address.
if (typeof address === "string") {
const response = await axios.get(
`${this.restURL}blockbook/balance/${address}`,
_this.axiosOptions
)
return response.data
// Handle array of addresses.
} else if (Array.isArray(address)) {
const response = await axios.post(
`${this.restURL}blockbook/balance`,
{
addresses: address
},
_this.axiosOptions
)
return response.data
}
throw new Error(`Input address must be a string or array of strings.`)
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api Blockbook.utxo() utxo()
* @apiName Blockbook Utxo
* @apiGroup Blockbook
* @apiDescription Return list of uxto for address.
*
* @apiExample Example usage:
* (async () => {
* try {
* let utxo = await bchjs.Blockbook.utxo('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf');
* console.log(utxo);
* } catch(error) {
* console.error(error)
* }
* })()
*
* [{
* "txid": "7774e449c5a3065144cefbc4c0c21e6b69c987f095856778ef9f45ddd8ae1a41",
* "vout": 0,
* "value": "1000",
* "height": 604392,
* "confirmations": 25530,
* "satoshis": 1000
* }]
*
*
* (async () => {
* try {
* let utxo = await bchjs.Blockbook.utxo([
* "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
* "bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c"
* ]);
* console.log(utxo);
* } catch(error) {
* console.error(error)
* }
* })()
*
* [
* [{
* "txid": "7774e449c5a3065144cefbc4c0c21e6b69c987f095856778ef9f45ddd8ae1a41",
* "vout": 0,
* "value": "1000",
* "height": 604392,
* "confirmations": 25530,
* "satoshis": 1000
* }],
* [{
* "txid": "d5228d2cdc77fbe5a9aa79f19b0933b6802f9f0067f42847fc4fe343664723e5",
* "vout": 0,
* "value": "6000",
* "confirmations": 0,
* "satoshis": 6000
* }]
* ]
*/
async utxo(address) {
try {
// Handle single address.
if (typeof address === "string") {
const response = await axios.get(
`${this.restURL}blockbook/utxos/${address}`,
_this.axiosOptions
)
return response.data
// Handle array of addresses.
} else if (Array.isArray(address)) {
const response = await axios.post(
`${this.restURL}blockbook/utxos`,
{
addresses: address
},
_this.axiosOptions
)
return response.data
}
throw new Error(`Input address must be a string or array of strings.`)
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api Blockbook.tx() tx()
* @apiName Blockbook Tx
* @apiGroup Blockbook
* @apiDescription Get details on a transaction.
*
* @apiExample Example usage:
* (async () => {
* try {
* let txDetails = await bchjs.Blockbook.tx(`5fe9b74056319a8c87f45cc745030715a6180758b94938dbf90d639d55652392`);
* console.log(txDetails);
* } catch(error) {
* console.error(error)
* }
* })()
*
*/
async tx(txid) {
try {
// Handle single txid.
if (typeof txid === "string") {
const response = await axios.get(
`${this.restURL}blockbook/tx/${txid}`,
_this.axiosOptions
)
return response.data
// Handle array of addresses.
} else if (Array.isArray(txid)) {
const response = await axios.post(
`${this.restURL}blockbook/tx`,
{
txids: txid
},
_this.axiosOptions
)
return response.data
}
throw new Error(`Input txid must be a string or array of strings.`)
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
}
module.exports = Blockbook
+14 -4
View File
@@ -11,11 +11,21 @@ class Blockchain {
constructor(config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
+14 -4
View File
@@ -10,11 +10,21 @@ class Control {
constructor(config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
+14 -5
View File
@@ -11,12 +11,21 @@ class ElectrumX {
constructor(config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`,
timeout: 15000
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
+14 -5
View File
@@ -11,12 +11,21 @@ class Encryption {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.axios = axios
// console.log(`Blockbook apiToken: ${this.apiToken}`)
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
+14 -4
View File
@@ -6,11 +6,21 @@ class Generating {
constructor(config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
+14 -4
View File
@@ -6,11 +6,21 @@ class Mining {
constructor(config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
+220 -2
View File
@@ -50,14 +50,16 @@ class Ninsight {
* // {
* // "txid": "d31dc2cf66fe4d3d3ae18e1065def58a64920746b1702b52f060e5edeea9883b",
* // "vout": 1,
* // "value": "1000000",
* // "amount": 0.03608203,
* // "satoshis": 3608203,
* // "height": 585570,
* // "confirmations": 10392
* // },
* // {
* // "txid": "41e9a118765ecf7a1ba4487c0863e23dba343cc5880381a72f0365ac2546c5fa",
* // "vout": 0,
* // "value": "1000000",
* // "amount": 0.03608203,
* // "satoshis": 3608203,
* // "height": 577125,
* // "confirmations": 18837
* // }
@@ -96,6 +98,222 @@ class Ninsight {
else throw error
}
}
/**
* @api Ninsight.unconfirmed() unconfirmed()
* @apiName Ninsight Unconfirmed Utxo
* @apiGroup Ninsight
* @apiDescription Returns a list of unconfirmed UTXOs for an address.
*
* @apiExample Example usage:
* (async () => {
* try {
* let utxo = await bchjs.Ninsight.unconfirmed('bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c');
* console.log(utxo);
* } catch(error) {
* console.error(error)
* }
* })()
*
* // [
* // {
* // "txid": "d31dc2cf66fe4d3d3ae18e1065def58a64920746b1702b52f060e5edeea9883b",
* // "vout": 1,
* // "amount": 0.03608203,
* // "satoshis": 3608203,
* // "confirmations": 0
* // "ts": 1559670801
* // },
* // {
* // "txid": "41e9a118765ecf7a1ba4487c0863e23dba343cc5880381a72f0365ac2546c5fa",
* // "vout": 0,
* // "amount": 0.03608203,
* // "satoshis": 3608203,
* // "confirmations": 0
* // "ts": 1559670902
* // }
* // ]
*
*/
async unconfirmed(address) {
try {
if (typeof address === "string") {
const response = await axios.post(
`${this.ninsightURL}/address/unconfirmed`,
{
addresses: [address]
},
_this.axiosOptions
)
return response.data
} else if (Array.isArray(address)) {
const response = await axios.post(
`${this.ninsightURL}/address/unconfirmed`,
{
addresses: address
},
_this.axiosOptions
)
return response.data
}
throw new Error(`Input address must be a string or array of strings.`)
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api Ninsight.transactions() transactions()
* @apiName Ninsight TX History
* @apiGroup Ninsight
* @apiDescription Return transactions history for address.
*
* @apiExample Example usage:
* (async () => {
* try {
* let txs = await bchjs.Ninsight.transactions('bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c');
* console.log(txs);
* } catch(error) {
* console.error(error)
* }
* })()
*
* // [
* // {
* // "pagesTotal": 1,
* // "txs": [
* // {
* // "txid": "ec7bc8349386e3e1939bbdc4f8092fdbdd6a380734e68486b558cd594c451d5b",
* // "version": 2,
* // "locktime": 0,
* // "vin": [
* // {
* // "txid": "4f1fc57c33659628938db740449bf92fb75799e1d5750a4aeef80eb52d6df1e0",
* // "vout": 0,
* // "sequence": 4294967295,
* // "n": 0,
* // ...
* // }
* // ...
* // ]
* // ...
* // }
* // ],
* // "legacyAddress": "1LpbYkEM5cryfhs58tH8c93p4SGzit7UrP",
* // "cashAddress": "bitcoincash:qrvk436u4r0ew2wj0rd9pnxhx4w90p2yfc29ta0d2n",
* // "currentPage": 0
* // }
* // ]
* //
*
*/
async transactions(address) {
try {
if (typeof address === "string") {
const response = await axios.post(
`${this.ninsightURL}/address/transactions`,
{
addresses: [address]
},
_this.axiosOptions
)
return response.data
} else if (Array.isArray(address)) {
const response = await axios.post(
`${this.ninsightURL}/address/transactions`,
{
addresses: address
},
_this.axiosOptions
)
return response.data
}
throw new Error(`Input address must be a string or array of strings.`)
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
/**
* @api Ninsight.txDetails() txDetails()
* @apiName Ninsight TX Details
* @apiGroup Ninsight
* @apiDescription Return transactions details for address(es).
*
* @apiExample Example usage:
* (async () => {
* try {
* let result = await bchjs.Ninsight.txDetails('fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33');
* console.log(result);
* } catch(error) {
* console.error(error)
* }
* })()
*
* // [
* // {
* // "txid": "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33",
* // "version": 1,
* // "locktime": 0,
* // "vin": [
* // {
* // "sequence": 4294967295,
* // "n": 0
* // }
* // ],
* // "vout": [
* // ...
* // ],
* // "blockhash": "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09",
* // "blockheight": 1000,
* // "confirmations": 659909,
* // "time": 1232346882,
* // "blocktime": 1232346882,
* // "firstSeenTime": null,
* // "valueOut": 50,
* // "size": 135
* // }
* // ]
*
*/
async txDetails(txid) {
try {
if (typeof txid === "string") {
const response = await axios.post(
`${this.ninsightURL}/transaction/details`,
{
txids: [txid]
},
_this.axiosOptions
)
return response.data
} else if (Array.isArray(txid)) {
const response = await axios.post(
`${this.ninsightURL}/transaction/details`,
{
txids: txid
},
_this.axiosOptions
)
return response.data
}
throw new Error(`Transaction ID must be a string or array of strings.`)
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
}
}
}
module.exports = Ninsight
+60 -28
View File
@@ -6,41 +6,30 @@ class Price {
constructor(config) {
_this = this
if (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
}
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
this.axios = axios
}
/**
* @api price.current() current()
* @apiName Price.
* @apiGroup Price
* @apiDescription Return current price of BCH in multiple currencies.
* This endpoint will be deprecated in favor of getUSD. It uses the Bitcoin.com
* price feed.
*
* @apiExample Example usage:
*(async () => {
* try {
* let current = await bchjs.Price.current('usd');
* console.log(current);
* } catch(err) {
* console.err(err)
* }
*})()
*
* // 26681
*/
// This endpoint is deprecated. Documentation removed.
async current(currency = "usd") {
try {
const response = await this.axios.get(
@@ -109,6 +98,14 @@ class Price {
* }
*})()
*
* {
* AED: "915.049218",
* AFN: "19144.48874646",
* ALGO: "826.6633482661356600405",
* ...
* ZRX: "644.844402797695193656",
* ZWL: "80215.03"
* }
*/
async rates() {
try {
@@ -124,6 +121,41 @@ class Price {
else throw err
}
}
/**
* @api price.getBchaUsd() getBchaUsd()
* @apiName Price getBchaUsd()
* @apiGroup Price
* @apiDescription Return current price of BCHA in USD.
* This endpoint gets the USD price of BCHA from the Coinex API. The price
* comes from bch-api, so it has a better chance of working in Tor.
*
* @apiExample Example usage:
*(async () => {
* try {
* let current = await bchjs.Price.getBchaUsd();
* console.log(current);
* } catch(err) {
* console.err(err)
* }
*})()
*
* // 18.81
*/
async getBchaUsd() {
try {
const response = await this.axios.get(
`${this.restURL}price/bchausd`,
_this.axiosOptions
)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
return response.data.usd
} catch (err) {
if (err.response && err.response.data) throw err.response.data
else throw err
}
}
}
module.exports = Price
+21 -12
View File
@@ -6,14 +6,27 @@ class RawTransactions {
constructor(config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
// Encapsulate dependencies
this.axios = axios
_this = this
}
@@ -262,9 +275,7 @@ class RawTransactions {
txids: txid,
verbose: verbose
},
headers: {
authorization: `Token ${this.apiToken}`
}
headers: _this.axiosOptions.headers
}
const response = await axios(options)
@@ -314,7 +325,7 @@ class RawTransactions {
try {
// Single tx hex.
if (typeof hex === "string") {
const response = await axios.get(
const response = await this.axios.get(
`${this.restURL}rawtransactions/sendRawTransaction/${hex}`,
_this.axiosOptions
)
@@ -337,11 +348,9 @@ class RawTransactions {
data: {
hexes: hex
},
headers: {
authorization: `Token ${this.apiToken}`
}
headers: _this.axiosOptions.headers
}
const response = await axios(options)
const response = await _this.axios(options)
return response.data
}
+14 -4
View File
@@ -4,11 +4,21 @@ class Schnorr {
constructor(config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
}
+20 -11
View File
@@ -18,22 +18,31 @@ const Utils = require("./utils")
// SLP is a superset of BITBOX
class SLP {
constructor(config) {
const tmp = {}
if (!config || !config.restURL) {
tmp.restURL = `https://api.fullstack.cash/v3/`
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
tmp.restURL = config.restURL
tmp.apiToken = config.apiToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
this.restURL = tmp.restURL
this.apiToken = tmp.apiToken
this.Address = new Address(tmp)
this.Address = new Address(config)
this.ECPair = ECPair
this.TokenType1 = new TokenType1(tmp)
this.TokenType1 = new TokenType1(config)
this.NFT1 = new NFT1(this.restURL)
this.Utils = new Utils(tmp)
this.Utils = new Utils(config)
}
}
+48 -25
View File
@@ -1,3 +1,7 @@
/*
This library handles the OP_RETURN of SLP TokenType1 transactions.
*/
//const BCHJS = require("../bch-js")
//const bchjs = new BCHJS()
@@ -18,17 +22,28 @@ class TokenType1 {
constructor(config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
addy = new Address(config)
this.Script = new Script()
this.axios = axios
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
// Instantiate the transaction builder.
TransactionBuilder.setAddress(addy)
@@ -82,12 +97,16 @@ class TokenType1 {
const tokenId = tokenUtxos[0].tokenId
const decimals = tokenUtxos[0].decimals
// Calculate the total amount of tokens owned by the wallet.
let totalTokens = 0
for (let i = 0; i < tokenUtxos.length; i++)
totalTokens += tokenUtxos[i].tokenQty
const sendQtyBig = new BigNumber(sendQty).times(10 ** decimals)
const change = totalTokens - sendQty
// Calculate the total amount of tokens owned by the wallet.
const totalTokens = tokenUtxos.reduce(
(tot, txo) =>
tot.plus(new BigNumber(txo.tokenQty).times(10 ** decimals)),
new BigNumber(0)
)
const change = totalTokens.minus(sendQtyBig)
// console.log(`change: ${change}`)
let script
@@ -98,19 +117,20 @@ class TokenType1 {
outputs = 2
// Convert the send quantity to the format expected by slp-mdm.
let baseQty = new BigNumber(sendQty).times(10 ** decimals)
baseQty = baseQty.absoluteValue()
baseQty = Math.floor(baseQty)
baseQty = baseQty.toString()
const baseQty = sendQtyBig.toString()
// console.log(`baseQty: `, baseQty)
// Convert the change quantity to the format expected by slp-mdm.
let baseChange = new BigNumber(change).times(10 ** decimals)
baseChange = baseChange.absoluteValue()
baseChange = Math.floor(baseChange)
baseChange = baseChange.toString()
const baseChange = change.toString()
// console.log(`baseChange: `, baseChange)
// Check for potential burns
const outputQty = new BigNumber(baseChange).plus(new BigNumber(baseQty))
const inputQty = new BigNumber(totalTokens)
const tokenOutputDelta = outputQty.minus(inputQty).toString() !== "0"
if (tokenOutputDelta)
throw "Token transaction inputs do not match outputs, cannot send transaction"
// Generate the OP_RETURN as a Buffer.
script = slpMdm.TokenType1.send(tokenId, [
new slpMdm.BN(baseQty),
@@ -120,13 +140,16 @@ class TokenType1 {
// Corner case, when there is no token change to send back.
} else {
let baseQty = new BigNumber(sendQty).times(10 ** decimals)
baseQty = baseQty.absoluteValue()
baseQty = Math.floor(baseQty)
baseQty = baseQty.toString()
const baseQty = sendQtyBig.toString()
// console.log(`baseQty: `, baseQty)
// console.log(`baseQty: ${baseQty.toString()}`)
// Check for potential burns
const noChangeOutputQty = new BigNumber(baseQty)
const noChangeInputQty = new BigNumber(totalTokens)
const tokenSingleOutputError =
noChangeOutputQty.minus(noChangeInputQty).toString() !== "0"
if (tokenSingleOutputError)
throw "Token transaction inputs do not match outputs, cannot send transaction"
// Generate the OP_RETURN as a Buffer.
script = slpMdm.TokenType1.send(tokenId, [new slpMdm.BN(baseQty)])
@@ -426,7 +449,7 @@ class TokenType1 {
return slpSendObj
} catch (err) {
console.log(err)
// console.log(err)
throw err
}
}
+378 -47
View File
@@ -1,5 +1,7 @@
// Public npm libraries
const axios = require("axios")
const slpParser = require("slp-parser")
const BigNumber = require("bignumber.js")
// const Script = require("../script")
// const scriptLib = new Script()
@@ -13,15 +15,28 @@ class Utils {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.slpParser = slpParser
this.authToken = config.authToken
this.axios = axios
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
_this = this
this.whitelist = []
}
/**
@@ -183,6 +198,7 @@ class Utils {
async list(id) {
let path
let method
if (!id) {
method = "get"
path = `${this.restURL}slp/list`
@@ -199,9 +215,9 @@ class Utils {
try {
let response
if (method === "get") {
response = await axios.get(path, _this.axiosOptions)
response = await _this.axios.get(path, _this.axiosOptions)
} else {
response = await axios.post(
response = await _this.axios.post(
path,
{
tokenIds: id
@@ -297,7 +313,7 @@ class Utils {
if (typeof address === "string") {
const path = `${this.restURL}slp/balancesForAddress/${address}`
const response = await axios.get(path, _this.axiosOptions)
const response = await _this.axios.get(path, _this.axiosOptions)
return response.data
// Array of addresses.
@@ -305,7 +321,7 @@ class Utils {
const path = `${this.restURL}slp/balancesForAddress`
// Dev note: must use axios.post for unit test stubbing.
const response = await axios.post(
const response = await _this.axios.post(
path,
{
addresses: address
@@ -359,10 +375,10 @@ class Utils {
*/
// Retrieve token balances for a given tokenId.
async balancesForToken(tokenId) {
const path = `${this.restURL}slp/balancesForToken/${tokenId}`
try {
const response = await axios.get(path, _this.axiosOptions)
const path = `${this.restURL}slp/balancesForToken/${tokenId}`
const response = await _this.axios.get(path, _this.axiosOptions)
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
@@ -416,6 +432,10 @@ class Utils {
* '00ea27261196a411776f81029c0ebe34362936b4a9847deb1f7a40a02b3a1476',
* valid: true } ]
*/
// This function has two responses. If SLPDB is working correctly, the output
// will be like the examples above. If SLPDB has fallen behind real-time
// processing, it will return this output:
// [ null ]
async validateTxid(txid) {
const path = `${this.restURL}slp/validateTxid`
@@ -427,27 +447,19 @@ class Utils {
else txids = txid
try {
const response = await axios.post(
const response = await _this.axios.post(
path,
{
txids: txids
},
_this.axiosOptions
)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
// console.log(
// `validateTxid response.data: ${JSON.stringify(response.data, null, 2)}`
// )
const validatedTxids = response.data
// Handle any null values
for (let i = 0; i < validatedTxids.length; i++) {
if (validatedTxids[i] === null) {
validatedTxids[i] = {
txid: txids[i],
valid: false
}
}
}
return validatedTxids
} catch (error) {
if (error.response && error.response.data) throw error.response.data
@@ -475,7 +487,7 @@ class Utils {
* // validate single SLP txid
* (async () => {
* try {
* let validated = await bchjs.SLP.Utils.validateTxid(
* let validated = await bchjs.SLP.Utils.validateTxid2(
* "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb"
* );
* console.log(validated);
@@ -503,7 +515,7 @@ class Utils {
const path = `${this.restURL}slp/validateTxid2/${txid}`
const response = await axios.get(path, _this.axiosOptions)
const response = await _this.axios.get(path, _this.axiosOptions)
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
@@ -515,6 +527,154 @@ class Utils {
}
}
/**
* @api SLP.Utils.whitelist() whitelist()
* @apiName whitelist
* @apiGroup SLP Utils
* @apiDescription Get SLP tokens in whitelist
* Retrieves a list of the SLP tokens that in the whitelist. Tokens in the
* whitelist can be validated with the validateTxid3() function. validateTxid3()
* will still work when the SLP network is under stress.
*
* @apiExample Example usage:
*
* // validate single SLP txid
* (async () => {
* try {
* let list = await bchjs.SLP.Utils.whitelit();
* console.log(list);
* } catch (error) {
* console.error(error);
* }
* })();
*
* // returns
* [
* {
* name: 'USDH',
* tokenId:
* 'c4b0d62156b3fa5c8f3436079b5394f7edc1bef5dc1cd2f9d0c4d46f82cca479'
* },
* {
* name: 'SPICE',
* tokenId:
* '4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf'
* },
* {
* name: 'PSF',
* tokenId:
* '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0'
* },
* {
* name: 'TROUT',
* tokenId:
* 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
* },
* {
* name: 'PSFTEST',
* tokenId:
* 'd0ef4de95b78222bfee2326ab11382f4439aa0855936e2fe6ac129a8d778baa0'
* }
* ]
*/
async getWhitelist() {
try {
const path = `${this.restURL}slp/whitelist`
// Retrieve the whitelist from the REST API if we haven't gotten it yet.
if (this.whitelist.length === 0) {
const response = await _this.axios.get(path, _this.axiosOptions)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
this.whitelist = response.data
}
return this.whitelist
} catch (error) {
if (error.response && error.response.data) throw error.response.data
throw error
}
}
/**
* @api SLP.Utils.validateTxid3() validateTxid3()
* @apiName validateTxid3
* @apiGroup SLP Utils
* @apiDescription Validate that txid is an SLP transaction using the SLPDB whitelist server.
* Same exact functionality as the validateTxid() function, but this function
* calls the whitelist SLPDB. It will only validate SLP tokens that are in the
* whitelist. You can retrieve the whitelist with the SLP.Utils.whitelist()
* function.
*
* @apiExample Example usage:
*
* // validate single SLP txid
* (async () => {
* try {
* let validated = await bchjs.SLP.Utils.validateTxid3(
* "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb"
* );
* console.log(validated);
* } catch (error) {
* console.error(error);
* }
* })();
*
* // returns
* [ { txid:
* 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
* valid: true } ]
*
* // validate multiple SLP txids
* (async () => {
* try {
* let validated = await bchjs.SLP.Utils.validateTxid3([
* "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb",
* "00ea27261196a411776f81029c0ebe34362936b4a9847deb1f7a40a02b3a1476"
* ]);
* console.log(validated);
* } catch (error) {
* console.error(error);
* }
* })();
*
* // returns
* [ { txid:
* 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
* valid: true },
* { txid:
* '00ea27261196a411776f81029c0ebe34362936b4a9847deb1f7a40a02b3a1476',
* valid: true } ]
*/
async validateTxid3(txid) {
const path = `${this.restURL}slp/validateTxid3`
// console.log(`txid: ${JSON.stringify(txid, null, 2)}`)
// Handle a single TXID or an array of TXIDs.
let txids
if (typeof txid === "string") txids = [txid]
else txids = txid
try {
const response = await _this.axios.post(
path,
{
txids: txids
},
_this.axiosOptions
)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
const validatedTxids = response.data
return validatedTxids
} catch (error) {
if (error.response && error.response.data) throw error.response.data
throw error
}
}
/**
* @api SLP.Utils.tokenStats() tokenStats()
* @apiName tokenStats
@@ -551,10 +711,11 @@ class Utils {
* }
*/
async tokenStats(tokenId) {
const path = `${this.restURL}slp/tokenStats/${tokenId}`
try {
const response = await axios.get(path, _this.axiosOptions)
const path = `${this.restURL}slp/tokenStats/${tokenId}`
const response = await _this.axios.get(path, _this.axiosOptions)
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
@@ -621,10 +782,11 @@ class Utils {
*/
// Retrieve token transactions for a given tokenId and address.
async transactions(tokenId, address) {
const path = `${this.restURL}slp/transactions/${tokenId}/${address}`
try {
const response = await axios.get(path, _this.axiosOptions)
const path = `${this.restURL}slp/transactions/${tokenId}/${address}`
const response = await _this.axios.get(path, _this.axiosOptions)
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
@@ -660,10 +822,11 @@ class Utils {
* }
*/
async burnTotal(transactionId) {
const path = `${this.restURL}slp/burnTotal/${transactionId}`
try {
const response = await axios.get(path, _this.axiosOptions)
const path = `${this.restURL}slp/burnTotal/${transactionId}`
const response = await _this.axios.get(path, _this.axiosOptions)
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
@@ -705,7 +868,7 @@ class Utils {
// console.log(`this.restURL: ${this.restURL}`)
const path = `${this.restURL}slp/txDetails/${txid}`
const response = await axios.get(path, _this.axiosOptions)
const response = await _this.axios.get(path, _this.axiosOptions)
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
@@ -780,7 +943,7 @@ class Utils {
// Retrieve the transaction object from the full node.
const path = `${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=true`
const response = await axios.get(path, _this.axiosOptions)
const response = await _this.axios.get(path, _this.axiosOptions)
const txDetails = response.data
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
@@ -931,6 +1094,7 @@ class Utils {
}
}
// Ensure the UTXO has a vout or tx_pos property.
if (!Number.isInteger(utxo.vout)) {
if (Number.isInteger(utxo.tx_pos)) {
utxo.vout = utxo.tx_pos
@@ -965,9 +1129,13 @@ class Utils {
if (
!err.message ||
(err.message.indexOf("scriptpubkey not op_return") === -1 &&
err.message.indexOf("lokad id") === -1)
err.message.indexOf("lokad id") === -1 &&
err.message.indexOf("trailing data") === -1)
) {
// console.log(`error from decodeOpReturn(${utxo.txid}): `, err)
// console.log(
// `unknown error from decodeOpReturn(). Marking as 'null'`,
// err
// )
utxo.isValid = null
outAry.push(utxo)
@@ -976,6 +1144,7 @@ class Utils {
// an SLP UTXO.
// Mark as false and continue the loop.
} else {
// console.log("marking as invalid")
utxo.isValid = false
outAry.push(utxo)
}
@@ -1010,7 +1179,9 @@ class Utils {
// Tokens
else {
utxo.utxoType = "token"
utxo.tokenQty = slpData.qty / Math.pow(10, slpData.decimals)
utxo.tokenQty = new BigNumber(slpData.qty)
.div(Math.pow(10, slpData.decimals))
.toString()
}
utxo.tokenId = utxo.txid
@@ -1053,7 +1224,9 @@ class Utils {
// Tokens
else {
utxo.utxoType = "token"
utxo.tokenQty = slpData.qty / Math.pow(10, genesisData.decimals)
utxo.tokenQty = new BigNumber(slpData.qty)
.div(Math.pow(10, genesisData.decimals))
.toString()
}
// Hydrate the UTXO object with information about the SLP token.
@@ -1111,7 +1284,12 @@ class Utils {
utxo.tokenType = slpData.tokenType
// Calculate the real token quantity.
utxo.tokenQty = tokenQty / Math.pow(10, genesisData.decimals)
const tokenQtyBig = new BigNumber(tokenQty).div(
Math.pow(10, genesisData.decimals)
)
//console.log(`tokenQtyBig`, tokenQtyBig.toString())
utxo.tokenQty = tokenQtyBig.toString()
// console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
@@ -1119,16 +1297,127 @@ class Utils {
}
}
// Finally, validate the SLP txid with SLPDB.
// *After* the UTXO has been hydrated with SLP data,
// validate the TXID with SLPDB.
if (outAry[i].tokenType) {
var isValid = cachedTxValidation[utxo.txid]
if (isValid == null) {
// Only execute this block if the current UTXO has a 'tokenType'
// property. i.e. it has been successfully hydrated with SLP
// information.
// CT 12/13/2020: Disabling the cache until I get processing of tokens
// to be more stable.
// If the value has been cached, use the cached version first.
let isValid = cachedTxValidation[utxo.txid]
if (!isValid) isValid = null
// let isValid = null
// There are two possible responses from SLPDB. If SLPDB is functioning
// correctly, then validateTxid() will return this:
// isValid: [
// {
// "txid": "ff0c0354f8d3ddb34fa36f73494eb58ea24f8b8da6904aa8ed43b7a74886c583",
// "valid": true
// }
// ]
//
// If SLPDB has fallen behind real-time processing, it will return this:
// isValid: [
// null
// ]
//
// Note: validateTxid3() has the same output as validateTxid().
// validateTxid2() uses slp-validate, which has a different output format.
// If not in the cache, try the general SLPDB.
if (isValid === null) {
// console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
isValid = await this.validateTxid(utxo.txid)
cachedTxValidation[utxo.txid] = isValid
// console.log(
// `validateTxid() isValid: ${JSON.stringify(isValid, null, 2)}`
// )
// Handle corner case where SLPDB returns an array with a null element.
if (isValid[0] === null)
isValid = [{ txid: utxo.txid, valid: null }]
isValid = isValid[0].valid
// Save the result to the local cache.
// cachedTxValidation[utxo.txid] = isValid
}
// console.log(`isValid: ${JSON.stringify(isValid, null, 2)}`)
outAry[i].isValid = isValid[0].valid
// console.log(
// `pre-validateTxid3() isValid: ${JSON.stringify(isValid, null, 2)}`
// )
// If still null, check the whitelist SLPDB
if (isValid === null) {
// console.log(
// `checking against whitelist SLPDB. outAry[${i}]: ${JSON.stringify(
// outAry[i],
// null,
// 2
// )}`
// )
// Figure out if the token UTXO is in the whitelist.
let utxoInWhitelist = false
for (let j = 0; j < this.whitelist.length; j++) {
if (outAry[i].tokenId === this.whitelist[j].tokenId) {
utxoInWhitelist = true
break
}
}
// If the utxo.tokenId is in the whitelist, check the validity with
// the whitelist SLPDB. This should still be functioning properly
// if the general SLPDB is not.
if (utxoInWhitelist) {
isValid = await this.validateTxid3(utxo.txid)
// console.log(
// `whitelist-SLPDB for ${utxo.txid}: ${JSON.stringify(
// isValid,
// null,
// 2
// )}`
// )
if (isValid[0] !== null) isValid = isValid[0].valid
// Save the result to the local cache.
// cachedTxValidation[utxo.txid] = isValid
}
}
// console.log(
// `pre-validateTxid2() isValid: ${JSON.stringify(isValid, null, 2)}`
// )
// If still null, as a last resort, check it against slp-validate
if (isValid === null) {
try {
isValid = await this.validateTxid2(utxo.txid)
} catch (err) {
// Mark as invalid if validateTxid2() throws an error.
isValid = null
}
// console.log(
// `slp-validate isValid: ${JSON.stringify(isValid, null, 2)}`
// )
if (isValid !== null) isValid = isValid.isValid
// Save the result to the local cache.
// cachedTxValidation[utxo.txid] = isValid
}
// console.log(`isValid: ${JSON.stringify(isValid, null, 2)}`)
outAry[i].isValid = isValid
// Save the txid to the local cache to reduce API calls.
cachedTxValidation[utxo.txid] = isValid
}
}
@@ -1309,7 +1598,7 @@ class Utils {
// Throw error if input is not an array.
if (!Array.isArray(utxos)) throw new Error("Input must be an array.")
const response = await axios.post(
const response = await _this.axios.post(
`${this.restURL}slp/hydrateUtxos`,
{
utxos: utxos
@@ -1323,6 +1612,48 @@ class Utils {
else throw error
}
}
/**
* @api SLP.Utils.getStatus() getStatus()
* @apiName getStatus
* @apiGroup SLP Utils
* @apiDescription Get the status and health of the SLPDB connected to bch-api.
*
* @apiExample Example usage:
*
* // Get the current blockheight of the SLPDB indexer.
* (async () => {
* try {
* let validated = await bchjs.SLP.Utils.validateTxid(
* "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb"
* );
* console.log(validated);
* } catch (error) {
* console.error(error);
* }
* })();
*
* // returns
* [ { txid:
* 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
* valid: true } ]
*
*/
async getStatus(txid) {
const path = `${this.restURL}slp/status`
try {
const response = await _this.axios.get(path, _this.axiosOptions)
// console.log(
// `getStatus response.data: ${JSON.stringify(response.data, null, 2)}`
// )
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
throw error
}
}
}
module.exports = Utils
+14 -4
View File
@@ -6,11 +6,21 @@ class Util {
constructor(config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
}
}
+13 -6
View File
@@ -4,12 +4,19 @@
To Run Test:
- Update the RESTURL for bch-api you want to test against.
- Ensure the BCHJSTOKEN environment variable is set to an empty string.
- If working with bch-api locally, eliminate the local IP address from the
whitelist in bch-api/src/middleware/route-ratelimit.js
Run this test with this command:
mocha --timeout=30000 anonymous-rate-limits.js
*/
const assert = require("chai").assert
const RESTURL = `https://api.fullstack.cash/v3/`
// const RESTURL = `http://localhost:3000/v3/`
// const RESTURL = `https://abc.fullstack.cash/v4/`
const RESTURL = `https://bchn.fullstack.cash/v4/`
// const RESTURL = `http://localhost:3000/v4/`
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({ restURL: RESTURL })
@@ -23,7 +30,7 @@ describe("#anonymous rate limits", () => {
it("should allow an anonymous call to an indexer", async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
const result = await bchjs.Blockbook.balance(addr)
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "balance")
@@ -31,11 +38,11 @@ describe("#anonymous rate limits", () => {
it("should throw error when rate limit exceeded", async () => {
try {
for (let i = 0; i < 5; i++) await bchjs.Control.getNetworkInfo()
for (let i = 0; i < 35; i++) await bchjs.Control.getNetworkInfo()
assert.equal(true, false, "unexpected result")
assert.fail("Unexpected result")
} catch (err) {
assert.include(err.error, "Too many requests")
}
}).timeout(5000)
}).timeout(20000)
})
@@ -0,0 +1,56 @@
/*
Mocha test that verifies that the bch-api server is enforcing its
access rules for Basic Authentication.
To Run Test:
- Update the restURL for bch-api you want to test against.
- Update the PRO_PASS value with a current PRO_PASSES string used by bch-api.
*/
const assert = require("chai").assert
const PRO_PASS = "testpassword"
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({
// restURL: `https://bchn.fullstack.cash/v4/`,
restURL: `https://abc.fullstack.cash/v4/`,
// restURL: `http://localhost:3000/v4/`,
authPass: PRO_PASS
})
describe("#Basic Authentication rate limits", () => {
it("should allow more than 20 RPM to full node", async () => {
for (let i = 0; i < 22; i++) {
const result = await bchjs.Control.getNetworkInfo()
if (i === 5) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, "version", "more than 3 calls allowed")
}
if (i === 15) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, "version", "more than 10 calls allowed")
}
}
}).timeout(45000)
it("should allow more than 20 RPM to an indexer", async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
for (let i = 0; i < 22; i++) {
const result = await bchjs.Blockbook.balance(addr)
if (i === 5) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, "balance", "more than 3 calls allowed")
}
if (i === 15) {
// console.log(`validating 5th call: ${i}`)
assert.property(result, "balance", "more than 10 calls allowed")
}
}
}).timeout(45000)
})
+18 -16
View File
@@ -1,4 +1,8 @@
/*
CT 11/11/2020:
There is no longer a free tier. These tests have been deprecated.
--------
Mocha test that verifies that the bch-api server is enforcing its
FREE access rules
@@ -10,12 +14,12 @@
const assert = require("chai").assert
const JWT_TOKEN =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2YyMDIyMWMxMDAxMmFkOTQwMSIsImVtYWlsIjoiZGVtb0BkZW1vLmNvbSIsImFwaUxldmVsIjoxMCwicmF0ZUxpbWl0IjozLCJpYXQiOjE1OTA1Mjk2NzgsImV4cCI6MTU5MzEyMTY3OH0.4q5MFDCcVx0FusivJPiEIj3w8nhFG7ZV5IhJS7faUlc"
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2YyMDIyMWMxMDAxMmFkOTQwMSIsImVtYWlsIjoiZGVtb0BkZW1vLmNvbSIsImFwaUxldmVsIjoxMCwicmF0ZUxpbWl0IjozLCJpYXQiOjE2MDQ4NTQ2OTEsImV4cCI6MTYwNzQ0NjY5MX0.iwse0z0KDKHx9graCxcOwj6lSlfKQAb1zLhmjvygvts"
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({
restURL: `https://api.fullstack.cash/v3/`,
// restURL: `http://localhost:3000/v3/`,
restURL: `https://api.fullstack.cash/v4/`,
// restURL: `http://localhost:3000/v4/`,
apiToken: JWT_TOKEN
})
@@ -28,19 +32,6 @@ describe("#free rate limits", () => {
assert.property(result, "balance")
}).timeout(5000)
// it("should throw error when rate limit exceeded 3 RPM for indexer endpoints", async () => {
// const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
//
// try {
// for (let i = 0; i < 5; i++) await bchjs.Blockbook.balance(addr)
//
// assert.equal(true, false, "unexpected result")
// } catch (err) {
// // console.log(`err: `, err)
// assert.include(err.error, "Too many requests")
// }
// }).timeout(10000)
it("should allow up to 10 RPM to indexer, then throw error", async () => {
try {
const addr = "bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0"
@@ -87,4 +78,15 @@ describe("#free rate limits", () => {
assert.notInclude(err.error, 3)
}
}).timeout(20000)
it("should throw error when rate limit exceeded 20 RPM for indexer endpoints", async () => {
try {
for (let i = 0; i < 22; i++) await bchjs.Control.getNetworkInfo()
assert.fail("unexpected result")
} catch (err) {
// console.log(`err: `, err)
assert.include(err.error, "Too many requests")
}
}).timeout(20000)
})
+28 -21
View File
@@ -1,48 +1,54 @@
/*
CT 11/11/2020:
There is no longer a free tier. These tests have been deprecated.
----
Mocha test that verifies that the bch-api server is enforcing its
full-node access rules
To Run Test:
- Update the restURL for bch-api you want to test against.
- Update the JWT_TOKEN value with a current full-node-level JWT token.
- Update the JWT_TOKEN value with a paid tier JWT token.
*/
const assert = require("chai").assert
const JWT_TOKEN =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYmY4MjA1YTYwODliMjliYTlhZjc1OSIsImlhdCI6MTU3MjgzMTgzOSwiZXhwIjoxNTc1NDIzODM5fQ.sFFS4AF04U2aUwmKkBIfnMQIUoygzV9UMVzzQuwctpY"
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M"
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({
restURL: `https://api.bchjs.cash/v3/`,
// restURL: `http://localhost:3000/v3/`,
// restURL: `https://bchn.fullstack.cash/v4/`,
restURL: `https:/abc.fullstack.cash/v4/`,
// restURL: `http://localhost:3000/v4/`,
apiToken: JWT_TOKEN
})
describe("#full node rate limits", () => {
it("should allow an free call to an indexer", async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
const result = await bchjs.Blockbook.balance(addr)
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "balance")
}).timeout(5000)
it("should throw error when rate limit exceeded 3 RPM for indexer endpoints", async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
// CT 11/8/20: New rate limits make this test invalid.
// it("should throw error when rate limit exceeded 20 RPM for indexer endpoints", async () => {
// const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
//
// try {
// for (let i = 0; i < 22; i++) await bchjs.Electrumx.balance(addr)
//
// assert.fail("unexpected result")
// } catch (err) {
// // console.log(`err: `, err)
// assert.include(err.error, "Too many requests")
// }
// }).timeout(10000)
try {
for (let i = 0; i < 5; i++) await bchjs.Blockbook.balance(addr)
assert.equal(true, false, "unexpected result")
} catch (err) {
// console.log(`err: `, err)
assert.include(err.error, "Too many requests")
}
}).timeout(10000)
it("should allow more than 10 RPM to full node", async () => {
for (let i = 0; i < 20; i++) {
it("should allow more than 20 RPM to full node", async () => {
for (let i = 0; i < 22; i++) {
const result = await bchjs.Control.getNetworkInfo()
if (i === 5) {
@@ -55,10 +61,11 @@ describe("#full node rate limits", () => {
assert.property(result, "version", "more than 10 calls allowed")
}
}
}).timeout(10000)
}).timeout(20000)
it("should throw error for more than 100 RPM to fullnode", async () => {
try {
console.log(`This test usually doesn't pass, because of latency.`)
for (let i = 0; i < 100; i++) await bchjs.Control.getNetworkInfo()
} catch (err) {
// console.log(`validating after 10th call`)
@@ -66,5 +73,5 @@ describe("#full node rate limits", () => {
assert.include(err.error, "Too many requests")
assert.include(err.error, 100)
}
}).timeout(30000)
}).timeout(45000)
})
+12 -11
View File
@@ -10,18 +10,19 @@
const assert = require("chai").assert
const JWT_TOKEN =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTU5MDQzMjIxNywiZXhwIjoxNTkzMDI0MjE3fQ.R0Euhutd5FHCxLlSzjq1TYsGjI6iua_AguWIeLK2xCU"
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M"
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({
restURL: `https://api.fullstack.cash/v3/`,
// restURL: `http://localhost:3000/v3/`,
// restURL: `https://bchn.fullstack.cash/v4/`,
restURL: `https://abc.fullstack.cash/v4/`,
// restURL: `http://localhost:3000/v4/`,
apiToken: JWT_TOKEN
})
describe("#full node rate limits", () => {
it("should allow more than 10 RPM to full node", async () => {
for (let i = 0; i < 20; i++) {
describe("#Indexer rate limits", () => {
it("should allow more than 20 RPM to full node", async () => {
for (let i = 0; i < 22; i++) {
const result = await bchjs.Control.getNetworkInfo()
if (i === 5) {
@@ -34,13 +35,13 @@ describe("#full node rate limits", () => {
assert.property(result, "version", "more than 10 calls allowed")
}
}
}).timeout(30000)
}).timeout(45000)
it("should allow more than 10 RPM to an indexer", async () => {
it("should allow more than 20 RPM to an indexer", async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
for (let i = 0; i < 20; i++) {
const result = await bchjs.Blockbook.balance(addr)
for (let i = 0; i < 22; i++) {
const result = await bchjs.Electrumx.balance(addr)
if (i === 5) {
// console.log(`validating 5th call: ${i}`)
@@ -52,5 +53,5 @@ describe("#full node rate limits", () => {
assert.property(result, "balance", "more than 10 calls allowed")
}
}
}).timeout(30000)
}).timeout(45000)
})
-170
View File
@@ -1,170 +0,0 @@
/*
Integration tests for the Blockbook library.
*/
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
//const axios = require("axios")
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe(`#Blockbook`, () => {
describe(`#Balance`, () => {
it(`should GET balance for a single address`, async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
const result = await bchjs.Blockbook.balance(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
"page",
"totalPages",
"itemsOnPage",
"address",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxs",
"txs",
"txids"
])
assert.isArray(result.txids)
})
it(`should POST request balances for an array of addresses`, async () => {
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
]
const result = await bchjs.Blockbook.balance(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"page",
"totalPages",
"itemsOnPage",
"address",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxs",
"txs",
"txids"
])
assert.isArray(result[0].txids)
})
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.Blockbook.balance(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
const result = await bchjs.Blockbook.balance(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
const addr = "bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7"
const result = await bchjs.Blockbook.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
it(`should POST utxo details for an array of addresses`, async () => {
const addr = [
"bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7",
"bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr"
]
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isArray(result[0])
assert.hasAnyKeys(result[0][0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.Blockbook.utxo(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr")
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
})
+8 -56
View File
@@ -21,6 +21,10 @@ util.inspect.defaultOptions = {
}
describe(`#blockchain`, () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe(`#getBestBlockHash`, () => {
it(`should GET best block hash`, async () => {
const result = await bchjs.Blockchain.getBestBlockHash()
@@ -85,20 +89,6 @@ describe(`#blockchain`, () => {
])
})
it(`should throw an error for improper input`, async () => {
try {
const hash = 12345
await bchjs.Blockchain.getBlockHeader(hash)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input hash must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const data = []
@@ -185,20 +175,6 @@ describe(`#blockchain`, () => {
assert.include(err.error, `Transaction not in mempool`)
}
})
it(`should throw an error for improper single input`, async () => {
try {
const txid = 12345
await bchjs.Blockchain.getMempoolEntry(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input must be a string or array of strings`
)
}
})
})
describe(`#getTxOutProof`, () => {
@@ -224,20 +200,6 @@ describe(`#blockchain`, () => {
assert.isArray(result)
assert.isString(result[0])
})
it(`should throw an error for improper single input`, async () => {
try {
const txid = 12345
await bchjs.Blockchain.getTxOutProof(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input must be a string or array of strings`
)
}
})
})
describe(`#verifyTxOutProof`, () => {
@@ -269,20 +231,6 @@ describe(`#blockchain`, () => {
)
})
it(`should throw an error for improper single input`, async () => {
try {
const txid = 12345
await bchjs.Blockchain.verifyTxOutProof(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const data = []
@@ -329,3 +277,7 @@ describe(`#blockchain`, () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -0,0 +1,71 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
TODO
*/
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../../../src/bch-js")
const bchjs = new BCHJS()
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe("#rawtransaction", () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
/*
Testing sentRawTransaction isn't really possible with an integration test,
as the endpoint really needs an e2e test to be properly tested. The tests
below expect error messages returned from the server, but at least test
that the server is responding on those endpoints, and responds consistently.
*/
describe("sendRawTransaction", () => {
it("should send a single transaction hex", async () => {
try {
const hex =
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
await bchjs.RawTransactions.sendRawTransaction(hex)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "bad-txns-inputs-missingorspent")
}
})
it("should send an array of tx hexes", async () => {
try {
const hexes = [
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000",
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
]
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "bad-txns-inputs-missingorspent")
}
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+223
View File
@@ -0,0 +1,223 @@
/*
Integration tests for the bchjs covering SLP tokens.
These tests are specific to the ABC chain.
*/
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../../../src/bch-js")
let bchjs
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 1
}
describe(`#SLP`, () => {
// before(() => {
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
// })
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
bchjs = new BCHJS()
})
describe("#util", () => {
describe("#tokenUtxoDetails", () => {
it("should handle a range of UTXO types", async () => {
const utxos = [
// Malformed SLP tx
{
note: "Malformed SLP tx",
tx_hash:
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
tx_pos: 1,
value: 546
},
// Normal TX (non-SLP)
{
note: "Normal TX (non-SLP)",
tx_hash:
"01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0",
tx_pos: 0,
value: 400000
},
// Valid PSF SLP tx
{
note: "Valid PSF SLP tx",
tx_hash:
"daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd",
tx_pos: 1,
value: 546
},
// Valid SLP token not in whitelist
{
note: "Valid SLP token not in whitelist",
tx_hash:
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488",
tx_pos: 1,
value: 546
},
// Token send on BCHN network.
{
note: "Token send on BCHN network",
tx_hash:
"402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019",
tx_pos: 1,
value: 546
},
// Token send on ABC network.
{
note: "Token send on ABC network",
tx_hash:
"336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d",
tx_pos: 1,
value: 546
},
// Known invalid SLP token send of PSF tokens.
{
note: "Known invalid SLP token send of PSF tokens",
tx_hash:
"2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74",
tx_pos: 1,
value: 546
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
// Malformed SLP tx
assert.equal(data[0].tx_hash, utxos[0].tx_hash)
assert.equal(data[0].isValid, false)
// Normal TX (non-SLP)
assert.equal(data[1].tx_hash, utxos[1].tx_hash)
assert.equal(data[1].isValid, false)
// Valid PSF SLP tx
assert.equal(data[2].tx_hash, utxos[2].tx_hash)
assert.equal(data[2].isValid, true)
// Valid SLP token not in whitelist
assert.equal(data[3].tx_hash, utxos[3].tx_hash)
assert.equal(data[3].isValid, true)
// Token send on BCHN network
assert.equal(data[4].tx_hash, utxos[4].tx_hash)
assert.equal(data[4].isValid, null)
// Token send on ABC network
assert.equal(data[5].tx_hash, utxos[5].tx_hash)
assert.equal(data[5].isValid, true)
// Known invalid SLP token send of PSF tokens
assert.equal(data[6].tx_hash, utxos[6].tx_hash)
assert.equal(data[6].isValid, false)
})
})
describe("#validateTxid3", () => {
it("should invalidate a known invalid TXID", async () => {
const txid =
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a"
const result = await bchjs.SLP.Utils.validateTxid3(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "txid")
assert.equal(result[0].txid, txid)
assert.property(result[0], "valid")
assert.equal(result[0].valid, null)
})
it("should validate a known valid TXID", async () => {
const txid =
"daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd"
const result = await bchjs.SLP.Utils.validateTxid3(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "txid")
assert.equal(result[0].txid, txid)
assert.property(result[0], "valid")
assert.equal(result[0].valid, true)
})
it("should handle a mix of valid, invalid, and non-SLP txs", async () => {
const txids = [
// Malformed SLP tx
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
// Normal TX (non-SLP)
"01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0",
// Valid PSF SLP tx
"daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd",
// Valid SLP token not in whitelist
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488",
// Unprocessed SLP TX
// "a0d6406eecfd8634158efa9314ff15b4cbf451938e9dc7b5678c46b41eabc6ed" // Mint baton
"402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019"
]
const result = await bchjs.SLP.Utils.validateTxid3(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].valid, null)
assert.equal(result[1].valid, null)
assert.equal(result[2].valid, true)
assert.equal(result[3].valid, true)
assert.equal(result[4].valid, null)
})
})
describe("#validateTxid", () => {
it("should handle a mix of valid, invalid, and non-SLP txs", async () => {
const txids = [
// Malformed SLP tx
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
// Normal TX (non-SLP)
"01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0",
// Valid PSF SLP tx
"daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd",
// Valid SLP token not in whitelist
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488",
// Token send on BCHN network.
"402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019",
// Token send on ABC network.
"336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d"
]
const result = await bchjs.SLP.Utils.validateTxid(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].valid, null)
assert.equal(result[1].valid, null)
assert.equal(result[2].valid, true)
assert.equal(result[3].valid, true)
assert.equal(result[4].valid, null)
assert.equal(result[5].valid, true)
})
})
})
})
// Promise-based sleep function
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -0,0 +1,71 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
TODO
*/
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../../../src/bch-js")
const bchjs = new BCHJS()
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe("#rawtransaction", () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
/*
Testing sentRawTransaction isn't really possible with an integration test,
as the endpoint really needs an e2e test to be properly tested. The tests
below expect error messages returned from the server, but at least test
that the server is responding on those endpoints, and responds consistently.
*/
describe("sendRawTransaction", () => {
it("should send a single transaction hex", async () => {
try {
const hex =
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
await bchjs.RawTransactions.sendRawTransaction(hex)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "Missing inputs")
}
})
it("should send an array of tx hexes", async () => {
try {
const hexes = [
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000",
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
]
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "Missing inputs")
}
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+247
View File
@@ -0,0 +1,247 @@
/*
Integration tests for the bchjs covering SLP tokens.
These tests are specific to the ABC chain.
*/
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../../../src/bch-js")
let bchjs
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 1
}
describe(`#SLP`, () => {
// before(() => {
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
// })
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
bchjs = new BCHJS()
})
describe("#util", () => {
describe("#tokenUtxoDetails", () => {
it("should handle a range of UTXO types", async () => {
const utxos = [
// Malformed SLP tx
{
note: "Malformed SLP tx",
tx_hash:
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
tx_pos: 1,
value: 546
},
// Normal TX (non-SLP)
{
note: "Normal TX (non-SLP)",
tx_hash:
"01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0",
tx_pos: 0,
value: 400000
},
// Valid PSF SLP tx
{
note: "Valid PSF SLP tx",
tx_hash:
"daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd",
tx_pos: 1,
value: 546
},
// Valid SLP token not in whitelist
{
note: "Valid SLP token not in whitelist",
tx_hash:
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488",
tx_pos: 1,
value: 546
},
// Token send on BCHN network.
{
note: "Token send on BCHN network",
tx_hash:
"402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019",
tx_pos: 1,
value: 546
},
// Token send on ABC network.
{
note: "Token send on ABC network",
tx_hash:
"336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d",
tx_pos: 1,
value: 546
},
// Known invalid SLP token send of PSF tokens.
{
note: "Known invalid SLP token send of PSF tokens",
tx_hash:
"2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74",
tx_pos: 1,
value: 546
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
// Malformed SLP tx
assert.equal(data[0].tx_hash, utxos[0].tx_hash)
assert.equal(data[0].isValid, false)
// Normal TX (non-SLP)
assert.equal(data[1].tx_hash, utxos[1].tx_hash)
assert.equal(data[1].isValid, false)
// Valid PSF SLP tx
assert.equal(data[2].tx_hash, utxos[2].tx_hash)
assert.equal(data[2].isValid, true)
// Valid SLP token not in whitelist
assert.equal(data[3].tx_hash, utxos[3].tx_hash)
assert.equal(data[3].isValid, true)
// Token send on BCHN network
assert.equal(data[4].tx_hash, utxos[4].tx_hash)
assert.equal(data[4].isValid, true)
// Token send on ABC network
assert.equal(data[5].tx_hash, utxos[5].tx_hash)
assert.equal(data[5].isValid, null)
// Known invalid SLP token send of PSF tokens
assert.equal(data[6].tx_hash, utxos[6].tx_hash)
assert.equal(data[6].isValid, false)
})
})
describe("#validateTxid3", () => {
it("should invalidate a known invalid TXID", async () => {
const txid =
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a"
const result = await bchjs.SLP.Utils.validateTxid3(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "txid")
assert.equal(result[0].txid, txid)
assert.property(result[0], "valid")
assert.equal(result[0].valid, null)
})
it("should validate a known valid TXID", async () => {
const txid =
"daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd"
const result = await bchjs.SLP.Utils.validateTxid3(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "txid")
assert.equal(result[0].txid, txid)
assert.property(result[0], "valid")
assert.equal(result[0].valid, true)
})
it("should handle a mix of valid, invalid, and non-SLP txs", async () => {
const txids = [
// Malformed SLP tx
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
// Normal TX (non-SLP)
"01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0",
// Valid PSF SLP tx
"daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd",
// Valid SLP token not in whitelist
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488",
// Unprocessed SLP TX
"402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019"
]
const result = await bchjs.SLP.Utils.validateTxid3(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].txid, txids[0])
assert.equal(result[0].valid, null)
assert.equal(result[1].txid, txids[1])
assert.equal(result[1].valid, null)
assert.equal(result[2].txid, txids[2])
assert.equal(result[2].valid, true)
// True in validateTxid() but null in validateTxid3()
assert.equal(result[3].txid, txids[3])
assert.equal(result[3].valid, null)
// Note: This should change from null to true once SLPDB finishes indexing.
assert.equal(result[4].txid, txids[4])
assert.equal(result[4].valid, null)
})
})
describe("#validateTxid", () => {
it("should handle a mix of valid, invalid, and non-SLP txs", async () => {
const txids = [
// Malformed SLP tx
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
// Normal TX (non-SLP)
"01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0",
// Valid PSF SLP tx
"daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd",
// Valid SLP token not in whitelist
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488",
// Token send on BCHN network.
"402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019",
// Token send on ABC network.
"336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d"
]
const result = await bchjs.SLP.Utils.validateTxid(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].txid, txids[0])
assert.equal(result[0].valid, null)
assert.equal(result[1].txid, txids[1])
assert.equal(result[1].valid, null)
assert.equal(result[2].txid, txids[2])
assert.equal(result[2].valid, true)
// True in validateTxid() but null in validateTxid3()
assert.equal(result[3].txid, txids[3])
assert.equal(result[3].valid, true)
assert.equal(result[4].txid, txids[4])
assert.equal(result[4].valid, true)
assert.equal(result[5].txid, txids[5])
assert.equal(result[5].valid, null)
})
})
})
})
// Promise-based sleep function
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -12,11 +12,11 @@ const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
: "https://testnet3.fullstack.cash/v4/"
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
const BCHJS = require("../../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// Inspect utility used for debugging.
@@ -27,11 +27,15 @@ util.inspect.defaultOptions = {
depth: 3
}
describe(`#blockchain`, () => {
describe(`#getBestBlockHash`, () => {
it(`should GET best block hash`, async () => {
describe("#blockchain", () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe("#getBestBlockHash", () => {
it("should GET best block hash", async () => {
const result = await bchjs.Blockchain.getBestBlockHash()
//console.log(`result: ${util.inspect(result)}`)
// console.log(`result: ${util.inspect(result)}`)
assert.isString(result)
assert.equal(result.length, 64, "Specific hash length")
@@ -39,7 +43,7 @@ describe(`#blockchain`, () => {
})
describe("#getBlockHeader", () => {
it(`should GET block header for a single hash`, async () => {
it("should GET block header for a single hash", async () => {
const hash =
"000000000000c57178ace90210289e6b5383134c5b5306e1cdd8395176e10aaf"
@@ -64,7 +68,7 @@ describe(`#blockchain`, () => {
])
})
it(`should GET block headers for an array of hashes`, async () => {
it("should GET block headers for an array of hashes", async () => {
const hash = [
"000000000000c57178ace90210289e6b5383134c5b5306e1cdd8395176e10aaf",
"00000000000b7db4cbae48d852fcbef32f728014582094ad613fe12af6600ff2"
@@ -92,21 +96,7 @@ describe(`#blockchain`, () => {
])
})
it(`should throw an error for improper input`, async () => {
try {
const hash = 12345
await bchjs.Blockchain.getBlockHeader(hash)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input hash must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
it("should throw error on array size rate limit", async () => {
try {
const data = []
for (let i = 0; i < 25; i++) {
@@ -115,7 +105,7 @@ describe(`#blockchain`, () => {
)
}
const result = await bchjs.Blockchain.getBlockHeader(data)
await bchjs.Blockchain.getBlockHeader(data)
// console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
@@ -178,7 +168,7 @@ describe(`#blockchain`, () => {
})
*/
it(`should throw an error if txid is not in mempool`, async () => {
it("should throw an error if txid is not in mempool", async () => {
try {
const txid =
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
@@ -187,39 +177,25 @@ describe(`#blockchain`, () => {
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: ${util.inspect(err)}`)
// console.log(`err: ${util.inspect(err)}`)
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, `Transaction not in mempool`)
}
})
it(`should throw an error for improper single input`, async () => {
try {
const txid = 12345
await bchjs.Blockchain.getMempoolEntry(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input must be a string or array of strings`
)
assert.include(err.error, "Transaction not in mempool")
}
})
})
describe(`#getTxOutProof`, () => {
it(`should get single tx out proof`, async () => {
describe("#getTxOutProof", () => {
it("should get single tx out proof", async () => {
const txid =
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
const result = await bchjs.Blockchain.getTxOutProof(txid)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isString(result)
})
it(`should get an array of tx out proofs`, async () => {
it("should get an array of tx out proofs", async () => {
const txid = [
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04",
"fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752"
@@ -231,27 +207,13 @@ describe(`#blockchain`, () => {
assert.isArray(result)
assert.isString(result[0])
})
it(`should throw an error for improper single input`, async () => {
try {
const txid = 12345
await bchjs.Blockchain.getTxOutProof(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input must be a string or array of strings`
)
}
})
})
describe(`#verifyTxOutProof`, () => {
describe("#verifyTxOutProof", () => {
const mockTxOutProof =
"00000020ac86ce8f2bda235c0dc135d18f6a777c44b121e8f41db8a51ca65000000000000cd4de3c49337712f3a1092c47c3bf73ec2f9b1cfd289ee991ede0b6eab4df229d5b8c5dffff001d82ce005b0700000003ec55d9142eac2c1d2229e5af24898b2590c111b62e2787fa1998d3d713fd432fd557124ed758fa156a6cdc6d317d5575aec2b86dfb159c62ecb4743f28bef1cb52e7a32fbec31e367ec152fdb952f75ee75bd8575f97b394093dbb0e6c694ffc0135"
it(`should verify a single proof`, async () => {
it("should verify a single proof", async () => {
const result = await bchjs.Blockchain.verifyTxOutProof(mockTxOutProof)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
@@ -263,10 +225,10 @@ describe(`#blockchain`, () => {
)
})
it(`should verify an array of proofs`, async () => {
it("should verify an array of proofs", async () => {
const proofs = [mockTxOutProof, mockTxOutProof]
const result = await bchjs.Blockchain.verifyTxOutProof(proofs)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
@@ -276,21 +238,7 @@ describe(`#blockchain`, () => {
)
})
it(`should throw an error for improper single input`, async () => {
try {
const txid = 12345
await bchjs.Blockchain.verifyTxOutProof(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
`Input must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
it("should throw error on array size rate limit", async () => {
try {
const data = []
for (let i = 0; i < 25; i++) data.push(mockTxOutProof)
@@ -306,3 +254,7 @@ describe(`#blockchain`, () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -7,12 +7,16 @@ const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
: `https://testnet3.fullstack.cash/v4/`
const BCHJS = require("../../../src/bch-js")
const BCHJS = require("../../../../src/bch-js")
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
describe(`#control`, () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe(`#getNetworkInfo`, () => {
it("should get info on the full node", async () => {
const result = await bchjs.Control.getNetworkInfo()
@@ -22,3 +26,7 @@ describe(`#control`, () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -4,14 +4,20 @@ const sinon = require("sinon")
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
: `https://testnet3.fullstack.cash/v4/`
const BCHJS = require("../../../src/bch-js")
const BCHJS = require("../../../../src/bch-js")
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
describe(`#ElectrumX`, () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
beforeEach(async () => {
sandbox = sinon.createSandbox()
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
afterEach(() => sandbox.restore())
describe(`#utxo`, () => {
@@ -275,7 +281,8 @@ describe(`#ElectrumX`, () => {
describe(`#txData`, () => {
it(`should GET details for a single transaction`, async () => {
const txid = "76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee"
const txid =
"76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee"
const result = await bchjs.Electrumx.txData(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
@@ -322,8 +329,11 @@ describe(`#ElectrumX`, () => {
it(`should throw error on array size rate limit`, async () => {
try {
const txids = []
for (let i = 0; i < 25; i++)
txids.push("76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee")
for (let i = 0; i < 25; i++) {
txids.push(
"76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee"
)
}
await bchjs.Electrumx.txData(txids)
@@ -338,15 +348,23 @@ describe(`#ElectrumX`, () => {
describe(`#broadcast`, () => {
it(`should broadcast a single transaction`, async () => {
const txHex = "020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000"
const txHex =
"020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000"
try {
await bchjs.Electrumx.broadcast(txHex)
} catch (err) {
assert.property(err, "success")
assert.equal(err.success, false)
assert.include(err.error, "Missing inputs")
assert.include(
err.error,
"the transaction was rejected by network rules"
)
}
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+147
View File
@@ -0,0 +1,147 @@
const chai = require("chai")
const assert = chai.assert
const sinon = require("sinon")
const BCHJS = require("../../../../src/bch-js")
const bchjs = new BCHJS({ ninsightURL: "https://trest.bitcoin.com/v2" })
describe(`#Ninsight`, () => {
let sandbox
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
const addr = "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr"
const result = await bchjs.Ninsight.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result[0], "utxos")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "cashAddress")
assert.property(result[0], "slpAddress")
assert.property(result[0], "scriptPubKey")
assert.property(result[0], "asm")
assert.isArray(result[0].utxos)
assert.property(result[0].utxos[0], "txid")
assert.property(result[0].utxos[0], "vout")
assert.property(result[0].utxos[0], "amount")
assert.property(result[0].utxos[0], "satoshis")
assert.property(result[0].utxos[0], "height")
assert.property(result[0].utxos[0], "confirmations")
})
it(`should POST utxo details for an array of addresses`, async () => {
const addr = [
"bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
"bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"
]
const result = await bchjs.Ninsight.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isArray(result[0].utxos)
assert.property(result[0], "utxos")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "cashAddress")
assert.property(result[0], "slpAddress")
assert.property(result[0], "scriptPubKey")
assert.property(result[0], "asm")
// assert.hasAnyKeys(result[0][0], [
// "txid",
// "vout",
// "value",
// "height",
// "confirmations"
// ])
})
})
describe(`#transactions`, () => {
it(`should POST transactions history for a single address`, async () => {
const addr = "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr"
const result = await bchjs.Ninsight.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "cashAddress")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "txs")
assert.isArray(result[0].txs)
assert.property(result[0].txs[0], "txid")
assert.property(result[0].txs[0], "vin")
assert.property(result[0].txs[0], "vout")
})
it(`should POST transactions history for an array of addresses`, async () => {
const addr = [
"bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
"bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"
]
const result = await bchjs.Ninsight.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "cashAddress")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "txs")
assert.isArray(result[0].txs)
assert.property(result[0].txs[0], "txid")
assert.property(result[0].txs[0], "vin")
assert.property(result[0].txs[0], "vout")
})
})
describe(`#txDetails`, () => {
it(`should POST transactions details for a single address`, async () => {
const txid =
"76856d82e00b2696acd8d989e1fa6c46b431005046a285ce905814cac0ff8fea"
const result = await bchjs.Ninsight.txDetails(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "txid")
assert.property(result[0], "version")
assert.property(result[0], "locktime")
assert.property(result[0], "vin")
assert.property(result[0], "vout")
assert.property(result[0], "blockhash")
assert.property(result[0], "blockheight")
assert.property(result[0], "confirmations")
assert.property(result[0], "time")
assert.property(result[0], "blocktime")
assert.property(result[0], "valueOut")
assert.property(result[0], "size")
})
it(`should POST transactions details for an array of addresses`, async () => {
const txid = [
"f191d1062789d7071da6f2168ba306869a829294f6b1c09d03492db4ca3a8e77",
"76856d82e00b2696acd8d989e1fa6c46b431005046a285ce905814cac0ff8fea"
]
const result = await bchjs.Ninsight.txDetails(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "txid")
assert.property(result[0], "vin")
assert.property(result[0], "vout")
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -10,11 +10,11 @@ const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
: `https://testnet3.fullstack.cash/v4/`
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
const BCHJS = require("../../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// Inspect utility used for debugging.
@@ -26,6 +26,10 @@ util.inspect.defaultOptions = {
}
describe("#rawtransaction", () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe("#decodeRawTransaction", () => {
it("should decode tx for a single hex", async () => {
const hex =
@@ -70,21 +74,6 @@ describe("#rawtransaction", () => {
assert.isArray(result[0].vout)
})
it(`should throw an error for improper single input`, async () => {
try {
const addr = 12345
await bchjs.RawTransactions.decodeRawTransaction(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input must be a string or array of strings.`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const data = []
@@ -239,22 +228,6 @@ describe("#rawtransaction", () => {
const result = await bchjs.RawTransactions.decodeScript(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
})
*/
/*
it(`should throw an error for improper single input`, async () => {
try {
const addr = 12345
await bchjs.RawTransactions.decodeRawTransaction(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input must be a string or array of strings.`
)
}
})
*/
})
@@ -299,21 +272,6 @@ describe("#rawtransaction", () => {
}
})
it(`should throw an error for improper single input`, async () => {
try {
const addr = 12345
await bchjs.RawTransactions.sendRawTransaction(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input hex must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const dataMock =
@@ -332,3 +290,7 @@ describe("#rawtransaction", () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -7,11 +7,11 @@ const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
: `https://testnet3.fullstack.cash/v4/`
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
const BCHJS = require("../../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// Inspect utility used for debugging.
@@ -25,7 +25,7 @@ util.inspect.defaultOptions = {
describe(`#SLP`, () => {
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
await sleep(1000)
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe("#util", () => {
@@ -73,22 +73,6 @@ describe(`#SLP`, () => {
})
describe("#balancesForAddress", () => {
it(`should throw an error if input is not a string or array of strings`, async () => {
try {
const address = 1234
await bchjs.SLP.Utils.balancesForAddress(address)
assert.equal(true, false, "Uh oh. Code path should not end here.")
} catch (err) {
//console.log(`Error: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
it(`should fetch all balances for address: slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9`, async () => {
// Mock the call to rest.bitcoin.com
if (process.env.TEST === "unit") {
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
export RESTURL=https://free-test.fullstack.cash/v4/
export NETWORK=testnet
export IS_USING_FREE_TIER=true
cd test/integration/testnet/
mocha --timeout 30000 blockchain.js control.js electrumx.js rawtransaction.js slp.js util.js
#mocha --timeout 30000 blockchain.js
@@ -8,11 +8,11 @@ const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
: `https://testnet3.fullstack.cash/v4/`
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
const BCHJS = require("../../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// Inspect utility used for debugging.
@@ -24,6 +24,10 @@ util.inspect.defaultOptions = {
}
describe(`#util`, () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe(`#validateAddress`, () => {
it(`should return false for testnet addr on mainnet`, async () => {
const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peu`
@@ -82,21 +86,6 @@ describe(`#util`, () => {
])
})
it(`should throw an error for improper single input`, async () => {
try {
const address = 15432
await bchjs.Util.validateAddress(address)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input must be a string or array of strings.`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const dataMock = `bchtest:pq6k9969f6v6sg7a75jkru4n7wn9sknv5cztcp0dnh`
@@ -114,3 +103,7 @@ describe(`#util`, () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+8
View File
@@ -8,6 +8,10 @@ const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
describe(`#control`, () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe(`#getNetworkInfo`, () => {
it("should get info on the full node", async () => {
const result = await bchjs.Control.getNetworkInfo()
@@ -17,3 +21,7 @@ describe(`#control`, () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+15 -2
View File
@@ -7,7 +7,13 @@ const bchjs = new BCHJS()
describe(`#ElectrumX`, () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
beforeEach(async () => {
sandbox = sinon.createSandbox()
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
afterEach(() => sandbox.restore())
describe(`#utxo`, () => {
@@ -346,8 +352,15 @@ describe(`#ElectrumX`, () => {
} catch (err) {
assert.property(err, "success")
assert.equal(err.success, false)
assert.include(err.error, "Missing inputs")
assert.include(
err.error,
"the transaction was rejected by network rules"
)
}
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+8
View File
@@ -4,6 +4,10 @@ const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
describe("#Encryption", () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe("#getPubKey", () => {
it("should get a public key", async () => {
const addr = "bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq"
@@ -29,3 +33,7 @@ describe("#Encryption", () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -0,0 +1,71 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
TODO
*/
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../../../src/bch-js")
const bchjs = new BCHJS()
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe("#rawtransaction", () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
/*
Testing sentRawTransaction isn't really possible with an integration test,
as the endpoint really needs an e2e test to be properly tested. The tests
below expect error messages returned from the server, but at least test
that the server is responding on those endpoints, and responds consistently.
*/
describe("sendRawTransaction", () => {
it("should send a single transaction hex", async () => {
try {
const hex =
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
await bchjs.RawTransactions.sendRawTransaction(hex)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "Missing inputs")
}
})
it("should send an array of tx hexes", async () => {
try {
const hexes = [
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000",
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
]
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "Missing inputs")
}
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -0,0 +1,246 @@
/*
Integration tests for the bchjs covering SLP tokens.
These tests are specific to the ABC chain.
*/
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../../../src/bch-js")
let bchjs
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 1
}
describe(`#SLP`, () => {
// before(() => {
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
// })
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
bchjs = new BCHJS()
})
describe("#util", () => {
describe("#tokenUtxoDetails", () => {
it("should handle a range of UTXO types", async () => {
const utxos = [
// Malformed SLP tx
{
note: "Malformed SLP tx",
tx_hash:
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
tx_pos: 1,
value: 546
},
// Normal TX (non-SLP)
{
note: "Normal TX (non-SLP)",
tx_hash:
"01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0",
tx_pos: 0,
value: 400000
},
// Valid PSF SLP tx
{
note: "Valid PSF SLP tx",
tx_hash:
"daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd",
tx_pos: 1,
value: 546
},
// Valid SLP token not in whitelist
{
note: "Valid SLP token not in whitelist",
tx_hash:
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488",
tx_pos: 1,
value: 546
},
// Token send on BCHN network.
{
note: "Token send on BCHN network",
tx_hash:
"402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019",
tx_pos: 1,
value: 546
},
// Token send on ABC network.
{
note: "Token send on ABC network",
tx_hash:
"336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d",
tx_pos: 1,
value: 546
},
// Known invalid SLP token send of PSF tokens.
{
note: "Known invalid SLP token send of PSF tokens",
tx_hash:
"2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74",
tx_pos: 1,
value: 546
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
// Malformed SLP tx
assert.equal(data[0].tx_hash, utxos[0].tx_hash)
assert.equal(data[0].isValid, false)
// Normal TX (non-SLP)
assert.equal(data[1].tx_hash, utxos[1].tx_hash)
assert.equal(data[1].isValid, false)
// Valid PSF SLP tx
assert.equal(data[2].tx_hash, utxos[2].tx_hash)
assert.equal(data[2].isValid, true)
// Valid SLP token not in whitelist
assert.equal(data[3].tx_hash, utxos[3].tx_hash)
assert.equal(data[3].isValid, true)
// Token send on BCHN network
assert.equal(data[4].tx_hash, utxos[4].tx_hash)
assert.equal(data[4].isValid, true)
// Token send on ABC network
assert.equal(data[5].tx_hash, utxos[5].tx_hash)
assert.equal(data[5].isValid, null)
// Known invalid SLP token send of PSF tokens
assert.equal(data[6].tx_hash, utxos[6].tx_hash)
assert.equal(data[6].isValid, false)
})
})
describe("#validateTxid3", () => {
it("should invalidate a known invalid TXID", async () => {
const txid =
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a"
const result = await bchjs.SLP.Utils.validateTxid3(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "txid")
assert.equal(result[0].txid, txid)
assert.property(result[0], "valid")
assert.equal(result[0].valid, null)
})
it("should validate a known valid TXID", async () => {
const txid =
"daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd"
const result = await bchjs.SLP.Utils.validateTxid3(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "txid")
assert.equal(result[0].txid, txid)
assert.property(result[0], "valid")
assert.equal(result[0].valid, true)
})
it("should handle a mix of valid, invalid, and non-SLP txs", async () => {
const txids = [
// Malformed SLP tx
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
// Normal TX (non-SLP)
"01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0",
// Valid PSF SLP tx
"daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd",
// Valid SLP token not in whitelist
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488",
// Unprocessed SLP TX
"402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019"
]
const result = await bchjs.SLP.Utils.validateTxid3(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].txid, txids[0])
assert.equal(result[0].valid, null)
assert.equal(result[1].txid, txids[1])
assert.equal(result[1].valid, null)
assert.equal(result[2].txid, txids[2])
assert.equal(result[2].valid, true)
// True in validateTxid()
assert.equal(result[3].txid, txids[3])
assert.equal(result[3].valid, true)
assert.equal(result[4].txid, txids[4])
assert.equal(result[4].valid, true)
})
})
describe("#validateTxid", () => {
it("should handle a mix of valid, invalid, and non-SLP txs", async () => {
const txids = [
// Malformed SLP tx
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
// Normal TX (non-SLP)
"01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0",
// Valid PSF SLP tx
"daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd",
// Valid SLP token not in whitelist
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488",
// Token send on BCHN network.
"402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019",
// Token send on ABC network.
"336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d"
]
const result = await bchjs.SLP.Utils.validateTxid(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].txid, txids[0])
assert.equal(result[0].valid, null)
assert.equal(result[1].txid, txids[1])
assert.equal(result[1].valid, null)
assert.equal(result[2].txid, txids[2])
assert.equal(result[2].valid, true)
// True in validateTxid() but null in validateTxid3()
assert.equal(result[3].txid, txids[3])
assert.equal(result[3].valid, true)
assert.equal(result[4].txid, txids[4])
assert.equal(result[4].valid, true)
assert.equal(result[5].txid, txids[5])
assert.equal(result[5].valid, null)
})
})
})
})
// Promise-based sleep function
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+82 -1
View File
@@ -7,7 +7,13 @@ const bchjs = new BCHJS({ ninsightURL: "https://rest.bitcoin.com/v2" })
describe(`#Ninsight`, () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
beforeEach(async () => {
sandbox = sinon.createSandbox()
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
afterEach(() => sandbox.restore())
describe(`#utxo`, () => {
@@ -54,4 +60,79 @@ describe(`#Ninsight`, () => {
assert.property(result[0], "asm")
})
})
describe(`#transactions`, () => {
it(`should POST transactions history for a single address`, async () => {
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
const result = await bchjs.Ninsight.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "cashAddress")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "txs")
assert.isArray(result[0].txs)
assert.property(result[0].txs[0], "txid")
assert.property(result[0].txs[0], "vin")
assert.property(result[0].txs[0], "vout")
})
it(`should POST transactions history for an array of addresses`, async () => {
const addr = [
"bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7",
"bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr"
]
const result = await bchjs.Ninsight.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "cashAddress")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "txs")
assert.isArray(result[0].txs)
assert.property(result[0].txs[0], "txid")
assert.property(result[0].txs[0], "vin")
assert.property(result[0].txs[0], "vout")
})
})
describe(`#txDetails`, () => {
it(`should POST transactions details for a single address`, async () => {
const txid = "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"
const result = await bchjs.Ninsight.txDetails(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "txid")
assert.property(result[0], "version")
assert.property(result[0], "locktime")
assert.property(result[0], "vin")
assert.property(result[0], "vout")
assert.property(result[0], "blockhash")
assert.property(result[0], "blockheight")
assert.property(result[0], "confirmations")
assert.property(result[0], "time")
assert.property(result[0], "blocktime")
assert.property(result[0], "valueOut")
assert.property(result[0], "size")
})
it(`should POST transactions details for an array of addresses`, async () => {
const txid = [
"fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33",
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
]
const result = await bchjs.Ninsight.txDetails(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "txid")
assert.property(result[0], "vin")
assert.property(result[0], "vout")
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+8 -36
View File
@@ -8,19 +8,11 @@ const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
describe(`#OpenBazaar`, () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe(`#Balance`, () => {
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.OpenBazaar.balance(addr)
// assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(err.message, `Input address must be a string`)
}
})
it(`should GET balance for a single address`, async () => {
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
@@ -45,18 +37,6 @@ describe(`#OpenBazaar`, () => {
})
describe(`#utxo`, () => {
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.OpenBazaar.utxo(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(err.message, `Input address must be a string`)
}
})
it(`should GET utxos for a single address`, async () => {
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
@@ -76,18 +56,6 @@ describe(`#OpenBazaar`, () => {
})
describe(`#tx`, () => {
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.OpenBazaar.tx(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(err.message, `Input txid must be a string`)
}
})
it(`should GET transactions for a single address`, async () => {
const addr =
"2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7"
@@ -115,3 +83,7 @@ describe(`#OpenBazaar`, () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+28 -1
View File
@@ -3,6 +3,10 @@ const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
describe("#price", () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe("#current", () => {
describe("#single currency", () => {
it("should get current price for single currency", async () => {
@@ -17,7 +21,30 @@ describe("#price", () => {
const result = await bchjs.Price.getUsd()
// console.log(result)
assert.isNumber(result.usd)
assert.isNumber(result)
})
})
describe("#getBchaUsd", () => {
it("should get the USD price of BCHA", async () => {
const result = await bchjs.Price.getBchaUsd()
console.log(result)
assert.isNumber(result)
})
})
describe("#rates", () => {
it("should get the price of BCH in several currencies", async () => {
const result = await bchjs.Price.rates()
// console.log(result)
assert.property(result, "USD")
assert.property(result, "CAD")
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+8 -80
View File
@@ -19,6 +19,10 @@ util.inspect.defaultOptions = {
}
describe("#rawtransaction", () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe("#decodeRawTransaction", () => {
it("should decode tx for a single hex", async () => {
const hex =
@@ -63,21 +67,6 @@ describe("#rawtransaction", () => {
assert.isArray(result[0].vout)
})
it(`should throw an error for improper single input`, async () => {
try {
const addr = 12345
await bchjs.RawTransactions.decodeRawTransaction(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input must be a string or array of strings.`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const data = []
@@ -232,22 +221,6 @@ describe("#rawtransaction", () => {
const result = await bchjs.RawTransactions.decodeScript(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
})
*/
/*
it(`should throw an error for improper single input`, async () => {
try {
const addr = 12345
await bchjs.RawTransactions.decodeRawTransaction(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input must be a string or array of strings.`
)
}
})
*/
})
@@ -258,55 +231,6 @@ describe("#rawtransaction", () => {
that the server is responding on those endpoints, and responds consistently.
*/
describe("sendRawTransaction", () => {
it("should send a single transaction hex", async () => {
try {
const hex =
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
await bchjs.RawTransactions.sendRawTransaction(hex)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "Missing inputs")
}
})
it("should send an array of tx hexes", async () => {
try {
const hexes = [
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000",
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
]
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "Missing inputs")
}
})
it(`should throw an error for improper single input`, async () => {
try {
const addr = 12345
await bchjs.RawTransactions.sendRawTransaction(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input hex must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const dataMock =
@@ -325,3 +249,7 @@ describe("#rawtransaction", () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+105 -33
View File
@@ -24,7 +24,7 @@ describe(`#SLP`, () => {
beforeEach(async () => {
// Introduce a delay so that the BVT doesn't trip the rate limits.
await sleep(1000)
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
bchjs = new BCHJS()
})
@@ -463,25 +463,34 @@ describe(`#SLP`, () => {
assert.equal(data[0].isValid, false)
})
it("should handle null SLPDB validations", async () => {
const utxos = [
{
height: 665577,
tx_hash:
"4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419",
tx_pos: 1,
value: 546
},
{
height: 665577,
tx_hash:
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488",
tx_pos: 1,
value: 546
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.isArray(data)
// assert.equal(data[0].isValid, null)
})
})
describe("#balancesForAddress", () => {
it(`should throw an error if input is not a string or array of strings`, async () => {
try {
const address = 1234
await bchjs.SLP.Utils.balancesForAddress(address)
assert.equal(true, false, "Uh oh. Code path should not end here.")
} catch (err) {
//console.log(`Error: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
it(`should fetch all balances for address: simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9`, async () => {
const balances = await bchjs.SLP.Utils.balancesForAddress(
"simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9"
@@ -520,19 +529,6 @@ describe(`#SLP`, () => {
})
describe("#hydrateUtxos", () => {
it("should throw an error if input is not an array", async () => {
try {
const utxos = 1234
await bchjs.SLP.Utils.hydrateUtxos(utxos)
assert.equal(true, false, "Uh oh. Code path should not end here.")
} catch (err) {
// console.log(`Error: `, err)
assert.include(err.message, `Input must be an array.`)
}
})
it("should hydrate UTXOs", async () => {
const utxos = [
{
@@ -599,9 +595,9 @@ describe(`#SLP`, () => {
it("should process data directly from Electrumx", async () => {
const addrs = [
"bitcoincash:qq6mvsm7l92d77zpymmltvaw09p5uzghyuyx7spygg",
"bitcoincash:qpjdrs8qruzh8xvusdfmutjx62awcepnhyperm3g89",
"bitcoincash:qzygn28zpgeemnptkn26xzyuzzfu9l8f9vfvq7kptk"
"bitcoincash:qqnt53cfw990u6y38xgezm0lfa8hknw0wueezcpagp",
"bitcoincash:qrh3qgtax6adegzc7zxm6m4sgrv9wq28yqnfn33ce5",
"bitcoincash:qqcaee5w4ws77n8s2gzy6fwtma6uxd7ctq8553e495"
]
const utxos = await bchjs.Electrumx.utxo(addrs)
@@ -632,6 +628,60 @@ describe(`#SLP`, () => {
console.log("Error: ", err)
}
})
it("should handle null SLPDB validations", async () => {
const utxos = [
{
height: 665577,
tx_hash:
"4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419",
tx_pos: 1,
value: 546
},
{
height: 665577,
tx_hash:
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
tx_pos: 1,
value: 546
}
]
const data = await bchjs.SLP.Utils.hydrateUtxos([{ utxos: utxos }])
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.isArray(data.slpUtxos)
assert.equal(data.slpUtxos[0].isValid, null)
})
})
describe("#validateTxid", () => {
// This test is not necessary.
it("should handle a null response from SLPDB", async () => {
const txid =
"4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419"
const result = await bchjs.SLP.Utils.validateTxid(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].txid, txid)
// assert.equal(result[0].valid, null)
})
it("should handle a null response from SLPDB", async () => {
const txid = [
"4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419",
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488"
]
const result = await bchjs.SLP.Utils.validateTxid(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result[0].txid, txid[0])
// assert.equal(result[0].valid, null)
})
})
describe("#validateTxid2", () => {
@@ -663,6 +713,28 @@ describe(`#SLP`, () => {
assert.equal(result.isValid, true)
})
})
describe("#getWhitelist", () => {
it("should get the whitelist", async () => {
const result = await bchjs.SLP.Utils.getWhitelist()
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "name")
assert.property(result[1], "tokenId")
})
})
describe("#getStatus", () => {
it("should return the current block height of the SLPDB indexer", async () => {
const result = await bchjs.SLP.Utils.getStatus()
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "bchBlockHeight")
assert.property(result, "slpProcessedBlockHeight")
})
})
})
describe("#tokentype1", () => {
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
export RESTURL=https://bchn-free-main.fullstack.cash/v3/
#export RESTURL=http://localhost:3000/v3/
cd test/integration/
mocha --timeout 30000 blockchain.js control.js electrumx.js ninsight.js openbazaar.js price.js rawtransaction.js slp.js util.js
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
export RESTURL=https://free-main.fullstack.cash/v3/
#export RESTURL=http://localhost:3000/v3/
cd test/integration/
mocha --timeout 30000 blockchain.js control.js electrumx.js ninsight.js openbazaar.js price.js rawtransaction.js slp.js util.js
-178
View File
@@ -1,178 +0,0 @@
/*
Integration tests for the Blockbook library.
*/
const chai = require("chai")
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
// const bchjs = new BCHJS({ restURL: RESTURL })
//const axios = require("axios")
// Inspect utility used for debugging.
const util = require("util")
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
depth: 3
}
describe(`#Blockbook`, () => {
describe(`#Balance`, () => {
it(`should GET balance for a single address`, async () => {
const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
const result = await bchjs.Blockbook.balance(addr)
// console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
"page",
"totalPages",
"itemsOnPage",
"address",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxs",
"txs",
"txids"
])
assert.isArray(result.txids)
})
it(`should POST request balances for an array of addresses`, async () => {
const addr = [
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2",
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
]
const result = await bchjs.Blockbook.balance(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"page",
"totalPages",
"itemsOnPage",
"address",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxs",
"txs",
"txids"
])
assert.isArray(result[0].txids)
})
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.Blockbook.balance(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2")
const result = await bchjs.Blockbook.balance(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
const result = await bchjs.Blockbook.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
it(`should POST utxo details for an array of addresses`, async () => {
const addr = [
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2",
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
]
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isArray(result[0])
assert.hasAnyKeys(result[0][0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.Blockbook.utxo(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2")
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
})
})
-65
View File
@@ -1,65 +0,0 @@
const chai = require("chai")
const assert = chai.assert
const sinon = require("sinon")
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({ ninsightURL: "https://trest.bitcoin.com/v2" })
describe(`#Ninsight`, () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
const addr = "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr"
const result = await bchjs.Ninsight.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result[0], "utxos")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "cashAddress")
assert.property(result[0], "slpAddress")
assert.property(result[0], "scriptPubKey")
assert.property(result[0], "asm")
assert.isArray(result[0].utxos)
assert.property(result[0].utxos[0], "txid")
assert.property(result[0].utxos[0], "vout")
assert.property(result[0].utxos[0], "amount")
assert.property(result[0].utxos[0], "satoshis")
assert.property(result[0].utxos[0], "height")
assert.property(result[0].utxos[0], "confirmations")
})
it(`should POST utxo details for an array of addresses`, async () => {
const addr = [
"bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
"bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"
]
const result = await bchjs.Ninsight.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isArray(result[0].utxos)
assert.property(result[0], "utxos")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "cashAddress")
assert.property(result[0], "slpAddress")
assert.property(result[0], "scriptPubKey")
assert.property(result[0], "asm")
// assert.hasAnyKeys(result[0][0], [
// "txid",
// "vout",
// "value",
// "height",
// "confirmations"
// ])
})
})
})
-124
View File
@@ -1,124 +0,0 @@
/*
tests for OpenBazaar library.
*/
// Force testnet call to OB1 servers.
process.env.NETWORK = "testnet"
const chai = require("chai")
const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
describe(`#OpenBazaar`, () => {
describe(`#Balance`, () => {
// it(`should GET balance for a single address`, async () => {
// const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
//
// const result = await bchjs.OpenBazaar.balance(addr)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.hasAllKeys(result, [
// "page",
// "totalPages",
// "itemsOnPage",
// "addrStr",
// "balance",
// "totalReceived",
// "totalSent",
// "unconfirmedBalance",
// "unconfirmedTxApperances",
// "txApperances",
// "transactions"
// ])
// assert.isArray(result.transactions)
// })
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.OpenBazaar.balance(addr)
// assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(err.message, `Input address must be a string`)
}
})
})
describe(`#utxo`, () => {
// it(`should GET utxos for a single address`, async () => {
// const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
//
// const result = await bchjs.OpenBazaar.utxo(addr)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.isArray(result)
// assert.hasAllKeys(result[0], [
// "txid",
// "vout",
// "amount",
// "height",
// "confirmations",
// "satoshis"
// ])
// })
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.OpenBazaar.utxo(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(err.message, `Input address must be a string`)
}
})
})
describe(`#tx`, () => {
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.OpenBazaar.tx(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(err.message, `Input txid must be a string`)
}
})
// it(`should GET transactions for a single address`, async () => {
// const addr =
// "ed4692f50a4553527dd26cd8674ca06a0ab2d366f3135ca3668310467ead3cbf"
//
// const result = await bchjs.OpenBazaar.tx(addr)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.hasAnyKeys(result, [
// "txid",
// "version",
// "vin",
// "vout",
// "blockhash",
// "blockheight",
// "confirmations",
// "blocktime",
// "valueOut",
// "valueIn",
// "fees",
// "hex"
// ])
// assert.isArray(result.vin)
// assert.isArray(result.vout)
// })
})
})
@@ -1,9 +0,0 @@
#!/bin/bash
export RESTURL=https://free-test.fullstack.cash/v3/
export NETWORK=testnet
#export RESTURL=http://localhost:3000/v3/
cd test/integration/testnet/
mocha --timeout 30000 blockchain.js control.js electrumx.js openbazaar.js rawtransaction.js slp.js util.js
#mocha --timeout 30000 blockchain.js
+8 -15
View File
@@ -17,6 +17,10 @@ util.inspect.defaultOptions = {
}
describe(`#util`, () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe(`#validateAddress`, () => {
it(`should return false for testnet addr on mainnet`, async () => {
const address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
@@ -75,21 +79,6 @@ describe(`#util`, () => {
])
})
it(`should throw an error for improper single input`, async () => {
try {
const address = 15432
await bchjs.Util.validateAddress(address)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input must be a string or array of strings.`
)
}
})
it(`should throw error on array size rate limit`, async () => {
try {
const dataMock = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`
@@ -107,3 +96,7 @@ describe(`#util`, () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+781 -751
View File
File diff suppressed because it is too large Load Diff
-25
View File
@@ -1,25 +0,0 @@
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../src/bch-js")
// Used for debugging and iterrogating JS objects.
const util = require("util")
util.inspect.defaultOptions = { depth: 1 }
describe(`#BitboxShim`, () => {
it("should create the shim library", () => {
const BitboxShim = BCHJS.BitboxShim()
const bitbox = new BitboxShim()
//console.log(`bitbox.Address: ${util.inspect(bitbox.Address)}`)
assert.hasAnyKeys(bitbox.Address, [
// "details",
// "utxo",
// "unconfirmed",
// "transactions",
// "toLegacyAddress"
"restURL"
])
})
})
+37 -37
View File
@@ -1,7 +1,13 @@
const fixtures = require("./fixtures/bitcoincash.json")
// Public npm libraries
const assert = require("assert")
// Mocks
const fixtures = require("./fixtures/bitcoincash.json")
// Unit under test (uut)
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
// const bchjs = new BCHJS()
let bchjs
// TODO
// 1. generate testnet p2sh
@@ -20,28 +26,26 @@ const bchjs = new BCHJS()
// 6. More error test cases.
describe("#BitcoinCash", () => {
beforeEach(() => {
bchjs = new BCHJS()
})
describe("price conversion", () => {
describe("#toBitcoinCash", () => {
it("should exercise toBitcoinCash", () => {
fixtures.conversion.toBCH.satoshis.forEach(satoshi => {
it(`should convert ${satoshi[0]} Satoshis to ${
satoshi[1]
} $BCH`, () => {
it(`should convert ${satoshi[0]} Satoshis to ${satoshi[1]} $BCH`, () => {
assert.equal(bchjs.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1])
})
})
fixtures.conversion.toBCH.strings.forEach(satoshi => {
it(`should convert "${satoshi[0]}" Satoshis as a string to ${
satoshi[1]
} $BCH`, () => {
it(`should convert "${satoshi[0]}" Satoshis as a string to ${satoshi[1]} $BCH`, () => {
assert.equal(bchjs.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1])
})
})
fixtures.conversion.toBCH.not.forEach(bch => {
it(`converts ${bch[0]} to Bitcoin Cash, not to ${
bch[1]
} Satoshi`, () => {
it(`converts ${bch[0]} to Bitcoin Cash, not to ${bch[1]} Satoshi`, () => {
assert.notEqual(bchjs.BitcoinCash.toBitcoinCash(bch[0]), bch[1])
})
})
@@ -53,7 +57,7 @@ describe("#BitcoinCash", () => {
})
})
describe("#toSatoshi", () => {
it("should exercise toSatoshi", () => {
fixtures.conversion.toSatoshi.bch.forEach(bch => {
it(`should convert ${bch[0]} $BCH to ${bch[1]} Satoshis`, () => {
assert.equal(bchjs.BitcoinCash.toSatoshi(bch[0]), bch[1])
@@ -61,17 +65,13 @@ describe("#BitcoinCash", () => {
})
fixtures.conversion.toSatoshi.strings.forEach(bch => {
it(`should convert "${bch[0]}" $BCH as a string to ${
bch[1]
} Satoshis`, () => {
it(`should convert "${bch[0]}" $BCH as a string to ${bch[1]} Satoshis`, () => {
assert.equal(bchjs.BitcoinCash.toSatoshi(bch[0]), bch[1])
})
})
fixtures.conversion.toSatoshi.not.forEach(satoshi => {
it(`converts ${satoshi[0]} to Satoshi, not to ${
satoshi[1]
} Bitcoin Cash`, () => {
it(`converts ${satoshi[0]} to Satoshi, not to ${satoshi[1]} Bitcoin Cash`, () => {
assert.notEqual(bchjs.BitcoinCash.toSatoshi(satoshi[0]), satoshi[1])
})
})
@@ -83,7 +83,7 @@ describe("#BitcoinCash", () => {
})
})
describe("#satsToBits", () => {
it("should exercise satsToBits", () => {
fixtures.conversion.satsToBits.bch.forEach(bch => {
it(`should convert ${bch[0]} BCH to ${bch[1]} bits`, () => {
assert.equal(
@@ -94,9 +94,7 @@ describe("#BitcoinCash", () => {
})
fixtures.conversion.satsToBits.strings.forEach(bch => {
it(`should convert "${bch[0]}" BCH as a string to ${
bch[1]
} bits`, () => {
it(`should convert "${bch[0]}" BCH as a string to ${bch[1]} bits`, () => {
assert.equal(
bchjs.BitcoinCash.satsToBits(bchjs.BitcoinCash.toSatoshi(bch[0])),
bch[1]
@@ -121,7 +119,7 @@ describe("#BitcoinCash", () => {
})
describe("sign and verify messages", () => {
describe("#signMessageWithPrivKey", () => {
it("should exercise signMessageWithPrivKey", () => {
fixtures.signatures.sign.forEach(sign => {
it(`should sign a message w/ ${sign.network} ${sign.privateKeyWIF}`, () => {
const privateKeyWIF = sign.privateKeyWIF
@@ -135,7 +133,7 @@ describe("#BitcoinCash", () => {
})
})
describe("#verifyMessage", () => {
it("shoudl exercise verifyMessage", () => {
fixtures.signatures.verify.forEach(sign => {
it(`should verify a valid signed message from ${sign.network} cashaddr address ${sign.address}`, () => {
assert.equal(
@@ -149,22 +147,24 @@ describe("#BitcoinCash", () => {
})
})
fixtures.signatures.verify.forEach(sign => {
const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
it(`should verify a valid signed message from ${sign.network} legacy address ${legacyAddress}`, () => {
assert.equal(
bchjs.BitcoinCash.verifyMessage(
legacyAddress,
sign.signature,
sign.message
),
true
)
it("should verify legacy addresses", () => {
fixtures.signatures.verify.forEach(sign => {
const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
it(`should verify a valid signed message from ${sign.network} legacy address ${legacyAddress}`, () => {
assert.equal(
bchjs.BitcoinCash.verifyMessage(
legacyAddress,
sign.signature,
sign.message
),
true
)
})
})
})
fixtures.signatures.verify.forEach(sign => {
const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
// const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
it(`should not verify an invalid signed message from ${sign.network} cashaddr address ${sign.address}`, () => {
assert.equal(
bchjs.BitcoinCash.verifyMessage(
-275
View File
@@ -1,275 +0,0 @@
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
const axios = require("axios")
const sinon = require("sinon")
const mockData = require("./fixtures/blockbook-mock")
describe(`#Blockbook`, () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
describe(`#Balance`, () => {
it(`should GET balance for a single address`, async () => {
// Stub the network call.
sandbox.stub(axios, "get").resolves({ data: mockData.balance })
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
const result = await bchjs.Blockbook.balance(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.hasAnyKeys(result, [
"page",
"totalPages",
"itemsOnPage",
"address",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxs",
"txs",
"txids"
])
assert.isArray(result.txids)
})
it(`should POST request balances for an array of addresses`, async () => {
// Stub the network call.
sandbox
.stub(axios, "post")
.resolves({ data: [mockData.balance, mockData.balance] })
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
]
const result = await bchjs.Blockbook.balance(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"page",
"totalPages",
"itemsOnPage",
"address",
"balance",
"totalReceived",
"totalSent",
"unconfirmedBalance",
"unconfirmedTxs",
"txs",
"txids"
])
assert.isArray(result[0].txids)
})
it(`should throw an error for improper input`, async () => {
try {
// Stub the network call.
sandbox
.stub(axios, "post")
.throws(`Input address must be a string or array of strings`)
const addr = 12345
await bchjs.Blockbook.balance(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
/*
it(`should throw error on array size rate limit`, async () => {
try {
// Stub the network call.
sandbox.stub(axios, "post").throws(`Array too large`)
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
const result = await bchjs.Blockbook.balance(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
*/
})
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
// Stub the network call.
sandbox.stub(axios, "get").resolves({ data: mockData.utxo })
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
it(`should POST utxo details for an array of addresses`, async () => {
// Stub the network call.
sandbox.stub(axios, "post").resolves({ data: mockData.utxos })
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
]
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isArray(result[0])
assert.hasAnyKeys(result[0][0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
it(`should throw an error for improper input`, async () => {
try {
// Stub the network call.
sandbox
.stub(axios, "post")
.throws(`Input address must be a string or array of strings`)
const addr = 12345
await bchjs.Blockbook.utxo(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings`
)
}
})
/*
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
const result = await bchjs.Blockbook.utxo(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
*/
})
describe(`#tx`, () => {
it(`should GET tx details for a single txid`, async () => {
// Stub the network call.
sandbox.stub(axios, "get").resolves({ data: mockData.utxo })
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
const result = await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"txid",
"vout",
"value",
"height",
"confirmations"
])
})
// it(`should POST utxo details for an array of addresses`, async () => {
// // Stub the network call.
// sandbox.stub(axios, "post").resolves({ data: mockData.utxos })
//
// const addr = [
// "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
// "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
// ]
//
// const result = await bchjs.Blockbook.utxo(addr)
// //console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.isArray(result)
// assert.isArray(result[0])
// assert.hasAnyKeys(result[0][0], [
// "txid",
// "vout",
// "value",
// "height",
// "confirmations"
// ])
// })
// it(`should throw an error for improper input`, async () => {
// try {
// // Stub the network call.
// sandbox
// .stub(axios, "post")
// .throws(`Input address must be a string or array of strings`)
//
// const addr = 12345
//
// await bchjs.Blockbook.utxo(addr)
// assert.equal(true, false, "Unexpected result!")
// } catch (err) {
// //console.log(`err: `, err)
// assert.include(
// err.message,
// `Input address must be a string or array of strings`
// )
// }
// })
/*
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
const result = await bchjs.Blockbook.utxo(addr)
console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.hasAnyKeys(err, ["error"])
assert.include(err.error, "Array too large")
}
})
*/
})
})
+11 -4
View File
@@ -1,13 +1,20 @@
// Public npm libraries.
const assert = require("assert")
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
const Buffer = require("safe-buffer").Buffer
// Mocks
const fixtures = require("./fixtures/ecpair.json")
// Unit under test (uut)
const BCHJS = require("../../src/bch-js")
// const bchjs = new BCHJS()
let bchjs
describe("#ECPair", () => {
beforeEach(() => {
bchjs = new BCHJS()
})
describe("#fromWIF", () => {
fixtures.fromWIF.forEach(fixture => {
it(`should create ECPair from WIF ${fixture.privateKeyWIF}`, () => {
-64
View File
@@ -1,64 +0,0 @@
/*
Unit test mocks for Blockbook endpoints.
*/
const balance = {
page: 1,
totalPages: 1,
itemsOnPage: 1000,
address: "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
balance: "230000",
totalReceived: "6194528752",
totalSent: "6194298752",
unconfirmedBalance: "0",
unconfirmedTxs: 0,
txs: 3,
txids: [
"27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c",
"6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d",
"5d95f4e6047901fc1502a9758bbdb14ce73f24662b1784d13e0217b3d37bb7a2"
]
}
const utxo = [
{
txid: "27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c",
vout: 0,
value: "100000",
height: 560430,
confirmations: 29321
},
{
txid: "6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d",
vout: 0,
value: "130000",
height: 560039,
confirmations: 29712
}
]
const utxos = [
[
{
txid: "27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c",
vout: 0,
value: "100000",
height: 560430,
confirmations: 29868
},
{
txid: "6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d",
vout: 0,
value: "130000",
height: 560039,
confirmations: 30259
}
],
[]
]
module.exports = {
balance,
utxo,
utxos
}
+142 -1
View File
@@ -21,9 +21,150 @@ const utxo = {
"OP_DUP OP_HASH160 2fe2c4c5ef359bb2fe1a849f891cecffbcfb4f77 OP_EQUALVERIFY OP_CHECKSIG"
}
const unconfirmed = {
utxos: [
{
txid: "3904ffe6f8fba4ceda5e887130f60fcb18bdc7dcee10392a57f89475c5c108f1",
vout: 0,
amount: 0.03608203,
satoshis: 3608203,
confirmations: 0,
ts: 1559670801
}
],
legacyAddress: "1AyWs8U4HUnTLmxxFiGoJbsXauRsvBrcKW",
cashAddress: "bitcoincash:qpkkjkhe29mqhqmu3evtq3dsnruuzl3rku6usknlh5",
slpAddress: "simpleledger:qpkkjkhe29mqhqmu3evtq3dsnruuzl3rkuk8mdxlf2",
scriptPubKey: "76a9146d695af951760b837c8e58b045b098f9c17e23b788ac"
}
const utxoPost = [utxo, utxo]
const unconfirmedPost = [unconfirmed, unconfirmed]
const transactions = {
pagesTotal: 1,
txs: [
{
txid: "ec7bc8349386e3e1939bbdc4f8092fdbdd6a380734e68486b558cd594c451d5b",
version: 2,
locktime: 0,
vin: [
{
txid:
"4f1fc57c33659628938db740449bf92fb75799e1d5750a4aeef80eb52d6df1e0",
vout: 0,
sequence: 4294967295,
n: 0,
scriptSig: {
hex:
"483045022100a3662a19ae384a1ceddea57765e425e61b04823e976d574da3911ac6b55d7f9b02200e571d985bce987675a2d58587a346fa40c39f4df13dc88548a92c52d5b24422412103f953f7630acc15bd3f5078c698f3af777286ae955b57e4857c158f75d87adb5f",
asm:
"3045022100a3662a19ae384a1ceddea57765e425e61b04823e976d574da3911ac6b55d7f9b02200e571d985bce987675a2d58587a346fa40c39f4df13dc88548a92c52d5b24422[ALL|FORKID] 03f953f7630acc15bd3f5078c698f3af777286ae955b57e4857c158f75d87adb5f"
},
addr: "17HPz8RQ4XM6mjre6aspvqyj1j648CZidM",
valueSat: 1111,
value: 0.00001111,
doubleSpentTxID: null
},
{
txid:
"126d62c299e7e14c66fe0b485d13082c23641f003690462046bc24ad2d1180c1",
vout: 0,
sequence: 4294967295,
n: 1,
scriptSig: {
hex:
"47304402203e3f923207111ff9bbd2fb5ab1a49a9145ad809ee0cad0e0ddaed64bfe38dc16022012ee288fb413bd500c63f8bb95e46b6b57d34762decd46b7188478a1c398eeda412103f953f7630acc15bd3f5078c698f3af777286ae955b57e4857c158f75d87adb5f",
asm:
"304402203e3f923207111ff9bbd2fb5ab1a49a9145ad809ee0cad0e0ddaed64bfe38dc16022012ee288fb413bd500c63f8bb95e46b6b57d34762decd46b7188478a1c398eeda[ALL|FORKID] 03f953f7630acc15bd3f5078c698f3af777286ae955b57e4857c158f75d87adb5f"
},
addr: "17HPz8RQ4XM6mjre6aspvqyj1j648CZidM",
valueSat: 1000,
value: 0.00001,
doubleSpentTxID: null
}
],
vout: [
{
value: "0.00001736",
n: 0,
scriptPubKey: {
hex: "76a914d96ac75ca8df9729d278da50ccd7355c5785444e88ac",
asm:
"OP_DUP OP_HASH160 d96ac75ca8df9729d278da50ccd7355c5785444e OP_EQUALVERIFY OP_CHECKSIG",
addresses: ["1LpbYkEM5cryfhs58tH8c93p4SGzit7UrP"],
type: "pubkeyhash"
},
spentTxId: null,
spentIndex: null,
spentHeight: null
}
],
blockheight: -1,
confirmations: 0,
time: 1559673337,
valueOut: 0.00001736,
size: 339,
valueIn: 0.00002111,
fees: 0.00000375
}
],
legacyAddress: "1LpbYkEM5cryfhs58tH8c93p4SGzit7UrP",
cashAddress: "bitcoincash:qrvk436u4r0ew2wj0rd9pnxhx4w90p2yfc29ta0d2n",
currentPage: 0
}
const transactionsPost = [transactions, transactions]
const details = {
txid: "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33",
version: 1,
locktime: 0,
vin: [
{
coinbase: "04ffff001d02fd04",
sequence: 4294967295,
n: 0
}
],
vout: [
{
value: "50.00000000",
n: 0,
scriptPubKey: {
hex:
"4104f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446aac",
asm:
"04f5eeb2b10c944c6b9fbcfff94c35bdeecd93df977882babc7f3a2cf7f5c81d3b09a68db7f0e04f21de5d4230e75e6dbe7ad16eefe0d4325a62067dc6f369446a OP_CHECKSIG",
addresses: ["1BW18n7MfpU35q4MTBSk8pse3XzQF8XvzT"],
type: "pubkeyhash",
cashAddrs: ["bitcoincash:qpej6mkrwca4tvy2snq4crhrf88v4ljspysx0ueetk"]
},
spentTxId: null,
spentIndex: null,
spentHeight: null
}
],
blockhash:
"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09",
blockheight: 1000,
confirmations: 585610,
time: 1232346882,
blocktime: 1232346882,
isCoinBase: true,
valueOut: 50,
size: 135
}
const detailsPost = [details, details]
module.exports = {
utxo,
utxoPost
utxoPost,
unconfirmed,
unconfirmedPost,
transactions,
transactionsPost,
details,
detailsPost
}
+189 -1
View File
@@ -1107,6 +1107,189 @@ const txDetailsSLPNftGenesis = {
blocktime: 1591329189
}
const mockWhitelist = [
{
name: "USDH",
tokenId: "c4b0d62156b3fa5c8f3436079b5394f7edc1bef5dc1cd2f9d0c4d46f82cca479"
},
{
name: "SPICE",
tokenId: "4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf"
},
{
name: "PSF",
tokenId: "38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0"
},
{
name: "TROUT",
tokenId: "a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2"
},
{
name: "PSFTEST",
tokenId: "d0ef4de95b78222bfee2326ab11382f4439aa0855936e2fe6ac129a8d778baa0"
}
]
const mockValidateTxid3Valid = [
{
txid: "daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd",
valid: true
}
]
const mockValidateTxid3Invalid = [
{
txid: "f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
valid: null
}
]
const mockValidateTxidArray = [
{
txid: "daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd",
valid: true
},
{
txid: "3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488",
valid: true
},
{
txid: "f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a",
valid: false
},
{
txid: "01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0",
valid: false
}
]
const whitelist = [
{
name: "USDH",
tokenId: "c4b0d62156b3fa5c8f3436079b5394f7edc1bef5dc1cd2f9d0c4d46f82cca479"
},
{
name: "SPICE",
tokenId: "4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf"
},
{
name: "PSF",
tokenId: "38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0"
},
{
name: "TROUT",
tokenId: "a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2"
},
{
name: "PSFTEST",
tokenId: "d0ef4de95b78222bfee2326ab11382f4439aa0855936e2fe6ac129a8d778baa0"
},
{
name: "TOK-CH",
tokenId: "497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
}
]
const slpdbStatus = {
_id: "5fe4cd90cd2bd2000f7fe46c",
version: "1.0.0-beta-rc13",
versionHash: "bb4a805610b9e4d67c1595b716df36190c75e8b1",
deplVersionHash: null,
startCmd: "node index run",
context: "SLPDB",
lastStatusUpdate: {
utc: "Thu, 24 Dec 2020 17:19:12 GMT",
unix: 1608830352
},
lastIncomingTxnZmq: {
utc: "Thu, 24 Dec 2020 17:19:12 GMT",
unix: 1608830352
},
lastIncomingBlockZmq: {
utc: "Thu, 24 Dec 2020 16:43:38 GMT",
unix: 1608828218
},
lastOutgoingTxnZmq: null,
lastOutgoingBlockZmq: null,
state: "RUNNING",
stateHistory: [
{
utc: "Mon, 07 Dec 2020 15:26:23 GMT",
state: "STARTUP_BLOCK_SYNC"
},
{
utc: "Tue, 08 Dec 2020 19:53:04 GMT",
state: "RUNNING"
}
],
network: "mainnet",
bchBlockHeight: 667270,
bchBlockHash:
"000000000000000003d57b35b1b6b8073c8311974e2b9a473e1bd6daa98fde53",
slpProcessedBlockHeight: 667270,
mempoolInfoBch: {
loaded: true,
size: 534,
bytes: 320552,
usage: 956384,
maxmempool: 300000000,
mempoolminfee: 0.00001,
minrelaytxfee: 0.00001
},
mempoolSizeSlp: 78,
tokensCount: 77976,
pastStackTraces: [
"[Tue, 08 Dec 2020 19:35:36 GMT] MongoServerSelectionError: connection <monitor> to 172.17.0.1:12301 timed out\n at Timeout._onTimeout (/home/safeuser/SLPDB/node_modules/mongodb/lib/core/sdam/topology.js:438:30)\n at listOnTimeout (internal/timers.js:554:17)\n at processTimers (internal/timers.js:497:7)",
"[Tue, 08 Dec 2020 19:35:36 GMT] MongoServerSelectionError: connection <monitor> to 172.17.0.1:12301 timed out\n at Timeout._onTimeout (/home/safeuser/SLPDB/node_modules/mongodb/lib/core/sdam/topology.js:438:30)\n at listOnTimeout (internal/timers.js:554:17)\n at processTimers (internal/timers.js:497:7)"
],
doubleSpends: [
{
txo:
"3e377f67e9d065f02e47633d847cdb04b0679d51baccdc0feea5297529e330b5:820",
details: {
originalTxid:
"dc148149d25a546fffe0b207c62b192811c288481df5f43f1f76f67b6004f98c",
current:
"de12db60e253c378eeebb1df85153168a998db8267ec54b38589cc31348b2b8d",
time: {
utc: "Sat, 19 Dec 2020 02:25:37 GMT",
unix: 1608344737
}
}
}
],
reorgs: [],
mongoDbStats: {
db: "slpdb",
collections: 5,
views: 0,
objects: 2497140,
avgObjSize: 3188.778575890819,
dataSize: 7593.943150520325,
storageSize: 3357.74609375,
indexes: 71,
indexSize: 1490.14453125,
totalSize: 4847.890625,
scaleFactor: 1048576,
fsUsedSize: 74424.46484375,
fsTotalSize: 153676.98046875,
ok: 1
},
publicUrl: "fullstack--bchn-02",
telemetryHash: null,
system: {
loadAvg1: 0.16,
loadAvg5: 0.11,
loadAvg15: 0.04,
platform: "linux",
cpuCount: 8,
freeMem: 5780.51953125,
totalMem: 31360.8828125,
uptime: 1654085,
processUptime: 1374204.613560816
}
}
module.exports = {
mockList,
mockToken,
@@ -1131,5 +1314,10 @@ module.exports = {
mockTxDetails,
mockDualValidation,
mockDualOpData,
mockInvalidSlpSend
mockInvalidSlpSend,
mockWhitelist,
mockValidateTxid3Valid,
mockValidateTxid3Invalid,
whitelist,
slpdbStatus
}
+10 -2
View File
@@ -1,10 +1,18 @@
// Public npm libraries
const assert = require("assert")
const axios = require("axios")
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
const sinon = require("sinon")
// Unit under test (uut)
const BCHJS = require("../../src/bch-js")
// const bchjs = new BCHJS()
let bchjs
describe("#Generating", () => {
beforeEach(() => {
bchjs = new BCHJS()
})
describe("#generateToAddress", () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
+62 -49
View File
@@ -1,11 +1,20 @@
const fixtures = require("./fixtures/hdnode.json")
const slpFixtures = require("./fixtures/slp/address.json")
// Public npm libraries
const assert = require("assert")
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
const Buffer = require("safe-buffer").Buffer
// Mocks
const fixtures = require("./fixtures/hdnode.json")
const slpFixtures = require("./fixtures/slp/address.json")
// Unit under test (uut)
const BCHJS = require("../../src/bch-js")
let bchjs
describe("#HDNode", () => {
beforeEach(() => {
bchjs = new BCHJS()
})
describe("#fromSeed", () => {
fixtures.fromSeed.forEach(mnemonic => {
it(`should create an HDNode from root seed buffer`, async () => {
@@ -178,71 +187,75 @@ describe("#HDNode", () => {
})
describe("#fromXPriv", () => {
fixtures.fromXPriv.forEach(fixture => {
const hdNode = bchjs.HDNode.fromXPriv(fixture.xpriv)
it(`should create HDNode from xpriv ${fixture.xpriv}`, () => {
assert.notEqual(hdNode, null)
})
it("should exercise fromXPriv", () => {
fixtures.fromXPriv.forEach(fixture => {
const hdNode = bchjs.HDNode.fromXPriv(fixture.xpriv)
it(`should create HDNode from xpriv ${fixture.xpriv}`, () => {
assert.notEqual(hdNode, null)
})
it(`should export xpriv ${fixture.xpriv}`, () => {
assert.equal(bchjs.HDNode.toXPriv(hdNode), fixture.xpriv)
})
it(`should export xpriv ${fixture.xpriv}`, () => {
assert.equal(bchjs.HDNode.toXPriv(hdNode), fixture.xpriv)
})
it(`should export xpub ${fixture.xpub}`, () => {
assert.equal(bchjs.HDNode.toXPub(hdNode), fixture.xpub)
})
it(`should export xpub ${fixture.xpub}`, () => {
assert.equal(bchjs.HDNode.toXPub(hdNode), fixture.xpub)
})
it(`should export legacy address ${fixture.legacy}`, () => {
assert.equal(bchjs.HDNode.toLegacyAddress(hdNode), fixture.legacy)
})
it(`should export legacy address ${fixture.legacy}`, () => {
assert.equal(bchjs.HDNode.toLegacyAddress(hdNode), fixture.legacy)
})
it(`should export cashaddress ${fixture.cashaddress}`, () => {
assert.equal(bchjs.HDNode.toCashAddress(hdNode), fixture.cashaddress)
})
it(`should export cashaddress ${fixture.cashaddress}`, () => {
assert.equal(bchjs.HDNode.toCashAddress(hdNode), fixture.cashaddress)
})
it(`should export regtest cashaddress ${fixture.regtestaddress}`, () => {
assert.equal(
bchjs.HDNode.toCashAddress(hdNode, true),
fixture.regtestaddress
)
})
it(`should export regtest cashaddress ${fixture.regtestaddress}`, () => {
assert.equal(
bchjs.HDNode.toCashAddress(hdNode, true),
fixture.regtestaddress
)
})
it(`should export privateKeyWIF ${fixture.privateKeyWIF}`, () => {
assert.equal(bchjs.HDNode.toWIF(hdNode), fixture.privateKeyWIF)
it(`should export privateKeyWIF ${fixture.privateKeyWIF}`, () => {
assert.equal(bchjs.HDNode.toWIF(hdNode), fixture.privateKeyWIF)
})
})
})
})
describe("#fromXPub", () => {
fixtures.fromXPub.forEach(fixture => {
const hdNode = bchjs.HDNode.fromXPub(fixture.xpub)
it(`should create HDNode from xpub ${fixture.xpub}`, () => {
assert.notEqual(hdNode, null)
})
it("should exercise fromXPub", () => {
fixtures.fromXPub.forEach(fixture => {
const hdNode = bchjs.HDNode.fromXPub(fixture.xpub)
it(`should create HDNode from xpub ${fixture.xpub}`, () => {
assert.notEqual(hdNode, null)
})
it(`should export xpub ${fixture.xpub}`, () => {
assert.equal(bchjs.HDNode.toXPub(hdNode), fixture.xpub)
})
it(`should export xpub ${fixture.xpub}`, () => {
assert.equal(bchjs.HDNode.toXPub(hdNode), fixture.xpub)
})
it(`should export legacy address ${fixture.legacy}`, () => {
assert.equal(bchjs.HDNode.toLegacyAddress(hdNode), fixture.legacy)
})
it(`should export legacy address ${fixture.legacy}`, () => {
assert.equal(bchjs.HDNode.toLegacyAddress(hdNode), fixture.legacy)
})
it(`should export cashaddress ${fixture.cashaddress}`, () => {
assert.equal(bchjs.HDNode.toCashAddress(hdNode), fixture.cashaddress)
})
it(`should export cashaddress ${fixture.cashaddress}`, () => {
assert.equal(bchjs.HDNode.toCashAddress(hdNode), fixture.cashaddress)
})
it(`should export regtest cashaddress ${fixture.regtestaddress}`, () => {
assert.equal(
bchjs.HDNode.toCashAddress(hdNode, true),
fixture.regtestaddress
)
it(`should export regtest cashaddress ${fixture.regtestaddress}`, () => {
assert.equal(
bchjs.HDNode.toCashAddress(hdNode, true),
fixture.regtestaddress
)
})
})
})
})
describe("#bip32", () => {
describe("create accounts and addresses", () => {
it("should create accounts and addresses", () => {
fixtures.accounts.forEach(async fixture => {
const seedBuffer = await bchjs.Mnemonic.toSeed(fixture.mnemonic)
console.log(`seedBuffer: ${seedBuffer.toString()}`)
+9 -2
View File
@@ -1,10 +1,17 @@
// Public npm libraries
const assert = require("assert")
const axios = require("axios")
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
const sinon = require("sinon")
// Unit under test (uut)
const BCHJS = require("../../src/bch-js")
let bchjs
describe("#Mining", () => {
beforeEach(() => {
bchjs = new BCHJS()
})
describe("#getBlockTemplate", () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
+174
View File
@@ -78,4 +78,178 @@ describe(`#Ninsight`, () => {
assert.property(result[0], "asm")
})
})
describe("#unconfirmed", () => {
it("should throw an error for improper input", async () => {
try {
const addr = 12345
await bchjs.Ninsight.unconfirmed(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
assert.include(
err.message,
"Input address must be a string or array of strings."
)
}
})
it(`should POST utxos for a single address`, async () => {
// Stub the network call.
sandbox.stub(axios, "post").resolves({ data: mockData.unconfirmed })
const addr = "bitcoincash:qpkkjkhe29mqhqmu3evtq3dsnruuzl3rku6usknlh5"
const result = await bchjs.Ninsight.unconfirmed(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "utxos")
assert.property(result, "legacyAddress")
assert.property(result, "cashAddress")
assert.property(result, "slpAddress")
assert.property(result, "scriptPubKey")
assert.isArray(result.utxos)
assert.property(result.utxos[0], "txid")
assert.property(result.utxos[0], "vout")
assert.property(result.utxos[0], "amount")
assert.property(result.utxos[0], "satoshis")
assert.property(result.utxos[0], "confirmations")
assert.property(result.utxos[0], "ts")
})
it(`should POST utxo details for an array of addresses`, async () => {
// Mock the network call.
sandbox.stub(axios, "post").resolves({ data: mockData.unconfirmedPost })
const addr = [
"bitcoincash:qpkkjkhe29mqhqmu3evtq3dsnruuzl3rku6usknlh5",
"bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr"
]
const result = await bchjs.Ninsight.unconfirmed(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isArray(result[0].utxos)
assert.property(result[0], "utxos")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "cashAddress")
assert.property(result[0], "slpAddress")
assert.property(result[0], "scriptPubKey")
})
})
describe(`#transactions`, () => {
it(`should throw an error for improper input`, async () => {
try {
const addr = 12345
await bchjs.Ninsight.transactions(addr)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Input address must be a string or array of strings.`
)
}
})
it(`should POST transaction history for a single address`, async () => {
// Stub the network call.
sandbox.stub(axios, "post").resolves({ data: mockData.transactionsPost })
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
const result = await bchjs.Ninsight.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "cashAddress")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "txs")
assert.isArray(result[0].txs)
assert.property(result[0].txs[0], "txid")
assert.property(result[0].txs[0], "vin")
assert.property(result[0].txs[0], "vout")
})
it(`should POST transaction history for an array of addresses`, async () => {
// Mock the network call.
sandbox.stub(axios, "post").resolves({ data: mockData.transactionsPost })
const addr = [
"bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7",
"bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr"
]
const result = await bchjs.Ninsight.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "cashAddress")
assert.property(result[0], "legacyAddress")
assert.property(result[0], "txs")
assert.isArray(result[0].txs)
assert.property(result[0].txs[0], "txid")
})
})
describe(`#txDetails`, () => {
it(`should throw an error for improper input`, async () => {
try {
const txid = 12345
await bchjs.Ninsight.txDetails(txid)
assert.equal(true, false, "Unexpected result!")
} catch (err) {
//console.log(`err: `, err)
assert.include(
err.message,
`Transaction ID must be a string or array of strings.`
)
}
})
it(`should POST transaction details for a single TxID`, async () => {
// Stub the network call.
sandbox.stub(axios, "post").resolves({ data: mockData.detailsPost })
const txid = "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"
const result = await bchjs.Ninsight.txDetails(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "txid")
assert.property(result[0], "version")
assert.property(result[0], "locktime")
assert.property(result[0], "vin")
assert.property(result[0], "vout")
assert.property(result[0], "blockhash")
assert.property(result[0], "blockheight")
assert.property(result[0], "confirmations")
assert.property(result[0], "time")
assert.property(result[0], "blocktime")
assert.property(result[0], "isCoinBase")
assert.property(result[0], "valueOut")
assert.property(result[0], "size")
})
it(`should POST transaction details for an array of TxIDs`, async () => {
// Stub the network call.
sandbox.stub(axios, "post").resolves({ data: mockData.detailsPost })
const txid = [
"fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33",
"fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"
]
const result = await bchjs.Ninsight.txDetails(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.property(result[0], "txid")
assert.property(result[0], "vin")
assert.property(result[0], "vout")
})
})
})
+12 -1
View File
@@ -5,7 +5,7 @@ const sinon = require("sinon")
const mockDataLib = require("./fixtures/price-mocks")
let mockData
describe("#Price", () => {
describe("#price", () => {
let sandbox
let bchjs
@@ -56,4 +56,15 @@ describe("#Price", () => {
assert.property(result, "CAD")
})
})
describe("#getBchaUsd", () => {
it("should get the USD price of BCHA", async () => {
sandbox.stub(bchjs.Price.axios, "get").resolves({ data: { usd: 18.87 } })
const result = await bchjs.Price.getBchaUsd()
// console.log(result)
assert.isNumber(result)
})
})
})
+28 -22
View File
@@ -1,23 +1,28 @@
/*
TODO:
-Replace old unit tests mocking axios with the more generalized nock library.
See the sendRawTransaction test for an example.
-Create a mocking library of data to compare unit and integration tests.
*/
// Public npm libraries
const assert = require("assert")
const axios = require("axios")
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
const sinon = require("sinon")
const nock = require("nock") // HTTP mocking
// const nock = require("nock") // HTTP mocking
// Unit under test (uut)
const BCHJS = require("../../src/bch-js")
// const bchjs = new BCHJS()
let bchjs
// Used for debugging
const util = require("util")
util.inspect.defaultOptions = { depth: 1 }
// const util = require("util")
// util.inspect.defaultOptions = { depth: 1 }
describe("#RawTransactions", () => {
beforeEach(() => {
bchjs = new BCHJS()
})
describe("#decodeRawTransaction", () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
@@ -111,19 +116,20 @@ describe("#RawTransactions", () => {
assert.equal(data, result)
})
it("should send an array of raw transactions", async () => {
const data = "Error: transaction already in block chain"
// Mock the http call to rest.bitcoin.com
nock(`${bchjs.RawTransactions.restURL}`)
.post(uri => uri.includes(`/`))
.reply(200, { data: data })
const result = await bchjs.RawTransactions.sendRawTransaction([
"020000000160d663961c63c7f0a07f22ec07b8f55b3935bfdbed8b1d8454916e8932fbf109010000006b4830450221008479fab4cfdcb111833d250a43f98ac26d43272b7a29cb1b9a0491eae5c44b3502203448b17253632395c29a7d62058bbfe93efb20fc8636ba6837002d464195aec04121029123258f7cdcd45b864066bcaa9b71f24d5ed1fa1dd36eaf107d8432b5014658ffffffff016d180000000000001976a91479d3297d1823149f4ec61df31d19f2fad5390c0288ac00000000"
])
assert.equal(data, result.data)
})
// it("should send an array of raw transactions", async () => {
// const data = "Error: transaction already in block chain"
//
// // Mock the http call to rest.bitcoin.com
// // nock(`${bchjs.RawTransactions.restURL}`)
// // .post(uri => uri.includes(`/`))
// // .reply(200, { data: data })
// sandbox.stub(bchjs, "axios").resolves({ data: data })
//
// const result = await bchjs.RawTransactions.sendRawTransaction([
// "020000000160d663961c63c7f0a07f22ec07b8f55b3935bfdbed8b1d8454916e8932fbf109010000006b4830450221008479fab4cfdcb111833d250a43f98ac26d43272b7a29cb1b9a0491eae5c44b3502203448b17253632395c29a7d62058bbfe93efb20fc8636ba6837002d464195aec04121029123258f7cdcd45b864066bcaa9b71f24d5ed1fa1dd36eaf107d8432b5014658ffffffff016d180000000000001976a91479d3297d1823149f4ec61df31d19f2fad5390c0288ac00000000"
// ])
//
// assert.equal(data, result.data)
// })
})
})
+31 -20
View File
@@ -1,10 +1,19 @@
const fixtures = require("./fixtures/script.json")
// Public npm libraries
const assert = require("assert")
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
const Buffer = require("safe-buffer").Buffer
// Mocks
const fixtures = require("./fixtures/script.json")
// Unit under test (uut)
const BCHJS = require("../../src/bch-js")
let bchjs
describe("#Script", () => {
beforeEach(() => {
bchjs = new BCHJS()
})
describe("#decode", () => {
describe("P2PKH scriptSig", () => {
fixtures.decodeScriptSig.forEach(fixture => {
@@ -321,25 +330,27 @@ describe("#Script", () => {
})
describe("#pubKeyHashOutputTemplate", () => {
fixtures.pubKeyHashOutputTemplate.forEach(fixture => {
const node = bchjs.HDNode.fromXPriv(fixture.xpriv)
const identifier = bchjs.HDNode.toIdentifier(node)
it(`should encode pubKeyHash output`, () => {
const buf = bchjs.Script.pubKeyHash.output.encode(identifier)
assert.equal(buf.toString("hex"), fixture.hex)
})
it("should exercise pubKeyHashOutputTemplate", () => {
fixtures.pubKeyHashOutputTemplate.forEach(fixture => {
const node = bchjs.HDNode.fromXPriv(fixture.xpriv)
const identifier = bchjs.HDNode.toIdentifier(node)
it(`should encode pubKeyHash output`, () => {
const buf = bchjs.Script.pubKeyHash.output.encode(identifier)
assert.equal(buf.toString("hex"), fixture.hex)
})
it(`should decode pubKeyHash output`, () => {
const buf = bchjs.Script.pubKeyHash.output.decode(
Buffer.from(`${fixture.hex}`, "hex")
)
assert.equal(buf.toString("hex"), identifier.toString("hex"))
})
it(`should decode pubKeyHash output`, () => {
const buf = bchjs.Script.pubKeyHash.output.decode(
Buffer.from(`${fixture.hex}`, "hex")
)
assert.equal(buf.toString("hex"), identifier.toString("hex"))
})
it(`should confirm correctly formatted pubKeyHash output`, () => {
const buf = bchjs.Script.pubKeyHash.output.encode(identifier)
const valid = bchjs.Script.pubKeyHash.output.check(buf)
assert.equal(valid, true)
it(`should confirm correctly formatted pubKeyHash output`, () => {
const buf = bchjs.Script.pubKeyHash.output.encode(identifier)
const valid = bchjs.Script.pubKeyHash.output.check(buf)
assert.equal(valid, true)
})
})
})
})
+82 -74
View File
@@ -1,7 +1,9 @@
const assert = require("assert")
const slp = require("../../src/slp/slp")
const SLP = new slp({ restURL: "http://fakeurl.com/" })
const BCHJS = require("../../src/bch-js")
// const SLP = require("../../src/slp/slp")
// const SLP = new slp({ restURL: "http://fakeurl.com/" })
let slp
const fixtures = require("./fixtures/slp/address.json")
//const axios = require("axios")
@@ -86,12 +88,18 @@ const SLP_TESTNET_ADDRESSES_NO_PREFIX = SLP_TESTNET_ADDRESSES.map(address => {
})
*/
describe("#SLP Address", () => {
beforeEach(() => {
const bchjs = new BCHJS()
// console.log(`bchjs.restURL: ${bchjs.restURL}`)
slp = bchjs.SLP
})
describe("#mainnet", () => {
describe("#toLegacyAddress", () => {
it("should convert mainnet legacy address format to itself correctly", () => {
assert.deepEqual(
LEGACY_MAINNET_ADDRESSES.map(address =>
SLP.Address.toLegacyAddress(address)
slp.Address.toLegacyAddress(address)
),
LEGACY_MAINNET_ADDRESSES
)
@@ -100,7 +108,7 @@ describe("#SLP Address", () => {
it(`should convert cashAddr to legacyAddr`, async () => {
assert.deepEqual(
CASH_MAINNET_ADDRESSES.map(address =>
SLP.Address.toLegacyAddress(address)
slp.Address.toLegacyAddress(address)
),
LEGACY_MAINNET_ADDRESSES
)
@@ -109,7 +117,7 @@ describe("#SLP Address", () => {
it(`should convert slpAddr to legacyAddr`, async () => {
assert.deepEqual(
SLP_MAINNET_ADDRESSES.map(address =>
SLP.Address.toLegacyAddress(address)
slp.Address.toLegacyAddress(address)
),
LEGACY_MAINNET_ADDRESSES
)
@@ -120,7 +128,7 @@ describe("#SLP Address", () => {
it("should convert mainnet cash address format to itself correctly", () => {
assert.deepEqual(
CASH_MAINNET_ADDRESSES.map(address =>
SLP.Address.toCashAddress(address)
slp.Address.toCashAddress(address)
),
CASH_MAINNET_ADDRESSES
)
@@ -129,7 +137,7 @@ describe("#SLP Address", () => {
it(`should convert legacyAddr to cashAddr`, async () => {
assert.deepEqual(
LEGACY_MAINNET_ADDRESSES.map(address =>
SLP.Address.toCashAddress(address)
slp.Address.toCashAddress(address)
),
CASH_MAINNET_ADDRESSES
)
@@ -138,7 +146,7 @@ describe("#SLP Address", () => {
it(`should convert slpAddr to cashAddr`, async () => {
assert.deepEqual(
SLP_MAINNET_ADDRESSES.map(address =>
SLP.Address.toCashAddress(address)
slp.Address.toCashAddress(address)
),
CASH_MAINNET_ADDRESSES
)
@@ -149,7 +157,7 @@ describe("#SLP Address", () => {
it("should convert mainnet slp address format to itself correctly", () => {
assert.deepEqual(
SLP_MAINNET_ADDRESSES.map(address =>
SLP.Address.toSLPAddress(address)
slp.Address.toSLPAddress(address)
),
SLP_MAINNET_ADDRESSES
)
@@ -158,7 +166,7 @@ describe("#SLP Address", () => {
it(`should convert legacyAddr to slpAddr`, async () => {
assert.deepEqual(
LEGACY_MAINNET_ADDRESSES.map(address =>
SLP.Address.toSLPAddress(address)
slp.Address.toSLPAddress(address)
),
SLP_MAINNET_ADDRESSES
)
@@ -167,7 +175,7 @@ describe("#SLP Address", () => {
it(`should convert cashAddr to slpAddr`, async () => {
assert.deepEqual(
CASH_MAINNET_ADDRESSES.map(address =>
SLP.Address.toSLPAddress(address)
slp.Address.toSLPAddress(address)
),
SLP_MAINNET_ADDRESSES
)
@@ -178,7 +186,7 @@ describe("#SLP Address", () => {
describe("is legacy addr", () => {
LEGACY_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a legacy address`, () => {
const isLegacyaddr = SLP.Address.isLegacyAddress(address)
const isLegacyaddr = slp.Address.isLegacyAddress(address)
assert.equal(isLegacyaddr, true)
})
})
@@ -187,7 +195,7 @@ describe("#SLP Address", () => {
describe("cashaddr is not legacy addr", () => {
CASH_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a legacy address`, () => {
const isLegacyaddr = SLP.Address.isLegacyAddress(address)
const isLegacyaddr = slp.Address.isLegacyAddress(address)
assert.equal(isLegacyaddr, false)
})
})
@@ -196,7 +204,7 @@ describe("#SLP Address", () => {
describe("slpaddr is not legacy addr", () => {
SLP_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a legacy address`, () => {
const isLegacyaddr = SLP.Address.isLegacyAddress(address)
const isLegacyaddr = slp.Address.isLegacyAddress(address)
assert.equal(isLegacyaddr, false)
})
})
@@ -207,7 +215,7 @@ describe("#SLP Address", () => {
describe("is cashaddr", () => {
CASH_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a cashaddr address`, () => {
const isCashaddr = SLP.Address.isCashAddress(address)
const isCashaddr = slp.Address.isCashAddress(address)
assert.equal(isCashaddr, true)
})
})
@@ -216,7 +224,7 @@ describe("#SLP Address", () => {
describe("legacy is not cash addr", () => {
LEGACY_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a cash address`, () => {
const isCashaddr = SLP.Address.isCashAddress(address)
const isCashaddr = slp.Address.isCashAddress(address)
assert.equal(isCashaddr, false)
})
})
@@ -225,7 +233,7 @@ describe("#SLP Address", () => {
describe("slpaddr is not cash addr", () => {
SLP_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a cash address`, () => {
const isCashaddr = SLP.Address.isCashAddress(address)
const isCashaddr = slp.Address.isCashAddress(address)
assert.equal(isCashaddr, false)
})
})
@@ -236,7 +244,7 @@ describe("#SLP Address", () => {
describe("is slpaddr", () => {
SLP_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is an slp address`, () => {
const isSLPaddr = SLP.Address.isSLPAddress(address)
const isSLPaddr = slp.Address.isSLPAddress(address)
assert.equal(isSLPaddr, true)
})
})
@@ -245,7 +253,7 @@ describe("#SLP Address", () => {
describe("legacy is not slp addr", () => {
LEGACY_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not an slp address`, () => {
const isSLPaddr = SLP.Address.isSLPAddress(address)
const isSLPaddr = slp.Address.isSLPAddress(address)
assert.equal(isSLPaddr, false)
})
})
@@ -254,7 +262,7 @@ describe("#SLP Address", () => {
describe("cash is not slp addr", () => {
CASH_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not an slp address`, () => {
const isSLPaddr = SLP.Address.isSLPAddress(address)
const isSLPaddr = slp.Address.isSLPAddress(address)
assert.equal(isSLPaddr, false)
})
})
@@ -265,7 +273,7 @@ describe("#SLP Address", () => {
describe("mainnet legacy addr", () => {
LEGACY_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a mainnet address`, () => {
const isMainnetaddr = SLP.Address.isMainnetAddress(address)
const isMainnetaddr = slp.Address.isMainnetAddress(address)
assert.equal(isMainnetaddr, true)
})
})
@@ -274,7 +282,7 @@ describe("#SLP Address", () => {
describe("mainnet cash addr", () => {
CASH_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a mainnet address`, () => {
const isMainnetaddr = SLP.Address.isMainnetAddress(address)
const isMainnetaddr = slp.Address.isMainnetAddress(address)
assert.equal(isMainnetaddr, true)
})
})
@@ -283,7 +291,7 @@ describe("#SLP Address", () => {
describe("mainnet slp addr", () => {
SLP_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a mainnet address`, () => {
const isMainnetaddr = SLP.Address.isMainnetAddress(address)
const isMainnetaddr = slp.Address.isMainnetAddress(address)
assert.equal(isMainnetaddr, true)
})
})
@@ -292,7 +300,7 @@ describe("#SLP Address", () => {
describe("testnet legacy addr", () => {
LEGACY_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a mainnet address`, () => {
const isMainnetaddr = SLP.Address.isMainnetAddress(address)
const isMainnetaddr = slp.Address.isMainnetAddress(address)
assert.equal(isMainnetaddr, false)
})
})
@@ -301,7 +309,7 @@ describe("#SLP Address", () => {
describe("testnet cash addr", () => {
CASH_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a mainnet address`, () => {
const isMainnetaddr = SLP.Address.isMainnetAddress(address)
const isMainnetaddr = slp.Address.isMainnetAddress(address)
assert.equal(isMainnetaddr, false)
})
})
@@ -310,7 +318,7 @@ describe("#SLP Address", () => {
describe("testnet slp addr", () => {
SLP_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a mainnet address`, () => {
const isMainnetaddr = SLP.Address.isMainnetAddress(address)
const isMainnetaddr = slp.Address.isMainnetAddress(address)
assert.equal(isMainnetaddr, false)
})
})
@@ -321,7 +329,7 @@ describe("#SLP Address", () => {
describe("mainnet legacy addr", () => {
MAINNET_P2PKH_ADDRESSES.forEach(address => {
it(`should detect ${address} is a P2PKH address`, () => {
const isP2PKHaddr = SLP.Address.isP2PKHAddress(address)
const isP2PKHaddr = slp.Address.isP2PKHAddress(address)
assert.equal(isP2PKHaddr, true)
})
})
@@ -332,7 +340,7 @@ describe("#SLP Address", () => {
describe("mainnet legacy addr", () => {
MAINNET_P2SH_ADDRESSES.forEach(address => {
it(`should detect ${address} is a P2SH address`, () => {
const isP2SHaddr = SLP.Address.isP2SHAddress(address)
const isP2SHaddr = slp.Address.isP2SHAddress(address)
assert.equal(isP2SHaddr, true)
})
})
@@ -342,21 +350,21 @@ describe("#SLP Address", () => {
describe("#detectAddressFormat", () => {
LEGACY_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a legacy address`, () => {
const isLegacy = SLP.Address.detectAddressFormat(address)
const isLegacy = slp.Address.detectAddressFormat(address)
assert.equal(isLegacy, "legacy")
})
})
CASH_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a cash address`, () => {
const isCashaddr = SLP.Address.detectAddressFormat(address)
const isCashaddr = slp.Address.detectAddressFormat(address)
assert.equal(isCashaddr, "cashaddr")
})
})
SLP_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is an slp address`, () => {
const isSlpaddr = SLP.Address.detectAddressFormat(address)
const isSlpaddr = slp.Address.detectAddressFormat(address)
assert.equal(isSlpaddr, "slpaddr")
})
})
@@ -365,21 +373,21 @@ describe("#SLP Address", () => {
describe("#detectAddressNetwork", () => {
LEGACY_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a mainnet address`, () => {
const isMainnet = SLP.Address.detectAddressNetwork(address)
const isMainnet = slp.Address.detectAddressNetwork(address)
assert.equal(isMainnet, "mainnet")
})
})
CASH_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a mainnet address`, () => {
const isMainnet = SLP.Address.detectAddressNetwork(address)
const isMainnet = slp.Address.detectAddressNetwork(address)
assert.equal(isMainnet, "mainnet")
})
})
SLP_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a mainnet address`, () => {
const isMainnet = SLP.Address.detectAddressNetwork(address)
const isMainnet = slp.Address.detectAddressNetwork(address)
assert.equal(isMainnet, "mainnet")
})
})
@@ -388,14 +396,14 @@ describe("#SLP Address", () => {
describe("#detectAddressType", () => {
MAINNET_P2PKH_ADDRESSES.forEach(address => {
it(`should detect ${address} is a p2pkh address`, () => {
const isp2pkh = SLP.Address.detectAddressType(address)
const isp2pkh = slp.Address.detectAddressType(address)
assert.equal(isp2pkh, "p2pkh")
})
})
MAINNET_P2SH_ADDRESSES.forEach(address => {
it(`should detect ${address} is a p2sh address`, () => {
const isp2sh = SLP.Address.detectAddressType(address)
const isp2sh = slp.Address.detectAddressType(address)
assert.equal(isp2sh, "p2sh")
})
})
@@ -407,7 +415,7 @@ describe("#SLP Address", () => {
it("should convert testnet legacy address format to itself correctly", () => {
assert.deepEqual(
LEGACY_TESTNET_ADDRESSES.map(address =>
SLP.Address.toLegacyAddress(address)
slp.Address.toLegacyAddress(address)
),
LEGACY_TESTNET_ADDRESSES
)
@@ -416,7 +424,7 @@ describe("#SLP Address", () => {
it(`should convert cashAddr to legacyAddr`, async () => {
assert.deepEqual(
CASH_TESTNET_ADDRESSES.map(address =>
SLP.Address.toLegacyAddress(address)
slp.Address.toLegacyAddress(address)
),
LEGACY_TESTNET_ADDRESSES
)
@@ -425,7 +433,7 @@ describe("#SLP Address", () => {
it(`should convert slpAddr to legacyAddr`, async () => {
assert.deepEqual(
SLP_TESTNET_ADDRESSES.map(address =>
SLP.Address.toLegacyAddress(address)
slp.Address.toLegacyAddress(address)
),
LEGACY_TESTNET_ADDRESSES
)
@@ -436,7 +444,7 @@ describe("#SLP Address", () => {
it("should convert testnet cash address format to itself correctly", () => {
assert.deepEqual(
CASH_TESTNET_ADDRESSES.map(address =>
SLP.Address.toCashAddress(address)
slp.Address.toCashAddress(address)
),
CASH_TESTNET_ADDRESSES
)
@@ -445,7 +453,7 @@ describe("#SLP Address", () => {
it(`should convert legacyAddr to cashAddr`, async () => {
assert.deepEqual(
LEGACY_TESTNET_ADDRESSES.map(address =>
SLP.Address.toCashAddress(address)
slp.Address.toCashAddress(address)
),
CASH_TESTNET_ADDRESSES
)
@@ -454,7 +462,7 @@ describe("#SLP Address", () => {
it(`should convert slpAddr to cashAddr`, async () => {
assert.deepEqual(
SLP_TESTNET_ADDRESSES.map(address =>
SLP.Address.toCashAddress(address)
slp.Address.toCashAddress(address)
),
CASH_TESTNET_ADDRESSES
)
@@ -465,7 +473,7 @@ describe("#SLP Address", () => {
it("should convert testnet slp address format to itself correctly", () => {
assert.deepEqual(
SLP_TESTNET_ADDRESSES.map(address =>
SLP.Address.toSLPAddress(address)
slp.Address.toSLPAddress(address)
),
SLP_TESTNET_ADDRESSES
)
@@ -474,7 +482,7 @@ describe("#SLP Address", () => {
it(`should convert legacyAddr to slpAddr`, async () => {
assert.deepEqual(
LEGACY_TESTNET_ADDRESSES.map(address =>
SLP.Address.toSLPAddress(address)
slp.Address.toSLPAddress(address)
),
SLP_TESTNET_ADDRESSES
)
@@ -483,7 +491,7 @@ describe("#SLP Address", () => {
it(`should convert cashAddr to slpAddr`, async () => {
assert.deepEqual(
CASH_TESTNET_ADDRESSES.map(address =>
SLP.Address.toSLPAddress(address)
slp.Address.toSLPAddress(address)
),
SLP_TESTNET_ADDRESSES
)
@@ -494,7 +502,7 @@ describe("#SLP Address", () => {
describe("is legacy addr", () => {
LEGACY_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a legacy address`, () => {
const isLegacyaddr = SLP.Address.isLegacyAddress(address)
const isLegacyaddr = slp.Address.isLegacyAddress(address)
assert.equal(isLegacyaddr, true)
})
})
@@ -503,7 +511,7 @@ describe("#SLP Address", () => {
describe("cashaddr is not legacy addr", () => {
CASH_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a legacy address`, () => {
const isLegacyaddr = SLP.Address.isLegacyAddress(address)
const isLegacyaddr = slp.Address.isLegacyAddress(address)
assert.equal(isLegacyaddr, false)
})
})
@@ -512,7 +520,7 @@ describe("#SLP Address", () => {
describe("slpaddr is not legacy addr", () => {
SLP_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a legacy address`, () => {
const isLegacyaddr = SLP.Address.isLegacyAddress(address)
const isLegacyaddr = slp.Address.isLegacyAddress(address)
assert.equal(isLegacyaddr, false)
})
})
@@ -523,7 +531,7 @@ describe("#SLP Address", () => {
describe("is cashaddr", () => {
CASH_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a cashaddr address`, () => {
const isCashaddr = SLP.Address.isCashAddress(address)
const isCashaddr = slp.Address.isCashAddress(address)
assert.equal(isCashaddr, true)
})
})
@@ -532,7 +540,7 @@ describe("#SLP Address", () => {
describe("legacy is not cash addr", () => {
LEGACY_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a cash address`, () => {
const isCashaddr = SLP.Address.isCashAddress(address)
const isCashaddr = slp.Address.isCashAddress(address)
assert.equal(isCashaddr, false)
})
})
@@ -541,7 +549,7 @@ describe("#SLP Address", () => {
describe("slpaddr is not cash addr", () => {
SLP_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a cash address`, () => {
const isCashaddr = SLP.Address.isCashAddress(address)
const isCashaddr = slp.Address.isCashAddress(address)
assert.equal(isCashaddr, false)
})
})
@@ -552,7 +560,7 @@ describe("#SLP Address", () => {
describe("is slpaddr", () => {
SLP_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is an slp address`, () => {
const isSLPaddr = SLP.Address.isSLPAddress(address)
const isSLPaddr = slp.Address.isSLPAddress(address)
assert.equal(isSLPaddr, true)
})
})
@@ -561,7 +569,7 @@ describe("#SLP Address", () => {
describe("legacy is not slp addr", () => {
LEGACY_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not an slp address`, () => {
const isSLPaddr = SLP.Address.isSLPAddress(address)
const isSLPaddr = slp.Address.isSLPAddress(address)
assert.equal(isSLPaddr, false)
})
})
@@ -570,7 +578,7 @@ describe("#SLP Address", () => {
describe("cash is not slp addr", () => {
CASH_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not an slp address`, () => {
const isSLPaddr = SLP.Address.isSLPAddress(address)
const isSLPaddr = slp.Address.isSLPAddress(address)
assert.equal(isSLPaddr, false)
})
})
@@ -581,7 +589,7 @@ describe("#SLP Address", () => {
describe("testnet legacy addr", () => {
LEGACY_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a testnet address`, () => {
const isTestnetaddr = SLP.Address.isTestnetAddress(address)
const isTestnetaddr = slp.Address.isTestnetAddress(address)
assert.equal(isTestnetaddr, true)
})
})
@@ -590,7 +598,7 @@ describe("#SLP Address", () => {
describe("testnet cash addr", () => {
CASH_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a testnet address`, () => {
const isTestnetaddr = SLP.Address.isTestnetAddress(address)
const isTestnetaddr = slp.Address.isTestnetAddress(address)
assert.equal(isTestnetaddr, true)
})
})
@@ -599,7 +607,7 @@ describe("#SLP Address", () => {
describe("testnet slp addr", () => {
SLP_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a testnet address`, () => {
const isTestnetaddr = SLP.Address.isTestnetAddress(address)
const isTestnetaddr = slp.Address.isTestnetAddress(address)
assert.equal(isTestnetaddr, true)
})
})
@@ -608,7 +616,7 @@ describe("#SLP Address", () => {
describe("mainnet legacy addr", () => {
LEGACY_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a testnet address`, () => {
const isTestnetaddr = SLP.Address.isTestnetAddress(address)
const isTestnetaddr = slp.Address.isTestnetAddress(address)
assert.equal(isTestnetaddr, false)
})
})
@@ -617,7 +625,7 @@ describe("#SLP Address", () => {
describe("mainnet cash addr", () => {
CASH_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a testnet address`, () => {
const isTestnetaddr = SLP.Address.isTestnetAddress(address)
const isTestnetaddr = slp.Address.isTestnetAddress(address)
assert.equal(isTestnetaddr, false)
})
})
@@ -626,7 +634,7 @@ describe("#SLP Address", () => {
describe("mainnet slp addr", () => {
SLP_MAINNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is not a testnet address`, () => {
const isTestnetaddr = SLP.Address.isTestnetAddress(address)
const isTestnetaddr = slp.Address.isTestnetAddress(address)
assert.equal(isTestnetaddr, false)
})
})
@@ -637,7 +645,7 @@ describe("#SLP Address", () => {
describe("testnet legacy addr", () => {
TESTNET_P2PKH_ADDRESSES.forEach(address => {
it(`should detect ${address} is a P2PKH address`, () => {
const isP2PKHaddr = SLP.Address.isP2PKHAddress(address)
const isP2PKHaddr = slp.Address.isP2PKHAddress(address)
assert.equal(isP2PKHaddr, true)
})
})
@@ -648,7 +656,7 @@ describe("#SLP Address", () => {
describe("testnet legacy addr", () => {
TESTNET_P2SH_ADDRESSES.forEach(address => {
it(`should detect ${address} is a P2SH address`, () => {
const isP2SHaddr = SLP.Address.isP2SHAddress(address)
const isP2SHaddr = slp.Address.isP2SHAddress(address)
assert.equal(isP2SHaddr, true)
})
})
@@ -658,21 +666,21 @@ describe("#SLP Address", () => {
describe("#detectAddressFormat", () => {
LEGACY_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a legacy address`, () => {
const isLegacy = SLP.Address.detectAddressFormat(address)
const isLegacy = slp.Address.detectAddressFormat(address)
assert.equal(isLegacy, "legacy")
})
})
CASH_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a cash address`, () => {
const isCashaddr = SLP.Address.detectAddressFormat(address)
const isCashaddr = slp.Address.detectAddressFormat(address)
assert.equal(isCashaddr, "cashaddr")
})
})
SLP_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is an slp address`, () => {
const isSlpaddr = SLP.Address.detectAddressFormat(address)
const isSlpaddr = slp.Address.detectAddressFormat(address)
assert.equal(isSlpaddr, "slpaddr")
})
})
@@ -681,21 +689,21 @@ describe("#SLP Address", () => {
describe("#detectAddressNetwork", () => {
LEGACY_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a testnet address`, () => {
const isTestnet = SLP.Address.detectAddressNetwork(address)
const isTestnet = slp.Address.detectAddressNetwork(address)
assert.equal(isTestnet, "testnet")
})
})
CASH_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a testnet address`, () => {
const isTestnet = SLP.Address.detectAddressNetwork(address)
const isTestnet = slp.Address.detectAddressNetwork(address)
assert.equal(isTestnet, "testnet")
})
})
SLP_TESTNET_ADDRESSES.forEach(address => {
it(`should detect ${address} is a testnet address`, () => {
const isTestnet = SLP.Address.detectAddressNetwork(address)
const isTestnet = slp.Address.detectAddressNetwork(address)
assert.equal(isTestnet, "testnet")
})
})
@@ -704,7 +712,7 @@ describe("#SLP Address", () => {
describe("#detectAddressType", () => {
TESTNET_P2PKH_ADDRESSES.forEach(address => {
it(`should detect ${address} is a p2pkh address`, () => {
const isp2pkh = SLP.Address.detectAddressType(address)
const isp2pkh = slp.Address.detectAddressType(address)
assert.equal(isp2pkh, "p2pkh")
})
})
@@ -713,7 +721,7 @@ describe("#SLP Address", () => {
describe("#detectAddressType", () => {
TESTNET_P2SH_ADDRESSES.forEach(address => {
it(`should detect ${address} is a p2sh address`, () => {
const isp2sh = SLP.Address.detectAddressType(address)
const isp2sh = slp.Address.detectAddressType(address)
assert.equal(isp2sh, "p2sh")
})
})
@@ -753,7 +761,7 @@ describe("#details", () => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
SLP.Address.details(
slp.Address.details(
"simpleledger:qr4zg7xth86yzq94gl8jvnf5z4wuupzt3gev5wtnm6"
)
.then(result => {
@@ -788,7 +796,7 @@ describe("#utxo", () => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
SLP.Address.utxo("simpleledger:qr4zg7xth86yzq94gl8jvnf5z4wuupzt3gev5wtnm6")
slp.Address.utxo("simpleledger:qr4zg7xth86yzq94gl8jvnf5z4wuupzt3gev5wtnm6")
.then(result => {
assert.deepEqual(
"467969e067f5612863d0bf2daaa70dede2c6be03abb6fd401c5ef6e1e1f1f5c5",
@@ -815,7 +823,7 @@ describe("#unconfirmed", () => {
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
SLP.Address.unconfirmed(
slp.Address.unconfirmed(
"simpleledger:qr4zg7xth86yzq94gl8jvnf5z4wuupzt3gev5wtnm6"
)
.then(result => {
@@ -828,7 +836,7 @@ describe("#unconfirmed", () => {
// (async () => {
// try {
// const details = await SLP.Address.unconfirmed(
// const details = await slp.Address.unconfirmed(
// "simpleledger:qr4zg7xth86yzq94gl8jvnf5z4wuupzt3gev5wtnm6"
// )
// console.log(details)
+12 -3
View File
@@ -1,10 +1,19 @@
const fixtures = require("./fixtures/slp/ecpair.json")
const assert = require("assert")
const SLP = require("../../src/slp/slp")
const slp = new SLP({ restURL: "http://fakeurl.com/" })
const fixtures = require("./fixtures/slp/ecpair.json")
const BCHJS = require("../../src/bch-js")
let slp
// const SLP = require("../../src/slp/slp")
// const slp = new SLP({ restURL: "http://fakeurl.com/" })
describe("#SLP ECPair", () => {
beforeEach(() => {
const bchjs = new BCHJS()
slp = bchjs.SLP
})
describe("#toSLPAddress", () => {
it(`should return slp address for ecpair`, async () => {
fixtures.wif.forEach((wif, index) => {
File diff suppressed because it is too large Load Diff
+718 -486
View File
File diff suppressed because it is too large Load Diff