Compare commits

..
57 Commits
Author SHA1 Message Date
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
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
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
Chris Troutner 37a5f0e6fa Merge pull request #37 from Permissionless-Software-Foundation/ct-unstable
feat(price): Added additional endpoints for retrieving market price o…
2020-10-19 19:40:51 -07:00
Chris Troutner 2180b14e1f feat(price): Added additional endpoints for retrieving market price of BCH 2020-10-19 19:36:55 -07:00
63 changed files with 3931 additions and 1021 deletions
+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)
+7 -7
View File
@@ -9,14 +9,14 @@
"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": "bash test/integration/test-bchn-integration.sh",
"test:integration:bchn": "bash test/integration/test-bchn-integration.sh",
"test:integration:abc": "RESTURL=https://abc.fullstack.cash/v3/ IS_USING_FREE_TIER=true mocha --timeout 30000 test/integration/",
"test:integration:testnet": "IS_USING_FREE_TIER=true 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:local:bchn": "RESTURL=http://localhost:3000/v3/ bash test/integration/test-free-tier-bchn.sh",
"test:integration:local:testnet": "RESTURL=http://localhost:4000/v3/ mocha --timeout 30000 test/integration/testnet",
"test:temp": "RESTURL=http://localhost:3000/v3/ mocha --timeout 30000 -g '#price' test/integration/",
"test:integration:api": "RESTURL=https://api.fullstack.cash/v3/ mocha --timeout 30000 test/integration",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"coverage:report": "nyc --reporter=html mocha --timeout 25000 test/unit/",
+17
View File
@@ -11,6 +11,23 @@ class Address {
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}`
}
}
}
}
/**
+20 -2
View File
@@ -55,9 +55,27 @@ 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}`)
@@ -90,7 +108,7 @@ class BCHJS {
this.Generating = new Generating(libConfig)
this.HDNode = new HDNode(this.Address)
this.Mnemonic = new Mnemonic(this.Address)
this.Price = new Price()
this.Price = new Price(libConfig)
this.Script = new Script()
this.TransactionBuilder = TransactionBuilder
this.TransactionBuilder.setAddress(this.Address)
+18 -243
View File
@@ -1,6 +1,10 @@
/*
This library interacts with the REST API endpoints in bch-api that communicate
with the Blockbook API.
CT 11/10/20
These endpoints will be soon be deprecated. Blockbook is being fazed out in
favor of Fulcrum.
*/
const axios = require("axios")
@@ -11,184 +15,28 @@ class Blockbook {
constructor(config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// console.log(`Blockbook apiToken: ${this.apiToken}`)
// 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
}
/**
* @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.
@@ -220,62 +68,6 @@ class Blockbook {
}
}
/**
* @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.
@@ -306,23 +98,6 @@ class Blockbook {
}
}
/**
* @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.
+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
+168 -22
View File
@@ -1,32 +1,178 @@
const axios = require("axios")
/**
* @api price.current() current()
* @apiName Price.
* @apiGroup Price
* @apiDescription Return current price of BCH in multiple currencies.
*
* @apiExample Example usage:
*(async () => {
* try {
* let current = await bchjs.Price.current('usd');
* console.log(current);
* } catch(error) {
* console.error(error)
* }
*})()
*
* // 26681
*/
let _this
class Price {
constructor(config) {
_this = this
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}`
}
}
}
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
*/
async current(currency = "usd") {
try {
const response = await axios.get(
const response = await this.axios.get(
`https://index-api.bitcoin.com/api/v0/cash/price/${currency.toLowerCase()}`
)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
return response.data.price
} catch (error) {
if (error.response && error.response.data) throw error.response.data
else throw error
} catch (err) {
if (err.response && err.response.data) throw err.response.data
else throw err
}
}
/**
* @api price.getUsd() getUsd()
* @apiName Price getUsd()
* @apiGroup Price
* @apiDescription Return current price of BCH in USD.
* This endpoint gets the USD price of BCH from the Coinbase 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.getUsd();
* console.log(current);
* } catch(err) {
* console.err(err)
* }
*})()
*
* // 266.81
*/
async getUsd() {
try {
const response = await this.axios.get(
`${this.restURL}price/usd`,
_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
}
}
/**
* @api price.rates() rates()
* @apiName Price rates()
* @apiGroup Price
* @apiDescription Return current price of BCH in several different currencies.
* This endpoint gets the price of BCH from the Coinbase API in many different
* currencies. 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.rates();
* console.log(current);
* } catch(err) {
* console.err(err)
* }
*})()
*
* {
* AED: "915.049218",
* AFN: "19144.48874646",
* ALGO: "826.6633482661356600405",
* ...
* ZRX: "644.844402797695193656",
* ZWL: "80215.03"
* }
*/
async rates() {
try {
const response = await this.axios.get(
`${this.restURL}price/rates`,
_this.axiosOptions
)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
return response.data
} catch (err) {
if (err.response && err.response.data) throw err.response.data
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
}
}
}
+16 -10
View File
@@ -6,11 +6,21 @@ 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}`
}
}
}
@@ -262,9 +272,7 @@ class RawTransactions {
txids: txid,
verbose: verbose
},
headers: {
authorization: `Token ${this.apiToken}`
}
headers: _this.axiosOptions.headers
}
const response = await axios(options)
@@ -337,9 +345,7 @@ class RawTransactions {
data: {
hexes: hex
},
headers: {
authorization: `Token ${this.apiToken}`
}
headers: _this.axiosOptions.headers
}
const response = await axios(options)
+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)
}
}
+18 -7
View File
@@ -18,17 +18,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)
@@ -426,7 +437,7 @@ class TokenType1 {
return slpSendObj
} catch (err) {
console.log(err)
// console.log(err)
throw err
}
}
+14 -4
View File
@@ -13,11 +13,21 @@ class Utils {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.slpParser = slpParser
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 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}`
}
}
}
+12 -5
View File
@@ -4,11 +4,18 @@
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 = `https://abc.fullstack.cash/v3/`
const RESTURL = `https://bchn.fullstack.cash/v3/`
// const RESTURL = `http://localhost:3000/v3/`
const BCHJS = require("../../../src/bch-js")
@@ -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/v3/`,
restURL: `https://abc.fullstack.cash/v3/`,
// restURL: `http://localhost:3000/v3/`,
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)
})
+16 -14
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,7 +14,7 @@
const assert = require("chai").assert
const JWT_TOKEN =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2YyMDIyMWMxMDAxMmFkOTQwMSIsImVtYWlsIjoiZGVtb0BkZW1vLmNvbSIsImFwaUxldmVsIjoxMCwicmF0ZUxpbWl0IjozLCJpYXQiOjE1OTA1Mjk2NzgsImV4cCI6MTU5MzEyMTY3OH0.4q5MFDCcVx0FusivJPiEIj3w8nhFG7ZV5IhJS7faUlc"
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2YyMDIyMWMxMDAxMmFkOTQwMSIsImVtYWlsIjoiZGVtb0BkZW1vLmNvbSIsImFwaUxldmVsIjoxMCwicmF0ZUxpbWl0IjozLCJpYXQiOjE2MDQ4NTQ2OTEsImV4cCI6MTYwNzQ0NjY5MX0.iwse0z0KDKHx9graCxcOwj6lSlfKQAb1zLhmjvygvts"
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({
@@ -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)
})
+27 -20
View File
@@ -1,20 +1,25 @@
/*
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: `https://bchn.fullstack.cash/v3/`,
restURL: `https:/abc.fullstack.cash/v3/`,
// restURL: `http://localhost:3000/v3/`,
apiToken: JWT_TOKEN
})
@@ -22,27 +27,28 @@ const bchjs = new BCHJS({
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)
})
+11 -10
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: `https://bchn.fullstack.cash/v3/`,
restURL: `https://abc.fullstack.cash/v3/`,
// restURL: `http://localhost:3000/v3/`,
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)
})
+331
View File
@@ -0,0 +1,331 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
TODO
- getMempoolEntry() only works on TXs in the mempool, so it needs to be part
of an e2e test to be properly tested.
*/
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(`#blockchain`, () => {
describe(`#getBestBlockHash`, () => {
it(`should GET best block hash`, async () => {
const result = await bchjs.Blockchain.getBestBlockHash()
//console.log(`result: ${util.inspect(result)}`)
assert.isString(result)
assert.equal(result.length, 64, "Specific hash length")
})
})
describe("#getBlockHeader", () => {
it(`should GET block header for a single hash`, async () => {
const hash =
"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"
const result = await bchjs.Blockchain.getBlockHeader(hash)
assert.hasAllKeys(result, [
"hash",
"confirmations",
"height",
"version",
"versionHex",
"merkleroot",
"time",
"mediantime",
"nonce",
"bits",
"difficulty",
"chainwork",
"previousblockhash",
"nextblockhash",
"nTx"
])
})
it(`should GET block headers for an array of hashes`, async () => {
const hash = [
"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201",
"00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3"
]
const result = await bchjs.Blockchain.getBlockHeader(hash)
assert.isArray(result)
assert.hasAllKeys(result[0], [
"hash",
"confirmations",
"height",
"version",
"versionHex",
"merkleroot",
"time",
"mediantime",
"nonce",
"bits",
"difficulty",
"chainwork",
"previousblockhash",
"nextblockhash",
"nTx"
])
})
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 = []
for (let i = 0; i < 25; i++) {
data.push(
"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"
)
}
const result = await bchjs.Blockchain.getBlockHeader(data)
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("#getMempoolEntry", () => {
/*
// To run this test, the txid must be unconfirmed.
const txid =
"defea04c38ee00cf73ad402984714ed22dc0dd99b2ae5cb50d791d94343ba79b"
it(`should GET single mempool entry`, async () => {
const result = await bchjs.Blockchain.getMempoolEntry(txid)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"size",
"fee",
"modifiedfee",
"time",
"height",
"startingpriority",
"currentpriority",
"descendantcount",
"descendantsize",
"descendantfees",
"ancestorcount",
"ancestorsize",
"ancestorfees",
"depends"
])
})
it(`should get an array of mempool entries`, async () => {
const result = await bchjs.Blockchain.getMempoolEntry([txid, txid])
console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"size",
"fee",
"modifiedfee",
"time",
"height",
"startingpriority",
"currentpriority",
"descendantcount",
"descendantsize",
"descendantfees",
"ancestorcount",
"ancestorsize",
"ancestorfees",
"depends"
])
})
*/
it(`should throw an error if txid is not in mempool`, async () => {
try {
const txid =
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
await bchjs.Blockchain.getMempoolEntry(txid)
assert.equal(true, false, "Unexpected result!")
} catch (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`
)
}
})
})
describe(`#getTxOutProof`, () => {
it(`should get single tx out proof`, async () => {
const txid =
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
const result = await bchjs.Blockchain.getTxOutProof(txid)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isString(result)
})
it(`should get an array of tx out proofs`, async () => {
const txid = [
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7",
"fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"
]
const result = await bchjs.Blockchain.getTxOutProof(txid)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
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`, () => {
const mockTxOutProof =
"0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01"
it(`should verify a single proof`, async () => {
const result = await bchjs.Blockchain.verifyTxOutProof(mockTxOutProof)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
assert.equal(
result[0],
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
)
})
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)}`)
assert.isArray(result)
assert.isString(result[0])
assert.equal(
result[0],
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
)
})
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 = []
for (let i = 0; i < 25; i++) data.push(mockTxOutProof)
const result = await bchjs.Blockchain.verifyTxOutProof(data)
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("#getTxOut", () => {
it("should get information on an unspent tx", async () => {
const result = await bchjs.Blockchain.getTxOut(
"62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8",
0,
true
)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
"bestblock",
"confirmations",
"value",
"scriptPubKey",
"coinbase"
])
})
it("should get information on a spent tx", async () => {
const result = await bchjs.Blockchain.getTxOut(
"87380e52d151856b23173d6d8a3db01b984c6b50f77ea045a5a1cf4f54497871",
0,
true
)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.equal(result, null)
})
})
})
+19
View File
@@ -0,0 +1,19 @@
/*
Integration tests for bchjs control library.
*/
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS()
describe(`#control`, () => {
describe(`#getNetworkInfo`, () => {
it("should get info on the full node", async () => {
const result = await bchjs.Control.getNetworkInfo()
console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "version")
})
})
})
+356
View File
@@ -0,0 +1,356 @@
const chai = require("chai")
const assert = chai.assert
const sinon = require("sinon")
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS()
describe(`#ElectrumX`, () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
describe(`#utxo`, () => {
it(`should GET utxos for a single address`, async () => {
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
const result = await bchjs.Electrumx.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.isArray(result.utxos)
assert.property(result.utxos[0], "height")
assert.property(result.utxos[0], "tx_hash")
assert.property(result.utxos[0], "tx_pos")
assert.property(result.utxos[0], "value")
})
it(`should POST request for UTXOs for an array of addresses`, async () => {
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
]
const result = await bchjs.Electrumx.utxo(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.isArray(result.utxos)
assert.property(result.utxos[0], "utxos")
assert.isArray(result.utxos[0].utxos)
assert.property(result.utxos[0], "address")
assert.property(result.utxos[0].utxos[0], "height")
assert.property(result.utxos[0].utxos[0], "tx_hash")
assert.property(result.utxos[0].utxos[0], "tx_pos")
assert.property(result.utxos[0].utxos[0], "value")
})
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.Electrumx.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(`#balance`, () => {
it(`should GET balance for a single address`, async () => {
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "balance")
assert.property(result.balance, "confirmed")
assert.property(result.balance, "unconfirmed")
})
it(`should POST request for balances for an array of addresses`, async () => {
const addr = [
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
]
const result = await bchjs.Electrumx.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "balances")
assert.isArray(result.balances)
assert.property(result.balances[0], "address")
assert.property(result.balances[0], "balance")
assert.property(result.balances[0].balance, "confirmed")
assert.property(result.balances[0].balance, "unconfirmed")
})
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.Electrumx.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(`#transactions`, () => {
it(`should GET transaction history for a single address`, async () => {
const addr = "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
const result = await bchjs.Electrumx.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "transactions")
assert.isArray(result.transactions)
assert.property(result.transactions[0], "height")
assert.property(result.transactions[0], "tx_hash")
})
it(`should POST request for transaction history for an array of addresses`, async () => {
const addr = [
"bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj",
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
]
const result = await bchjs.Electrumx.transactions(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "transactions")
assert.isArray(result.transactions)
assert.property(result.transactions[0], "address")
assert.property(result.transactions[0], "transactions")
assert.isArray(result.transactions[0].transactions)
assert.property(result.transactions[0].transactions[0], "height")
assert.property(result.transactions[0].transactions[0], "tx_hash")
})
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0")
const result = await bchjs.Electrumx.transactions(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(`#unconfirmed`, () => {
// These tests won't work because unconfirmed transactions are transient in nature.
/*
it(`should GET unconfirmed UTXOs (mempool) for a single address`, async () => {
const addr = "bitcoincash:qqy6qwk3wpne95hhv8uzwr4cn8m7c06cqgchl77dnv"
const result = await bchjs.Electrumx.unconfirmed(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.isArray(result.utxos)
assert.property(result.utxos[0], "height")
assert.property(result.utxos[0], "tx_hash")
assert.property(result.utxos[0], "fee")
})
it(`should POST request for unconfirmed UTXOs (mempool) for an array of addresses`, async () => {
const addr = [
"bitcoincash:qqy6qwk3wpne95hhv8uzwr4cn8m7c06cqgchl77dnv",
"bitcoincash:qpyrtsl9msdu2klgfpcmn2v5r22w9rk24g8pal74ts"
]
const result = await bchjs.Electrumx.unconfirmed(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "utxos")
assert.isArray(result.utxos)
assert.property(result.utxos[0], "utxos")
assert.isArray(result.utxos[0].utxos)
assert.property(result.utxos[0], "address")
assert.property(result.utxos[0].utxos[0], "height")
assert.property(result.utxos[0].utxos[0], "tx_hash")
assert.property(result.utxos[0].utxos[0], "fee")
})
*/
it(`should throw error on array size rate limit`, async () => {
try {
const addr = []
for (let i = 0; i < 25; i++)
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
await bchjs.Electrumx.unconfirmed(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(`#blockHeader`, () => {
it(`should GET block headers for given height and count`, async () => {
const height = 42
const count = 2
const result = await bchjs.Electrumx.blockHeader(height, count)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "headers")
assert.isArray(result.headers)
assert.equal(result.headers.length, 2)
})
it(`should GET block headers for given height with default count = 1`, async () => {
const height = 42
const result = await bchjs.Electrumx.blockHeader(height)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "headers")
assert.isArray(result.headers)
assert.equal(result.headers.length, 1)
})
})
describe(`#txData`, () => {
it(`should GET details for a single transaction`, async () => {
const txid =
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
const result = await bchjs.Electrumx.txData(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "details")
assert.isObject(result.details)
assert.property(result.details, "blockhash")
assert.property(result.details, "hash")
assert.property(result.details, "hex")
assert.property(result.details, "vin")
assert.property(result.details, "vout")
assert.equal(result.details.hash, txid)
})
it(`should POST details for an array of transactions`, async () => {
const txids = [
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
]
const result = await bchjs.Electrumx.txData(txids)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "transactions")
assert.isArray(result.transactions)
assert.property(result.transactions[0], "txid")
assert.property(result.transactions[0], "details")
assert.property(result.transactions[0].details, "blockhash")
assert.property(result.transactions[0].details, "hash")
assert.property(result.transactions[0].details, "hex")
assert.property(result.transactions[0].details, "vin")
assert.property(result.transactions[0].details, "vout")
})
it(`should throw error on array size rate limit`, async () => {
try {
const txids = []
for (let i = 0; i < 25; i++) {
txids.push(
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
)
}
await bchjs.Electrumx.txData(txids)
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(`#broadcast`, () => {
it(`should broadcast a single transaction`, async () => {
const txHex =
"020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000"
try {
await bchjs.Electrumx.broadcast(txHex)
} catch (err) {
assert.property(err, "success")
assert.equal(err.success, false)
assert.include(
err.error,
"the transaction was rejected by network rules"
)
}
})
})
})
+31
View File
@@ -0,0 +1,31 @@
const assert = require("chai").assert
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS()
describe("#Encryption", () => {
describe("#getPubKey", () => {
it("should get a public key", async () => {
const addr = "bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq"
const result = await bchjs.encryption.getPubKey(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, true)
assert.property(result, "publicKey")
})
it("should report when public key can not be found", async () => {
const addr = "bitcoincash:qrgqqkky28jdkv3w0ctrah0mz3jcsnsklc34gtukrh"
const result = await bchjs.encryption.getPubKey(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "success")
assert.equal(result.success, false)
assert.property(result, "publicKey")
assert.equal(result.publicKey, "not found")
})
})
})
+129
View File
@@ -0,0 +1,129 @@
const chai = require("chai")
const assert = chai.assert
const sinon = require("sinon")
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS({ ninsightURL: "https://rest.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 = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
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 = [
"bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7",
"bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr"
]
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")
})
})
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], "isCoinBase")
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")
})
})
})
+117
View File
@@ -0,0 +1,117 @@
/*
tests for OpenBazaar library.
*/
const chai = require("chai")
const assert = chai.assert
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS()
describe(`#OpenBazaar`, () => {
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"
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)
})
})
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"
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"
])
})
})
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"
const result = await bchjs.OpenBazaar.tx(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
"txid",
"version",
"vin",
"vout",
"blockhash",
"blockheight",
"confirmations",
"blocktime",
"valueOut",
"valueIn",
"fees",
"hex",
"time"
])
assert.isArray(result.vin)
assert.isArray(result.vout)
})
})
})
+42
View File
@@ -0,0 +1,42 @@
const assert = require("chai").assert
const BCHJS = require("../../../src/bch-js")
const bchjs = new BCHJS()
describe("#price", () => {
describe("#current", () => {
describe("#single currency", () => {
it("should get current price for single currency", async () => {
const result = await bchjs.Price.current("usd")
assert.notEqual(0, result)
})
})
})
describe("#getUsd", () => {
it("should get the USD price of BCH", async () => {
const result = await bchjs.Price.getUsd()
// console.log(result)
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")
})
})
})
+329
View File
@@ -0,0 +1,329 @@
/*
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", () => {
describe("#decodeRawTransaction", () => {
it("should decode tx for a single hex", async () => {
const hex =
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
const result = await bchjs.RawTransactions.decodeRawTransaction(hex)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"txid",
"hash",
"size",
"version",
"locktime",
"vin",
"vout"
])
assert.isArray(result.vin)
assert.isArray(result.vout)
})
it("should decode an array of tx hexes", async () => {
const hexes = [
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000",
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
]
const result = await bchjs.RawTransactions.decodeRawTransaction(hexes)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"txid",
"hash",
"size",
"version",
"locktime",
"vin",
"vout"
])
assert.isArray(result[0].vin)
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 = []
for (let i = 0; i < 25; i++) {
data.push(
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
)
}
const result = await bchjs.RawTransactions.decodeRawTransaction(data)
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("#getRawTransaction", () => {
it("should decode a single txid, with concise output", async () => {
const txid =
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1"
const verbose = false
const result = await bchjs.RawTransactions.getRawTransaction(
txid,
verbose
)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isString(result)
})
it("should decode a single txid, with verbose output", async () => {
const txid =
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1"
const verbose = true
const result = await bchjs.RawTransactions.getRawTransaction(
txid,
verbose
)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"hex",
"txid",
"hash",
"size",
"version",
"locktime",
"vin",
"vout",
"blockhash",
"confirmations",
"time",
"blocktime"
])
assert.isArray(result.vin)
assert.isArray(result.vout)
})
it("should decode an array of txids, with a concise output", async () => {
const txid = [
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1",
"b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f"
]
const verbose = false
const result = await bchjs.RawTransactions.getRawTransaction(
txid,
verbose
)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.isString(result[0])
})
it("should decode an array of txids, with a verbose output", async () => {
const txid = [
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1",
"b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f"
]
const verbose = true
const result = await bchjs.RawTransactions.getRawTransaction(
txid,
verbose
)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"hex",
"txid",
"hash",
"size",
"version",
"locktime",
"vin",
"vout",
"blockhash",
"confirmations",
"time",
"blocktime"
])
assert.isArray(result[0].vin)
assert.isArray(result[0].vout)
})
it(`should throw error on array size rate limit`, async () => {
try {
const dataMock =
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1"
const data = []
for (let i = 0; i < 25; i++) data.push(dataMock)
const result = await bchjs.RawTransactions.getRawTransaction(data)
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("#decodeScript", () => {
it("should decode script for a single hex", async () => {
const hex =
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
const result = await bchjs.RawTransactions.decodeScript(hex)
//console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ["asm", "type", "p2sh"])
})
// CT 2/20/19 - Waiting for this PR to be merged complete the test:
// https://github.com/Bitcoin-com/rest.bitcoin.com/pull/312
/*
it("should decode an array of tx hexes", async () => {
const hexes = [
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16",
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
]
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.`
)
}
})
*/
})
/*
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.fail("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)}`)
assert.fail("Unexpected result!")
} 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 =
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
const data = []
for (let i = 0; i < 25; i++) data.push(dataMock)
const result = await bchjs.RawTransactions.sendRawTransaction(data)
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")
}
})
})
})
+700
View File
@@ -0,0 +1,700 @@
/*
Integration tests for the bchjs covering SLP tokens.
*/
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.
await sleep(1000)
bchjs = new BCHJS()
})
describe("#util", () => {
describe("#list", () => {
it(`should get information on the Spice token`, async () => {
const tokenId = `4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf`
const result = await bchjs.SLP.Utils.list(tokenId)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"decimals",
"timestamp",
"timestamp_unix",
"versionType",
"documentUri",
"symbol",
"name",
"containsBaton",
"id",
"documentHash",
"initialTokenQty",
"blockCreated",
"blockLastActiveSend",
"blockLastActiveMint",
"txnsSinceGenesis",
"validAddress",
"totalMinted",
"totalBurned",
"circulatingSupply",
"mintingBatonStatus"
])
})
})
// describe("#decodeOpReturn", () => {
// it("should decode the OP_RETURN for a SEND txid", async () => {
// const txid =
// "266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1"
//
// const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.hasAllKeys(result, [
// "tokenType",
// "transactionType",
// "tokenId",
// "spendData"
// ])
// })
//
// it("should decode the OP_RETURN for a GENESIS txid", async () => {
// const txid =
// "497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
//
// const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.hasAllKeys(result, [
// "tokenType",
// "transactionType",
// "ticker",
// "name",
// "documentUrl",
// "documentHash",
// "decimals",
// "mintBatonVout",
// "initialQty",
// "tokensSentTo",
// "batonHolder"
// ])
// })
//
// it("should decode the OP_RETURN for a MINT txid", async () => {
// const txid =
// "65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4"
//
// const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
//
// assert.hasAllKeys(result, [
// "tokenType",
// "transactionType",
// "tokenId",
// "mintBatonVout",
// "batonStillExists",
// "quantity",
// "tokensSentTo",
// "batonHolder"
// ])
// })
//
// it("should throw an error for a non-SLP transaction", async () => {
// try {
// const txid =
// "3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec"
//
// await bchjs.SLP.Utils.decodeOpReturn(txid)
//
// assert.equal(true, false, "Unexpected result")
// } catch (err) {
// // console.log(`err: `, err)
// assert.include(err.message, "Not an OP_RETURN")
// }
// })
// })
describe("#decodeOpReturn", () => {
it("should decode the OP_RETURN for a SEND txid", async () => {
const txid =
"266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1"
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ["tokenType", "txType", "tokenId", "amounts"])
assert.equal(
result.tokenId,
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
)
// Verify outputs
assert.equal(result.amounts.length, 2)
assert.equal(result.amounts[0], "100000000")
assert.equal(result.amounts[1], "99883300000000")
})
it("should decode the OP_RETURN for a GENESIS txid", async () => {
const txid =
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
"tokenType",
"txType",
"tokenId",
"ticker",
"name",
"documentUri",
"documentHash",
"decimals",
"mintBatonVout",
"qty"
])
assert.equal(
result.tokenId,
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
)
assert.equal(result.txType, "GENESIS")
assert.equal(result.ticker, "TOK-CH")
assert.equal(result.name, "TokyoCash")
})
it("should decode the OP_RETURN for a MINT txid", async () => {
const txid =
"65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4"
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, [
"tokenType",
"txType",
"tokenId",
"mintBatonVout",
"qty"
])
})
it("should throw an error for a non-SLP transaction", async () => {
try {
const txid =
"3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec"
await bchjs.SLP.Utils.decodeOpReturn(txid)
assert.equal(true, false, "Unexpected result")
} catch (err) {
// console.log(`err: `, err)
assert.include(err.message, "scriptpubkey not op_return")
}
})
// Note: This TX is interpreted as valid by the original decodeOpReturn().
// Fixing this issue and related issues was the reason for creating the
// decodeOpReturn2() method using the slp-parser library.
it("should throw error for invalid SLP transaction", async () => {
try {
const txid =
"a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415"
await bchjs.SLP.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
} catch (err) {
// console.log(`err: `, err)
assert.include(err.message, "amount string size not 8 bytes")
}
})
})
describe("#tokenUtxoDetails", () => {
// // This captures an important corner-case. When an SLP token is created, the
// // change UTXO will contain the same SLP txid, but it is not an SLP UTXO.
it("should return details on minting baton from genesis transaction", async () => {
const utxos = [
{
txid:
"bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90",
vout: 3,
amount: 0.00002015,
satoshis: 2015,
height: 594892,
confirmations: 5
},
{
txid:
"bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90",
vout: 2,
amount: 0.00000546,
satoshis: 546,
height: 594892,
confirmations: 5
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.equal(data[0].isValid, false, "Change UTXO marked as false.")
assert.property(data[1], "txid")
assert.property(data[1], "vout")
assert.property(data[1], "amount")
assert.property(data[1], "satoshis")
assert.property(data[1], "height")
assert.property(data[1], "confirmations")
assert.property(data[1], "utxoType")
assert.property(data[1], "tokenId")
assert.property(data[1], "tokenTicker")
assert.property(data[1], "tokenName")
assert.property(data[1], "tokenDocumentUrl")
assert.property(data[1], "tokenDocumentHash")
assert.property(data[1], "decimals")
assert.property(data[1], "isValid")
assert.equal(data[1].isValid, true)
})
it("should return details for a MINT token utxo", async () => {
// Mock the call to REST API
const utxos = [
{
txid:
"cf4b922d1e1aa56b52d752d4206e1448ea76c3ebe69b3b97d8f8f65413bd5c76",
vout: 1,
amount: 0.00000546,
satoshis: 546,
height: 600297,
confirmations: 76
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.property(data[0], "txid")
assert.property(data[0], "vout")
assert.property(data[0], "amount")
assert.property(data[0], "satoshis")
assert.property(data[0], "height")
assert.property(data[0], "confirmations")
assert.property(data[0], "utxoType")
assert.property(data[0], "transactionType")
assert.property(data[0], "tokenId")
assert.property(data[0], "tokenTicker")
assert.property(data[0], "tokenName")
assert.property(data[0], "tokenDocumentUrl")
assert.property(data[0], "tokenDocumentHash")
assert.property(data[0], "decimals")
assert.property(data[0], "mintBatonVout")
assert.property(data[0], "tokenQty")
assert.property(data[0], "isValid")
assert.equal(data[0].isValid, true)
})
it("should return details for a simple SEND SLP token utxo", async () => {
const utxos = [
{
txid:
"fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb",
vout: 1,
amount: 0.00000546,
satoshis: 546,
height: 596089,
confirmations: 748
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.property(data[0], "txid")
assert.property(data[0], "vout")
assert.property(data[0], "amount")
assert.property(data[0], "satoshis")
assert.property(data[0], "height")
assert.property(data[0], "confirmations")
assert.property(data[0], "utxoType")
assert.property(data[0], "tokenId")
assert.property(data[0], "tokenTicker")
assert.property(data[0], "tokenName")
assert.property(data[0], "tokenDocumentUrl")
assert.property(data[0], "tokenDocumentHash")
assert.property(data[0], "decimals")
assert.property(data[0], "tokenQty")
assert.property(data[0], "isValid")
assert.equal(data[0].isValid, true)
})
it("should handle BCH and SLP utxos in the same TX", async () => {
const utxos = [
{
txid:
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
vout: 3,
value: "6816",
height: 606848,
confirmations: 13,
satoshis: 6816
},
{
txid:
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
vout: 2,
value: "546",
height: 606848,
confirmations: 13,
satoshis: 546
}
]
const result = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result.length, 2)
assert.equal(result[0].isValid, false)
assert.equal(result[1].isValid, true)
})
it("should handle problematic utxos", async () => {
const utxos = [
{
txid:
"0e3a217fc22612002031d317b4cecd9b692b66b52951a67b23c43041aefa3959",
vout: 0,
amount: 0.00018362,
satoshis: 18362,
height: 613483,
confirmations: 124
},
{
txid:
"67fd3c7c3a6eb0fea9ab311b91039545086220f7eeeefa367fa28e6e43009f19",
vout: 1,
amount: 0.00000546,
satoshis: 546,
height: 612075,
confirmations: 1532
}
]
const result = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.equal(result.length, 2)
assert.equal(result[0].isValid, false)
assert.equal(result[1].isValid, true)
})
it("should return false for BCH-only UTXOs", async () => {
const utxos = [
{
txid:
"a937f792c7c9eb23b4f344ce5c233d1ac0909217d0a504d71e6b1e4efb864a3b",
vout: 0,
amount: 0.00001,
satoshis: 1000,
confirmations: 0,
ts: 1578424704
},
{
txid:
"53fd141c2e999e080a5860887441a2c45e9cbe262027e2bd2ac998fc76e43c44",
vout: 0,
amount: 0.00001,
satoshis: 1000,
confirmations: 0,
ts: 1578424634
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.isArray(data)
assert.equal(data[0].isValid, false)
assert.equal(data[1].isValid, false)
})
it("should handle a dust attack", async () => {
// it("#dustattack", async () => {
const utxos = [
{
height: 655965,
tx_hash:
"a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e",
tx_pos: 151,
value: 547,
satoshis: 547,
txid:
"a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e",
vout: 151,
address: "bitcoincash:qq4dw3sm8qvglspy6w2qg0u2ugsy9zcfcqrpeflwww",
hdIndex: 11
}
]
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.equal(data[0].isValid, false)
})
})
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"
)
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
assert.isArray(balances)
assert.hasAllKeys(balances[0], [
"tokenId",
"balanceString",
"balance",
"decimalCount",
"slpAddress"
])
})
it(`should fetch balances for multiple addresses`, async () => {
const addresses = [
"simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9",
"simpleledger:qqss4zp80hn6szsa4jg2s9fupe7g5tcg5ucdyl3r57"
]
const balances = await bchjs.SLP.Utils.balancesForAddress(addresses)
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
assert.isArray(balances)
assert.isArray(balances[0])
assert.hasAllKeys(balances[0][0], [
"tokenId",
"balanceString",
"balance",
"decimalCount",
"slpAddress"
])
})
})
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 = [
{
utxos: [
{
txid:
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
vout: 3,
value: "6816",
height: 606848,
confirmations: 13,
satoshis: 6816
},
{
txid:
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
vout: 2,
value: "546",
height: 606848,
confirmations: 13,
satoshis: 546
}
]
}
]
const result = await bchjs.SLP.Utils.hydrateUtxos(utxos)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Test the general structure of the output.
assert.isArray(result.slpUtxos)
assert.equal(result.slpUtxos.length, 1)
assert.equal(result.slpUtxos[0].utxos.length, 2)
// Test the non-slp UTXO.
assert.property(result.slpUtxos[0].utxos[0], "txid")
assert.property(result.slpUtxos[0].utxos[0], "vout")
assert.property(result.slpUtxos[0].utxos[0], "value")
assert.property(result.slpUtxos[0].utxos[0], "height")
assert.property(result.slpUtxos[0].utxos[0], "confirmations")
assert.property(result.slpUtxos[0].utxos[0], "satoshis")
assert.property(result.slpUtxos[0].utxos[0], "isValid")
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
// Test the slp UTXO.
assert.property(result.slpUtxos[0].utxos[1], "txid")
assert.property(result.slpUtxos[0].utxos[1], "vout")
assert.property(result.slpUtxos[0].utxos[1], "value")
assert.property(result.slpUtxos[0].utxos[1], "height")
assert.property(result.slpUtxos[0].utxos[1], "confirmations")
assert.property(result.slpUtxos[0].utxos[1], "satoshis")
assert.property(result.slpUtxos[0].utxos[1], "isValid")
assert.equal(result.slpUtxos[0].utxos[1].isValid, true)
assert.property(result.slpUtxos[0].utxos[1], "transactionType")
assert.property(result.slpUtxos[0].utxos[1], "tokenId")
assert.property(result.slpUtxos[0].utxos[1], "tokenTicker")
assert.property(result.slpUtxos[0].utxos[1], "tokenName")
assert.property(result.slpUtxos[0].utxos[1], "tokenDocumentUrl")
assert.property(result.slpUtxos[0].utxos[1], "tokenDocumentHash")
assert.property(result.slpUtxos[0].utxos[1], "decimals")
assert.property(result.slpUtxos[0].utxos[1], "tokenType")
assert.property(result.slpUtxos[0].utxos[1], "tokenQty")
})
it("should process data directly from Electrumx", async () => {
const addrs = [
"bitcoincash:qqnt53cfw990u6y38xgezm0lfa8hknw0wueezcpagp",
"bitcoincash:qrh3qgtax6adegzc7zxm6m4sgrv9wq28yqnfn33ce5",
"bitcoincash:qqcaee5w4ws77n8s2gzy6fwtma6uxd7ctq8553e495"
]
const utxos = await bchjs.Electrumx.utxo(addrs)
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
const result = await bchjs.SLP.Utils.hydrateUtxos(utxos.utxos)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
// Test the general structure of the output.
assert.isArray(result.slpUtxos)
assert.equal(result.slpUtxos.length, 3)
assert.equal(result.slpUtxos[0].utxos.length, 1)
assert.equal(result.slpUtxos[1].utxos.length, 1)
assert.equal(result.slpUtxos[2].utxos.length, 2)
try {
// Test the expected values.
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
assert.equal(result.slpUtxos[1].utxos[0].isValid, true)
assert.equal(result.slpUtxos[1].utxos[0].tokenTicker, "TROUT")
assert.equal(result.slpUtxos[2].utxos[0].isValid, false)
assert.equal(result.slpUtxos[2].utxos[1].isValid, true)
assert.equal(result.slpUtxos[2].utxos[1].tokenTicker, "VALENTINE")
} catch (err) {
console.error(
'The hydrateUtxos call may hitting rate limits, or SLPDB may be having issues if "isValid" results are "null"'
)
console.log("Error: ", err)
}
})
})
describe("#validateTxid2", () => {
it("should invalidate a known invalid TXID", async () => {
const txid =
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a"
const result = await bchjs.SLP.Utils.validateTxid2(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "txid")
assert.equal(result.txid, txid)
assert.property(result, "isValid")
assert.equal(result.isValid, false)
})
it("should validate a known valid TXID", async () => {
const txid =
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488"
const result = await bchjs.SLP.Utils.validateTxid2(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "txid")
assert.equal(result.txid, txid)
assert.property(result, "isValid")
assert.equal(result.isValid, true)
})
})
})
describe("#tokentype1", () => {
describe("#getHexOpReturn", () => {
it("should return OP_RETURN object ", async () => {
const tokenUtxos = [
{
tokenId:
"0a321bff9761f28e06a268b14711274bb77617410a16807bd0437ef234a072b1",
decimals: 0,
tokenQty: 2
}
]
const sendQty = 1.5
const result = await bchjs.SLP.TokenType1.getHexOpReturn(
tokenUtxos,
sendQty
)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, "script")
assert.isString(result.script)
assert.property(result, "outputs")
assert.isNumber(result.outputs)
})
})
})
})
// Promise-based sleep function
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+109
View File
@@ -0,0 +1,109 @@
/*
Integration tests for the bchjs. Only covers calls made to
rest.bitcoin.com.
*/
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(`#util`, () => {
describe(`#validateAddress`, () => {
it(`should return false for testnet addr on mainnet`, async () => {
const address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
const result = await bchjs.Util.validateAddress(address)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ["isvalid"])
assert.equal(result.isvalid, false)
})
it(`should return false for bad address`, async () => {
const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peu`
const result = await bchjs.Util.validateAddress(address)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAllKeys(result, ["isvalid"])
assert.equal(result.isvalid, false)
})
it(`should validate valid address`, async () => {
const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`
const result = await bchjs.Util.validateAddress(address)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.hasAnyKeys(result, [
"isvalid",
"address",
"scriptPubKey",
//"ismine",
//"iswatchonly",
"isscript"
])
assert.equal(result.isvalid, true)
})
it(`should validate an array of addresses`, async () => {
const address = [
`bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`,
`bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`
]
const result = await bchjs.Util.validateAddress(address)
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result)
assert.hasAnyKeys(result[0], [
"isvalid",
"address",
"scriptPubKey",
//"ismine",
//"iswatchonly",
"isscript"
])
})
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`
const data = []
for (let i = 0; i < 25; i++) data.push(dataMock)
const result = await bchjs.Util.validateAddress(data)
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 -30
View File
@@ -18,6 +18,10 @@ util.inspect.defaultOptions = {
}
describe(`#Blockbook`, () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe(`#Balance`, () => {
it(`should GET balance for a single address`, async () => {
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
@@ -67,21 +71,6 @@ describe(`#Blockbook`, () => {
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 = []
@@ -136,21 +125,6 @@ describe(`#Blockbook`, () => {
])
})
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 = []
@@ -168,3 +142,7 @@ describe(`#Blockbook`, () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+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))
}
+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))
}
+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))
}
+37 -1
View File
@@ -1,8 +1,12 @@
const assert = require("assert")
const assert = require("chai").assert
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 () => {
@@ -11,4 +15,36 @@ describe("#price", () => {
})
})
})
describe("#getUsd", () => {
it("should get the USD price of BCH", async () => {
const result = await bchjs.Price.getUsd()
// console.log(result)
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))
}
+10 -48
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.`
)
}
})
*/
})
@@ -271,7 +244,7 @@ describe("#rawtransaction", () => {
//console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "Missing inputs")
assert.include(err.error, "bad-txns-inputs-missingorspent (code 16)")
}
})
@@ -288,22 +261,7 @@ describe("#rawtransaction", () => {
// 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`
)
assert.include(err.error, "bad-txns-inputs-missingorspent (code 16)")
}
})
@@ -325,3 +283,7 @@ describe("#rawtransaction", () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+4 -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()
})
@@ -466,22 +466,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: simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9`, async () => {
const balances = await bchjs.SLP.Utils.balancesForAddress(
"simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9"
@@ -520,19 +504,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 +570,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)
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
export RESTURL=https://bchn.fullstack.cash/v3/
#export RESTURL=http://localhost:3000/v3/
#export IS_USING_FREE_TIER=true
cd test/integration/bchn/
mocha --timeout 30000 blockchain.js control.js encryption.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://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
+10 -2
View File
@@ -8,7 +8,7 @@ const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
: `https://testnet3.fullstack.cash/v3/`
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
@@ -26,6 +26,10 @@ util.inspect.defaultOptions = {
}
describe(`#Blockbook`, () => {
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
})
describe(`#Balance`, () => {
it(`should GET balance for a single address`, async () => {
const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
@@ -165,7 +169,7 @@ describe(`#Blockbook`, () => {
for (let i = 0; i < 25; i++)
addr.push("bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2")
const result = await bchjs.Blockbook.utxo(addr)
await bchjs.Blockbook.utxo(addr)
//console.log(`result: ${util.inspect(result)}`)
assert.equal(true, false, "Unexpected result!")
@@ -176,3 +180,7 @@ describe(`#Blockbook`, () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+29 -77
View File
@@ -12,7 +12,7 @@ const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
: "https://testnet3.fullstack.cash/v3/"
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
@@ -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))
}
+9 -1
View File
@@ -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/v3/`
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))
}
+25 -7
View File
@@ -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/v3/`
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))
}
+82 -1
View File
@@ -7,7 +7,13 @@ const bchjs = new BCHJS({ ninsightURL: "https://trest.bitcoin.com/v2" })
describe(`#Ninsight`, () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
beforeEach(async () => {
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
sandbox = sinon.createSandbox()
})
afterEach(() => sandbox.restore())
describe(`#utxo`, () => {
@@ -62,4 +68,79 @@ describe(`#Ninsight`, () => {
// ])
})
})
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))
}
-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)
// })
})
})
+11 -49
View File
@@ -10,7 +10,7 @@ const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
: `https://testnet3.fullstack.cash/v3/`
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
@@ -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.`
)
}
})
*/
})
@@ -278,7 +251,7 @@ describe("#rawtransaction", () => {
//console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ["error"])
assert.include(err.error, "Missing inputs")
assert.include(err.error, "bad-txns-inputs-missingorspent (code 16)")
}
})
@@ -295,22 +268,7 @@ describe("#rawtransaction", () => {
// 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`
)
assert.include(err.error, "bad-txns-inputs-missingorspent (code 16)")
}
})
@@ -332,3 +290,7 @@ describe("#rawtransaction", () => {
})
})
})
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
+2 -18
View File
@@ -7,7 +7,7 @@ const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
: `https://testnet3.fullstack.cash/v3/`
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
@@ -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") {
+2 -2
View File
@@ -2,8 +2,8 @@
export RESTURL=https://free-test.fullstack.cash/v3/
export NETWORK=testnet
#export RESTURL=http://localhost:3000/v3/
export IS_USING_FREE_TIER=true
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 control.js electrumx.js rawtransaction.js slp.js util.js
#mocha --timeout 30000 blockchain.js
+9 -16
View File
@@ -8,7 +8,7 @@ const assert = chai.assert
const RESTURL = process.env.RESTURL
? process.env.RESTURL
: `https://tapi.fullstack.cash/v3/`
: `https://testnet3.fullstack.cash/v3/`
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
const BCHJS = require("../../../src/bch-js")
@@ -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 -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))
}
-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"
])
})
})
+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
}
+214
View File
@@ -0,0 +1,214 @@
/*
Mocks for price.
*/
const mockRates = {
AED: "915.049218",
AFN: "19144.48874646",
ALGO: "826.6633482661356600405",
ALL: "26221.96098759",
AMD: "119977.82663822",
ANG: "446.841810455",
AOA: "162269.774275",
ARS: "19322.704621",
ATOM: "45.5920571010248851205",
AUD: "353.78913716",
AWG: "448.407",
AZN: "424.1182875",
BAL: "18.9361216125975755781",
BAM: "413.75759465",
BAND: "40.84187228461349099275",
BAT: "1169.75444148879972951",
BBD: "498.23",
BCH: "1.0",
BDT: "21107.92000745",
BGN: "413.93197515",
BHD: "93.93578597",
BIF: "481540.76228735",
BMD: "249.115",
BND: "337.84677362",
BOB: "1718.851399565",
BRL: "1396.737982",
BSD: "249.115",
BSV: "1.555324933590611026515",
BTC: "0.021265",
BTN: "18249.513962505",
BWP: "2848.17713393",
BYN: "637.963336685",
BYR: "6379633.36685000049823",
BZD: "501.752236985",
CAD: "328.80838319",
CDF: "488848.679106575",
CGLD: "121.0412516398620018305",
CHF: "226.8989243",
CLF: "7.110489445",
CLP: "196202.978234955",
CNH: "1664.25510705",
CNY: "1666.429881",
COMP: "2.4706436576415750709",
COP: "958730.858397465",
CRC: "150173.845981",
CUC: "248.997666835",
CVE: "23541.3675",
CZK: "5770.848621",
DAI: "247.0463573269230002455",
DASH: "3.327367317363110236645",
DJF: "44315.31795969",
DKK: "1575.7370741",
DOP: "14529.76988648",
DZD: "32107.28592277",
EEK: "3640.489633465",
EGP: "3911.404438",
EOS: "96.6873665825732601419",
ERN: "3736.727740265",
ETB: "9302.454572035",
ETC: "44.91795888928957612395",
ETH: "0.6574429621419051422355",
EUR: "211.595",
FJD: "533.11855575",
FKP: "192.55642863",
GBP: "192.87",
GEL: "804.64145",
GGP: "192.55642863",
GHS: "1448.776859925",
GIP: "192.55642863",
GMD: "12891.70125",
GNF: "2438630.43574976",
GTQ: "1936.689014855",
GYD: "52047.88891278",
HKD: "1930.67861725",
HNL: "6126.43736492",
HRK: "1605.40119007",
HTG: "15682.48428085",
HUF: "77261.419177275",
IDR: "3666848.2425",
ILS: "843.29662455",
IMP: "192.55642863",
INR: "18275.43761675",
IQD: "297176.65680577",
ISK: "34639.44075",
JEP: "192.55642863",
JMD: "36261.061070375",
JOD: "176.622535",
JPY: "26304.9247525",
KES: "27093.7474",
KGS: "20240.23303148",
KHR: "1021526.66327067",
KMF: "104678.164103975",
KNC: "275.5392102643512742545",
KRW: "284115.6575",
KWD: "76.196555935",
KYD: "207.44852333",
KZT: "106578.169689505",
LAK: "2300372.70137523",
LBP: "376426.60931701",
LINK: "22.8704181013371177476",
LKR: "45903.840861165",
LRC: "1428.4116972477063306",
LRD: "48689.521020355",
LSL: "4093.68786226",
LTC: "5.182877353583689269445",
LTL: "803.357262175",
LVL: "163.484459015",
LYD: "340.470203685",
MAD: "2290.86403115",
MDL: "4231.74490411",
MGA: "978918.42727237",
MKD: "13034.71219274",
MKR: "0.43727565410331105846",
MMK: "321367.16219401",
MNT: "706980.17312004",
MOP: "1987.157222705",
MRO: "88934.055",
MTL: "170.32939187",
MUR: "9942.18014823",
MVR: "3836.371",
MWK: "187533.350248305",
MXN: "5285.574344805",
MYR: "1033.2044625",
MZN: "18168.45667469",
NAD: "4120.3621",
NGN: "95465.8503",
NIO: "8675.07065117",
NMR: "8.6886689628111785348",
NOK: "2328.95371465",
NPR: "29198.52701022",
NZD: "378.934057915",
OMG: "74.27621574882972595255",
OMR: "95.913509955",
OXT: "1023.479868529169993565",
PAB: "249.115",
PEN: "892.41413087",
PGK: "870.976539545",
PHP: "12100.979598855",
PKR: "40413.26181118",
PLN: "968.71705891",
PYG: "1750259.579863715",
QAR: "907.08999375",
REN: "758.802924154736515935",
REP: "18.2168190127970744169",
REPV2: "18.225711080673967324",
RON: "1032.33256",
RSD: "24895.307525",
RUB: "19351.4774035",
RWF: "243426.179717085",
SAR: "934.309544225",
SBD: "2013.0584566",
SCR: "4561.388071665",
SEK: "2201.10291435",
SGD: "338.356712025",
SHP: "192.55642863",
SLL: "2482430.971263275",
SOS: "144000.839307095",
SRD: "3525.97371",
SSP: "32449.7199",
STD: "5232524.31108792",
SVC: "2178.147216215",
SZL: "4091.741526765",
THB: "7785.4665375",
TJS: "2568.96954016",
TMT: "871.9025",
TND: "686.00043125",
TOP: "578.0165522",
TRY: "1963.587954325",
TTD: "1689.460313635",
TWD: "7158.9423125",
TZS: "577510.41827928",
UAH: "7061.44019619",
UGX: "931508.2111739",
UMA: "30.09543944427665349095",
UNI: "79.18593747516647884725",
USD: "249.115",
USDC: "249.115",
UYU: "10688.478117885",
UZS: "2582693.606121005",
VEF: "61901998.996866715",
VES: "112695476.713406465",
VND: "5773814.12282902",
VUV: "28486.73470656",
WST: "653.35042289",
XAF: "138884.3079243",
XAG: "10.22661168355",
XAU: "0.1312935696",
XCD: "673.24574325",
XDR: "176.50246157",
XLM: "2936.20532162536435083",
XOF: "138884.3079243",
XPD: "0.1061030608",
XPF: "25265.84267069",
XPT: "0.2910211253",
XRP: "1014.931757995518373565",
XTZ: "113.8135051169590628124",
YER: "62365.930534515",
YFI: "0.0178703370267443543872",
ZAR: "4122.31765275",
ZEC: "3.87305659203980154283",
ZMK: "1308619.842149325",
ZMW: "5027.95231667",
ZRX: "644.844402797695193656",
ZWL: "80215.03"
}
module.exports = {
mockRates
}
+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")
})
})
})
+61 -19
View File
@@ -1,28 +1,70 @@
const chai = require("chai")
const assert = require("assert")
const assert = require("chai").assert
const BCHJS = require("../../src/bch-js")
const bchjs = new BCHJS()
const axios = require("axios")
const sinon = require("sinon")
describe("#Price", () => {
const mockDataLib = require("./fixtures/price-mocks")
let mockData
describe("#price", () => {
let sandbox
let bchjs
beforeEach(() => {
sandbox = sinon.createSandbox()
bchjs = new BCHJS()
mockData = Object.assign({}, mockDataLib)
})
afterEach(() => sandbox.restore())
describe("#current", () => {
describe("#single currency", () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
afterEach(() => sandbox.restore())
it("should get current price for single currency", async () => {
sandbox
.stub(bchjs.Price.axios, "get")
.resolves({ data: { price: 24905 } })
it("should get current price for single currency", done => {
const data = 46347
const resolved = new Promise(r => r({ data: data }))
sandbox.stub(axios, "get").returns(resolved)
const result = await bchjs.Price.current("usd")
// console.log(result)
bchjs.Price.current("usd")
.then(result => {
assert.deepEqual(data.price, result)
})
.then(done, done)
})
assert.isNumber(result)
})
})
describe("#getUsd", () => {
it("should get the USD price of BCH", async () => {
sandbox.stub(bchjs.Price.axios, "get").resolves({ data: { usd: 249.87 } })
const result = await bchjs.Price.getUsd()
// console.log(result)
assert.isNumber(result)
})
})
describe("#rates", () => {
it("should get the price of BCH in several currencies", async () => {
sandbox
.stub(bchjs.Price.axios, "get")
.resolves({ data: mockData.mockRates })
const result = await bchjs.Price.rates()
// console.log(result)
assert.property(result, "USD")
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)
})
})
})