Compare commits

...
52 Commits
Author SHA1 Message Date
Chris Troutner 7f08789c6a Updating to major version 7 2025-11-25 16:57:48 -08:00
Chris Troutner 63dcddb3ab Fixing unit tests 2025-11-25 16:54:26 -08:00
Chris Troutner c2f150bf81 fix(deps): Updating dependencies 2025-11-25 16:40:38 -08:00
Chris Troutner 889ffcfe1d integration test 2025-11-25 16:36:10 -08:00
Chris Troutner 26a6175889 Got x402 integration tests working 2025-11-25 13:27:13 -08:00
Chris Troutner 07de91afa2 feat(BCHJSWIF): Env var lets user pass WIF private key as env var 2025-11-25 12:09:46 -08:00
Chris Troutner 246da25f91 Added x402 support 2025-11-25 10:59:30 -08:00
Chris Troutner f24d36ccee feat(auth): Added Bearer basic auth, removed other auth patterns 2025-11-25 08:46:18 -08:00
Chris Troutner f80cce96b1 Adjusting package.json scripts 2025-11-25 08:31:11 -08:00
Chris Troutner 1c6939ab43 fix(integration tests): Only supporting BCH, all tests in one directory 2025-11-23 10:30:23 -08:00
Chris Troutner bcb236a66b Fixed last integration test 2025-11-17 10:42:37 -08:00
Chris Troutner b66ff3cb59 fixing unit tests 2025-11-17 10:36:14 -08:00
Chris Troutner 2dad11180b feat(util): Removing util.validateAddress functions 2025-11-17 10:28:27 -08:00
Chris Troutner 22e13ef654 fix(dsproof): Fixed integration test 2025-11-17 10:20:55 -08:00
Chris Troutner 4dabdac792 fix(price): Refactored price and integration tests 2025-11-17 10:13:53 -08:00
Chris Troutner 857b57240e Adding new fulcrum test 2025-11-17 07:45:52 -08:00
Chris Troutner 7b9aba3738 fixed broken fulcrum test 2025-11-17 07:44:30 -08:00
Chris Troutner 2c49af2de3 feat(psf-bch-api): Using psf-bch-api instead of legacy bch-api 2025-11-17 07:37:21 -08:00
Chris Troutner 3c0590ba23 Removing XEC and Testnet integration tests 2025-11-17 07:24:47 -08:00
Chris Troutner b20a034bc9 fix(apidoc): Fixing contrast in api docs 2025-11-16 19:40:15 -08:00
Chris Troutner 12e5143d9a fix(lint): Fixing linting issue 2025-11-16 13:47:24 -08:00
Chris Troutner 8e3fa6dcf1 feat(ESM): Converted code base to ESM format, away from CommonJS 2025-11-16 13:37:04 -08:00
Chris Troutner 76442208a2 Removing unneeded dev dependency 2025-11-16 12:00:44 -08:00
Chris Troutner 2cf8905852 Removing more unnecessary dev dependencies 2025-11-16 11:53:25 -08:00
Chris Troutner d134aff9f4 Removing unneeded dev dependency 2025-11-16 11:47:29 -08:00
Chris Troutner 005b628301 Updating more dependencies 2025-11-16 11:44:45 -08:00
Chris Troutner f3c2168435 Updating more dependencies 2025-11-16 11:38:56 -08:00
Chris Troutner 71b8bb089d Updated more dependencies 2025-11-16 11:34:26 -08:00
Chris Troutner 2333229e54 Upgraded some npm dependencies 2025-11-16 10:55:44 -08:00
Chris Troutner 13c69593b2 Merge pull request #271 from Permissionless-Software-Foundation/ct-unstable
fix(llm): Adding LLM summary of library
2025-11-06 08:54:19 -08:00
Chris Troutner 8316c4eabb fix(llm): Adding LLM summary of library 2025-11-06 08:52:32 -08:00
Chris Troutner 30cf010e80 Merge pull request #270 from Permissionless-Software-Foundation/ct-unstable
fix(axios): Updating axios
2025-10-07 17:42:39 -07:00
Chris Troutner f28eeea5b0 fix(axios): Updating axios 2025-10-07 17:41:12 -07:00
Chris Troutner 9758eb9995 Merge pull request #269 from Permissionless-Software-Foundation/ct-unstable
fix(utxo.get()): Handling corner-case when SLP indexer is not returni…
2025-06-29 14:38:18 -07:00
Chris Troutner 4260a74d91 fix(utxo.get()): Handling corner-case when SLP indexer is not returning data 2025-06-29 14:36:44 -07:00
Chris Troutner 01625abb37 Merge pull request #267 from Permissionless-Software-Foundation/ct-unstable
feat(getPsffppPrice): New endpoint to get PSFFPP pin price
2024-09-03 19:29:59 -07:00
Chris Troutner b34040cd08 feat(getPsffppPrice): New endpoint to get PSFFPP pin price 2024-09-03 19:28:22 -07:00
Chris Troutner 01a4d0f1aa Adding integration-test-pearson.sh to gitignore 2023-06-02 15:03:25 -07:00
Chris Troutner 7c7c6395e1 Merge pull request #265 from Permissionless-Software-Foundation/ct-unstable
fix(nft): Removing NFT parent and child functions from SLPDB that hav…
2023-06-02 06:27:00 -07:00
Chris Troutner 3408a8fd3b fix(nft): Removing NFT parent and child functions from SLPDB that have been replaced with psf-slp-indexer 2023-06-02 06:24:57 -07:00
Chris Troutner 86a1cadfac Merge pull request #264 from Permissionless-Software-Foundation/ct-unstable
fix(Utxo.get()): Updating documentation
2023-04-09 05:57:08 -07:00
Chris Troutner 7000a83a37 fix(Utxo.get()): Updating documentation 2023-04-09 05:54:22 -07:00
Chris Troutner b331450473 Merge pull request #263 from Permissionless-Software-Foundation/ct-unstable
fix(getPubKey): Debugging errors with getPubKey()
2023-04-08 12:20:32 -07:00
Chris Troutner af7c8ffa6d fix(getPubKey): Debugging errors with getPubKey() 2023-04-08 12:17:40 -07:00
Chris Troutner 2e04548ade Merge pull request #262 from Permissionless-Software-Foundation/ct-unstable
fix(tests): Fixing integration tests that broke with infoUtxo impleme…
2023-04-01 16:38:05 -07:00
Chris Troutner 412fa5e1ce fix(tests): Fixing integration tests that broke with infoUtxo implementation 2023-04-01 16:36:07 -07:00
Chris Troutner a08a4236d6 Merge pull request #261 from Permissionless-Software-Foundation/ct-unstable
feat(Utxo.get()): Creating infoUtxo category for utxos less than 1000…
2023-03-31 13:43:19 -07:00
Chris Troutner e700a22560 feat(Utxo.get()): Creating infoUtxo category for utxos less than 1000 sats 2023-03-31 13:41:37 -07:00
Chris Troutner 4573c63ca3 Merge pull request #260 from Permissionless-Software-Foundation/ct-unstable
fix(tests): Commenting out integration tests that fails due to 429 er…
2023-03-14 06:48:37 -07:00
Chris Troutner bd18e8a755 fix(tests): Commenting out integration tests that fails due to 429 errors 2023-03-14 06:28:50 -07:00
Chris Troutner cf8f48ffe1 Merge pull request #259 from Permissionless-Software-Foundation/ct-unstable
fix(tests): Commenting out integration tests that are commonly failing
2023-03-11 17:28:44 -08:00
Chris Troutner fc96b04a64 fix(tests): Commenting out integration tests that are commonly failing 2023-03-11 17:26:00 -08:00
115 changed files with 21382 additions and 20448 deletions
+1
View File
@@ -5,6 +5,7 @@ wallet.json
integration-test-sweet.sh
integration-test-ss.sh
integration-test-bitfinex.sh
integration-test-pearson.sh
docs/
coverage/
+10 -10
View File
@@ -5,7 +5,7 @@
[![License](https://img.shields.io/npm/l/@psf/bch-js)](https://github.com/Permissionless-Software-Foundation/bch-js/blob/master/LICENSE.md)
[![js-standard-style](https://img.shields.io/badge/javascript-standard%20code%20style-green.svg?style=flat-square)](https://github.com/feross/standard) [![Join the chat at https://gitter.im/Permissionless-Software-Foundation/bch-js](https://badges.gitter.im/Permissionless-Software-Foundation/bch-js.svg)](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) and eCash (XEC) blockchains. bch-js contains a toolbox of handy tools, and an easy API for talking with [bch-api REST API](https://github.com/Permissionless-Software-Foundation/bch-api). [FullStack.cash](https://fullstack.cash) offers paid cloud access to bch-api. You can run your own infrastructure by following documentation on [CashStack.info](https://cashstack.info).
[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) and eCash (XEC) blockchains. 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:
@@ -31,30 +31,30 @@ Here are two YouTube walk-through videos to help you get started:
- Instantiate the library in your code:
```
const BCHJS = require("@psf/bch-js")
```javascript
import BCHJS from "@psf/bch-js"
let bchjs = new BCHJS() // Defaults to BCHN network.
```
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/
- ABC Mainnet REST API server: https://abc.fullstack.cash/v5/
- BCHN Mainnet REST API server: https://bchn.fullstack.cash/v6/
- ABC Mainnet REST API server: https://abc.fullstack.cash/v6/
- Check server status: https://metrics.fullstack.cash
### API Key (JWT Token)
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
The [psf-bch-api](https://github.com/Permissionless-Software-Foundation/psf-bch-api) REST API hosted by [FullStack.cash](https://fullstack.cash) uses JWT tokens to pay for increased
rate limits when interacting with the back end server. See [this article](https://cashstack.info) if you want to understand the system-as-a-whole. The JWT token can be fed to bch-js _implicitly_ or _explicitly_.
- Implicitly: bch-js will detect your JWT token if you set the `BCHJSTOKEN` environment variable.
- Explicitly: You can directly feed in the JWT token with the `apiToken` property when instantiating the library. Here is an example:
```
const BCHJS = require("@psf/bch-js")
```javascript
import BCHJS from "@psf/bch-js"
let bchjs = new BCHJS({
restURL: 'https://bchn.fullstack.cash/v5/',
restURL: 'https://bchn.fullstack.cash/v6/',
apiToken: 'eyJhbGciO...' // Your JWT token here.
})
```
+38
View File
@@ -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"
+10451
View File
File diff suppressed because it is too large Load Diff
+9643 -17248
View File
File diff suppressed because it is too large Load Diff
+37 -46
View File
@@ -1,6 +1,7 @@
{
"name": "@psf/bch-js",
"version": "6.0.0",
"version": "7.0.0",
"type": "module",
"description": "A JavaScript library for working with Bitcoin Cash, eCash, and SLP Tokens",
"author": "Chris Troutner <chris.troutner@gmail.com>",
"contributors": [
@@ -9,25 +10,16 @@
],
"main": "src/bch-js",
"scripts": {
"test": "nyc mocha --trace-warnings --unhandled-rejections=strict --timeout 30000 test/unit/",
"test:integration": "npm run test:integration:bchn",
"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:abc": "export RESTURL=https://abc.fullstack.cash/v5/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/abc/",
"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: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:local:abc": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
"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:testnet": "RESTURL=http://localhost:4000/v5/ mocha --timeout 30000 test/integration/chains/testnet",
"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:abc": "export RESTURL=http://192.168.2.142:3000/v5/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
"test:integration:temp:bchn": "export RESTURL=http://157.90.174.219:3000/v5/ && mocha --timeout 30000 test/integration/",
"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",
"test": "c8 mocha --trace-warnings --unhandled-rejections=strict --timeout 30000 test/unit/",
"test:integration": "npm run test:integration:local:noauth",
"test:integration:nft": "export RESTURL=https://bchn.fullstack.cash/v6/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 -g '#nft1' test/integration/slp.js",
"test:integration:bchn": "export RESTURL=https://bchn.fullstack.cash/v6/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/",
"test:integration:local:noauth": "export RESTURL=http://localhost:5942/v6/ && mocha --timeout 30000 test/integration/",
"test:integration:local:auth": "export RESTURL=http://5.78.147.3:5942/v6/ && export BCHJSBEARERTOKEN=temp01 && mocha --timeout 30000 test/integration/",
"test:integration:decatur": "export RESTURL=http://192.168.2.127:5942/v6/ && mocha --timeout 30000 test/integration/",
"test:integration:x402": "export RESTURL=http://localhost:5942/v6/ && export BCHJSWIF=L1eYaneXDDXy8VDig4Arwe8wYHbhtsA5wuQvwsKwhaYeneoZuKG4 && mocha --timeout 30000 test/integration/",
"coverage": "nyc --reporter=html mocha --timeout 25000 test/unit/",
"docs": "./node_modules/.bin/apidoc -i src/ -o docs && ./fix-docs-contrast.sh",
"lint": "standard --env mocha --fix"
},
"license": "MIT",
@@ -42,45 +34,39 @@
"@psf/bitcoincash-ops": "2.0.0",
"@psf/bitcoincashjs-lib": "4.0.3",
"@psf/coininfo": "4.0.0",
"axios": "0.26.1",
"axios": "1.13.2",
"bc-bip68": "1.0.5",
"bchaddrjs-slp": "0.2.5",
"bchaddrjs-slp": "0.2.14",
"bigi": "1.4.2",
"bignumber.js": "9.0.0",
"bip-schnorr": "0.3.0",
"bip38": "2.0.2",
"bip39": "3.0.2",
"bignumber.js": "9.3.1",
"bip-schnorr": "0.6.7",
"bip38": "3.1.1",
"bip39": "3.1.0",
"bip66": "1.1.5",
"bitcoinjs-message": "2.0.0",
"bitcoinjs-message": "2.2.0",
"bs58": "4.0.1",
"ecashaddrjs": "1.0.7",
"ini": "1.3.8",
"randombytes": "2.0.6",
"safe-buffer": "5.1.2",
"satoshi-bitcoin": "1.0.4",
"slp-mdm": "0.0.6",
"ini": "6.0.0",
"randombytes": "2.1.0",
"safe-buffer": "5.2.1",
"satoshi-bitcoin": "1.0.5",
"slp-mdm": "0.0.7",
"slp-parser": "0.0.4",
"wif": "2.0.6"
"wif": "2.0.6",
"x402-bch-axios": "1.1.1"
},
"devDependencies": {
"apidoc": "0.50.5",
"assert": "2.0.0",
"apidoc": "1.2.0",
"assert": "2.1.0",
"c8": "10.1.3",
"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",
"lodash.clonedeep": "4.5.0",
"mocha": "9.2.1",
"node-mocks-http": "1.7.0",
"mocha": "11.7.5",
"nyc": "15.1.0",
"semantic-release": "^19.0.2",
"semantic-release": "24.2.9",
"sinon": "9.2.2",
"standard": "^16.0.4"
"standard": "17.1.2"
},
"apidoc": {
"title": "bch-js",
@@ -90,5 +76,10 @@
"hooks": {
"pre-commit": "npm run lint"
}
},
"standard": {
"parserOptions": {
"ecmaVersion": "latest"
}
}
}
+12 -23
View File
@@ -1,7 +1,7 @@
// const axios = require("axios")
const Bitcoin = require('@psf/bitcoincashjs-lib')
const cashaddr = require('ecashaddrjs')
const coininfo = require('@psf/coininfo')
// import axios from "axios"
import Bitcoin from '@psf/bitcoincashjs-lib'
import cashaddr from 'ecashaddrjs'
import coininfo from '@psf/coininfo'
class Address {
constructor (config) {
@@ -10,22 +10,11 @@ class Address {
else tmp.restURL = config.restURL
this.restURL = tmp.restURL
this.apiToken = tmp.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
}
@@ -312,28 +301,28 @@ class Address {
return {
prefix: 'bitcoincash',
type: 'P2PKH',
hash: hash,
hash,
format: 'legacy'
}
case info.main.versions.scripthash:
return {
prefix: 'bitcoincash',
type: 'P2SH',
hash: hash,
hash,
format: 'legacy'
}
case info.test.versions.public:
return {
prefix: 'bchtest',
type: 'P2PKH',
hash: hash,
hash,
format: 'legacy'
}
case info.test.versions.scripthash:
return {
prefix: 'bchtest',
type: 'P2SH',
hash: hash,
hash,
format: 'legacy'
}
default:
@@ -871,4 +860,4 @@ class Address {
}
}
module.exports = Address
export default Address
+82 -49
View File
@@ -7,36 +7,45 @@
*/
// bch-api mainnet.
const DEFAULT_REST_API = 'https://api.fullstack.cash/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
const BitcoinCash = require('./bitcoincash')
const Crypto = require('./crypto')
const Util = require('./util')
const Blockchain = require('./blockchain')
const Control = require('./control')
const Generating = require('./generating')
const Mining = require('./mining')
const RawTransactions = require('./raw-transactions')
const Mnemonic = require('./mnemonic')
const Address = require('./address')
const HDNode = require('./hdnode')
const TransactionBuilder = require('./transaction-builder')
const ECPair = require('./ecpair')
const Script = require('./script')
const Price = require('./price')
const Schnorr = require('./schnorr')
const SLP = require('./slp/slp')
const Encryption = require('./encryption')
const Utxo = require('./utxo')
const Transaction = require('./transaction')
const DSProof = require('./dsproof')
const Ecash = require('./ecash')
import BitcoinCash from './bitcoincash.js'
import Crypto from './crypto.js'
import Util from './util.js'
import Blockchain from './blockchain.js'
import Control from './control.js'
import Generating from './generating.js'
import Mining from './mining.js'
import RawTransactions from './raw-transactions.js'
import Mnemonic from './mnemonic.js'
import Address from './address.js'
import HDNode from './hdnode.js'
import TransactionBuilder from './transaction-builder.js'
import ECPair from './ecpair.js'
import Script from './script.js'
import Price from './price.js'
import Schnorr from './schnorr.js'
import SLP from './slp/slp.js'
import Encryption from './encryption.js'
import Utxo from './utxo.js'
import Transaction from './transaction.js'
import DSProof from './dsproof.js'
import Ecash from './ecash.js'
// Indexers
const Electrumx = require('./electrumx')
const PsfSlpIndexer = require('./psf-slp-indexer')
import Electrumx from './electrumx.js'
import PsfSlpIndexer from './psf-slp-indexer.js'
const DEFAULT_REST_API = 'https://api.fullstack.cash/v6/'
class BCHJS {
constructor (config) {
@@ -47,39 +56,55 @@ class BCHJS {
this.restURL = process.env.RESTURL
} else this.restURL = DEFAULT_REST_API
// Retrieve the apiToken
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 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
}
// Retrieve the Basic Authentication password.
this.authPass = '' // default value.
if (config && config.authPass && config.authPass !== '') {
this.authPass = config.authPass
} else if (process.env.BCHJSAUTHPASS && process.env.BCHJSAUTHPASS !== '') {
this.authPass = process.env.BCHJSAUTHPASS
}
// Generate a Basic Authentication token from an auth password
// Generate the authentication token for the authorization header.
this.authToken = ''
if (this.authPass) {
// console.log(`bch-js initialized with authPass: ${this.authPass}`)
// Generate the header for Basic Authentication.
const combined = `fullstackcash:${this.authPass}`
const base64Credential = Buffer.from(combined).toString('base64')
this.authToken = `Basic ${base64Credential}`
if (this.bearerToken) {
this.authToken = `Bearer ${this.bearerToken}`
}
// x402 payment configuration
// 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
}
this.paymentAmountSats = (config && config.paymentAmountSats) || 2000 * 10
this.bchServerURL = (config && config.bchServerURL) || 'https://free-bch.fullstack.cash'
const libConfig = {
restURL: this.restURL,
apiToken: this.apiToken,
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,
{ bchServerURL: this.bchServerURL }
)
libConfig.axios = axiosInstance
}
// ElectrumX indexer
this.Electrumx = new Electrumx(libConfig)
@@ -117,7 +142,15 @@ class BCHJS {
this.eCash = new Ecash()
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
View File
@@ -1,13 +1,12 @@
const Bitcoin = require('@psf/bitcoincashjs-lib')
const sb = require('satoshi-bitcoin')
const bitcoinMessage = require('bitcoinjs-message')
const bs58 = require('bs58')
const bip21 = require('@psf/bip21')
const coininfo = require('@psf/coininfo')
const bip38 = require('bip38')
const wif = require('wif')
const Buffer = require('safe-buffer').Buffer
import Bitcoin from '@psf/bitcoincashjs-lib'
import sb from 'satoshi-bitcoin'
import bitcoinMessage from 'bitcoinjs-message'
import bs58 from 'bs58'
import bip21 from '@psf/bip21'
import coininfo from '@psf/coininfo'
import bip38 from 'bip38'
import wif from 'wif'
import { Buffer } from 'safe-buffer'
class BitcoinCash {
constructor (address) {
@@ -519,4 +518,4 @@ class BitcoinCash {
}
}
module.exports = BitcoinCash
export default BitcoinCash
+60 -68
View File
@@ -3,33 +3,22 @@
- Add blockhash functionality back into getTxOutProof
*/
const axios = require('axios')
import axios from 'axios'
// let _this
class Blockchain {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Use the shared axios instance if provided, otherwise fall back to axios
this.axios = config.axios || axios
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
// _this = this
}
/**
@@ -52,8 +41,8 @@ class Blockchain {
*/
async getBestBlockHash () {
try {
const response = await axios.get(
`${this.restURL}blockchain/getBestBlockHash`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/getBestBlockHash`,
this.axiosOptions
)
return response.data
@@ -106,8 +95,8 @@ class Blockchain {
if (!blockhash || typeof blockhash !== 'string') {
throw new Error('blockhash must be a string')
}
const response = await axios.post(
`${this.restURL}blockchain/getblock`,
const response = await this.axios.post(
`${this.restURL}full-node/blockchain/getblock`,
{
blockhash,
verbosity
@@ -160,8 +149,8 @@ class Blockchain {
*/
async getBlockchainInfo () {
try {
const response = await axios.get(
`${this.restURL}blockchain/getBlockchainInfo`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/getBlockchainInfo`,
this.axiosOptions
)
return response.data
@@ -191,12 +180,15 @@ class Blockchain {
*/
async getBlockCount () {
try {
const response = await axios.get(
`${this.restURL}blockchain/getBlockCount`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/getBlockCount`,
this.axiosOptions
)
return response.data
} catch (error) {
console.log('Error in bch-js/blockchain.js/getBlockCount()')
console.log('blockchain.js restURL: ', this.restURL)
if (error.response && error.response.data) throw error.response.data
else throw error
}
@@ -224,8 +216,8 @@ class Blockchain {
if (typeof height !== 'string') height = JSON.stringify(height)
try {
const response = await axios.get(
`${this.restURL}blockchain/getBlockHash/${height}`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/getBlockHash/${height}`,
this.axiosOptions
)
return response.data
@@ -271,8 +263,8 @@ class Blockchain {
try {
// Handle single hash.
if (typeof hash === 'string') {
const response = await axios.get(
`${this.restURL}blockchain/getBlockHeader/${hash}?verbose=${verbose}`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/getBlockHeader/${hash}?verbose=${verbose}`,
this.axiosOptions
)
@@ -281,11 +273,11 @@ class Blockchain {
// Handle array of hashes.
} else if (Array.isArray(hash)) {
// Dev note: must use axios.post for unit test stubbing.
const response = await axios.post(
`${this.restURL}blockchain/getBlockHeader`,
const response = await this.axios.post(
`${this.restURL}full-node/blockchain/getBlockHeader`,
{
hashes: hash,
verbose: verbose
verbose
},
this.axiosOptions
)
@@ -332,8 +324,8 @@ class Blockchain {
*/
async getChainTips () {
try {
const response = await axios.get(
`${this.restURL}blockchain/getChainTips`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/getChainTips`,
this.axiosOptions
)
return response.data
@@ -364,8 +356,8 @@ class Blockchain {
*/
async getDifficulty () {
try {
const response = await axios.get(
`${this.restURL}blockchain/getDifficulty`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/getDifficulty`,
this.axiosOptions
)
return response.data
@@ -380,8 +372,8 @@ class Blockchain {
if (typeof txid !== 'string') txid = JSON.stringify(txid)
try {
const response = await axios.get(
`${this.restURL}blockchain/getMempoolAncestors/${txid}?verbose=${verbose}`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/getMempoolAncestors/${txid}?verbose=${verbose}`,
this.axiosOptions
)
return response.data
@@ -395,8 +387,8 @@ class Blockchain {
if (typeof txid !== 'string') txid = JSON.stringify(txid)
try {
const response = await axios.get(
`${this.restURL}blockchain/getMempoolDescendants/${txid}?verbose=${verbose}`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/getMempoolDescendants/${txid}?verbose=${verbose}`,
this.axiosOptions
)
return response.data
@@ -492,16 +484,16 @@ class Blockchain {
try {
if (typeof txid === 'string') {
const response = await axios.get(
`${this.restURL}blockchain/getMempoolEntry/${txid}`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/getMempoolEntry/${txid}`,
this.axiosOptions
)
return response.data
} else if (Array.isArray(txid)) {
// Dev note: must use axios.post for unit test stubbing.
const response = await axios.post(
`${this.restURL}blockchain/getMempoolEntry`,
const response = await this.axios.post(
`${this.restURL}full-node/blockchain/getMempoolEntry`,
{
txids: txid
},
@@ -543,8 +535,8 @@ class Blockchain {
*/
async getMempoolInfo () {
try {
const response = await axios.get(
`${this.restURL}blockchain/getMempoolInfo`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/getMempoolInfo`,
this.axiosOptions
)
return response.data
@@ -590,8 +582,8 @@ class Blockchain {
*/
async getRawMempool (verbose = false) {
try {
const response = await axios.get(
`${this.restURL}blockchain/getRawMempool?vebose=${verbose}`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/getRawMempool?vebose=${verbose}`,
this.axiosOptions
)
return response.data
@@ -634,14 +626,14 @@ class Blockchain {
}
// 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.axiosOptions
// )
const response = await axios.post(
`${this.restURL}blockchain/getTxOut`,
const response = await this.axios.post(
`${this.restURL}full-node/blockchain/getTxOut`,
{
txid: txid,
txid,
vout: n,
mempool: includeMempool
},
@@ -695,19 +687,19 @@ class Blockchain {
try {
// Single txid.
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}`
const response = await axios.get(path, this.axiosOptions)
const response = await this.axios.get(path, this.axiosOptions)
return response.data
// Array of txids.
} else if (Array.isArray(txids)) {
// Dev note: must use axios.post for unit test stubbing.
const response = await axios.post(
`${this.restURL}blockchain/getTxOutProof`,
const response = await this.axios.post(
`${this.restURL}full-node/blockchain/getTxOutProof`,
{
txids: txids
txids
},
this.axiosOptions
)
@@ -724,8 +716,8 @@ class Blockchain {
async preciousBlock (blockhash) {
try {
const response = await axios.get(
`${this.restURL}blockchain/preciousBlock/${blockhash}`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/preciousBlock/${blockhash}`,
this.axiosOptions
)
return response.data
@@ -737,8 +729,8 @@ class Blockchain {
async pruneBlockchain (height) {
try {
const response = await axios.post(
`${this.restURL}blockchain/pruneBlockchain/${height}`,
const response = await this.axios.post(
`${this.restURL}full-node/blockchain/pruneBlockchain/${height}`,
this.axiosOptions
)
return response.data
@@ -750,8 +742,8 @@ class Blockchain {
async verifyChain (checklevel = 3, nblocks = 6) {
try {
const response = await axios.get(
`${this.restURL}blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}`,
this.axiosOptions
)
return response.data
@@ -802,8 +794,8 @@ class Blockchain {
try {
// Single block
if (typeof proof === 'string') {
const response = await axios.get(
`${this.restURL}blockchain/verifyTxOutProof/${proof}`,
const response = await this.axios.get(
`${this.restURL}full-node/blockchain/verifyTxOutProof/${proof}`,
this.axiosOptions
)
return response.data
@@ -811,8 +803,8 @@ class Blockchain {
// Array of hashes.
} else if (Array.isArray(proof)) {
// Dev note: must use axios.post for unit test stubbing.
const response = await axios.post(
`${this.restURL}blockchain/verifyTxOutProof`,
const response = await this.axios.post(
`${this.restURL}full-node/blockchain/verifyTxOutProof`,
{
proofs: proof
},
@@ -830,4 +822,4 @@ class Blockchain {
}
}
module.exports = Blockchain
export default Blockchain
+11 -22
View File
@@ -2,33 +2,22 @@
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.
class Control {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Use the shared axios instance if provided, otherwise fall back to axios
this.axios = config.axios || axios
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
// _this = this
}
/**
@@ -79,8 +68,8 @@ class Control {
*/
async getNetworkInfo () {
try {
const response = await axios.get(
`${this.restURL}control/getNetworkInfo`,
const response = await this.axios.get(
`${this.restURL}full-node/control/getNetworkInfo`,
this.axiosOptions
)
return response.data
@@ -92,8 +81,8 @@ class Control {
async getMemoryInfo () {
try {
const response = await axios.get(
`${this.restURL}control/getMemoryInfo`,
const response = await this.axios.get(
`${this.restURL}full-node/control/getMemoryInfo`,
this.axiosOptions
)
return response.data
@@ -115,4 +104,4 @@ class Control {
// }
}
module.exports = Control
export default Control
+3 -3
View File
@@ -1,5 +1,5 @@
const randomBytes = require('randombytes')
const Bitcoin = require('@psf/bitcoincashjs-lib')
import randomBytes from 'randombytes'
import Bitcoin from '@psf/bitcoincashjs-lib'
class Crypto {
/**
@@ -135,4 +135,4 @@ class Crypto {
}
}
module.exports = Crypto
export default Crypto
+6 -17
View File
@@ -1,27 +1,16 @@
const axios = require('axios')
import axios from 'axios'
let _this
class DSProof {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
this.axios = axios
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
@@ -67,7 +56,7 @@ class DSProof {
throw new Error(`txid must be of length 64 (not ${txid.length})`)
}
const response = await _this.axios.get(
`${this.restURL}dsproof/getdsproof/${txid}`,
`${this.restURL}full-node/dsproof/getdsproof/${txid}`,
this.axiosOptions
)
return response.data
@@ -78,4 +67,4 @@ class DSProof {
}
}
module.exports = DSProof
export default DSProof
+1 -1
View File
@@ -44,4 +44,4 @@ class eCash {
}
}
module.exports = eCash
export default eCash
+3 -3
View File
@@ -1,5 +1,5 @@
const Bitcoin = require('@psf/bitcoincashjs-lib')
const coininfo = require('@psf/coininfo')
import Bitcoin from '@psf/bitcoincashjs-lib'
import coininfo from '@psf/coininfo'
class ECPair {
static setAddress (address) {
@@ -166,4 +166,4 @@ class ECPair {
}
}
module.exports = ECPair
export default ECPair
+34 -44
View File
@@ -3,10 +3,10 @@
by FullStack.cash
*/
// Public npm libraries
const axios = require('axios')
import axios from 'axios'
// Local libraries.
const Blockchain = require('./blockchain')
import Blockchain from './blockchain.js'
// const Address = require('./address')
// let _this
@@ -14,30 +14,18 @@ const Blockchain = require('./blockchain')
class ElectrumX {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Use the shared axios instance if provided, otherwise fall back to axios
this.axios = config.axios || axios
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
// Encapsulate dependencies
this.blockchain = new Blockchain(config)
// this.address = new Address(config)
// _this = this
}
/**
@@ -111,16 +99,16 @@ class ElectrumX {
// Handle single address.
if (typeof address === 'string') {
const response = await axios.get(
`${this.restURL}electrumx/utxos/${address}`,
const response = await this.axios.get(
`${this.restURL}fulcrum/utxos/${address}`,
this.axiosOptions
)
return response.data
// Handle array of addresses.
} else if (Array.isArray(address)) {
const response = await axios.post(
`${this.restURL}electrumx/utxos`,
const response = await this.axios.post(
`${this.restURL}fulcrum/utxos`,
{
addresses: address
},
@@ -195,16 +183,16 @@ class ElectrumX {
try {
// Handle single address.
if (typeof address === 'string') {
const response = await axios.get(
`${this.restURL}electrumx/balance/${address}`,
const response = await this.axios.get(
`${this.restURL}fulcrum/balance/${address}`,
this.axiosOptions
)
return response.data
// Handle array of addresses.
} else if (Array.isArray(address)) {
const response = await axios.post(
`${this.restURL}electrumx/balance`,
const response = await this.axios.post(
`${this.restURL}fulcrum/balance`,
{
addresses: address
},
@@ -293,16 +281,16 @@ class ElectrumX {
try {
// Handle single address.
if (typeof address === 'string') {
const response = await axios.get(
`${this.restURL}electrumx/transactions/${address}/${allTxs}`,
const response = await this.axios.get(
`${this.restURL}fulcrum/transactions/${address}/${allTxs}`,
this.axiosOptions
)
return response.data
// Handle array of addresses.
} else if (Array.isArray(address)) {
const response = await axios.post(
`${this.restURL}electrumx/transactions`,
const response = await this.axios.post(
`${this.restURL}fulcrum/transactions`,
{
addresses: address,
usrObj, // pass user data when making an internal call.
@@ -388,16 +376,16 @@ class ElectrumX {
try {
// Handle single address.
if (typeof address === 'string') {
const response = await axios.get(
`${this.restURL}electrumx/unconfirmed/${address}`,
const response = await this.axios.get(
`${this.restURL}fulcrum/unconfirmed/${address}`,
this.axiosOptions
)
return response.data
// Handle array of addresses.
} else if (Array.isArray(address)) {
const response = await axios.post(
`${this.restURL}electrumx/unconfirmed`,
const response = await this.axios.post(
`${this.restURL}fulcrum/unconfirmed`,
{
addresses: address
},
@@ -457,8 +445,8 @@ class ElectrumX {
*/
async blockHeader (height, count = 1) {
try {
const response = await axios.get(
`${this.restURL}electrumx/block/headers/${height}?count=${count}`,
const response = await this.axios.get(
`${this.restURL}fulcrum/block/headers/${height}?count=${count}`,
this.axiosOptions
)
return response.data
@@ -548,14 +536,14 @@ class ElectrumX {
try {
// Handle single transaction.
if (typeof txid === 'string') {
const response = await axios.get(
`${this.restURL}electrumx/tx/data/${txid}`,
const response = await this.axios.get(
`${this.restURL}fulcrum/tx/data/${txid}`,
this.axiosOptions
)
return response.data
} else if (Array.isArray(txid)) {
const response = await axios.post(
`${this.restURL}electrumx/tx/data`,
const response = await this.axios.post(
`${this.restURL}fulcrum/tx/data`,
{
txids: txid
},
@@ -596,8 +584,8 @@ class ElectrumX {
async broadcast (txHex) {
try {
if (typeof txHex === 'string') {
const response = await axios.post(
`${this.restURL}electrumx/tx/broadcast`,
const response = await this.axios.post(
`${this.restURL}fulcrum/tx/broadcast`,
{ txHex },
this.axiosOptions
)
@@ -720,9 +708,11 @@ class ElectrumX {
return this.sortConfTxs(modifiedTxs, sortingOrder)
} catch (err) {
console.log('Error in util.js/sort0ConfTxs')
console.log('electrumx.js restURL: ', this.restURL)
throw err
}
}
}
module.exports = ElectrumX
export default ElectrumX
+8 -17
View File
@@ -2,33 +2,24 @@
This library contains useful functions that deal with encryption.
*/
const axios = require('axios')
import axios from 'axios'
let _this
class Encryption {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.axios = axios
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
// Use the shared axios instance if provided, otherwise fall back to axios
this.axios = config.axios || axios
_this = this
}
@@ -73,4 +64,4 @@ class Encryption {
}
}
module.exports = Encryption
export default Encryption
+8 -19
View File
@@ -1,35 +1,24 @@
const axios = require('axios')
import axios from 'axios'
// let _this
class Generating {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Use the shared axios instance if provided, otherwise fall back to axios
this.axios = config.axios || axios
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
// _this = this
}
async generateToAddress (blocks, address, maxtries = 1000000) {
try {
const response = await axios.post(
const response = await this.axios.post(
`${this.restURL}generating/generateToAddress/${blocks}/${address}?maxtries=${maxtries}`,
this.axiosOptions
)
@@ -41,4 +30,4 @@ class Generating {
}
}
module.exports = Generating
export default Generating
+5 -5
View File
@@ -1,7 +1,7 @@
const Bitcoin = require('@psf/bitcoincashjs-lib')
const coininfo = require('@psf/coininfo')
const bip32utils = require('@chris.troutner/bip32-utils')
const bchaddrjs = require('bchaddrjs-slp')
import Bitcoin from '@psf/bitcoincashjs-lib'
import coininfo from '@psf/coininfo'
import bip32utils from '@chris.troutner/bip32-utils'
import bchaddrjs from 'bchaddrjs-slp'
class HDNode {
constructor (address) {
@@ -637,4 +637,4 @@ class HDNode {
}
}
module.exports = HDNode
export default HDNode
+11 -22
View File
@@ -1,35 +1,24 @@
const axios = require('axios')
import axios from 'axios'
// let _this
class Mining {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Use the shared axios instance if provided, otherwise fall back to axios
this.axios = config.axios || axios
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
// _this = this
}
async getBlockTemplate (templateRequest) {
try {
const response = await axios.get(
const response = await this.axios.get(
`${this.restURL}mining/getBlockTemplate/${templateRequest}`,
this.axiosOptions
)
@@ -42,7 +31,7 @@ class Mining {
async getMiningInfo () {
try {
const response = await axios.get(
const response = await this.axios.get(
`${this.restURL}mining/getMiningInfo`,
this.axiosOptions
)
@@ -55,7 +44,7 @@ class Mining {
async getNetworkHashps (nblocks = 120, height = 1) {
try {
const response = await axios.get(
const response = await this.axios.get(
`${this.restURL}mining/getNetworkHashps?nblocks=${nblocks}&height=${height}`,
this.axiosOptions
)
@@ -71,7 +60,7 @@ class Mining {
if (parameters) path = `${path}?parameters=${parameters}`
try {
const response = await axios.post(path, this.axiosOptions)
const response = await this.axios.post(path, this.axiosOptions)
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
@@ -80,4 +69,4 @@ class Mining {
}
}
module.exports = Mining
export default Mining
+8 -11
View File
@@ -1,11 +1,8 @@
/* eslint no-prototype-builtins: "off" */
/* eslint node/no-callback-literal: "off" */
const BIP39 = require('bip39')
const randomBytes = require('randombytes')
const Bitcoin = require('@psf/bitcoincashjs-lib')
const Buffer = require('safe-buffer').Buffer
const wif = require('wif')
import BIP39 from 'bip39'
import randomBytes from 'randombytes'
import Bitcoin from '@psf/bitcoincashjs-lib'
import { Buffer } from 'safe-buffer'
import wif from 'wif'
class Mnemonic {
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
@@ -356,7 +353,7 @@ const _extend = function (dst) {
const sources = Array.prototype.slice.call(arguments, 1)
for (let i = 0; i < sources.length; ++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
}
@@ -503,7 +500,7 @@ const Levenshtein = {
try {
options.progress.call(null, (i * 100.0) / str1.length)
} catch (err) {
return cb(`Progress callback: ${err.toString()}`)
return cb(new Error(`Progress callback: ${err.toString()}`))
}
}
+43 -108
View File
@@ -1,49 +1,22 @@
const axios = require('axios')
import axios from 'axios'
// let _this
class Price {
constructor (config) {
// _this = this
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
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
// }
// }
/**
* @api price.getUsd() getUsd()
* @apiName Price getUsd()
@@ -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()
* @apiName Price getBchUsd()
@@ -230,6 +129,42 @@ class Price {
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
+21 -32
View File
@@ -7,41 +7,30 @@
*/
// Public npm libraries
const axios = require('axios')
import axios from 'axios'
// Local libraries
const RawTransaction = require('./raw-transactions')
const SlpUtils = require('./slp/utils')
import RawTransaction from './raw-transactions.js'
import SlpUtils from './slp/utils.js'
// let _this
class PsfSlpIndexer {
constructor (config = {}) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
// Use the shared axios instance if provided, otherwise fall back to axios
this.axios = config.axios || axios
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
// Encapsulate dependencies
this.rawTransaction = new RawTransaction(config)
this.slpUtils = new SlpUtils(config)
// _this = this
}
/**
@@ -71,8 +60,8 @@ class PsfSlpIndexer {
*/
async status () {
try {
const response = await axios.get(
`${this.restURL}psf/slp/status`,
const response = await this.axios.get(
`${this.restURL}slp/status`,
this.axiosOptions
)
return response.data
@@ -136,8 +125,8 @@ class PsfSlpIndexer {
// Handle single address.
if (typeof address === 'string') {
const response = await axios.post(
`${this.restURL}psf/slp/address`,
const response = await this.axios.post(
`${this.restURL}slp/address`,
{ address },
this.axiosOptions
)
@@ -201,8 +190,8 @@ class PsfSlpIndexer {
try {
// Handle single address.
if (typeof tokenId === 'string') {
const response = await axios.post(
`${this.restURL}psf/slp/token`,
const response = await this.axios.post(
`${this.restURL}slp/token`,
{ tokenId, withTxHistory },
this.axiosOptions
)
@@ -293,8 +282,8 @@ class PsfSlpIndexer {
// Handle single address.
if (typeof txid === 'string') {
const response = await axios.post(
`${this.restURL}psf/slp/txid`,
const response = await this.axios.post(
`${this.restURL}slp/txid`,
{ txid },
this.axiosOptions
)
@@ -423,12 +412,12 @@ class PsfSlpIndexer {
*/
async getTokenData (tokenId, withTxHistory = false) {
try {
const url = `${this.restURL}psf/slp/token/data`
const url = `${this.restURL}slp/token/data`
// console.log(`url: ${url}`)
// Handle single address.
if (typeof tokenId === 'string') {
const response = await axios.post(
const response = await this.axios.post(
// 'https://bchn.fullstack.cash/v5/psf/slp/token/data/',
url,
{ tokenId, withTxHistory },
@@ -516,12 +505,12 @@ class PsfSlpIndexer {
*/
async getTokenData2 (tokenId, updateCache = false) {
try {
const url = `${this.restURL}psf/slp/token/data2`
const url = `${this.restURL}slp/token/data2`
// console.log(`url: ${url}`)
// Handle single address.
if (typeof tokenId === 'string') {
const response = await axios.post(
const response = await this.axios.post(
// 'https://bchn.fullstack.cash/v5/psf/slp/token/data/',
url,
{ tokenId, updateCache },
@@ -539,4 +528,4 @@ class PsfSlpIndexer {
}
}
module.exports = PsfSlpIndexer
export default PsfSlpIndexer
+23 -35
View File
@@ -1,33 +1,20 @@
const axios = require('axios')
import axios from 'axios'
// let _this
class RawTransactions {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
// Encapsulate dependencies
this.axios = axios
// this = this
// Use the shared axios instance if provided, otherwise fall back to axios
this.axios = config.axios || axios
}
/**
@@ -96,8 +83,8 @@ class RawTransactions {
try {
// Single hex
if (typeof hex === 'string') {
const response = await axios.get(
`${this.restURL}rawtransactions/decodeRawTransaction/${hex}`,
const response = await this.axios.get(
`${this.restURL}full-node/rawtransactions/decodeRawTransaction/${hex}`,
this.axiosOptions
)
@@ -107,13 +94,13 @@ class RawTransactions {
} else if (Array.isArray(hex)) {
const options = {
method: 'POST',
url: `${this.restURL}rawtransactions/decodeRawTransaction`,
url: `${this.restURL}full-node/rawtransactions/decodeRawTransaction`,
data: {
hexes: hex
},
headers: this.axiosOptions.headers
}
const response = await axios(options)
const response = await this.axios(options)
return response.data
}
@@ -164,8 +151,8 @@ class RawTransactions {
try {
if (typeof script === 'string') {
const response = await axios.get(
`${this.restURL}rawtransactions/decodeScript/${script}`,
const response = await this.axios.get(
`${this.restURL}full-node/rawtransactions/decodeScript/${script}`,
this.axiosOptions
)
@@ -173,13 +160,13 @@ class RawTransactions {
} else if (Array.isArray(script)) {
const options = {
method: 'POST',
url: `${this.restURL}rawtransactions/decodeScript`,
url: `${this.restURL}full-node/rawtransactions/decodeScript`,
data: {
hexes: script
},
headers: this.axiosOptions.headers
}
const response = await axios(options)
const response = await this.axios(options)
return response.data
}
@@ -263,8 +250,8 @@ class RawTransactions {
// 'getRawTransaction() this.axiosOptions: ',
// this.axiosOptions
// )
const response = await axios.get(
`${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=${verbose}`,
const response = await this.axios.get(
`${this.restURL}full-node/rawtransactions/getRawTransaction/${txid}?verbose=${verbose}`,
this.axiosOptions
)
@@ -272,15 +259,15 @@ class RawTransactions {
} else if (Array.isArray(txid)) {
const options = {
method: 'POST',
url: `${this.restURL}rawtransactions/getRawTransaction`,
url: `${this.restURL}full-node/rawtransactions/getRawTransaction`,
data: {
txids: txid,
verbose: verbose,
verbose,
usrObj // pass user data when making an internal call.
},
headers: this.axiosOptions.headers
}
const response = await axios(options)
const response = await this.axios(options)
return response.data
}
@@ -407,6 +394,7 @@ class RawTransactions {
// pass back the raw transaction data.
/* exit quietly */
}
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
return txDetails
} catch (error) {
@@ -459,7 +447,7 @@ class RawTransactions {
// Single tx hex.
if (typeof hex === 'string') {
const response = await this.axios.get(
`${this.restURL}rawtransactions/sendRawTransaction/${hex}`,
`${this.restURL}full-node/rawtransactions/sendRawTransaction/${hex}`,
this.axiosOptions
)
@@ -477,7 +465,7 @@ class RawTransactions {
} else if (Array.isArray(hex)) {
const options = {
method: 'POST',
url: `${this.restURL}rawtransactions/sendRawTransaction`,
url: `${this.restURL}full-node/rawtransactions/sendRawTransaction`,
data: {
hexes: hex
},
@@ -497,4 +485,4 @@ class RawTransactions {
}
}
module.exports = RawTransactions
export default RawTransactions
+5 -16
View File
@@ -1,24 +1,13 @@
const schnorr = require('bip-schnorr')
import schnorr from 'bip-schnorr'
class Schnorr {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
}
@@ -509,4 +498,4 @@ class Schnorr {
}
}
module.exports = Schnorr
export default Schnorr
+4 -2
View File
@@ -1,4 +1,6 @@
const Bitcoin = require('@psf/bitcoincashjs-lib')
import Bitcoin from '@psf/bitcoincashjs-lib'
import { createRequire } from 'module'
const require = createRequire(import.meta.url)
const opcodes = require('@psf/bitcoincash-ops')
class Script {
@@ -240,4 +242,4 @@ class Script {
}
}
module.exports = Script
export default Script
+4 -4
View File
@@ -1,9 +1,9 @@
const BCHJSAddress = require('../address')
import BCHJSAddress from '../address.js'
import bchaddrjs from 'bchaddrjs-slp'
// const bchAddress = new BCHJSAddress()
let bchAddress
const bchaddrjs = require('bchaddrjs-slp')
class Address extends BCHJSAddress {
constructor (config) {
super(config)
@@ -661,4 +661,4 @@ class Address extends BCHJSAddress {
}
}
module.exports = Address
export default Address
+4 -4
View File
@@ -1,9 +1,9 @@
// const BCHJS = require("../bch-js")
// import BCHJS from "../bch-js.js"
// 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 {
/*
@@ -31,4 +31,4 @@ class ECPair extends BCHJSECPair {
}
}
module.exports = ECPair
export default ECPair
+6 -97
View File
@@ -9,18 +9,18 @@
*/
// Public npm libraries
const axios = require('axios')
// import axios from 'axios'
// Local libraries.
const Address = require('./address')
import Address from './address.js'
// const BigNumber = require('bignumber.js')
const slpMdm = require('slp-mdm')
// import BigNumber from 'bignumber.js'
import slpMdm from 'slp-mdm'
import TransactionBuilder from '../transaction-builder.js'
// let _this
// const addy = new Address()
let addy
const TransactionBuilder = require('../transaction-builder')
class Nft1 {
constructor (config) {
@@ -419,97 +419,6 @@ class Nft1 {
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
View File
@@ -7,34 +7,23 @@
// imports
// require deps
// const BCHJS = require("../bch-js")
const Address = require('./address')
const ECPair = require('./ecpair')
// const HDNode = require("./hdnode")
const TokenType1 = require('./tokentype1')
const NFT1 = require('./nft1')
const Utils = require('./utils')
// import BCHJS from "../bch-js.js"
import Address from './address.js'
import ECPair from './ecpair.js'
// import HDNode from "./hdnode.js"
import TokenType1 from './tokentype1.js'
import NFT1 from './nft1.js'
import Utils from './utils.js'
// SLP is a superset of BITBOX
class SLP {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
@@ -46,4 +35,4 @@ class SLP {
}
}
module.exports = SLP
export default SLP
+11 -22
View File
@@ -2,41 +2,30 @@
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 Address = require('./address')
const Script = require('../script')
import Address from './address.js'
import Script from '../script.js'
const BigNumber = require('bignumber.js')
const slpMdm = require('slp-mdm')
const axios = require('axios')
import BigNumber from 'bignumber.js'
import slpMdm from 'slp-mdm'
import axios from 'axios'
import TransactionBuilder from '../transaction-builder.js'
// const addy = new Address()
let addy
const TransactionBuilder = require('../transaction-builder')
let _this // local global
class TokenType1 {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
@@ -483,4 +472,4 @@ class TokenType1 {
}
}
module.exports = TokenType1
export default TokenType1
+9 -19
View File
@@ -1,35 +1,25 @@
/* eslint-disable no-useless-catch */
// Public npm libraries
const axios = require('axios')
const slpParser = require('slp-parser')
import axios from 'axios'
import slpParser from 'slp-parser'
// Local libraries
const Util = require('../util')
import Util from '../util.js'
let _this
class Utils {
constructor (config = {}) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.slpParser = slpParser
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) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
@@ -184,4 +174,4 @@ class Utils {
}
}
module.exports = Utils
export default Utils
+5 -5
View File
@@ -1,7 +1,7 @@
const Bitcoin = require('@psf/bitcoincashjs-lib')
const coininfo = require('@psf/coininfo')
const bip66 = require('bip66')
const bip68 = require('bc-bip68')
import Bitcoin from '@psf/bitcoincashjs-lib'
import coininfo from '@psf/coininfo'
import bip66 from 'bip66'
import bip68 from 'bc-bip68'
class TransactionBuilder {
static setAddress (address) {
@@ -163,4 +163,4 @@ class TransactionBuilder {
}
}
module.exports = TransactionBuilder
export default TransactionBuilder
+5 -5
View File
@@ -6,10 +6,10 @@
// const BigNumber = require('bignumber.js')
// Local libraries
const RawTransaction = require('./raw-transactions')
const SlpUtils = require('./slp/utils')
const Blockchain = require('./blockchain')
const PsfSlpIndexer = require('./psf-slp-indexer')
import RawTransaction from './raw-transactions.js'
import SlpUtils from './slp/utils.js'
import Blockchain from './blockchain.js'
import PsfSlpIndexer from './psf-slp-indexer.js'
class Transaction {
constructor (config = {}) {
@@ -77,4 +77,4 @@ class Transaction {
}
}
module.exports = Transaction
export default Transaction
+5 -98
View File
@@ -1,30 +1,17 @@
const axios = require('axios')
// import axios from 'axios'
// let _this
class Util {
constructor (config) {
this.restURL = config.restURL
this.apiToken = config.apiToken
this.authToken = config.authToken
if (this.authToken) {
// Add Basic Authentication token to the authorization header.
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
} else {
// Add JWT token to the authorization header.
this.axiosOptions = {
headers: {
authorization: `Token ${this.apiToken}`
}
this.axiosOptions = {
headers: {
authorization: this.authToken
}
}
// _this = this
}
/**
@@ -223,86 +210,6 @@ class Util {
sleep (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 options1 = {
method: 'POST',
url: `${this.restURL}util/validateAddress`,
data: {
addresses: address
}
// headers: {
// authorization: `Token ${this.apiToken}`
// }
}
const options = Object.assign({}, options1, this.axiosOptions)
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
+20 -8
View File
@@ -6,11 +6,11 @@
*/
// Local libraries
const Electrumx = require('./electrumx')
const Slp = require('./slp/slp')
const PsfSlpIndexer = require('./psf-slp-indexer')
const BigNumber = require('bignumber.js')
const Blockchain = require('./blockchain')
import Electrumx from './electrumx.js'
import Slp from './slp/slp.js'
import PsfSlpIndexer from './psf-slp-indexer.js'
import BigNumber from 'bignumber.js'
import Blockchain from './blockchain.js'
class UTXO {
constructor (config = {}) {
@@ -32,6 +32,8 @@ class UTXO {
* properties:
* - address: "" - the address these UTXOs are associated with
* - 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
* not spent, to be safe.
* - slpUtxos: {} - UTXOs confirmed to be colored as valid SLP tokens
@@ -151,7 +153,9 @@ class UTXO {
// the indexer.
const txData = await this.psfSlpIndexer.tx(thisUtxo.tx_hash)
// 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
} else {
thisUtxo.isSlp = false
@@ -177,8 +181,15 @@ class UTXO {
// Hydrate the UTXOs with additional token data.
type1TokenUtxos = await this.hydrateTokenData(type1TokenUtxos)
// Collect BCH UTXOs above 1000 sats
const bchUtxos = utxos.filter(x => x.isSlp === false && x.value > 1000)
// 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
const bchUtxos = utxos.filter(x => x.isSlp === false)
let type1BatonUtxos = utxos.filter(
x => x.isSlp === true && x.type === 'baton' && x.tokenType === 1
)
@@ -208,6 +219,7 @@ class UTXO {
const outObj = {
address: addr,
bchUtxos,
infoUtxos,
slpUtxos: {
type1: {
tokens: type1TokenUtxos,
@@ -408,4 +420,4 @@ class UTXO {
}
}
module.exports = UTXO
export default UTXO
+4 -3
View File
@@ -2,10 +2,11 @@
A Mocha test file for running end-to-end (e2e) tests.
*/
// const mocha = require("mocha")
const assert = require('chai').assert
// import mocha from "mocha"
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('#send-tokens', () => {
+8 -2
View File
@@ -3,12 +3,18 @@
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`
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 __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
describe('#IPFS', () => {
it('should upload a file to the server', async () => {
const path = `${__dirname.toString()}/ipfs-e2e.js`
@@ -12,13 +12,14 @@
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://bchn.fullstack.cash/v5/'
// const RESTURL = `http://localhost:3000/v5/`
const BCHJS = require('../../../src/bch-js')
const bchjs = new BCHJS({ restURL: RESTURL })
describe('#anonymous rate limits', () => {
@@ -7,11 +7,12 @@
- 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 BCHJS = require('../../../src/bch-js')
const bchjs = new BCHJS({
// restURL: `https://bchn.fullstack.cash/v5/`,
restURL: 'https://abc.fullstack.cash/v5/',
+4 -3
View File
@@ -11,12 +11,13 @@
- 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 =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2YyMDIyMWMxMDAxMmFkOTQwMSIsImVtYWlsIjoiZGVtb0BkZW1vLmNvbSIsImFwaUxldmVsIjoxMCwicmF0ZUxpbWl0IjozLCJpYXQiOjE2MDQ4NTQ2OTEsImV4cCI6MTYwNzQ0NjY5MX0.iwse0z0KDKHx9graCxcOwj6lSlfKQAb1zLhmjvygvts'
const BCHJS = require('../../../src/bch-js')
const bchjs = new BCHJS({
restURL: 'https://api.fullstack.cash/v5/',
// restURL: `http://localhost:3000/v5/`,
@@ -11,12 +11,13 @@
- 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 =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M'
const BCHJS = require('../../../src/bch-js')
const bchjs = new BCHJS({
// restURL: `https://bchn.fullstack.cash/v5/`,
restURL: 'https:/abc.fullstack.cash/v5/',
+4 -3
View File
@@ -7,12 +7,13 @@
- 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 =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M'
const BCHJS = require('../../../src/bch-js')
const bchjs = new BCHJS({
// restURL: `https://bchn.fullstack.cash/v5/`,
restURL: 'https://abc.fullstack.cash/v5/',
@@ -18,26 +18,33 @@ const RECV_ADDR2 = 'bchtest:qz6yw0kqgfkknfy6jh2jvlfnkzmre3lt2u0pgcckdk'
const SATOSHIS_TO_SEND = 1000
// Instantiate BITBOX.
const bitboxLib = '../../../lib/BITBOX'
const BITBOXSDK = require(bitboxLib)
const BITBOX = new BITBOXSDK({ restURL: 'https://trest.bitcoin.com/v2/' })
// const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" })
// const util = require('util')
// Note: Dynamic require with variable - use dynamic import in ESM
const bitboxLib = '../../../lib/BITBOX.js'
let BITBOXSDK, BITBOX, walletInfo
// Open the wallet generated with create-wallet.
let walletInfo = {}
try {
walletInfo = require('./wallet.json')
} catch (err) {
console.log(
'Could not open wallet.json. Generate a wallet with create-wallet first.'
)
process.exit(0)
}
let SEND_ADDR, SEND_MNEMONIC
const SEND_ADDR = walletInfo.cashAddress
const SEND_MNEMONIC = walletInfo.mnemonic
// Load dependencies asynchronously
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 () {
try {
@@ -57,7 +64,10 @@ async function testSend () {
console.log('Error in testSend: ', err)
}
}
testSend()
// Load dependencies then run test
loadDependencies().then(() => {
testSend()
})
// Build a TX hex with the largest UTXO.
async function buildTx1 (recAddr) {
@@ -17,26 +17,33 @@ const RECV_ADDR1 = 'bchtest:qzfn2mly05t6fjsh5kjj0dqq0jjtct27ng089dgg05'
const SATOSHIS_TO_SEND = 1000
// Instantiate BITBOX.
const bitboxLib = '../../../lib/BITBOX'
const BITBOXSDK = require(bitboxLib)
const BITBOX = new BITBOXSDK({ restURL: 'https://trest.bitcoin.com/v2/' })
// const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" })
// const util = require('util')
// Note: Dynamic require with variable - use dynamic import in ESM
const bitboxLib = '../../../lib/BITBOX.js'
let BITBOXSDK, BITBOX, walletInfo
// Open the wallet generated with create-wallet.
let walletInfo = {}
try {
walletInfo = require('./wallet.json')
} catch (err) {
console.log(
'Could not open wallet.json. Generate a wallet with create-wallet first.'
)
process.exit(0)
}
let SEND_ADDR, SEND_MNEMONIC
const SEND_ADDR = walletInfo.cashAddress
const SEND_MNEMONIC = walletInfo.mnemonic
// Load dependencies asynchronously
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 () {
try {
@@ -54,7 +61,10 @@ async function testSend () {
console.log('Error in testSend: ', err)
}
}
testSend()
// Load dependencies then run test
loadDependencies().then(() => {
testSend()
})
// Build a TX hex with the largest UTXO.
async function buildTx1 (recAddr) {
+4 -4
View File
@@ -8,7 +8,9 @@
*/
// Inspect utility used for debugging.
const util = require('util')
import util from 'util'
import lib from '../util/e2e-util.js'
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
@@ -21,8 +23,6 @@ util.inspect.defaultOptions = {
const WALLET1 = '../wallet1.json'
const WALLET2 = '../wallet2.json'
const lib = require('../util/e2e-util')
// The main test function.
// Sends a token and reports on how long it takes to show up in SLPDB production.
async function sendTokenTest () {
@@ -95,6 +95,6 @@ function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
module.exports = {
export default {
sendTokenTest
}
+6 -3
View File
@@ -3,14 +3,14 @@
tests.
*/
module.exports = {
import SLPSDK from '../../../lib/SLP.js'
export default {
openWallet,
sendToken,
getTestTokenBalance,
threeDecimals
}
const SLPSDK = require('../../../lib/SLP')
const slpsdk = new SLPSDK()
const testTokenId =
@@ -20,6 +20,9 @@ const testTokenId =
// token balance.
async function openWallet (filename) {
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 walletBalance = await getBalance(walletInfo)
+1 -1
View File
@@ -9,7 +9,7 @@
- Start a local copy of bch-api
*/
const BCHJS = require('../../../src/bch-js.js')
import BCHJS from '../../../src/bch-js.js'
const bchjs = new BCHJS({
restURL: 'http://localhost:3000/v5/'
})
+5 -5
View File
@@ -7,13 +7,13 @@
of an e2e test to be properly tested.
*/
const chai = require('chai')
const assert = chai.assert
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
import chai from 'chai'
import BCHJS from '../../src/bch-js.js'
// Inspect utility used for debugging.
const util = require('util')
import util from 'util'
const assert = chai.assert
const bchjs = new BCHJS()
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
@@ -1,38 +0,0 @@
/*
Integration tests for the psf-slp-indexer.js library, specific to the eCash
blockchain.
*/
// Global npm libraries
const assert = require('chai').assert
// Local libraries
const BCHJS = require('../../../../src/bch-js')
let bchjs
describe('#psf-slp-indexer', () => {
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()
})
describe('#balance', () => {
it('should get token balance for an ecash address', async () => {
const addr = 'ecash:qr5c4hfy52zn87484cucvzle5pljz0gtr5vhtw9z09'
const result = await bchjs.PsfSlpIndexer.balance(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result.balance, 'utxos')
assert.property(result.balance, 'txs')
assert.property(result.balance, 'balances')
})
})
})
// Promise-based sleep function
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
@@ -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,38 +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 = 'ecash:qr5c4hfy52zn87484cucvzle5pljz0gtr5vhtw9z09'
// 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, 'address')
assert.property(result, 'bchUtxos')
assert.property(result, 'nullUtxos')
assert.property(result, 'slpUtxos')
assert.isArray(result.bchUtxos)
assert.isArray(result.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))
}
-301
View File
@@ -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,37 +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)
})
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')
})
})
})
-103
View File
@@ -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))
}
-172
View File
@@ -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
-109
View File
@@ -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 -2
View File
@@ -2,9 +2,9 @@
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 BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
describe('#control', () => {
@@ -2,9 +2,13 @@
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()
describe('#DSProof', () => {
+8 -9
View File
@@ -1,8 +1,8 @@
const chai = require('chai')
const assert = chai.assert
const sinon = require('sinon')
import chai from 'chai'
import sinon from 'sinon'
const BCHJS = require('../../src/bch-js')
import BCHJS from '../../src/bch-js.js'
const assert = chai.assert
const bchjs = new BCHJS()
describe('#ElectrumX', () => {
@@ -359,12 +359,8 @@ describe('#ElectrumX', () => {
try {
await bchjs.Electrumx.broadcast(txHex)
} catch (err) {
// console.log('err: ', err)
assert.property(err, 'success')
assert.equal(err.success, false)
assert.include(
err.error.error,
err.error,
'the transaction was rejected by network rules'
)
}
@@ -373,6 +369,9 @@ describe('#ElectrumX', () => {
describe('#sortAllTxs', () => {
it('should GET transaction history for a single address', async () => {
// Add delay for this endpoint.
await sleep(6000)
const addr = 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
const txs = await bchjs.Electrumx.transactions(addr)
+12 -3
View File
@@ -1,7 +1,7 @@
const assert = require('chai').assert
// const assert = require('chai').assert
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
// const BCHJS = require('../../src/bch-js')
// const bchjs = new BCHJS()
describe('#Encryption', () => {
beforeEach(async () => {
@@ -9,7 +9,12 @@ describe('#Encryption', () => {
})
describe('#getPubKey', () => {
// Commenting out these tests since they are failing in BVT due to 429 errors
/*
it('should get a public key', async () => {
// Add delay for this endpoint.
await sleep(8000)
const addr = 'bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq'
const result = await bchjs.encryption.getPubKey(addr)
@@ -21,6 +26,9 @@ describe('#Encryption', () => {
})
it('should report when public key can not be found', async () => {
// Add delay for this endpoint.
await sleep(8000)
const addr = 'bitcoincash:qrgqqkky28jdkv3w0ctrah0mz3jcsnsklc34gtukrh'
const result = await bchjs.encryption.getPubKey(addr)
@@ -31,6 +39,7 @@ describe('#Encryption', () => {
assert.property(result, 'publicKey')
assert.equal(result.publicKey, 'not found')
})
*/
})
})
+6 -33
View File
@@ -1,5 +1,6 @@
const assert = require('chai').assert
const BCHJS = require('../../src/bch-js')
import chai from 'chai'
import BCHJS from '../../src/bch-js.js'
const { assert } = chai
const bchjs = new BCHJS()
describe('#price', () => {
@@ -7,33 +8,6 @@ describe('#price', () => {
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', () => {
it('should get the USD price of BCH', async () => {
const result = await bchjs.Price.getBchUsd()
@@ -43,13 +17,12 @@ describe('#price', () => {
})
})
describe('#rates', () => {
describe('#getPsffppPrice', () => {
it('should get the price of BCH in several currencies', async () => {
const result = await bchjs.Price.rates()
const result = await bchjs.Price.getPsffppPrice()
// console.log(result)
assert.property(result, 'USD')
assert.property(result, 'CAD')
assert.isNumber(result)
})
})
})
@@ -4,10 +4,11 @@
*/
// Global npm libraries
const assert = require('chai').assert
import chai from 'chai'
// Local libraries
const BCHJS = require('../../../../src/bch-js')
import BCHJS from '../../src/bch-js.js'
const { assert } = chai
let bchjs
describe('#psf-slp-indexer', () => {
@@ -95,9 +96,7 @@ describe('#psf-slp-indexer', () => {
})
// FlexUSD transactions
// Currently FlexUSD UTXOs are reported as invalid SLP UTXOs, which means
// the wallet will burn them. There is a TODO in the code. This test will
// need to be changed when it is done.
// FlexUSD is blacklisted by the SLP indexer.
it('should mark blacklisted token as null', async () => {
const txid =
'302113c11b90edc5f36c073d2f8a75e1e0eaf59b56235491a843d3819cd6a85f'
@@ -108,7 +107,7 @@ describe('#psf-slp-indexer', () => {
assert.property(result.txData, 'vin')
assert.property(result.txData, 'vout')
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 () => {
+39 -5
View File
@@ -4,13 +4,13 @@
TODO
*/
const chai = require('chai')
const assert = chai.assert
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
import chai from 'chai'
import BCHJS from '../../src/bch-js.js'
// Inspect utility used for debugging.
const util = require('util')
import util from 'util'
const assert = chai.assert
const bchjs = new BCHJS()
util.inspect.defaultOptions = {
showHidden: true,
colors: true,
@@ -231,6 +231,40 @@ describe('#rawtransaction', () => {
that the server is responding on those endpoints, and responds consistently.
*/
describe('#sendRawTransaction', () => {
it('should send a single transaction hex', async () => {
try {
const hex =
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
await bchjs.RawTransactions.sendRawTransaction(hex)
// console.log(`result ${JSON.stringify(result, null, 2)}`)
assert.equal(true, false, 'Unexpected result!')
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ['error'])
assert.include(err.error, 'Missing inputs')
}
})
it('should send an array of tx hexes', async () => {
try {
const hexes = [
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
]
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
console.log(`result ${JSON.stringify(result, null, 2)}`)
} catch (err) {
// console.log(`err: ${util.inspect(err)}`)
assert.hasAllKeys(err, ['error'])
assert.include(err.error, 'Missing inputs')
}
})
it('should throw error on array size rate limit', async () => {
try {
const dataMock =
+147 -5
View File
@@ -2,14 +2,14 @@
Integration tests for the bchjs covering SLP tokens.
*/
const chai = require('chai')
const assert = chai.assert
import chai from 'chai'
const BCHJS = require('../../src/bch-js')
let bchjs
import BCHJS from '../../src/bch-js.js'
// Inspect utility used for debugging.
const util = require('util')
import util from 'util'
const assert = chai.assert
let bchjs
util.inspect.defaultOptions = {
showHidden: 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')
})
})
})
}
})
})
+27 -2
View File
@@ -2,8 +2,9 @@
Integration tests for the transaction.js library.
*/
const assert = require('chai').assert
const BCHJS = require('../../src/bch-js')
import chai from 'chai'
import BCHJS from '../../src/bch-js.js'
const { assert } = chai
const bchjs = new BCHJS()
describe('#Transaction', () => {
@@ -11,6 +12,30 @@ describe('#Transaction', () => {
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) {
describe('#getOld', () => {
it('should get details about a non-SLP transaction', async () => {
@@ -2,9 +2,10 @@
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({ restURL: 'http://192.168.2.129:3000/v5/' })
@@ -79,6 +80,7 @@ describe('#UTXO', () => {
assert.property(result, 'nullUtxos')
assert.isAbove(result.bchUtxos.length, 0)
assert.isAbove(result.infoUtxos.length, 0)
assert.isAbove(result.slpUtxos.type1.tokens.length, 0)
assert.equal(result.slpUtxos.type1.mintBatons.length, 0)
})
+7 -4
View File
@@ -1,12 +1,15 @@
// Public npm libraries.
const assert = require('assert')
const Bitcoin = require('@psf/bitcoincashjs-lib')
import assert from 'assert'
// import { assert } from 'chai'
import Bitcoin from '@psf/bitcoincashjs-lib'
// Mocks
const fixtures = require('./fixtures/address.json')
import { createRequire } from 'module'
// 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
function flatten (arrays) {
+5 -3
View File
@@ -1,11 +1,13 @@
// Public npm libraries
const assert = require('assert')
import assert from 'assert'
// Mocks
const fixtures = require('./fixtures/bitcoincash.json')
import { createRequire } from 'module'
// 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()
let bchjs
+23 -22
View File
@@ -1,11 +1,12 @@
const assert = require('assert')
const assert2 = require('chai').assert
const axios = require('axios')
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
const sinon = require('sinon')
import assert from 'assert'
import chai from 'chai'
import axios from 'axios'
import BCHJS from '../../src/bch-js.js'
import sinon from '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('#getBestBlockHash', () => {
@@ -60,7 +61,7 @@ describe('#Blockchain', () => {
}
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)
const blockhash =
@@ -129,7 +130,7 @@ describe('#Blockchain', () => {
}
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)
bchjs.Blockchain.getBlockchainInfo()
@@ -147,7 +148,7 @@ describe('#Blockchain', () => {
const data = 527810
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)
bchjs.Blockchain.getBlockCount()
@@ -166,7 +167,7 @@ describe('#Blockchain', () => {
'000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0'
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)
bchjs.Blockchain.getBlockHash(527810)
@@ -201,7 +202,7 @@ describe('#Blockchain', () => {
}
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)
bchjs.Blockchain.getBlockHeader(
@@ -222,7 +223,7 @@ describe('#Blockchain', () => {
const data = '577528469277.1339'
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)
bchjs.Blockchain.getDifficulty()
@@ -240,7 +241,7 @@ describe('#Blockchain', () => {
const data = 'Transaction not in mempool'
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)
bchjs.Blockchain.getMempoolAncestors(
@@ -263,7 +264,7 @@ describe('#Blockchain', () => {
}
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)
bchjs.Blockchain.getMempoolDescendants(
@@ -286,7 +287,7 @@ describe('#Blockchain', () => {
}
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)
bchjs.Blockchain.getMempoolEntry(
@@ -314,7 +315,7 @@ describe('#Blockchain', () => {
}
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)
bchjs.Blockchain.getMempoolInfo()
@@ -355,7 +356,7 @@ describe('#Blockchain', () => {
}
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)
bchjs.Blockchain.getRawMempool()
@@ -451,7 +452,7 @@ describe('#Blockchain', () => {
}
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)
bchjs.Blockchain.preciousBlock()
@@ -469,7 +470,7 @@ describe('#Blockchain', () => {
const data = 'Cannot prune blocks because node is not in prune mode.'
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)
bchjs.Blockchain.pruneBlockchain(507)
@@ -487,7 +488,7 @@ describe('#Blockchain', () => {
const data = true
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)
bchjs.Blockchain.verifyChain(3, 6)
@@ -505,7 +506,7 @@ describe('#Blockchain', () => {
const data = "proof must be hexadecimal string (not '')"
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)
bchjs.Blockchain.verifyTxOutProof('3')
+6 -6
View File
@@ -1,8 +1,8 @@
const assert = require('assert')
const axios = require('axios')
const BCHJS = require('../../src/bch-js')
import assert from 'assert'
import axios from 'axios'
import BCHJS from '../../src/bch-js.js'
import sinon from 'sinon'
const bchjs = new BCHJS()
const sinon = require('sinon')
describe('#Control', () => {
let sandbox
@@ -24,7 +24,7 @@ describe('#Control', () => {
relayfee: 0.00001,
errors: ''
}
const resolved = new Promise(resolve => resolve({ data: data }))
const resolved = new Promise(resolve => resolve({ data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Control.getNetworkInfo()
@@ -47,7 +47,7 @@ describe('#Control', () => {
chunks_free: 1
}
}
const resolved = new Promise(resolve => resolve({ data: data }))
const resolved = new Promise(resolve => resolve({ data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Control.getMemoryInfo()
+5 -3
View File
@@ -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 assert = require('assert')
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
const Buffer = require('safe-buffer').Buffer
describe('#Crypto', () => {
describe('#sha256', () => {
+5 -4
View File
@@ -1,10 +1,11 @@
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
import chai from 'chai'
import sinon from 'sinon'
// Unit under test (uut)
const BCHJS = require('../../src/bch-js')
const mockData = require('./fixtures/dsproof-mock')
import BCHJS from '../../src/bch-js.js'
import mockData from './fixtures/dsproof-mock.js'
const { assert } = chai
let bchjs
const txid = 'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'
+3 -2
View File
@@ -3,8 +3,9 @@
*/
// Global npm libraries
const assert = require('chai').assert
const Ecash = require('../../src/ecash')
import chai from 'chai'
import Ecash from '../../src/ecash.js'
const { assert } = chai
const uut = new Ecash()
describe('#eCash', () => {
+6 -4
View File
@@ -1,12 +1,14 @@
// Public npm libraries.
const assert = require('assert')
const Buffer = require('safe-buffer').Buffer
import assert from 'assert'
import { Buffer } from 'safe-buffer'
// Mocks
const fixtures = require('./fixtures/ecpair.json')
import { createRequire } from 'module'
// 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()
let bchjs
+7 -7
View File
@@ -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 axios = require('axios')
const sinon = require('sinon')
const BCHJS = require('../../src/bch-js')
const bchjs = new BCHJS()
const mockData = require('./fixtures/electrumx-mock')
describe('#ElectrumX', () => {
let sandbox
beforeEach(() => (sandbox = sinon.createSandbox()))
+6 -5
View File
@@ -1,12 +1,13 @@
const assert = require('chai').assert
const sinon = require('sinon')
import chai from 'chai'
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()
let bchjs
const mockData = require('./fixtures/encryption-mock')
describe('#Encryption', () => {
let sandbox
+1 -1
View File
@@ -39,7 +39,7 @@ const utxo = [
}
]
module.exports = {
export default {
balance,
utxo
}
+1 -1
View File
@@ -2,7 +2,7 @@
Mock data used for unit testing.
*/
module.exports = {
export default {
details: {
hash: '000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0',
size: 216,
+1 -1
View File
@@ -2,7 +2,7 @@
Mock data used for unit testing.
*/
module.exports = {
export default {
bestBlockHash:
'0000000000000000008e1f65f875703872544aa888c7ca6587f055f8f5fbd4bf',
+1 -1
View File
@@ -14,6 +14,6 @@ const dsproof = {
]
}
module.exports = {
export default {
dsproof
}
+1 -1
View File
@@ -290,7 +290,7 @@ const txHistoryWithUnconfirmed = {
]
}
module.exports = {
export default {
utxo,
utxos,
balance,
+1 -1
View File
@@ -13,7 +13,7 @@ const failureMock = {
publicKey: 'not found'
}
module.exports = {
export default {
successMock,
failureMock
}
+1 -1
View File
@@ -118,7 +118,7 @@ const paidFileData = {
}
}
module.exports = {
export default {
uploadData,
paymentInfo,
mockNewFileModel,
+1 -1
View File
@@ -77,7 +77,7 @@ const tx = {
'0200000001ac1e2e38764f9b81f3ff4317b4bd1a381dbdf311277a736f375d4ce217d3095f010000006a473044022000dd11c41a472f2e54348db996e60864d489429f12d1e044d49ff600b880c9590220715a926404bb0e2731a3795afb341ec1dad3f84ead7d27cd31fcc59abb14738c4121038476128287ac37c7a3cf7e8625fd5f024db1bc3d8e37395abe7bf42fda78d0d9ffffffff02e8030000000000001976a9142fe2c4c5ef359bb2fe1a849f891cecffbcfb4f7788acb0b40000000000001976a9142dbf5e1804c39a497b908c876097d63210c8490288ac00000000'
}
module.exports = {
export default {
balance,
utxo,
tx
+1 -1
View File
@@ -209,6 +209,6 @@ const mockRates = {
ZWL: '80215.03'
}
module.exports = {
export default {
mockRates
}
+1 -1
View File
@@ -203,7 +203,7 @@ const tokenMedia01 = {
ps002Compatible: true
}
module.exports = {
export default {
tokenStats,
txData,
balance,
+1 -1
View File
@@ -55,7 +55,7 @@ const mockGetInputAddrsOutput = [
}
]
module.exports = {
export default {
mockTx,
mockParentTx1,
mockGetInputAddrsOutput
+1 -1
View File
@@ -1411,7 +1411,7 @@ mock503Error.response = {
}
}
module.exports = {
export default {
mockList,
mockToken,
mockTokens,
+1 -1
View File
@@ -769,7 +769,7 @@ const genesisTestOpReturn03 = {
qty: '100000000000000000'
}
module.exports = {
export default {
nonSlpTxDetails,
slpTxDetails,
mockOpReturnData01,
+1 -1
View File
@@ -476,7 +476,7 @@ const noUtxoErr = {
'Key not found in database [bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7]'
}
module.exports = {
export default {
mockUtxoData,
mockHydratedUtxos,
mockTwoHydratedAddrs,
+5 -5
View File
@@ -1,10 +1,10 @@
// Public npm libraries
const assert = require('assert')
const axios = require('axios')
const sinon = require('sinon')
import assert from 'assert'
import axios from 'axios'
import sinon from 'sinon'
// Unit under test (uut)
const BCHJS = require('../../src/bch-js')
import BCHJS from '../../src/bch-js.js'
// const bchjs = new BCHJS()
let bchjs
@@ -20,7 +20,7 @@ describe('#Generating', () => {
it('should generate', done => {
const data = []
const resolved = new Promise(resolve => resolve({ data: data }))
const resolved = new Promise(resolve => resolve({ data }))
sandbox.stub(axios, 'post').returns(resolved)
bchjs.Generating.generateToAddress(
+6 -4
View File
@@ -1,13 +1,15 @@
// Public npm libraries
const assert = require('assert')
const Buffer = require('safe-buffer').Buffer
import assert from 'assert'
import { Buffer } from 'safe-buffer'
// Mocks
const fixtures = require('./fixtures/hdnode.json')
import { createRequire } from 'module'
// const slpFixtures = require('./fixtures/slp/address.json')
// 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/hdnode.json')
let bchjs
describe('#HDNode', () => {
+8 -8
View File
@@ -1,10 +1,10 @@
// Public npm libraries
const assert = require('assert')
const axios = require('axios')
const sinon = require('sinon')
import assert from 'assert'
import axios from 'axios'
import sinon from 'sinon'
// Unit under test (uut)
const BCHJS = require('../../src/bch-js')
import BCHJS from '../../src/bch-js.js'
let bchjs
describe('#Mining', () => {
@@ -30,7 +30,7 @@ describe('#Mining', () => {
sigops: 2
}
const resolved = new Promise(resolve => resolve({ data: data }))
const resolved = new Promise(resolve => resolve({ data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Mining.getBlockTemplate('')
@@ -59,7 +59,7 @@ describe('#Mining', () => {
chain: 'main'
}
const resolved = new Promise(resolve => resolve({ data: data }))
const resolved = new Promise(resolve => resolve({ data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Mining.getMiningInfo()
@@ -78,7 +78,7 @@ describe('#Mining', () => {
it('should get network hashps', done => {
const data = 3586365937646890000
const resolved = new Promise(resolve => resolve({ data: data }))
const resolved = new Promise(resolve => resolve({ data }))
sandbox.stub(axios, 'get').returns(resolved)
bchjs.Mining.getNetworkHashps()
@@ -98,7 +98,7 @@ describe('#Mining', () => {
it('should TODO', done => {
const data = {}
const resolved = new Promise(resolve => resolve({ data: data }))
const resolved = new Promise(resolve => resolve({ data }))
sandbox.stub(axios, 'post').returns(resolved)
bchjs.Mining.submitBlock()

Some files were not shown because too many files have changed in this diff Show More