mirror of
https://github.com/Permissionless-Software-Foundation/bch-js.git
synced 2026-09-22 09:02:01 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7649eeffec | ||
|
|
f7d79dea28 | ||
|
|
2f1d6995a6 | ||
|
|
462885e97b | ||
|
|
24774a706e | ||
|
|
d5f7e6aa7f | ||
|
|
04e3346086 | ||
|
|
cb2a90fc93 | ||
|
|
66c2d3ab22 | ||
|
|
89d13fe241 | ||
|
|
ad0b1b5ddb | ||
|
|
ae30b89d68 | ||
|
|
2e88d26ff2 | ||
|
|
b1745d37e0 | ||
|
|
9733c07e04 | ||
|
|
430f5f015e | ||
|
|
9e76b34d05 | ||
|
|
61078b2e91 | ||
|
|
82733a7e1a | ||
|
|
3685ea1541 | ||
|
|
5f217af3e9 | ||
|
|
e2ca3cfb00 | ||
|
|
690520d72e | ||
|
|
36660f3bc9 | ||
|
|
80ee5c8d31 | ||
|
|
b7e04522ce | ||
|
|
19f243428d | ||
|
|
16079c8d04 | ||
|
|
6743ca5fa9 | ||
|
|
ec046d3ef7 | ||
|
|
85405d8e70 | ||
|
|
1989b72b2a | ||
|
|
f1f2bf42d9 | ||
|
|
348a073714 | ||
|
|
e822b91e2c | ||
|
|
29a5173036 | ||
|
|
0bffff6f9b | ||
|
|
8c603d3886 | ||
|
|
542e59461f | ||
|
|
0912aadc1a | ||
|
|
638804de42 | ||
|
|
fe33ba3381 | ||
|
|
6f913cf3ad | ||
|
|
4d94ad13ff | ||
|
|
c02080d12a | ||
|
|
cc1809b242 | ||
|
|
13a7917d9b | ||
|
|
1573e0bc4c | ||
|
|
3fb5377acd | ||
|
|
a1ba2ac2f7 | ||
|
|
7dc29230da | ||
|
|
3b013b6215 | ||
|
|
9129c594dd | ||
|
|
64d99531de | ||
|
|
c9a8c5008e | ||
|
|
7f08789c6a | ||
|
|
63dcddb3ab | ||
|
|
c2f150bf81 | ||
|
|
889ffcfe1d | ||
|
|
26a6175889 | ||
|
|
07de91afa2 | ||
|
|
246da25f91 | ||
|
|
f24d36ccee | ||
|
|
f80cce96b1 | ||
|
|
1c6939ab43 | ||
|
|
bcb236a66b | ||
|
|
b66ff3cb59 | ||
|
|
2dad11180b | ||
|
|
22e13ef654 | ||
|
|
4dabdac792 | ||
|
|
857b57240e | ||
|
|
7b9aba3738 | ||
|
|
2c49af2de3 | ||
|
|
3c0590ba23 | ||
|
|
b20a034bc9 | ||
|
|
12e5143d9a | ||
|
|
8e3fa6dcf1 | ||
|
|
76442208a2 | ||
|
|
2cf8905852 | ||
|
|
d134aff9f4 | ||
|
|
005b628301 | ||
|
|
f3c2168435 | ||
|
|
71b8bb089d | ||
|
|
2333229e54 | ||
|
|
13c69593b2 | ||
|
|
8316c4eabb | ||
|
|
30cf010e80 | ||
|
|
f28eeea5b0 | ||
|
|
9758eb9995 | ||
|
|
4260a74d91 | ||
|
|
01625abb37 | ||
|
|
b34040cd08 | ||
|
|
01a4d0f1aa | ||
|
|
7c7c6395e1 | ||
|
|
3408a8fd3b | ||
|
|
86a1cadfac | ||
|
|
7000a83a37 | ||
|
|
b331450473 | ||
|
|
af7c8ffa6d | ||
|
|
2e04548ade | ||
|
|
412fa5e1ce | ||
|
|
a08a4236d6 | ||
|
|
e700a22560 | ||
|
|
4573c63ca3 | ||
|
|
bd18e8a755 | ||
|
|
cf8f48ffe1 | ||
|
|
fc96b04a64 | ||
|
|
661a759f80 | ||
|
|
ba915e84cf | ||
|
|
eae7172e3d | ||
|
|
6dd2a0590f | ||
|
|
3152e87b5d | ||
|
|
4b66f3841d | ||
|
|
9f98a47682 | ||
|
|
0833e8ca78 | ||
|
|
e01a18b65e | ||
|
|
055cd7feca | ||
|
|
906d9b2094 | ||
|
|
9326fd6e59 | ||
|
|
1d91eed5df | ||
|
|
62e56c832b | ||
|
|
d5b7e4ab1d | ||
|
|
2137a75fce | ||
|
|
8966cac210 | ||
|
|
9d32f828bc | ||
|
|
91a7106818 | ||
|
|
44e671dfbe | ||
|
|
979fb481de | ||
|
|
66253ed5a6 | ||
|
|
6ef5ac0f7c | ||
|
|
21c322d0df | ||
|
|
1b0e9ef0ff | ||
|
|
78776bee93 | ||
|
|
a6e3155f37 | ||
|
|
47f60bccde | ||
|
|
d0a3b27682 | ||
|
|
372d1b099d | ||
|
|
dbfaf9c4ab | ||
|
|
eaa08f74e7 | ||
|
|
9ac620ee64 | ||
|
|
ac0a4b0407 | ||
|
|
686012037f | ||
|
|
cfb7b9f779 | ||
|
|
06e5af4b5d | ||
|
|
249e93a3f4 | ||
|
|
761a2d226c | ||
|
|
5e5e636831 | ||
|
|
2adc2dfebb | ||
|
|
f9bc44ccb7 | ||
|
|
298b8f56ff | ||
|
|
139da8cf7b | ||
|
|
08e03c14d8 | ||
|
|
7da010e7af | ||
|
|
7b6eebe7c7 | ||
|
|
843f5eacef | ||
|
|
416e302ca5 | ||
|
|
1c66da70b6 | ||
|
|
59e92adf0b | ||
|
|
f369411ccb | ||
|
|
0504cf7b8d | ||
|
|
88ae47cade | ||
|
|
d144b13500 | ||
|
|
30d58bc337 | ||
|
|
651ae3f6ca | ||
|
|
04cd90f0f4 | ||
|
|
552ee31b79 | ||
|
|
affa9619bb | ||
|
|
39bff131af | ||
|
|
a84fecfe41 | ||
|
|
0736c9f2a1 | ||
|
|
aa898b31e7 | ||
|
|
29c3381cc5 | ||
|
|
f7ba6bb3ae | ||
|
|
62056e1ac4 | ||
|
|
a60e2fa2da | ||
|
|
37fe679800 | ||
|
|
4250d841c5 | ||
|
|
31079afc35 | ||
|
|
62b44d5058 | ||
|
|
150295cb43 | ||
|
|
5de2f71ea5 | ||
|
|
50a1d60229 | ||
|
|
f3e25a0338 | ||
|
|
640c582724 | ||
|
|
b472fa2673 | ||
|
|
ea83335fd2 | ||
|
|
3050819784 |
@@ -4,6 +4,8 @@ wallet-info.txt
|
|||||||
wallet.json
|
wallet.json
|
||||||
integration-test-sweet.sh
|
integration-test-sweet.sh
|
||||||
integration-test-ss.sh
|
integration-test-ss.sh
|
||||||
|
integration-test-bitfinex.sh
|
||||||
|
integration-test-pearson.sh
|
||||||
|
|
||||||
docs/
|
docs/
|
||||||
coverage/
|
coverage/
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
Copyright 2022 Permissionless Software Foundation contributors
|
Copyright 2022-2026 Permissionless Software Foundation contributors
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
|||||||
@@ -3,26 +3,20 @@
|
|||||||
[](https://www.npmjs.com/package/@psf/bch-js)
|
[](https://www.npmjs.com/package/@psf/bch-js)
|
||||||
[](https://npmjs.org/package/@psf/bch-js)
|
[](https://npmjs.org/package/@psf/bch-js)
|
||||||
[](https://github.com/Permissionless-Software-Foundation/bch-js/blob/master/LICENSE.md)
|
[](https://github.com/Permissionless-Software-Foundation/bch-js/blob/master/LICENSE.md)
|
||||||
[](https://github.com/feross/standard)
|
[](https://github.com/feross/standard) [](https://gitter.im/Permissionless-Software-Foundation/bch-js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
[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.
|
[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) blockchain. bch-js contains a toolbox of handy tools, and an easy API for talking with [psf-bch-api REST API](https://github.com/Permissionless-Software-Foundation/psf-bch-api). [FullStack.cash](https://fullstack.cash) offers paid cloud access to psf-bch-api. You can run your own infrastructure by following documentation on [CashStack.info](https://cashstack.info).
|
||||||
|
|
||||||
### 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
|
### Quick Links
|
||||||
|
|
||||||
|
- [Code Examples](https://github.com/Permissionless-Software-Foundation/psf-js-examples) using bch-js
|
||||||
- [npm Library](https://www.npmjs.com/package/@psf/bch-js)
|
- [npm Library](https://www.npmjs.com/package/@psf/bch-js)
|
||||||
- [Documentation](https://bchjs.fullstack.cash/)
|
- [API Reference](https://bchjs.fullstack.cash/)
|
||||||
- [Examples](https://github.com/Permissionless-Software-Foundation/bch-js-examples)
|
- [x402-bch.fullstack.cash](https://x402-bch.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](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.
|
- [CashStack.info](https://cashstack.info) - bch-js is part of the Cash Stack, a JavaScript framework for writing web 2 and web 3 business applications.
|
||||||
- [Permissionless Software Foundation](https://psfoundation.cash) - The organization that maintains this library.
|
- [Permissionless Software Foundation](https://psfoundation.info) - The organization that maintains this library.
|
||||||
|
|
||||||
|
|
||||||
### Quick Notes
|
### Quick Notes
|
||||||
|
|
||||||
@@ -30,73 +24,97 @@ Here are two YouTube walk-through videos to help you get started:
|
|||||||
|
|
||||||
- Instantiate the library in your code:
|
- Instantiate the library in your code:
|
||||||
|
|
||||||
```
|
```javascript
|
||||||
const BCHJS = require("@psf/bch-js")
|
import BCHJS from "@psf/bch-js"
|
||||||
let bchjs = new BCHJS() // Defaults to BCHN network.
|
let bchjs = new BCHJS() // Defaults to BCHN network.
|
||||||
```
|
```
|
||||||
|
|
||||||
This library is intended to be paired with
|
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:
|
the [psf-bch-api](https://github.com/Permissionless-Software-Foundation/psf-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:
|
||||||
|
|
||||||
- BCHN Mainnet REST API server: https://bchn.fullstack.cash/v5/
|
- BCHN Mainnet REST API server: https://x402-bch.fullstack.cash/v7/
|
||||||
- ABC Mainnet REST API server: https://abc.fullstack.cash/v5/
|
|
||||||
- Check server status: https://metrics.fullstack.cash
|
- Check server status: https://metrics.fullstack.cash
|
||||||
|
|
||||||
### API Key
|
## Configuration
|
||||||
|
|
||||||
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
|
bch-js can be configured through constructor options or environment variables. Configuration options passed to the constructor take precedence over environment variables.
|
||||||
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.
|
### Constructor Options
|
||||||
- Explicitly: You can directly feed in the JWT token with the `apiToken` property when instantiating the library. Here is an example:
|
|
||||||
|
|
||||||
```
|
When instantiating BCHJS, you can pass a configuration object:
|
||||||
const BCHJS = require("@psf/bch-js")
|
|
||||||
let bchjs = new BCHJS({
|
```javascript
|
||||||
restURL: 'https://bchn.fullstack.cash/v5/',
|
import BCHJS from "@psf/bch-js"
|
||||||
apiToken: 'eyJhbGciO...' // Your JWT token here.
|
|
||||||
|
const bchjs = new BCHJS({
|
||||||
|
restURL: 'https://x402-bch.fullstack.cash/v5/',
|
||||||
|
bearerToken: 'your-bearer-token',
|
||||||
|
wif: 'your-private-key-wif',
|
||||||
|
paymentAmountSats: 20000,
|
||||||
|
bchServerURL: 'https://bch.fullstack.cash'
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
### Gatsby
|
### Configuration Options
|
||||||
|
|
||||||
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):
|
| Option | Type | Required | Default | Description |
|
||||||
|
|--------|------|----------|---------|-------------|
|
||||||
|
| `restURL` | string | Yes* | - | The REST API server URL for making API calls. Must include trailing slash. *Required unless `RESTURL` environment variable is set. |
|
||||||
|
| `bearerToken` | string | No | `''` | Bearer token for authentication with the REST API server. |
|
||||||
|
| `wif` | string | No | `''` | Private key in WIF format. When provided, enables automatic x402 payment handling. |
|
||||||
|
| `paymentAmountSats` | number | No | `20000` | Default amount of satoshis to send when making x402 payments. |
|
||||||
|
| `bchServerURL` | string | No | `'https://bch.fullstack.cash'` | BCH server URL used for broadcasting payment transactions to the blockchain. This is separate from `restURL` and is specifically for x402 payment processing. |
|
||||||
|
|
||||||
```
|
### Environment Variables
|
||||||
exports.onCreateWebpackConfig = ({ actions }) => {
|
|
||||||
actions.setWebpackConfig({
|
You can also configure bch-js using environment variables:
|
||||||
node: {
|
|
||||||
fs: 'empty'
|
| Environment Variable | Config Option | Description |
|
||||||
}
|
|---------------------|---------------|-------------|
|
||||||
})
|
| `RESTURL` | `restURL` | REST API server URL for making API calls. |
|
||||||
}
|
| `BCHJSBEARERTOKEN` | `bearerToken` | Bearer token for API authentication. |
|
||||||
|
| `BCHJSWIF` | `wif` | Private key in WIF format for x402 payments. |
|
||||||
|
| `BCHJSBCHSERVERURL` | `bchServerURL` | BCH server URL for x402 payment transactions. |
|
||||||
|
|
||||||
|
### Understanding restURL vs bchServerURL
|
||||||
|
|
||||||
|
These two configuration options serve different purposes:
|
||||||
|
|
||||||
|
- **`restURL`**: The REST API server used for all regular API calls (utxo queries, transaction history, etc.). This can be any bch-api compatible server, such as `https://x402-bch.fullstack.cash/v5/` or `https://bch.fullstack.cash/v5/`.
|
||||||
|
|
||||||
|
- **`bchServerURL`**: The BCH infrastructure server used specifically for broadcasting x402 payment transactions to the blockchain. This defaults to `https://bch.fullstack.cash` and should typically remain unchanged unless you have specific infrastructure requirements.
|
||||||
|
|
||||||
|
**Example Use Case**: Most users will use `https://x402-bch.fullstack.cash/v5/` as their `restURL` to access x402-protected APIs. However, when bch-js needs to make an x402 payment, it uses the `bchServerURL` (default: `https://bch.fullstack.cash`) to broadcast the payment transaction. This ensures payment transactions are sent through a reliable BCH infrastructure endpoint.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Use x402-bch server for API calls, but bch.fullstack.cash for payments
|
||||||
|
const bchjs = new BCHJS({
|
||||||
|
restURL: 'https://x402-bch.fullstack.cash/v5/',
|
||||||
|
wif: 'your-private-key-wif'
|
||||||
|
// bchServerURL defaults to 'https://bch.fullstack.cash'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Or explicitly set both
|
||||||
|
const bchjs2 = new BCHJS({
|
||||||
|
restURL: 'https://x402-bch.fullstack.cash/v5/',
|
||||||
|
bchServerURL: 'https://bch.fullstack.cash',
|
||||||
|
wif: 'your-private-key-wif'
|
||||||
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
This is because the new IPFS class in bch-js uses the fs library for uploading files, which is not supported by Gatsby.
|
### Web Apps
|
||||||
|
|
||||||
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.
|
[minimal-slp-wallet](https://www.npmjs.com/package/minimal-slp-wallet) is a minimal wallet 'engine' that incorporates bch-js. It's compiled with Browserify for front end apps.
|
||||||
|
|
||||||
## Features
|
[This gist](https://gist.github.com/christroutner/6cb9d1b615f3f9363af79723157bc434) shows how to include minimal-slp-wallet into a basic web page without using a framework.
|
||||||
|
|
||||||
- [ECMAScript 2017 standard JavaScript](https://en.wikipedia.org/wiki/ECMAScript#8th_Edition_-_ECMAScript_2017) used instead of TypeScript. Works
|
[bch-wallet-web3-spa](https://github.com/Permissionless-Software-Foundation/bch-wallet-web3-spa) is a React web app template using bch-js and minimal-slp-wallet.
|
||||||
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.
|
|
||||||
|
|
||||||
- [Greenkeeper](https://greenkeeper.io/) automatic dependency management for
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Documentation:
|
## Documentation:
|
||||||
|
|
||||||
Full documentation for this library can be found here:
|
Full documentation for this library can be found here:
|
||||||
|
|
||||||
- [Documentation](https://bchjs.fullstack.cash/)
|
- [API Reference](https://bchjs.fullstack.cash/)
|
||||||
|
|
||||||
bch-js uses [APIDOC](http://apidocjs.com/) so that documentation and working code
|
bch-js uses [APIDOC](http://apidocjs.com/) so that documentation and working code
|
||||||
live in the same repository. To generate the documentation:
|
live in the same repository. To generate the documentation:
|
||||||
@@ -109,14 +127,15 @@ live in the same repository. To generate the documentation:
|
|||||||
Have questions? Need help? Join our community support
|
Have questions? Need help? Join our community support
|
||||||
[Telegram channel](https://t.me/bch_js_toolkit)
|
[Telegram channel](https://t.me/bch_js_toolkit)
|
||||||
|
|
||||||
## IPFS Releases
|
## Donate
|
||||||
|
|
||||||
Copies of this repository are also published on [IPFS](https://ipfs.io).
|
This open source software is developed and maintained by the [Permissionless Software Foundation](https://psfoundation.cash). If this library provides value to you, please consider making a donation to support the PSF developers:
|
||||||
|
|
||||||
- v4.5.4: QmWv3pxJy3MH8vU5nLUVyzqFxfNKXLQQEnz1rgStNuQijd
|
<div align="center">
|
||||||
|
<img src="./img/donation-qr.png" />
|
||||||
|
<p>bitcoincash:qqsrke9lh257tqen99dkyy2emh4uty0vky9y0z0lsr</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
[MIT](LICENSE.md)
|
[MIT](LICENSE.md)
|
||||||
|
|
||||||
test
|
|
||||||
|
|||||||
Executable
+38
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Script to improve contrast in auto-generated API documentation
|
||||||
|
# The code examples in api-doc use grey-on-grey colors that are hard to read.
|
||||||
|
# This fixes that issue by improving text contrast for better readability.
|
||||||
|
# Run this script *after* running 'npm run docs'
|
||||||
|
|
||||||
|
FILE="./docs/assets/prism.css"
|
||||||
|
|
||||||
|
# Check if file exists
|
||||||
|
if [ ! -f "$FILE" ]; then
|
||||||
|
echo "Error: $FILE not found. Make sure to run 'npm run docs' first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create a backup
|
||||||
|
#cp "$FILE" "$FILE.bak"
|
||||||
|
|
||||||
|
# Improve contrast:
|
||||||
|
# - Change default text color from #ccc to #e8e8e8 (brighter light gray)
|
||||||
|
# - Change comment color from #999 to #b5b5b5 (lighter for better visibility)
|
||||||
|
# - Change punctuation color from #ccc to #e8e8e8 (consistent with text)
|
||||||
|
|
||||||
|
# Replace default text color in code[class*="language-"] and pre[class*="language-"]
|
||||||
|
sed -i 's/color: #ccc;/color: #000000;/g' "$FILE"
|
||||||
|
|
||||||
|
# Replace comment color
|
||||||
|
sed -i 's/color: #999;/color: #b5b5b5;/g' "$FILE"
|
||||||
|
|
||||||
|
|
||||||
|
# Replace punctuation color (already handled by first sed, but explicit for clarity)
|
||||||
|
# The punctuation token also uses #ccc, so the first sed command handles it
|
||||||
|
|
||||||
|
echo "✓ Improved contrast in prism.css:"
|
||||||
|
echo " - Default text: #ccc → #e8e8e8"
|
||||||
|
echo " - Comments: #999 → #b5b5b5"
|
||||||
|
echo " - Punctuation: #ccc → #e8e8e8"
|
||||||
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
+10451
File diff suppressed because it is too large
Load Diff
Generated
+11287
-19960
File diff suppressed because it is too large
Load Diff
+42
-50
@@ -1,33 +1,27 @@
|
|||||||
{
|
{
|
||||||
"name": "@psf/bch-js",
|
"name": "@psf/bch-js",
|
||||||
"version": "6.0.0",
|
"version": "7.0.0",
|
||||||
"description": "A JavaScript library for working with Bitcoin Cash, eCash, and SLP Tokens",
|
"type": "module",
|
||||||
|
"description": "A JavaScript library for working with Bitcoin Cash and SLP Tokens",
|
||||||
"author": "Chris Troutner <chris.troutner@gmail.com>",
|
"author": "Chris Troutner <chris.troutner@gmail.com>",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"Gabriel Cardona <gabriel@bitcoin.com>",
|
"Gabriel Cardona <gabriel@bitcoin.com>",
|
||||||
"Stoyan Zhekov <zh@zhware.net>"
|
"Stoyan Zhekov <zh@zhware.net>"
|
||||||
],
|
],
|
||||||
"main": "src/bch-js",
|
"main": "src/bch-js.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "nyc mocha --trace-warnings --unhandled-rejections=strict --timeout 30000 test/unit/",
|
"test": "export RESTURL=http://localhost:5942/v6 && c8 mocha --trace-warnings --unhandled-rejections=strict --timeout 30000 test/unit/",
|
||||||
"test:integration": "npm run test:integration:bchn",
|
"test:custom": "export RESTURL=http://localhost:5942/v6 && c8 mocha --trace-warnings --unhandled-rejections=strict --timeout 60000 ${MOCHA_GREP:+--grep $MOCHA_GREP} test/unit/",
|
||||||
"test:integration:nft": "export RESTURL=https://bchn.fullstack.cash/v5/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 -g '#nft1' test/integration/chains/bchn/slp.js",
|
"test:integration": "npm run test:integration:local:noauth",
|
||||||
"test:integration:abc": "export RESTURL=https://abc.fullstack.cash/v5/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/abc/",
|
"test:integration:fullstack:free": "export RESTURL=https://bch.fullstack.cash/v6 && mocha --timeout 60000 test/integration/",
|
||||||
"test:integration:bchn": "export RESTURL=https://bchn.fullstack.cash/v5/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
|
"test:integration:fullstack:x402": "export RESTURL=https://x402-bch.fullstack.cash/v6 && export BCHJSWIF=L1eYaneXDDXy8VDig4Arwe8wYHbhtsA5wuQvwsKwhaYeneoZuKG4 && mocha --timeout 120000 test/integration/",
|
||||||
"test:integration:bchn:slpdb": "export TESTSLP=1 && export RESTURL=https://bchn.fullstack.cash/v5/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
|
"test:integration:fullstack:auth": "export RESTURL=http://dev.fullstack.cash/v6 && export BCHJSBEARERTOKEN=test01 && mocha --timeout 30000 test/integration/",
|
||||||
"test:integration:local:abc": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
|
"test:integration:local:noauth": "export RESTURL=http://192.168.1.65:5942/v6 && mocha --timeout 30000 test/integration/",
|
||||||
"test:integration:local:bchn": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
|
"test:integration:local:auth": "export RESTURL=http://192.168.1.115:5942/v6 && export BCHJSBEARERTOKEN=temp01 && mocha --timeout 30000 test/integration/",
|
||||||
"test:integration:local:testnet": "RESTURL=http://localhost:4000/v5/ mocha --timeout 30000 test/integration/chains/testnet",
|
"test:integration:local:x402": "export RESTURL=http://localhost:5942/v6 && export BCHJSWIF=L1eYaneXDDXy8VDig4Arwe8wYHbhtsA5wuQvwsKwhaYeneoZuKG4 && mocha --timeout 1200000 test/integration/",
|
||||||
"test:integration:decatur:bchn": "export RESTURL=http://192.168.2.129:3000/v5/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
|
"test:integration:decatur": "export RESTURL=http://192.168.1.65:5942/v6 && mocha --timeout 30000 test/integration/",
|
||||||
"test:integration:decatur:abc": "export RESTURL=http://192.168.2.141:3000/v5/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
|
"coverage": "nyc --reporter=html mocha --timeout 25000 test/unit/",
|
||||||
"test:integration:temp:bchn": "export RESTURL=http://157.90.174.219:3000/v5/ && mocha --timeout 30000 test/integration/",
|
"docs": "./node_modules/.bin/apidoc -i src/ -o docs && ./fix-docs-contrast.sh",
|
||||||
"test:temp": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 -g '#Encryption' test/integration/",
|
|
||||||
"test:temp2": "mocha --timeout=30000 -g '#TransactionLib' test/unit/",
|
|
||||||
"test:temp3": "export RESTURL=https://bchn.fullstack.cash/v5/ && mocha --timeout 30000 -g '#DSProof' test/integration/chains/",
|
|
||||||
"test:temp4": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 -g '#decodeOpReturn' test/integration/",
|
|
||||||
"coverage": "nyc report --reporter=text-lcov | coveralls",
|
|
||||||
"coverage:report": "nyc --reporter=html mocha --timeout 25000 test/unit/",
|
|
||||||
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
|
|
||||||
"lint": "standard --env mocha --fix"
|
"lint": "standard --env mocha --fix"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -39,48 +33,41 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chris.troutner/bip32-utils": "1.0.5",
|
"@chris.troutner/bip32-utils": "1.0.5",
|
||||||
"@psf/bip21": "2.0.1",
|
"@psf/bip21": "2.0.1",
|
||||||
"@psf/bitcoincash-ops": "2.0.0",
|
"@psf/bitcoincashjs-lib": "4.0.3",
|
||||||
"@psf/bitcoincashjs-lib": "4.0.2",
|
|
||||||
"@psf/coininfo": "4.0.0",
|
"@psf/coininfo": "4.0.0",
|
||||||
"axios": "0.26.1",
|
"axios": "1.13.2",
|
||||||
"bc-bip68": "1.0.5",
|
"bc-bip68": "1.0.5",
|
||||||
"bchaddrjs-slp": "0.2.5",
|
"bchaddrjs-slp": "0.2.14",
|
||||||
"bigi": "1.4.2",
|
"bigi": "1.4.2",
|
||||||
"bignumber.js": "9.0.0",
|
"bignumber.js": "9.3.1",
|
||||||
"bip-schnorr": "0.3.0",
|
"bip-schnorr": "0.6.7",
|
||||||
"bip38": "2.0.2",
|
"bip38": "3.1.1",
|
||||||
"bip39": "3.0.2",
|
"bip39": "3.1.0",
|
||||||
"bip66": "1.1.5",
|
"bip66": "1.1.5",
|
||||||
"bitcoinjs-message": "2.0.0",
|
"bitcoinjs-message": "2.2.0",
|
||||||
"bs58": "4.0.1",
|
"bs58": "4.0.1",
|
||||||
"ecashaddrjs": "1.0.7",
|
"ecashaddrjs": "1.0.7",
|
||||||
"ini": "1.3.8",
|
"ini": "6.0.0",
|
||||||
"randombytes": "2.0.6",
|
"randombytes": "2.1.0",
|
||||||
"safe-buffer": "5.1.2",
|
"safe-buffer": "5.2.1",
|
||||||
"satoshi-bitcoin": "1.0.4",
|
"satoshi-bitcoin": "1.0.5",
|
||||||
"slp-mdm": "0.0.6",
|
"slp-mdm": "0.0.7",
|
||||||
"slp-parser": "0.0.4",
|
"slp-parser": "0.0.4",
|
||||||
"wif": "2.0.6"
|
"wif": "2.0.6",
|
||||||
|
"x402-bch-axios": "2.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"apidoc": "0.50.5",
|
"apidoc": "1.2.0",
|
||||||
"assert": "2.0.0",
|
"assert": "2.1.0",
|
||||||
|
"c8": "10.1.3",
|
||||||
"chai": "4.1.2",
|
"chai": "4.1.2",
|
||||||
"coveralls": "3.0.2",
|
|
||||||
"eslint": "7.17.0",
|
|
||||||
"eslint-config-prettier": "7.1.0",
|
|
||||||
"eslint-config-standard": "16.0.3",
|
|
||||||
"eslint-plugin-node": "11.1.0",
|
|
||||||
"eslint-plugin-prettier": "3.3.1",
|
|
||||||
"eslint-plugin-standard": "4.0.0",
|
|
||||||
"husky": "4.3.8",
|
"husky": "4.3.8",
|
||||||
"lodash.clonedeep": "4.5.0",
|
"lodash.clonedeep": "4.5.0",
|
||||||
"mocha": "9.2.1",
|
"mocha": "11.7.5",
|
||||||
"node-mocks-http": "1.7.0",
|
|
||||||
"nyc": "15.1.0",
|
"nyc": "15.1.0",
|
||||||
"semantic-release": "^19.0.2",
|
"semantic-release": "24.2.9",
|
||||||
"sinon": "9.2.2",
|
"sinon": "9.2.2",
|
||||||
"standard": "^16.0.4"
|
"standard": "17.1.2"
|
||||||
},
|
},
|
||||||
"apidoc": {
|
"apidoc": {
|
||||||
"title": "bch-js",
|
"title": "bch-js",
|
||||||
@@ -90,5 +77,10 @@
|
|||||||
"hooks": {
|
"hooks": {
|
||||||
"pre-commit": "npm run lint"
|
"pre-commit": "npm run lint"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"standard": {
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": "latest"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-24
@@ -1,7 +1,7 @@
|
|||||||
// const axios = require("axios")
|
// import axios from "axios"
|
||||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
import Bitcoin from '@psf/bitcoincashjs-lib'
|
||||||
const cashaddr = require('ecashaddrjs')
|
import cashaddr from 'ecashaddrjs'
|
||||||
const coininfo = require('@psf/coininfo')
|
import coininfo from '@psf/coininfo'
|
||||||
|
|
||||||
class Address {
|
class Address {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
@@ -10,22 +10,11 @@ class Address {
|
|||||||
else tmp.restURL = config.restURL
|
else tmp.restURL = config.restURL
|
||||||
|
|
||||||
this.restURL = tmp.restURL
|
this.restURL = tmp.restURL
|
||||||
this.apiToken = tmp.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,7 +122,7 @@ class Address {
|
|||||||
* @api Address.toEcashAddress() toEcashAddress()
|
* @api Address.toEcashAddress() toEcashAddress()
|
||||||
* @apiName toEcashAddress
|
* @apiName toEcashAddress
|
||||||
* @apiGroup Address
|
* @apiGroup Address
|
||||||
* @apiDescription Convert legacy to cashAddress format
|
* @apiDescription Convert legacy to eCash (XEC) format
|
||||||
*
|
*
|
||||||
* @apiExample Example usage:
|
* @apiExample Example usage:
|
||||||
* // mainnet
|
* // mainnet
|
||||||
@@ -158,6 +147,35 @@ class Address {
|
|||||||
return ecashAddress.split(':')[1]
|
return ecashAddress.split(':')[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api Address.toEtokenAddress() toEtokenAddress()
|
||||||
|
* @apiName toEtokenAddress
|
||||||
|
* @apiGroup Address
|
||||||
|
* @apiDescription Convert legacy to eToken (XEC) format
|
||||||
|
*
|
||||||
|
* @apiExample Example usage:
|
||||||
|
* // mainnet
|
||||||
|
* bchjs.Address.toEtokenAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2')
|
||||||
|
* // etoken:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
|
||||||
|
*
|
||||||
|
* // mainnet no prefix
|
||||||
|
* bchjs.Address.toEtokenAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2', false)
|
||||||
|
* // qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
toEtokenAddress (address, prefix = true) {
|
||||||
|
const decoded = this._decode(address)
|
||||||
|
|
||||||
|
const etokenAddress = cashaddr.encode(
|
||||||
|
'etoken',
|
||||||
|
decoded.type,
|
||||||
|
decoded.hash
|
||||||
|
)
|
||||||
|
|
||||||
|
if (prefix) return etokenAddress
|
||||||
|
return etokenAddress.split(':')[1]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api Address.ecashtoCashAddress() ecashtoCashAddress()
|
* @api Address.ecashtoCashAddress() ecashtoCashAddress()
|
||||||
* @apiName ecashtoCashAddress
|
* @apiName ecashtoCashAddress
|
||||||
@@ -283,28 +301,28 @@ class Address {
|
|||||||
return {
|
return {
|
||||||
prefix: 'bitcoincash',
|
prefix: 'bitcoincash',
|
||||||
type: 'P2PKH',
|
type: 'P2PKH',
|
||||||
hash: hash,
|
hash,
|
||||||
format: 'legacy'
|
format: 'legacy'
|
||||||
}
|
}
|
||||||
case info.main.versions.scripthash:
|
case info.main.versions.scripthash:
|
||||||
return {
|
return {
|
||||||
prefix: 'bitcoincash',
|
prefix: 'bitcoincash',
|
||||||
type: 'P2SH',
|
type: 'P2SH',
|
||||||
hash: hash,
|
hash,
|
||||||
format: 'legacy'
|
format: 'legacy'
|
||||||
}
|
}
|
||||||
case info.test.versions.public:
|
case info.test.versions.public:
|
||||||
return {
|
return {
|
||||||
prefix: 'bchtest',
|
prefix: 'bchtest',
|
||||||
type: 'P2PKH',
|
type: 'P2PKH',
|
||||||
hash: hash,
|
hash,
|
||||||
format: 'legacy'
|
format: 'legacy'
|
||||||
}
|
}
|
||||||
case info.test.versions.scripthash:
|
case info.test.versions.scripthash:
|
||||||
return {
|
return {
|
||||||
prefix: 'bchtest',
|
prefix: 'bchtest',
|
||||||
type: 'P2SH',
|
type: 'P2SH',
|
||||||
hash: hash,
|
hash,
|
||||||
format: 'legacy'
|
format: 'legacy'
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -842,4 +860,4 @@ class Address {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Address
|
export default Address
|
||||||
|
|||||||
+105
-49
@@ -7,36 +7,44 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// bch-api mainnet.
|
// bch-api mainnet.
|
||||||
const DEFAULT_REST_API = 'https://api.fullstack.cash/v5/'
|
|
||||||
// const DEFAULT_REST_API = "http://localhost:3000/v5/"
|
// const DEFAULT_REST_API = "http://localhost:3000/v5/"
|
||||||
|
|
||||||
|
// Global npm libraries
|
||||||
|
import axios from 'axios'
|
||||||
|
import {
|
||||||
|
createSigner,
|
||||||
|
withPaymentInterceptor,
|
||||||
|
createPaymentHeader,
|
||||||
|
selectPaymentRequirements
|
||||||
|
} from 'x402-bch-axios'
|
||||||
|
|
||||||
// local deps
|
// local deps
|
||||||
const BitcoinCash = require('./bitcoincash')
|
import BitcoinCash from './bitcoincash.js'
|
||||||
const Crypto = require('./crypto')
|
import Crypto from './crypto.js'
|
||||||
const Util = require('./util')
|
import Util from './util.js'
|
||||||
const Blockchain = require('./blockchain')
|
import Blockchain from './blockchain.js'
|
||||||
const Control = require('./control')
|
import Control from './control.js'
|
||||||
const Generating = require('./generating')
|
import Generating from './generating.js'
|
||||||
const Mining = require('./mining')
|
import Mining from './mining.js'
|
||||||
const RawTransactions = require('./raw-transactions')
|
import RawTransactions from './raw-transactions.js'
|
||||||
const Mnemonic = require('./mnemonic')
|
import Mnemonic from './mnemonic.js'
|
||||||
const Address = require('./address')
|
import Address from './address.js'
|
||||||
const HDNode = require('./hdnode')
|
import HDNode from './hdnode.js'
|
||||||
const TransactionBuilder = require('./transaction-builder')
|
import TransactionBuilder from './transaction-builder.js'
|
||||||
const ECPair = require('./ecpair')
|
import ECPair from './ecpair.js'
|
||||||
const Script = require('./script')
|
import Script from './script.js'
|
||||||
const Price = require('./price')
|
import Price from './price.js'
|
||||||
const Schnorr = require('./schnorr')
|
import Schnorr from './schnorr.js'
|
||||||
const SLP = require('./slp/slp')
|
import SLP from './slp/slp.js'
|
||||||
const Encryption = require('./encryption')
|
import Encryption from './encryption.js'
|
||||||
const Utxo = require('./utxo')
|
import Utxo from './utxo.js'
|
||||||
const Transaction = require('./transaction')
|
import Transaction from './transaction.js'
|
||||||
const DSProof = require('./dsproof')
|
import DSProof from './dsproof.js'
|
||||||
const Ecash = require('./ecash')
|
import Ecash from './ecash.js'
|
||||||
|
|
||||||
// Indexers
|
// Indexers
|
||||||
const Electrumx = require('./electrumx')
|
import Electrumx from './electrumx.js'
|
||||||
const PsfSlpIndexer = require('./psf-slp-indexer')
|
import PsfSlpIndexer from './psf-slp-indexer.js'
|
||||||
|
|
||||||
class BCHJS {
|
class BCHJS {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
@@ -45,41 +53,81 @@ class BCHJS {
|
|||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
} else if (process.env.RESTURL && process.env.RESTURL !== '') {
|
} else if (process.env.RESTURL && process.env.RESTURL !== '') {
|
||||||
this.restURL = process.env.RESTURL
|
this.restURL = process.env.RESTURL
|
||||||
} else this.restURL = DEFAULT_REST_API
|
} else {
|
||||||
|
throw new Error(
|
||||||
// Retrieve the apiToken
|
'REST API URL is required. Provide config.restURL or set the RESTURL environment variable.'
|
||||||
this.apiToken = '' // default value.
|
)
|
||||||
if (config && config.apiToken && config.apiToken !== '') {
|
|
||||||
this.apiToken = config.apiToken
|
|
||||||
} else if (process.env.BCHJSTOKEN && process.env.BCHJSTOKEN !== '') {
|
|
||||||
this.apiToken = process.env.BCHJSTOKEN
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the Basic Authentication password.
|
// Normalize restURL to always have a trailing slash
|
||||||
this.authPass = '' // default value.
|
if (!this.restURL.endsWith('/')) {
|
||||||
if (config && config.authPass && config.authPass !== '') {
|
this.restURL = this.restURL + '/'
|
||||||
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
|
// Retrieve the Bearer token for simple token authentication.
|
||||||
|
this.bearerToken = '' // default value.
|
||||||
|
if (config && config.bearerToken && config.bearerToken !== '') {
|
||||||
|
this.bearerToken = config.bearerToken
|
||||||
|
} else if (process.env.BCHJSBEARERTOKEN && process.env.BCHJSBEARERTOKEN !== '') {
|
||||||
|
this.bearerToken = process.env.BCHJSBEARERTOKEN
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the authentication token for the authorization header.
|
||||||
this.authToken = ''
|
this.authToken = ''
|
||||||
if (this.authPass) {
|
if (this.bearerToken) {
|
||||||
// console.log(`bch-js initialized with authPass: ${this.authPass}`)
|
this.authToken = `Bearer ${this.bearerToken}`
|
||||||
// Generate the header for Basic Authentication.
|
}
|
||||||
const combined = `fullstackcash:${this.authPass}`
|
|
||||||
const base64Credential = Buffer.from(combined).toString('base64')
|
// x402 payment configuration
|
||||||
this.authToken = `Basic ${base64Credential}`
|
// If a WIF private key is provided, enable x402 automatic payment handling
|
||||||
|
this.wif = ''
|
||||||
|
if (config && config.wif && config.wif !== '') {
|
||||||
|
this.wif = config.wif
|
||||||
|
} else if (process.env.BCHJSWIF && process.env.BCHJSWIF !== '') {
|
||||||
|
this.wif = process.env.BCHJSWIF
|
||||||
|
}
|
||||||
|
|
||||||
|
// Most TXs cost about 250 sats. So we'll set the default to 25000 sats,
|
||||||
|
// so the mining fee is 1% of the transaction.
|
||||||
|
this.paymentAmountSats = (config && config.paymentAmountSats) || 25000
|
||||||
|
|
||||||
|
// BCH server URL for x402 payments (separate from REST API server)
|
||||||
|
// This is used when broadcasting payment transactions to the blockchain
|
||||||
|
if (config && config.bchServerURL && config.bchServerURL !== '') {
|
||||||
|
this.bchServerURL = config.bchServerURL
|
||||||
|
} else if (process.env.BCHJSBCHSERVERURL && process.env.BCHJSBCHSERVERURL !== '') {
|
||||||
|
this.bchServerURL = process.env.BCHJSBCHSERVERURL
|
||||||
|
} else {
|
||||||
|
this.bchServerURL = 'https://bch.fullstack.cash/v6'
|
||||||
}
|
}
|
||||||
|
|
||||||
const libConfig = {
|
const libConfig = {
|
||||||
restURL: this.restURL,
|
restURL: this.restURL,
|
||||||
apiToken: this.apiToken,
|
|
||||||
authToken: this.authToken
|
authToken: this.authToken
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log(`apiToken: ${this.apiToken}`)
|
// If WIF is provided, create an axios instance with x402 payment interceptor
|
||||||
|
// Otherwise, let sub-modules use their own axios import for backwards compatibility
|
||||||
|
if (this.wif) {
|
||||||
|
let axiosInstance = axios.create({
|
||||||
|
baseURL: this.restURL,
|
||||||
|
headers: {
|
||||||
|
authorization: this.authToken
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const signer = createSigner(this.wif, this.paymentAmountSats)
|
||||||
|
axiosInstance = withPaymentInterceptor(
|
||||||
|
axiosInstance,
|
||||||
|
signer,
|
||||||
|
{
|
||||||
|
apiType: 'rest-api',
|
||||||
|
bchServerURL: this.bchServerURL
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
libConfig.axios = axiosInstance
|
||||||
|
}
|
||||||
|
|
||||||
// ElectrumX indexer
|
// ElectrumX indexer
|
||||||
this.Electrumx = new Electrumx(libConfig)
|
this.Electrumx = new Electrumx(libConfig)
|
||||||
@@ -117,7 +165,15 @@ class BCHJS {
|
|||||||
this.eCash = new Ecash()
|
this.eCash = new Ecash()
|
||||||
|
|
||||||
this.PsfSlpIndexer = new PsfSlpIndexer(libConfig)
|
this.PsfSlpIndexer = new PsfSlpIndexer(libConfig)
|
||||||
|
|
||||||
|
// Expose x402 helper functions for advanced use cases
|
||||||
|
this.x402 = {
|
||||||
|
createSigner,
|
||||||
|
withPaymentInterceptor,
|
||||||
|
createPaymentHeader,
|
||||||
|
selectPaymentRequirements
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = BCHJS
|
export default BCHJS
|
||||||
|
|||||||
+10
-11
@@ -1,13 +1,12 @@
|
|||||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
import Bitcoin from '@psf/bitcoincashjs-lib'
|
||||||
const sb = require('satoshi-bitcoin')
|
import sb from 'satoshi-bitcoin'
|
||||||
const bitcoinMessage = require('bitcoinjs-message')
|
import bitcoinMessage from 'bitcoinjs-message'
|
||||||
const bs58 = require('bs58')
|
import bs58 from 'bs58'
|
||||||
const bip21 = require('@psf/bip21')
|
import bip21 from '@psf/bip21'
|
||||||
const coininfo = require('@psf/coininfo')
|
import coininfo from '@psf/coininfo'
|
||||||
const bip38 = require('bip38')
|
import bip38 from 'bip38'
|
||||||
const wif = require('wif')
|
import wif from 'wif'
|
||||||
|
import { Buffer } from 'safe-buffer'
|
||||||
const Buffer = require('safe-buffer').Buffer
|
|
||||||
|
|
||||||
class BitcoinCash {
|
class BitcoinCash {
|
||||||
constructor (address) {
|
constructor (address) {
|
||||||
@@ -519,4 +518,4 @@ class BitcoinCash {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = BitcoinCash
|
export default BitcoinCash
|
||||||
|
|||||||
+157
-106
@@ -3,33 +3,22 @@
|
|||||||
- Add blockhash functionality back into getTxOutProof
|
- Add blockhash functionality back into getTxOutProof
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
|
|
||||||
// let _this
|
// let _this
|
||||||
|
|
||||||
class Blockchain {
|
class Blockchain {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||||
|
this.axios = config.axios || axios
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// _this = this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,14 +41,17 @@ class Blockchain {
|
|||||||
*/
|
*/
|
||||||
async getBestBlockHash () {
|
async getBestBlockHash () {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/getBestBlockHash`,
|
`${this.restURL}full-node/blockchain/getBestBlockHash`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,8 +98,8 @@ class Blockchain {
|
|||||||
if (!blockhash || typeof blockhash !== 'string') {
|
if (!blockhash || typeof blockhash !== 'string') {
|
||||||
throw new Error('blockhash must be a string')
|
throw new Error('blockhash must be a string')
|
||||||
}
|
}
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}blockchain/getblock`,
|
`${this.restURL}full-node/blockchain/getblock`,
|
||||||
{
|
{
|
||||||
blockhash,
|
blockhash,
|
||||||
verbosity
|
verbosity
|
||||||
@@ -116,8 +108,11 @@ class Blockchain {
|
|||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,14 +155,17 @@ class Blockchain {
|
|||||||
*/
|
*/
|
||||||
async getBlockchainInfo () {
|
async getBlockchainInfo () {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/getBlockchainInfo`,
|
`${this.restURL}full-node/blockchain/getBlockchainInfo`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,14 +189,20 @@ class Blockchain {
|
|||||||
*/
|
*/
|
||||||
async getBlockCount () {
|
async getBlockCount () {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/getBlockCount`,
|
`${this.restURL}full-node/blockchain/getBlockCount`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
console.log('Error in bch-js/blockchain.js/getBlockCount()')
|
||||||
else throw error
|
console.log('blockchain.js restURL: ', this.restURL)
|
||||||
|
|
||||||
|
if (error.response && error.response.data) {
|
||||||
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,14 +228,17 @@ class Blockchain {
|
|||||||
if (typeof height !== 'string') height = JSON.stringify(height)
|
if (typeof height !== 'string') height = JSON.stringify(height)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/getBlockHash/${height}`,
|
`${this.restURL}full-node/blockchain/getBlockHash/${height}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,8 +278,8 @@ class Blockchain {
|
|||||||
try {
|
try {
|
||||||
// Handle single hash.
|
// Handle single hash.
|
||||||
if (typeof hash === 'string') {
|
if (typeof hash === 'string') {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/getBlockHeader/${hash}?verbose=${verbose}`,
|
`${this.restURL}full-node/blockchain/getBlockHeader/${hash}?verbose=${verbose}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -281,11 +288,11 @@ class Blockchain {
|
|||||||
// Handle array of hashes.
|
// Handle array of hashes.
|
||||||
} else if (Array.isArray(hash)) {
|
} else if (Array.isArray(hash)) {
|
||||||
// Dev note: must use axios.post for unit test stubbing.
|
// Dev note: must use axios.post for unit test stubbing.
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}blockchain/getBlockHeader`,
|
`${this.restURL}full-node/blockchain/getBlockHeader`,
|
||||||
{
|
{
|
||||||
hashes: hash,
|
hashes: hash,
|
||||||
verbose: verbose
|
verbose
|
||||||
},
|
},
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
@@ -295,8 +302,13 @@ class Blockchain {
|
|||||||
|
|
||||||
throw new Error('Input hash must be a string or array of strings.')
|
throw new Error('Input hash must be a string or array of strings.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
// console.log('Error in bch-js/blockchain.js/getBlockHeader() error: ', error)
|
||||||
else throw error
|
|
||||||
|
if (error.response && error.response.data) {
|
||||||
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,14 +344,17 @@ class Blockchain {
|
|||||||
*/
|
*/
|
||||||
async getChainTips () {
|
async getChainTips () {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/getChainTips`,
|
`${this.restURL}full-node/blockchain/getChainTips`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,14 +379,17 @@ class Blockchain {
|
|||||||
*/
|
*/
|
||||||
async getDifficulty () {
|
async getDifficulty () {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/getDifficulty`,
|
`${this.restURL}full-node/blockchain/getDifficulty`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,14 +398,17 @@ class Blockchain {
|
|||||||
if (typeof txid !== 'string') txid = JSON.stringify(txid)
|
if (typeof txid !== 'string') txid = JSON.stringify(txid)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/getMempoolAncestors/${txid}?verbose=${verbose}`,
|
`${this.restURL}full-node/blockchain/getMempoolAncestors/${txid}?verbose=${verbose}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,14 +416,17 @@ class Blockchain {
|
|||||||
if (typeof txid !== 'string') txid = JSON.stringify(txid)
|
if (typeof txid !== 'string') txid = JSON.stringify(txid)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/getMempoolDescendants/${txid}?verbose=${verbose}`,
|
`${this.restURL}full-node/blockchain/getMempoolDescendants/${txid}?verbose=${verbose}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,16 +516,16 @@ class Blockchain {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof txid === 'string') {
|
if (typeof txid === 'string') {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/getMempoolEntry/${txid}`,
|
`${this.restURL}full-node/blockchain/getMempoolEntry/${txid}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
return response.data
|
return response.data
|
||||||
} else if (Array.isArray(txid)) {
|
} else if (Array.isArray(txid)) {
|
||||||
// Dev note: must use axios.post for unit test stubbing.
|
// Dev note: must use axios.post for unit test stubbing.
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}blockchain/getMempoolEntry`,
|
`${this.restURL}full-node/blockchain/getMempoolEntry`,
|
||||||
{
|
{
|
||||||
txids: txid
|
txids: txid
|
||||||
},
|
},
|
||||||
@@ -513,8 +537,11 @@ class Blockchain {
|
|||||||
|
|
||||||
throw new Error('Input must be a string or array of strings.')
|
throw new Error('Input must be a string or array of strings.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,14 +570,17 @@ class Blockchain {
|
|||||||
*/
|
*/
|
||||||
async getMempoolInfo () {
|
async getMempoolInfo () {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/getMempoolInfo`,
|
`${this.restURL}full-node/blockchain/getMempoolInfo`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,14 +620,17 @@ class Blockchain {
|
|||||||
*/
|
*/
|
||||||
async getRawMempool (verbose = false) {
|
async getRawMempool (verbose = false) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/getRawMempool?vebose=${verbose}`,
|
`${this.restURL}full-node/blockchain/getRawMempool?vebose=${verbose}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,14 +667,14 @@ class Blockchain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send the request to the REST API.
|
// Send the request to the REST API.
|
||||||
// const response = await axios.get(
|
// const response = await this.axios.get(
|
||||||
// `${this.restURL}blockchain/getTxOut/${txid}/${n}?includeMempool=${includeMempool}`,
|
// `${this.restURL}blockchain/getTxOut/${txid}/${n}?includeMempool=${includeMempool}`,
|
||||||
// this.axiosOptions
|
// this.axiosOptions
|
||||||
// )
|
// )
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}blockchain/getTxOut`,
|
`${this.restURL}full-node/blockchain/getTxOut`,
|
||||||
{
|
{
|
||||||
txid: txid,
|
txid,
|
||||||
vout: n,
|
vout: n,
|
||||||
mempool: includeMempool
|
mempool: includeMempool
|
||||||
},
|
},
|
||||||
@@ -650,8 +683,11 @@ class Blockchain {
|
|||||||
|
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -695,19 +731,19 @@ class Blockchain {
|
|||||||
try {
|
try {
|
||||||
// Single txid.
|
// Single txid.
|
||||||
if (typeof txids === 'string') {
|
if (typeof txids === 'string') {
|
||||||
const path = `${this.restURL}blockchain/getTxOutProof/${txids}`
|
const path = `${this.restURL}full-node/blockchain/getTxOutProof/${txids}`
|
||||||
// if (blockhash) path = `${path}?blockhash=${blockhash}`
|
// if (blockhash) path = `${path}?blockhash=${blockhash}`
|
||||||
|
|
||||||
const response = await axios.get(path, this.axiosOptions)
|
const response = await this.axios.get(path, this.axiosOptions)
|
||||||
return response.data
|
return response.data
|
||||||
|
|
||||||
// Array of txids.
|
// Array of txids.
|
||||||
} else if (Array.isArray(txids)) {
|
} else if (Array.isArray(txids)) {
|
||||||
// Dev note: must use axios.post for unit test stubbing.
|
// Dev note: must use axios.post for unit test stubbing.
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}blockchain/getTxOutProof`,
|
`${this.restURL}full-node/blockchain/getTxOutProof`,
|
||||||
{
|
{
|
||||||
txids: txids
|
txids
|
||||||
},
|
},
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
@@ -717,47 +753,59 @@ class Blockchain {
|
|||||||
|
|
||||||
throw new Error('Input must be a string or array of strings.')
|
throw new Error('Input must be a string or array of strings.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async preciousBlock (blockhash) {
|
async preciousBlock (blockhash) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/preciousBlock/${blockhash}`,
|
`${this.restURL}full-node/blockchain/preciousBlock/${blockhash}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async pruneBlockchain (height) {
|
async pruneBlockchain (height) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}blockchain/pruneBlockchain/${height}`,
|
`${this.restURL}full-node/blockchain/pruneBlockchain/${height}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async verifyChain (checklevel = 3, nblocks = 6) {
|
async verifyChain (checklevel = 3, nblocks = 6) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}`,
|
`${this.restURL}full-node/blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,8 +850,8 @@ class Blockchain {
|
|||||||
try {
|
try {
|
||||||
// Single block
|
// Single block
|
||||||
if (typeof proof === 'string') {
|
if (typeof proof === 'string') {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}blockchain/verifyTxOutProof/${proof}`,
|
`${this.restURL}full-node/blockchain/verifyTxOutProof/${proof}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
@@ -811,8 +859,8 @@ class Blockchain {
|
|||||||
// Array of hashes.
|
// Array of hashes.
|
||||||
} else if (Array.isArray(proof)) {
|
} else if (Array.isArray(proof)) {
|
||||||
// Dev note: must use axios.post for unit test stubbing.
|
// Dev note: must use axios.post for unit test stubbing.
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}blockchain/verifyTxOutProof`,
|
`${this.restURL}full-node/blockchain/verifyTxOutProof`,
|
||||||
{
|
{
|
||||||
proofs: proof
|
proofs: proof
|
||||||
},
|
},
|
||||||
@@ -824,10 +872,13 @@ class Blockchain {
|
|||||||
|
|
||||||
throw new Error('Input must be a string or array of strings.')
|
throw new Error('Input must be a string or array of strings.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Blockchain
|
export default Blockchain
|
||||||
|
|||||||
+11
-22
@@ -2,33 +2,22 @@
|
|||||||
API endpoints for basic control and information of the full node.
|
API endpoints for basic control and information of the full node.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
|
|
||||||
// let _this // Global reference to the instance of this class.
|
// let _this // Global reference to the instance of this class.
|
||||||
|
|
||||||
class Control {
|
class Control {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||||
|
this.axios = config.axios || axios
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// _this = this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -79,8 +68,8 @@ class Control {
|
|||||||
*/
|
*/
|
||||||
async getNetworkInfo () {
|
async getNetworkInfo () {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}control/getNetworkInfo`,
|
`${this.restURL}full-node/control/getNetworkInfo`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
@@ -92,8 +81,8 @@ class Control {
|
|||||||
|
|
||||||
async getMemoryInfo () {
|
async getMemoryInfo () {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}control/getMemoryInfo`,
|
`${this.restURL}full-node/control/getMemoryInfo`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
@@ -115,4 +104,4 @@ class Control {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Control
|
export default Control
|
||||||
|
|||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
const randomBytes = require('randombytes')
|
import randomBytes from 'randombytes'
|
||||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
import Bitcoin from '@psf/bitcoincashjs-lib'
|
||||||
|
|
||||||
class Crypto {
|
class Crypto {
|
||||||
/**
|
/**
|
||||||
@@ -135,4 +135,4 @@ class Crypto {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Crypto
|
export default Crypto
|
||||||
|
|||||||
+13
-20
@@ -1,27 +1,17 @@
|
|||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
|
|
||||||
class DSProof {
|
class DSProof {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
this.axios = axios
|
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||||
|
this.axios = config.axios || axios
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,15 +57,18 @@ class DSProof {
|
|||||||
throw new Error(`txid must be of length 64 (not ${txid.length})`)
|
throw new Error(`txid must be of length 64 (not ${txid.length})`)
|
||||||
}
|
}
|
||||||
const response = await _this.axios.get(
|
const response = await _this.axios.get(
|
||||||
`${this.restURL}dsproof/getdsproof/${txid}`,
|
`${this.restURL}full-node/dsproof/getdsproof/${txid}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = DSProof
|
export default DSProof
|
||||||
|
|||||||
+1
-1
@@ -44,4 +44,4 @@ class eCash {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = eCash
|
export default eCash
|
||||||
|
|||||||
+3
-3
@@ -1,5 +1,5 @@
|
|||||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
import Bitcoin from '@psf/bitcoincashjs-lib'
|
||||||
const coininfo = require('@psf/coininfo')
|
import coininfo from '@psf/coininfo'
|
||||||
|
|
||||||
class ECPair {
|
class ECPair {
|
||||||
static setAddress (address) {
|
static setAddress (address) {
|
||||||
@@ -166,4 +166,4 @@ class ECPair {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ECPair
|
export default ECPair
|
||||||
|
|||||||
+80
-61
@@ -3,38 +3,29 @@
|
|||||||
by FullStack.cash
|
by FullStack.cash
|
||||||
*/
|
*/
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
|
|
||||||
// Local libraries.
|
// Local libraries.
|
||||||
const Blockchain = require('./blockchain')
|
import Blockchain from './blockchain.js'
|
||||||
|
// const Address = require('./address')
|
||||||
|
|
||||||
// let _this
|
// let _this
|
||||||
|
|
||||||
class ElectrumX {
|
class ElectrumX {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||||
|
this.axios = config.axios || axios
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encapsulate dependencies
|
||||||
this.blockchain = new Blockchain(config)
|
this.blockchain = new Blockchain(config)
|
||||||
|
|
||||||
// _this = this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,7 +35,7 @@ class ElectrumX {
|
|||||||
* @apiDescription Return a list of uxtos for an address.
|
* @apiDescription Return a list of uxtos for an address.
|
||||||
*
|
*
|
||||||
* @apiExample Example usage:
|
* @apiExample Example usage:
|
||||||
* (async () => {
|
* (async () => {
|
||||||
* try {
|
* try {
|
||||||
* let utxo = await bchjs.Electrumx.utxo('bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9');
|
* let utxo = await bchjs.Electrumx.utxo('bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9');
|
||||||
* console.log(utxo);
|
* console.log(utxo);
|
||||||
@@ -104,18 +95,20 @@ class ElectrumX {
|
|||||||
*/
|
*/
|
||||||
async utxo (address) {
|
async utxo (address) {
|
||||||
try {
|
try {
|
||||||
|
// console.log(`electrumx.js/utxo() restURL: ${this.restURL}`)
|
||||||
|
|
||||||
// Handle single address.
|
// Handle single address.
|
||||||
if (typeof address === 'string') {
|
if (typeof address === 'string') {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}electrumx/utxos/${address}`,
|
`${this.restURL}fulcrum/utxos/${address}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
|
|
||||||
// Handle array of addresses.
|
// Handle array of addresses.
|
||||||
} else if (Array.isArray(address)) {
|
} else if (Array.isArray(address)) {
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}electrumx/utxos`,
|
`${this.restURL}fulcrum/utxos`,
|
||||||
{
|
{
|
||||||
addresses: address
|
addresses: address
|
||||||
},
|
},
|
||||||
@@ -127,8 +120,11 @@ class ElectrumX {
|
|||||||
|
|
||||||
throw new Error('Input address must be a string or array of strings.')
|
throw new Error('Input address must be a string or array of strings.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,16 +186,16 @@ class ElectrumX {
|
|||||||
try {
|
try {
|
||||||
// Handle single address.
|
// Handle single address.
|
||||||
if (typeof address === 'string') {
|
if (typeof address === 'string') {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}electrumx/balance/${address}`,
|
`${this.restURL}fulcrum/balance/${address}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
|
|
||||||
// Handle array of addresses.
|
// Handle array of addresses.
|
||||||
} else if (Array.isArray(address)) {
|
} else if (Array.isArray(address)) {
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}electrumx/balance`,
|
`${this.restURL}fulcrum/balance`,
|
||||||
{
|
{
|
||||||
addresses: address
|
addresses: address
|
||||||
},
|
},
|
||||||
@@ -211,8 +207,11 @@ class ElectrumX {
|
|||||||
|
|
||||||
throw new Error('Input address must be a string or array of strings.')
|
throw new Error('Input address must be a string or array of strings.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,23 +283,24 @@ class ElectrumX {
|
|||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
async transactions (address, usrObj = null) {
|
async transactions (address, usrObj = null, allTxs = false) {
|
||||||
try {
|
try {
|
||||||
// Handle single address.
|
// Handle single address.
|
||||||
if (typeof address === 'string') {
|
if (typeof address === 'string') {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}electrumx/transactions/${address}`,
|
`${this.restURL}fulcrum/transactions/${address}/${allTxs}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
|
|
||||||
// Handle array of addresses.
|
// Handle array of addresses.
|
||||||
} else if (Array.isArray(address)) {
|
} else if (Array.isArray(address)) {
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}electrumx/transactions`,
|
`${this.restURL}fulcrum/transactions`,
|
||||||
{
|
{
|
||||||
addresses: address,
|
addresses: address,
|
||||||
usrObj // pass user data when making an internal call.
|
usrObj, // pass user data when making an internal call.
|
||||||
|
allTxs
|
||||||
},
|
},
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
@@ -310,8 +310,12 @@ class ElectrumX {
|
|||||||
|
|
||||||
throw new Error('Input address must be a string or array of strings.')
|
throw new Error('Input address must be a string or array of strings.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
// console.log('Error in transactions(): ', error)
|
||||||
else throw error
|
if (error.response && error.response.data) {
|
||||||
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,16 +385,16 @@ class ElectrumX {
|
|||||||
try {
|
try {
|
||||||
// Handle single address.
|
// Handle single address.
|
||||||
if (typeof address === 'string') {
|
if (typeof address === 'string') {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}electrumx/unconfirmed/${address}`,
|
`${this.restURL}fulcrum/unconfirmed/${address}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
|
|
||||||
// Handle array of addresses.
|
// Handle array of addresses.
|
||||||
} else if (Array.isArray(address)) {
|
} else if (Array.isArray(address)) {
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}electrumx/unconfirmed`,
|
`${this.restURL}fulcrum/unconfirmed`,
|
||||||
{
|
{
|
||||||
addresses: address
|
addresses: address
|
||||||
},
|
},
|
||||||
@@ -402,8 +406,11 @@ class ElectrumX {
|
|||||||
|
|
||||||
throw new Error('Input address must be a string or array of strings.')
|
throw new Error('Input address must be a string or array of strings.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,17 +457,21 @@ class ElectrumX {
|
|||||||
*/
|
*/
|
||||||
async blockHeader (height, count = 1) {
|
async blockHeader (height, count = 1) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}electrumx/block/headers/${height}?count=${count}`,
|
`${this.restURL}fulcrum/block/headers/${height}?count=${count}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.log("error: ", error)
|
// console.log("error: ", error)
|
||||||
if (error.response && error.response.data) {
|
if (error.response && error.response.data) {
|
||||||
if (error.response && error.response.data) {
|
const errorData = error.response.data
|
||||||
throw new Error(error.response.data.error)
|
if (errorData.error) {
|
||||||
} else throw error.response.data
|
throw new Error(errorData.error)
|
||||||
|
} else {
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
@@ -541,14 +552,14 @@ class ElectrumX {
|
|||||||
try {
|
try {
|
||||||
// Handle single transaction.
|
// Handle single transaction.
|
||||||
if (typeof txid === 'string') {
|
if (typeof txid === 'string') {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}electrumx/tx/data/${txid}`,
|
`${this.restURL}fulcrum/tx/data/${txid}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} else if (Array.isArray(txid)) {
|
} else if (Array.isArray(txid)) {
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}electrumx/tx/data`,
|
`${this.restURL}fulcrum/tx/data`,
|
||||||
{
|
{
|
||||||
txids: txid
|
txids: txid
|
||||||
},
|
},
|
||||||
@@ -560,8 +571,11 @@ class ElectrumX {
|
|||||||
|
|
||||||
throw new Error('Input txId must be a string or array of strings.')
|
throw new Error('Input txId must be a string or array of strings.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,8 +603,8 @@ class ElectrumX {
|
|||||||
async broadcast (txHex) {
|
async broadcast (txHex) {
|
||||||
try {
|
try {
|
||||||
if (typeof txHex === 'string') {
|
if (typeof txHex === 'string') {
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}electrumx/tx/broadcast`,
|
`${this.restURL}fulcrum/tx/broadcast`,
|
||||||
{ txHex },
|
{ txHex },
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
@@ -600,8 +614,11 @@ class ElectrumX {
|
|||||||
|
|
||||||
throw new Error('Input txHex must be a string.')
|
throw new Error('Input txHex must be a string.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) {
|
||||||
else throw error
|
const errorData = error.response.data
|
||||||
|
const errorMessage = typeof errorData === 'string' ? errorData : (errorData.error || errorData.message || JSON.stringify(errorData))
|
||||||
|
throw new Error(errorMessage)
|
||||||
|
} else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -713,9 +730,11 @@ class ElectrumX {
|
|||||||
return this.sortConfTxs(modifiedTxs, sortingOrder)
|
return this.sortConfTxs(modifiedTxs, sortingOrder)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('Error in util.js/sort0ConfTxs')
|
console.log('Error in util.js/sort0ConfTxs')
|
||||||
|
console.log('electrumx.js restURL: ', this.restURL)
|
||||||
|
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ElectrumX
|
export default ElectrumX
|
||||||
|
|||||||
+30
-17
@@ -2,36 +2,49 @@
|
|||||||
This library contains useful functions that deal with encryption.
|
This library contains useful functions that deal with encryption.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
|
|
||||||
class Encryption {
|
class Encryption {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.axios = axios
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||||
|
this.axios = config.axios || axios
|
||||||
|
|
||||||
_this = this
|
_this = this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api encryption.getPubKey() getPubKey()
|
||||||
|
* @apiName Encryption getPubKey()
|
||||||
|
* @apiGroup Encryption
|
||||||
|
* @apiDescription Get the public key for an address
|
||||||
|
* Given an address, the command will search the blockchain for a public
|
||||||
|
* key associated with that address. The address needs to have made at least
|
||||||
|
* one spend transaction, in order for its public key to be retrievable.
|
||||||
|
*
|
||||||
|
* @apiExample Example usage:
|
||||||
|
*(async () => {
|
||||||
|
* try {
|
||||||
|
* const addr = 'bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d'
|
||||||
|
* const pubkey = await bchjs.encryption.getPubKey(addr);
|
||||||
|
* console.log(pubkey);
|
||||||
|
* } catch(err) {
|
||||||
|
* console.error(err)
|
||||||
|
* }
|
||||||
|
*})()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
// Search the blockchain for a public key associated with a BCH address.
|
// Search the blockchain for a public key associated with a BCH address.
|
||||||
async getPubKey (addr) {
|
async getPubKey (addr) {
|
||||||
try {
|
try {
|
||||||
@@ -51,4 +64,4 @@ class Encryption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Encryption
|
export default Encryption
|
||||||
|
|||||||
+8
-19
@@ -1,35 +1,24 @@
|
|||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
|
|
||||||
// let _this
|
// let _this
|
||||||
|
|
||||||
class Generating {
|
class Generating {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||||
|
this.axios = config.axios || axios
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// _this = this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async generateToAddress (blocks, address, maxtries = 1000000) {
|
async generateToAddress (blocks, address, maxtries = 1000000) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}generating/generateToAddress/${blocks}/${address}?maxtries=${maxtries}`,
|
`${this.restURL}generating/generateToAddress/${blocks}/${address}?maxtries=${maxtries}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
@@ -41,4 +30,4 @@ class Generating {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Generating
|
export default Generating
|
||||||
|
|||||||
+5
-5
@@ -1,7 +1,7 @@
|
|||||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
import Bitcoin from '@psf/bitcoincashjs-lib'
|
||||||
const coininfo = require('@psf/coininfo')
|
import coininfo from '@psf/coininfo'
|
||||||
const bip32utils = require('@chris.troutner/bip32-utils')
|
import bip32utils from '@chris.troutner/bip32-utils'
|
||||||
const bchaddrjs = require('bchaddrjs-slp')
|
import bchaddrjs from 'bchaddrjs-slp'
|
||||||
|
|
||||||
class HDNode {
|
class HDNode {
|
||||||
constructor (address) {
|
constructor (address) {
|
||||||
@@ -637,4 +637,4 @@ class HDNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = HDNode
|
export default HDNode
|
||||||
|
|||||||
+11
-22
@@ -1,35 +1,24 @@
|
|||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
|
|
||||||
// let _this
|
// let _this
|
||||||
|
|
||||||
class Mining {
|
class Mining {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||||
|
this.axios = config.axios || axios
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// _this = this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getBlockTemplate (templateRequest) {
|
async getBlockTemplate (templateRequest) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}mining/getBlockTemplate/${templateRequest}`,
|
`${this.restURL}mining/getBlockTemplate/${templateRequest}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
@@ -42,7 +31,7 @@ class Mining {
|
|||||||
|
|
||||||
async getMiningInfo () {
|
async getMiningInfo () {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}mining/getMiningInfo`,
|
`${this.restURL}mining/getMiningInfo`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
@@ -55,7 +44,7 @@ class Mining {
|
|||||||
|
|
||||||
async getNetworkHashps (nblocks = 120, height = 1) {
|
async getNetworkHashps (nblocks = 120, height = 1) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}mining/getNetworkHashps?nblocks=${nblocks}&height=${height}`,
|
`${this.restURL}mining/getNetworkHashps?nblocks=${nblocks}&height=${height}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
@@ -71,7 +60,7 @@ class Mining {
|
|||||||
if (parameters) path = `${path}?parameters=${parameters}`
|
if (parameters) path = `${path}?parameters=${parameters}`
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(path, this.axiosOptions)
|
const response = await this.axios.post(path, this.axiosOptions)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data) throw error.response.data
|
||||||
@@ -80,4 +69,4 @@ class Mining {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Mining
|
export default Mining
|
||||||
|
|||||||
+8
-11
@@ -1,11 +1,8 @@
|
|||||||
/* eslint no-prototype-builtins: "off" */
|
import BIP39 from 'bip39'
|
||||||
/* eslint node/no-callback-literal: "off" */
|
import randomBytes from 'randombytes'
|
||||||
|
import Bitcoin from '@psf/bitcoincashjs-lib'
|
||||||
const BIP39 = require('bip39')
|
import { Buffer } from 'safe-buffer'
|
||||||
const randomBytes = require('randombytes')
|
import wif from 'wif'
|
||||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
|
||||||
const Buffer = require('safe-buffer').Buffer
|
|
||||||
const wif = require('wif')
|
|
||||||
|
|
||||||
class Mnemonic {
|
class Mnemonic {
|
||||||
constructor (address) {
|
constructor (address) {
|
||||||
@@ -338,7 +335,7 @@ class Mnemonic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Mnemonic
|
export default Mnemonic
|
||||||
|
|
||||||
// The following code is from: https://raw.githubusercontent.com/iancoleman/bip39/7ff86d4c983f1e8c80b87b31acfd69fcf98c1b82/src/js/levenshtein.js
|
// The following code is from: https://raw.githubusercontent.com/iancoleman/bip39/7ff86d4c983f1e8c80b87b31acfd69fcf98c1b82/src/js/levenshtein.js
|
||||||
|
|
||||||
@@ -356,7 +353,7 @@ const _extend = function (dst) {
|
|||||||
const sources = Array.prototype.slice.call(arguments, 1)
|
const sources = Array.prototype.slice.call(arguments, 1)
|
||||||
for (let i = 0; i < sources.length; ++i) {
|
for (let i = 0; i < sources.length; ++i) {
|
||||||
const src = sources[i]
|
const src = sources[i]
|
||||||
for (const p in src) if (src.hasOwnProperty(p)) dst[p] = src[p]
|
for (const p in src) if (Object.prototype.hasOwnProperty.call(src, p)) dst[p] = src[p]
|
||||||
}
|
}
|
||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
@@ -503,7 +500,7 @@ const Levenshtein = {
|
|||||||
try {
|
try {
|
||||||
options.progress.call(null, (i * 100.0) / str1.length)
|
options.progress.call(null, (i * 100.0) / str1.length)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return cb(`Progress callback: ${err.toString()}`)
|
return cb(new Error(`Progress callback: ${err.toString()}`))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+44
-109
@@ -1,47 +1,20 @@
|
|||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
|
|
||||||
// let _this
|
// let _this
|
||||||
|
|
||||||
class Price {
|
class Price {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
// _this = this
|
|
||||||
|
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.axios = axios
|
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||||
}
|
this.axios = config.axios || axios
|
||||||
|
|
||||||
// This endpoint is deprecated. Documentation removed.
|
|
||||||
async current (currency = 'usd') {
|
|
||||||
try {
|
|
||||||
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 (err) {
|
|
||||||
if (err.response && err.response.data) throw err.response.data
|
|
||||||
else throw err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,7 +40,7 @@ class Price {
|
|||||||
async getUsd () {
|
async getUsd () {
|
||||||
try {
|
try {
|
||||||
const response = await this.axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}price/usd`,
|
`${this.restURL}price/bchusd`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||||
@@ -122,80 +95,6 @@ class Price {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @api price.getBchaUsd() getBchaUsd()
|
|
||||||
* @apiName Price getBchaUsd()
|
|
||||||
* @apiGroup Price
|
|
||||||
* @apiDescription Return current price of BCHA in USD.
|
|
||||||
* This endpoint gets the USD price of XEC from the Coinex API. The price
|
|
||||||
* denominated in BCHA 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.error(err)
|
|
||||||
* }
|
|
||||||
*})()
|
|
||||||
*
|
|
||||||
* // 212.34
|
|
||||||
*/
|
|
||||||
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)}`)
|
|
||||||
|
|
||||||
const bchaPrice = response.data.usd * 1000000
|
|
||||||
// Convert XEC denomination to BCHA denomination
|
|
||||||
|
|
||||||
return bchaPrice
|
|
||||||
} catch (err) {
|
|
||||||
if (err.response && err.response.data) throw err.response.data
|
|
||||||
else throw err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @api price.getXecUsd() getXecUsd()
|
|
||||||
* @apiName Price getXecUsd()
|
|
||||||
* @apiGroup Price
|
|
||||||
* @apiDescription Return current price of XEC in USD.
|
|
||||||
* This endpoint gets the USD price of XEC 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.getXecUsd();
|
|
||||||
* console.log(current);
|
|
||||||
* } catch(err) {
|
|
||||||
* console.error(err)
|
|
||||||
* }
|
|
||||||
*})()
|
|
||||||
*
|
|
||||||
* // 0.00021234
|
|
||||||
*/
|
|
||||||
async getXecUsd () {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api price.getBchUsd() getBchUsd()
|
* @api price.getBchUsd() getBchUsd()
|
||||||
* @apiName Price getBchUsd()
|
* @apiName Price getBchUsd()
|
||||||
@@ -230,6 +129,42 @@ class Price {
|
|||||||
else throw err
|
else throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api price.getPsffppPrice() getPsffppPrice()
|
||||||
|
* @apiName Price getPsffppPrice()
|
||||||
|
* @apiGroup Price
|
||||||
|
* @apiDescription Return the cost in PSF tokens to write 1MB of data to the PSFFPP
|
||||||
|
* Find out more at PSFFPP.com. This is a IPFS pinning service that can pin
|
||||||
|
* up to 100MB per transaction into its network. The cost is denominated in
|
||||||
|
* PSF SLP tokens. The endpoint returns the cost to pin 1MB of data to the
|
||||||
|
* PSFFPP network.
|
||||||
|
*
|
||||||
|
* @apiExample Example usage:
|
||||||
|
*(async () => {
|
||||||
|
* try {
|
||||||
|
* let current = await bchjs.Price.getPsffppPrice();
|
||||||
|
* console.log(current);
|
||||||
|
* } catch(err) {
|
||||||
|
* console.error(err)
|
||||||
|
* }
|
||||||
|
*})()
|
||||||
|
*
|
||||||
|
* // 0.08335233
|
||||||
|
*/
|
||||||
|
async getPsffppPrice () {
|
||||||
|
try {
|
||||||
|
const response = await this.axios.get(
|
||||||
|
`${this.restURL}price/psffpp`,
|
||||||
|
this.axiosOptions
|
||||||
|
)
|
||||||
|
|
||||||
|
return response.data.writePrice
|
||||||
|
} catch (err) {
|
||||||
|
if (err.response && err.response.data) throw err.response.data
|
||||||
|
else throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Price
|
export default Price
|
||||||
|
|||||||
+207
-31
@@ -7,41 +7,32 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const RawTransaction = require('./raw-transactions')
|
import RawTransaction from './raw-transactions.js'
|
||||||
const SlpUtils = require('./slp/utils')
|
import SlpUtils from './slp/utils.js'
|
||||||
|
import Blockchain from './blockchain.js'
|
||||||
|
|
||||||
// let _this
|
// let _this
|
||||||
|
|
||||||
class PsfSlpIndexer {
|
class PsfSlpIndexer {
|
||||||
constructor (config = {}) {
|
constructor (config = {}) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||||
|
this.axios = config.axios || axios
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encapsulate dependencies
|
// Encapsulate dependencies
|
||||||
this.rawTransaction = new RawTransaction(config)
|
this.rawTransaction = new RawTransaction(config)
|
||||||
this.slpUtils = new SlpUtils(config)
|
this.slpUtils = new SlpUtils(config)
|
||||||
|
this.blockchain = new Blockchain(config)
|
||||||
// _this = this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,13 +62,13 @@ class PsfSlpIndexer {
|
|||||||
*/
|
*/
|
||||||
async status () {
|
async status () {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}psf/slp/status`,
|
`${this.restURL}slp/status`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data && error.response.data.error) throw new Error(error.response.data.error)
|
||||||
else throw error
|
else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,8 +127,8 @@ class PsfSlpIndexer {
|
|||||||
|
|
||||||
// Handle single address.
|
// Handle single address.
|
||||||
if (typeof address === 'string') {
|
if (typeof address === 'string') {
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}psf/slp/address`,
|
`${this.restURL}slp/address`,
|
||||||
{ address },
|
{ address },
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
@@ -145,7 +136,7 @@ class PsfSlpIndexer {
|
|||||||
}
|
}
|
||||||
throw new Error('Input address must be a string.')
|
throw new Error('Input address must be a string.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data && error.response.data.error) throw new Error(error.response.data.error)
|
||||||
else throw error
|
else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,14 +185,15 @@ class PsfSlpIndexer {
|
|||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async tokenStats (tokenId, withTxHistory = false) {
|
async tokenStats (tokenId, withTxHistory = false) {
|
||||||
try {
|
try {
|
||||||
// Handle single address.
|
// Handle single address.
|
||||||
if (typeof tokenId === 'string') {
|
if (typeof tokenId === 'string') {
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}psf/slp/token`,
|
`${this.restURL}slp/token`,
|
||||||
{ tokenId, withTxHistory },
|
{ tokenId, withTxHistory },
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
@@ -209,7 +201,7 @@ class PsfSlpIndexer {
|
|||||||
}
|
}
|
||||||
throw new Error('Input tokenId must be a string.')
|
throw new Error('Input tokenId must be a string.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response && error.response.data) throw error.response.data
|
if (error.response && error.response.data && error.response.data.error) throw new Error(error.response.data.error)
|
||||||
else throw error
|
else throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -288,15 +280,20 @@ class PsfSlpIndexer {
|
|||||||
*/
|
*/
|
||||||
async tx (txid) {
|
async tx (txid) {
|
||||||
try {
|
try {
|
||||||
|
// console.log('txid: ', txid)
|
||||||
|
|
||||||
// Handle single address.
|
// Handle single address.
|
||||||
if (typeof txid === 'string') {
|
if (typeof txid === 'string') {
|
||||||
const response = await axios.post(
|
const response = await this.axios.post(
|
||||||
`${this.restURL}psf/slp/txid`,
|
`${this.restURL}slp/txid`,
|
||||||
{ txid },
|
{ txid },
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
|
// console.log('response: ', response)
|
||||||
|
|
||||||
return response.data
|
return response.data
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('Input txid must be a string.')
|
throw new Error('Input txid must be a string.')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.log('error: ', error)
|
// console.log('error: ', error)
|
||||||
@@ -316,11 +313,28 @@ class PsfSlpIndexer {
|
|||||||
|
|
||||||
// Check if this txid belongs to a blacklisted token.
|
// Check if this txid belongs to a blacklisted token.
|
||||||
const isInBlacklist = await this.checkBlacklist(txid)
|
const isInBlacklist = await this.checkBlacklist(txid)
|
||||||
|
// console.log('isInBlacklist: ', isInBlacklist)
|
||||||
|
|
||||||
// Get the TX Details from the full node.
|
// Get the TX Details from the full node.
|
||||||
const txDetails = await this.rawTransaction.getTxData(txid)
|
const txDetails = await this.rawTransaction.getTxData(txid)
|
||||||
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
|
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
|
||||||
|
|
||||||
|
// Add blockheight, height, time, and blocktime to the txDetails object.
|
||||||
|
if (txDetails.height === null) {
|
||||||
|
// Get current block height and increment by 1
|
||||||
|
const currentBlockHeight = await this.blockchain.getBlockCount()
|
||||||
|
const estimatedHeight = currentBlockHeight + 1
|
||||||
|
|
||||||
|
// Set height and blockheight
|
||||||
|
txDetails.height = estimatedHeight
|
||||||
|
txDetails.blockheight = estimatedHeight
|
||||||
|
|
||||||
|
// Set time and blocktime to current unix timestamp
|
||||||
|
const currentTime = Math.floor(Date.now() / 1000)
|
||||||
|
txDetails.time = currentTime
|
||||||
|
txDetails.blocktime = currentTime
|
||||||
|
}
|
||||||
|
|
||||||
if (isInBlacklist) {
|
if (isInBlacklist) {
|
||||||
txDetails.isValidSlp = null
|
txDetails.isValidSlp = null
|
||||||
} else {
|
} else {
|
||||||
@@ -368,6 +382,168 @@ class PsfSlpIndexer {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api PsfSlpIndexer.getTokenData() getTokenData()
|
||||||
|
* @apiName Token Data
|
||||||
|
* @apiGroup PSF SLP
|
||||||
|
* @apiDescription Get mutable and immutable data if the token contains them.
|
||||||
|
*
|
||||||
|
* @apiExample Example usage:
|
||||||
|
* (async () => {
|
||||||
|
* try {
|
||||||
|
* let tokenData = await bchjs.PsfSlpIndexer.getTokenData('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2')
|
||||||
|
* console.log(tokenData)
|
||||||
|
* } catch(error) {
|
||||||
|
* console.error(error)
|
||||||
|
* }
|
||||||
|
* })()
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* genesisData: {
|
||||||
|
* type: 1,
|
||||||
|
* ticker: 'TROUT',
|
||||||
|
* name: "Trout's test token",
|
||||||
|
* tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2',
|
||||||
|
* documentUri: 'troutsblog.com',
|
||||||
|
* documentHash: '',
|
||||||
|
* decimals: 2,
|
||||||
|
* mintBatonIsActive: true,
|
||||||
|
* tokensInCirculationBN: '100098953386',
|
||||||
|
* tokensInCirculationStr: '100098953386',
|
||||||
|
* blockCreated: 622414,
|
||||||
|
* totalBurned: '1046614',
|
||||||
|
* totalMinted: '100100000000'
|
||||||
|
* ]
|
||||||
|
* },
|
||||||
|
* immutableData :{
|
||||||
|
* issuer:"FullStack.cash.",
|
||||||
|
* website:"https://fullstack.cash/",
|
||||||
|
* dateCreated:"2022-01-11"
|
||||||
|
* },
|
||||||
|
* mutableData :{
|
||||||
|
* "tokenIcon":"https://gateway.ipfs.io/ipfs/bafybeiehitanirn5gmhqjg44xrmdtomn4n5lu5yjoepsvgpswk5mggaw6i/LP_logo-1.png",
|
||||||
|
* "about":"Mutable data managed with npm package: https://www.npmjs.com/package/slp-mutable-data"
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getTokenData (tokenId, withTxHistory = false) {
|
||||||
|
try {
|
||||||
|
const url = `${this.restURL}slp/token/data`
|
||||||
|
// console.log(`url: ${url}`)
|
||||||
|
|
||||||
|
// Handle single address.
|
||||||
|
if (typeof tokenId === 'string') {
|
||||||
|
const response = await this.axios.post(
|
||||||
|
// 'https://bchn.fullstack.cash/v5/psf/slp/token/data/',
|
||||||
|
url,
|
||||||
|
{ tokenId, withTxHistory },
|
||||||
|
this.axiosOptions
|
||||||
|
)
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
throw new Error('Input tokenId must be a string.')
|
||||||
|
} catch (error) {
|
||||||
|
if (error.response && error.response.data && error.response.data.error) throw new Error(error.response.data.error)
|
||||||
|
else throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api PsfSlpIndexer.getTokenData2() getTokenData2()
|
||||||
|
* @apiName Token Data
|
||||||
|
* @apiGroup PSF SLP
|
||||||
|
* @apiDescription Get token icon and other media associated with a token.
|
||||||
|
*
|
||||||
|
* Get the icon for a token, given it's token ID.
|
||||||
|
* This function expects a string input of a token ID property.
|
||||||
|
* This function returns an object with a tokenIcon property that contains
|
||||||
|
* the URL to the icon.
|
||||||
|
*
|
||||||
|
* The output object always have these properties:
|
||||||
|
* - tokenIcon: A url to the token icon, if it exists.
|
||||||
|
* - tokenStats: Data about the token from psf-slp-indexer.
|
||||||
|
* - optimizedTokenIcon: An alternative, potentially more optimal, url to the token icon, if it exists.
|
||||||
|
* - iconRepoCompatible: true if the token icon is available via token.bch.sx
|
||||||
|
* - ps002Compatible: true if the token icon is compatible with PS007 specification.
|
||||||
|
*
|
||||||
|
* @apiExample Example usage:
|
||||||
|
* (async () => {
|
||||||
|
* try {
|
||||||
|
* let tokenData = await bchjs.PsfSlpIndexer.getTokenData2('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2')
|
||||||
|
* console.log(tokenData)
|
||||||
|
* } catch(error) {
|
||||||
|
* console.error(error)
|
||||||
|
* }
|
||||||
|
* })()
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* tokenStats: {
|
||||||
|
* type: 1,
|
||||||
|
* ticker: 'CTAIA006',
|
||||||
|
* name: 'CTAIA006 - AI Art by Chris Troutner',
|
||||||
|
* tokenId: '0e4543f820699294ab57e02ee2b1815a8bbc7b17a4333e4a138034e4b2324a61',
|
||||||
|
* documentUri: 'ipfs://bafybeia5yuq7rg6jmwquako7t277cwrobcunz7cumqrv4wn6bgfvthemku',
|
||||||
|
* documentHash: '78a00e9db312b8fff4e5c37cf592be83e6bab7f3bd5a54c9545bad5d4f3ee0f5',
|
||||||
|
* decimals: 0,
|
||||||
|
* mintBatonIsActive: false,
|
||||||
|
* tokensInCirculationBN: '1',
|
||||||
|
* tokensInCirculationStr: '1',
|
||||||
|
* blockCreated: 757507,
|
||||||
|
* totalBurned: '0',
|
||||||
|
* totalMinted: '1'
|
||||||
|
* },
|
||||||
|
* mutableData: {
|
||||||
|
* tokenIcon: 'https://bafybeihiv5jvlhoymmbous3h2akotogj6b7hruhjcj3zq7dsfteimuuttm.ipfs.w3s.link/whale-night-sky-01.png',
|
||||||
|
* fullSizedUrl: '',
|
||||||
|
* about: 'This NFT was created using the PSF Token Studio at https://nft-creator.fullstack.cash',
|
||||||
|
* userData: ''
|
||||||
|
* },
|
||||||
|
* immutableData: {
|
||||||
|
* issuer: 'http://psfoundation.cash',
|
||||||
|
* website: 'https://nft-creator.fullstack.cash',
|
||||||
|
* dateCreated: '9/12/2022, 5:17:38 PM',
|
||||||
|
* userData: '{\n' +
|
||||||
|
* ' "title": "CTAIA006 - AI Art by Chris Troutner",\n' +
|
||||||
|
* ' "about": "AI generated art. Generated from DALL-E at https://labs.openai.com",\n' +
|
||||||
|
* ' "prompt": "whale swimming through a sky full of stars",\n' +
|
||||||
|
* ' "algorithm": "DALL-E (stable diffusion)",\n' +
|
||||||
|
* ' "set": "1-of-2"\n' +
|
||||||
|
* '}'
|
||||||
|
* },
|
||||||
|
* tokenIcon: 'https://bafybeihiv5jvlhoymmbous3h2akotogj6b7hruhjcj3zq7dsfteimuuttm.ipfs.w3s.link/whale-night-sky-01.png',
|
||||||
|
* fullSizedUrl: '',
|
||||||
|
* optimizedTokenIcon: 'https://p2wdb-gateway-678.fullstack.cash/ipfs/bafybeihiv5jvlhoymmbous3h2akotogj6b7hruhjcj3zq7dsfteimuuttm/whale-night-sky-01.png',
|
||||||
|
* optimizedFullSizedUrl: '',
|
||||||
|
* iconRepoCompatible: false,
|
||||||
|
* ps002Compatible: true
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async getTokenData2 (tokenId, updateCache = false) {
|
||||||
|
try {
|
||||||
|
const url = `${this.restURL}slp/token/data2`
|
||||||
|
// console.log(`url: ${url}`)
|
||||||
|
|
||||||
|
// Handle single address.
|
||||||
|
if (typeof tokenId === 'string') {
|
||||||
|
const response = await this.axios.post(
|
||||||
|
// 'https://bchn.fullstack.cash/v5/psf/slp/token/data/',
|
||||||
|
url,
|
||||||
|
{ tokenId, updateCache },
|
||||||
|
this.axiosOptions
|
||||||
|
)
|
||||||
|
return response.data
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Input tokenId must be a string.')
|
||||||
|
} catch (error) {
|
||||||
|
// console.log('error: ', error)
|
||||||
|
if (error.response && error.response.data && error.response.data.error) throw new Error(error.response.data.error)
|
||||||
|
else throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = PsfSlpIndexer
|
export default PsfSlpIndexer
|
||||||
|
|||||||
+101
-50
@@ -1,33 +1,60 @@
|
|||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
|
|
||||||
// let _this
|
// let _this
|
||||||
|
|
||||||
class RawTransactions {
|
class RawTransactions {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encapsulate dependencies
|
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||||
this.axios = axios
|
this.axios = config.axios || axios
|
||||||
|
|
||||||
// this = this
|
// Retry configuration for transient network failures during broadcast.
|
||||||
|
this.maxBroadcastRetries = 2
|
||||||
|
this.broadcastRetryDelayMs = 250
|
||||||
|
}
|
||||||
|
|
||||||
|
_sleep (ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
}
|
||||||
|
|
||||||
|
_isTransientNetworkError (error) {
|
||||||
|
if (!error) return false
|
||||||
|
|
||||||
|
const msg = String(error.message || '').toLowerCase()
|
||||||
|
const causeMsg = String(error?.cause?.message || '').toLowerCase()
|
||||||
|
const stack = String(error.stack || '').toLowerCase()
|
||||||
|
const code = String(error.code || error?.cause?.code || '').toUpperCase()
|
||||||
|
|
||||||
|
if (['ECONNRESET', 'EPIPE', 'ETIMEDOUT'].includes(code)) return true
|
||||||
|
if (msg.includes('socket hang up')) return true
|
||||||
|
if (causeMsg.includes('socket hang up')) return true
|
||||||
|
if (stack.includes('socket hang up')) return true
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
async _postSendRawTransaction (hexes) {
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${this.restURL}full-node/rawtransactions/sendRawTransaction`,
|
||||||
|
data: {
|
||||||
|
hexes
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
...this.axiosOptions.headers,
|
||||||
|
Connection: 'close'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.axios(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,8 +123,8 @@ class RawTransactions {
|
|||||||
try {
|
try {
|
||||||
// Single hex
|
// Single hex
|
||||||
if (typeof hex === 'string') {
|
if (typeof hex === 'string') {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}rawtransactions/decodeRawTransaction/${hex}`,
|
`${this.restURL}full-node/rawtransactions/decodeRawTransaction/${hex}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -107,13 +134,13 @@ class RawTransactions {
|
|||||||
} else if (Array.isArray(hex)) {
|
} else if (Array.isArray(hex)) {
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: `${this.restURL}rawtransactions/decodeRawTransaction`,
|
url: `${this.restURL}full-node/rawtransactions/decodeRawTransaction`,
|
||||||
data: {
|
data: {
|
||||||
hexes: hex
|
hexes: hex
|
||||||
},
|
},
|
||||||
headers: this.axiosOptions.headers
|
headers: this.axiosOptions.headers
|
||||||
}
|
}
|
||||||
const response = await axios(options)
|
const response = await this.axios(options)
|
||||||
|
|
||||||
return response.data
|
return response.data
|
||||||
}
|
}
|
||||||
@@ -164,8 +191,8 @@ class RawTransactions {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof script === 'string') {
|
if (typeof script === 'string') {
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}rawtransactions/decodeScript/${script}`,
|
`${this.restURL}full-node/rawtransactions/decodeScript/${script}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -173,13 +200,13 @@ class RawTransactions {
|
|||||||
} else if (Array.isArray(script)) {
|
} else if (Array.isArray(script)) {
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: `${this.restURL}rawtransactions/decodeScript`,
|
url: `${this.restURL}full-node/rawtransactions/decodeScript`,
|
||||||
data: {
|
data: {
|
||||||
hexes: script
|
hexes: script
|
||||||
},
|
},
|
||||||
headers: this.axiosOptions.headers
|
headers: this.axiosOptions.headers
|
||||||
}
|
}
|
||||||
const response = await axios(options)
|
const response = await this.axios(options)
|
||||||
|
|
||||||
return response.data
|
return response.data
|
||||||
}
|
}
|
||||||
@@ -263,8 +290,8 @@ class RawTransactions {
|
|||||||
// 'getRawTransaction() this.axiosOptions: ',
|
// 'getRawTransaction() this.axiosOptions: ',
|
||||||
// this.axiosOptions
|
// this.axiosOptions
|
||||||
// )
|
// )
|
||||||
const response = await axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=${verbose}`,
|
`${this.restURL}full-node/rawtransactions/getRawTransaction/${txid}?verbose=${verbose}`,
|
||||||
this.axiosOptions
|
this.axiosOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -272,15 +299,15 @@ class RawTransactions {
|
|||||||
} else if (Array.isArray(txid)) {
|
} else if (Array.isArray(txid)) {
|
||||||
const options = {
|
const options = {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: `${this.restURL}rawtransactions/getRawTransaction`,
|
url: `${this.restURL}full-node/rawtransactions/getRawTransaction`,
|
||||||
data: {
|
data: {
|
||||||
txids: txid,
|
txids: txid,
|
||||||
verbose: verbose,
|
verbose,
|
||||||
usrObj // pass user data when making an internal call.
|
usrObj // pass user data when making an internal call.
|
||||||
},
|
},
|
||||||
headers: this.axiosOptions.headers
|
headers: this.axiosOptions.headers
|
||||||
}
|
}
|
||||||
const response = await axios(options)
|
const response = await this.axios(options)
|
||||||
|
|
||||||
return response.data
|
return response.data
|
||||||
}
|
}
|
||||||
@@ -381,6 +408,8 @@ class RawTransactions {
|
|||||||
// Appends the BCH address to the inputs of the transaction.
|
// Appends the BCH address to the inputs of the transaction.
|
||||||
async getTxData (txid) {
|
async getTxData (txid) {
|
||||||
try {
|
try {
|
||||||
|
// console.log('getTxData() txid: ', txid)
|
||||||
|
|
||||||
if (typeof txid !== 'string') {
|
if (typeof txid !== 'string') {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Input to raw-transaction.js/getTxData() must be a string containg a TXID.'
|
'Input to raw-transaction.js/getTxData() must be a string containg a TXID.'
|
||||||
@@ -391,17 +420,25 @@ class RawTransactions {
|
|||||||
const txDetails = await this.getRawTransaction(txid, true)
|
const txDetails = await this.getRawTransaction(txid, true)
|
||||||
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
|
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
|
||||||
|
|
||||||
const inAddrs = await this._getInputAddrs(txDetails)
|
try {
|
||||||
// console.log(`inAddrs: ${JSON.stringify(inAddrs, null, 2)}`)
|
const inAddrs = await this._getInputAddrs(txDetails)
|
||||||
|
// console.log(`inAddrs: ${JSON.stringify(inAddrs, null, 2)}`)
|
||||||
|
|
||||||
// Add the input address to the transaction data.
|
// Add the input address to the transaction data.
|
||||||
for (let i = 0; i < inAddrs.length; i++) {
|
for (let i = 0; i < inAddrs.length; i++) {
|
||||||
txDetails.vin[i].address = inAddrs[i].address
|
txDetails.vin[i].address = inAddrs[i].address
|
||||||
txDetails.vin[i].value = inAddrs[i].value
|
txDetails.vin[i].value = inAddrs[i].value
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Coinbase transactions will throw an error. Just ignore them and
|
||||||
|
// pass back the raw transaction data.
|
||||||
|
/* exit quietly */
|
||||||
}
|
}
|
||||||
|
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
|
||||||
|
|
||||||
return txDetails
|
return txDetails
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// console.log('error: ', error)
|
||||||
if (error.error) throw new Error(error.error)
|
if (error.error) throw new Error(error.error)
|
||||||
|
|
||||||
// This case handles rate limit errors.
|
// This case handles rate limit errors.
|
||||||
@@ -450,8 +487,14 @@ class RawTransactions {
|
|||||||
// Single tx hex.
|
// Single tx hex.
|
||||||
if (typeof hex === 'string') {
|
if (typeof hex === 'string') {
|
||||||
const response = await this.axios.get(
|
const response = await this.axios.get(
|
||||||
`${this.restURL}rawtransactions/sendRawTransaction/${hex}`,
|
`${this.restURL}full-node/rawtransactions/sendRawTransaction/${hex}`,
|
||||||
this.axiosOptions
|
{
|
||||||
|
...this.axiosOptions,
|
||||||
|
headers: {
|
||||||
|
...this.axiosOptions.headers,
|
||||||
|
Connection: 'close'
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (response.data === '66: insufficient priority') {
|
if (response.data === '66: insufficient priority') {
|
||||||
@@ -466,17 +509,25 @@ class RawTransactions {
|
|||||||
|
|
||||||
// Array input
|
// Array input
|
||||||
} else if (Array.isArray(hex)) {
|
} else if (Array.isArray(hex)) {
|
||||||
const options = {
|
let lastErr
|
||||||
method: 'POST',
|
|
||||||
url: `${this.restURL}rawtransactions/sendRawTransaction`,
|
|
||||||
data: {
|
|
||||||
hexes: hex
|
|
||||||
},
|
|
||||||
headers: this.axiosOptions.headers
|
|
||||||
}
|
|
||||||
const response = await this.axios(options)
|
|
||||||
|
|
||||||
return response.data
|
for (let attempt = 0; attempt <= this.maxBroadcastRetries; attempt++) {
|
||||||
|
try {
|
||||||
|
const response = await this._postSendRawTransaction(hex)
|
||||||
|
return response.data
|
||||||
|
} catch (err) {
|
||||||
|
lastErr = err
|
||||||
|
|
||||||
|
const isLastAttempt = attempt >= this.maxBroadcastRetries
|
||||||
|
const shouldRetry = this._isTransientNetworkError(err) && !isLastAttempt
|
||||||
|
if (!shouldRetry) throw err
|
||||||
|
|
||||||
|
const delay = this.broadcastRetryDelayMs * Math.pow(2, attempt)
|
||||||
|
await this._sleep(delay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw lastErr
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('Input hex must be a string or array of strings.')
|
throw new Error('Input hex must be a string or array of strings.')
|
||||||
@@ -488,4 +539,4 @@ class RawTransactions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = RawTransactions
|
export default RawTransactions
|
||||||
|
|||||||
+5
-16
@@ -1,24 +1,13 @@
|
|||||||
const schnorr = require('bip-schnorr')
|
import schnorr from 'bip-schnorr'
|
||||||
|
|
||||||
class Schnorr {
|
class Schnorr {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -509,4 +498,4 @@ class Schnorr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Schnorr
|
export default Schnorr
|
||||||
|
|||||||
+128
-3
@@ -1,5 +1,130 @@
|
|||||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
import Bitcoin from '@psf/bitcoincashjs-lib'
|
||||||
const opcodes = require('@psf/bitcoincash-ops')
|
|
||||||
|
// Inline opcodes data to avoid fs/import.meta issues in browser builds.
|
||||||
|
// This data is from @psf/bitcoincash-ops/index.json
|
||||||
|
const opcodes = {
|
||||||
|
OP_FALSE: 0,
|
||||||
|
OP_0: 0,
|
||||||
|
OP_PUSHDATA1: 76,
|
||||||
|
OP_PUSHDATA2: 77,
|
||||||
|
OP_PUSHDATA4: 78,
|
||||||
|
OP_1NEGATE: 79,
|
||||||
|
OP_RESERVED: 80,
|
||||||
|
OP_TRUE: 81,
|
||||||
|
OP_1: 81,
|
||||||
|
OP_2: 82,
|
||||||
|
OP_3: 83,
|
||||||
|
OP_4: 84,
|
||||||
|
OP_5: 85,
|
||||||
|
OP_6: 86,
|
||||||
|
OP_7: 87,
|
||||||
|
OP_8: 88,
|
||||||
|
OP_9: 89,
|
||||||
|
OP_10: 90,
|
||||||
|
OP_11: 91,
|
||||||
|
OP_12: 92,
|
||||||
|
OP_13: 93,
|
||||||
|
OP_14: 94,
|
||||||
|
OP_15: 95,
|
||||||
|
OP_16: 96,
|
||||||
|
OP_NOP: 97,
|
||||||
|
OP_VER: 98,
|
||||||
|
OP_IF: 99,
|
||||||
|
OP_NOTIF: 100,
|
||||||
|
OP_VERIF: 101,
|
||||||
|
OP_VERNOTIF: 102,
|
||||||
|
OP_ELSE: 103,
|
||||||
|
OP_ENDIF: 104,
|
||||||
|
OP_VERIFY: 105,
|
||||||
|
OP_RETURN: 106,
|
||||||
|
OP_TOALTSTACK: 107,
|
||||||
|
OP_FROMALTSTACK: 108,
|
||||||
|
OP_2DROP: 109,
|
||||||
|
OP_2DUP: 110,
|
||||||
|
OP_3DUP: 111,
|
||||||
|
OP_2OVER: 112,
|
||||||
|
OP_2ROT: 113,
|
||||||
|
OP_2SWAP: 114,
|
||||||
|
OP_IFDUP: 115,
|
||||||
|
OP_DEPTH: 116,
|
||||||
|
OP_DROP: 117,
|
||||||
|
OP_DUP: 118,
|
||||||
|
OP_NIP: 119,
|
||||||
|
OP_OVER: 120,
|
||||||
|
OP_PICK: 121,
|
||||||
|
OP_ROLL: 122,
|
||||||
|
OP_ROT: 123,
|
||||||
|
OP_SWAP: 124,
|
||||||
|
OP_TUCK: 125,
|
||||||
|
OP_CAT: 126,
|
||||||
|
OP_SPLIT: 127,
|
||||||
|
OP_NUM2BIN: 128,
|
||||||
|
OP_BIN2NUM: 129,
|
||||||
|
OP_SIZE: 130,
|
||||||
|
OP_INVERT: 131,
|
||||||
|
OP_AND: 132,
|
||||||
|
OP_OR: 133,
|
||||||
|
OP_XOR: 134,
|
||||||
|
OP_EQUAL: 135,
|
||||||
|
OP_EQUALVERIFY: 136,
|
||||||
|
OP_RESERVED1: 137,
|
||||||
|
OP_RESERVED2: 138,
|
||||||
|
OP_1ADD: 139,
|
||||||
|
OP_1SUB: 140,
|
||||||
|
OP_2MUL: 141,
|
||||||
|
OP_2DIV: 142,
|
||||||
|
OP_NEGATE: 143,
|
||||||
|
OP_ABS: 144,
|
||||||
|
OP_NOT: 145,
|
||||||
|
OP_0NOTEQUAL: 146,
|
||||||
|
OP_ADD: 147,
|
||||||
|
OP_SUB: 148,
|
||||||
|
OP_MUL: 149,
|
||||||
|
OP_DIV: 150,
|
||||||
|
OP_MOD: 151,
|
||||||
|
OP_LSHIFT: 152,
|
||||||
|
OP_RSHIFT: 153,
|
||||||
|
OP_BOOLAND: 154,
|
||||||
|
OP_BOOLOR: 155,
|
||||||
|
OP_NUMEQUAL: 156,
|
||||||
|
OP_NUMEQUALVERIFY: 157,
|
||||||
|
OP_NUMNOTEQUAL: 158,
|
||||||
|
OP_LESSTHAN: 159,
|
||||||
|
OP_GREATERTHAN: 160,
|
||||||
|
OP_LESSTHANOREQUAL: 161,
|
||||||
|
OP_GREATERTHANOREQUAL: 162,
|
||||||
|
OP_MIN: 163,
|
||||||
|
OP_MAX: 164,
|
||||||
|
OP_WITHIN: 165,
|
||||||
|
OP_RIPEMD160: 166,
|
||||||
|
OP_SHA1: 167,
|
||||||
|
OP_SHA256: 168,
|
||||||
|
OP_HASH160: 169,
|
||||||
|
OP_HASH256: 170,
|
||||||
|
OP_CODESEPARATOR: 171,
|
||||||
|
OP_CHECKSIG: 172,
|
||||||
|
OP_CHECKSIGVERIFY: 173,
|
||||||
|
OP_CHECKMULTISIG: 174,
|
||||||
|
OP_CHECKMULTISIGVERIFY: 175,
|
||||||
|
OP_NOP1: 176,
|
||||||
|
OP_NOP2: 177,
|
||||||
|
OP_CHECKLOCKTIMEVERIFY: 177,
|
||||||
|
OP_NOP3: 178,
|
||||||
|
OP_CHECKSEQUENCEVERIFY: 178,
|
||||||
|
OP_NOP4: 179,
|
||||||
|
OP_NOP5: 180,
|
||||||
|
OP_NOP6: 181,
|
||||||
|
OP_NOP7: 182,
|
||||||
|
OP_NOP8: 183,
|
||||||
|
OP_NOP9: 184,
|
||||||
|
OP_NOP10: 185,
|
||||||
|
OP_CHECKDATASIG: 186,
|
||||||
|
OP_CHECKDATASIGVERIFY: 187,
|
||||||
|
OP_REVERSEBYTES: 188,
|
||||||
|
OP_PUBKEYHASH: 253,
|
||||||
|
OP_PUBKEY: 254,
|
||||||
|
OP_INVALIDOPCODE: 255
|
||||||
|
}
|
||||||
|
|
||||||
class Script {
|
class Script {
|
||||||
constructor () {
|
constructor () {
|
||||||
@@ -240,4 +365,4 @@ class Script {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Script
|
export default Script
|
||||||
|
|||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
const BCHJSAddress = require('../address')
|
import BCHJSAddress from '../address.js'
|
||||||
|
|
||||||
|
import bchaddrjs from 'bchaddrjs-slp'
|
||||||
// const bchAddress = new BCHJSAddress()
|
// const bchAddress = new BCHJSAddress()
|
||||||
let bchAddress
|
let bchAddress
|
||||||
|
|
||||||
const bchaddrjs = require('bchaddrjs-slp')
|
|
||||||
|
|
||||||
class Address extends BCHJSAddress {
|
class Address extends BCHJSAddress {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
super(config)
|
super(config)
|
||||||
@@ -661,4 +661,4 @@ class Address extends BCHJSAddress {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Address
|
export default Address
|
||||||
|
|||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
// const BCHJS = require("../bch-js")
|
// import BCHJS from "../bch-js.js"
|
||||||
// const bchjs = new BCHJS()
|
// const bchjs = new BCHJS()
|
||||||
|
|
||||||
const BCHJSECPair = require('../ecpair')
|
import BCHJSECPair from '../ecpair.js'
|
||||||
|
|
||||||
const bchaddrjs = require('bchaddrjs-slp')
|
import bchaddrjs from 'bchaddrjs-slp'
|
||||||
|
|
||||||
class ECPair extends BCHJSECPair {
|
class ECPair extends BCHJSECPair {
|
||||||
/*
|
/*
|
||||||
@@ -31,4 +31,4 @@ class ECPair extends BCHJSECPair {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ECPair
|
export default ECPair
|
||||||
|
|||||||
+7
-98
@@ -9,18 +9,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const axios = require('axios')
|
// import axios from 'axios'
|
||||||
|
|
||||||
// Local libraries.
|
// Local libraries.
|
||||||
const Address = require('./address')
|
import Address from './address.js'
|
||||||
|
|
||||||
// const BigNumber = require('bignumber.js')
|
// import BigNumber from 'bignumber.js'
|
||||||
const slpMdm = require('slp-mdm')
|
import slpMdm from 'slp-mdm'
|
||||||
|
import TransactionBuilder from '../transaction-builder.js'
|
||||||
|
|
||||||
// let _this
|
// let _this
|
||||||
// const addy = new Address()
|
// const addy = new Address()
|
||||||
let addy
|
let addy
|
||||||
const TransactionBuilder = require('../transaction-builder')
|
|
||||||
|
|
||||||
class Nft1 {
|
class Nft1 {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
@@ -147,7 +147,7 @@ class Nft1 {
|
|||||||
// Loop through the tokenUtxos array and find the minting baton.
|
// Loop through the tokenUtxos array and find the minting baton.
|
||||||
let mintBatonUtxo
|
let mintBatonUtxo
|
||||||
for (let i = 0; i < tokenUtxos.length; i++) {
|
for (let i = 0; i < tokenUtxos.length; i++) {
|
||||||
if (tokenUtxos[i].utxoType === 'minting-baton') {
|
if (tokenUtxos[i].utxoType === 'minting-baton' || tokenUtxos[i].type === 'baton') {
|
||||||
mintBatonUtxo = tokenUtxos[i]
|
mintBatonUtxo = tokenUtxos[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -419,97 +419,6 @@ class Nft1 {
|
|||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @api SLP.NFT1.listNFTGroupChildren() listNFTGroupChildren()
|
|
||||||
* @apiName listNFTGroupChildren
|
|
||||||
* @apiGroup SLP NFT1
|
|
||||||
* @apiDescription Return list of NFT children tokens in a NFT Group.
|
|
||||||
* It's assumed provided groupId parameter is for an NFT Group token (type=129)
|
|
||||||
*
|
|
||||||
* Returns an Array with GENESIS transaction IDs of the children tokens.
|
|
||||||
*
|
|
||||||
* @apiExample Example usage:
|
|
||||||
*
|
|
||||||
* const groupId = '68cd33ecd909068fbea318ae5ff1d6207cf754e53b191327d6d73b6916424c0a'
|
|
||||||
* const children = await bchjs.SLP.Nft1.listNFTGroupChildren(groupId)
|
|
||||||
*
|
|
||||||
* children = {
|
|
||||||
* "nftChildren": [
|
|
||||||
* "45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a9",
|
|
||||||
* "928ce61fe1006b1325a0ba0dce700bf83986a6f0691ba26e121c9ac035d12a55"
|
|
||||||
* ]
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
async listNFTGroupChildren (groupId) {
|
|
||||||
try {
|
|
||||||
if (typeof groupId === 'string') {
|
|
||||||
const response = await axios.get(
|
|
||||||
`${this.restURL}slp/nftChildren/${groupId}`,
|
|
||||||
this.axiosOptions
|
|
||||||
)
|
|
||||||
return response.data
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('groupId must be a string.')
|
|
||||||
} catch (error) {
|
|
||||||
// console.log('Error in listNFTGroupChildren()')
|
|
||||||
if (error.response && error.response.data) throw error.response.data
|
|
||||||
else throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @api SLP.NFT1.parentNFTGroup() parentNFTGroup()
|
|
||||||
* @apiName parentNFTGroup
|
|
||||||
* @apiGroup SLP NFT1
|
|
||||||
* @apiDescription Return parent NFT Group information for a given NFT child token.
|
|
||||||
* It's assumed provided groupId parameter is for an NFT Child token (type=65)
|
|
||||||
*
|
|
||||||
* Returns a JSON with NFT group information.
|
|
||||||
*
|
|
||||||
* @apiExample Example usage:
|
|
||||||
*
|
|
||||||
* const tokenId = '45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a9'
|
|
||||||
* const group = await bchjs.SLP.Nft1.parentNFTGroup(tokenId)
|
|
||||||
*
|
|
||||||
* group = {
|
|
||||||
* "nftGroup": {
|
|
||||||
* "decimals": 0,
|
|
||||||
* "timestamp": "2021-05-03 10:36:01",
|
|
||||||
* "timestamp_unix": 1620038161,
|
|
||||||
* "versionType": 129,
|
|
||||||
* "documentUri": "psfoundation.cash",
|
|
||||||
* "symbol": "PSF.TEST.GROUP",
|
|
||||||
* "name": "PSF Test NFT Group",
|
|
||||||
* "containsBaton": true,
|
|
||||||
* "id": "68cd33ecd909068fbea318ae5ff1d6207cf754e53b191327d6d73b6916424c0a",
|
|
||||||
* "documentHash": null,
|
|
||||||
* "initialTokenQty": 1000000,
|
|
||||||
* "blockCreated": 686117,
|
|
||||||
* "totalMinted": null,
|
|
||||||
* "totalBurned": null,
|
|
||||||
* "circulatingSupply": null
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
async parentNFTGroup (tokenId) {
|
|
||||||
try {
|
|
||||||
if (typeof tokenId === 'string') {
|
|
||||||
const response = await axios.get(
|
|
||||||
`${this.restURL}slp/nftGroup/${tokenId}`,
|
|
||||||
this.axiosOptions
|
|
||||||
)
|
|
||||||
return response.data
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('tokenId must be a string.')
|
|
||||||
} catch (error) {
|
|
||||||
// console.log('Error in parentNFTGroup()')
|
|
||||||
if (error.response && error.response.data) throw error.response.data
|
|
||||||
else throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Nft1
|
export default Nft1
|
||||||
|
|||||||
+11
-22
@@ -7,34 +7,23 @@
|
|||||||
|
|
||||||
// imports
|
// imports
|
||||||
// require deps
|
// require deps
|
||||||
// const BCHJS = require("../bch-js")
|
// import BCHJS from "../bch-js.js"
|
||||||
const Address = require('./address')
|
import Address from './address.js'
|
||||||
const ECPair = require('./ecpair')
|
import ECPair from './ecpair.js'
|
||||||
// const HDNode = require("./hdnode")
|
// import HDNode from "./hdnode.js"
|
||||||
const TokenType1 = require('./tokentype1')
|
import TokenType1 from './tokentype1.js'
|
||||||
const NFT1 = require('./nft1')
|
import NFT1 from './nft1.js'
|
||||||
const Utils = require('./utils')
|
import Utils from './utils.js'
|
||||||
|
|
||||||
// SLP is a superset of BITBOX
|
// SLP is a superset of BITBOX
|
||||||
class SLP {
|
class SLP {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,4 +35,4 @@ class SLP {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = SLP
|
export default SLP
|
||||||
|
|||||||
+18
-24
@@ -2,41 +2,30 @@
|
|||||||
This library handles the OP_RETURN of SLP TokenType1 transactions.
|
This library handles the OP_RETURN of SLP TokenType1 transactions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// const BCHJS = require("../bch-js")
|
// import BCHJS from "../bch-js.js"
|
||||||
// const bchjs = new BCHJS()
|
// const bchjs = new BCHJS()
|
||||||
|
|
||||||
const Address = require('./address')
|
import Address from './address.js'
|
||||||
const Script = require('../script')
|
import Script from '../script.js'
|
||||||
|
|
||||||
const BigNumber = require('bignumber.js')
|
import BigNumber from 'bignumber.js'
|
||||||
const slpMdm = require('slp-mdm')
|
import slpMdm from 'slp-mdm'
|
||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
|
import TransactionBuilder from '../transaction-builder.js'
|
||||||
|
|
||||||
// const addy = new Address()
|
// const addy = new Address()
|
||||||
let addy
|
let addy
|
||||||
const TransactionBuilder = require('../transaction-builder')
|
|
||||||
|
|
||||||
let _this // local global
|
let _this // local global
|
||||||
|
|
||||||
class TokenType1 {
|
class TokenType1 {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,11 +364,14 @@ class TokenType1 {
|
|||||||
if (!Array.isArray(tokenUtxos)) {
|
if (!Array.isArray(tokenUtxos)) {
|
||||||
throw new Error('tokenUtxos must be an array.')
|
throw new Error('tokenUtxos must be an array.')
|
||||||
}
|
}
|
||||||
|
if (!mintQty) {
|
||||||
|
throw new Error('mintQty must be a positive number.')
|
||||||
|
}
|
||||||
|
|
||||||
// Loop through the tokenUtxos array and find the minting baton.
|
// Loop through the tokenUtxos array and find the minting baton.
|
||||||
let mintBatonUtxo
|
let mintBatonUtxo
|
||||||
for (let i = 0; i < tokenUtxos.length; i++) {
|
for (let i = 0; i < tokenUtxos.length; i++) {
|
||||||
if (tokenUtxos[i].utxoType === 'minting-baton') {
|
if (tokenUtxos[i].utxoType === 'minting-baton' || tokenUtxos[i].type === 'baton') {
|
||||||
mintBatonUtxo = tokenUtxos[i]
|
mintBatonUtxo = tokenUtxos[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,7 +387,7 @@ class TokenType1 {
|
|||||||
if (!tokenId) {
|
if (!tokenId) {
|
||||||
throw new Error('tokenId property not found in mint-baton UTXO.')
|
throw new Error('tokenId property not found in mint-baton UTXO.')
|
||||||
}
|
}
|
||||||
if (!decimals) {
|
if (!decimals && decimals !== 0) {
|
||||||
throw new Error('decimals property not found in mint-baton UTXO.')
|
throw new Error('decimals property not found in mint-baton UTXO.')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,6 +396,8 @@ class TokenType1 {
|
|||||||
baseQty = Math.floor(baseQty)
|
baseQty = Math.floor(baseQty)
|
||||||
baseQty = baseQty.toString()
|
baseQty = baseQty.toString()
|
||||||
|
|
||||||
|
if (isNaN(baseQty)) throw new Error('baseQty is non a number!')
|
||||||
|
|
||||||
// Signal that the baton should be passed or detroyed.
|
// Signal that the baton should be passed or detroyed.
|
||||||
let batonVout = 2
|
let batonVout = 2
|
||||||
if (destroyBaton) batonVout = null
|
if (destroyBaton) batonVout = null
|
||||||
@@ -478,4 +472,4 @@ class TokenType1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TokenType1
|
export default TokenType1
|
||||||
|
|||||||
+9
-19
@@ -1,35 +1,25 @@
|
|||||||
/* eslint-disable no-useless-catch */
|
/* eslint-disable no-useless-catch */
|
||||||
|
|
||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
const slpParser = require('slp-parser')
|
import slpParser from 'slp-parser'
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const Util = require('../util')
|
import Util from '../util.js'
|
||||||
|
|
||||||
let _this
|
let _this
|
||||||
|
|
||||||
class Utils {
|
class Utils {
|
||||||
constructor (config = {}) {
|
constructor (config = {}) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.slpParser = slpParser
|
this.slpParser = slpParser
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
this.axios = axios
|
// Use the shared axios instance if provided, otherwise fall back to axios
|
||||||
|
this.axios = config.axios || axios
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,4 +174,4 @@ class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Utils
|
export default Utils
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
import Bitcoin from '@psf/bitcoincashjs-lib'
|
||||||
const coininfo = require('@psf/coininfo')
|
import coininfo from '@psf/coininfo'
|
||||||
const bip66 = require('bip66')
|
import bip66 from 'bip66'
|
||||||
const bip68 = require('bc-bip68')
|
import bip68 from 'bc-bip68'
|
||||||
|
|
||||||
class TransactionBuilder {
|
class TransactionBuilder {
|
||||||
static setAddress (address) {
|
static setAddress (address) {
|
||||||
@@ -163,4 +163,4 @@ class TransactionBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = TransactionBuilder
|
export default TransactionBuilder
|
||||||
|
|||||||
+6
-5
@@ -6,10 +6,10 @@
|
|||||||
// const BigNumber = require('bignumber.js')
|
// const BigNumber = require('bignumber.js')
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const RawTransaction = require('./raw-transactions')
|
import RawTransaction from './raw-transactions.js'
|
||||||
const SlpUtils = require('./slp/utils')
|
import SlpUtils from './slp/utils.js'
|
||||||
const Blockchain = require('./blockchain')
|
import Blockchain from './blockchain.js'
|
||||||
const PsfSlpIndexer = require('./psf-slp-indexer')
|
import PsfSlpIndexer from './psf-slp-indexer.js'
|
||||||
|
|
||||||
class Transaction {
|
class Transaction {
|
||||||
constructor (config = {}) {
|
constructor (config = {}) {
|
||||||
@@ -41,6 +41,7 @@ class Transaction {
|
|||||||
* })()
|
* })()
|
||||||
*/
|
*/
|
||||||
async get (txid) {
|
async get (txid) {
|
||||||
|
// console.log('transaction.get() txid: ', txid)
|
||||||
return await this.psfSlpIndexer.tx(txid)
|
return await this.psfSlpIndexer.tx(txid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,4 +77,4 @@ class Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Transaction
|
export default Transaction
|
||||||
|
|||||||
+5
-97
@@ -1,30 +1,17 @@
|
|||||||
const axios = require('axios')
|
// import axios from 'axios'
|
||||||
|
|
||||||
// let _this
|
// let _this
|
||||||
|
|
||||||
class Util {
|
class Util {
|
||||||
constructor (config) {
|
constructor (config) {
|
||||||
this.restURL = config.restURL
|
this.restURL = config.restURL
|
||||||
this.apiToken = config.apiToken
|
|
||||||
this.authToken = config.authToken
|
this.authToken = config.authToken
|
||||||
|
|
||||||
if (this.authToken) {
|
this.axiosOptions = {
|
||||||
// Add Basic Authentication token to the authorization header.
|
headers: {
|
||||||
this.axiosOptions = {
|
authorization: this.authToken
|
||||||
headers: {
|
|
||||||
authorization: this.authToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Add JWT token to the authorization header.
|
|
||||||
this.axiosOptions = {
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// _this = this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -223,85 +210,6 @@ class Util {
|
|||||||
sleep (ms) {
|
sleep (ms) {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @api Util.validateAddress() validateAddress()
|
|
||||||
* @apiName Validate Address.
|
|
||||||
* @apiGroup Util
|
|
||||||
* @apiDescription Return information about the given bitcoin address.
|
|
||||||
*
|
|
||||||
* @apiExample Example usage:
|
|
||||||
* (async () => {
|
|
||||||
* try {
|
|
||||||
* let validateAddress = await bchjs.Util.validateAddress("bitcoincash:qzc86hrdufhcwlyzk7k82x77kfs2myekn57nv9cw5f");
|
|
||||||
* console.log(validateAddress);
|
|
||||||
* } catch(error) {
|
|
||||||
* console.error(error)
|
|
||||||
* }
|
|
||||||
* })()
|
|
||||||
*
|
|
||||||
* // { isvalid: true,
|
|
||||||
* // address: '17fshh33qUze2yifiJ2sXgijSMzJ2KNEwu',
|
|
||||||
* // scriptPubKey: '76a914492ae280d70af33acf0ae7cd329b961e65e9cbd888ac',
|
|
||||||
* // ismine: true,
|
|
||||||
* // iswatchonly: false,
|
|
||||||
* // isscript: false,
|
|
||||||
* // pubkey: '0312eeb9ae5f14c3cf43cece11134af860c2ef7d775060e3a578ceec888acada31',
|
|
||||||
* // iscompressed: true,
|
|
||||||
* // account: 'Test' }
|
|
||||||
*
|
|
||||||
* (async () => {
|
|
||||||
* try {
|
|
||||||
* let validateAddress = await bchjs.Util.validateAddress(["bitcoincash:qzc86hrdufhcwlyzk7k82x77kfs2myekn57nv9cw5f"]);
|
|
||||||
* console.log(validateAddress);
|
|
||||||
* } catch(error) {
|
|
||||||
* console.error(error)
|
|
||||||
* }
|
|
||||||
* })()
|
|
||||||
*
|
|
||||||
* // [{ isvalid: true,
|
|
||||||
* // address: '17fshh33qUze2yifiJ2sXgijSMzJ2KNEwu',
|
|
||||||
* // scriptPubKey: '76a914492ae280d70af33acf0ae7cd329b961e65e9cbd888ac',
|
|
||||||
* // ismine: true,
|
|
||||||
* // iswatchonly: false,
|
|
||||||
* // isscript: false,
|
|
||||||
* // pubkey: '0312eeb9ae5f14c3cf43cece11134af860c2ef7d775060e3a578ceec888acada31',
|
|
||||||
* // iscompressed: true,
|
|
||||||
* // account: 'Test' }]
|
|
||||||
*/
|
|
||||||
async validateAddress (address) {
|
|
||||||
try {
|
|
||||||
// Single block
|
|
||||||
if (typeof address === 'string') {
|
|
||||||
const response = await axios.get(
|
|
||||||
`${this.restURL}util/validateAddress/${address}`,
|
|
||||||
this.axiosOptions
|
|
||||||
)
|
|
||||||
return response.data
|
|
||||||
|
|
||||||
// Array of blocks.
|
|
||||||
} else if (Array.isArray(address)) {
|
|
||||||
const options = {
|
|
||||||
method: 'POST',
|
|
||||||
url: `${this.restURL}util/validateAddress`,
|
|
||||||
data: {
|
|
||||||
addresses: address
|
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
authorization: `Token ${this.apiToken}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const response = await axios(options)
|
|
||||||
|
|
||||||
return response.data
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('Input 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 = Util
|
export default Util
|
||||||
|
|||||||
+139
-20
@@ -6,10 +6,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Local libraries
|
// Local libraries
|
||||||
const Electrumx = require('./electrumx')
|
import Electrumx from './electrumx.js'
|
||||||
const Slp = require('./slp/slp')
|
import Slp from './slp/slp.js'
|
||||||
const PsfSlpIndexer = require('./psf-slp-indexer')
|
import PsfSlpIndexer from './psf-slp-indexer.js'
|
||||||
const BigNumber = require('bignumber.js')
|
import BigNumber from 'bignumber.js'
|
||||||
|
import Blockchain from './blockchain.js'
|
||||||
|
|
||||||
class UTXO {
|
class UTXO {
|
||||||
constructor (config = {}) {
|
constructor (config = {}) {
|
||||||
@@ -18,6 +19,13 @@ class UTXO {
|
|||||||
this.slp = new Slp(config)
|
this.slp = new Slp(config)
|
||||||
this.psfSlpIndexer = new PsfSlpIndexer(config)
|
this.psfSlpIndexer = new PsfSlpIndexer(config)
|
||||||
this.BigNumber = BigNumber
|
this.BigNumber = BigNumber
|
||||||
|
this.blockchain = new Blockchain(config)
|
||||||
|
|
||||||
|
// Bind 'this' object to all subfunctions.
|
||||||
|
this.get = this.get.bind(this)
|
||||||
|
this.hydrateTokenData = this.hydrateTokenData.bind(this)
|
||||||
|
this.findBiggestUtxo = this.findBiggestUtxo.bind(this)
|
||||||
|
this.isValid = this.isValid.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,6 +38,8 @@ class UTXO {
|
|||||||
* properties:
|
* properties:
|
||||||
* - address: "" - the address these UTXOs are associated with
|
* - address: "" - the address these UTXOs are associated with
|
||||||
* - bchUtxos: [] - UTXOs confirmed to be spendable as normal BCH
|
* - bchUtxos: [] - UTXOs confirmed to be spendable as normal BCH
|
||||||
|
* - infoUtxos: [] - UTXOs under of 1000 sats or less that can not be categorized
|
||||||
|
* as another type of UTXO (like a token).
|
||||||
* - nullUtxo: [] - UTXOs that did not pass SLP validation. Should be ignored and
|
* - nullUtxo: [] - UTXOs that did not pass SLP validation. Should be ignored and
|
||||||
* not spent, to be safe.
|
* not spent, to be safe.
|
||||||
* - slpUtxos: {} - UTXOs confirmed to be colored as valid SLP tokens
|
* - slpUtxos: {} - UTXOs confirmed to be colored as valid SLP tokens
|
||||||
@@ -80,7 +90,10 @@ class UTXO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the address is a BCH address.
|
// Ensure the address is a BCH address.
|
||||||
const addr = this.slp.Address.toCashAddress(address)
|
let addr = address
|
||||||
|
if (!addr.includes('ecash')) {
|
||||||
|
addr = this.slp.Address.toCashAddress(address)
|
||||||
|
}
|
||||||
|
|
||||||
// Get the UTXOs associated with the address.
|
// Get the UTXOs associated with the address.
|
||||||
const utxoData = await this.electrumx.utxo(addr)
|
const utxoData = await this.electrumx.utxo(addr)
|
||||||
@@ -104,6 +117,11 @@ class UTXO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the sync status of the SLP indexer
|
||||||
|
const syncStatus = await this.psfSlpIndexer.status()
|
||||||
|
const slpIndexerHeight = syncStatus.status.syncedBlockHeight
|
||||||
|
const chainBlockHeight = syncStatus.status.chainBlockHeight
|
||||||
|
|
||||||
// Loop through the Fulcrum UTXOs.
|
// Loop through the Fulcrum UTXOs.
|
||||||
for (let i = 0; i < utxos.length; i++) {
|
for (let i = 0; i < utxos.length; i++) {
|
||||||
const thisUtxo = utxos[i]
|
const thisUtxo = utxos[i]
|
||||||
@@ -125,9 +143,7 @@ class UTXO {
|
|||||||
thisUtxo.qty = thisSlpUtxo.qty
|
thisUtxo.qty = thisSlpUtxo.qty
|
||||||
thisUtxo.tokenId = thisSlpUtxo.tokenId
|
thisUtxo.tokenId = thisSlpUtxo.tokenId
|
||||||
thisUtxo.address = thisSlpUtxo.address
|
thisUtxo.address = thisSlpUtxo.address
|
||||||
|
thisUtxo.tokenType = thisSlpUtxo.tokenType
|
||||||
// tokenQty is property expected by SLP.tokentype1.js library
|
|
||||||
thisUtxo.tokenQty = thisUtxo.qyStr
|
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -143,38 +159,85 @@ class UTXO {
|
|||||||
// the indexer.
|
// the indexer.
|
||||||
const txData = await this.psfSlpIndexer.tx(thisUtxo.tx_hash)
|
const txData = await this.psfSlpIndexer.tx(thisUtxo.tx_hash)
|
||||||
// console.log(`txData: ${JSON.stringify(txData, null, 2)}`)
|
// console.log(`txData: ${JSON.stringify(txData, null, 2)}`)
|
||||||
if (txData.txData.isValidSlp === null) {
|
|
||||||
|
// txData.txData === undefined if the SLP indexer is syncing.
|
||||||
|
if (!txData.txData || txData.txData.isValidSlp === null) {
|
||||||
thisUtxo.isSlp = null
|
thisUtxo.isSlp = null
|
||||||
} else {
|
} else {
|
||||||
thisUtxo.isSlp = false
|
thisUtxo.isSlp = false
|
||||||
}
|
}
|
||||||
// console.log(`thisUtxo.isSlp: ${thisUtxo.isSlp}`)
|
// console.log(`thisUtxo.isSlp: ${thisUtxo.isSlp}`)
|
||||||
|
|
||||||
|
// If the SLP indexer more than 1 block behind the full node, then
|
||||||
|
// move any BCH UTXOs of 600 sats or less into the null array. This
|
||||||
|
// protects token UTXOs from being burned accidentally.
|
||||||
|
if (slpIndexerHeight < chainBlockHeight - 1) {
|
||||||
|
if (thisUtxo.value < 601) {
|
||||||
|
thisUtxo.isSlp = null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get token UTXOs
|
// Get token UTXOs
|
||||||
let type1TokenUtxos = utxos.filter(
|
let type1TokenUtxos = utxos.filter(
|
||||||
x => x.isSlp === true && x.type === 'token'
|
x => x.isSlp === true && x.type === 'token' && x.tokenType === 1
|
||||||
)
|
)
|
||||||
|
|
||||||
// Hydrate the UTXOs with additional token data.
|
// Hydrate the UTXOs with additional token data.
|
||||||
type1TokenUtxos = await this.hydrateTokenData(type1TokenUtxos)
|
type1TokenUtxos = await this.hydrateTokenData(type1TokenUtxos)
|
||||||
|
|
||||||
const bchUtxos = utxos.filter(x => x.isSlp === false)
|
// Collect BCH UTXOs above 1000 sats
|
||||||
const type1BatonUtxos = utxos.filter(
|
const bchUtxos = utxos.filter(x => x.isSlp === false && x.value > 1000)
|
||||||
x => x.isSlp === true && x.type === 'baton'
|
|
||||||
|
// Collect all BCH UTXOs at 1000 sats or smaller
|
||||||
|
// The prevents SLP tokens, BCMR, and other 'colored' UTXOs from being
|
||||||
|
// accidentally included into normal BCH transactions.
|
||||||
|
const infoUtxos = utxos.filter(x => x.isSlp === false && x.value <= 1000)
|
||||||
|
|
||||||
|
// Collect and hydrate any type1 baton UTXOs
|
||||||
|
let type1BatonUtxos = utxos.filter(
|
||||||
|
x => x.isSlp === true && x.type === 'baton' && x.tokenType === 1
|
||||||
)
|
)
|
||||||
|
type1BatonUtxos = await this.hydrateTokenData(type1BatonUtxos)
|
||||||
|
|
||||||
|
// Collect and hydrate NFT Group tokens
|
||||||
|
let nftGroupTokenUtxos = utxos.filter(
|
||||||
|
x => x.isSlp === true && x.type === 'token' && x.tokenType === 129
|
||||||
|
)
|
||||||
|
nftGroupTokenUtxos = await this.hydrateTokenData(nftGroupTokenUtxos)
|
||||||
|
|
||||||
|
// Collect and hydrate any Group baton UTXOs
|
||||||
|
let groupBatonUtxos = utxos.filter(
|
||||||
|
x => x.isSlp === true && x.type === 'baton' && x.tokenType === 129
|
||||||
|
)
|
||||||
|
groupBatonUtxos = await this.hydrateTokenData(groupBatonUtxos)
|
||||||
|
|
||||||
|
// Collect and hydrate NFT child tokens
|
||||||
|
let nftChildTokenUtxos = utxos.filter(
|
||||||
|
x => x.isSlp === true && x.type === 'token' && x.tokenType === 65
|
||||||
|
)
|
||||||
|
nftChildTokenUtxos = await this.hydrateTokenData(nftChildTokenUtxos)
|
||||||
|
|
||||||
|
// Isolate any UTXOs that are marked null by the SLP indexer.
|
||||||
const nullUtxos = utxos.filter(x => x.isSlp === null)
|
const nullUtxos = utxos.filter(x => x.isSlp === null)
|
||||||
|
|
||||||
const outObj = {
|
const outObj = {
|
||||||
address: addr,
|
address: addr,
|
||||||
bchUtxos,
|
bchUtxos,
|
||||||
|
infoUtxos,
|
||||||
slpUtxos: {
|
slpUtxos: {
|
||||||
type1: {
|
type1: {
|
||||||
tokens: type1TokenUtxos,
|
tokens: type1TokenUtxos,
|
||||||
mintBatons: type1BatonUtxos
|
mintBatons: type1BatonUtxos
|
||||||
},
|
},
|
||||||
nft: {} // Allocated for future support of NFT spec.
|
group: {
|
||||||
|
tokens: nftGroupTokenUtxos,
|
||||||
|
mintBatons: groupBatonUtxos
|
||||||
|
},
|
||||||
|
nft: {
|
||||||
|
tokens: nftChildTokenUtxos
|
||||||
|
}
|
||||||
},
|
},
|
||||||
nullUtxos
|
nullUtxos
|
||||||
}
|
}
|
||||||
@@ -228,11 +291,16 @@ class UTXO {
|
|||||||
thisUtxo.documentHash = genData[0].tokenData.documentHash
|
thisUtxo.documentHash = genData[0].tokenData.documentHash
|
||||||
thisUtxo.decimals = genData[0].tokenData.decimals
|
thisUtxo.decimals = genData[0].tokenData.decimals
|
||||||
|
|
||||||
// Calculate the real token quantity
|
if (thisUtxo.type !== 'baton') {
|
||||||
const qty = new BigNumber(thisUtxo.qty).dividedBy(
|
// Calculate the real token quantity
|
||||||
10 ** parseInt(thisUtxo.decimals)
|
const qty = new BigNumber(thisUtxo.qty).dividedBy(
|
||||||
)
|
10 ** parseInt(thisUtxo.decimals)
|
||||||
thisUtxo.qtyStr = qty.toString()
|
)
|
||||||
|
thisUtxo.qtyStr = qty.toString()
|
||||||
|
|
||||||
|
// tokenQty is property expected by SLP.tokentype1.js library
|
||||||
|
thisUtxo.tokenQty = thisUtxo.qtyStr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return utxoAry
|
return utxoAry
|
||||||
@@ -305,6 +373,57 @@ class UTXO {
|
|||||||
|
|
||||||
return utxos[largestIndex]
|
return utxos[largestIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api Utxo.isValid() isValid()
|
||||||
|
* @apiName isValid
|
||||||
|
* @apiGroup UTXO
|
||||||
|
* @apiDescription Validate that UTXO exists and is still spendable.
|
||||||
|
*
|
||||||
|
* Given a UTXO, this method will return true if the UTXO is still in the
|
||||||
|
* mempool and still valid for spending. It will return false if the UTXO
|
||||||
|
* has been spent.
|
||||||
|
*
|
||||||
|
* @apiExample Example usage:
|
||||||
|
* (async () => {
|
||||||
|
* try {
|
||||||
|
* const utxos = await bchjs.Utxo.get('bitcoincash:qq54fgjn3hz0357n8a6guy4demw9xfkjk5jcj0xr0z');
|
||||||
|
* const isValid = bchjs.Utxo.isValid(utxos.bchUtxos[0])
|
||||||
|
* console.log(isValid);
|
||||||
|
* } catch(error) {
|
||||||
|
* console.error(error)
|
||||||
|
* }
|
||||||
|
* })()
|
||||||
|
*
|
||||||
|
* // returns
|
||||||
|
* true
|
||||||
|
*/
|
||||||
|
async isValid (utxo) {
|
||||||
|
try {
|
||||||
|
// console.log('utxo: ', utxo)
|
||||||
|
|
||||||
|
// Convert different properties from different indexers
|
||||||
|
const txid = utxo.txid || utxo.tx_hash
|
||||||
|
const vout = utxo.vout | utxo.tx_pos
|
||||||
|
|
||||||
|
// Query the full node
|
||||||
|
const txOut = await this.blockchain.getTxOut(txid, vout, true)
|
||||||
|
// console.log('txOut: ', txOut)
|
||||||
|
|
||||||
|
// Simplify results to either true or false.
|
||||||
|
let isValid = null
|
||||||
|
if (txOut === null) {
|
||||||
|
isValid = false
|
||||||
|
} else {
|
||||||
|
isValid = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return isValid
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Error in Utxo.isValid()')
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = UTXO
|
export default UTXO
|
||||||
|
|||||||
@@ -2,10 +2,11 @@
|
|||||||
A Mocha test file for running end-to-end (e2e) tests.
|
A Mocha test file for running end-to-end (e2e) tests.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// const mocha = require("mocha")
|
// import mocha from "mocha"
|
||||||
const assert = require('chai').assert
|
import chai from 'chai'
|
||||||
|
|
||||||
const sendToken = require('./send-token/send-token')
|
import sendToken from './send-token/send-token.js'
|
||||||
|
const { assert } = chai
|
||||||
|
|
||||||
describe('#end-to-end tests', () => {
|
describe('#end-to-end tests', () => {
|
||||||
describe('#send-tokens', () => {
|
describe('#send-tokens', () => {
|
||||||
|
|||||||
@@ -3,12 +3,18 @@
|
|||||||
IPFS is working.
|
IPFS is working.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
process.env.IPFS_API = 'http://localhost:5001'
|
import { fileURLToPath } from 'url'
|
||||||
|
import { dirname } from 'path'
|
||||||
// process.env.IPFS_API = `https://ipfs-api.fullstack.cash`
|
// process.env.IPFS_API = `https://ipfs-api.fullstack.cash`
|
||||||
|
|
||||||
const BCHJS = require('../../../src/bch-js')
|
import BCHJS from '../../../src/bch-js.js'
|
||||||
|
|
||||||
|
process.env.IPFS_API = 'http://localhost:5001'
|
||||||
const bchjs = new BCHJS()
|
const bchjs = new BCHJS()
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url)
|
||||||
|
const __dirname = dirname(__filename)
|
||||||
|
|
||||||
describe('#IPFS', () => {
|
describe('#IPFS', () => {
|
||||||
it('should upload a file to the server', async () => {
|
it('should upload a file to the server', async () => {
|
||||||
const path = `${__dirname.toString()}/ipfs-e2e.js`
|
const path = `${__dirname.toString()}/ipfs-e2e.js`
|
||||||
|
|||||||
@@ -12,13 +12,14 @@
|
|||||||
mocha --timeout=30000 anonymous-rate-limits.js
|
mocha --timeout=30000 anonymous-rate-limits.js
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
import chai from 'chai'
|
||||||
|
// const RESTURL = `http://localhost:3000/v5/`
|
||||||
|
|
||||||
|
import BCHJS from '../../../src/bch-js.js'
|
||||||
|
const { assert } = chai
|
||||||
|
|
||||||
// const RESTURL = `https://abc.fullstack.cash/v5/`
|
// const RESTURL = `https://abc.fullstack.cash/v5/`
|
||||||
const RESTURL = 'https://bchn.fullstack.cash/v5/'
|
const RESTURL = 'https://bchn.fullstack.cash/v5/'
|
||||||
// const RESTURL = `http://localhost:3000/v5/`
|
|
||||||
|
|
||||||
const BCHJS = require('../../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS({ restURL: RESTURL })
|
const bchjs = new BCHJS({ restURL: RESTURL })
|
||||||
|
|
||||||
describe('#anonymous rate limits', () => {
|
describe('#anonymous rate limits', () => {
|
||||||
|
|||||||
@@ -7,11 +7,12 @@
|
|||||||
- Update the PRO_PASS value with a current PRO_PASSES string used by bch-api.
|
- Update the PRO_PASS value with a current PRO_PASSES string used by bch-api.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
import chai from 'chai'
|
||||||
|
|
||||||
|
import BCHJS from '../../../src/bch-js.js'
|
||||||
|
const { assert } = chai
|
||||||
|
|
||||||
const PRO_PASS = 'testpassword'
|
const PRO_PASS = 'testpassword'
|
||||||
|
|
||||||
const BCHJS = require('../../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS({
|
const bchjs = new BCHJS({
|
||||||
// restURL: `https://bchn.fullstack.cash/v5/`,
|
// restURL: `https://bchn.fullstack.cash/v5/`,
|
||||||
restURL: 'https://abc.fullstack.cash/v5/',
|
restURL: 'https://abc.fullstack.cash/v5/',
|
||||||
|
|||||||
@@ -11,12 +11,13 @@
|
|||||||
- Update the JWT_TOKEN value with a current free-level JWT token.
|
- Update the JWT_TOKEN value with a current free-level JWT token.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
import chai from 'chai'
|
||||||
|
|
||||||
|
import BCHJS from '../../../src/bch-js.js'
|
||||||
|
const { assert } = chai
|
||||||
|
|
||||||
const JWT_TOKEN =
|
const JWT_TOKEN =
|
||||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2YyMDIyMWMxMDAxMmFkOTQwMSIsImVtYWlsIjoiZGVtb0BkZW1vLmNvbSIsImFwaUxldmVsIjoxMCwicmF0ZUxpbWl0IjozLCJpYXQiOjE2MDQ4NTQ2OTEsImV4cCI6MTYwNzQ0NjY5MX0.iwse0z0KDKHx9graCxcOwj6lSlfKQAb1zLhmjvygvts'
|
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2YyMDIyMWMxMDAxMmFkOTQwMSIsImVtYWlsIjoiZGVtb0BkZW1vLmNvbSIsImFwaUxldmVsIjoxMCwicmF0ZUxpbWl0IjozLCJpYXQiOjE2MDQ4NTQ2OTEsImV4cCI6MTYwNzQ0NjY5MX0.iwse0z0KDKHx9graCxcOwj6lSlfKQAb1zLhmjvygvts'
|
||||||
|
|
||||||
const BCHJS = require('../../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS({
|
const bchjs = new BCHJS({
|
||||||
restURL: 'https://api.fullstack.cash/v5/',
|
restURL: 'https://api.fullstack.cash/v5/',
|
||||||
// restURL: `http://localhost:3000/v5/`,
|
// restURL: `http://localhost:3000/v5/`,
|
||||||
|
|||||||
@@ -11,12 +11,13 @@
|
|||||||
- Update the JWT_TOKEN value with a paid tier JWT token.
|
- Update the JWT_TOKEN value with a paid tier JWT token.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
import chai from 'chai'
|
||||||
|
|
||||||
|
import BCHJS from '../../../src/bch-js.js'
|
||||||
|
const { assert } = chai
|
||||||
|
|
||||||
const JWT_TOKEN =
|
const JWT_TOKEN =
|
||||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M'
|
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M'
|
||||||
|
|
||||||
const BCHJS = require('../../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS({
|
const bchjs = new BCHJS({
|
||||||
// restURL: `https://bchn.fullstack.cash/v5/`,
|
// restURL: `https://bchn.fullstack.cash/v5/`,
|
||||||
restURL: 'https:/abc.fullstack.cash/v5/',
|
restURL: 'https:/abc.fullstack.cash/v5/',
|
||||||
|
|||||||
@@ -7,12 +7,13 @@
|
|||||||
- Update the JWT_TOKEN value with a current indexer-level JWT token.
|
- Update the JWT_TOKEN value with a current indexer-level JWT token.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
import chai from 'chai'
|
||||||
|
|
||||||
|
import BCHJS from '../../../src/bch-js.js'
|
||||||
|
const { assert } = chai
|
||||||
|
|
||||||
const JWT_TOKEN =
|
const JWT_TOKEN =
|
||||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M'
|
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M'
|
||||||
|
|
||||||
const BCHJS = require('../../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS({
|
const bchjs = new BCHJS({
|
||||||
// restURL: `https://bchn.fullstack.cash/v5/`,
|
// restURL: `https://bchn.fullstack.cash/v5/`,
|
||||||
restURL: 'https://abc.fullstack.cash/v5/',
|
restURL: 'https://abc.fullstack.cash/v5/',
|
||||||
|
|||||||
@@ -18,26 +18,33 @@ const RECV_ADDR2 = 'bchtest:qz6yw0kqgfkknfy6jh2jvlfnkzmre3lt2u0pgcckdk'
|
|||||||
const SATOSHIS_TO_SEND = 1000
|
const SATOSHIS_TO_SEND = 1000
|
||||||
|
|
||||||
// Instantiate BITBOX.
|
// Instantiate BITBOX.
|
||||||
const bitboxLib = '../../../lib/BITBOX'
|
// Note: Dynamic require with variable - use dynamic import in ESM
|
||||||
const BITBOXSDK = require(bitboxLib)
|
const bitboxLib = '../../../lib/BITBOX.js'
|
||||||
const BITBOX = new BITBOXSDK({ restURL: 'https://trest.bitcoin.com/v2/' })
|
let BITBOXSDK, BITBOX, walletInfo
|
||||||
// const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" })
|
|
||||||
|
|
||||||
// const util = require('util')
|
|
||||||
|
|
||||||
// Open the wallet generated with create-wallet.
|
// Open the wallet generated with create-wallet.
|
||||||
let walletInfo = {}
|
let SEND_ADDR, SEND_MNEMONIC
|
||||||
try {
|
|
||||||
walletInfo = require('./wallet.json')
|
|
||||||
} catch (err) {
|
|
||||||
console.log(
|
|
||||||
'Could not open wallet.json. Generate a wallet with create-wallet first.'
|
|
||||||
)
|
|
||||||
process.exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
const SEND_ADDR = walletInfo.cashAddress
|
// Load dependencies asynchronously
|
||||||
const SEND_MNEMONIC = walletInfo.mnemonic
|
async function loadDependencies () {
|
||||||
|
BITBOXSDK = (await import(bitboxLib)).default
|
||||||
|
BITBOX = new BITBOXSDK({ restURL: 'https://trest.bitcoin.com/v2/' })
|
||||||
|
// const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" })
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { createRequire } = await import('module')
|
||||||
|
const require = createRequire(import.meta.url)
|
||||||
|
walletInfo = require('./wallet.json')
|
||||||
|
} catch (err) {
|
||||||
|
console.log(
|
||||||
|
'Could not open wallet.json. Generate a wallet with create-wallet first.'
|
||||||
|
)
|
||||||
|
process.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
SEND_ADDR = walletInfo.cashAddress
|
||||||
|
SEND_MNEMONIC = walletInfo.mnemonic
|
||||||
|
}
|
||||||
|
|
||||||
async function testSend () {
|
async function testSend () {
|
||||||
try {
|
try {
|
||||||
@@ -57,7 +64,10 @@ async function testSend () {
|
|||||||
console.log('Error in testSend: ', err)
|
console.log('Error in testSend: ', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
testSend()
|
// Load dependencies then run test
|
||||||
|
loadDependencies().then(() => {
|
||||||
|
testSend()
|
||||||
|
})
|
||||||
|
|
||||||
// Build a TX hex with the largest UTXO.
|
// Build a TX hex with the largest UTXO.
|
||||||
async function buildTx1 (recAddr) {
|
async function buildTx1 (recAddr) {
|
||||||
|
|||||||
@@ -17,26 +17,33 @@ const RECV_ADDR1 = 'bchtest:qzfn2mly05t6fjsh5kjj0dqq0jjtct27ng089dgg05'
|
|||||||
const SATOSHIS_TO_SEND = 1000
|
const SATOSHIS_TO_SEND = 1000
|
||||||
|
|
||||||
// Instantiate BITBOX.
|
// Instantiate BITBOX.
|
||||||
const bitboxLib = '../../../lib/BITBOX'
|
// Note: Dynamic require with variable - use dynamic import in ESM
|
||||||
const BITBOXSDK = require(bitboxLib)
|
const bitboxLib = '../../../lib/BITBOX.js'
|
||||||
const BITBOX = new BITBOXSDK({ restURL: 'https://trest.bitcoin.com/v2/' })
|
let BITBOXSDK, BITBOX, walletInfo
|
||||||
// const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" })
|
|
||||||
|
|
||||||
// const util = require('util')
|
|
||||||
|
|
||||||
// Open the wallet generated with create-wallet.
|
// Open the wallet generated with create-wallet.
|
||||||
let walletInfo = {}
|
let SEND_ADDR, SEND_MNEMONIC
|
||||||
try {
|
|
||||||
walletInfo = require('./wallet.json')
|
|
||||||
} catch (err) {
|
|
||||||
console.log(
|
|
||||||
'Could not open wallet.json. Generate a wallet with create-wallet first.'
|
|
||||||
)
|
|
||||||
process.exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
const SEND_ADDR = walletInfo.cashAddress
|
// Load dependencies asynchronously
|
||||||
const SEND_MNEMONIC = walletInfo.mnemonic
|
async function loadDependencies () {
|
||||||
|
BITBOXSDK = (await import(bitboxLib)).default
|
||||||
|
BITBOX = new BITBOXSDK({ restURL: 'https://trest.bitcoin.com/v2/' })
|
||||||
|
// const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" })
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { createRequire } = await import('module')
|
||||||
|
const require = createRequire(import.meta.url)
|
||||||
|
walletInfo = require('./wallet.json')
|
||||||
|
} catch (err) {
|
||||||
|
console.log(
|
||||||
|
'Could not open wallet.json. Generate a wallet with create-wallet first.'
|
||||||
|
)
|
||||||
|
process.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
SEND_ADDR = walletInfo.cashAddress
|
||||||
|
SEND_MNEMONIC = walletInfo.mnemonic
|
||||||
|
}
|
||||||
|
|
||||||
async function testSend () {
|
async function testSend () {
|
||||||
try {
|
try {
|
||||||
@@ -54,7 +61,10 @@ async function testSend () {
|
|||||||
console.log('Error in testSend: ', err)
|
console.log('Error in testSend: ', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
testSend()
|
// Load dependencies then run test
|
||||||
|
loadDependencies().then(() => {
|
||||||
|
testSend()
|
||||||
|
})
|
||||||
|
|
||||||
// Build a TX hex with the largest UTXO.
|
// Build a TX hex with the largest UTXO.
|
||||||
async function buildTx1 (recAddr) {
|
async function buildTx1 (recAddr) {
|
||||||
|
|||||||
@@ -8,7 +8,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Inspect utility used for debugging.
|
// Inspect utility used for debugging.
|
||||||
const util = require('util')
|
import util from 'util'
|
||||||
|
|
||||||
|
import lib from '../util/e2e-util.js'
|
||||||
util.inspect.defaultOptions = {
|
util.inspect.defaultOptions = {
|
||||||
showHidden: true,
|
showHidden: true,
|
||||||
colors: true,
|
colors: true,
|
||||||
@@ -21,8 +23,6 @@ util.inspect.defaultOptions = {
|
|||||||
const WALLET1 = '../wallet1.json'
|
const WALLET1 = '../wallet1.json'
|
||||||
const WALLET2 = '../wallet2.json'
|
const WALLET2 = '../wallet2.json'
|
||||||
|
|
||||||
const lib = require('../util/e2e-util')
|
|
||||||
|
|
||||||
// The main test function.
|
// The main test function.
|
||||||
// Sends a token and reports on how long it takes to show up in SLPDB production.
|
// Sends a token and reports on how long it takes to show up in SLPDB production.
|
||||||
async function sendTokenTest () {
|
async function sendTokenTest () {
|
||||||
@@ -95,6 +95,6 @@ function sleep (ms) {
|
|||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
sendTokenTest
|
sendTokenTest
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
tests.
|
tests.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
import SLPSDK from '../../../lib/SLP.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
openWallet,
|
openWallet,
|
||||||
sendToken,
|
sendToken,
|
||||||
getTestTokenBalance,
|
getTestTokenBalance,
|
||||||
threeDecimals
|
threeDecimals
|
||||||
}
|
}
|
||||||
|
|
||||||
const SLPSDK = require('../../../lib/SLP')
|
|
||||||
const slpsdk = new SLPSDK()
|
const slpsdk = new SLPSDK()
|
||||||
|
|
||||||
const testTokenId =
|
const testTokenId =
|
||||||
@@ -20,6 +20,9 @@ const testTokenId =
|
|||||||
// token balance.
|
// token balance.
|
||||||
async function openWallet (filename) {
|
async function openWallet (filename) {
|
||||||
try {
|
try {
|
||||||
|
// Note: Dynamic imports for JSON files - use createRequire
|
||||||
|
const { createRequire } = await import('module')
|
||||||
|
const require = createRequire(import.meta.url)
|
||||||
const walletInfo = require(filename)
|
const walletInfo = require(filename)
|
||||||
|
|
||||||
// const walletBalance = await getBalance(walletInfo)
|
// const walletBalance = await getBalance(walletInfo)
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
This test is used to interrogate the behavior of bch-js when a psf-slp-indexer
|
||||||
|
panicks and starts indexing from SLP genesis. In this corner-case, bch-js
|
||||||
|
should detect the indexer is out of sync, and protect any token UTXOs by
|
||||||
|
moving any UTXO under 600 sats into the null array.
|
||||||
|
|
||||||
|
TO RUN THIS TEST:
|
||||||
|
- Reset a local instance of psf-slp-indexer to sync from genesis.
|
||||||
|
- Start a local copy of bch-api
|
||||||
|
*/
|
||||||
|
|
||||||
|
import BCHJS from '../../../src/bch-js.js'
|
||||||
|
const bchjs = new BCHJS({
|
||||||
|
restURL: 'http://localhost:3000/v5/'
|
||||||
|
})
|
||||||
|
|
||||||
|
async function startTest () {
|
||||||
|
try {
|
||||||
|
const addr = 'bitcoincash:qzkvas58zag9tjry693mflkjze2m20ps7vx7uw7z9d'
|
||||||
|
|
||||||
|
const result = await bchjs.Utxo.get(addr)
|
||||||
|
console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in startTest(): ', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startTest()
|
||||||
@@ -7,13 +7,13 @@
|
|||||||
of an e2e test to be properly tested.
|
of an e2e test to be properly tested.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const chai = require('chai')
|
import chai from 'chai'
|
||||||
const assert = chai.assert
|
import BCHJS from '../../src/bch-js.js'
|
||||||
const BCHJS = require('../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS()
|
|
||||||
|
|
||||||
// Inspect utility used for debugging.
|
// Inspect utility used for debugging.
|
||||||
const util = require('util')
|
import util from 'util'
|
||||||
|
const assert = chai.assert
|
||||||
|
const bchjs = new BCHJS()
|
||||||
util.inspect.defaultOptions = {
|
util.inspect.defaultOptions = {
|
||||||
showHidden: true,
|
showHidden: true,
|
||||||
colors: true,
|
colors: true,
|
||||||
@@ -103,8 +103,8 @@ describe('#blockchain', () => {
|
|||||||
console.log(`result: ${util.inspect(result)}`)
|
console.log(`result: ${util.inspect(result)}`)
|
||||||
assert.equal(true, false, 'Unexpected result!')
|
assert.equal(true, false, 'Unexpected result!')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.hasAnyKeys(err, ['error'])
|
assert.instanceOf(err, Error)
|
||||||
assert.include(err.error, 'Array too large')
|
assert.include(err.message, 'Array too large')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -171,8 +171,8 @@ describe('#blockchain', () => {
|
|||||||
assert.equal(true, false, 'Unexpected result!')
|
assert.equal(true, false, 'Unexpected result!')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// console.log(`err: ${util.inspect(err)}`)
|
// console.log(`err: ${util.inspect(err)}`)
|
||||||
assert.hasAnyKeys(err, ['error'])
|
assert.instanceOf(err, Error)
|
||||||
assert.include(err.error, 'Transaction not in mempool')
|
assert.include(err.message, 'Transaction not in mempool')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -241,8 +241,8 @@ describe('#blockchain', () => {
|
|||||||
console.log(`result: ${util.inspect(result)}`)
|
console.log(`result: ${util.inspect(result)}`)
|
||||||
assert.equal(true, false, 'Unexpected result!')
|
assert.equal(true, false, 'Unexpected result!')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.hasAnyKeys(err, ['error'])
|
assert.instanceOf(err, Error)
|
||||||
assert.include(err.error, 'Array too large')
|
assert.include(err.message, 'Array too large')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -318,7 +318,9 @@ describe('#blockchain', () => {
|
|||||||
it('should get info about the blockchain', async () => {
|
it('should get info about the blockchain', async () => {
|
||||||
const result = await bchjs.Blockchain.getBlockchainInfo()
|
const result = await bchjs.Blockchain.getBlockchainInfo()
|
||||||
|
|
||||||
console.log(`blockchain info: ${JSON.stringify(result, null, 2)}`)
|
// console.log(`blockchain info: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
|
assert.property(result, 'blocks')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
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({ restURL: process.env.RESTURL })
|
|
||||||
|
|
||||||
// Inspect utility used for debugging.
|
|
||||||
const util = require('util')
|
|
||||||
util.inspect.defaultOptions = {
|
|
||||||
showHidden: true,
|
|
||||||
colors: true,
|
|
||||||
depth: 3
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('#rawtransaction', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
|
||||||
})
|
|
||||||
|
|
||||||
/*
|
|
||||||
Testing sentRawTransaction isn't really possible with an integration test,
|
|
||||||
as the endpoint really needs an e2e test to be properly tested. The tests
|
|
||||||
below expect error messages returned from the server, but at least test
|
|
||||||
that the server is responding on those endpoints, and responds consistently.
|
|
||||||
*/
|
|
||||||
describe('sendRawTransaction', () => {
|
|
||||||
it('should send a single transaction hex', async () => {
|
|
||||||
try {
|
|
||||||
const hex =
|
|
||||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
|
||||||
|
|
||||||
await bchjs.RawTransactions.sendRawTransaction(hex)
|
|
||||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
|
||||||
|
|
||||||
assert.equal(true, false, 'Unexpected result!')
|
|
||||||
} catch (err) {
|
|
||||||
// console.log(`err: ${util.inspect(err)}`)
|
|
||||||
|
|
||||||
assert.hasAllKeys(err, ['error'])
|
|
||||||
assert.include(err.error, 'bad-txns-inputs-missingorspent')
|
|
||||||
// assert.include(err.error, 'Missing inputs')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should send an array of tx hexes', async () => {
|
|
||||||
try {
|
|
||||||
const hexes = [
|
|
||||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
|
|
||||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
|
||||||
]
|
|
||||||
|
|
||||||
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
|
|
||||||
console.log(`result ${JSON.stringify(result, null, 2)}`)
|
|
||||||
} catch (err) {
|
|
||||||
// console.log(`err: ${util.inspect(err)}`)
|
|
||||||
|
|
||||||
assert.hasAllKeys(err, ['error'])
|
|
||||||
assert.include(err.error, 'bad-txns-inputs-missingorspent')
|
|
||||||
// assert.include(err.error, 'Missing inputs')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
function sleep (ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
Integration tests for the utxo.js library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// const assert = require('chai').assert
|
|
||||||
|
|
||||||
// const BCHJS = require('../../../../src/bch-js')
|
|
||||||
// const bchjs = new BCHJS()
|
|
||||||
|
|
||||||
describe('#UTXO', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
// sandbox = sinon.createSandbox()
|
|
||||||
|
|
||||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
|
||||||
})
|
|
||||||
|
|
||||||
/*
|
|
||||||
describe('#get', () => {
|
|
||||||
it('should get hydrated and filtered UTXOs for an address', async () => {
|
|
||||||
// const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
|
||||||
const addr = 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
|
||||||
|
|
||||||
const result = await bchjs.Utxo.get(addr)
|
|
||||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
||||||
|
|
||||||
assert.isArray(result)
|
|
||||||
assert.property(result[0], 'address')
|
|
||||||
assert.property(result[0], 'bchUtxos')
|
|
||||||
assert.property(result[0], 'nullUtxos')
|
|
||||||
assert.property(result[0], 'slpUtxos')
|
|
||||||
assert.isArray(result[0].bchUtxos)
|
|
||||||
assert.isArray(result[0].nullUtxos)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
})
|
|
||||||
|
|
||||||
function sleep (ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
Integration tests for the bchjs. Only covers calls made to
|
|
||||||
rest.bitcoin.com.
|
|
||||||
|
|
||||||
TODO
|
|
||||||
*/
|
|
||||||
|
|
||||||
const chai = require('chai')
|
|
||||||
const assert = chai.assert
|
|
||||||
const BCHJS = require('../../../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS()
|
|
||||||
|
|
||||||
// Inspect utility used for debugging.
|
|
||||||
const util = require('util')
|
|
||||||
util.inspect.defaultOptions = {
|
|
||||||
showHidden: true,
|
|
||||||
colors: true,
|
|
||||||
depth: 3
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('#rawtransaction', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
|
|
||||||
})
|
|
||||||
|
|
||||||
/*
|
|
||||||
Testing sentRawTransaction isn't really possible with an integration test,
|
|
||||||
as the endpoint really needs an e2e test to be properly tested. The tests
|
|
||||||
below expect error messages returned from the server, but at least test
|
|
||||||
that the server is responding on those endpoints, and responds consistently.
|
|
||||||
*/
|
|
||||||
describe('sendRawTransaction', () => {
|
|
||||||
it('should send a single transaction hex', async () => {
|
|
||||||
try {
|
|
||||||
const hex =
|
|
||||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
|
||||||
|
|
||||||
await bchjs.RawTransactions.sendRawTransaction(hex)
|
|
||||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
|
||||||
|
|
||||||
assert.equal(true, false, 'Unexpected result!')
|
|
||||||
} catch (err) {
|
|
||||||
// console.log(`err: ${util.inspect(err)}`)
|
|
||||||
|
|
||||||
assert.hasAllKeys(err, ['error'])
|
|
||||||
assert.include(err.error, 'Missing inputs')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should send an array of tx hexes', async () => {
|
|
||||||
try {
|
|
||||||
const hexes = [
|
|
||||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
|
|
||||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
|
||||||
]
|
|
||||||
|
|
||||||
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
|
|
||||||
console.log(`result ${JSON.stringify(result, null, 2)}`)
|
|
||||||
} catch (err) {
|
|
||||||
// console.log(`err: ${util.inspect(err)}`)
|
|
||||||
|
|
||||||
assert.hasAllKeys(err, ['error'])
|
|
||||||
assert.include(err.error, 'Missing inputs')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
function sleep (ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
@@ -1,301 +0,0 @@
|
|||||||
/*
|
|
||||||
Integration tests for the bchjs covering SLP tokens.
|
|
||||||
These tests are specific to the ABC chain.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const chai = require('chai')
|
|
||||||
const assert = chai.assert
|
|
||||||
|
|
||||||
const BCHJS = require('../../../../src/bch-js')
|
|
||||||
let bchjs
|
|
||||||
|
|
||||||
// Inspect utility used for debugging.
|
|
||||||
const util = require('util')
|
|
||||||
util.inspect.defaultOptions = {
|
|
||||||
showHidden: true,
|
|
||||||
colors: true,
|
|
||||||
depth: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('#SLP', () => {
|
|
||||||
// before(() => {
|
|
||||||
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
|
|
||||||
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
|
|
||||||
// })
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
// Introduce a delay so that the BVT doesn't trip the rate limits.
|
|
||||||
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
|
|
||||||
|
|
||||||
bchjs = new BCHJS()
|
|
||||||
})
|
|
||||||
|
|
||||||
if (process.env.TESTSLP) {
|
|
||||||
describe('#util', () => {
|
|
||||||
describe('#decodeOpReturn', () => {
|
|
||||||
it('should decode a NFT Child transaction', async () => {
|
|
||||||
const txid =
|
|
||||||
'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b'
|
|
||||||
|
|
||||||
const data = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
||||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
||||||
|
|
||||||
assert.property(data, 'tokenType')
|
|
||||||
assert.property(data, 'txType')
|
|
||||||
assert.property(data, 'ticker')
|
|
||||||
assert.property(data, 'name')
|
|
||||||
assert.property(data, 'tokenId')
|
|
||||||
assert.property(data, 'documentUri')
|
|
||||||
assert.property(data, 'documentHash')
|
|
||||||
assert.property(data, 'decimals')
|
|
||||||
assert.property(data, 'mintBatonVout')
|
|
||||||
assert.property(data, 'qty')
|
|
||||||
|
|
||||||
assert.equal(data.tokenType, 65)
|
|
||||||
assert.equal(data.mintBatonVout, 0)
|
|
||||||
assert.equal(data.qty, '1')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#tokenUtxoDetails', () => {
|
|
||||||
it('should handle a range of UTXO types', async () => {
|
|
||||||
const utxos = [
|
|
||||||
// Malformed SLP tx
|
|
||||||
{
|
|
||||||
note: 'Malformed SLP tx',
|
|
||||||
tx_hash:
|
|
||||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
|
||||||
tx_pos: 1,
|
|
||||||
value: 546
|
|
||||||
},
|
|
||||||
// Normal TX (non-SLP)
|
|
||||||
{
|
|
||||||
note: 'Normal TX (non-SLP)',
|
|
||||||
tx_hash:
|
|
||||||
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
|
||||||
tx_pos: 0,
|
|
||||||
value: 400000
|
|
||||||
},
|
|
||||||
// Valid PSF SLP tx
|
|
||||||
{
|
|
||||||
note: 'Valid PSF SLP tx',
|
|
||||||
tx_hash:
|
|
||||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
|
||||||
tx_pos: 1,
|
|
||||||
value: 546
|
|
||||||
},
|
|
||||||
// Valid SLP token not in whitelist
|
|
||||||
{
|
|
||||||
note: 'Valid SLP token not in whitelist',
|
|
||||||
tx_hash:
|
|
||||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
|
||||||
tx_pos: 1,
|
|
||||||
value: 546
|
|
||||||
},
|
|
||||||
// Token send on BCHN network.
|
|
||||||
{
|
|
||||||
note: 'Token send on BCHN network',
|
|
||||||
tx_hash:
|
|
||||||
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
|
|
||||||
tx_pos: 1,
|
|
||||||
value: 546
|
|
||||||
},
|
|
||||||
// Token send on ABC network.
|
|
||||||
{
|
|
||||||
note: 'Token send on ABC network',
|
|
||||||
tx_hash:
|
|
||||||
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d',
|
|
||||||
tx_pos: 1,
|
|
||||||
value: 546
|
|
||||||
},
|
|
||||||
// Known invalid SLP token send of PSF tokens.
|
|
||||||
{
|
|
||||||
note: 'Known invalid SLP token send of PSF tokens',
|
|
||||||
tx_hash:
|
|
||||||
'2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74',
|
|
||||||
tx_pos: 1,
|
|
||||||
value: 546
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
|
||||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
|
||||||
|
|
||||||
// Malformed SLP tx
|
|
||||||
assert.equal(data[0].tx_hash, utxos[0].tx_hash)
|
|
||||||
assert.equal(data[0].isValid, false)
|
|
||||||
|
|
||||||
// Normal TX (non-SLP)
|
|
||||||
assert.equal(data[1].tx_hash, utxos[1].tx_hash)
|
|
||||||
assert.equal(data[1].isValid, false)
|
|
||||||
|
|
||||||
// Valid PSF SLP tx
|
|
||||||
assert.equal(data[2].tx_hash, utxos[2].tx_hash)
|
|
||||||
assert.equal(data[2].isValid, true)
|
|
||||||
|
|
||||||
// Valid SLP token not in whitelist
|
|
||||||
assert.equal(data[3].tx_hash, utxos[3].tx_hash)
|
|
||||||
assert.equal(data[3].isValid, true)
|
|
||||||
|
|
||||||
// Token send on BCHN network
|
|
||||||
assert.equal(data[4].tx_hash, utxos[4].tx_hash)
|
|
||||||
assert.equal(data[4].isValid, true)
|
|
||||||
|
|
||||||
// Token send on ABC network
|
|
||||||
assert.equal(data[5].tx_hash, utxos[5].tx_hash)
|
|
||||||
assert.equal(data[5].isValid, null)
|
|
||||||
|
|
||||||
// Known invalid SLP token send of PSF tokens
|
|
||||||
assert.equal(data[6].tx_hash, utxos[6].tx_hash)
|
|
||||||
assert.equal(data[6].isValid, false)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#validateTxid3', () => {
|
|
||||||
it('should invalidate a known invalid TXID', async () => {
|
|
||||||
const txid =
|
|
||||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
|
|
||||||
|
|
||||||
const result = await bchjs.SLP.Utils.validateTxid3(txid)
|
|
||||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
||||||
|
|
||||||
assert.isArray(result)
|
|
||||||
|
|
||||||
assert.property(result[0], 'txid')
|
|
||||||
assert.equal(result[0].txid, txid)
|
|
||||||
|
|
||||||
assert.property(result[0], 'valid')
|
|
||||||
assert.equal(result[0].valid, null)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should validate a known valid TXID', async () => {
|
|
||||||
const txid =
|
|
||||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd'
|
|
||||||
|
|
||||||
const result = await bchjs.SLP.Utils.validateTxid3(txid)
|
|
||||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
||||||
|
|
||||||
assert.isArray(result)
|
|
||||||
|
|
||||||
assert.property(result[0], 'txid')
|
|
||||||
assert.equal(result[0].txid, txid)
|
|
||||||
|
|
||||||
assert.property(result[0], 'valid')
|
|
||||||
assert.equal(result[0].valid, true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
|
|
||||||
const txids = [
|
|
||||||
// Malformed SLP tx
|
|
||||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
|
||||||
// Normal TX (non-SLP)
|
|
||||||
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
|
||||||
// Valid PSF SLP tx
|
|
||||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
|
||||||
// Valid SLP token not in whitelist
|
|
||||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
|
||||||
// Unprocessed SLP TX
|
|
||||||
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019'
|
|
||||||
]
|
|
||||||
|
|
||||||
const result = await bchjs.SLP.Utils.validateTxid3(txids)
|
|
||||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
||||||
|
|
||||||
assert.isArray(result)
|
|
||||||
|
|
||||||
assert.equal(result[0].txid, txids[0])
|
|
||||||
assert.equal(result[0].valid, null)
|
|
||||||
|
|
||||||
assert.equal(result[1].txid, txids[1])
|
|
||||||
assert.equal(result[1].valid, null)
|
|
||||||
|
|
||||||
assert.equal(result[2].txid, txids[2])
|
|
||||||
assert.equal(result[2].valid, true)
|
|
||||||
|
|
||||||
// True in validateTxid() but null in validateTxid3()
|
|
||||||
assert.equal(result[3].txid, txids[3])
|
|
||||||
assert.equal(result[3].valid, null)
|
|
||||||
|
|
||||||
// Note: This should change from null to true once SLPDB finishes indexing.
|
|
||||||
assert.equal(result[4].txid, txids[4])
|
|
||||||
assert.equal(result[4].valid, null)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#validateTxid', () => {
|
|
||||||
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
|
|
||||||
const txids = [
|
|
||||||
// Malformed SLP tx
|
|
||||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
|
||||||
// Normal TX (non-SLP)
|
|
||||||
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
|
||||||
// Valid PSF SLP tx
|
|
||||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
|
||||||
// Valid SLP token not in whitelist
|
|
||||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
|
||||||
// Token send on BCHN network.
|
|
||||||
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
|
|
||||||
// Token send on ABC network.
|
|
||||||
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d'
|
|
||||||
]
|
|
||||||
|
|
||||||
const result = await bchjs.SLP.Utils.validateTxid(txids)
|
|
||||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
||||||
|
|
||||||
assert.isArray(result)
|
|
||||||
|
|
||||||
assert.equal(result[0].txid, txids[0])
|
|
||||||
assert.equal(result[0].valid, null)
|
|
||||||
|
|
||||||
assert.equal(result[1].txid, txids[1])
|
|
||||||
assert.equal(result[1].valid, null)
|
|
||||||
|
|
||||||
assert.equal(result[2].txid, txids[2])
|
|
||||||
assert.equal(result[2].valid, true)
|
|
||||||
|
|
||||||
// True in validateTxid() but null in validateTxid3()
|
|
||||||
assert.equal(result[3].txid, txids[3])
|
|
||||||
assert.equal(result[3].valid, true)
|
|
||||||
|
|
||||||
assert.equal(result[4].txid, txids[4])
|
|
||||||
assert.equal(result[4].valid, true)
|
|
||||||
|
|
||||||
assert.equal(result[5].txid, txids[5])
|
|
||||||
assert.equal(result[5].valid, null)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
describe('#nft1', () => {
|
|
||||||
describe('#listNFTGroupChildren', () => {
|
|
||||||
it('should return array of children GENESIS transactions IDs', async () => {
|
|
||||||
const groupId =
|
|
||||||
'68cd33ecd909068fbea318ae5ff1d6207cf754e53b191327d6d73b6916424c0a'
|
|
||||||
const result = await bchjs.SLP.NFT1.listNFTGroupChildren(groupId)
|
|
||||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
||||||
assert.property(result, 'nftChildren')
|
|
||||||
assert.isArray(result.nftChildren)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
describe('#parentNFTGroup', () => {
|
|
||||||
it('should return parent NFT group information', async () => {
|
|
||||||
const tokenId =
|
|
||||||
'45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a9'
|
|
||||||
const result = await bchjs.SLP.NFT1.parentNFTGroup(tokenId)
|
|
||||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
||||||
assert.property(result, 'nftGroup')
|
|
||||||
assert.property(result.nftGroup, 'id')
|
|
||||||
assert.property(result.nftGroup, 'name')
|
|
||||||
assert.property(result.nftGroup, 'symbol')
|
|
||||||
assert.property(result.nftGroup, 'documentUri')
|
|
||||||
assert.property(result.nftGroup, 'versionType')
|
|
||||||
assert.property(result.nftGroup, 'initialTokenQty')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Promise-based sleep function
|
|
||||||
function sleep (ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
Integration tests for the transaction.js library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const assert = require('chai').assert
|
|
||||||
const BCHJS = require('../../../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS()
|
|
||||||
|
|
||||||
describe('#Transaction', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
if (process.env.IS_USING_FREE_TIER) await bchjs.Util.sleep(1000)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#get', () => {
|
|
||||||
it('should get a tx details for a non-SLP TX with an OP_RETURN', async () => {
|
|
||||||
const txid =
|
|
||||||
'01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b'
|
|
||||||
|
|
||||||
const result = await bchjs.Transaction.get(txid)
|
|
||||||
// console.log('result: ', result)
|
|
||||||
|
|
||||||
assert.property(result.txData, 'txid')
|
|
||||||
assert.property(result.txData, 'vin')
|
|
||||||
assert.property(result.txData, 'vout')
|
|
||||||
assert.equal(result.txData.isValidSlp, false)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
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', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
|
||||||
})
|
|
||||||
|
|
||||||
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 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')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
function sleep (ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
@@ -1,260 +0,0 @@
|
|||||||
/*
|
|
||||||
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 RESTURL = process.env.RESTURL
|
|
||||||
? process.env.RESTURL
|
|
||||||
: 'https://testnet3.fullstack.cash/v5/'
|
|
||||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
|
||||||
|
|
||||||
const BCHJS = require('../../../../src/bch-js')
|
|
||||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v5/` })
|
|
||||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
|
||||||
|
|
||||||
// Inspect utility used for debugging.
|
|
||||||
const util = require('util')
|
|
||||||
util.inspect.defaultOptions = {
|
|
||||||
showHidden: true,
|
|
||||||
colors: true,
|
|
||||||
depth: 3
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('#blockchain', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
|
||||||
})
|
|
||||||
|
|
||||||
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 =
|
|
||||||
'000000000000c57178ace90210289e6b5383134c5b5306e1cdd8395176e10aaf'
|
|
||||||
|
|
||||||
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 = [
|
|
||||||
'000000000000c57178ace90210289e6b5383134c5b5306e1cdd8395176e10aaf',
|
|
||||||
'00000000000b7db4cbae48d852fcbef32f728014582094ad613fe12af6600ff2'
|
|
||||||
]
|
|
||||||
|
|
||||||
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 error on array size rate limit', async () => {
|
|
||||||
try {
|
|
||||||
const data = []
|
|
||||||
for (let i = 0; i < 25; i++) {
|
|
||||||
data.push(
|
|
||||||
'00000000000b7db4cbae48d852fcbef32f728014582094ad613fe12af6600ff2'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 =
|
|
||||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
|
|
||||||
|
|
||||||
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')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
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)}`)
|
|
||||||
|
|
||||||
assert.isString(result)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should get an array of tx out proofs', async () => {
|
|
||||||
const txid = [
|
|
||||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04',
|
|
||||||
'fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752'
|
|
||||||
]
|
|
||||||
|
|
||||||
const result = await bchjs.Blockchain.getTxOutProof(txid)
|
|
||||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
||||||
|
|
||||||
assert.isArray(result)
|
|
||||||
assert.isString(result[0])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#verifyTxOutProof', () => {
|
|
||||||
const mockTxOutProof =
|
|
||||||
'00000020ac86ce8f2bda235c0dc135d18f6a777c44b121e8f41db8a51ca65000000000000cd4de3c49337712f3a1092c47c3bf73ec2f9b1cfd289ee991ede0b6eab4df229d5b8c5dffff001d82ce005b0700000003ec55d9142eac2c1d2229e5af24898b2590c111b62e2787fa1998d3d713fd432fd557124ed758fa156a6cdc6d317d5575aec2b86dfb159c62ecb4743f28bef1cb52e7a32fbec31e367ec152fdb952f75ee75bd8575f97b394093dbb0e6c694ffc0135'
|
|
||||||
|
|
||||||
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],
|
|
||||||
'fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752'
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
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],
|
|
||||||
'fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752'
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
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')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
function sleep (ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
Integration tests for bchjs control library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const chai = require('chai')
|
|
||||||
const assert = chai.assert
|
|
||||||
|
|
||||||
const RESTURL = process.env.RESTURL
|
|
||||||
? process.env.RESTURL
|
|
||||||
: 'https://testnet3.fullstack.cash/v5/'
|
|
||||||
|
|
||||||
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(1500)
|
|
||||||
})
|
|
||||||
|
|
||||||
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')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
function sleep (ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
@@ -1,376 +0,0 @@
|
|||||||
const chai = require('chai')
|
|
||||||
const assert = chai.assert
|
|
||||||
const sinon = require('sinon')
|
|
||||||
const util = require('util')
|
|
||||||
|
|
||||||
const RESTURL = process.env.RESTURL
|
|
||||||
? process.env.RESTURL
|
|
||||||
: 'https://testnet3.fullstack.cash/v5/'
|
|
||||||
|
|
||||||
const BCHJS = require('../../../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
|
||||||
|
|
||||||
describe('#ElectrumX', () => {
|
|
||||||
let sandbox
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
sandbox = sinon.createSandbox()
|
|
||||||
|
|
||||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(() => sandbox.restore())
|
|
||||||
|
|
||||||
describe('#utxo', () => {
|
|
||||||
it('should GET utxos for a single address', async () => {
|
|
||||||
const addr = 'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2'
|
|
||||||
|
|
||||||
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 utxo details for an array of addresses', async () => {
|
|
||||||
const addr = [
|
|
||||||
'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2',
|
|
||||||
'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2'
|
|
||||||
]
|
|
||||||
|
|
||||||
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('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2')
|
|
||||||
}
|
|
||||||
|
|
||||||
// const result = await bchjs.Electrumx.utxo(addr)
|
|
||||||
// console.log(`result: ${util.inspect(result)}`)
|
|
||||||
await bchjs.Electrumx.utxo(addr)
|
|
||||||
|
|
||||||
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 = 'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2'
|
|
||||||
|
|
||||||
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 = [
|
|
||||||
'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2',
|
|
||||||
'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2'
|
|
||||||
]
|
|
||||||
|
|
||||||
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('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2')
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = 'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2'
|
|
||||||
|
|
||||||
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 = [
|
|
||||||
'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2',
|
|
||||||
'bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2'
|
|
||||||
]
|
|
||||||
|
|
||||||
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('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2')
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = "bchtest:qp25k20dgcljrz4hkdz43partam3j5httyprjp23qd"
|
|
||||||
|
|
||||||
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 unconfirmed UTXO details for an array of addresses`, async () => {
|
|
||||||
const addr = [
|
|
||||||
"bchtest:qp25k20dgcljrz4hkdz43partam3j5httyprjp23qd",
|
|
||||||
"bchtest:qpkl3xylrjx4jup6m66e7zg7whlaucsxeudxeqawdj"
|
|
||||||
]
|
|
||||||
|
|
||||||
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('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2')
|
|
||||||
}
|
|
||||||
|
|
||||||
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 =
|
|
||||||
'76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee'
|
|
||||||
|
|
||||||
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 = [
|
|
||||||
'76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee',
|
|
||||||
'76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee'
|
|
||||||
]
|
|
||||||
|
|
||||||
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(
|
|
||||||
'76d2ee0ebd8b978742f6478ff9a12f478c34e4cee0a2b919059101d961bd01ee'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
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.error,
|
|
||||||
'the transaction was rejected by network rules'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
function sleep (ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
@@ -1,296 +0,0 @@
|
|||||||
/*
|
|
||||||
Integration tests for the bchjs. Only covers calls made to
|
|
||||||
rest.bitcoin.com.
|
|
||||||
|
|
||||||
TODO
|
|
||||||
*/
|
|
||||||
|
|
||||||
const chai = require('chai')
|
|
||||||
const assert = chai.assert
|
|
||||||
|
|
||||||
const RESTURL = process.env.RESTURL
|
|
||||||
? process.env.RESTURL
|
|
||||||
: 'https://testnet3.fullstack.cash/v5/'
|
|
||||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
|
||||||
|
|
||||||
const BCHJS = require('../../../../src/bch-js')
|
|
||||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v5/` })
|
|
||||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
|
||||||
|
|
||||||
// Inspect utility used for debugging.
|
|
||||||
const util = require('util')
|
|
||||||
util.inspect.defaultOptions = {
|
|
||||||
showHidden: true,
|
|
||||||
colors: true,
|
|
||||||
depth: 3
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('#rawtransaction', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
|
||||||
})
|
|
||||||
|
|
||||||
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 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 =
|
|
||||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
|
|
||||||
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 =
|
|
||||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
|
|
||||||
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 = [
|
|
||||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04',
|
|
||||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
|
|
||||||
]
|
|
||||||
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 = [
|
|
||||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04',
|
|
||||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
|
|
||||||
]
|
|
||||||
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 limit', async () => {
|
|
||||||
try {
|
|
||||||
const dataMock =
|
|
||||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
|
|
||||||
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)}`)
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
})
|
|
||||||
|
|
||||||
/*
|
|
||||||
Testing sentRawTransaction isn't really possible with an integration test,
|
|
||||||
as the endpoint really needs an e2e test to be properly tested. The tests
|
|
||||||
below expect error messages returned from the server, but at least test
|
|
||||||
that the server is responding on those endpoints, and responds consistently.
|
|
||||||
*/
|
|
||||||
describe('sendRawTransaction', () => {
|
|
||||||
it('should send a single transaction hex', async () => {
|
|
||||||
try {
|
|
||||||
const hex =
|
|
||||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
|
||||||
|
|
||||||
await bchjs.RawTransactions.sendRawTransaction(hex)
|
|
||||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
|
||||||
|
|
||||||
assert.equal(true, false, 'Unexpected result!')
|
|
||||||
} catch (err) {
|
|
||||||
// console.log(`err: ${util.inspect(err)}`)
|
|
||||||
|
|
||||||
assert.hasAllKeys(err, ['error'])
|
|
||||||
assert.include(err.error, 'Missing inputs')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should send an array of tx hexes', async () => {
|
|
||||||
try {
|
|
||||||
const hexes = [
|
|
||||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
|
|
||||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
|
||||||
]
|
|
||||||
|
|
||||||
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
|
|
||||||
console.log(`result ${JSON.stringify(result, null, 2)}`)
|
|
||||||
} catch (err) {
|
|
||||||
// console.log(`err: ${util.inspect(err)}`)
|
|
||||||
|
|
||||||
assert.hasAllKeys(err, ['error'])
|
|
||||||
assert.include(err.error, 'Missing inputs')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
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')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
function sleep (ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
/*
|
|
||||||
Integration tests for the bchjs covering SLP tokens.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const chai = require('chai')
|
|
||||||
const assert = chai.assert
|
|
||||||
|
|
||||||
const RESTURL = process.env.RESTURL
|
|
||||||
? process.env.RESTURL
|
|
||||||
: 'https://testnet3.fullstack.cash/v5/'
|
|
||||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
|
||||||
|
|
||||||
const BCHJS = require('../../../../src/bch-js')
|
|
||||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v5/` })
|
|
||||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
|
||||||
|
|
||||||
// Inspect utility used for debugging.
|
|
||||||
const util = require('util')
|
|
||||||
util.inspect.defaultOptions = {
|
|
||||||
showHidden: true,
|
|
||||||
colors: true,
|
|
||||||
depth: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('#SLP', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
// Introduce a delay so that the BVT doesn't trip the rate limits.
|
|
||||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#util', () => {
|
|
||||||
it('should get information on the Oasis token', async () => {
|
|
||||||
const tokenId =
|
|
||||||
'a371e9934c7695d08a5eb7f31d3bceb4f3644860cc67520cda1e149423b9ec39'
|
|
||||||
|
|
||||||
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 =
|
|
||||||
'ad28116e0818339342dddfc5f58ca8a5379ceb9679b4e4cbd72f4de905415ec1'
|
|
||||||
|
|
||||||
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
|
||||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
||||||
|
|
||||||
assert.hasAllKeys(result, ['amounts', 'tokenType', 'tokenId', 'txType'])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#balancesForAddress', () => {
|
|
||||||
it('should fetch all balances for address: slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9', async () => {
|
|
||||||
const balances = await bchjs.SLP.Utils.balancesForAddress(
|
|
||||||
'slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9'
|
|
||||||
)
|
|
||||||
// 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 = [
|
|
||||||
'slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9',
|
|
||||||
'slptest:qr5uy4h8ysyhwkp9s245scckdnc7teyjqc5ft2z43h'
|
|
||||||
]
|
|
||||||
|
|
||||||
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('#tokenUtxoDetails', () => {
|
|
||||||
it('should hydrate UTXOs', async () => {
|
|
||||||
const bchAddr = bchjs.SLP.Address.toCashAddress(
|
|
||||||
'slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9'
|
|
||||||
)
|
|
||||||
|
|
||||||
const utxos = await bchjs.Electrumx.utxo([bchAddr])
|
|
||||||
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
|
||||||
|
|
||||||
const utxoInfo = await bchjs.SLP.Utils.tokenUtxoDetails(
|
|
||||||
utxos.utxos[0].utxos
|
|
||||||
)
|
|
||||||
// console.log(`utxoInfo: ${JSON.stringify(utxoInfo, null, 2)}`)
|
|
||||||
|
|
||||||
assert.isArray(utxoInfo)
|
|
||||||
|
|
||||||
// first UTXO should be a PSF test token.
|
|
||||||
assert.equal(utxoInfo[0].isValid, true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#hydrateUtxos', () => {
|
|
||||||
// This test will error out if the LOCAL_RESTURL settings is not set properly
|
|
||||||
// in bch-api.
|
|
||||||
it('should hydrate UTXOs', async () => {
|
|
||||||
const bchAddr = bchjs.SLP.Address.toCashAddress(
|
|
||||||
'slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9'
|
|
||||||
)
|
|
||||||
|
|
||||||
const utxos = await bchjs.Electrumx.utxo([bchAddr])
|
|
||||||
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
|
||||||
|
|
||||||
const utxoInfo = await bchjs.SLP.Utils.hydrateUtxos(utxos.utxos)
|
|
||||||
// console.log(`utxoInfo: ${JSON.stringify(utxoInfo, null, 2)}`)
|
|
||||||
|
|
||||||
assert.isArray(utxoInfo.slpUtxos[0].utxos)
|
|
||||||
|
|
||||||
// first UTXO should be a PSF test token.
|
|
||||||
assert.equal(utxoInfo.slpUtxos[0].utxos[0].isValid, true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#validateTxid2', () => {
|
|
||||||
it('should validate a token txid', async () => {
|
|
||||||
const txid =
|
|
||||||
'ad28116e0818339342dddfc5f58ca8a5379ceb9679b4e4cbd72f4de905415ec1'
|
|
||||||
|
|
||||||
const validated = await bchjs.SLP.Utils.validateTxid(txid)
|
|
||||||
// console.log(validated)
|
|
||||||
|
|
||||||
assert.equal(validated[0].valid, true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Promise-based sleep function
|
|
||||||
function sleep (ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
export RESTURL=https://free-test.fullstack.cash/v5/
|
|
||||||
export NETWORK=testnet
|
|
||||||
export IS_USING_FREE_TIER=true
|
|
||||||
|
|
||||||
cd test/integration/testnet/
|
|
||||||
mocha --timeout 30000 blockchain.js control.js electrumx.js rawtransaction.js slp.js util.js
|
|
||||||
#mocha --timeout 30000 blockchain.js
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
/*
|
|
||||||
Integration tests for the bchjs. Only covers calls made to
|
|
||||||
rest.bitcoin.com.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const chai = require('chai')
|
|
||||||
const assert = chai.assert
|
|
||||||
|
|
||||||
const RESTURL = process.env.RESTURL
|
|
||||||
? process.env.RESTURL
|
|
||||||
: 'https://testnet3.fullstack.cash/v5/'
|
|
||||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
|
||||||
|
|
||||||
const BCHJS = require('../../../../src/bch-js')
|
|
||||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v5/` })
|
|
||||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
|
||||||
|
|
||||||
// Inspect utility used for debugging.
|
|
||||||
const util = require('util')
|
|
||||||
util.inspect.defaultOptions = {
|
|
||||||
showHidden: true,
|
|
||||||
colors: true,
|
|
||||||
depth: 3
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('#util', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#validateAddress', () => {
|
|
||||||
it('should return false for testnet addr on mainnet', 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 return false for bad address', async () => {
|
|
||||||
const address = 'bchtest:qqqk4y6lsl5da64sg53xezmplyu5kmpyz2ysaa5y'
|
|
||||||
|
|
||||||
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 = 'bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y'
|
|
||||||
|
|
||||||
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 = [
|
|
||||||
'bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y',
|
|
||||||
'bchtest:pq6k9969f6v6sg7a75jkru4n7wn9sknv5cztcp0dnh'
|
|
||||||
]
|
|
||||||
|
|
||||||
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 error on array size rate limit', async () => {
|
|
||||||
try {
|
|
||||||
const dataMock = 'bchtest:pq6k9969f6v6sg7a75jkru4n7wn9sknv5cztcp0dnh'
|
|
||||||
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')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
function sleep (ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
Integration tests for bchjs control library.
|
Integration tests for bchjs control library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const chai = require('chai')
|
import chai from 'chai'
|
||||||
|
import BCHJS from '../../src/bch-js.js'
|
||||||
const assert = chai.assert
|
const assert = chai.assert
|
||||||
const BCHJS = require('../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS()
|
const bchjs = new BCHJS()
|
||||||
|
|
||||||
describe('#control', () => {
|
describe('#control', () => {
|
||||||
@@ -15,7 +15,7 @@ describe('#control', () => {
|
|||||||
describe('#getNetworkInfo', () => {
|
describe('#getNetworkInfo', () => {
|
||||||
it('should get info on the full node', async () => {
|
it('should get info on the full node', async () => {
|
||||||
const result = await bchjs.Control.getNetworkInfo()
|
const result = await bchjs.Control.getNetworkInfo()
|
||||||
console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
assert.property(result, 'version')
|
assert.property(result, 'version')
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,9 +2,13 @@
|
|||||||
Integration tests for bchjs dsproof library.
|
Integration tests for bchjs dsproof library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
// Global npm libraries
|
||||||
|
import chai from 'chai'
|
||||||
|
|
||||||
|
// Local libraries
|
||||||
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
const { assert } = chai
|
||||||
|
|
||||||
const BCHJS = require('../../../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS()
|
const bchjs = new BCHJS()
|
||||||
|
|
||||||
describe('#DSProof', () => {
|
describe('#DSProof', () => {
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
const chai = require('chai')
|
import chai from 'chai'
|
||||||
const assert = chai.assert
|
import sinon from 'sinon'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
const BCHJS = require('../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
const assert = chai.assert
|
||||||
const bchjs = new BCHJS()
|
const bchjs = new BCHJS()
|
||||||
|
|
||||||
describe('#ElectrumX', () => {
|
describe('#ElectrumX', () => {
|
||||||
@@ -73,8 +73,8 @@ describe('#ElectrumX', () => {
|
|||||||
// console.log(`result: ${util.inspect(result)}`)
|
// console.log(`result: ${util.inspect(result)}`)
|
||||||
assert.equal(true, false, 'Unexpected result!')
|
assert.equal(true, false, 'Unexpected result!')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.hasAnyKeys(err, ['error'])
|
assert.instanceOf(err, Error)
|
||||||
assert.include(err.error, 'Array too large')
|
assert.include(err.message, 'Array too large')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -129,8 +129,8 @@ describe('#ElectrumX', () => {
|
|||||||
|
|
||||||
assert.equal(true, false, 'Unexpected result!')
|
assert.equal(true, false, 'Unexpected result!')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.hasAnyKeys(err, ['error'])
|
assert.instanceOf(err, Error)
|
||||||
assert.include(err.error, 'Array too large')
|
assert.include(err.message, 'Array too large')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -187,8 +187,8 @@ describe('#ElectrumX', () => {
|
|||||||
|
|
||||||
assert.equal(true, false, 'Unexpected result!')
|
assert.equal(true, false, 'Unexpected result!')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.hasAnyKeys(err, ['error'])
|
assert.instanceOf(err, Error)
|
||||||
assert.include(err.error, 'Array too large')
|
assert.include(err.message, 'Array too large')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -250,8 +250,8 @@ describe('#ElectrumX', () => {
|
|||||||
// console.log(`result: ${util.inspect(result)}`)
|
// console.log(`result: ${util.inspect(result)}`)
|
||||||
assert.equal(true, false, 'Unexpected result!')
|
assert.equal(true, false, 'Unexpected result!')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.hasAnyKeys(err, ['error'])
|
assert.instanceOf(err, Error)
|
||||||
assert.include(err.error, 'Array too large')
|
assert.include(err.message, 'Array too large')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -345,8 +345,8 @@ describe('#ElectrumX', () => {
|
|||||||
// console.log(`result: ${util.inspect(result)}`)
|
// console.log(`result: ${util.inspect(result)}`)
|
||||||
assert.equal(true, false, 'Unexpected result!')
|
assert.equal(true, false, 'Unexpected result!')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert.hasAnyKeys(err, ['error'])
|
assert.instanceOf(err, Error)
|
||||||
assert.include(err.error, 'Array too large')
|
assert.include(err.message, 'Array too large')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -359,12 +359,9 @@ describe('#ElectrumX', () => {
|
|||||||
try {
|
try {
|
||||||
await bchjs.Electrumx.broadcast(txHex)
|
await bchjs.Electrumx.broadcast(txHex)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// console.log('err: ', err)
|
// console.error('err: ', err)
|
||||||
|
|
||||||
assert.property(err, 'success')
|
|
||||||
assert.equal(err.success, false)
|
|
||||||
assert.include(
|
assert.include(
|
||||||
err.error.error,
|
err.message,
|
||||||
'the transaction was rejected by network rules'
|
'the transaction was rejected by network rules'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -373,6 +370,9 @@ describe('#ElectrumX', () => {
|
|||||||
|
|
||||||
describe('#sortAllTxs', () => {
|
describe('#sortAllTxs', () => {
|
||||||
it('should GET transaction history for a single address', async () => {
|
it('should GET transaction history for a single address', async () => {
|
||||||
|
// Add delay for this endpoint.
|
||||||
|
await sleep(6000)
|
||||||
|
|
||||||
const addr = 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
const addr = 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
||||||
|
|
||||||
const txs = await bchjs.Electrumx.transactions(addr)
|
const txs = await bchjs.Electrumx.transactions(addr)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const assert = require('chai').assert
|
// const assert = require('chai').assert
|
||||||
|
|
||||||
const BCHJS = require('../../src/bch-js')
|
// const BCHJS = require('../../src/bch-js')
|
||||||
const bchjs = new BCHJS()
|
// const bchjs = new BCHJS()
|
||||||
|
|
||||||
describe('#Encryption', () => {
|
describe('#Encryption', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@@ -9,7 +9,12 @@ describe('#Encryption', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('#getPubKey', () => {
|
describe('#getPubKey', () => {
|
||||||
|
// Commenting out these tests since they are failing in BVT due to 429 errors
|
||||||
|
/*
|
||||||
it('should get a public key', async () => {
|
it('should get a public key', async () => {
|
||||||
|
// Add delay for this endpoint.
|
||||||
|
await sleep(8000)
|
||||||
|
|
||||||
const addr = 'bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq'
|
const addr = 'bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq'
|
||||||
|
|
||||||
const result = await bchjs.encryption.getPubKey(addr)
|
const result = await bchjs.encryption.getPubKey(addr)
|
||||||
@@ -21,6 +26,9 @@ describe('#Encryption', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should report when public key can not be found', async () => {
|
it('should report when public key can not be found', async () => {
|
||||||
|
// Add delay for this endpoint.
|
||||||
|
await sleep(8000)
|
||||||
|
|
||||||
const addr = 'bitcoincash:qrgqqkky28jdkv3w0ctrah0mz3jcsnsklc34gtukrh'
|
const addr = 'bitcoincash:qrgqqkky28jdkv3w0ctrah0mz3jcsnsklc34gtukrh'
|
||||||
|
|
||||||
const result = await bchjs.encryption.getPubKey(addr)
|
const result = await bchjs.encryption.getPubKey(addr)
|
||||||
@@ -31,6 +39,7 @@ describe('#Encryption', () => {
|
|||||||
assert.property(result, 'publicKey')
|
assert.property(result, 'publicKey')
|
||||||
assert.equal(result.publicKey, 'not found')
|
assert.equal(result.publicKey, 'not found')
|
||||||
})
|
})
|
||||||
|
*/
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const assert = require('chai').assert
|
import chai from 'chai'
|
||||||
const BCHJS = require('../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
const { assert } = chai
|
||||||
const bchjs = new BCHJS()
|
const bchjs = new BCHJS()
|
||||||
|
|
||||||
describe('#price', () => {
|
describe('#price', () => {
|
||||||
@@ -7,32 +8,6 @@ describe('#price', () => {
|
|||||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||||
})
|
})
|
||||||
|
|
||||||
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('#getBchUsd', () => {
|
describe('#getBchUsd', () => {
|
||||||
it('should get the USD price of BCH', async () => {
|
it('should get the USD price of BCH', async () => {
|
||||||
const result = await bchjs.Price.getBchUsd()
|
const result = await bchjs.Price.getBchUsd()
|
||||||
@@ -42,13 +17,12 @@ describe('#price', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#rates', () => {
|
describe('#getPsffppPrice', () => {
|
||||||
it('should get the price of BCH in several currencies', async () => {
|
it('should get the price to write 1MB to the PSFFPP', async () => {
|
||||||
const result = await bchjs.Price.rates()
|
const result = await bchjs.Price.getPsffppPrice()
|
||||||
// console.log(result)
|
// console.log(result)
|
||||||
|
|
||||||
assert.property(result, 'USD')
|
assert.isNumber(result)
|
||||||
assert.property(result, 'CAD')
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+60
-7
@@ -1,10 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
Integration tests for the psf-slp-indexer.js library
|
Integration tests for the psf-slp-indexer.js library, specific to the BCH
|
||||||
|
blockchain.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
// Global npm libraries
|
||||||
|
import chai from 'chai'
|
||||||
|
|
||||||
const BCHJS = require('../../../../src/bch-js')
|
// Local libraries
|
||||||
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
const { assert } = chai
|
||||||
let bchjs
|
let bchjs
|
||||||
|
|
||||||
describe('#psf-slp-indexer', () => {
|
describe('#psf-slp-indexer', () => {
|
||||||
@@ -92,9 +96,7 @@ describe('#psf-slp-indexer', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// FlexUSD transactions
|
// FlexUSD transactions
|
||||||
// Currently FlexUSD UTXOs are reported as invalid SLP UTXOs, which means
|
// FlexUSD is blacklisted by the SLP indexer.
|
||||||
// the wallet will burn them. There is a TODO in the code. This test will
|
|
||||||
// need to be changed when it is done.
|
|
||||||
it('should mark blacklisted token as null', async () => {
|
it('should mark blacklisted token as null', async () => {
|
||||||
const txid =
|
const txid =
|
||||||
'302113c11b90edc5f36c073d2f8a75e1e0eaf59b56235491a843d3819cd6a85f'
|
'302113c11b90edc5f36c073d2f8a75e1e0eaf59b56235491a843d3819cd6a85f'
|
||||||
@@ -105,7 +107,7 @@ describe('#psf-slp-indexer', () => {
|
|||||||
assert.property(result.txData, 'vin')
|
assert.property(result.txData, 'vin')
|
||||||
assert.property(result.txData, 'vout')
|
assert.property(result.txData, 'vout')
|
||||||
assert.property(result.txData, 'isValidSlp')
|
assert.property(result.txData, 'isValidSlp')
|
||||||
assert.equal(result.txData.isValidSlp, null)
|
assert.equal(result.txData.isValidSlp, false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should throw error for non-existent txid', async () => {
|
it('should throw error for non-existent txid', async () => {
|
||||||
@@ -124,6 +126,57 @@ describe('#psf-slp-indexer', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('#getTokenData', () => {
|
||||||
|
it('should get token data', async () => {
|
||||||
|
const tokenId =
|
||||||
|
'd9aafa7acb514c597caf440ae268b5e4e955f2687e05f044cdf8fd9550d9a27b'
|
||||||
|
|
||||||
|
// bchjs.PsfSlpIndexer.restURL = 'http://localhost:3000/v5/'
|
||||||
|
const result = await bchjs.PsfSlpIndexer.getTokenData(tokenId)
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.property(result, 'genesisData')
|
||||||
|
assert.property(result, 'immutableData')
|
||||||
|
assert.property(result, 'mutableData')
|
||||||
|
|
||||||
|
assert.isObject(result.genesisData)
|
||||||
|
assert.isString(result.immutableData)
|
||||||
|
assert.isString(result.mutableData)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should get token data with a transaction history', async () => {
|
||||||
|
const tokenId = '43eddfb11c9941edffb8c8815574bb0a43969a7b1de39ad14cd043eaa24fd38d'
|
||||||
|
|
||||||
|
const result = await bchjs.PsfSlpIndexer.getTokenData(tokenId, true)
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.isArray(result.genesisData.txs)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// This test is commented out because it can not succeed in the BVT without
|
||||||
|
// tripping rate limits.
|
||||||
|
// describe('#getTokenData2', () => {
|
||||||
|
// it('should get token data', async () => {
|
||||||
|
// const tokenId =
|
||||||
|
// 'd9aafa7acb514c597caf440ae268b5e4e955f2687e05f044cdf8fd9550d9a27b'
|
||||||
|
//
|
||||||
|
// // bchjs.PsfSlpIndexer.restURL = 'http://localhost:3000/v5/'
|
||||||
|
// const result = await bchjs.PsfSlpIndexer.getTokenData2(tokenId)
|
||||||
|
// // console.log('result: ', result)
|
||||||
|
//
|
||||||
|
// assert.property(result, 'tokenStats')
|
||||||
|
// assert.property(result, 'mutableData')
|
||||||
|
// assert.property(result, 'immutableData')
|
||||||
|
// assert.property(result, 'tokenIcon')
|
||||||
|
// assert.property(result, 'fullSizedUrl')
|
||||||
|
// assert.property(result, 'optimizedTokenIcon')
|
||||||
|
// assert.property(result, 'optimizedFullSizedUrl')
|
||||||
|
// assert.property(result, 'iconRepoCompatible')
|
||||||
|
// assert.property(result, 'ps002Compatible')
|
||||||
|
// })
|
||||||
|
// })
|
||||||
})
|
})
|
||||||
|
|
||||||
// Promise-based sleep function
|
// Promise-based sleep function
|
||||||
@@ -4,13 +4,13 @@
|
|||||||
TODO
|
TODO
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const chai = require('chai')
|
import chai from 'chai'
|
||||||
const assert = chai.assert
|
import BCHJS from '../../src/bch-js.js'
|
||||||
const BCHJS = require('../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS()
|
|
||||||
|
|
||||||
// Inspect utility used for debugging.
|
// Inspect utility used for debugging.
|
||||||
const util = require('util')
|
import util from 'util'
|
||||||
|
const assert = chai.assert
|
||||||
|
const bchjs = new BCHJS()
|
||||||
util.inspect.defaultOptions = {
|
util.inspect.defaultOptions = {
|
||||||
showHidden: true,
|
showHidden: true,
|
||||||
colors: true,
|
colors: true,
|
||||||
@@ -204,7 +204,9 @@ describe('#rawtransaction', () => {
|
|||||||
const result = await bchjs.RawTransactions.decodeScript(hex)
|
const result = await bchjs.RawTransactions.decodeScript(hex)
|
||||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
assert.hasAllKeys(result, ['asm', 'type', 'p2sh'])
|
assert.property(result, 'asm')
|
||||||
|
assert.property(result, 'type')
|
||||||
|
assert.property(result, 'p2sh')
|
||||||
})
|
})
|
||||||
|
|
||||||
// CT 2/20/19 - Waiting for this PR to be merged complete the test:
|
// CT 2/20/19 - Waiting for this PR to be merged complete the test:
|
||||||
@@ -229,6 +231,40 @@ describe('#rawtransaction', () => {
|
|||||||
that the server is responding on those endpoints, and responds consistently.
|
that the server is responding on those endpoints, and responds consistently.
|
||||||
*/
|
*/
|
||||||
describe('#sendRawTransaction', () => {
|
describe('#sendRawTransaction', () => {
|
||||||
|
it('should send a single transaction hex', async () => {
|
||||||
|
try {
|
||||||
|
const hex =
|
||||||
|
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
||||||
|
|
||||||
|
await bchjs.RawTransactions.sendRawTransaction(hex)
|
||||||
|
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
|
assert.equal(true, false, 'Unexpected result!')
|
||||||
|
} catch (err) {
|
||||||
|
// console.log(`err: ${util.inspect(err)}`)
|
||||||
|
|
||||||
|
assert.hasAllKeys(err, ['error'])
|
||||||
|
assert.include(err.error, 'Missing inputs')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should send an array of tx hexes', async () => {
|
||||||
|
try {
|
||||||
|
const hexes = [
|
||||||
|
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
|
||||||
|
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
|
||||||
|
console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||||
|
} catch (err) {
|
||||||
|
// console.log(`err: ${util.inspect(err)}`)
|
||||||
|
|
||||||
|
assert.hasAllKeys(err, ['error'])
|
||||||
|
assert.include(err.error, 'Missing inputs')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it('should throw error on array size rate limit', async () => {
|
it('should throw error on array size rate limit', async () => {
|
||||||
try {
|
try {
|
||||||
const dataMock =
|
const dataMock =
|
||||||
|
|||||||
+147
-5
@@ -2,14 +2,14 @@
|
|||||||
Integration tests for the bchjs covering SLP tokens.
|
Integration tests for the bchjs covering SLP tokens.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const chai = require('chai')
|
import chai from 'chai'
|
||||||
const assert = chai.assert
|
|
||||||
|
|
||||||
const BCHJS = require('../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
let bchjs
|
|
||||||
|
|
||||||
// Inspect utility used for debugging.
|
// Inspect utility used for debugging.
|
||||||
const util = require('util')
|
import util from 'util'
|
||||||
|
const assert = chai.assert
|
||||||
|
let bchjs
|
||||||
util.inspect.defaultOptions = {
|
util.inspect.defaultOptions = {
|
||||||
showHidden: true,
|
showHidden: true,
|
||||||
colors: true,
|
colors: true,
|
||||||
@@ -524,6 +524,148 @@ describe('#SLP', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('#validateTxid3', () => {
|
||||||
|
it('should invalidate a known invalid TXID', async () => {
|
||||||
|
const txid =
|
||||||
|
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
|
||||||
|
|
||||||
|
const result = await bchjs.SLP.Utils.validateTxid3(txid)
|
||||||
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
|
assert.isArray(result)
|
||||||
|
|
||||||
|
assert.property(result[0], 'txid')
|
||||||
|
assert.equal(result[0].txid, txid)
|
||||||
|
|
||||||
|
assert.property(result[0], 'valid')
|
||||||
|
assert.equal(result[0].valid, null)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should validate a known valid TXID', async () => {
|
||||||
|
const txid =
|
||||||
|
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd'
|
||||||
|
|
||||||
|
const result = await bchjs.SLP.Utils.validateTxid3(txid)
|
||||||
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
|
assert.isArray(result)
|
||||||
|
|
||||||
|
assert.property(result[0], 'txid')
|
||||||
|
assert.equal(result[0].txid, txid)
|
||||||
|
|
||||||
|
assert.property(result[0], 'valid')
|
||||||
|
assert.equal(result[0].valid, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
|
||||||
|
const txids = [
|
||||||
|
// Malformed SLP tx
|
||||||
|
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
||||||
|
// Normal TX (non-SLP)
|
||||||
|
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
||||||
|
// Valid PSF SLP tx
|
||||||
|
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
||||||
|
// Valid SLP token not in whitelist
|
||||||
|
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
||||||
|
// Unprocessed SLP TX
|
||||||
|
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019'
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = await bchjs.SLP.Utils.validateTxid3(txids)
|
||||||
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
|
assert.isArray(result)
|
||||||
|
|
||||||
|
assert.equal(result[0].txid, txids[0])
|
||||||
|
assert.equal(result[0].valid, null)
|
||||||
|
|
||||||
|
assert.equal(result[1].txid, txids[1])
|
||||||
|
assert.equal(result[1].valid, null)
|
||||||
|
|
||||||
|
assert.equal(result[2].txid, txids[2])
|
||||||
|
assert.equal(result[2].valid, true)
|
||||||
|
|
||||||
|
// True in validateTxid() but null in validateTxid3()
|
||||||
|
assert.equal(result[3].txid, txids[3])
|
||||||
|
assert.equal(result[3].valid, null)
|
||||||
|
|
||||||
|
// Note: This should change from null to true once SLPDB finishes indexing.
|
||||||
|
assert.equal(result[4].txid, txids[4])
|
||||||
|
assert.equal(result[4].valid, null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#validateTxid', () => {
|
||||||
|
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
|
||||||
|
const txids = [
|
||||||
|
// Malformed SLP tx
|
||||||
|
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
||||||
|
// Normal TX (non-SLP)
|
||||||
|
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
||||||
|
// Valid PSF SLP tx
|
||||||
|
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
||||||
|
// Valid SLP token not in whitelist
|
||||||
|
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
||||||
|
// Token send on BCHN network.
|
||||||
|
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
|
||||||
|
// Token send on ABC network.
|
||||||
|
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d'
|
||||||
|
]
|
||||||
|
|
||||||
|
const result = await bchjs.SLP.Utils.validateTxid(txids)
|
||||||
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
|
assert.isArray(result)
|
||||||
|
|
||||||
|
assert.equal(result[0].txid, txids[0])
|
||||||
|
assert.equal(result[0].valid, null)
|
||||||
|
|
||||||
|
assert.equal(result[1].txid, txids[1])
|
||||||
|
assert.equal(result[1].valid, null)
|
||||||
|
|
||||||
|
assert.equal(result[2].txid, txids[2])
|
||||||
|
assert.equal(result[2].valid, true)
|
||||||
|
|
||||||
|
// True in validateTxid() but null in validateTxid3()
|
||||||
|
assert.equal(result[3].txid, txids[3])
|
||||||
|
assert.equal(result[3].valid, true)
|
||||||
|
|
||||||
|
assert.equal(result[4].txid, txids[4])
|
||||||
|
assert.equal(result[4].valid, true)
|
||||||
|
|
||||||
|
assert.equal(result[5].txid, txids[5])
|
||||||
|
assert.equal(result[5].valid, null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#nft1', () => {
|
||||||
|
describe('#listNFTGroupChildren', () => {
|
||||||
|
it('should return array of children GENESIS transactions IDs', async () => {
|
||||||
|
const groupId =
|
||||||
|
'68cd33ecd909068fbea318ae5ff1d6207cf754e53b191327d6d73b6916424c0a'
|
||||||
|
const result = await bchjs.SLP.NFT1.listNFTGroupChildren(groupId)
|
||||||
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
assert.property(result, 'nftChildren')
|
||||||
|
assert.isArray(result.nftChildren)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('#parentNFTGroup', () => {
|
||||||
|
it('should return parent NFT group information', async () => {
|
||||||
|
const tokenId =
|
||||||
|
'45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a9'
|
||||||
|
const result = await bchjs.SLP.NFT1.parentNFTGroup(tokenId)
|
||||||
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
assert.property(result, 'nftGroup')
|
||||||
|
assert.property(result.nftGroup, 'id')
|
||||||
|
assert.property(result.nftGroup, 'name')
|
||||||
|
assert.property(result.nftGroup, 'symbol')
|
||||||
|
assert.property(result.nftGroup, 'documentUri')
|
||||||
|
assert.property(result.nftGroup, 'versionType')
|
||||||
|
assert.property(result.nftGroup, 'initialTokenQty')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
Integration tests for the transaction.js library.
|
Integration tests for the transaction.js library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
import chai from 'chai'
|
||||||
const BCHJS = require('../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
const { assert } = chai
|
||||||
const bchjs = new BCHJS()
|
const bchjs = new BCHJS()
|
||||||
|
|
||||||
describe('#Transaction', () => {
|
describe('#Transaction', () => {
|
||||||
@@ -11,6 +12,30 @@ describe('#Transaction', () => {
|
|||||||
if (process.env.IS_USING_FREE_TIER) await bchjs.Util.sleep(1000)
|
if (process.env.IS_USING_FREE_TIER) await bchjs.Util.sleep(1000)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('#get', () => {
|
||||||
|
it('should get a tx details for a non-SLP TX with an OP_RETURN', async () => {
|
||||||
|
const txid =
|
||||||
|
'01517ff1587fa5ffe6f5eb91c99cf3f2d22330cd7ee847e928ce90ca95bf781b'
|
||||||
|
|
||||||
|
const result = await bchjs.Transaction.get(txid)
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.property(result.txData, 'txid')
|
||||||
|
assert.property(result.txData, 'vin')
|
||||||
|
assert.property(result.txData, 'vout')
|
||||||
|
assert.equal(result.txData.isValidSlp, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle a coinbase transaction', async () => {
|
||||||
|
const txid = 'cca1d2dd3a533d2f501448dec03face2cb2814afd59a533a611e9a2909f2302b'
|
||||||
|
|
||||||
|
const details = await bchjs.Transaction.get(txid)
|
||||||
|
// console.log(`details: ${JSON.stringify(details, null, 2)}`)
|
||||||
|
|
||||||
|
assert.property(details.txData, 'txid')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
if (process.env.TESTSLP) {
|
if (process.env.TESTSLP) {
|
||||||
describe('#getOld', () => {
|
describe('#getOld', () => {
|
||||||
it('should get details about a non-SLP transaction', async () => {
|
it('should get details about a non-SLP transaction', async () => {
|
||||||
|
|||||||
+78
-9
@@ -2,9 +2,10 @@
|
|||||||
Integration tests for the utxo.js library.
|
Integration tests for the utxo.js library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const assert = require('chai').assert
|
import chai from 'chai'
|
||||||
|
|
||||||
const BCHJS = require('../../../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
const { assert } = chai
|
||||||
const bchjs = new BCHJS()
|
const bchjs = new BCHJS()
|
||||||
// const bchjs = new BCHJS({ restURL: 'http://192.168.2.129:3000/v5/' })
|
// const bchjs = new BCHJS({ restURL: 'http://192.168.2.129:3000/v5/' })
|
||||||
|
|
||||||
@@ -79,14 +80,13 @@ describe('#UTXO', () => {
|
|||||||
assert.property(result, 'nullUtxos')
|
assert.property(result, 'nullUtxos')
|
||||||
|
|
||||||
assert.isAbove(result.bchUtxos.length, 0)
|
assert.isAbove(result.bchUtxos.length, 0)
|
||||||
|
assert.isAbove(result.infoUtxos.length, 0)
|
||||||
assert.isAbove(result.slpUtxos.type1.tokens.length, 0)
|
assert.isAbove(result.slpUtxos.type1.tokens.length, 0)
|
||||||
assert.equal(result.slpUtxos.type1.mintBatons.length, 0)
|
assert.equal(result.slpUtxos.type1.mintBatons.length, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: NFTs are currently not identified as different than normal BCH UTXOs.
|
it('should handle Type1 minting batons', async () => {
|
||||||
// The psf-slp-indexer needs to be updated to fix this issue.
|
const addr = 'simpleledger:qrp4mlmsrtwlvjn4seuchvtmus06tuqmpv4awvv7m7'
|
||||||
it('should handle minting batons', async () => {
|
|
||||||
const addr = 'simpleledger:qrm0c67wwqh0w7wjxua2gdt2xggnm90xwsr5k22euj'
|
|
||||||
|
|
||||||
const result = await bchjs.Utxo.get(addr)
|
const result = await bchjs.Utxo.get(addr)
|
||||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
@@ -105,13 +105,82 @@ describe('#UTXO', () => {
|
|||||||
assert.equal(result.slpUtxos.type1.tokens.length, 0)
|
assert.equal(result.slpUtxos.type1.tokens.length, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle Group NFTs', async () => {
|
it('should filter Group tokens and mint batons', async () => {
|
||||||
const addr = 'bitcoincash:qrnghwrfgccf3s5e9wnglzxegcnhje9rkcwv2eka33'
|
const addr = 'bitcoincash:qrp4mlmsrtwlvjn4seuchvtmus06tuqmpvex9he79q'
|
||||||
|
|
||||||
const result = await bchjs.Utxo.get(addr)
|
const result = await bchjs.Utxo.get(addr)
|
||||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
assert.equal(result.nullUtxos.length, 0)
|
assert.isAbove(result.slpUtxos.group.tokens.length, 0)
|
||||||
|
assert.isAbove(result.slpUtxos.group.mintBatons.length, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should filter NFTs', async () => {
|
||||||
|
const addr = 'bitcoincash:qrp4mlmsrtwlvjn4seuchvtmus06tuqmpvex9he79q'
|
||||||
|
|
||||||
|
const result = await bchjs.Utxo.get(addr)
|
||||||
|
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||||
|
|
||||||
|
assert.isAbove(result.slpUtxos.nft.tokens.length, 0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#isValid', () => {
|
||||||
|
it('should return true for valid UTXO with fullnode properties', async () => {
|
||||||
|
const utxo = {
|
||||||
|
txid: '260d4fb4006a330660c805327c840d569d7547b7e3e9659fb423b3a041c2e254',
|
||||||
|
vout: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await bchjs.Utxo.isValid(utxo)
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.equal(result, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return true for valid UTXO with fulcrum properties', async () => {
|
||||||
|
const utxo = {
|
||||||
|
tx_hash: '260d4fb4006a330660c805327c840d569d7547b7e3e9659fb423b3a041c2e254',
|
||||||
|
tx_pos: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await bchjs.Utxo.isValid(utxo)
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.equal(result, true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return true for valid UTXO with fullnode properties', async () => {
|
||||||
|
const utxo = {
|
||||||
|
txid: '17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a',
|
||||||
|
vout: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await bchjs.Utxo.isValid(utxo)
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.equal(result, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return true for valid UTXO with fulcrum properties', async () => {
|
||||||
|
const utxo = {
|
||||||
|
tx_hash: '17754221b29f189532d4fc2ae89fb467ad2dede30fdec4854eb2129b3ba90d7a',
|
||||||
|
tx_pos: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await bchjs.Utxo.isValid(utxo)
|
||||||
|
// console.log('result: ', result
|
||||||
|
|
||||||
|
assert.equal(result, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should process output of Utxo.get()', async () => {
|
||||||
|
const utxo = await bchjs.Utxo.get('bitcoincash:qqgahqa5zkknmhmvsc98jndpwn3r77gqgc02x03jce')
|
||||||
|
// console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
|
||||||
|
|
||||||
|
const result = await bchjs.Utxo.isValid(utxo.bchUtxos[0])
|
||||||
|
|
||||||
|
assert.equal(result, true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
+47
-4
@@ -1,12 +1,15 @@
|
|||||||
// Public npm libraries.
|
// Public npm libraries.
|
||||||
const assert = require('assert')
|
import assert from 'assert'
|
||||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
// import { assert } from 'chai'
|
||||||
|
import Bitcoin from '@psf/bitcoincashjs-lib'
|
||||||
|
|
||||||
// Mocks
|
// Mocks
|
||||||
const fixtures = require('./fixtures/address.json')
|
import { createRequire } from 'module'
|
||||||
|
|
||||||
// Unit under test (uut)
|
// Unit under test (uut)
|
||||||
const BCHJS = require('../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
const require = createRequire(import.meta.url)
|
||||||
|
const fixtures = require('./fixtures/address.json')
|
||||||
let bchjs
|
let bchjs
|
||||||
|
|
||||||
function flatten (arrays) {
|
function flatten (arrays) {
|
||||||
@@ -935,4 +938,44 @@ describe('#address.js', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('#toEcashAddress', () => {
|
||||||
|
it('should convert a BCH address to an eCash address', () => {
|
||||||
|
const cashAddr = 'bitcoincash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s7yw984vk'
|
||||||
|
|
||||||
|
const result = bchjs.Address.toEcashAddress(cashAddr)
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.equal(result, 'ecash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s8f6wu02p')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should convert a BCH address to an eCash address without a prefix', () => {
|
||||||
|
const cashAddr = 'bitcoincash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s7yw984vk'
|
||||||
|
|
||||||
|
const result = bchjs.Address.toEcashAddress(cashAddr, false)
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.equal(result, 'qr24z7q6s26d9wr078lr2pxsmxg22cyn9s8f6wu02p')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#toEtokenAddress', () => {
|
||||||
|
it('should convert a BCH address to an eToken address', () => {
|
||||||
|
const cashAddr = 'bitcoincash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s7yw984vk'
|
||||||
|
|
||||||
|
const result = bchjs.Address.toEtokenAddress(cashAddr)
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.equal(result, 'etoken:qr24z7q6s26d9wr078lr2pxsmxg22cyn9sfhnv2gwk')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should convert a BCH address to an eToken address without a prefix', () => {
|
||||||
|
const cashAddr = 'bitcoincash:qr24z7q6s26d9wr078lr2pxsmxg22cyn9s7yw984vk'
|
||||||
|
|
||||||
|
const result = bchjs.Address.toEtokenAddress(cashAddr, false)
|
||||||
|
// console.log('result: ', result)
|
||||||
|
|
||||||
|
assert.equal(result, 'qr24z7q6s26d9wr078lr2pxsmxg22cyn9sfhnv2gwk')
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+35
-25
@@ -1,11 +1,13 @@
|
|||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('assert')
|
import assert from 'assert'
|
||||||
|
|
||||||
// Mocks
|
// Mocks
|
||||||
const fixtures = require('./fixtures/bitcoincash.json')
|
import { createRequire } from 'module'
|
||||||
|
|
||||||
// Unit under test (uut)
|
// Unit under test (uut)
|
||||||
const BCHJS = require('../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
const require = createRequire(import.meta.url)
|
||||||
|
const fixtures = require('./fixtures/bitcoincash.json')
|
||||||
// const bchjs = new BCHJS()
|
// const bchjs = new BCHJS()
|
||||||
let bchjs
|
let bchjs
|
||||||
|
|
||||||
@@ -264,10 +266,15 @@ describe('#BitcoinCash', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#bip38', () => {
|
describe('#bip38', function () {
|
||||||
|
// Increase timeout for BIP38 tests as they use CPU-intensive scrypt operations
|
||||||
|
// Each encrypt/decrypt operation takes ~5-6 seconds in Node.js v22
|
||||||
|
this.timeout(60000)
|
||||||
|
|
||||||
describe('#encryptBIP38', () => {
|
describe('#encryptBIP38', () => {
|
||||||
fixtures.bip38.encrypt.mainnet.forEach(fixture => {
|
fixtures.bip38.encrypt.mainnet.forEach(fixture => {
|
||||||
it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on mainnet`, () => {
|
it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on mainnet`, function () {
|
||||||
|
this.timeout(60000)
|
||||||
const encryptedKey = bchjs.BitcoinCash.encryptBIP38(
|
const encryptedKey = bchjs.BitcoinCash.encryptBIP38(
|
||||||
fixture.wif,
|
fixture.wif,
|
||||||
fixture.password
|
fixture.password
|
||||||
@@ -276,20 +283,22 @@ describe('#BitcoinCash', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
fixtures.bip38.encrypt.testnet.forEach(fixture => {
|
// fixtures.bip38.encrypt.testnet.forEach(fixture => {
|
||||||
it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on testnet`, () => {
|
// it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on testnet`, function () {
|
||||||
const encryptedKey = bchjs.BitcoinCash.encryptBIP38(
|
// this.timeout(60000)
|
||||||
fixture.wif,
|
// const encryptedKey = bchjs.BitcoinCash.encryptBIP38(
|
||||||
fixture.password
|
// fixture.wif,
|
||||||
)
|
// fixture.password
|
||||||
assert.equal(encryptedKey, fixture.encryptedKey)
|
// )
|
||||||
})
|
// assert.equal(encryptedKey, fixture.encryptedKey)
|
||||||
})
|
// })
|
||||||
|
// })
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('#decryptBIP38', () => {
|
describe('#decryptBIP38', () => {
|
||||||
fixtures.bip38.decrypt.mainnet.forEach(fixture => {
|
fixtures.bip38.decrypt.mainnet.forEach(fixture => {
|
||||||
it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on mainnet`, () => {
|
it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on mainnet`, function () {
|
||||||
|
this.timeout(60000)
|
||||||
const wif = bchjs.BitcoinCash.decryptBIP38(
|
const wif = bchjs.BitcoinCash.decryptBIP38(
|
||||||
fixture.encryptedKey,
|
fixture.encryptedKey,
|
||||||
fixture.password,
|
fixture.password,
|
||||||
@@ -299,16 +308,17 @@ describe('#BitcoinCash', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
fixtures.bip38.decrypt.testnet.forEach(fixture => {
|
// fixtures.bip38.decrypt.testnet.forEach(fixture => {
|
||||||
it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on testnet`, () => {
|
// it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on testnet`, function () {
|
||||||
const wif = bchjs.BitcoinCash.decryptBIP38(
|
// this.timeout(60000)
|
||||||
fixture.encryptedKey,
|
// const wif = bchjs.BitcoinCash.decryptBIP38(
|
||||||
fixture.password,
|
// fixture.encryptedKey,
|
||||||
'testnet'
|
// fixture.password,
|
||||||
)
|
// 'testnet'
|
||||||
assert.equal(wif, fixture.wif)
|
// )
|
||||||
})
|
// assert.equal(wif, fixture.wif)
|
||||||
})
|
// })
|
||||||
|
// })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+24
-23
@@ -1,11 +1,12 @@
|
|||||||
const assert = require('assert')
|
import assert from 'assert'
|
||||||
const assert2 = require('chai').assert
|
import chai from 'chai'
|
||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
const BCHJS = require('../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
const bchjs = new BCHJS()
|
import sinon from 'sinon'
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
const mockData = require('./fixtures/blockchain-mock')
|
import mockData from './fixtures/blockchain-mock.js'
|
||||||
|
const { assert: assert2 } = chai
|
||||||
|
const bchjs = new BCHJS()
|
||||||
|
|
||||||
describe('#Blockchain', () => {
|
describe('#Blockchain', () => {
|
||||||
describe('#getBestBlockHash', () => {
|
describe('#getBestBlockHash', () => {
|
||||||
@@ -60,7 +61,7 @@ describe('#Blockchain', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('should get block by hash', done => {
|
it('should get block by hash', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'post').returns(resolved)
|
sandbox.stub(axios, 'post').returns(resolved)
|
||||||
|
|
||||||
const blockhash =
|
const blockhash =
|
||||||
@@ -92,7 +93,7 @@ describe('#Blockchain', () => {
|
|||||||
await bchjs.Blockchain.getBlock(blockhash)
|
await bchjs.Blockchain.getBlock(blockhash)
|
||||||
assert2.fail('Unexpected result')
|
assert2.fail('Unexpected result')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
assert2.include(err, 'Test Error')
|
assert2.include(err.message, 'Test Error')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -129,7 +130,7 @@ describe('#Blockchain', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('should get blockchain info', done => {
|
it('should get blockchain info', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.getBlockchainInfo()
|
bchjs.Blockchain.getBlockchainInfo()
|
||||||
@@ -147,7 +148,7 @@ describe('#Blockchain', () => {
|
|||||||
const data = 527810
|
const data = 527810
|
||||||
|
|
||||||
it('should get block count', done => {
|
it('should get block count', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.getBlockCount()
|
bchjs.Blockchain.getBlockCount()
|
||||||
@@ -166,7 +167,7 @@ describe('#Blockchain', () => {
|
|||||||
'000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0'
|
'000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0'
|
||||||
|
|
||||||
it('should get block hash by height', done => {
|
it('should get block hash by height', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.getBlockHash(527810)
|
bchjs.Blockchain.getBlockHash(527810)
|
||||||
@@ -201,7 +202,7 @@ describe('#Blockchain', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('should get block header by hash', done => {
|
it('should get block header by hash', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.getBlockHeader(
|
bchjs.Blockchain.getBlockHeader(
|
||||||
@@ -222,7 +223,7 @@ describe('#Blockchain', () => {
|
|||||||
const data = '577528469277.1339'
|
const data = '577528469277.1339'
|
||||||
|
|
||||||
it('should get difficulty', done => {
|
it('should get difficulty', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.getDifficulty()
|
bchjs.Blockchain.getDifficulty()
|
||||||
@@ -240,7 +241,7 @@ describe('#Blockchain', () => {
|
|||||||
const data = 'Transaction not in mempool'
|
const data = 'Transaction not in mempool'
|
||||||
|
|
||||||
it('should get mempool ancestors', done => {
|
it('should get mempool ancestors', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.getMempoolAncestors(
|
bchjs.Blockchain.getMempoolAncestors(
|
||||||
@@ -263,7 +264,7 @@ describe('#Blockchain', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('should get mempool descendants', done => {
|
it('should get mempool descendants', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.getMempoolDescendants(
|
bchjs.Blockchain.getMempoolDescendants(
|
||||||
@@ -286,7 +287,7 @@ describe('#Blockchain', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('should get mempool entry', done => {
|
it('should get mempool entry', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.getMempoolEntry(
|
bchjs.Blockchain.getMempoolEntry(
|
||||||
@@ -314,7 +315,7 @@ describe('#Blockchain', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('should get mempool info', done => {
|
it('should get mempool info', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.getMempoolInfo()
|
bchjs.Blockchain.getMempoolInfo()
|
||||||
@@ -355,7 +356,7 @@ describe('#Blockchain', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('should get mempool info', done => {
|
it('should get mempool info', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.getRawMempool()
|
bchjs.Blockchain.getRawMempool()
|
||||||
@@ -451,7 +452,7 @@ describe('#Blockchain', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('should get TODO', done => {
|
it('should get TODO', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.preciousBlock()
|
bchjs.Blockchain.preciousBlock()
|
||||||
@@ -469,7 +470,7 @@ describe('#Blockchain', () => {
|
|||||||
const data = 'Cannot prune blocks because node is not in prune mode.'
|
const data = 'Cannot prune blocks because node is not in prune mode.'
|
||||||
|
|
||||||
it('should prune blockchain', done => {
|
it('should prune blockchain', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'post').returns(resolved)
|
sandbox.stub(axios, 'post').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.pruneBlockchain(507)
|
bchjs.Blockchain.pruneBlockchain(507)
|
||||||
@@ -487,7 +488,7 @@ describe('#Blockchain', () => {
|
|||||||
const data = true
|
const data = true
|
||||||
|
|
||||||
it('should verify blockchain', done => {
|
it('should verify blockchain', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.verifyChain(3, 6)
|
bchjs.Blockchain.verifyChain(3, 6)
|
||||||
@@ -505,7 +506,7 @@ describe('#Blockchain', () => {
|
|||||||
const data = "proof must be hexadecimal string (not '')"
|
const data = "proof must be hexadecimal string (not '')"
|
||||||
|
|
||||||
it('should verify utxo proof', done => {
|
it('should verify utxo proof', done => {
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Blockchain.verifyTxOutProof('3')
|
bchjs.Blockchain.verifyTxOutProof('3')
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
const assert = require('assert')
|
import assert from 'assert'
|
||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
const BCHJS = require('../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
import sinon from 'sinon'
|
||||||
const bchjs = new BCHJS()
|
const bchjs = new BCHJS()
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
describe('#Control', () => {
|
describe('#Control', () => {
|
||||||
let sandbox
|
let sandbox
|
||||||
@@ -24,7 +24,7 @@ describe('#Control', () => {
|
|||||||
relayfee: 0.00001,
|
relayfee: 0.00001,
|
||||||
errors: ''
|
errors: ''
|
||||||
}
|
}
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Control.getNetworkInfo()
|
bchjs.Control.getNetworkInfo()
|
||||||
@@ -47,7 +47,7 @@ describe('#Control', () => {
|
|||||||
chunks_free: 1
|
chunks_free: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'get').returns(resolved)
|
sandbox.stub(axios, 'get').returns(resolved)
|
||||||
|
|
||||||
bchjs.Control.getMemoryInfo()
|
bchjs.Control.getMemoryInfo()
|
||||||
|
|||||||
+5
-3
@@ -1,8 +1,10 @@
|
|||||||
|
import { createRequire } from 'module'
|
||||||
|
import assert from 'assert'
|
||||||
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
import { Buffer } from 'safe-buffer'
|
||||||
|
const require = createRequire(import.meta.url)
|
||||||
const fixtures = require('./fixtures/crypto.json')
|
const fixtures = require('./fixtures/crypto.json')
|
||||||
const assert = require('assert')
|
|
||||||
const BCHJS = require('../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS()
|
const bchjs = new BCHJS()
|
||||||
const Buffer = require('safe-buffer').Buffer
|
|
||||||
|
|
||||||
describe('#Crypto', () => {
|
describe('#Crypto', () => {
|
||||||
describe('#sha256', () => {
|
describe('#sha256', () => {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('chai').assert
|
import chai from 'chai'
|
||||||
const sinon = require('sinon')
|
import sinon from 'sinon'
|
||||||
|
|
||||||
// Unit under test (uut)
|
// Unit under test (uut)
|
||||||
const BCHJS = require('../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
const mockData = require('./fixtures/dsproof-mock')
|
import mockData from './fixtures/dsproof-mock.js'
|
||||||
|
const { assert } = chai
|
||||||
|
|
||||||
let bchjs
|
let bchjs
|
||||||
const txid = 'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'
|
const txid = 'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'
|
||||||
|
|||||||
+3
-2
@@ -3,8 +3,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Global npm libraries
|
// Global npm libraries
|
||||||
const assert = require('chai').assert
|
import chai from 'chai'
|
||||||
const Ecash = require('../../src/ecash')
|
import Ecash from '../../src/ecash.js'
|
||||||
|
const { assert } = chai
|
||||||
const uut = new Ecash()
|
const uut = new Ecash()
|
||||||
|
|
||||||
describe('#eCash', () => {
|
describe('#eCash', () => {
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
// Public npm libraries.
|
// Public npm libraries.
|
||||||
const assert = require('assert')
|
import assert from 'assert'
|
||||||
const Buffer = require('safe-buffer').Buffer
|
import { Buffer } from 'safe-buffer'
|
||||||
|
|
||||||
// Mocks
|
// Mocks
|
||||||
const fixtures = require('./fixtures/ecpair.json')
|
import { createRequire } from 'module'
|
||||||
|
|
||||||
// Unit under test (uut)
|
// Unit under test (uut)
|
||||||
const BCHJS = require('../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
const require = createRequire(import.meta.url)
|
||||||
|
const fixtures = require('./fixtures/ecpair.json')
|
||||||
// const bchjs = new BCHJS()
|
// const bchjs = new BCHJS()
|
||||||
let bchjs
|
let bchjs
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
const chai = require('chai')
|
import chai from 'chai'
|
||||||
|
import axios from 'axios'
|
||||||
|
import sinon from 'sinon'
|
||||||
|
|
||||||
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
|
||||||
|
import mockData from './fixtures/electrumx-mock.js'
|
||||||
const assert = chai.assert
|
const assert = chai.assert
|
||||||
const axios = require('axios')
|
|
||||||
const sinon = require('sinon')
|
|
||||||
|
|
||||||
const BCHJS = require('../../src/bch-js')
|
|
||||||
const bchjs = new BCHJS()
|
const bchjs = new BCHJS()
|
||||||
|
|
||||||
const mockData = require('./fixtures/electrumx-mock')
|
|
||||||
|
|
||||||
describe('#ElectrumX', () => {
|
describe('#ElectrumX', () => {
|
||||||
let sandbox
|
let sandbox
|
||||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
const assert = require('chai').assert
|
import chai from 'chai'
|
||||||
const sinon = require('sinon')
|
import sinon from 'sinon'
|
||||||
|
|
||||||
const BCHJS = require('../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
|
|
||||||
|
import mockData from './fixtures/encryption-mock.js'
|
||||||
|
const { assert } = chai
|
||||||
// const bchjs = new BCHJS()
|
// const bchjs = new BCHJS()
|
||||||
let bchjs
|
let bchjs
|
||||||
|
|
||||||
const mockData = require('./fixtures/encryption-mock')
|
|
||||||
|
|
||||||
describe('#Encryption', () => {
|
describe('#Encryption', () => {
|
||||||
let sandbox
|
let sandbox
|
||||||
|
|
||||||
|
|||||||
@@ -406,11 +406,6 @@
|
|||||||
"wif": "L1XHKhaBAfkr2FJQn3pTfCMxz652WYfmvKj8xDCHCEDV9tWGcbYj",
|
"wif": "L1XHKhaBAfkr2FJQn3pTfCMxz652WYfmvKj8xDCHCEDV9tWGcbYj",
|
||||||
"password": "1EBPIyj55eR8bVUov9",
|
"password": "1EBPIyj55eR8bVUov9",
|
||||||
"encryptedKey": "6PYWWnBNfNpSqEJZKcfwbrYgTTdb9PNiGjQJ8r9V6cvsZNKLfcZD8YefQc"
|
"encryptedKey": "6PYWWnBNfNpSqEJZKcfwbrYgTTdb9PNiGjQJ8r9V6cvsZNKLfcZD8YefQc"
|
||||||
},
|
|
||||||
{
|
|
||||||
"wif": "L1phBREbhL4vb1uHHHCAse8bdGE5c7ic2PFjRxMawLzQCsiFVbvu",
|
|
||||||
"password": "9GKVkabAHBMyAf",
|
|
||||||
"encryptedKey": "6PYU2fDHRVF2194gKDGkbFbeu4mFgkWtVvg2RPd2Sp6KmZx3RCHFpgBB2G"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"testnet": [
|
"testnet": [
|
||||||
@@ -432,11 +427,6 @@
|
|||||||
"wif": "L1XHKhaBAfkr2FJQn3pTfCMxz652WYfmvKj8xDCHCEDV9tWGcbYj",
|
"wif": "L1XHKhaBAfkr2FJQn3pTfCMxz652WYfmvKj8xDCHCEDV9tWGcbYj",
|
||||||
"password": "1EBPIyj55eR8bVUov9",
|
"password": "1EBPIyj55eR8bVUov9",
|
||||||
"encryptedKey": "6PYWWnBNfNpSqEJZKcfwbrYgTTdb9PNiGjQJ8r9V6cvsZNKLfcZD8YefQc"
|
"encryptedKey": "6PYWWnBNfNpSqEJZKcfwbrYgTTdb9PNiGjQJ8r9V6cvsZNKLfcZD8YefQc"
|
||||||
},
|
|
||||||
{
|
|
||||||
"wif": "L1phBREbhL4vb1uHHHCAse8bdGE5c7ic2PFjRxMawLzQCsiFVbvu",
|
|
||||||
"password": "9GKVkabAHBMyAf",
|
|
||||||
"encryptedKey": "6PYU2fDHRVF2194gKDGkbFbeu4mFgkWtVvg2RPd2Sp6KmZx3RCHFpgBB2G"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"testnet": [
|
"testnet": [
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ const utxo = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
balance,
|
balance,
|
||||||
utxo
|
utxo
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Mock data used for unit testing.
|
Mock data used for unit testing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
details: {
|
details: {
|
||||||
hash: '000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0',
|
hash: '000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0',
|
||||||
size: 216,
|
size: 216,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Mock data used for unit testing.
|
Mock data used for unit testing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
bestBlockHash:
|
bestBlockHash:
|
||||||
'0000000000000000008e1f65f875703872544aa888c7ca6587f055f8f5fbd4bf',
|
'0000000000000000008e1f65f875703872544aa888c7ca6587f055f8f5fbd4bf',
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ const dsproof = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
dsproof
|
dsproof
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ const txHistoryWithUnconfirmed = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
utxo,
|
utxo,
|
||||||
utxos,
|
utxos,
|
||||||
balance,
|
balance,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const failureMock = {
|
|||||||
publicKey: 'not found'
|
publicKey: 'not found'
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
successMock,
|
successMock,
|
||||||
failureMock
|
failureMock
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ const paidFileData = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
uploadData,
|
uploadData,
|
||||||
paymentInfo,
|
paymentInfo,
|
||||||
mockNewFileModel,
|
mockNewFileModel,
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ const tx = {
|
|||||||
'0200000001ac1e2e38764f9b81f3ff4317b4bd1a381dbdf311277a736f375d4ce217d3095f010000006a473044022000dd11c41a472f2e54348db996e60864d489429f12d1e044d49ff600b880c9590220715a926404bb0e2731a3795afb341ec1dad3f84ead7d27cd31fcc59abb14738c4121038476128287ac37c7a3cf7e8625fd5f024db1bc3d8e37395abe7bf42fda78d0d9ffffffff02e8030000000000001976a9142fe2c4c5ef359bb2fe1a849f891cecffbcfb4f7788acb0b40000000000001976a9142dbf5e1804c39a497b908c876097d63210c8490288ac00000000'
|
'0200000001ac1e2e38764f9b81f3ff4317b4bd1a381dbdf311277a736f375d4ce217d3095f010000006a473044022000dd11c41a472f2e54348db996e60864d489429f12d1e044d49ff600b880c9590220715a926404bb0e2731a3795afb341ec1dad3f84ead7d27cd31fcc59abb14738c4121038476128287ac37c7a3cf7e8625fd5f024db1bc3d8e37395abe7bf42fda78d0d9ffffffff02e8030000000000001976a9142fe2c4c5ef359bb2fe1a849f891cecffbcfb4f7788acb0b40000000000001976a9142dbf5e1804c39a497b908c876097d63210c8490288ac00000000'
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
balance,
|
balance,
|
||||||
utxo,
|
utxo,
|
||||||
tx
|
tx
|
||||||
|
|||||||
@@ -209,6 +209,6 @@ const mockRates = {
|
|||||||
ZWL: '80215.03'
|
ZWL: '80215.03'
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
mockRates
|
mockRates
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,10 +144,71 @@ const tokenData01 = {
|
|||||||
qty: {}
|
qty: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
const tokenData = {
|
||||||
|
genesisData: tokenStats.tokenData,
|
||||||
|
immutableData: 'ipfs://bafybeidzfi3sictag4noy746gniyiwwcgio565xuzelmjfwxnga6qyiyai',
|
||||||
|
mutableData: 'ipfs://bafybeie6t5uyupddc7azms737xg4hxrj7i5t5ov3lb5g2qeehaujj6ak64'
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenMedia01 = {
|
||||||
|
tokenStats: {
|
||||||
|
type: 65,
|
||||||
|
ticker: 'TEST02',
|
||||||
|
name: 'How to Send BCH and Tokens',
|
||||||
|
tokenId: 'd9aafa7acb514c597caf440ae268b5e4e955f2687e05f044cdf8fd9550d9a27b',
|
||||||
|
documentUri: 'ipfs://bafybeigjujbb55wqr5lns7z7vleg5cfp4yjwqp4swisxpgxl4xsp5tngai',
|
||||||
|
documentHash: '845f803d8dd3c2b6be94a6cf3a445b54c36f2e01bd5c9ab4c23f37dbd531489e',
|
||||||
|
decimals: 0,
|
||||||
|
mintBatonIsActive: false,
|
||||||
|
tokensInCirculationBN: '0',
|
||||||
|
tokensInCirculationStr: '0',
|
||||||
|
blockCreated: 740089,
|
||||||
|
totalBurned: '1',
|
||||||
|
totalMinted: '1',
|
||||||
|
parentGroupId: 'c9c425f2c6352697c6665a53e035cbad8a44c4b1e36491a1838dc4655479aa09'
|
||||||
|
},
|
||||||
|
mutableData: {
|
||||||
|
updated: '2022-05-14T15:27:44.429Z',
|
||||||
|
tokenIcon: 'https://bafybeiefg3nd5iognbqztkpi5hj34dmwkqfe7v7xeayn2nhhatinmjmzcy.ipfs.dweb.link/send-bch-token-icon.png',
|
||||||
|
tokenInfo: 'https://token.fullstack.cash/?tokenid=d9aafa7acb514c597caf440ae268b5e4e955f2687e05f044cdf8fd9550d9a27b',
|
||||||
|
description: 'This is an NFT representing a video. This is a test token.',
|
||||||
|
issuer: 'Chris Troutner',
|
||||||
|
forSale: false,
|
||||||
|
display: true,
|
||||||
|
currentOwner: {
|
||||||
|
bchAddr: 'bitcoincash:qqy7jcrm3vmtqs96r878hy2kx90mn84f25ujqw9z5h',
|
||||||
|
name: 'Chris Troutner',
|
||||||
|
contactEmail: 'chris.troutner@gmail.com'
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
youtube: 'https://youtu.be/WZRwkLPtkaI',
|
||||||
|
rumble: 'https://rumble.com/v14n00h-how-to-send-bch-and-tokens.html',
|
||||||
|
odysee: 'https://odysee.com/@trout:5/how-to-send-bch-tokens:0',
|
||||||
|
lbry: 'lbry://@trout#5/how-to-send-bch-tokens#0',
|
||||||
|
ipfs: 'bafybeigf3ky5i6fyxwk5bjmtsr6urqmlx4zq2lqathgguytey67iinh4be',
|
||||||
|
filecoin: 'https://bafybeigf3ky5i6fyxwk5bjmtsr6urqmlx4zq2lqathgguytey67iinh4be.ipfs.dweb.link/send-bch-2022-02-20_08.22.45.mp4'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immutableData: {
|
||||||
|
creationDate: '2022-05-13T21:32:11.619Z',
|
||||||
|
issuer: 'Chris Troutner',
|
||||||
|
license: 'https://bafybeidnkhjfsbihp4gquwqrs6y35jfpcriafymceszwvkundjkwk546pi.ipfs.dweb.link/copyright.txt',
|
||||||
|
name: 'How to Send BCH and Tokens'
|
||||||
|
},
|
||||||
|
tokenIcon: 'https://bafybeiefg3nd5iognbqztkpi5hj34dmwkqfe7v7xeayn2nhhatinmjmzcy.ipfs.dweb.link/send-bch-token-icon.png',
|
||||||
|
fullSizedUrl: '',
|
||||||
|
optimizedTokenIcon: 'https://p2wdb-gateway-678.fullstack.cash/ipfs/bafybeiefg3nd5iognbqztkpi5hj34dmwkqfe7v7xeayn2nhhatinmjmzcy/send-bch-token-icon.png',
|
||||||
|
optimizedFullSizedUrl: '',
|
||||||
|
iconRepoCompatible: false,
|
||||||
|
ps002Compatible: true
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
tokenStats,
|
tokenStats,
|
||||||
txData,
|
txData,
|
||||||
balance,
|
balance,
|
||||||
status,
|
status,
|
||||||
tokenData01
|
tokenData01,
|
||||||
|
tokenData,
|
||||||
|
tokenMedia01
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ const mockGetInputAddrsOutput = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
mockTx,
|
mockTx,
|
||||||
mockParentTx1,
|
mockParentTx1,
|
||||||
mockGetInputAddrsOutput
|
mockGetInputAddrsOutput
|
||||||
|
|||||||
@@ -1411,7 +1411,7 @@ mock503Error.response = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
mockList,
|
mockList,
|
||||||
mockToken,
|
mockToken,
|
||||||
mockTokens,
|
mockTokens,
|
||||||
|
|||||||
@@ -769,7 +769,7 @@ const genesisTestOpReturn03 = {
|
|||||||
qty: '100000000000000000'
|
qty: '100000000000000000'
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
nonSlpTxDetails,
|
nonSlpTxDetails,
|
||||||
slpTxDetails,
|
slpTxDetails,
|
||||||
mockOpReturnData01,
|
mockOpReturnData01,
|
||||||
|
|||||||
@@ -476,7 +476,7 @@ const noUtxoErr = {
|
|||||||
'Key not found in database [bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7]'
|
'Key not found in database [bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7]'
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export default {
|
||||||
mockUtxoData,
|
mockUtxoData,
|
||||||
mockHydratedUtxos,
|
mockHydratedUtxos,
|
||||||
mockTwoHydratedAddrs,
|
mockTwoHydratedAddrs,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// Public npm libraries
|
// Public npm libraries
|
||||||
const assert = require('assert')
|
import assert from 'assert'
|
||||||
const axios = require('axios')
|
import axios from 'axios'
|
||||||
const sinon = require('sinon')
|
import sinon from 'sinon'
|
||||||
|
|
||||||
// Unit under test (uut)
|
// Unit under test (uut)
|
||||||
const BCHJS = require('../../src/bch-js')
|
import BCHJS from '../../src/bch-js.js'
|
||||||
// const bchjs = new BCHJS()
|
// const bchjs = new BCHJS()
|
||||||
let bchjs
|
let bchjs
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ describe('#Generating', () => {
|
|||||||
|
|
||||||
it('should generate', done => {
|
it('should generate', done => {
|
||||||
const data = []
|
const data = []
|
||||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
const resolved = new Promise(resolve => resolve({ data }))
|
||||||
sandbox.stub(axios, 'post').returns(resolved)
|
sandbox.stub(axios, 'post').returns(resolved)
|
||||||
|
|
||||||
bchjs.Generating.generateToAddress(
|
bchjs.Generating.generateToAddress(
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user