mirror of
https://github.com/Permissionless-Software-Foundation/bch-js.git
synced 2026-09-22 00:52:01 -07:00
Compare commits
105
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aef56c5c14 | ||
|
|
2472dc3606 | ||
|
|
2df36124b4 | ||
|
|
c422d8db34 | ||
|
|
ec2d8ea80a | ||
|
|
fc527834ea | ||
|
|
3ceebc1f12 | ||
|
|
2ff46c1f76 | ||
|
|
6926bbe113 | ||
|
|
360f1509dd | ||
|
|
d5d2e43ad0 | ||
|
|
1012f4c1bf | ||
|
|
3cedd251e5 | ||
|
|
bdb4de0353 | ||
|
|
1de0bdcf14 | ||
|
|
3a9e4f64b5 | ||
|
|
ea57f52b20 | ||
|
|
903aae1091 | ||
|
|
1af766cbda | ||
|
|
60ee10ef4d | ||
|
|
2d4bc6127e | ||
|
|
a2c2d41833 | ||
|
|
0e7db7bf39 | ||
|
|
46de4f6a25 | ||
|
|
2acf47a550 | ||
|
|
7fea5c2630 | ||
|
|
b297743521 | ||
|
|
6c33222172 | ||
|
|
9a36a8261a | ||
|
|
1433c77fcc | ||
|
|
b1c3311d50 | ||
|
|
b3e224e481 | ||
|
|
06e2dad45c | ||
|
|
d475f2220f | ||
|
|
10520a2e08 | ||
|
|
05b654d54a | ||
|
|
3c4051c3a5 | ||
|
|
0f3cc1e9e8 | ||
|
|
b9873f7ed8 | ||
|
|
82cd9270fa | ||
|
|
ac6b45b162 | ||
|
|
66a99c0560 | ||
|
|
17e4a32ff4 | ||
|
|
6a430b4da6 | ||
|
|
77ab090bc2 | ||
|
|
fdff4a1afb | ||
|
|
12701cf3dc | ||
|
|
1032625ac8 | ||
|
|
586c2972da | ||
|
|
3d41e41192 | ||
|
|
af8e0cdf45 | ||
|
|
10f6f58ec5 | ||
|
|
fd9f399f41 | ||
|
|
98582edd0b | ||
|
|
07b7cb0afd | ||
|
|
dda9658375 | ||
|
|
358dad533d | ||
|
|
7a63573143 | ||
|
|
333ced5c79 | ||
|
|
c6ceae1283 | ||
|
|
4e8a376720 | ||
|
|
cee348cb3e | ||
|
|
75e56e7aa7 | ||
|
|
d6ae6ffb6b | ||
|
|
12f6547167 | ||
|
|
d1847d2eca | ||
|
|
1f01e6ae47 | ||
|
|
1375601a81 | ||
|
|
e97a8e7cf5 | ||
|
|
3df211301c | ||
|
|
a81dec068c | ||
|
|
4af6716631 | ||
|
|
98f7cb8f3a | ||
|
|
348a67a79b | ||
|
|
a9c128f96b | ||
|
|
bdf1c50c9d | ||
|
|
ccc545b1be | ||
|
|
c6301055fa | ||
|
|
13d9f89a82 | ||
|
|
f5de593f89 | ||
|
|
3b0ec95fba | ||
|
|
0a328090ea | ||
|
|
315cb4f254 | ||
|
|
28f08f02ac | ||
|
|
ad5fabf2e6 | ||
|
|
f8f6db069b | ||
|
|
df620e0302 | ||
|
|
19f2e87528 | ||
|
|
5949e0f6f8 | ||
|
|
617bb16ddb | ||
|
|
83f14f5522 | ||
|
|
b8e22e1c99 | ||
|
|
72d560e407 | ||
|
|
248b2fa2a6 | ||
|
|
563cb297fe | ||
|
|
4c020240e1 | ||
|
|
e070409a95 | ||
|
|
fbbd855145 | ||
|
|
731987b35b | ||
|
|
1e8e7b79f2 | ||
|
|
b512b222dd | ||
|
|
650e3b53fc | ||
|
|
905658ca28 | ||
|
|
b0c91c407d | ||
|
|
d2c68efc0c |
@@ -0,0 +1,30 @@
|
||||
# http://editorconfig.org
|
||||
|
||||
# A special property that should be specified at the top of the file outside of
|
||||
# any sections. Set to true to stop .editor config file search on current file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
# Indentation style
|
||||
# Possible values - tab, space
|
||||
indent_style = space
|
||||
|
||||
# Indentation size in single-spaced characters
|
||||
# Possible values - an integer, tab
|
||||
indent_size = 2
|
||||
|
||||
# Line ending file format
|
||||
# Possible values - lf, crlf, cr
|
||||
end_of_line = lf
|
||||
|
||||
# File character encoding
|
||||
# Possible values - latin1, utf-8, utf-16be, utf-16le
|
||||
charset = utf-8
|
||||
|
||||
# Denotes whether to trim whitespace at the end of lines
|
||||
# Possible values - true, false
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Denotes whether file should end with a newline
|
||||
# Possible values - true, false
|
||||
insert_final_newline = true
|
||||
+6
-51
@@ -1,55 +1,10 @@
|
||||
{
|
||||
"root": true,
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module"
|
||||
"extends": "standard",
|
||||
"env": {
|
||||
"node": true,
|
||||
"mocha": true
|
||||
},
|
||||
"plugins": ["prettier"],
|
||||
"rules": {
|
||||
"no-debugger": ["warn"],
|
||||
"no-regex-spaces": ["error"],
|
||||
"no-unsafe-negation": ["error"],
|
||||
"curly": ["error", "multi-or-nest", "consistent"],
|
||||
"dot-location": ["error", "property"],
|
||||
"dot-notation": ["error"],
|
||||
"eqeqeq": ["error", "smart"],
|
||||
"no-else-return": ["error"],
|
||||
"no-extra-bind": ["error"],
|
||||
"no-extra-label": ["error"],
|
||||
"no-floating-decimal": ["error"],
|
||||
"no-implicit-coercion": ["error", { "allow": ["!!"] }],
|
||||
"wrap-iife": ["error", "inside"],
|
||||
"strict": ["error", "global"],
|
||||
"func-call-spacing": ["error", "never"],
|
||||
"comma-style": ["error", "last"],
|
||||
"keyword-spacing": ["error"],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"new-parens": ["error"],
|
||||
"no-lonely-if": ["error"],
|
||||
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }],
|
||||
"no-whitespace-before-property": ["error"],
|
||||
"semi": ["error", "never"],
|
||||
"arrow-body-style": ["error", "as-needed"],
|
||||
"arrow-parens": ["error", "as-needed"],
|
||||
"arrow-spacing": ["error"],
|
||||
"no-useless-computed-key": ["error"],
|
||||
"no-useless-rename": ["error"],
|
||||
"no-var": ["off"],
|
||||
"prefer-spread": ["off"],
|
||||
"prefer-template": ["error"],
|
||||
"rest-spread-spacing": ["error", "never"],
|
||||
"prefer-const": ["warn", { "destructuring": "all" }],
|
||||
"no-unreachable": ["warn"],
|
||||
"no-unused-vars": ["warn", { "args": "none" }],
|
||||
|
||||
"prettier/prettier": [
|
||||
"warn",
|
||||
{
|
||||
"printWidth": 80,
|
||||
"trailingComma": "none",
|
||||
"singleQuote": false,
|
||||
"semi": false
|
||||
}
|
||||
]
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 8
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ node_modules/*
|
||||
.nyc_output/*
|
||||
wallet-info.txt
|
||||
wallet.json
|
||||
integration-test-sweet.sh
|
||||
|
||||
docs/
|
||||
coverage/
|
||||
|
||||
@@ -35,15 +35,15 @@ const BCHJS = require("@psf/bch-js")
|
||||
let bchjs = new BCHJS() // Defaults to BCHN network.
|
||||
|
||||
// testnet
|
||||
bchjs = new BCHJS({ restURL: 'https://testnet3.fullstack.cash/v3/' })
|
||||
bchjs = new BCHJS({ restURL: 'https://testnet3.fullstack.cash/v4/' })
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
- BCHN Mainnet REST API server: https://bchn.fullstack.cash/v3/
|
||||
- ABC Mainnet REST API server: https://abc.fullstack.cash/v3/
|
||||
- Testnet3 REST API server: https://testnet3.fullstack.cash/v3/
|
||||
- BCHN Mainnet REST API server: https://bchn.fullstack.cash/v4/
|
||||
- ABC Mainnet REST API server: https://abc.fullstack.cash/v4/
|
||||
- Testnet3 REST API server: https://testnet3.fullstack.cash/v4/
|
||||
- Check server status: https://metrics.fullstack.cash
|
||||
|
||||
### API Key
|
||||
|
||||
Generated
+3351
-1291
File diff suppressed because it is too large
Load Diff
+33
-24
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@psf/bch-js",
|
||||
"version": "3.4.0",
|
||||
"version": "4.0.0",
|
||||
"description": "The FullStack.cash JavaScript library for Bitcoin Cash and SLP Tokens",
|
||||
"author": "Chris Troutner <chris.troutner@gmail.com>",
|
||||
"contributors": [
|
||||
@@ -8,19 +8,20 @@
|
||||
],
|
||||
"main": "src/bch-js",
|
||||
"scripts": {
|
||||
"test": "nyc mocha --timeout 30000 test/unit/",
|
||||
"test:integration": "bash test/integration/test-bchn-integration.sh",
|
||||
"test:integration:bchn": "bash test/integration/test-bchn-integration.sh",
|
||||
"test:integration:abc": "RESTURL=https://abc.fullstack.cash/v3/ IS_USING_FREE_TIER=true mocha --timeout 30000 test/integration/",
|
||||
"test:integration:testnet": "IS_USING_FREE_TIER=true mocha --timeout 30000 test/integration/testnet/",
|
||||
"test:integration:local": "RESTURL=http://localhost:3000/v3/ mocha --timeout 30000 test/integration",
|
||||
"test:integration:local:bchn": "RESTURL=http://localhost:3000/v3/ bash test/integration/test-free-tier-bchn.sh",
|
||||
"test:integration:local:testnet": "RESTURL=http://localhost:4000/v3/ mocha --timeout 30000 test/integration/testnet",
|
||||
"test:temp": "mocha --timeout 30000 -g '#Encryption' test/integration/",
|
||||
"test:integration:api": "RESTURL=https://api.fullstack.cash/v3/ mocha --timeout 30000 test/integration",
|
||||
"test": "nyc mocha --trace-warnings --unhandled-rejections=strict --timeout 30000 test/unit/",
|
||||
"test:integration": "npm run test:integration:bchn",
|
||||
"test:integration:abc": "export RESTURL=https://abc.fullstack.cash/v4/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/abc/",
|
||||
"test:integration:bchn": "export RESTURL=https://bchn.fullstack.cash/v4/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
|
||||
"test:integration:testnet": "IS_USING_FREE_TIER=true mocha --timeout 30000 test/integration/chains/testnet/",
|
||||
"test:integration:local": "RESTURL=http://localhost:3000/v4/ mocha --timeout 30000 test/integration",
|
||||
"test:integration:local:bchn": "RESTURL=http://localhost:3000/v4/ mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
|
||||
"test:integration:local:testnet": "RESTURL=http://localhost:4000/v4/ mocha --timeout 30000 test/integration/testnet",
|
||||
"test:temp": "export RESTURL=https://bchn.fullstack.cash/v4/ && mocha --timeout 30000 -g '#tokenUtxoDetails' test/integration/",
|
||||
"test:temp2": "mocha --timeout 30000 -g '#generateSendOpReturn' test/unit/",
|
||||
"coverage": "nyc report --reporter=text-lcov | coveralls",
|
||||
"coverage:report": "nyc --reporter=html mocha --timeout 25000 test/unit/",
|
||||
"docs": "./node_modules/.bin/apidoc -i src/ -o docs"
|
||||
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
|
||||
"lint": "standard --env mocha --fix"
|
||||
},
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/Permissionless-Software-Foundation/bch-js",
|
||||
@@ -31,35 +32,34 @@
|
||||
"dependencies": {
|
||||
"@uppy/core": "^1.10.4",
|
||||
"@uppy/tus": "^1.5.12",
|
||||
"apidoc": "^0.17.7",
|
||||
"apidoc": "^0.25.0",
|
||||
"assert": "^2.0.0",
|
||||
"axios": "^0.19.0",
|
||||
"axios": "^0.21.1",
|
||||
"bc-bip68": "^1.0.5",
|
||||
"bch-wallet-bridge.js": "github:web3bch/bch-wallet-bridge.js#master",
|
||||
"bchaddrjs-slp": "^0.2.5",
|
||||
"bigi": "^1.4.2",
|
||||
"bignumber.js": "^9.0.0",
|
||||
"bip-schnorr": "^0.3.0",
|
||||
"bip21": "Bitcoin-com/bip21",
|
||||
"bip32-utils": "Bitcoin-com/bip32-utils#0.13.1",
|
||||
"@psf/bip21": "^2.0.1",
|
||||
"@psf/bip32-utils": "^0.13.1",
|
||||
"bip38": "^2.0.2",
|
||||
"bip39": "^3.0.2",
|
||||
"bip66": "^1.1.5",
|
||||
"bitcoincash-ops": "christroutner/bitcoincash-ops",
|
||||
"bitcoincashjs-lib": "christroutner/bitcoincashjs-lib#master",
|
||||
"@psf/bitcoincash-ops": "^2.0.0",
|
||||
"@psf/bitcoincashjs-lib": "^4.0.2",
|
||||
"bitcoinjs-message": "^2.0.0",
|
||||
"bs58": "^4.0.1",
|
||||
"buffer": "^5.1.0",
|
||||
"cashaddrjs": "^0.3.3",
|
||||
"chalk": "^2.3.0",
|
||||
"clear": "0.1.0",
|
||||
"coininfo": "Bitcoin-com/coininfo",
|
||||
"@psf/coininfo": "^4.0.0",
|
||||
"commander": "^3.0.0",
|
||||
"cp-file": "^7.0.0",
|
||||
"ecurve": "^1.0.6",
|
||||
"figlet": "^1.2.0",
|
||||
"git-clone": "^0.1.0",
|
||||
"ini": "^1.3.5",
|
||||
"ini": "^1.3.8",
|
||||
"mkdirp": "^0.5.1",
|
||||
"node-cmd": "^3.0.0",
|
||||
"node-emoji": "^1.8.1",
|
||||
@@ -80,18 +80,27 @@
|
||||
"coveralls": "^3.0.2",
|
||||
"eslint": "5.16.0",
|
||||
"eslint-config-prettier": "^6.0.0",
|
||||
"eslint-config-standard": "^14.1.0",
|
||||
"eslint-plugin-node": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^3.1.0",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"husky": "^4.3.6",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"mocha": "^6.1.4",
|
||||
"nock": "^10.0.6",
|
||||
"node-mocks-http": "^1.7.0",
|
||||
"nyc": "^14.1.0",
|
||||
"prettier": "^1.18.2",
|
||||
"semantic-release": "^15.13.19",
|
||||
"sinon": "^7.3.2"
|
||||
"semantic-release": "^17.3.1",
|
||||
"sinon": "^7.3.2",
|
||||
"standard": "^16.0.3"
|
||||
},
|
||||
"apidoc": {
|
||||
"title": "bch-js",
|
||||
"url": "bchjs."
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "npm run lint"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+96
-78
@@ -1,16 +1,33 @@
|
||||
//const axios = require("axios")
|
||||
const Bitcoin = require("bitcoincashjs-lib")
|
||||
const cashaddr = require("cashaddrjs")
|
||||
const coininfo = require("coininfo")
|
||||
// const axios = require("axios")
|
||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
||||
const cashaddr = require('cashaddrjs')
|
||||
const coininfo = require('@psf/coininfo')
|
||||
|
||||
class Address {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
const tmp = {}
|
||||
if (!config || !config.restURL) tmp.restURL = `https://api.bchjs.cash/v3/`
|
||||
if (!config || !config.restURL) tmp.restURL = 'https://api.bchjs.cash/v4/'
|
||||
else tmp.restURL = config.restURL
|
||||
|
||||
this.restURL = tmp.restURL
|
||||
this.apiToken = tmp.apiToken
|
||||
this.authToken = config.authToken
|
||||
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,34 +54,34 @@ class Address {
|
||||
* // mqc1tmwY2368LLGktnePzEyPAsgADxbksi
|
||||
*/
|
||||
// Translate address from any address format into a specific format.
|
||||
toLegacyAddress(address) {
|
||||
toLegacyAddress (address) {
|
||||
const { prefix, type, hash } = this._decode(address)
|
||||
|
||||
let bitcoincash
|
||||
switch (prefix) {
|
||||
case "bitcoincash":
|
||||
case 'bitcoincash':
|
||||
bitcoincash = coininfo.bitcoincash.main
|
||||
break
|
||||
case "bchtest":
|
||||
case 'bchtest':
|
||||
bitcoincash = coininfo.bitcoincash.test
|
||||
break
|
||||
case "bchreg":
|
||||
case 'bchreg':
|
||||
bitcoincash = coininfo.bitcoincash.regtest
|
||||
break
|
||||
default:
|
||||
throw `unsupported prefix : ${prefix}`
|
||||
throw new Error(`unsupported prefix : ${prefix}`)
|
||||
}
|
||||
|
||||
let version
|
||||
switch (type) {
|
||||
case "P2PKH":
|
||||
case 'P2PKH':
|
||||
version = bitcoincash.versions.public
|
||||
break
|
||||
case "P2SH":
|
||||
case 'P2SH':
|
||||
version = bitcoincash.versions.scripthash
|
||||
break
|
||||
default:
|
||||
throw `unsupported address type : ${type}`
|
||||
throw new Error(`unsupported address type : ${type}`)
|
||||
}
|
||||
|
||||
const hashBuf = Buffer.from(hash)
|
||||
@@ -95,11 +112,11 @@ class Address {
|
||||
* bchjs.Address.toCashAddress('msDbtTj7kWXPpYaR7PQmMK84i66fJqQMLx', false)
|
||||
* // qzq9je6pntpva3wf6scr7mlnycr54sjgeqxgrr9ku3
|
||||
*/
|
||||
toCashAddress(address, prefix = true, regtest = false) {
|
||||
toCashAddress (address, prefix = true, regtest = false) {
|
||||
const decoded = this._decode(address)
|
||||
|
||||
let prefixString
|
||||
if (regtest) prefixString = "bchreg"
|
||||
if (regtest) prefixString = 'bchreg'
|
||||
else prefixString = decoded.prefix
|
||||
|
||||
const cashAddress = cashaddr.encode(
|
||||
@@ -109,14 +126,14 @@ class Address {
|
||||
)
|
||||
|
||||
if (prefix) return cashAddress
|
||||
return cashAddress.split(":")[1]
|
||||
return cashAddress.split(':')[1]
|
||||
}
|
||||
|
||||
// Converts any address format to hash160
|
||||
toHash160(address) {
|
||||
toHash160 (address) {
|
||||
const legacyAddress = this.toLegacyAddress(address)
|
||||
const bytes = Bitcoin.address.fromBase58Check(legacyAddress)
|
||||
return bytes.hash.toString("hex")
|
||||
return bytes.hash.toString('hex')
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,8 +156,8 @@ class Address {
|
||||
* // mhTg9sgNgvAGfmJs192oUzQWqAXHH5nqLE
|
||||
*/
|
||||
// Converts hash160 to Legacy Address
|
||||
hash160ToLegacy(hash160, network = Bitcoin.networks.bitcoin.pubKeyHash) {
|
||||
const buffer = Buffer.from(hash160, "hex")
|
||||
hash160ToLegacy (hash160, network = Bitcoin.networks.bitcoin.pubKeyHash) {
|
||||
const buffer = Buffer.from(hash160, 'hex')
|
||||
const legacyAddress = Bitcoin.address.toBase58Check(buffer, network)
|
||||
return legacyAddress
|
||||
}
|
||||
@@ -160,7 +177,7 @@ class Address {
|
||||
* 'bchtest:qq24rpar9qas3vc9r8d4p0prhwaf7jmx2u22nzt946'
|
||||
*/
|
||||
// Converts hash160 to Cash Address
|
||||
hash160ToCash(
|
||||
hash160ToCash (
|
||||
hash160,
|
||||
network = Bitcoin.networks.bitcoin.pubKeyHash,
|
||||
regtest = false
|
||||
@@ -169,7 +186,7 @@ class Address {
|
||||
return this.toCashAddress(legacyAddress, true, regtest)
|
||||
}
|
||||
|
||||
_decode(address) {
|
||||
_decode (address) {
|
||||
try {
|
||||
return this._decodeLegacyAddress(address)
|
||||
} catch (error) {}
|
||||
@@ -185,56 +202,56 @@ class Address {
|
||||
throw new Error(`Unsupported address format : ${address}`)
|
||||
}
|
||||
|
||||
_decodeLegacyAddress(address) {
|
||||
_decodeLegacyAddress (address) {
|
||||
const { version, hash } = Bitcoin.address.fromBase58Check(address)
|
||||
const info = coininfo.bitcoincash
|
||||
|
||||
switch (version) {
|
||||
case info.main.versions.public:
|
||||
return {
|
||||
prefix: "bitcoincash",
|
||||
type: "P2PKH",
|
||||
prefix: 'bitcoincash',
|
||||
type: 'P2PKH',
|
||||
hash: hash,
|
||||
format: "legacy"
|
||||
format: 'legacy'
|
||||
}
|
||||
case info.main.versions.scripthash:
|
||||
return {
|
||||
prefix: "bitcoincash",
|
||||
type: "P2SH",
|
||||
prefix: 'bitcoincash',
|
||||
type: 'P2SH',
|
||||
hash: hash,
|
||||
format: "legacy"
|
||||
format: 'legacy'
|
||||
}
|
||||
case info.test.versions.public:
|
||||
return {
|
||||
prefix: "bchtest",
|
||||
type: "P2PKH",
|
||||
prefix: 'bchtest',
|
||||
type: 'P2PKH',
|
||||
hash: hash,
|
||||
format: "legacy"
|
||||
format: 'legacy'
|
||||
}
|
||||
case info.test.versions.scripthash:
|
||||
return {
|
||||
prefix: "bchtest",
|
||||
type: "P2SH",
|
||||
prefix: 'bchtest',
|
||||
type: 'P2SH',
|
||||
hash: hash,
|
||||
format: "legacy"
|
||||
format: 'legacy'
|
||||
}
|
||||
default:
|
||||
throw new Error(`Invalid format : ${address}`)
|
||||
}
|
||||
}
|
||||
|
||||
_decodeCashAddress(address) {
|
||||
if (address.indexOf(":") !== -1) {
|
||||
_decodeCashAddress (address) {
|
||||
if (address.indexOf(':') !== -1) {
|
||||
const decoded = cashaddr.decode(address)
|
||||
decoded.format = "cashaddr"
|
||||
decoded.format = 'cashaddr'
|
||||
return decoded
|
||||
}
|
||||
|
||||
const prefixes = ["bitcoincash", "bchtest", "bchreg"]
|
||||
const prefixes = ['bitcoincash', 'bchtest', 'bchreg']
|
||||
for (let i = 0; i < prefixes.length; ++i) {
|
||||
try {
|
||||
const decoded = cashaddr.decode(`${prefixes[i]}:${address}`)
|
||||
decoded.format = "cashaddr"
|
||||
decoded.format = 'cashaddr'
|
||||
return decoded
|
||||
} catch (error) {}
|
||||
}
|
||||
@@ -242,12 +259,12 @@ class Address {
|
||||
throw new Error(`Invalid format : ${address}`)
|
||||
}
|
||||
|
||||
_encodeAddressFromHash160(address) {
|
||||
_encodeAddressFromHash160 (address) {
|
||||
try {
|
||||
return {
|
||||
legacyAddress: this.hash160ToLegacy(address),
|
||||
cashAddress: this.hash160ToCash(address),
|
||||
format: "hash160"
|
||||
format: 'hash160'
|
||||
}
|
||||
} catch (error) {}
|
||||
|
||||
@@ -286,8 +303,8 @@ class Address {
|
||||
* // true
|
||||
*/
|
||||
// Test for address format.
|
||||
isLegacyAddress(address) {
|
||||
return this.detectAddressFormat(address) === "legacy"
|
||||
isLegacyAddress (address) {
|
||||
return this.detectAddressFormat(address) === 'legacy'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,8 +338,8 @@ class Address {
|
||||
* bchjs.Address.isCashAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
|
||||
* // false
|
||||
*/
|
||||
isCashAddress(address) {
|
||||
return this.detectAddressFormat(address) === "cashaddr"
|
||||
isCashAddress (address) {
|
||||
return this.detectAddressFormat(address) === 'cashaddr'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -340,8 +357,8 @@ class Address {
|
||||
* bchjs.Address.isHash160(notHash160Address);
|
||||
* // false
|
||||
*/
|
||||
isHash160(address) {
|
||||
return this.detectAddressFormat(address) === "hash160"
|
||||
isHash160 (address) {
|
||||
return this.detectAddressFormat(address) === 'hash160'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -376,11 +393,11 @@ class Address {
|
||||
* // false
|
||||
*/
|
||||
// Test for address network.
|
||||
isMainnetAddress(address) {
|
||||
if (address[0] === "x") return true
|
||||
else if (address[0] === "t") return false
|
||||
isMainnetAddress (address) {
|
||||
if (address[0] === 'x') return true
|
||||
else if (address[0] === 't') return false
|
||||
|
||||
return this.detectAddressNetwork(address) === "mainnet"
|
||||
return this.detectAddressNetwork(address) === 'mainnet'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -414,11 +431,11 @@ class Address {
|
||||
* bchjs.Address.isTestnetAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
|
||||
* // true
|
||||
*/
|
||||
isTestnetAddress(address) {
|
||||
if (address[0] === "x") return false
|
||||
else if (address[0] === "t") return true
|
||||
isTestnetAddress (address) {
|
||||
if (address[0] === 'x') return false
|
||||
else if (address[0] === 't') return true
|
||||
|
||||
return this.detectAddressNetwork(address) === "testnet"
|
||||
return this.detectAddressNetwork(address) === 'testnet'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -456,8 +473,8 @@ class Address {
|
||||
* bchjs.Address.isRegTestAddress('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggt9t0a6zy')
|
||||
* // false
|
||||
*/
|
||||
isRegTestAddress(address) {
|
||||
return this.detectAddressNetwork(address) === "regtest"
|
||||
isRegTestAddress (address) {
|
||||
return this.detectAddressNetwork(address) === 'regtest'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -493,8 +510,8 @@ class Address {
|
||||
*/
|
||||
|
||||
// Test for address type.
|
||||
isP2PKHAddress(address) {
|
||||
return this.detectAddressType(address) === "p2pkh"
|
||||
isP2PKHAddress (address) {
|
||||
return this.detectAddressType(address) === 'p2pkh'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -529,8 +546,8 @@ class Address {
|
||||
* // false
|
||||
*/
|
||||
|
||||
isP2SHAddress(address) {
|
||||
return this.detectAddressType(address) === "p2sh"
|
||||
isP2SHAddress (address) {
|
||||
return this.detectAddressType(address) === 'p2sh'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -565,7 +582,7 @@ class Address {
|
||||
* // legacy
|
||||
*/
|
||||
// Detect address format.
|
||||
detectAddressFormat(address) {
|
||||
detectAddressFormat (address) {
|
||||
const decoded = this._decode(address)
|
||||
|
||||
return decoded.format
|
||||
@@ -603,19 +620,19 @@ class Address {
|
||||
* // testnet
|
||||
*/
|
||||
// Detect address network.
|
||||
detectAddressNetwork(address) {
|
||||
if (address[0] === "x") return "mainnet"
|
||||
else if (address[0] === "t") return "testnet"
|
||||
detectAddressNetwork (address) {
|
||||
if (address[0] === 'x') return 'mainnet'
|
||||
else if (address[0] === 't') return 'testnet'
|
||||
|
||||
const decoded = this._decode(address)
|
||||
|
||||
switch (decoded.prefix) {
|
||||
case "bitcoincash":
|
||||
return "mainnet"
|
||||
case "bchtest":
|
||||
return "testnet"
|
||||
case "bchreg":
|
||||
return "regtest"
|
||||
case 'bitcoincash':
|
||||
return 'mainnet'
|
||||
case 'bchtest':
|
||||
return 'testnet'
|
||||
case 'bchreg':
|
||||
return 'regtest'
|
||||
default:
|
||||
throw new Error(`Invalid prefix : ${decoded.prefix}`)
|
||||
}
|
||||
@@ -653,7 +670,7 @@ class Address {
|
||||
* // p2pkh
|
||||
*/
|
||||
// Detect address type.
|
||||
detectAddressType(address) {
|
||||
detectAddressType (address) {
|
||||
const decoded = this._decode(address)
|
||||
|
||||
return decoded.type.toLowerCase()
|
||||
@@ -688,7 +705,7 @@ class Address {
|
||||
* // bchtest:qzd7dvlnfukggjqsf5ju0qqwwltakfumjsck33js6m
|
||||
* // bchtest:qq322ataqeas4n0pdn4gz2sdereh5ae43ylk4qdvus
|
||||
*/
|
||||
fromXPub(xpub, path = "0/0") {
|
||||
fromXPub (xpub, path = '0/0') {
|
||||
const HDNode = Bitcoin.HDNode.fromBase58(
|
||||
xpub,
|
||||
Bitcoin.networks[this.detectAddressNetwork(xpub)]
|
||||
@@ -721,12 +738,13 @@ class Address {
|
||||
* bchjs.Address.fromOutputScript(scriptPubKey, 'testnet');
|
||||
* // bchtest:pz0qcslrqn7hr44hsszwl4lw5r6udkg6zqh2hmtpyr
|
||||
*/
|
||||
fromOutputScript(scriptPubKey, network = "mainnet") {
|
||||
fromOutputScript (scriptPubKey, network = 'mainnet') {
|
||||
let netParam
|
||||
if (network !== "bitcoincash" && network !== "mainnet")
|
||||
if (network !== 'bitcoincash' && network !== 'mainnet') {
|
||||
netParam = Bitcoin.networks.testnet
|
||||
}
|
||||
|
||||
const regtest = network === "bchreg"
|
||||
const regtest = network === 'bchreg'
|
||||
|
||||
return this.toCashAddress(
|
||||
Bitcoin.address.fromOutputScript(scriptPubKey, netParam),
|
||||
|
||||
+45
-125
@@ -7,64 +7,67 @@
|
||||
*/
|
||||
|
||||
// bch-api mainnet.
|
||||
// const DEFAULT_REST_API = "https://api.bchjs.cash/v3/"
|
||||
const DEFAULT_REST_API = "https://api.fullstack.cash/v3/"
|
||||
const DEFAULT_REST_API = 'https://api.fullstack.cash/v4/'
|
||||
// const DEFAULT_REST_API = "http://localhost:3000/v4/"
|
||||
|
||||
// local deps
|
||||
const BitcoinCash = require("./bitcoincash")
|
||||
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 Socket = require("./socket")
|
||||
const Wallet = require("./wallet")
|
||||
const Schnorr = require("./schnorr")
|
||||
const SLP = require("./slp/slp")
|
||||
const IPFS = require("./ipfs")
|
||||
const Encryption = require("./encryption")
|
||||
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 Socket = require('./socket')
|
||||
const Schnorr = require('./schnorr')
|
||||
const SLP = require('./slp/slp')
|
||||
const IPFS = require('./ipfs')
|
||||
const Encryption = require('./encryption')
|
||||
|
||||
// Indexers
|
||||
const Blockbook = require("./blockbook")
|
||||
const OpenBazaar = require("./openbazaar")
|
||||
const Ninsight = require("./ninsight")
|
||||
const Electrumx = require("./electrumx")
|
||||
const OpenBazaar = require('./openbazaar')
|
||||
const Ninsight = require('./ninsight')
|
||||
const Electrumx = require('./electrumx')
|
||||
|
||||
class BCHJS {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
// Try to retrieve the REST API URL from different sources.
|
||||
if (config && config.restURL && config.restURL !== "")
|
||||
this.restURL = config.restURL
|
||||
else if (process.env.RESTURL && process.env.RESTURL !== "")
|
||||
this.restURL = process.env.RESTURL
|
||||
else this.restURL = DEFAULT_REST_API
|
||||
if (config && config.restURL && config.restURL !== '') { this.restURL = config.restURL } else if (process.env.RESTURL && process.env.RESTURL !== '') { 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
|
||||
this.apiToken = '' // default value.
|
||||
if (config && config.apiToken && config.apiToken !== '') { this.apiToken = config.apiToken } else if (process.env.BCHJSTOKEN && process.env.BCHJSTOKEN !== '') { this.apiToken = process.env.BCHJSTOKEN }
|
||||
|
||||
// Retrieve the Basic Authentication password.
|
||||
this.authPass = '' // default value.
|
||||
if (config && config.authPass && config.authPass !== '') { this.authPass = config.authPass } else if (process.env.BCHJSAUTHPASS && process.env.BCHJSAUTHPASS !== '') { this.authPass = process.env.BCHJSAUTHPASS }
|
||||
|
||||
// Generate a Basic Authentication token from an auth password
|
||||
this.authToken = ''
|
||||
if (this.authPass) {
|
||||
// console.log(`bch-js initialized with authPass: ${this.authPass}`)
|
||||
// Generate the header for Basic Authentication.
|
||||
const combined = `fullstackcash:${this.authPass}`
|
||||
const base64Credential = Buffer.from(combined).toString('base64')
|
||||
this.authToken = `Basic ${base64Credential}`
|
||||
}
|
||||
|
||||
const libConfig = {
|
||||
restURL: this.restURL,
|
||||
apiToken: this.apiToken
|
||||
apiToken: this.apiToken,
|
||||
authToken: this.authToken
|
||||
}
|
||||
|
||||
// console.log(`apiToken: ${this.apiToken}`)
|
||||
|
||||
// Populate Blockbook endpoints.
|
||||
this.Blockbook = new Blockbook(libConfig)
|
||||
|
||||
// Populate OpenBazaar endpoints
|
||||
this.OpenBazaar = new OpenBazaar(libConfig)
|
||||
|
||||
@@ -96,7 +99,6 @@ class BCHJS {
|
||||
this.TransactionBuilder.setAddress(this.Address)
|
||||
this.Util = new Util(libConfig)
|
||||
this.Socket = Socket
|
||||
this.Wallet = Wallet
|
||||
this.Schnorr = new Schnorr(libConfig)
|
||||
|
||||
this.SLP = new SLP(libConfig)
|
||||
@@ -104,88 +106,6 @@ class BCHJS {
|
||||
|
||||
this.IPFS = new IPFS()
|
||||
}
|
||||
|
||||
static BitboxShim() {
|
||||
return BitboxShim
|
||||
}
|
||||
}
|
||||
|
||||
// Creat a shim so that all the endpoints match BITBOX SDK and this library
|
||||
// can be used as a drop-in replacement for BITBOX.
|
||||
class BitboxShim {
|
||||
constructor(config) {
|
||||
// Try to retrieve the REST API URL from different sources.
|
||||
if (config && config.restURL && config.restURL !== "")
|
||||
this.restURL = config.restURL
|
||||
else if (process.env.RESTURL && process.env.RESTURL !== "")
|
||||
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
|
||||
|
||||
const libConfig = {
|
||||
restURL: this.restURL,
|
||||
apiToken: this.apiToken
|
||||
}
|
||||
|
||||
// Populate utility functions
|
||||
this.Address = new Address(libConfig)
|
||||
this.BitcoinCash = new BitcoinCash(this.Address)
|
||||
this.Blockchain = new Blockchain(libConfig)
|
||||
this.Crypto = Crypto
|
||||
this.ECPair = ECPair
|
||||
this.ECPair.setAddress(this.Address)
|
||||
this.Generating = new Generating(libConfig)
|
||||
this.HDNode = new HDNode(this.Address)
|
||||
this.Mnemonic = new Mnemonic(this.Address)
|
||||
this.Price = new Price()
|
||||
this.Script = new Script()
|
||||
this.TransactionBuilder = TransactionBuilder
|
||||
this.TransactionBuilder.setAddress(this.Address)
|
||||
this.Util = new Util(libConfig)
|
||||
this.Socket = Socket
|
||||
this.Wallet = Wallet
|
||||
this.Schnorr = new Schnorr(libConfig)
|
||||
|
||||
// Populate the SLP endpoints.
|
||||
this.SLP = new SLP(libConfig)
|
||||
this.Address = this.SLP.Address
|
||||
|
||||
this.ECPair.toSLPAddress = this.SLP.ECPair.toSLPAddress
|
||||
|
||||
this.Util.list = this.SLP.Utils.list
|
||||
this.Util.balancesForAddress = this.SLP.Utils.balancesForAddress
|
||||
this.Util.balancesForToken = this.SLP.Utils.balancesForToken
|
||||
this.Util.balance = this.SLP.Utils.balance
|
||||
this.Util.validateTxid = this.SLP.Utils.validateTxid
|
||||
this.Util.tokenStats = this.SLP.Utils.tokenStats
|
||||
this.Util.transactions = this.SLP.Utils.transactions
|
||||
this.Util.burnTotal = this.SLP.Utils.burnTotal
|
||||
this.Util.decodeOpReturn = this.SLP.Utils.decodeOpReturn
|
||||
this.Util.isTokenUtxo = this.SLP.Utils.isTokenUtxo
|
||||
this.Util.tokenUtxoDetails = this.SLP.Utils.tokenUtxoDetails
|
||||
this.Util.txDetails = this.SLP.Utils.txDetails
|
||||
|
||||
// Populate Full Node
|
||||
this.Control = new Control(libConfig)
|
||||
this.Mining = new Mining(libConfig)
|
||||
this.RawTransactions = new RawTransactions(libConfig)
|
||||
|
||||
// Populate Blockbook endpoints.
|
||||
this.Blockbook = new Blockbook(libConfig)
|
||||
|
||||
// Populate OpenBazaar endpoints
|
||||
this.OpenBazaar = new OpenBazaar(libConfig)
|
||||
|
||||
// Bitcoin.com Ninsight indexer
|
||||
this.Ninsight = new Ninsight()
|
||||
this.Electrumx = new Electrumx(libConfig)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BCHJS
|
||||
|
||||
+40
-40
@@ -1,16 +1,16 @@
|
||||
const Bitcoin = require("bitcoincashjs-lib")
|
||||
const sb = require("satoshi-bitcoin")
|
||||
const bitcoinMessage = require("bitcoinjs-message")
|
||||
const bs58 = require("bs58")
|
||||
const bip21 = require("bip21")
|
||||
const coininfo = require("coininfo")
|
||||
const bip38 = require("bip38")
|
||||
const wif = require("wif")
|
||||
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
|
||||
const Buffer = require('safe-buffer').Buffer
|
||||
|
||||
class BitcoinCash {
|
||||
constructor(address) {
|
||||
constructor (address) {
|
||||
this._address = address
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ class BitcoinCash {
|
||||
* // 50700000000
|
||||
*/
|
||||
// Translate coins to satoshi value
|
||||
toSatoshi(coins) {
|
||||
toSatoshi (coins) {
|
||||
return sb.toSatoshi(coins)
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ class BitcoinCash {
|
||||
* // 507
|
||||
*/
|
||||
// Translate satoshi to coin value
|
||||
toBitcoinCash(satoshis) {
|
||||
toBitcoinCash (satoshis) {
|
||||
return sb.toBitcoin(satoshis)
|
||||
}
|
||||
|
||||
@@ -105,13 +105,13 @@ class BitcoinCash {
|
||||
* // 0.123
|
||||
*/
|
||||
// Translate satoshi to bits denomination
|
||||
toBits(satoshis) {
|
||||
toBits (satoshis) {
|
||||
return parseFloat(satoshis) / 100
|
||||
}
|
||||
|
||||
// Translate satoshi to bits denomination
|
||||
// TODO remove in 2.0
|
||||
satsToBits(satoshis) {
|
||||
satsToBits (satoshis) {
|
||||
return parseFloat(satoshis) / 100
|
||||
}
|
||||
|
||||
@@ -147,10 +147,10 @@ class BitcoinCash {
|
||||
* // IIYVhlo2Z6TWFjYX1+YM+7vQKz0m+zYdSe4eYpFLuAQDEZXqll7lZC8Au22VI2LLP5x+IerZckVk3QQPsA3e8/8=
|
||||
*/
|
||||
// sign message
|
||||
signMessageWithPrivKey(privateKeyWIF, message) {
|
||||
const network = privateKeyWIF.charAt(0) === "c" ? "testnet" : "mainnet"
|
||||
signMessageWithPrivKey (privateKeyWIF, message) {
|
||||
const network = privateKeyWIF.charAt(0) === 'c' ? 'testnet' : 'mainnet'
|
||||
let bitcoincash
|
||||
if (network === "mainnet") bitcoincash = coininfo.bitcoincash.main
|
||||
if (network === 'mainnet') bitcoincash = coininfo.bitcoincash.main
|
||||
else bitcoincash = coininfo.bitcoincash.test
|
||||
|
||||
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
|
||||
@@ -161,7 +161,7 @@ class BitcoinCash {
|
||||
const privateKey = keyPair.d.toBuffer(32)
|
||||
return bitcoinMessage
|
||||
.sign(message, privateKey, keyPair.compressed)
|
||||
.toString("base64")
|
||||
.toString('base64')
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,7 +180,7 @@ class BitcoinCash {
|
||||
* // true
|
||||
*/
|
||||
// verify message
|
||||
verifyMessage(address, signature, message) {
|
||||
verifyMessage (address, signature, message) {
|
||||
return bitcoinMessage.verify(
|
||||
message,
|
||||
this._address.toLegacyAddress(address),
|
||||
@@ -222,8 +222,8 @@ class BitcoinCash {
|
||||
* // 1Ly4gqPddveYHMNkfjoXHanVszXpD3duKg
|
||||
*/
|
||||
// encode base58Check
|
||||
encodeBase58Check(hex) {
|
||||
return bs58.encode(Buffer.from(hex, "hex"))
|
||||
encodeBase58Check (hex) {
|
||||
return bs58.encode(Buffer.from(hex, 'hex'))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,8 +260,8 @@ class BitcoinCash {
|
||||
* // 00db04c2e6f104997cb04c956bf25da6078e559d303127f08b
|
||||
*/
|
||||
// decode base58Check
|
||||
decodeBase58Check(address) {
|
||||
return bs58.decode(address).toString("hex")
|
||||
decodeBase58Check (address) {
|
||||
return bs58.decode(address).toString('hex')
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,7 +298,7 @@ class BitcoinCash {
|
||||
* // bitcoincash:qzw6tfrh8p0jh834uf9rhg77pjg5rgnt3qw0e54u03?amount=42&label=no%20prefix
|
||||
*/
|
||||
// encode bip21 url
|
||||
encodeBIP21(address, options, regtest = false) {
|
||||
encodeBIP21 (address, options, regtest = false) {
|
||||
return bip21.encode(
|
||||
this._address.toCashAddress(address, true, regtest),
|
||||
options
|
||||
@@ -335,7 +335,7 @@ class BitcoinCash {
|
||||
* // { address: 'qzw6tfrh8p0jh834uf9rhg77pjg5rgnt3qw0e54u03', options: { amount: 42, label: 'no prefix' } }
|
||||
*/
|
||||
// decode bip21 url
|
||||
decodeBIP21(url) {
|
||||
decodeBIP21 (url) {
|
||||
return bip21.decode(url)
|
||||
}
|
||||
|
||||
@@ -405,19 +405,19 @@ class BitcoinCash {
|
||||
* bchjs.BitcoinCash.getByteCount(inputs, outputs)
|
||||
* // 1780
|
||||
*/
|
||||
getByteCount(inputs, outputs) {
|
||||
getByteCount (inputs, outputs) {
|
||||
// from https://github.com/bitcoinjs/bitcoinjs-lib/issues/921#issuecomment-354394004
|
||||
let totalWeight = 0
|
||||
let hasWitness = false
|
||||
// assumes compressed pubkeys in all cases.
|
||||
const types = {
|
||||
inputs: {
|
||||
"MULTISIG-P2SH": 49 * 4,
|
||||
"MULTISIG-P2WSH": 6 + 41 * 4,
|
||||
"MULTISIG-P2SH-P2WSH": 6 + 76 * 4,
|
||||
'MULTISIG-P2SH': 49 * 4,
|
||||
'MULTISIG-P2WSH': 6 + 41 * 4,
|
||||
'MULTISIG-P2SH-P2WSH': 6 + 76 * 4,
|
||||
P2PKH: 148 * 4,
|
||||
P2WPKH: 108 + 41 * 4,
|
||||
"P2SH-P2WPKH": 108 + 64 * 4
|
||||
'P2SH-P2WPKH': 108 + 64 * 4
|
||||
},
|
||||
outputs: {
|
||||
P2SH: 32 * 4,
|
||||
@@ -427,26 +427,26 @@ class BitcoinCash {
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(inputs).forEach(function(key) {
|
||||
if (key.slice(0, 8) === "MULTISIG") {
|
||||
Object.keys(inputs).forEach(function (key) {
|
||||
if (key.slice(0, 8) === 'MULTISIG') {
|
||||
// ex. "MULTISIG-P2SH:2-3" would mean 2 of 3 P2SH MULTISIG
|
||||
const keyParts = key.split(":")
|
||||
const keyParts = key.split(':')
|
||||
if (keyParts.length !== 2) throw new Error(`invalid input: ${key}`)
|
||||
const newKey = keyParts[0]
|
||||
const mAndN = keyParts[1].split("-").map(function(item) {
|
||||
const mAndN = keyParts[1].split('-').map(function (item) {
|
||||
return parseInt(item)
|
||||
})
|
||||
|
||||
totalWeight += types.inputs[newKey] * inputs[key]
|
||||
const multiplyer = newKey === "MULTISIG-P2SH" ? 4 : 1
|
||||
const multiplyer = newKey === 'MULTISIG-P2SH' ? 4 : 1
|
||||
totalWeight += (73 * mAndN[0] + 34 * mAndN[1]) * multiplyer
|
||||
} else {
|
||||
totalWeight += types.inputs[key] * inputs[key]
|
||||
}
|
||||
if (key.indexOf("W") >= 0) hasWitness = true
|
||||
if (key.indexOf('W') >= 0) hasWitness = true
|
||||
})
|
||||
|
||||
Object.keys(outputs).forEach(function(key) {
|
||||
Object.keys(outputs).forEach(function (key) {
|
||||
totalWeight += types.outputs[key] * outputs[key]
|
||||
})
|
||||
|
||||
@@ -479,7 +479,7 @@ class BitcoinCash {
|
||||
* )
|
||||
* // 6PYUAPLwLSEjWSAfoe9NTSPkMZXnJA8j8EFJtKaeSnP18RCouutBrS2735
|
||||
*/
|
||||
encryptBIP38(privKeyWIF, passphrase) {
|
||||
encryptBIP38 (privKeyWIF, passphrase) {
|
||||
const decoded = wif.decode(privKeyWIF)
|
||||
|
||||
return bip38.encrypt(decoded.privateKey, decoded.compressed, passphrase)
|
||||
@@ -509,10 +509,10 @@ class BitcoinCash {
|
||||
* )
|
||||
* // cSx7KzdH9EcvDEireu2WYpGnXdFYpta7sJUNt5kVCJgA7kcAU8Gm
|
||||
*/
|
||||
decryptBIP38(encryptedKey, passphrase, network = "mainnet") {
|
||||
decryptBIP38 (encryptedKey, passphrase, network = 'mainnet') {
|
||||
const decryptedKey = bip38.decrypt(encryptedKey, passphrase)
|
||||
let prefix
|
||||
if (network === "testnet") prefix = 0xef
|
||||
if (network === 'testnet') prefix = 0xef
|
||||
else prefix = 0x80
|
||||
|
||||
return wif.encode(prefix, decryptedKey.privateKey, decryptedKey.compressed)
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
This library interacts with the REST API endpoints in bch-api that communicate
|
||||
with the Blockbook API.
|
||||
|
||||
CT 11/10/20
|
||||
These endpoints will be soon be deprecated. Blockbook is being fazed out in
|
||||
favor of Fulcrum.
|
||||
*/
|
||||
|
||||
const axios = require("axios")
|
||||
|
||||
let _this
|
||||
|
||||
class Blockbook {
|
||||
constructor(config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
// console.log(`Blockbook apiToken: ${this.apiToken}`)
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
}
|
||||
|
||||
async balance(address) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === "string") {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockbook/balance/${address}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
|
||||
// Handle array of addresses.
|
||||
} else if (Array.isArray(address)) {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}blockbook/balance`,
|
||||
{
|
||||
addresses: address
|
||||
},
|
||||
_this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input address must be a string or array of strings.`)
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async utxo(address) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === "string") {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockbook/utxos/${address}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
|
||||
// Handle array of addresses.
|
||||
} else if (Array.isArray(address)) {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}blockbook/utxos`,
|
||||
{
|
||||
addresses: address
|
||||
},
|
||||
_this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input address must be a string or array of strings.`)
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async tx(txid) {
|
||||
try {
|
||||
// Handle single txid.
|
||||
if (typeof txid === "string") {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockbook/tx/${txid}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
|
||||
// Handle array of addresses.
|
||||
} else if (Array.isArray(txid)) {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}blockbook/tx`,
|
||||
{
|
||||
txids: txid
|
||||
},
|
||||
_this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input txid must be a string or array of strings.`)
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Blockbook
|
||||
+57
-45
@@ -3,19 +3,29 @@
|
||||
- Add blockhash functionality back into getTxOutProof
|
||||
*/
|
||||
|
||||
const axios = require("axios")
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
|
||||
class Blockchain {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.authToken = config.authToken
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +50,7 @@ class Blockchain {
|
||||
* })()
|
||||
* // 241decef88889efac8e6ce428a8ac696fdde5972eceed97e1fb58d6106af31d5
|
||||
*/
|
||||
async getBestBlockHash() {
|
||||
async getBestBlockHash () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getBestBlockHash`,
|
||||
@@ -88,7 +98,7 @@ class Blockchain {
|
||||
* // previousblockhash: '0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d',
|
||||
* // nextblockhash: '00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6' }
|
||||
*/
|
||||
async getBlock(blockhash, verbose = true) {
|
||||
async getBlock (blockhash, verbose = true) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getBlock/${blockhash}?verbose=${verbose}`,
|
||||
@@ -138,7 +148,7 @@ class Blockchain {
|
||||
* // timeout: 1493596800,
|
||||
* // since: 419328 } } }
|
||||
*/
|
||||
async getBlockchainInfo() {
|
||||
async getBlockchainInfo () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getBlockchainInfo`,
|
||||
@@ -169,7 +179,7 @@ class Blockchain {
|
||||
* })()
|
||||
* // 529235
|
||||
*/
|
||||
async getBlockCount() {
|
||||
async getBlockCount () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getBlockCount`,
|
||||
@@ -200,8 +210,8 @@ class Blockchain {
|
||||
* })()
|
||||
* // [ '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f' ]
|
||||
*/
|
||||
async getBlockHash(height = 1) {
|
||||
if (typeof height !== "string") height = JSON.stringify(height)
|
||||
async getBlockHash (height = 1) {
|
||||
if (typeof height !== 'string') height = JSON.stringify(height)
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
@@ -247,10 +257,10 @@ class Blockchain {
|
||||
* // previousblockhash: '0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d',
|
||||
* // nextblockhash: '00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6' }]
|
||||
*/
|
||||
async getBlockHeader(hash, verbose = true) {
|
||||
async getBlockHeader (hash, verbose = true) {
|
||||
try {
|
||||
// Handle single hash.
|
||||
if (typeof hash === "string") {
|
||||
if (typeof hash === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getBlockHeader/${hash}?verbose=${verbose}`,
|
||||
_this.axiosOptions
|
||||
@@ -273,7 +283,7 @@ class Blockchain {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input hash must be a string or array of strings.`)
|
||||
throw new Error('Input hash must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -310,7 +320,7 @@ class Blockchain {
|
||||
* // branchlen: 1,
|
||||
* // status: 'valid-headers' } ]
|
||||
*/
|
||||
async getChainTips() {
|
||||
async getChainTips () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getChainTips`,
|
||||
@@ -342,7 +352,7 @@ class Blockchain {
|
||||
*
|
||||
* // 702784497476.8376
|
||||
*/
|
||||
async getDifficulty() {
|
||||
async getDifficulty () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getDifficulty`,
|
||||
@@ -356,8 +366,8 @@ class Blockchain {
|
||||
}
|
||||
|
||||
// getMempoolAncestors
|
||||
async getMempoolAncestors(txid, verbose = false) {
|
||||
if (typeof txid !== "string") txid = JSON.stringify(txid)
|
||||
async getMempoolAncestors (txid, verbose = false) {
|
||||
if (typeof txid !== 'string') txid = JSON.stringify(txid)
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
@@ -371,8 +381,8 @@ class Blockchain {
|
||||
}
|
||||
}
|
||||
|
||||
async getMempoolDescendants(txid, verbose = false) {
|
||||
if (typeof txid !== "string") txid = JSON.stringify(txid)
|
||||
async getMempoolDescendants (txid, verbose = false) {
|
||||
if (typeof txid !== 'string') txid = JSON.stringify(txid)
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
@@ -467,11 +477,11 @@ class Blockchain {
|
||||
* // }
|
||||
* // ]
|
||||
*/
|
||||
async getMempoolEntry(txid) {
|
||||
//if (typeof txid !== "string") txid = JSON.stringify(txid)
|
||||
async getMempoolEntry (txid) {
|
||||
// if (typeof txid !== "string") txid = JSON.stringify(txid)
|
||||
|
||||
try {
|
||||
if (typeof txid === "string") {
|
||||
if (typeof txid === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getMempoolEntry/${txid}`,
|
||||
_this.axiosOptions
|
||||
@@ -491,7 +501,7 @@ class Blockchain {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input must be a string or array of strings.`)
|
||||
throw new Error('Input must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -521,7 +531,7 @@ class Blockchain {
|
||||
* // maxmempool: 300000000,
|
||||
* // mempoolminfee: 0 }
|
||||
*/
|
||||
async getMempoolInfo() {
|
||||
async getMempoolInfo () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getMempoolInfo`,
|
||||
@@ -568,7 +578,7 @@ class Blockchain {
|
||||
* // depends:
|
||||
* // [ 'e25682caafc7000645d59f4c11d8d594b2943979b9d8fafb9f946e2b35c21b7e' ] },]
|
||||
*/
|
||||
async getRawMempool(verbose = false) {
|
||||
async getRawMempool (verbose = false) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getRawMempool?vebose=${verbose}`,
|
||||
@@ -600,20 +610,22 @@ class Blockchain {
|
||||
*
|
||||
* // null
|
||||
*/
|
||||
async getTxOut(txid, n, include_mempool = true) {
|
||||
async getTxOut (txid, n, includeMempool = true) {
|
||||
try {
|
||||
// Input validation
|
||||
if (typeof txid !== "string" || txid.length !== 64)
|
||||
throw new Error(`txid needs to be a proper transaction ID`)
|
||||
if (typeof txid !== 'string' || txid.length !== 64) {
|
||||
throw new Error('txid needs to be a proper transaction ID')
|
||||
}
|
||||
|
||||
if (isNaN(n)) throw new Error(`n must be an integer`)
|
||||
if (isNaN(n)) throw new Error('n must be an integer')
|
||||
|
||||
if (typeof include_mempool !== "boolean")
|
||||
throw new Error(`include_mempool input must be of type boolean`)
|
||||
if (typeof includeMempool !== 'boolean') {
|
||||
throw new Error('includeMempool input must be of type boolean')
|
||||
}
|
||||
|
||||
// Send the request to the REST API.
|
||||
// const response = await axios.get(
|
||||
// `${this.restURL}blockchain/getTxOut/${txid}/${n}?include_mempool=${include_mempool}`,
|
||||
// `${this.restURL}blockchain/getTxOut/${txid}/${n}?includeMempool=${includeMempool}`,
|
||||
// _this.axiosOptions
|
||||
// )
|
||||
const response = await axios.post(
|
||||
@@ -621,7 +633,7 @@ class Blockchain {
|
||||
{
|
||||
txid: txid,
|
||||
vout: n,
|
||||
mempool: include_mempool
|
||||
mempool: includeMempool
|
||||
},
|
||||
_this.axiosOptions
|
||||
)
|
||||
@@ -669,12 +681,12 @@ class Blockchain {
|
||||
* // "010000007de867cc8adc5cc8fb6b898ca4462cf9fd667d7830a275277447e60800000000338f121232e169d3100edd82004dc2a1f0e1f030c6c488fa61eafa930b0528fe021f7449ffff001d36b4af9a0100000001338f121232e169d3100edd82004dc2a1f0e1f030c6c488fa61eafa930b0528fe0101"
|
||||
* // ]
|
||||
*/
|
||||
async getTxOutProof(txids) {
|
||||
async getTxOutProof (txids) {
|
||||
try {
|
||||
// Single txid.
|
||||
if (typeof txids === "string") {
|
||||
if (typeof txids === 'string') {
|
||||
const path = `${this.restURL}blockchain/getTxOutProof/${txids}`
|
||||
//if (blockhash) path = `${path}?blockhash=${blockhash}`
|
||||
// if (blockhash) path = `${path}?blockhash=${blockhash}`
|
||||
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
return response.data
|
||||
@@ -693,14 +705,14 @@ class Blockchain {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input must be a string or array of strings.`)
|
||||
throw new Error('Input must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
async preciousBlock(blockhash) {
|
||||
async preciousBlock (blockhash) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/preciousBlock/${blockhash}`,
|
||||
@@ -713,7 +725,7 @@ class Blockchain {
|
||||
}
|
||||
}
|
||||
|
||||
async pruneBlockchain(height) {
|
||||
async pruneBlockchain (height) {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}blockchain/pruneBlockchain/${height}`,
|
||||
@@ -726,7 +738,7 @@ class Blockchain {
|
||||
}
|
||||
}
|
||||
|
||||
async verifyChain(checklevel = 3, nblocks = 6) {
|
||||
async verifyChain (checklevel = 3, nblocks = 6) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}`,
|
||||
@@ -776,10 +788,10 @@ class Blockchain {
|
||||
* // "03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
|
||||
* // ]
|
||||
*/
|
||||
async verifyTxOutProof(proof) {
|
||||
async verifyTxOutProof (proof) {
|
||||
try {
|
||||
// Single block
|
||||
if (typeof proof === "string") {
|
||||
if (typeof proof === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/verifyTxOutProof/${proof}`,
|
||||
_this.axiosOptions
|
||||
@@ -800,7 +812,7 @@ class Blockchain {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input must be a string or array of strings.`)
|
||||
throw new Error('Input must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
|
||||
+18
-8
@@ -2,19 +2,29 @@
|
||||
API endpoints for basic control and information of the full node.
|
||||
*/
|
||||
|
||||
const axios = require("axios")
|
||||
const axios = require('axios')
|
||||
|
||||
let _this // Global reference to the instance of this class.
|
||||
|
||||
class Control {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.authToken = config.authToken
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +77,7 @@ class Control {
|
||||
* warnings:
|
||||
* 'Warning: Unknown block versions being mined! It\'s possible unknown rules are in effect' }}
|
||||
*/
|
||||
async getNetworkInfo() {
|
||||
async getNetworkInfo () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}control/getNetworkInfo`,
|
||||
@@ -80,7 +90,7 @@ class Control {
|
||||
}
|
||||
}
|
||||
|
||||
async getMemoryInfo() {
|
||||
async getMemoryInfo () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}control/getMemoryInfo`,
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
const randomBytes = require("randombytes")
|
||||
const Bitcoin = require("bitcoincashjs-lib")
|
||||
const randomBytes = require('randombytes')
|
||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
||||
|
||||
class Crypto {
|
||||
/**
|
||||
@@ -26,7 +26,7 @@ class Crypto {
|
||||
*
|
||||
* */
|
||||
// Translate address from any address format into a specific format.
|
||||
static sha256(buffer) {
|
||||
static sha256 (buffer) {
|
||||
return Bitcoin.crypto.sha256(buffer)
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class Crypto {
|
||||
* bchjs.Crypto.ripemd160(buffer)
|
||||
* // <Buffer 5f 95 6a 88 86 30 51 ea 52 15 d8 97 0c ed 8e 21 8e b6 15 cf>
|
||||
* */
|
||||
static ripemd160(buffer) {
|
||||
static ripemd160 (buffer) {
|
||||
return Bitcoin.crypto.ripemd160(buffer)
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ class Crypto {
|
||||
* bchjs.Crypto.hash256(buffer)
|
||||
* // <Buffer 68 8f 1d 02 9e d5 4c 34 d0 32 0b 83 8b f6 fc 64 f6 2f 38 a6 e9 30 a0 af 5b db 4e 27 d1 a6 84 cd>
|
||||
* */
|
||||
static hash256(buffer) {
|
||||
static hash256 (buffer) {
|
||||
return Bitcoin.crypto.hash256(buffer)
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ class Crypto {
|
||||
* bchjs.Crypto.hash160(buffer)
|
||||
*
|
||||
* */
|
||||
static hash160(buffer) {
|
||||
static hash160 (buffer) {
|
||||
return Bitcoin.crypto.hash160(buffer)
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ class Crypto {
|
||||
* bchjs.Crypto.randomBytes(32)
|
||||
* // <Buffer ec 44 73 72 ea 48 3e 08 a5 0a 62 b8 40 0f 69 64 a7 75 35 af 20 3d e1 6d ce 3b f9 37 11 19 2b c6>
|
||||
* */
|
||||
static randomBytes(size = 16) {
|
||||
static randomBytes (size = 16) {
|
||||
return randomBytes(size)
|
||||
}
|
||||
}
|
||||
|
||||
+19
-15
@@ -1,10 +1,11 @@
|
||||
const Bitcoin = require("bitcoincashjs-lib")
|
||||
const coininfo = require("coininfo")
|
||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
||||
const coininfo = require('@psf/coininfo')
|
||||
|
||||
class ECPair {
|
||||
static setAddress(address) {
|
||||
static setAddress (address) {
|
||||
ECPair._address = address
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Ecpair.fromWIF() fromWIF()
|
||||
* @apiName fromWIF
|
||||
@@ -20,20 +21,19 @@ class ECPair {
|
||||
* let wif = 'cSNLj6xeg3Yg2rfcgKoWNx4MiAgn9ugCUUro37UDEhn6CzeYqjWW'
|
||||
* bchjs.ECPair.fromWIF(wif)
|
||||
* */
|
||||
static fromWIF(privateKeyWIF) {
|
||||
static fromWIF (privateKeyWIF) {
|
||||
let network
|
||||
if (privateKeyWIF[0] === "L" || privateKeyWIF[0] === "K")
|
||||
network = "mainnet"
|
||||
else if (privateKeyWIF[0] === "c") network = "testnet"
|
||||
if (privateKeyWIF[0] === 'L' || privateKeyWIF[0] === 'K') { network = 'mainnet' } else if (privateKeyWIF[0] === 'c') network = 'testnet'
|
||||
|
||||
let bitcoincash
|
||||
if (network === "mainnet") bitcoincash = coininfo.bitcoincash.main
|
||||
if (network === 'mainnet') bitcoincash = coininfo.bitcoincash.main
|
||||
else bitcoincash = coininfo.bitcoincash.test
|
||||
|
||||
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
|
||||
|
||||
return Bitcoin.ECPair.fromWIF(privateKeyWIF, bitcoincashBitcoinJSLib)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Ecpair.toWIF() toWIF()
|
||||
* @apiName toWIF
|
||||
@@ -57,17 +57,18 @@ class ECPair {
|
||||
* bchjs.ECPair.toWIF(ecpair);
|
||||
* // cT3tJP7BnjFJSAHbooMXrY8E9t2AFj37amSBAYFMeHfqPqPgD4ZA
|
||||
* */
|
||||
static toWIF(ecpair) {
|
||||
static toWIF (ecpair) {
|
||||
return ecpair.toWIF()
|
||||
}
|
||||
|
||||
static sign(ecpair, buffer) {
|
||||
static sign (ecpair, buffer) {
|
||||
return ecpair.sign(buffer)
|
||||
}
|
||||
|
||||
static verify(ecpair, buffer, signature) {
|
||||
static verify (ecpair, buffer, signature) {
|
||||
return ecpair.verify(buffer, signature)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Ecpair.fromPublicKey() fromPublicKey()
|
||||
* @apiName fromPublicKey
|
||||
@@ -83,9 +84,10 @@ class ECPair {
|
||||
* let pubkeyBuffer = Buffer.from("024a6d0737a23c472d078d78c1cbc3c2bbf8767b48e72684ff03a911b463da7fa6", 'hex');
|
||||
* bchjs.ECPair.fromPublicKey(pubkeyBuffer);
|
||||
* */
|
||||
static fromPublicKey(pubkeyBuffer) {
|
||||
static fromPublicKey (pubkeyBuffer) {
|
||||
return Bitcoin.ECPair.fromPublicKeyBuffer(pubkeyBuffer)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Ecpair.toPublicKey() toPublicKey()
|
||||
* @apiName toPublicKey
|
||||
@@ -105,9 +107,10 @@ class ECPair {
|
||||
* bchjs.ECPair.toPublicKey(ecpair);
|
||||
* //
|
||||
* */
|
||||
static toPublicKey(ecpair) {
|
||||
static toPublicKey (ecpair) {
|
||||
return ecpair.getPublicKeyBuffer()
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Ecpair.toLegacyAddress() toLegacyAddress()
|
||||
* @apiName toLegacyAddress
|
||||
@@ -131,9 +134,10 @@ class ECPair {
|
||||
* bchjs.ECPair.toLegacyAddress(ecpair);
|
||||
* // mg4PygFcXoyNJGJkM2Dcpe25av9wXzz1My
|
||||
* */
|
||||
static toLegacyAddress(ecpair) {
|
||||
static toLegacyAddress (ecpair) {
|
||||
return ecpair.getAddress()
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Ecpair.toCashAddress() toCashAddress()
|
||||
* @apiName toCashAddress
|
||||
@@ -157,7 +161,7 @@ class ECPair {
|
||||
* bchjs.ECPair.toCashAddress(ecpair);
|
||||
* // bchtest:qqzly4vrcxcjw62u4yq4nv86ltk2mc9v0yvq8mvj6m
|
||||
* */
|
||||
static toCashAddress(ecpair, regtest = false) {
|
||||
static toCashAddress (ecpair, regtest = false) {
|
||||
return ECPair._address.toCashAddress(ecpair.getAddress(), true, regtest)
|
||||
}
|
||||
}
|
||||
|
||||
+36
-29
@@ -3,20 +3,29 @@
|
||||
by FullStack.cash
|
||||
*/
|
||||
|
||||
const axios = require("axios")
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
|
||||
class ElectrumX {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.authToken = config.authToken
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`,
|
||||
timeout: 15000
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,10 +97,10 @@ class ElectrumX {
|
||||
* }
|
||||
*
|
||||
*/
|
||||
async utxo(address) {
|
||||
async utxo (address) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === "string") {
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/utxos/${address}`,
|
||||
_this.axiosOptions
|
||||
@@ -111,7 +120,7 @@ class ElectrumX {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input address must be a string or array of strings.`)
|
||||
throw new Error('Input address must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -172,10 +181,10 @@ class ElectrumX {
|
||||
* }
|
||||
*
|
||||
*/
|
||||
async balance(address) {
|
||||
async balance (address) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === "string") {
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/balance/${address}`,
|
||||
_this.axiosOptions
|
||||
@@ -195,7 +204,7 @@ class ElectrumX {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input address must be a string or array of strings.`)
|
||||
throw new Error('Input address must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -270,10 +279,10 @@ class ElectrumX {
|
||||
* }
|
||||
*
|
||||
*/
|
||||
async transactions(address) {
|
||||
async transactions (address) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === "string") {
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/transactions/${address}`,
|
||||
_this.axiosOptions
|
||||
@@ -293,7 +302,7 @@ class ElectrumX {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input address must be a string or array of strings.`)
|
||||
throw new Error('Input address must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -362,10 +371,10 @@ class ElectrumX {
|
||||
* }
|
||||
*
|
||||
*/
|
||||
async unconfirmed(address) {
|
||||
async unconfirmed (address) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === "string") {
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/unconfirmed/${address}`,
|
||||
_this.axiosOptions
|
||||
@@ -385,7 +394,7 @@ class ElectrumX {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input address must be a string or array of strings.`)
|
||||
throw new Error('Input address must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -433,7 +442,7 @@ class ElectrumX {
|
||||
* }
|
||||
*
|
||||
*/
|
||||
async blockHeader(height, count = 1) {
|
||||
async blockHeader (height, count = 1) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/block/headers/${height}?count=${count}`,
|
||||
@@ -443,9 +452,7 @@ class ElectrumX {
|
||||
} catch (error) {
|
||||
// console.log("error: ", error)
|
||||
if (error.response && error.response.data) {
|
||||
if (error.response && error.response.data)
|
||||
throw new Error(error.response.data.error)
|
||||
else throw error.response.data
|
||||
if (error.response && error.response.data) { throw new Error(error.response.data.error) } else throw error.response.data
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
@@ -522,10 +529,10 @@ class ElectrumX {
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
async txData(txid) {
|
||||
async txData (txid) {
|
||||
try {
|
||||
// Handle single transaction.
|
||||
if (typeof txid === "string") {
|
||||
if (typeof txid === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/tx/data/${txid}`,
|
||||
_this.axiosOptions
|
||||
@@ -543,7 +550,7 @@ class ElectrumX {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input txId must be a string or array of strings.`)
|
||||
throw new Error('Input txId must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -571,9 +578,9 @@ class ElectrumX {
|
||||
* "txid": "..."
|
||||
* }
|
||||
*/
|
||||
async broadcast(txHex) {
|
||||
async broadcast (txHex) {
|
||||
try {
|
||||
if (typeof txHex === "string") {
|
||||
if (typeof txHex === 'string') {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}electrumx/tx/broadcast`,
|
||||
{ txHex },
|
||||
@@ -583,7 +590,7 @@ class ElectrumX {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input txHex must be a string.`)
|
||||
throw new Error('Input txHex must be a string.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
|
||||
+18
-10
@@ -2,21 +2,30 @@
|
||||
This library contains useful functions that deal with encryption.
|
||||
*/
|
||||
|
||||
const axios = require("axios")
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
|
||||
class Encryption {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.axios = axios
|
||||
// console.log(`Blockbook apiToken: ${this.apiToken}`)
|
||||
this.authToken = config.authToken
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +33,9 @@ class Encryption {
|
||||
}
|
||||
|
||||
// Search the blockchain for a public key associated with a BCH address.
|
||||
async getPubKey(addr) {
|
||||
async getPubKey (addr) {
|
||||
try {
|
||||
if (!addr || typeof addr !== "string")
|
||||
throw new Error(`Input must be a valid Bitcoin Cash address.`)
|
||||
if (!addr || typeof addr !== 'string') { throw new Error('Input must be a valid Bitcoin Cash address.') }
|
||||
|
||||
const response = await _this.axios.get(
|
||||
`${this.restURL}encryption/publickey/${addr}`,
|
||||
|
||||
+17
-7
@@ -1,23 +1,33 @@
|
||||
const axios = require("axios")
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
|
||||
class Generating {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.authToken = config.authToken
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
}
|
||||
|
||||
async generateToAddress(blocks, address, maxtries = 1000000) {
|
||||
async generateToAddress (blocks, address, maxtries = 1000000) {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}generating/generateToAddress/${blocks}/${address}?maxtries=${maxtries}`,
|
||||
|
||||
+32
-34
@@ -1,10 +1,10 @@
|
||||
const Bitcoin = require("bitcoincashjs-lib")
|
||||
const coininfo = require("coininfo")
|
||||
const bip32utils = require("bip32-utils")
|
||||
const bchaddrjs = require("bchaddrjs-slp")
|
||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
||||
const coininfo = require('@psf/coininfo')
|
||||
const bip32utils = require('@psf/bip32-utils')
|
||||
const bchaddrjs = require('bchaddrjs-slp')
|
||||
|
||||
class HDNode {
|
||||
constructor(address) {
|
||||
constructor (address) {
|
||||
this._address = address
|
||||
}
|
||||
|
||||
@@ -32,11 +32,9 @@ class HDNode {
|
||||
* // create HDNode from seed buffer
|
||||
* bchjs.HDNode.fromSeed(seedBuffer);
|
||||
*/
|
||||
fromSeed(rootSeedBuffer, network = "mainnet") {
|
||||
fromSeed (rootSeedBuffer, network = 'mainnet') {
|
||||
let bitcoincash
|
||||
if (network === "bitcoincash" || network === "mainnet")
|
||||
bitcoincash = coininfo.bitcoincash.main
|
||||
else bitcoincash = coininfo.bitcoincash.test
|
||||
if (network === 'bitcoincash' || network === 'mainnet') { bitcoincash = coininfo.bitcoincash.main } else bitcoincash = coininfo.bitcoincash.test
|
||||
|
||||
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
|
||||
return Bitcoin.HDNode.fromSeedBuffer(
|
||||
@@ -75,7 +73,7 @@ class HDNode {
|
||||
* bchjs.HDNode.toLegacyAddress(hdNode);
|
||||
* // 14mVsq3H5Ep2Jb6AqoKsmY1BFHKCBGPDLi
|
||||
*/
|
||||
toLegacyAddress(hdNode) {
|
||||
toLegacyAddress (hdNode) {
|
||||
return hdNode.getAddress()
|
||||
}
|
||||
|
||||
@@ -109,7 +107,7 @@ class HDNode {
|
||||
* bchjs.HDNode.toCashAddress(hdNode);
|
||||
* // bitcoincash:qq549jxsjv66kw0smdju4es2axnk7hhe9cquhjg4gt
|
||||
*/
|
||||
toCashAddress(hdNode, regtest = false) {
|
||||
toCashAddress (hdNode, regtest = false) {
|
||||
return this._address.toCashAddress(hdNode.getAddress(), true, regtest)
|
||||
}
|
||||
|
||||
@@ -142,7 +140,7 @@ class HDNode {
|
||||
* bchjs.SLP.HDNode.toSLPAddress(hdNode);
|
||||
* // simpleledger:qqxh2z2z397m4c6u9s5x6wjtku742q8rpvm6al2nrf
|
||||
*/
|
||||
toSLPAddress(hdNode) {
|
||||
toSLPAddress (hdNode) {
|
||||
const cashAddr = this.toCashAddress(hdNode)
|
||||
return bchaddrjs.toSlpAddress(cashAddr)
|
||||
}
|
||||
@@ -177,7 +175,7 @@ class HDNode {
|
||||
* bchjs.HDNode.toWIF(hdNode);
|
||||
* // KwobPFhv3AuXc3ps6YtWfMVRpLBDBA7jnJddurfELTyTNcFhZYpJ
|
||||
*/
|
||||
toWIF(hdNode) {
|
||||
toWIF (hdNode) {
|
||||
return hdNode.keyPair.toWIF()
|
||||
}
|
||||
|
||||
@@ -211,7 +209,7 @@ class HDNode {
|
||||
* bchjs.HDNode.toXPub(hdNode);
|
||||
* // xpub661MyMwAqRbcFuMLeHkSbTNwNHG9MQyrAZqV1Q4MEAsmj9MYa5sxg8WC2LKqW6EHviHVucBjWi1n38juZpDDeX3U6YrsMeACdcNSTHkM8BQ
|
||||
*/
|
||||
toXPub(hdNode) {
|
||||
toXPub (hdNode) {
|
||||
return hdNode.neutered().toBase58()
|
||||
}
|
||||
|
||||
@@ -245,7 +243,7 @@ class HDNode {
|
||||
* bchjs.HDNode.toXPriv(hdNode);
|
||||
* // xprv9s21ZrQH143K2b5GPP6zHz22E6LeCgQXJtwNbC3MA3Kz7Se7tveKo96EhqwFtSkYWkyenVcMqM7uq35PcUNG8cUdpsJEgwKG3dvfP7TmL3v
|
||||
*/
|
||||
toXPriv(hdNode) {
|
||||
toXPriv (hdNode) {
|
||||
return hdNode.toBase58()
|
||||
}
|
||||
|
||||
@@ -277,7 +275,7 @@ class HDNode {
|
||||
* // create public key buffer from HDNode
|
||||
* bchjs.HDNode.toKeyPair(hdNode);
|
||||
*/
|
||||
toKeyPair(hdNode) {
|
||||
toKeyPair (hdNode) {
|
||||
return hdNode.keyPair
|
||||
}
|
||||
|
||||
@@ -311,7 +309,7 @@ class HDNode {
|
||||
* bchjs.HDNode.toPublicKey(hdNode);
|
||||
* // <Buffer 02 d2 26 74 6e 78 03 ac 11 e0 96 c6 24 de e8 dd 62 52 e7 8e 51 56 8a c1 18 62 aa 2a 72 50 1d ea 7d>
|
||||
*/
|
||||
toPublicKey(hdNode) {
|
||||
toPublicKey (hdNode) {
|
||||
return hdNode.getPublicKeyBuffer()
|
||||
}
|
||||
|
||||
@@ -329,10 +327,10 @@ class HDNode {
|
||||
* // testnet xpriv
|
||||
* bchjs.HDNode.fromXPriv('tprv8gQ3zr1F5pRHMebqqhorrorYNvUG3XkcZjSWVs2cEtRwwJy1TRhgRx4XcF8dYHM2eyTbTCcdKYNhqgyBQphxwRoVyVKr9zuyoA8WxNDRvom');
|
||||
*/
|
||||
fromXPriv(xpriv) {
|
||||
fromXPriv (xpriv) {
|
||||
let bitcoincash
|
||||
if (xpriv[0] === "x") bitcoincash = coininfo.bitcoincash.main
|
||||
else if (xpriv[0] === "t") bitcoincash = coininfo.bitcoincash.test
|
||||
if (xpriv[0] === 'x') bitcoincash = coininfo.bitcoincash.main
|
||||
else if (xpriv[0] === 't') bitcoincash = coininfo.bitcoincash.test
|
||||
|
||||
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
|
||||
return Bitcoin.HDNode.fromBase58(xpriv, bitcoincashBitcoinJSLib)
|
||||
@@ -352,10 +350,10 @@ class HDNode {
|
||||
* // testnet xpub
|
||||
* bchjs.HDNode.fromXPub('tpubDD669G3VEC6xF7ddjMUTGDWewwzCCrwX933HnP4ufAELmoDn5pXGcSgPnLodjFvWQwRXkG94f77BatEDA8dfQ99yy97kRYynUpNLENEqTBo');
|
||||
*/
|
||||
fromXPub(xpub) {
|
||||
fromXPub (xpub) {
|
||||
let bitcoincash
|
||||
if (xpub[0] === "x") bitcoincash = coininfo.bitcoincash.main
|
||||
else if (xpub[0] === "t") bitcoincash = coininfo.bitcoincash.test
|
||||
if (xpub[0] === 'x') bitcoincash = coininfo.bitcoincash.main
|
||||
else if (xpub[0] === 't') bitcoincash = coininfo.bitcoincash.test
|
||||
|
||||
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
|
||||
return Bitcoin.HDNode.fromBase58(xpub, bitcoincashBitcoinJSLib)
|
||||
@@ -378,7 +376,7 @@ class HDNode {
|
||||
* // derive hardened child HDNode
|
||||
* bchjs.HDNode.derivePath(hdNode, "m/44'/145'/0'");
|
||||
*/
|
||||
derivePath(hdnode, path) {
|
||||
derivePath (hdnode, path) {
|
||||
return hdnode.derivePath(path)
|
||||
}
|
||||
|
||||
@@ -399,7 +397,7 @@ class HDNode {
|
||||
* // derive unhardened child HDNode
|
||||
* bchjs.HDNode.derive(hdNode, 0);
|
||||
*/
|
||||
derive(hdnode, path) {
|
||||
derive (hdnode, path) {
|
||||
return hdnode.derive(path)
|
||||
}
|
||||
|
||||
@@ -420,7 +418,7 @@ class HDNode {
|
||||
* // derive hardened child HDNode
|
||||
* bchjs.HDNode.deriveHardened(hdNode, 0);
|
||||
*/
|
||||
deriveHardened(hdnode, path) {
|
||||
deriveHardened (hdnode, path) {
|
||||
return hdnode.deriveHardened(path)
|
||||
}
|
||||
|
||||
@@ -450,7 +448,7 @@ class HDNode {
|
||||
* // sign
|
||||
* bchjs.HDNode.sign(hdnode, buf);
|
||||
*/
|
||||
sign(hdnode, buffer) {
|
||||
sign (hdnode, buffer) {
|
||||
return hdnode.sign(buffer)
|
||||
}
|
||||
|
||||
@@ -494,7 +492,7 @@ class HDNode {
|
||||
* bchjs.HDNode.verify(hdnode2, buf, signature);
|
||||
* // false
|
||||
*/
|
||||
verify(hdnode, buffer, signature) {
|
||||
verify (hdnode, buffer, signature) {
|
||||
return hdnode.verify(buffer, signature)
|
||||
}
|
||||
|
||||
@@ -530,7 +528,7 @@ class HDNode {
|
||||
* bchjs.HDNode.isPublic(node);
|
||||
* // false
|
||||
*/
|
||||
isPublic(hdnode) {
|
||||
isPublic (hdnode) {
|
||||
return hdnode.isNeutered()
|
||||
}
|
||||
|
||||
@@ -566,7 +564,7 @@ class HDNode {
|
||||
* bchjs.HDNode.isPrivate(node);
|
||||
* // true
|
||||
*/
|
||||
isPrivate(hdnode) {
|
||||
isPrivate (hdnode) {
|
||||
return !hdnode.isNeutered()
|
||||
}
|
||||
|
||||
@@ -598,11 +596,11 @@ class HDNode {
|
||||
* bchjs.Crypto.hash160(publicKeyBuffer);
|
||||
* // <Buffer e1 8e 20 e3 f8 f1 c0 53 e6 1f 9e 3a 58 8e 71 f5 0b 8d 2d c4>
|
||||
*/
|
||||
toIdentifier(hdnode) {
|
||||
toIdentifier (hdnode) {
|
||||
return hdnode.getIdentifier()
|
||||
}
|
||||
|
||||
fromBase58(base58, network) {
|
||||
fromBase58 (base58, network) {
|
||||
return Bitcoin.HDNode.fromBase58(base58, network)
|
||||
}
|
||||
|
||||
@@ -625,14 +623,14 @@ class HDNode {
|
||||
* // create account
|
||||
* let account = bchjs.HDNode.createAccount([childNode]);
|
||||
*/
|
||||
createAccount(hdNodes) {
|
||||
createAccount (hdNodes) {
|
||||
const arr = hdNodes.map(
|
||||
(item, index) => new bip32utils.Chain(item.neutered())
|
||||
)
|
||||
return new bip32utils.Account(arr)
|
||||
}
|
||||
|
||||
createChain(hdNode) {
|
||||
createChain (hdNode) {
|
||||
return new bip32utils.Chain(hdNode)
|
||||
}
|
||||
}
|
||||
|
||||
+57
-47
@@ -3,19 +3,19 @@
|
||||
and downloading data from the IPFS network.
|
||||
*/
|
||||
|
||||
const axios = require("axios")
|
||||
const Uppy = require("@uppy/core")
|
||||
const Tus = require("@uppy/tus")
|
||||
const fs = require("fs")
|
||||
const axios = require('axios')
|
||||
const Uppy = require('@uppy/core')
|
||||
const Tus = require('@uppy/tus')
|
||||
const fs = require('fs')
|
||||
|
||||
let _this
|
||||
|
||||
class IPFS {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.IPFS_API = process.env.IPFS_API
|
||||
? process.env.IPFS_API
|
||||
: // : `http://localhost:5001`
|
||||
`https://ipfs-api.fullstack.cash`
|
||||
: 'https://ipfs-api.fullstack.cash'
|
||||
// : `http://localhost:5001`
|
||||
|
||||
// Default options when calling axios.
|
||||
this.axiosOptions = {
|
||||
@@ -35,16 +35,16 @@ class IPFS {
|
||||
}
|
||||
|
||||
// Initializes Uppy, which is used for file uploads.
|
||||
initUppy() {
|
||||
initUppy () {
|
||||
const uppy = Uppy({
|
||||
allowMultipleUploads: false,
|
||||
meta: { test: "avatar" },
|
||||
meta: { test: 'avatar' },
|
||||
debug: false,
|
||||
restrictions: {
|
||||
maxFileSize: null,
|
||||
maxNumberOfFiles: 1,
|
||||
minNumberOfFiles: 1,
|
||||
allowedFileTypes: null //type of files allowed to load
|
||||
allowedFileTypes: null // type of files allowed to load
|
||||
}
|
||||
})
|
||||
uppy.use(Tus, { endpoint: `${_this.IPFS_API}/uppy-files` })
|
||||
@@ -90,11 +90,12 @@ class IPFS {
|
||||
* "__v": 0
|
||||
* }
|
||||
*/
|
||||
async createFileModelServer(path) {
|
||||
async createFileModelServer (path) {
|
||||
try {
|
||||
// Ensure the file exists.
|
||||
if (!_this.fs.existsSync(path))
|
||||
if (!_this.fs.existsSync(path)) {
|
||||
throw new Error(`Could not find this file: ${path}`)
|
||||
}
|
||||
|
||||
// Read in the file.
|
||||
const fileBuf = _this.fs.readFileSync(path)
|
||||
@@ -103,11 +104,11 @@ class IPFS {
|
||||
// console.log(`Buffer length: ${fileBuf.length}`)
|
||||
|
||||
// Get the file name from the path.
|
||||
const splitPath = path.split("/")
|
||||
const splitPath = path.split('/')
|
||||
const fileName = splitPath[splitPath.length - 1]
|
||||
|
||||
// Get the file extension.
|
||||
const splitExt = fileName.split(".")
|
||||
const splitExt = fileName.split('.')
|
||||
const fileExt = splitExt[splitExt.length - 1]
|
||||
|
||||
const fileObj = {
|
||||
@@ -125,7 +126,7 @@ class IPFS {
|
||||
|
||||
return fileData.data
|
||||
} catch (err) {
|
||||
console.error(`Error in createFileModel()`)
|
||||
console.error('Error in createFileModel()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -157,15 +158,16 @@ class IPFS {
|
||||
* "fileExtension": "js"
|
||||
* }
|
||||
*/
|
||||
async uploadFileServer(path, modelId) {
|
||||
async uploadFileServer (path, modelId) {
|
||||
try {
|
||||
// Ensure the file exists.
|
||||
if (!_this.fs.existsSync(path))
|
||||
if (!_this.fs.existsSync(path)) {
|
||||
throw new Error(`Could not find this file: ${path}`)
|
||||
}
|
||||
|
||||
if (!modelId) {
|
||||
throw new Error(
|
||||
`Must include a file model ID in order to upload a file.`
|
||||
'Must include a file model ID in order to upload a file.'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -173,14 +175,14 @@ class IPFS {
|
||||
const fileBuf = _this.fs.readFileSync(path)
|
||||
|
||||
// Get the file name from the path.
|
||||
const splitPath = path.split("/")
|
||||
const splitPath = path.split('/')
|
||||
const fileName = splitPath[splitPath.length - 1]
|
||||
|
||||
// Prepare the upload object. Get a file ID from Uppy.
|
||||
const id = _this.uppy.addFile({
|
||||
name: fileName,
|
||||
data: fileBuf,
|
||||
source: "Local",
|
||||
source: 'Local',
|
||||
isRemote: false
|
||||
})
|
||||
// console.log(`id: ${JSON.stringify(id, null, 2)}`)
|
||||
@@ -191,8 +193,9 @@ class IPFS {
|
||||
// Upload the file to the server.
|
||||
const upData = await _this.uppy.upload()
|
||||
|
||||
if (upData.failed.length)
|
||||
throw new Error("The file could not be uploaded")
|
||||
if (upData.failed.length) {
|
||||
throw new Error('The file could not be uploaded')
|
||||
}
|
||||
|
||||
if (upData.successful.length) {
|
||||
delete upData.successful[0].data
|
||||
@@ -213,7 +216,7 @@ class IPFS {
|
||||
|
||||
return false
|
||||
} catch (err) {
|
||||
console.error(`Error in bch-js/src/ipfs.js/upload(): `)
|
||||
console.error('Error in bch-js/src/ipfs.js/upload(): ')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -246,9 +249,9 @@ class IPFS {
|
||||
* "fileName": "ipfs-e2e.js"
|
||||
* }
|
||||
*/
|
||||
async getStatus(modelId) {
|
||||
async getStatus (modelId) {
|
||||
try {
|
||||
if (!modelId) throw new Error(`Must include a file model ID.`)
|
||||
if (!modelId) throw new Error('Must include a file model ID.')
|
||||
|
||||
const fileData = await _this.axios.get(
|
||||
`${this.IPFS_API}/files/${modelId}`
|
||||
@@ -266,10 +269,11 @@ class IPFS {
|
||||
|
||||
return fileObj
|
||||
} catch (err) {
|
||||
console.error(`Error in getStatus()`)
|
||||
console.error('Error in getStatus()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api IPFS.createFileModelWeb() createFileModelWeb()
|
||||
* @apiName createFileModelWeb()
|
||||
@@ -311,20 +315,22 @@ class IPFS {
|
||||
* "__v": 0
|
||||
* }
|
||||
*/
|
||||
async createFileModelWeb(file) {
|
||||
async createFileModelWeb (file) {
|
||||
try {
|
||||
if (!file) throw new Error(`File is required`)
|
||||
if (!file) throw new Error('File is required')
|
||||
|
||||
const { name, size } = file
|
||||
|
||||
if (!name || typeof name !== "string")
|
||||
throw new Error(`File should have the property 'name' of string type`)
|
||||
if (!name || typeof name !== 'string') {
|
||||
throw new Error("File should have the property 'name' of string type")
|
||||
}
|
||||
|
||||
if (!size || typeof size !== "number")
|
||||
throw new Error(`File should have the property 'size' of number type`)
|
||||
if (!size || typeof size !== 'number') {
|
||||
throw new Error("File should have the property 'size' of number type")
|
||||
}
|
||||
|
||||
// Get the file extension.
|
||||
const splitExt = name.split(".")
|
||||
const splitExt = name.split('.')
|
||||
const fileExt = splitExt[splitExt.length - 1]
|
||||
|
||||
const fileObj = {
|
||||
@@ -342,7 +348,7 @@ class IPFS {
|
||||
|
||||
return fileData.data
|
||||
} catch (err) {
|
||||
console.error(`Error in createFileModelWeb()`)
|
||||
console.error('Error in createFileModelWeb()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -377,24 +383,27 @@ class IPFS {
|
||||
* "fileExtension": "js"
|
||||
* }
|
||||
*/
|
||||
async uploadFileWeb(file, modelId) {
|
||||
async uploadFileWeb (file, modelId) {
|
||||
try {
|
||||
if (!file) throw new Error(`File is required`)
|
||||
if (!file) throw new Error('File is required')
|
||||
|
||||
const { name, type, size } = file
|
||||
|
||||
if (!name || typeof name !== "string")
|
||||
throw new Error(`File should have the property 'name' of string type`)
|
||||
if (!name || typeof name !== 'string') {
|
||||
throw new Error("File should have the property 'name' of string type")
|
||||
}
|
||||
|
||||
if (!type || typeof type !== "string")
|
||||
throw new Error(`File should have the property 'type' of string type`)
|
||||
if (!type || typeof type !== 'string') {
|
||||
throw new Error("File should have the property 'type' of string type")
|
||||
}
|
||||
|
||||
if (!size || typeof size !== "number")
|
||||
throw new Error(`File should have the property 'size' of number type`)
|
||||
if (!size || typeof size !== 'number') {
|
||||
throw new Error("File should have the property 'size' of number type")
|
||||
}
|
||||
|
||||
if (!modelId) {
|
||||
throw new Error(
|
||||
`Must include a file model ID in order to upload a file.`
|
||||
'Must include a file model ID in order to upload a file.'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -402,7 +411,7 @@ class IPFS {
|
||||
const id = _this.uppy.addFile({
|
||||
name: name,
|
||||
data: file,
|
||||
source: "Local",
|
||||
source: 'Local',
|
||||
isRemote: false
|
||||
})
|
||||
// console.log(`id: ${JSON.stringify(id, null, 2)}`)
|
||||
@@ -413,8 +422,9 @@ class IPFS {
|
||||
// Upload the file to the server.
|
||||
const upData = await _this.uppy.upload()
|
||||
|
||||
if (upData.failed.length)
|
||||
throw new Error("The file could not be uploaded")
|
||||
if (upData.failed.length) {
|
||||
throw new Error('The file could not be uploaded')
|
||||
}
|
||||
|
||||
if (upData.successful.length) {
|
||||
delete upData.successful[0].data
|
||||
@@ -435,7 +445,7 @@ class IPFS {
|
||||
|
||||
return false
|
||||
} catch (err) {
|
||||
console.error(`Error in bch-js/src/ipfs.js/uploadFileWeb(): `)
|
||||
console.error('Error in bch-js/src/ipfs.js/uploadFileWeb(): ')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
+21
-11
@@ -1,26 +1,36 @@
|
||||
const axios = require("axios")
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
|
||||
class Mining {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.authToken = config.authToken
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
}
|
||||
|
||||
async getBlockTemplate(template_request) {
|
||||
async getBlockTemplate (templateRequest) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}mining/getBlockTemplate/${template_request}`,
|
||||
`${this.restURL}mining/getBlockTemplate/${templateRequest}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
@@ -30,7 +40,7 @@ class Mining {
|
||||
}
|
||||
}
|
||||
|
||||
async getMiningInfo() {
|
||||
async getMiningInfo () {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}mining/getMiningInfo`,
|
||||
@@ -43,7 +53,7 @@ class Mining {
|
||||
}
|
||||
}
|
||||
|
||||
async getNetworkHashps(nblocks = 120, height = 1) {
|
||||
async getNetworkHashps (nblocks = 120, height = 1) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}mining/getNetworkHashps?nblocks=${nblocks}&height=${height}`,
|
||||
@@ -56,7 +66,7 @@ class Mining {
|
||||
}
|
||||
}
|
||||
|
||||
async submitBlock(hex, parameters) {
|
||||
async submitBlock (hex, parameters) {
|
||||
let path = `${this.restURL}mining/submitBlock/${hex}`
|
||||
if (parameters) path = `${path}?parameters=${parameters}`
|
||||
|
||||
|
||||
+33
-33
@@ -1,11 +1,14 @@
|
||||
const BIP39 = require("bip39")
|
||||
const randomBytes = require("randombytes")
|
||||
const Bitcoin = require("bitcoincashjs-lib")
|
||||
const Buffer = require("safe-buffer").Buffer
|
||||
const wif = require("wif")
|
||||
/* 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')
|
||||
|
||||
class Mnemonic {
|
||||
constructor(address) {
|
||||
constructor (address) {
|
||||
this._address = address
|
||||
}
|
||||
|
||||
@@ -45,7 +48,7 @@ class Mnemonic {
|
||||
* bchjs.Mnemonic.generate(256, bitbox.Mnemonic.wordLists().korean)
|
||||
* // 기능 단추 교육 비난 시집 근육 운동 코미디 숟가락 과목 한동안 유적 시리즈 삼월 앞날 유난히 흰색 사실 논문 장사 어른 논문 의논 장차
|
||||
*/
|
||||
generate(bits = 128, wordlist) {
|
||||
generate (bits = 128, wordlist) {
|
||||
return BIP39.generateMnemonic(bits, randomBytes, wordlist)
|
||||
}
|
||||
|
||||
@@ -95,11 +98,8 @@ class Mnemonic {
|
||||
* // generate 16 bytes of entropy
|
||||
* let entropy = bchjs.Crypto.randomBytes(16);
|
||||
* //
|
||||
* // turn entropy to 12 japanese word mnemonic
|
||||
* bchjs.Mnemonic.fromEntropy(entropy.toString('hex'), bchjs.Mnemonic.wordLists().japanese)
|
||||
* // ぱそこん にあう にんめい きどく ちそう せんきょ かいが きおく いれる いねむり しいく きかんしゃ
|
||||
*/
|
||||
fromEntropy(bytes, wordlist) {
|
||||
fromEntropy (bytes, wordlist) {
|
||||
return BIP39.entropyToMnemonic(bytes, wordlist)
|
||||
}
|
||||
|
||||
@@ -136,8 +136,8 @@ class Mnemonic {
|
||||
* bchjs.Mnemonic.toEntropy(mnemonic)
|
||||
* // <Buffer f3 79 da 02 cc 42 6e 6e 26 43 0d 25 e6 cc 37 2d fd 0a 1a 2e 4a 33 ac 4d c6 ae 6d 56 01 7f 64 2d>
|
||||
*/
|
||||
toEntropy(mnemonic, wordlist) {
|
||||
return Buffer.from(BIP39.mnemonicToEntropy(mnemonic, wordlist), "hex")
|
||||
toEntropy (mnemonic, wordlist) {
|
||||
return Buffer.from(BIP39.mnemonicToEntropy(mnemonic, wordlist), 'hex')
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,11 +157,11 @@ class Mnemonic {
|
||||
* bchjs.Mnemonic.validate('boil lonely casino manage habit where total glory muffin name limit mansion boil lonely casino manage habit where total glory muffin name limit mansion', bitbox.Mnemonic.wordLists().english)
|
||||
* // Invalid mnemonic
|
||||
*/
|
||||
validate(mnemonic, wordlist) {
|
||||
validate (mnemonic, wordlist) {
|
||||
// Preprocess the words
|
||||
const words = mnemonic.split(" ")
|
||||
const words = mnemonic.split(' ')
|
||||
// Detect blank phrase
|
||||
if (words.length === 0) return "Blank mnemonic"
|
||||
if (words.length === 0) return 'Blank mnemonic'
|
||||
|
||||
// Check each word
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
@@ -173,11 +173,11 @@ class Mnemonic {
|
||||
}
|
||||
}
|
||||
// Check the words are valid
|
||||
//const properPhrase = words.join()
|
||||
// const properPhrase = words.join()
|
||||
const isValid = BIP39.validateMnemonic(mnemonic, wordlist)
|
||||
if (!isValid) return "Invalid mnemonic"
|
||||
if (!isValid) return 'Invalid mnemonic'
|
||||
|
||||
return "Valid mnemonic"
|
||||
return 'Valid mnemonic'
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,7 +203,7 @@ class Mnemonic {
|
||||
* await bchjs.Mnemonic.toSeed('frost deliver coin clutch upon round scene wonder various wise luggage country', 'yayayayay');
|
||||
* // <Buffer 1d 00 9f a3 a8 86 51 a4 04 d5 03 3d eb 6d b1 01 e2 f1 3b c3 c8 6d 1f b9 93 b4 d1 33 dc 84 21 12 2c 9b 52 10 ba d8 96 15 e0 b0 9a 34 33 52 f8 07 c8 c4 ... >
|
||||
*/
|
||||
toSeed(mnemonic, password = "") {
|
||||
toSeed (mnemonic, password = '') {
|
||||
return BIP39.mnemonicToSeed(mnemonic, password)
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ class Mnemonic {
|
||||
* // spanish: []
|
||||
* // }
|
||||
*/
|
||||
wordLists() {
|
||||
wordLists () {
|
||||
return BIP39.wordlists
|
||||
}
|
||||
|
||||
@@ -260,10 +260,10 @@ class Mnemonic {
|
||||
* // { privateKeyWIF: 'L5gB66JqhfouEtZG5aRMQ9JaVS2ggkK3YozGfzZegBupaPXqdfaz',
|
||||
* // address: 'bitcoincash:qphwlpu2wzjxrjts94pn4wh778fwsu2afg2aj5her9' } ]
|
||||
*/
|
||||
async toKeypairs(mnemonic, numberOfKeypairs = 1, regtest = false) {
|
||||
const rootSeedBuffer = await this.toSeed(mnemonic, "")
|
||||
async toKeypairs (mnemonic, numberOfKeypairs = 1, regtest = false) {
|
||||
const rootSeedBuffer = await this.toSeed(mnemonic, '')
|
||||
const hdNode = Bitcoin.HDNode.fromSeedBuffer(rootSeedBuffer)
|
||||
const HDPath = `44'/145'/0'/0/`
|
||||
const HDPath = "44'/145'/0'/0/"
|
||||
|
||||
const accounts = []
|
||||
|
||||
@@ -321,7 +321,7 @@ class Mnemonic {
|
||||
* bchjs.Mnemonic.findNearestWord(word, wordlist);
|
||||
* // neve
|
||||
*/
|
||||
findNearestWord(word, wordlist) {
|
||||
findNearestWord (word, wordlist) {
|
||||
let minDistance = 99
|
||||
let closestWord = wordlist[0]
|
||||
for (let i = 0; i < wordlist.length; i++) {
|
||||
@@ -352,7 +352,7 @@ module.exports = Mnemonic
|
||||
* @return Object the final object.
|
||||
*/
|
||||
|
||||
const _extend = function(dst) {
|
||||
const _extend = function (dst) {
|
||||
const sources = Array.prototype.slice.call(arguments, 1)
|
||||
for (let i = 0; i < sources.length; ++i) {
|
||||
const src = sources[i]
|
||||
@@ -365,8 +365,8 @@ const _extend = function(dst) {
|
||||
* Defer execution of given function.
|
||||
* @param {Function} func
|
||||
*/
|
||||
const _defer = function(func) {
|
||||
if (typeof setImmediate === "function") return setImmediate(func)
|
||||
const _defer = function (func) {
|
||||
if (typeof setImmediate === 'function') return setImmediate(func)
|
||||
|
||||
return setTimeout(func, 0)
|
||||
}
|
||||
@@ -374,7 +374,7 @@ const _defer = function(func) {
|
||||
/**
|
||||
* Based on the algorithm at http://en.wikipedia.org/wiki/Levenshtein_distance.
|
||||
*/
|
||||
var Levenshtein = {
|
||||
const Levenshtein = {
|
||||
/**
|
||||
* Calculate levenshtein distance of the two strings.
|
||||
*
|
||||
@@ -382,7 +382,7 @@ var Levenshtein = {
|
||||
* @param str2 String the second string.
|
||||
* @return Integer the levenshtein distance (0 and above).
|
||||
*/
|
||||
get: function(str1, str2) {
|
||||
get: function (str1, str2) {
|
||||
// base cases
|
||||
if (str1 === str2) return 0
|
||||
if (str1.length === 0) return str2.length
|
||||
@@ -432,7 +432,7 @@ var Levenshtein = {
|
||||
* @param [options] Object additional options.
|
||||
* @param [options.progress] Function progress callback with signature: function(percentComplete)
|
||||
*/
|
||||
getAsync: function(str1, str2, cb, options) {
|
||||
getAsync: function (str1, str2, cb, options) {
|
||||
options = _extend(
|
||||
{},
|
||||
{
|
||||
@@ -457,7 +457,7 @@ var Levenshtein = {
|
||||
i = 0
|
||||
j = -1
|
||||
|
||||
var __calculate = function() {
|
||||
const __calculate = function () {
|
||||
// reset timer
|
||||
startTime = new Date().valueOf()
|
||||
currentTime = startTime
|
||||
@@ -499,7 +499,7 @@ var Levenshtein = {
|
||||
}
|
||||
|
||||
// send a progress update?
|
||||
if (null !== options.progress) {
|
||||
if (options.progress !== null) {
|
||||
try {
|
||||
options.progress.call(null, (i * 100.0) / str1.length)
|
||||
} catch (err) {
|
||||
|
||||
+15
-15
@@ -3,12 +3,12 @@
|
||||
Bitcoin.com
|
||||
*/
|
||||
|
||||
const axios = require("axios")
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
|
||||
class Ninsight {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
// this.restURL = config.restURL
|
||||
// this.apiToken = config.apiToken
|
||||
|
||||
@@ -16,7 +16,7 @@ class Ninsight {
|
||||
if (config) {
|
||||
this.ninsightURL = config.ninsightURL
|
||||
? config.ninsightURL
|
||||
: `https://rest.bitcoin.com/v2`
|
||||
: 'https://rest.bitcoin.com/v2'
|
||||
}
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
@@ -66,10 +66,10 @@ class Ninsight {
|
||||
* // ]
|
||||
*
|
||||
*/
|
||||
async utxo(address) {
|
||||
async utxo (address) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === "string") {
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.post(
|
||||
`${this.ninsightURL}/address/utxo`,
|
||||
{
|
||||
@@ -92,7 +92,7 @@ class Ninsight {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input address must be a string or array of strings.`)
|
||||
throw new Error('Input address must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -135,9 +135,9 @@ class Ninsight {
|
||||
* // ]
|
||||
*
|
||||
*/
|
||||
async unconfirmed(address) {
|
||||
async unconfirmed (address) {
|
||||
try {
|
||||
if (typeof address === "string") {
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.post(
|
||||
`${this.ninsightURL}/address/unconfirmed`,
|
||||
{
|
||||
@@ -159,7 +159,7 @@ class Ninsight {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input address must be a string or array of strings.`)
|
||||
throw new Error('Input address must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -211,9 +211,9 @@ class Ninsight {
|
||||
* //
|
||||
*
|
||||
*/
|
||||
async transactions(address) {
|
||||
async transactions (address) {
|
||||
try {
|
||||
if (typeof address === "string") {
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.post(
|
||||
`${this.ninsightURL}/address/transactions`,
|
||||
{
|
||||
@@ -235,7 +235,7 @@ class Ninsight {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input address must be a string or array of strings.`)
|
||||
throw new Error('Input address must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -284,9 +284,9 @@ class Ninsight {
|
||||
* // ]
|
||||
*
|
||||
*/
|
||||
async txDetails(txid) {
|
||||
async txDetails (txid) {
|
||||
try {
|
||||
if (typeof txid === "string") {
|
||||
if (typeof txid === 'string') {
|
||||
const response = await axios.post(
|
||||
`${this.ninsightURL}/transaction/details`,
|
||||
{
|
||||
@@ -308,7 +308,7 @@ class Ninsight {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Transaction ID must be a string or array of strings.`)
|
||||
throw new Error('Transaction ID must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
|
||||
+14
-14
@@ -3,12 +3,12 @@
|
||||
provides for their application.
|
||||
*/
|
||||
|
||||
const axios = require("axios")
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
|
||||
class OpenBazaar {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
|
||||
@@ -55,12 +55,12 @@ class OpenBazaar {
|
||||
* }
|
||||
*
|
||||
*/
|
||||
async balance(address) {
|
||||
async balance (address) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === "string") {
|
||||
if (typeof address === 'string') {
|
||||
let response
|
||||
if (process.env.NETWORK === "testnet") {
|
||||
if (process.env.NETWORK === 'testnet') {
|
||||
response = await axios.get(
|
||||
`https://tbch.blockbook.api.openbazaar.org/api/address/${address}`,
|
||||
_this.axiosOptions
|
||||
@@ -75,7 +75,7 @@ class OpenBazaar {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input address must be a string.`)
|
||||
throw new Error('Input address must be a string.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -109,12 +109,12 @@ class OpenBazaar {
|
||||
* }
|
||||
* ]
|
||||
*/
|
||||
async utxo(address) {
|
||||
async utxo (address) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === "string") {
|
||||
if (typeof address === 'string') {
|
||||
let response
|
||||
if (process.env.NETWORK === "testnet") {
|
||||
if (process.env.NETWORK === 'testnet') {
|
||||
response = await axios.get(
|
||||
`https://tbch.blockbook.api.openbazaar.org/api/utxo/${address}`,
|
||||
_this.axiosOptions
|
||||
@@ -127,7 +127,7 @@ class OpenBazaar {
|
||||
}
|
||||
return response.data
|
||||
}
|
||||
throw new Error(`Input address must be a string.`)
|
||||
throw new Error('Input address must be a string.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -199,12 +199,12 @@ class OpenBazaar {
|
||||
* }
|
||||
*
|
||||
*/
|
||||
async tx(txid) {
|
||||
async tx (txid) {
|
||||
try {
|
||||
// Handle single txid.
|
||||
if (typeof txid === "string") {
|
||||
if (typeof txid === 'string') {
|
||||
let response
|
||||
if (process.env.NETWORK === "testnet") {
|
||||
if (process.env.NETWORK === 'testnet') {
|
||||
response = await axios.get(
|
||||
`https://tbch.blockbook.api.openbazaar.org/api/tx/${txid}`,
|
||||
_this.axiosOptions
|
||||
@@ -218,7 +218,7 @@ class OpenBazaar {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input txid must be a string.`)
|
||||
throw new Error('Input txid must be a string.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
|
||||
+57
-33
@@ -1,47 +1,36 @@
|
||||
const axios = require("axios")
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
|
||||
class Price {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
_this = this
|
||||
|
||||
if (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
}
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.authToken = config.authToken
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.axios = axios
|
||||
}
|
||||
|
||||
/**
|
||||
* @api price.current() current()
|
||||
* @apiName Price.
|
||||
* @apiGroup Price
|
||||
* @apiDescription Return current price of BCH in multiple currencies.
|
||||
* This endpoint will be deprecated in favor of getUSD. It uses the Bitcoin.com
|
||||
* price feed.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*(async () => {
|
||||
* try {
|
||||
* let current = await bchjs.Price.current('usd');
|
||||
* console.log(current);
|
||||
* } catch(err) {
|
||||
* console.err(err)
|
||||
* }
|
||||
*})()
|
||||
*
|
||||
* // 26681
|
||||
*/
|
||||
async current(currency = "usd") {
|
||||
// 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()}`
|
||||
@@ -75,7 +64,7 @@ class Price {
|
||||
*
|
||||
* // 266.81
|
||||
*/
|
||||
async getUsd() {
|
||||
async getUsd () {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/usd`,
|
||||
@@ -118,7 +107,7 @@ class Price {
|
||||
* ZWL: "80215.03"
|
||||
* }
|
||||
*/
|
||||
async rates() {
|
||||
async rates () {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/rates`,
|
||||
@@ -132,6 +121,41 @@ class Price {
|
||||
else throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api price.getBchaUsd() getBchaUsd()
|
||||
* @apiName Price getBchaUsd()
|
||||
* @apiGroup Price
|
||||
* @apiDescription Return current price of BCHA in USD.
|
||||
* This endpoint gets the USD price of BCHA from the Coinex API. The price
|
||||
* comes from bch-api, so it has a better chance of working in Tor.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*(async () => {
|
||||
* try {
|
||||
* let current = await bchjs.Price.getBchaUsd();
|
||||
* console.log(current);
|
||||
* } catch(err) {
|
||||
* console.err(err)
|
||||
* }
|
||||
*})()
|
||||
*
|
||||
* // 18.81
|
||||
*/
|
||||
async getBchaUsd () {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/bchausd`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
return response.data.usd
|
||||
} catch (err) {
|
||||
if (err.response && err.response.data) throw err.response.data
|
||||
else throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Price
|
||||
|
||||
+41
-32
@@ -1,19 +1,32 @@
|
||||
const axios = require("axios")
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
|
||||
class RawTransactions {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.authToken = config.authToken
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Encapsulate dependencies
|
||||
this.axios = axios
|
||||
|
||||
_this = this
|
||||
}
|
||||
|
||||
@@ -79,10 +92,10 @@ class RawTransactions {
|
||||
* // vin: [ [Object] ],
|
||||
* // vout: [ [Object] ] } ]
|
||||
*/
|
||||
async decodeRawTransaction(hex) {
|
||||
async decodeRawTransaction (hex) {
|
||||
try {
|
||||
// Single hex
|
||||
if (typeof hex === "string") {
|
||||
if (typeof hex === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}rawtransactions/decodeRawTransaction/${hex}`,
|
||||
_this.axiosOptions
|
||||
@@ -93,7 +106,7 @@ class RawTransactions {
|
||||
// Array of hexes
|
||||
} else if (Array.isArray(hex)) {
|
||||
const options = {
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
url: `${this.restURL}rawtransactions/decodeRawTransaction`,
|
||||
data: {
|
||||
hexes: hex
|
||||
@@ -107,7 +120,7 @@ class RawTransactions {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input must be a string or array of strings.`)
|
||||
throw new Error('Input must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -147,11 +160,11 @@ class RawTransactions {
|
||||
* // type: 'nonstandard',
|
||||
* // p2sh: 'bitcoincash:pqwndulzwft8dlmqrteqyc9hf823xr3lcc7ypt74ts' }]
|
||||
*/
|
||||
async decodeScript(script) {
|
||||
//if (typeof script !== "string") script = JSON.stringify(script)
|
||||
async decodeScript (script) {
|
||||
// if (typeof script !== "string") script = JSON.stringify(script)
|
||||
|
||||
try {
|
||||
if (typeof script === "string") {
|
||||
if (typeof script === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}rawtransactions/decodeScript/${script}`,
|
||||
_this.axiosOptions
|
||||
@@ -160,7 +173,7 @@ class RawTransactions {
|
||||
return response.data
|
||||
} else if (Array.isArray(script)) {
|
||||
const options = {
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
url: `${this.restURL}rawtransactions/decodeScript`,
|
||||
data: {
|
||||
hexes: script
|
||||
@@ -174,7 +187,7 @@ class RawTransactions {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input must be a string or array of strings.`)
|
||||
throw new Error('Input must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -245,9 +258,9 @@ class RawTransactions {
|
||||
* // time: 1547752564,
|
||||
* // blocktime: 1547752564 } ]
|
||||
*/
|
||||
async getRawTransaction(txid, verbose = false) {
|
||||
async getRawTransaction (txid, verbose = false) {
|
||||
try {
|
||||
if (typeof txid === "string") {
|
||||
if (typeof txid === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=${verbose}`,
|
||||
_this.axiosOptions
|
||||
@@ -256,22 +269,20 @@ class RawTransactions {
|
||||
return response.data
|
||||
} else if (Array.isArray(txid)) {
|
||||
const options = {
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
url: `${this.restURL}rawtransactions/getRawTransaction`,
|
||||
data: {
|
||||
txids: txid,
|
||||
verbose: verbose
|
||||
},
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
headers: _this.axiosOptions.headers
|
||||
}
|
||||
const response = await axios(options)
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input must be a string or array of strings.`)
|
||||
throw new Error('Input must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
@@ -310,16 +321,16 @@ class RawTransactions {
|
||||
* })()
|
||||
* // ['0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098']
|
||||
*/
|
||||
async sendRawTransaction(hex, allowhighfees = false) {
|
||||
async sendRawTransaction (hex, allowhighfees = false) {
|
||||
try {
|
||||
// Single tx hex.
|
||||
if (typeof hex === "string") {
|
||||
const response = await axios.get(
|
||||
if (typeof hex === 'string') {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}rawtransactions/sendRawTransaction/${hex}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
|
||||
if (response.data === "66: insufficient priority") {
|
||||
if (response.data === '66: insufficient priority') {
|
||||
console.warn(
|
||||
`WARN: Insufficient Priority! This is likely due to a fee that is too low, or insufficient funds.
|
||||
Please ensure that there is BCH in the given wallet. If you are running on the testnet, get some
|
||||
@@ -332,21 +343,19 @@ class RawTransactions {
|
||||
// Array input
|
||||
} else if (Array.isArray(hex)) {
|
||||
const options = {
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
url: `${this.restURL}rawtransactions/sendRawTransaction`,
|
||||
data: {
|
||||
hexes: hex
|
||||
},
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
headers: _this.axiosOptions.headers
|
||||
}
|
||||
const response = await axios(options)
|
||||
const response = await _this.axios(options)
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input hex must be a string or array of strings.`)
|
||||
throw new Error('Input hex must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
|
||||
+32
-22
@@ -1,14 +1,24 @@
|
||||
const schnorr = require("bip-schnorr")
|
||||
const schnorr = require('bip-schnorr')
|
||||
|
||||
class Schnorr {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.authToken = config.authToken
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +46,7 @@ class Schnorr {
|
||||
* console.log("The signature is: " + createdSignature.toString("hex"))
|
||||
* // The signature is: 2a298dacae57395a15d0795ddbfd1dcb564da82b0f269bc70a74f8220429ba1d1e51a22ccec35599b8f266912281f8365ffc2d035a230434a1a64dc59f7013fd
|
||||
*/
|
||||
sign(privateKey, message) {
|
||||
sign (privateKey, message) {
|
||||
return schnorr.sign(privateKey, message)
|
||||
}
|
||||
|
||||
@@ -68,7 +78,7 @@ class Schnorr {
|
||||
* console.error("The signature verification failed: " + e)
|
||||
* }
|
||||
*/
|
||||
verify(publicKey, message, signatureToVerify) {
|
||||
verify (publicKey, message, signatureToVerify) {
|
||||
return schnorr.verify(publicKey, message, signatureToVerify)
|
||||
}
|
||||
|
||||
@@ -130,7 +140,7 @@ class Schnorr {
|
||||
* console.error("The signature verification failed: " + e)
|
||||
* }
|
||||
*/
|
||||
batchVerify(publicKeys, messages, signaturesToVerify) {
|
||||
batchVerify (publicKeys, messages, signaturesToVerify) {
|
||||
return schnorr.batchVerify(publicKeys, messages, signaturesToVerify)
|
||||
}
|
||||
|
||||
@@ -179,7 +189,7 @@ class Schnorr {
|
||||
* console.error("The signature verification failed: " + e)
|
||||
* }
|
||||
*/
|
||||
nonInteractive(privateKeys, message) {
|
||||
nonInteractive (privateKeys, message) {
|
||||
return schnorr.muSig.nonInteractive(privateKeys, message)
|
||||
}
|
||||
|
||||
@@ -253,7 +263,7 @@ class Schnorr {
|
||||
* // -----------------------------------------------------------------------
|
||||
* publicData.pubKeyHash = bchjs.Schnorr.computeEll(publicData.pubKeys)
|
||||
*/
|
||||
computeEll(publicKeys) {
|
||||
computeEll (publicKeys) {
|
||||
return schnorr.muSig.computeEll(publicKeys)
|
||||
}
|
||||
|
||||
@@ -271,7 +281,7 @@ class Schnorr {
|
||||
* publicData.pubKeyHash
|
||||
* )
|
||||
*/
|
||||
publicKeyCombine(publicKeys, publicKeyHash) {
|
||||
publicKeyCombine (publicKeys, publicKeyHash) {
|
||||
return schnorr.muSig.pubKeyCombine(publicKeys, publicKeyHash)
|
||||
}
|
||||
|
||||
@@ -303,7 +313,7 @@ class Schnorr {
|
||||
* })
|
||||
* const signerSession = signerPrivateData[0].session
|
||||
*/
|
||||
sessionInitialize(sessionId, privateKey, message, pubKeyCombined, ell, idx) {
|
||||
sessionInitialize (sessionId, privateKey, message, pubKeyCombined, ell, idx) {
|
||||
return schnorr.muSig.sessionInitialize(
|
||||
sessionId,
|
||||
privateKey,
|
||||
@@ -355,7 +365,7 @@ class Schnorr {
|
||||
* data => (data.session.nonceIsNegated = signerSession.nonceIsNegated)
|
||||
* )
|
||||
*/
|
||||
sessionNonceCombine(session, nonces) {
|
||||
sessionNonceCombine (session, nonces) {
|
||||
return schnorr.muSig.sessionNonceCombine(session, nonces)
|
||||
}
|
||||
|
||||
@@ -382,7 +392,7 @@ class Schnorr {
|
||||
* )
|
||||
* })
|
||||
*/
|
||||
partialSign(session, message, nonceCombined, pubKeyCombined) {
|
||||
partialSign (session, message, nonceCombined, pubKeyCombined) {
|
||||
return schnorr.muSig.partialSign(
|
||||
session,
|
||||
message,
|
||||
@@ -426,7 +436,7 @@ class Schnorr {
|
||||
* )
|
||||
* }
|
||||
*/
|
||||
partialSignatureVerify(
|
||||
partialSignatureVerify (
|
||||
session,
|
||||
partialSignature,
|
||||
nonceCombined,
|
||||
@@ -474,27 +484,27 @@ class Schnorr {
|
||||
* publicData.signature
|
||||
* )
|
||||
*/
|
||||
partialSignaturesCombine(nonceCombined, partialSignatures) {
|
||||
partialSignaturesCombine (nonceCombined, partialSignatures) {
|
||||
return schnorr.muSig.partialSigCombine(nonceCombined, partialSignatures)
|
||||
}
|
||||
|
||||
bufferToInt(buffer) {
|
||||
bufferToInt (buffer) {
|
||||
return schnorr.convert.bufferToInt(buffer)
|
||||
}
|
||||
|
||||
intToBuffer(bigInteger) {
|
||||
intToBuffer (bigInteger) {
|
||||
return schnorr.convert.intToBuffer(bigInteger)
|
||||
}
|
||||
|
||||
hash(buffer) {
|
||||
hash (buffer) {
|
||||
return schnorr.convert.hash(buffer)
|
||||
}
|
||||
|
||||
pointToBuffer(point) {
|
||||
pointToBuffer (point) {
|
||||
return schnorr.convert.pointToBuffer(point)
|
||||
}
|
||||
|
||||
pubKeyToPoint(publicKey) {
|
||||
pubKeyToPoint (publicKey) {
|
||||
return schnorr.convert.pubKeyToPoint(publicKey)
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,8 +1,8 @@
|
||||
const Bitcoin = require("bitcoincashjs-lib")
|
||||
const opcodes = require("bitcoincash-ops")
|
||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
||||
const opcodes = require('@psf/bitcoincash-ops')
|
||||
|
||||
class Script {
|
||||
constructor() {
|
||||
constructor () {
|
||||
this.opcodes = opcodes
|
||||
this.nullData = Bitcoin.script.nullData
|
||||
this.multisig = {
|
||||
@@ -58,7 +58,7 @@ class Script {
|
||||
* bchjs.Script.classifyInput(bchjs.Script.fromASM(scripthashInput));
|
||||
* // scripthash
|
||||
*/
|
||||
classifyInput(script) {
|
||||
classifyInput (script) {
|
||||
return Bitcoin.script.classifyInput(script)
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ class Script {
|
||||
* bchjs.Script.classifyOutput(bchjs.Script.fromASM(scripthashOutput));
|
||||
* // scripthash
|
||||
*/
|
||||
classifyOutput(script) {
|
||||
classifyOutput (script) {
|
||||
return Bitcoin.script.classifyOutput(script)
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ class Script {
|
||||
* // 136,
|
||||
* // 172 ]
|
||||
*/
|
||||
decode(scriptBuffer) {
|
||||
decode (scriptBuffer) {
|
||||
return Bitcoin.script.decompile(scriptBuffer)
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ class Script {
|
||||
* bchjs.Script.encode(scriptPubKey);
|
||||
* // <Buffer 76 a9 14 24 e9 c0 78 04 d0 ee 7e 5b da 93 4e 0a 3a e8 71 0f c0 07 dd 88 ac>
|
||||
*/
|
||||
encode(scriptChunks) {
|
||||
encode (scriptChunks) {
|
||||
const arr = []
|
||||
scriptChunks.forEach(chunk => {
|
||||
arr.push(chunk)
|
||||
@@ -187,7 +187,7 @@ class Script {
|
||||
* bchjs.Script.encode2(scriptPubKey);
|
||||
* // <Buffer 76 a9 14 24 e9 c0 78 04 d0 ee 7e 5b da 93 4e 0a 3a e8 71 0f c0 07 dd 88 ac>
|
||||
*/
|
||||
encode2(scriptChunks) {
|
||||
encode2 (scriptChunks) {
|
||||
const arr = []
|
||||
scriptChunks.forEach(chunk => {
|
||||
arr.push(chunk)
|
||||
@@ -213,7 +213,7 @@ class Script {
|
||||
* bchjs.Script.toASM(scriptBuffer);
|
||||
* // OP_DUP OP_HASH160 bee4182d9fbc8931a728410a0cd3e0f340f2995a OP_EQUALVERIFY OP_CHECKSIG
|
||||
*/
|
||||
toASM(buffer) {
|
||||
toASM (buffer) {
|
||||
return Bitcoin.script.toASM(buffer)
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ class Script {
|
||||
* bchjs.Script.fromASM(scriptPubKeyASM);
|
||||
* // <Buffer 76 a9 14 be e4 18 2d 9f bc 89 31 a7 28 41 0a 0c d3 e0 f3 40 f2 99 5a 88 ac>
|
||||
*/
|
||||
fromASM(asm) {
|
||||
fromASM (asm) {
|
||||
return Bitcoin.script.fromASM(asm)
|
||||
}
|
||||
}
|
||||
|
||||
+26
-20
@@ -1,11 +1,11 @@
|
||||
const BCHJSAddress = require("../address")
|
||||
const BCHJSAddress = require('../address')
|
||||
// const bchAddress = new BCHJSAddress()
|
||||
let bchAddress
|
||||
|
||||
const bchaddrjs = require("bchaddrjs-slp")
|
||||
const bchaddrjs = require('bchaddrjs-slp')
|
||||
|
||||
class Address extends BCHJSAddress {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
super(config)
|
||||
|
||||
this.restURL = config.restURL
|
||||
@@ -52,11 +52,11 @@ class Address extends BCHJSAddress {
|
||||
* bchjs.SLP.Address.toSLPAddress('msDbtTj7kWXPpYaR7PQmMK84i66fJqQMLx', false)
|
||||
* // qzq9je6pntpva3wf6scr7mlnycr54sjgeqauyclpwv
|
||||
*/
|
||||
toSLPAddress(address, prefix = true, regtest = false) {
|
||||
toSLPAddress (address, prefix = true, regtest = false) {
|
||||
this._ensureValidAddress(address)
|
||||
const slpAddress = bchaddrjs.toSlpAddress(address)
|
||||
if (prefix) return slpAddress
|
||||
return slpAddress.split(":")[1]
|
||||
return slpAddress.split(':')[1]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,11 +98,11 @@ class Address extends BCHJSAddress {
|
||||
* bchjs.SLP.Address.toCashAddress('msDbtTj7kWXPpYaR7PQmMK84i66fJqQMLx', false)
|
||||
* // qzq9je6pntpva3wf6scr7mlnycr54sjgeqxgrr9ku3
|
||||
*/
|
||||
toCashAddress(address, prefix = true, regtest = false) {
|
||||
toCashAddress (address, prefix = true, regtest = false) {
|
||||
this._ensureValidAddress(address)
|
||||
const cashAddress = bchaddrjs.toCashAddress(address)
|
||||
if (prefix) return cashAddress
|
||||
return cashAddress.split(":")[1]
|
||||
return cashAddress.split(':')[1]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,18 +145,18 @@ class Address extends BCHJSAddress {
|
||||
* bchjs.SLP.Address.toLegacyAddress('qph2v4mkxjgdqgmlyjx6njmey0ftrxlnggs3v58dse')
|
||||
* // mqc1tmwY2368LLGktnePzEyPAsgADxbksi
|
||||
*/
|
||||
toLegacyAddress(address) {
|
||||
toLegacyAddress (address) {
|
||||
this._ensureValidAddress(address)
|
||||
const cashAddr = bchaddrjs.toCashAddress(address)
|
||||
return bchAddress.toLegacyAddress(cashAddr)
|
||||
}
|
||||
|
||||
isLegacyAddress(address) {
|
||||
isLegacyAddress (address) {
|
||||
this._ensureValidAddress(address)
|
||||
return bchAddress.isLegacyAddress(address)
|
||||
}
|
||||
|
||||
isCashAddress(address) {
|
||||
isCashAddress (address) {
|
||||
this._ensureValidAddress(address)
|
||||
if (bchaddrjs.isSlpAddress(address)) return false
|
||||
|
||||
@@ -195,7 +195,7 @@ class Address extends BCHJSAddress {
|
||||
* bchjs.SLP.Address.isSLPAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
|
||||
* // false
|
||||
*/
|
||||
isSLPAddress(address) {
|
||||
isSLPAddress (address) {
|
||||
this._ensureValidAddress(address)
|
||||
return bchaddrjs.isSlpAddress(address)
|
||||
}
|
||||
@@ -248,7 +248,7 @@ class Address extends BCHJSAddress {
|
||||
* bchjs.SLP.Address.isMainnetAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
|
||||
* // false
|
||||
*/
|
||||
isMainnetAddress(address) {
|
||||
isMainnetAddress (address) {
|
||||
this._ensureValidAddress(address)
|
||||
const cashaddr = bchaddrjs.toCashAddress(address)
|
||||
return bchAddress.isMainnetAddress(cashaddr)
|
||||
@@ -301,11 +301,12 @@ class Address extends BCHJSAddress {
|
||||
* bchjs.SLP.Address.isTestnetAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
|
||||
* // true
|
||||
*/
|
||||
isTestnetAddress(address) {
|
||||
isTestnetAddress (address) {
|
||||
this._ensureValidAddress(address)
|
||||
const cashAddr = bchaddrjs.toCashAddress(address)
|
||||
return bchAddress.isTestnetAddress(cashAddr)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Address.isP2PKHAddress() isP2PKHAddress()
|
||||
* @apiName isP2PKHAddress
|
||||
@@ -353,11 +354,12 @@ class Address extends BCHJSAddress {
|
||||
* bchjs.SLP.Address.isP2PKHAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
|
||||
* // true
|
||||
*/
|
||||
isP2PKHAddress(address) {
|
||||
isP2PKHAddress (address) {
|
||||
this._ensureValidAddress(address)
|
||||
const cashAddr = bchaddrjs.toCashAddress(address)
|
||||
return bchAddress.isP2PKHAddress(cashAddr)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Address.isP2SHAddress() isP2SHAddress()
|
||||
* @apiName isP2SHAddress
|
||||
@@ -405,11 +407,12 @@ class Address extends BCHJSAddress {
|
||||
* bchjs.SLP.Address.isP2SHAddress('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
|
||||
* // false
|
||||
*/
|
||||
isP2SHAddress(address) {
|
||||
isP2SHAddress (address) {
|
||||
this._ensureValidAddress(address)
|
||||
const cashAddr = bchaddrjs.toCashAddress(address)
|
||||
return bchAddress.isP2SHAddress(cashAddr)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Address.detectAddressFormat() detectAddressFormat()
|
||||
* @apiName detectAddressFormat
|
||||
@@ -457,12 +460,13 @@ class Address extends BCHJSAddress {
|
||||
* bchjs.SLP.Address.detectAddressFormat('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
|
||||
* // legacy
|
||||
*/
|
||||
detectAddressFormat(address) {
|
||||
detectAddressFormat (address) {
|
||||
this._ensureValidAddress(address)
|
||||
if (bchaddrjs.isSlpAddress(address)) return "slpaddr"
|
||||
if (bchaddrjs.isSlpAddress(address)) return 'slpaddr'
|
||||
|
||||
return bchAddress.detectAddressFormat(address)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Address.detectAddressNetwork() detectAddressNetwork()
|
||||
* @apiName detectAddressNetwork
|
||||
@@ -510,11 +514,12 @@ class Address extends BCHJSAddress {
|
||||
* bchjs.SLP.Address.detectAddressNetwork('mqc1tmwY2368LLGktnePzEyPAsgADxbksi')
|
||||
* // testnet
|
||||
*/
|
||||
detectAddressNetwork(address) {
|
||||
detectAddressNetwork (address) {
|
||||
this._ensureValidAddress(address)
|
||||
const cashAddr = bchaddrjs.toCashAddress(address)
|
||||
return bchAddress.detectAddressNetwork(cashAddr)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Address.detectAddressType() detectAddressType()
|
||||
* @apiName detectAddressType
|
||||
@@ -562,11 +567,12 @@ class Address extends BCHJSAddress {
|
||||
* bchjs.SLP.Address.detectAddressType('mqc1tmwY2368LLGktnePzEyPAsgADxbksi');
|
||||
* // p2pkh
|
||||
*/
|
||||
detectAddressType(address) {
|
||||
detectAddressType (address) {
|
||||
this._ensureValidAddress(address)
|
||||
const cashAddr = bchaddrjs.toCashAddress(address)
|
||||
return bchAddress.detectAddressType(cashAddr)
|
||||
}
|
||||
|
||||
/*
|
||||
async details(address) {
|
||||
let tmpBITBOX
|
||||
@@ -644,7 +650,7 @@ class Address extends BCHJSAddress {
|
||||
return tmpBITBOX.Address.transactions(address)
|
||||
}
|
||||
*/
|
||||
_ensureValidAddress(address) {
|
||||
_ensureValidAddress (address) {
|
||||
try {
|
||||
bchaddrjs.toCashAddress(address)
|
||||
} catch (err) {
|
||||
|
||||
+5
-5
@@ -1,9 +1,9 @@
|
||||
//const BCHJS = require("../bch-js")
|
||||
//const bchjs = new BCHJS()
|
||||
// const BCHJS = require("../bch-js")
|
||||
// const bchjs = new BCHJS()
|
||||
|
||||
const BCHJSECPair = require("../ecpair")
|
||||
const BCHJSECPair = require('../ecpair')
|
||||
|
||||
const bchaddrjs = require("bchaddrjs-slp")
|
||||
const bchaddrjs = require('bchaddrjs-slp')
|
||||
|
||||
class ECPair extends BCHJSECPair {
|
||||
/*
|
||||
@@ -25,7 +25,7 @@ class ECPair extends BCHJSECPair {
|
||||
* bchjs.SLP.ECPair.toSLPAddress(ecpair);
|
||||
* // slptest:qq835u5srlcqwrtwt6xm4efwan30fxg9hcqag6fk03
|
||||
*/
|
||||
static toSLPAddress(ecpair) {
|
||||
static toSLPAddress (ecpair) {
|
||||
const slpAddress = bchaddrjs.toSlpAddress(this.toCashAddress(ecpair))
|
||||
return slpAddress
|
||||
}
|
||||
|
||||
+60
-54
@@ -8,17 +8,17 @@
|
||||
(Parent) token.
|
||||
*/
|
||||
|
||||
const Address = require("./address")
|
||||
const Address = require('./address')
|
||||
|
||||
const BigNumber = require("bignumber.js")
|
||||
const slpMdm = require("slp-mdm")
|
||||
// const BigNumber = require('bignumber.js')
|
||||
const slpMdm = require('slp-mdm')
|
||||
|
||||
// const addy = new Address()
|
||||
let addy
|
||||
const TransactionBuilder = require("../transaction-builder")
|
||||
const TransactionBuilder = require('../transaction-builder')
|
||||
|
||||
class TokenType1 {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
|
||||
addy = new Address(config)
|
||||
@@ -59,12 +59,12 @@ class TokenType1 {
|
||||
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/tree/master/applications/slp/nft
|
||||
*
|
||||
*/
|
||||
newNFTGroupOpReturn(configObj) {
|
||||
newNFTGroupOpReturn (configObj) {
|
||||
try {
|
||||
// TODO: Add input validation.
|
||||
|
||||
// Prevent error if user fails to add the document hash.
|
||||
if (!configObj.documentHash) configObj.documentHash = ""
|
||||
if (!configObj.documentHash) configObj.documentHash = ''
|
||||
|
||||
// If mint baton is not specified, then replace it with null.
|
||||
if (!configObj.mintBatonVout) configObj.mintBatonVout = null
|
||||
@@ -81,7 +81,7 @@ class TokenType1 {
|
||||
|
||||
return script
|
||||
} catch (err) {
|
||||
console.log(`Error in generateNFTParentOpReturn()`)
|
||||
console.log('Error in generateNFTParentOpReturn()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -130,43 +130,47 @@ class TokenType1 {
|
||||
* // See additional code here:
|
||||
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/tree/master/applications/slp/nft
|
||||
*/
|
||||
mintNFTGroupOpReturn(tokenUtxos, mintQty, destroyBaton = false) {
|
||||
try {
|
||||
// Throw error if input is not an array.
|
||||
if (!Array.isArray(tokenUtxos))
|
||||
throw new Error(`tokenUtxos must be an array.`)
|
||||
|
||||
// Loop through the tokenUtxos array and find the minting baton.
|
||||
let mintBatonUtxo
|
||||
for (let i = 0; i < tokenUtxos.length; i++) {
|
||||
if (tokenUtxos[i].utxoType === "minting-baton")
|
||||
mintBatonUtxo = tokenUtxos[i]
|
||||
}
|
||||
|
||||
// Throw an error if the minting baton could not be found.
|
||||
if (!mintBatonUtxo)
|
||||
throw new Error(`Minting baton could not be found in tokenUtxos array.`)
|
||||
|
||||
const tokenId = mintBatonUtxo.tokenId
|
||||
|
||||
if (!tokenId)
|
||||
throw new Error(`tokenId property not found in mint-baton UTXO.`)
|
||||
|
||||
// Signal that the baton should be passed or detroyed.
|
||||
let batonVout = 2
|
||||
if (destroyBaton) batonVout = null
|
||||
|
||||
const script = slpMdm.NFT1.Group.mint(
|
||||
tokenId,
|
||||
batonVout,
|
||||
new slpMdm.BN(mintQty)
|
||||
)
|
||||
|
||||
return script
|
||||
} catch (err) {
|
||||
// console.log(`Error in generateMintOpReturn()`)
|
||||
throw err
|
||||
mintNFTGroupOpReturn (tokenUtxos, mintQty, destroyBaton = false) {
|
||||
// try {
|
||||
// Throw error if input is not an array.
|
||||
if (!Array.isArray(tokenUtxos)) {
|
||||
throw new Error('tokenUtxos must be an array.')
|
||||
}
|
||||
|
||||
// Loop through the tokenUtxos array and find the minting baton.
|
||||
let mintBatonUtxo
|
||||
for (let i = 0; i < tokenUtxos.length; i++) {
|
||||
if (tokenUtxos[i].utxoType === 'minting-baton') {
|
||||
mintBatonUtxo = tokenUtxos[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Throw an error if the minting baton could not be found.
|
||||
if (!mintBatonUtxo) {
|
||||
throw new Error('Minting baton could not be found in tokenUtxos array.')
|
||||
}
|
||||
|
||||
const tokenId = mintBatonUtxo.tokenId
|
||||
|
||||
if (!tokenId) {
|
||||
throw new Error('tokenId property not found in mint-baton UTXO.')
|
||||
}
|
||||
|
||||
// Signal that the baton should be passed or detroyed.
|
||||
let batonVout = 2
|
||||
if (destroyBaton) batonVout = null
|
||||
|
||||
const script = slpMdm.NFT1.Group.mint(
|
||||
tokenId,
|
||||
batonVout,
|
||||
new slpMdm.BN(mintQty)
|
||||
)
|
||||
|
||||
return script
|
||||
// } catch (err) {
|
||||
// // console.log(`Error in generateMintOpReturn()`)
|
||||
// throw err
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,12 +204,12 @@ class TokenType1 {
|
||||
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/tree/master/applications/slp/nft
|
||||
*
|
||||
*/
|
||||
generateNFTChildGenesisOpReturn(configObj) {
|
||||
generateNFTChildGenesisOpReturn (configObj) {
|
||||
try {
|
||||
// TODO: Add input validation.
|
||||
|
||||
// Prevent error if user fails to add the document hash.
|
||||
if (!configObj.documentHash) configObj.documentHash = ""
|
||||
if (!configObj.documentHash) configObj.documentHash = ''
|
||||
|
||||
// If mint baton is not specified, then replace it with null.
|
||||
if (!configObj.mintBatonVout) configObj.mintBatonVout = null
|
||||
@@ -217,12 +221,12 @@ class TokenType1 {
|
||||
configObj.documentHash,
|
||||
0,
|
||||
configObj.mintBatonVout,
|
||||
new slpMdm.BN("1")
|
||||
new slpMdm.BN('1')
|
||||
)
|
||||
|
||||
return script
|
||||
} catch (err) {
|
||||
console.log(`Error in generateNFTChildGenesisOpReturn()`)
|
||||
console.log('Error in generateNFTChildGenesisOpReturn()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -270,7 +274,7 @@ class TokenType1 {
|
||||
* // See additional code here:
|
||||
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/tree/master/applications/slp/nft
|
||||
*/
|
||||
generateNFTChildSendOpReturn(tokenUtxos, sendQty) {
|
||||
generateNFTChildSendOpReturn (tokenUtxos, sendQty) {
|
||||
try {
|
||||
// TODO: Add input validation.
|
||||
|
||||
@@ -278,8 +282,9 @@ class TokenType1 {
|
||||
|
||||
// Calculate the total amount of tokens owned by the wallet.
|
||||
let totalTokens = 0
|
||||
for (let i = 0; i < tokenUtxos.length; i++)
|
||||
for (let i = 0; i < tokenUtxos.length; i++) {
|
||||
totalTokens += tokenUtxos[i].tokenQty
|
||||
}
|
||||
|
||||
const change = totalTokens - sendQty
|
||||
|
||||
@@ -312,7 +317,7 @@ class TokenType1 {
|
||||
|
||||
return { script, outputs }
|
||||
} catch (err) {
|
||||
console.log(`Error in generateNFTChildSendOpReturn()`)
|
||||
console.log('Error in generateNFTChildSendOpReturn()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -360,7 +365,7 @@ class TokenType1 {
|
||||
* // See additional code here:
|
||||
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/tree/master/applications/slp/nft
|
||||
*/
|
||||
generateNFTGroupSendOpReturn(tokenUtxos, sendQty) {
|
||||
generateNFTGroupSendOpReturn (tokenUtxos, sendQty) {
|
||||
try {
|
||||
// TODO: Add input validation.
|
||||
|
||||
@@ -368,8 +373,9 @@ class TokenType1 {
|
||||
|
||||
// Calculate the total amount of tokens owned by the wallet.
|
||||
let totalTokens = 0
|
||||
for (let i = 0; i < tokenUtxos.length; i++)
|
||||
for (let i = 0; i < tokenUtxos.length; i++) {
|
||||
totalTokens += tokenUtxos[i].tokenQty
|
||||
}
|
||||
|
||||
const change = totalTokens - sendQty
|
||||
|
||||
@@ -402,7 +408,7 @@ class TokenType1 {
|
||||
|
||||
return { script, outputs }
|
||||
} catch (err) {
|
||||
console.log(`Error in generateNFTGroupSendOpReturn()`)
|
||||
console.log('Error in generateNFTGroupSendOpReturn()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
+27
-18
@@ -7,33 +7,42 @@
|
||||
|
||||
// imports
|
||||
// require deps
|
||||
//const BCHJS = require("../bch-js")
|
||||
const Address = require("./address")
|
||||
const ECPair = require("./ecpair")
|
||||
// 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")
|
||||
const TokenType1 = require('./tokentype1')
|
||||
const NFT1 = require('./nft1')
|
||||
const Utils = require('./utils')
|
||||
|
||||
// SLP is a superset of BITBOX
|
||||
class SLP {
|
||||
constructor(config) {
|
||||
const tmp = {}
|
||||
if (!config || !config.restURL) {
|
||||
tmp.restURL = `https://api.fullstack.cash/v3/`
|
||||
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 {
|
||||
tmp.restURL = config.restURL
|
||||
tmp.apiToken = config.apiToken
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.restURL = tmp.restURL
|
||||
this.apiToken = tmp.apiToken
|
||||
|
||||
this.Address = new Address(tmp)
|
||||
this.Address = new Address(config)
|
||||
this.ECPair = ECPair
|
||||
this.TokenType1 = new TokenType1(tmp)
|
||||
this.TokenType1 = new TokenType1(config)
|
||||
this.NFT1 = new NFT1(this.restURL)
|
||||
this.Utils = new Utils(tmp)
|
||||
this.Utils = new Utils(config)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+97
-57
@@ -1,34 +1,49 @@
|
||||
//const BCHJS = require("../bch-js")
|
||||
//const bchjs = new BCHJS()
|
||||
/*
|
||||
This library handles the OP_RETURN of SLP TokenType1 transactions.
|
||||
*/
|
||||
|
||||
const Address = require("./address")
|
||||
const Script = require("../script")
|
||||
// const BCHJS = require("../bch-js")
|
||||
// const bchjs = new BCHJS()
|
||||
|
||||
const BigNumber = require("bignumber.js")
|
||||
const slpMdm = require("slp-mdm")
|
||||
const axios = require("axios")
|
||||
const Address = require('./address')
|
||||
const Script = require('../script')
|
||||
|
||||
const BigNumber = require('bignumber.js')
|
||||
const slpMdm = require('slp-mdm')
|
||||
const axios = require('axios')
|
||||
|
||||
// const addy = new Address()
|
||||
let addy
|
||||
const TransactionBuilder = require("../transaction-builder")
|
||||
const TransactionBuilder = require('../transaction-builder')
|
||||
|
||||
let _this // local global
|
||||
|
||||
class TokenType1 {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.authToken = config.authToken
|
||||
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addy = new Address(config)
|
||||
this.Script = new Script()
|
||||
|
||||
this.axios = axios
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate the transaction builder.
|
||||
TransactionBuilder.setAddress(addy)
|
||||
@@ -77,17 +92,21 @@ class TokenType1 {
|
||||
* // See additional code here:
|
||||
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/blob/master/applications/slp/send-token/send-token.js
|
||||
*/
|
||||
generateSendOpReturn(tokenUtxos, sendQty) {
|
||||
generateSendOpReturn (tokenUtxos, sendQty) {
|
||||
try {
|
||||
const tokenId = tokenUtxos[0].tokenId
|
||||
const decimals = tokenUtxos[0].decimals
|
||||
|
||||
// Calculate the total amount of tokens owned by the wallet.
|
||||
let totalTokens = 0
|
||||
for (let i = 0; i < tokenUtxos.length; i++)
|
||||
totalTokens += tokenUtxos[i].tokenQty
|
||||
const sendQtyBig = new BigNumber(sendQty).times(10 ** decimals)
|
||||
|
||||
const change = totalTokens - sendQty
|
||||
// Calculate the total amount of tokens owned by the wallet.
|
||||
const totalTokens = tokenUtxos.reduce(
|
||||
(tot, txo) =>
|
||||
tot.plus(new BigNumber(txo.tokenQty).times(10 ** decimals)),
|
||||
new BigNumber(0)
|
||||
)
|
||||
|
||||
const change = totalTokens.minus(sendQtyBig)
|
||||
// console.log(`change: ${change}`)
|
||||
|
||||
let script
|
||||
@@ -98,18 +117,22 @@ class TokenType1 {
|
||||
outputs = 2
|
||||
|
||||
// Convert the send quantity to the format expected by slp-mdm.
|
||||
let baseQty = new BigNumber(sendQty).times(10 ** decimals)
|
||||
baseQty = baseQty.absoluteValue()
|
||||
baseQty = Math.floor(baseQty)
|
||||
baseQty = baseQty.toString()
|
||||
// console.log(`baseQty: `, baseQty)
|
||||
const baseQty = sendQtyBig.toString()
|
||||
console.log('baseQty: ', baseQty)
|
||||
|
||||
// Convert the change quantity to the format expected by slp-mdm.
|
||||
let baseChange = new BigNumber(change).times(10 ** decimals)
|
||||
baseChange = baseChange.absoluteValue()
|
||||
baseChange = Math.floor(baseChange)
|
||||
baseChange = baseChange.toString()
|
||||
// console.log(`baseChange: `, baseChange)
|
||||
const baseChange = change.toString()
|
||||
console.log('baseChange: ', baseChange)
|
||||
|
||||
// Check for potential burns
|
||||
const outputQty = new BigNumber(baseChange).plus(
|
||||
new BigNumber(baseQty)
|
||||
)
|
||||
const inputQty = new BigNumber(totalTokens)
|
||||
const tokenOutputDelta = outputQty.minus(inputQty).toString() !== '0'
|
||||
if (tokenOutputDelta) {
|
||||
throw new Error('Token transaction inputs do not match outputs, cannot send transaction')
|
||||
}
|
||||
|
||||
// Generate the OP_RETURN as a Buffer.
|
||||
script = slpMdm.TokenType1.send(tokenId, [
|
||||
@@ -120,13 +143,17 @@ class TokenType1 {
|
||||
|
||||
// Corner case, when there is no token change to send back.
|
||||
} else {
|
||||
let baseQty = new BigNumber(sendQty).times(10 ** decimals)
|
||||
baseQty = baseQty.absoluteValue()
|
||||
baseQty = Math.floor(baseQty)
|
||||
baseQty = baseQty.toString()
|
||||
const baseQty = sendQtyBig.toString()
|
||||
// console.log(`baseQty: `, baseQty)
|
||||
|
||||
// console.log(`baseQty: ${baseQty.toString()}`)
|
||||
// Check for potential burns
|
||||
const noChangeOutputQty = new BigNumber(baseQty)
|
||||
const noChangeInputQty = new BigNumber(totalTokens)
|
||||
const tokenSingleOutputError =
|
||||
noChangeOutputQty.minus(noChangeInputQty).toString() !== '0'
|
||||
if (tokenSingleOutputError) {
|
||||
throw new Error('Token transaction inputs do not match outputs, cannot send transaction')
|
||||
}
|
||||
|
||||
// Generate the OP_RETURN as a Buffer.
|
||||
script = slpMdm.TokenType1.send(tokenId, [new slpMdm.BN(baseQty)])
|
||||
@@ -134,7 +161,7 @@ class TokenType1 {
|
||||
|
||||
return { script, outputs }
|
||||
} catch (err) {
|
||||
console.log(`Error in generateSendOpReturn()`)
|
||||
console.log('Error in generateSendOpReturn()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -185,15 +212,21 @@ class TokenType1 {
|
||||
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/blob/master/applications/slp/burn-tokens/burn-tokens.js
|
||||
*
|
||||
*/
|
||||
generateBurnOpReturn(tokenUtxos, burnQty) {
|
||||
generateBurnOpReturn (tokenUtxos, burnQty) {
|
||||
try {
|
||||
const tokenId = tokenUtxos[0].tokenId
|
||||
const decimals = tokenUtxos[0].decimals
|
||||
|
||||
// Calculate the total amount of tokens owned by the wallet.
|
||||
let totalTokens = 0
|
||||
for (let i = 0; i < tokenUtxos.length; i++)
|
||||
totalTokens += tokenUtxos[i].tokenQty
|
||||
for (let i = 0; i < tokenUtxos.length; i++) {
|
||||
totalTokens += parseFloat(tokenUtxos[i].tokenQty)
|
||||
}
|
||||
|
||||
// Make sure burn quantity isn't bigger than the total amount in tokens
|
||||
if (burnQty > totalTokens) {
|
||||
burnQty = totalTokens
|
||||
}
|
||||
|
||||
const remainder = totalTokens - burnQty
|
||||
|
||||
@@ -209,7 +242,7 @@ class TokenType1 {
|
||||
|
||||
return script
|
||||
} catch (err) {
|
||||
console.log(`Error in generateBurnOpReturn()`)
|
||||
console.log('Error in generateBurnOpReturn()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -248,7 +281,7 @@ class TokenType1 {
|
||||
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/blob/master/applications/slp/create-token/create-token.js
|
||||
*
|
||||
*/
|
||||
generateGenesisOpReturn(configObj) {
|
||||
generateGenesisOpReturn (configObj) {
|
||||
try {
|
||||
// TODO: Add input validation.
|
||||
|
||||
@@ -260,7 +293,7 @@ class TokenType1 {
|
||||
baseQty = baseQty.toString()
|
||||
|
||||
// Prevent error if user fails to add the document hash.
|
||||
if (!configObj.documentHash) configObj.documentHash = ""
|
||||
if (!configObj.documentHash) configObj.documentHash = ''
|
||||
|
||||
// If mint baton is not specified, then replace it with null.
|
||||
if (!configObj.mintBatonVout) configObj.mintBatonVout = null
|
||||
@@ -277,7 +310,7 @@ class TokenType1 {
|
||||
|
||||
return script
|
||||
} catch (err) {
|
||||
console.log(`Error in generateGenesisOpReturn()`)
|
||||
console.log('Error in generateGenesisOpReturn()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -328,30 +361,37 @@ class TokenType1 {
|
||||
* // See additional code here:
|
||||
* // https://github.com/Permissionless-Software-Foundation/bch-js-examples/blob/master/applications/slp/mint-token/mint-token.js
|
||||
*/
|
||||
generateMintOpReturn(tokenUtxos, mintQty, destroyBaton = false) {
|
||||
generateMintOpReturn (tokenUtxos, mintQty, destroyBaton = false) {
|
||||
try {
|
||||
// Throw error if input is not an array.
|
||||
if (!Array.isArray(tokenUtxos))
|
||||
throw new Error(`tokenUtxos must be an array.`)
|
||||
if (!Array.isArray(tokenUtxos)) {
|
||||
throw new Error('tokenUtxos must be an array.')
|
||||
}
|
||||
|
||||
// Loop through the tokenUtxos array and find the minting baton.
|
||||
let mintBatonUtxo
|
||||
for (let i = 0; i < tokenUtxos.length; i++) {
|
||||
if (tokenUtxos[i].utxoType === "minting-baton")
|
||||
if (tokenUtxos[i].utxoType === 'minting-baton') {
|
||||
mintBatonUtxo = tokenUtxos[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Throw an error if the minting baton could not be found.
|
||||
if (!mintBatonUtxo)
|
||||
throw new Error(`Minting baton could not be found in tokenUtxos array.`)
|
||||
if (!mintBatonUtxo) {
|
||||
throw new Error(
|
||||
'Minting baton could not be found in tokenUtxos array.'
|
||||
)
|
||||
}
|
||||
|
||||
const tokenId = mintBatonUtxo.tokenId
|
||||
const decimals = mintBatonUtxo.decimals
|
||||
|
||||
if (!tokenId)
|
||||
throw new Error(`tokenId property not found in mint-baton UTXO.`)
|
||||
if (!decimals)
|
||||
throw new Error(`decimals property not found in mint-baton UTXO.`)
|
||||
if (!tokenId) {
|
||||
throw new Error('tokenId property not found in mint-baton UTXO.')
|
||||
}
|
||||
if (!decimals) {
|
||||
throw new Error('decimals property not found in mint-baton UTXO.')
|
||||
}
|
||||
|
||||
let baseQty = new BigNumber(mintQty).times(10 ** decimals)
|
||||
baseQty = baseQty.absoluteValue()
|
||||
@@ -370,7 +410,7 @@ class TokenType1 {
|
||||
|
||||
return script
|
||||
} catch (err) {
|
||||
// console.log(`Error in generateMintOpReturn()`)
|
||||
console.log('Error in generateMintOpReturn()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -402,7 +442,7 @@ class TokenType1 {
|
||||
* "outputs": 2
|
||||
* }
|
||||
*/
|
||||
async getHexOpReturn(tokenUtxos, sendQty) {
|
||||
async getHexOpReturn (tokenUtxos, sendQty) {
|
||||
try {
|
||||
// TODO: Add input filtering.
|
||||
|
||||
@@ -426,7 +466,7 @@ class TokenType1 {
|
||||
|
||||
return slpSendObj
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
console.log('Error in getHexOpReturn()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
+468
-136
@@ -1,5 +1,7 @@
|
||||
const axios = require("axios")
|
||||
const slpParser = require("slp-parser")
|
||||
// Public npm libraries
|
||||
const axios = require('axios')
|
||||
const slpParser = require('slp-parser')
|
||||
const BigNumber = require('bignumber.js')
|
||||
|
||||
// const Script = require("../script")
|
||||
// const scriptLib = new Script()
|
||||
@@ -9,19 +11,32 @@ const slpParser = require("slp-parser")
|
||||
let _this
|
||||
|
||||
class Utils {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.slpParser = slpParser
|
||||
this.authToken = config.authToken
|
||||
this.axios = axios
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
|
||||
this.whitelist = []
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,17 +195,18 @@ class Utils {
|
||||
* circulatingSupply: 19882.03820723,
|
||||
* mintingBatonStatus: 'ALIVE' } ]
|
||||
*/
|
||||
async list(id) {
|
||||
async list (id) {
|
||||
let path
|
||||
let method
|
||||
|
||||
if (!id) {
|
||||
method = "get"
|
||||
method = 'get'
|
||||
path = `${this.restURL}slp/list`
|
||||
} else if (typeof id === "string") {
|
||||
method = "get"
|
||||
} else if (typeof id === 'string') {
|
||||
method = 'get'
|
||||
path = `${this.restURL}slp/list/${id}`
|
||||
} else if (typeof id === "object") {
|
||||
method = "post"
|
||||
} else if (typeof id === 'object') {
|
||||
method = 'post'
|
||||
path = `${this.restURL}slp/list`
|
||||
}
|
||||
|
||||
@@ -198,10 +214,10 @@ class Utils {
|
||||
|
||||
try {
|
||||
let response
|
||||
if (method === "get") {
|
||||
response = await axios.get(path, _this.axiosOptions)
|
||||
if (method === 'get') {
|
||||
response = await _this.axios.get(path, _this.axiosOptions)
|
||||
} else {
|
||||
response = await axios.post(
|
||||
response = await _this.axios.post(
|
||||
path,
|
||||
{
|
||||
tokenIds: id
|
||||
@@ -291,13 +307,13 @@ class Utils {
|
||||
* array of addresses.
|
||||
*/
|
||||
// Retrieve token balances for a given address.
|
||||
async balancesForAddress(address) {
|
||||
async balancesForAddress (address) {
|
||||
try {
|
||||
// Single address.
|
||||
if (typeof address === "string") {
|
||||
if (typeof address === 'string') {
|
||||
const path = `${this.restURL}slp/balancesForAddress/${address}`
|
||||
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
const response = await _this.axios.get(path, _this.axiosOptions)
|
||||
return response.data
|
||||
|
||||
// Array of addresses.
|
||||
@@ -305,7 +321,7 @@ class Utils {
|
||||
const path = `${this.restURL}slp/balancesForAddress`
|
||||
|
||||
// Dev note: must use axios.post for unit test stubbing.
|
||||
const response = await axios.post(
|
||||
const response = await _this.axios.post(
|
||||
path,
|
||||
{
|
||||
addresses: address
|
||||
@@ -316,7 +332,7 @@ class Utils {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error("Input address must be a string or array of strings.")
|
||||
throw new Error('Input address must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
throw error
|
||||
@@ -358,11 +374,11 @@ class Utils {
|
||||
*
|
||||
*/
|
||||
// Retrieve token balances for a given tokenId.
|
||||
async balancesForToken(tokenId) {
|
||||
const path = `${this.restURL}slp/balancesForToken/${tokenId}`
|
||||
|
||||
async balancesForToken (tokenId) {
|
||||
try {
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
const path = `${this.restURL}slp/balancesForToken/${tokenId}`
|
||||
|
||||
const response = await _this.axios.get(path, _this.axiosOptions)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
@@ -416,38 +432,34 @@ class Utils {
|
||||
* '00ea27261196a411776f81029c0ebe34362936b4a9847deb1f7a40a02b3a1476',
|
||||
* valid: true } ]
|
||||
*/
|
||||
async validateTxid(txid) {
|
||||
// This function has two responses. If SLPDB is working correctly, the output
|
||||
// will be like the examples above. If SLPDB has fallen behind real-time
|
||||
// processing, it will return this output:
|
||||
// [ null ]
|
||||
async validateTxid (txid) {
|
||||
const path = `${this.restURL}slp/validateTxid`
|
||||
|
||||
// console.log(`txid: ${JSON.stringify(txid, null, 2)}`)
|
||||
|
||||
// Handle a single TXID or an array of TXIDs.
|
||||
let txids
|
||||
if (typeof txid === "string") txids = [txid]
|
||||
if (typeof txid === 'string') txids = [txid]
|
||||
else txids = txid
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
const response = await _this.axios.post(
|
||||
path,
|
||||
{
|
||||
txids: txids
|
||||
},
|
||||
_this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
// console.log(
|
||||
// `validateTxid response.data: ${JSON.stringify(response.data, null, 2)}`
|
||||
// )
|
||||
|
||||
const validatedTxids = response.data
|
||||
|
||||
// Handle any null values
|
||||
for (let i = 0; i < validatedTxids.length; i++) {
|
||||
if (validatedTxids[i] === null) {
|
||||
validatedTxids[i] = {
|
||||
txid: txids[i],
|
||||
valid: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return validatedTxids
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
@@ -475,7 +487,7 @@ class Utils {
|
||||
* // validate single SLP txid
|
||||
* (async () => {
|
||||
* try {
|
||||
* let validated = await bchjs.SLP.Utils.validateTxid(
|
||||
* let validated = await bchjs.SLP.Utils.validateTxid2(
|
||||
* "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb"
|
||||
* );
|
||||
* console.log(validated);
|
||||
@@ -489,32 +501,182 @@ class Utils {
|
||||
* 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
|
||||
* valid: true } ]
|
||||
*/
|
||||
async validateTxid2(txid) {
|
||||
async validateTxid2 (txid) {
|
||||
try {
|
||||
// console.log(`txid: ${JSON.stringify(txid, null, 2)}`)
|
||||
|
||||
if (
|
||||
!txid ||
|
||||
txid === "" ||
|
||||
typeof txid !== "string" ||
|
||||
txid === '' ||
|
||||
typeof txid !== 'string' ||
|
||||
txid.length !== 64
|
||||
)
|
||||
throw new Error("txid must be 64 character string.")
|
||||
) {
|
||||
throw new Error('txid must be 64 character string.')
|
||||
}
|
||||
|
||||
const path = `${this.restURL}slp/validateTxid2/${txid}`
|
||||
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
const response = await _this.axios.get(path, _this.axiosOptions)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
|
||||
if (error.error && error.error.indexOf("Network error") > -1)
|
||||
throw new Error("slp-validate timed out")
|
||||
if (error.error && error.error.indexOf('Network error') > -1) {
|
||||
throw new Error('slp-validate timed out')
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Utils.whitelist() whitelist()
|
||||
* @apiName whitelist
|
||||
* @apiGroup SLP Utils
|
||||
* @apiDescription Get SLP tokens in whitelist
|
||||
* Retrieves a list of the SLP tokens that in the whitelist. Tokens in the
|
||||
* whitelist can be validated with the validateTxid3() function. validateTxid3()
|
||||
* will still work when the SLP network is under stress.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*
|
||||
* // validate single SLP txid
|
||||
* (async () => {
|
||||
* try {
|
||||
* let list = await bchjs.SLP.Utils.whitelit();
|
||||
* console.log(list);
|
||||
* } catch (error) {
|
||||
* console.error(error);
|
||||
* }
|
||||
* })();
|
||||
*
|
||||
* // returns
|
||||
* [
|
||||
* {
|
||||
* name: 'USDH',
|
||||
* tokenId:
|
||||
* 'c4b0d62156b3fa5c8f3436079b5394f7edc1bef5dc1cd2f9d0c4d46f82cca479'
|
||||
* },
|
||||
* {
|
||||
* name: 'SPICE',
|
||||
* tokenId:
|
||||
* '4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf'
|
||||
* },
|
||||
* {
|
||||
* name: 'PSF',
|
||||
* tokenId:
|
||||
* '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0'
|
||||
* },
|
||||
* {
|
||||
* name: 'TROUT',
|
||||
* tokenId:
|
||||
* 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'
|
||||
* },
|
||||
* {
|
||||
* name: 'PSFTEST',
|
||||
* tokenId:
|
||||
* 'd0ef4de95b78222bfee2326ab11382f4439aa0855936e2fe6ac129a8d778baa0'
|
||||
* }
|
||||
* ]
|
||||
*/
|
||||
async getWhitelist () {
|
||||
try {
|
||||
const path = `${this.restURL}slp/whitelist`
|
||||
|
||||
// Retrieve the whitelist from the REST API if we haven't gotten it yet.
|
||||
if (this.whitelist.length === 0) {
|
||||
const response = await _this.axios.get(path, _this.axiosOptions)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
this.whitelist = response.data
|
||||
}
|
||||
|
||||
return this.whitelist
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Utils.validateTxid3() validateTxid3()
|
||||
* @apiName validateTxid3
|
||||
* @apiGroup SLP Utils
|
||||
* @apiDescription Validate that txid is an SLP transaction using the SLPDB whitelist server.
|
||||
* Same exact functionality as the validateTxid() function, but this function
|
||||
* calls the whitelist SLPDB. It will only validate SLP tokens that are in the
|
||||
* whitelist. You can retrieve the whitelist with the SLP.Utils.whitelist()
|
||||
* function.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*
|
||||
* // validate single SLP txid
|
||||
* (async () => {
|
||||
* try {
|
||||
* let validated = await bchjs.SLP.Utils.validateTxid3(
|
||||
* "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb"
|
||||
* );
|
||||
* console.log(validated);
|
||||
* } catch (error) {
|
||||
* console.error(error);
|
||||
* }
|
||||
* })();
|
||||
*
|
||||
* // returns
|
||||
* [ { txid:
|
||||
* 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
|
||||
* valid: true } ]
|
||||
*
|
||||
* // validate multiple SLP txids
|
||||
* (async () => {
|
||||
* try {
|
||||
* let validated = await bchjs.SLP.Utils.validateTxid3([
|
||||
* "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb",
|
||||
* "00ea27261196a411776f81029c0ebe34362936b4a9847deb1f7a40a02b3a1476"
|
||||
* ]);
|
||||
* console.log(validated);
|
||||
* } catch (error) {
|
||||
* console.error(error);
|
||||
* }
|
||||
* })();
|
||||
*
|
||||
* // returns
|
||||
* [ { txid:
|
||||
* 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
|
||||
* valid: true },
|
||||
* { txid:
|
||||
* '00ea27261196a411776f81029c0ebe34362936b4a9847deb1f7a40a02b3a1476',
|
||||
* valid: true } ]
|
||||
*/
|
||||
async validateTxid3 (txid) {
|
||||
const path = `${this.restURL}slp/validateTxid3`
|
||||
|
||||
// console.log(`txid: ${JSON.stringify(txid, null, 2)}`)
|
||||
|
||||
// Handle a single TXID or an array of TXIDs.
|
||||
let txids
|
||||
if (typeof txid === 'string') txids = [txid]
|
||||
else txids = txid
|
||||
|
||||
try {
|
||||
const response = await _this.axios.post(
|
||||
path,
|
||||
{
|
||||
txids: txids
|
||||
},
|
||||
_this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
const validatedTxids = response.data
|
||||
|
||||
return validatedTxids
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Utils.tokenStats() tokenStats()
|
||||
* @apiName tokenStats
|
||||
@@ -550,11 +712,12 @@ class Utils {
|
||||
* satoshisLockedUp: 135408
|
||||
* }
|
||||
*/
|
||||
async tokenStats(tokenId) {
|
||||
const path = `${this.restURL}slp/tokenStats/${tokenId}`
|
||||
|
||||
async tokenStats (tokenId) {
|
||||
try {
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
const path = `${this.restURL}slp/tokenStats/${tokenId}`
|
||||
|
||||
const response = await _this.axios.get(path, _this.axiosOptions)
|
||||
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
@@ -620,11 +783,12 @@ class Utils {
|
||||
* ]
|
||||
*/
|
||||
// Retrieve token transactions for a given tokenId and address.
|
||||
async transactions(tokenId, address) {
|
||||
const path = `${this.restURL}slp/transactions/${tokenId}/${address}`
|
||||
|
||||
async transactions (tokenId, address) {
|
||||
try {
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
const path = `${this.restURL}slp/transactions/${tokenId}/${address}`
|
||||
|
||||
const response = await _this.axios.get(path, _this.axiosOptions)
|
||||
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
@@ -659,11 +823,12 @@ class Utils {
|
||||
* burnTotal: 100
|
||||
* }
|
||||
*/
|
||||
async burnTotal(transactionId) {
|
||||
const path = `${this.restURL}slp/burnTotal/${transactionId}`
|
||||
|
||||
async burnTotal (transactionId) {
|
||||
try {
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
const path = `${this.restURL}slp/burnTotal/${transactionId}`
|
||||
|
||||
const response = await _this.axios.get(path, _this.axiosOptions)
|
||||
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
@@ -692,20 +857,21 @@ class Utils {
|
||||
* })()
|
||||
*
|
||||
*/
|
||||
async txDetails(txid) {
|
||||
async txDetails (txid) {
|
||||
try {
|
||||
if (
|
||||
!txid ||
|
||||
txid === "" ||
|
||||
typeof txid !== "string" ||
|
||||
txid === '' ||
|
||||
typeof txid !== 'string' ||
|
||||
txid.length !== 64
|
||||
)
|
||||
throw new Error("txid string must be included.")
|
||||
) {
|
||||
throw new Error('txid string must be included.')
|
||||
}
|
||||
|
||||
// console.log(`this.restURL: ${this.restURL}`)
|
||||
const path = `${this.restURL}slp/txDetails/${txid}`
|
||||
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
const response = await _this.axios.get(path, _this.axiosOptions)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
@@ -757,7 +923,7 @@ class Utils {
|
||||
* }
|
||||
*/
|
||||
// Reimplementation of decodeOpReturn() using slp-parser.
|
||||
async decodeOpReturn(txid, cache = null) {
|
||||
async decodeOpReturn (txid, cache = null) {
|
||||
// The cache object is an in-memory cache (JS Object) that can be passed
|
||||
// into this function. It helps if multiple vouts from the same TXID are
|
||||
// being evaluated. In that case, it can significantly reduce the number
|
||||
@@ -766,8 +932,9 @@ class Utils {
|
||||
// cache[txid] = returnValue
|
||||
// Then pass that cache object back into this function every time its called.
|
||||
if (cache) {
|
||||
if (!(cache instanceof Object))
|
||||
throw new Error("decodeOpReturn cache parameter must be Object")
|
||||
if (!(cache instanceof Object)) {
|
||||
throw new Error('decodeOpReturn cache parameter must be Object')
|
||||
}
|
||||
|
||||
const cachedVal = cache[txid]
|
||||
if (cachedVal) return cachedVal
|
||||
@@ -775,12 +942,13 @@ class Utils {
|
||||
|
||||
try {
|
||||
// Validate the txid input.
|
||||
if (!txid || txid === "" || typeof txid !== "string")
|
||||
throw new Error("txid string must be included.")
|
||||
if (!txid || txid === '' || typeof txid !== 'string') {
|
||||
throw new Error('txid string must be included.')
|
||||
}
|
||||
|
||||
// Retrieve the transaction object from the full node.
|
||||
const path = `${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=true`
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
const response = await _this.axios.get(path, _this.axiosOptions)
|
||||
const txDetails = response.data
|
||||
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
|
||||
|
||||
@@ -788,19 +956,19 @@ class Utils {
|
||||
const opReturn = txDetails.vout[0].scriptPubKey.hex
|
||||
// console.log(`opReturn hex: ${opReturn}`)
|
||||
|
||||
const parsedData = _this.slpParser.parseSLP(Buffer.from(opReturn, "hex"))
|
||||
const parsedData = _this.slpParser.parseSLP(Buffer.from(opReturn, 'hex'))
|
||||
// console.log(`parsedData: ${JSON.stringify(parsedData, null, 2)}`)
|
||||
|
||||
// Convert Buffer data to hex strings or utf8 strings.
|
||||
let tokenData = {}
|
||||
if (parsedData.transactionType === "SEND") {
|
||||
if (parsedData.transactionType === 'SEND') {
|
||||
tokenData = {
|
||||
tokenType: parsedData.tokenType,
|
||||
txType: parsedData.transactionType,
|
||||
tokenId: parsedData.data.tokenId.toString("hex"),
|
||||
tokenId: parsedData.data.tokenId.toString('hex'),
|
||||
amounts: parsedData.data.amounts
|
||||
}
|
||||
} else if (parsedData.transactionType === "GENESIS") {
|
||||
} else if (parsedData.transactionType === 'GENESIS') {
|
||||
tokenData = {
|
||||
tokenType: parsedData.tokenType,
|
||||
txType: parsedData.transactionType,
|
||||
@@ -813,11 +981,11 @@ class Utils {
|
||||
mintBatonVout: parsedData.data.mintBatonVout,
|
||||
qty: parsedData.data.qty
|
||||
}
|
||||
} else if (parsedData.transactionType === "MINT") {
|
||||
} else if (parsedData.transactionType === 'MINT') {
|
||||
tokenData = {
|
||||
tokenType: parsedData.tokenType,
|
||||
txType: parsedData.transactionType,
|
||||
tokenId: parsedData.data.tokenId.toString("hex"),
|
||||
tokenId: parsedData.data.tokenId.toString('hex'),
|
||||
mintBatonVout: parsedData.data.mintBatonVout,
|
||||
qty: parsedData.data.qty
|
||||
}
|
||||
@@ -891,46 +1059,46 @@ class Utils {
|
||||
// https://github.com/Bitcoin-com/slp-sdk/issues/84
|
||||
|
||||
// CT 5/31/20: Refactored to use slp-parse library.
|
||||
async tokenUtxoDetails(utxos) {
|
||||
async tokenUtxoDetails (utxos) {
|
||||
try {
|
||||
// utxo list may have duplicate tx_hash, varying tx_pos
|
||||
// only need to call decodeOpReturn once for those
|
||||
const decodeOpReturnCache = {}
|
||||
const cachedTxValidation = {}
|
||||
// Throw error if input is not an array.
|
||||
if (!Array.isArray(utxos)) throw new Error("Input must be an array.")
|
||||
if (!Array.isArray(utxos)) throw new Error('Input must be an array.')
|
||||
|
||||
// Loop through each element in the array and validate the input before
|
||||
// further processing.
|
||||
for (let i = 0; i < utxos.length; i++) {
|
||||
const utxo = utxos[i]
|
||||
|
||||
if (!utxo.satoshis) {
|
||||
// If Electrumx, convert the value to satoshis.
|
||||
if (utxo.value) {
|
||||
utxo.satoshis = utxo.value
|
||||
}
|
||||
// If there is neither a satoshis or value property, throw an error.
|
||||
else {
|
||||
throw new Error(
|
||||
`utxo ${i} does not have a satoshis or value property.`
|
||||
)
|
||||
}
|
||||
}
|
||||
// CT 1/9/21: This code can be removed after 2/1/21
|
||||
// if (!utxo.satoshis) {
|
||||
// // If Electrumx, convert the value to satoshis.
|
||||
// if (utxo.value) {
|
||||
// utxo.satoshis = utxo.value
|
||||
// } else {
|
||||
// // If there is neither a satoshis or value property, throw an error.
|
||||
// throw new Error(
|
||||
// `utxo ${i} does not have a satoshis or value property.`
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
if (!utxo.txid) {
|
||||
// If Electrumx, convert the tx_hash property to txid.
|
||||
if (utxo.tx_hash) {
|
||||
utxo.txid = utxo.tx_hash
|
||||
}
|
||||
// If there is neither a txid or tx_hash property, throw an error.
|
||||
else {
|
||||
} else {
|
||||
// If there is neither a txid or tx_hash property, throw an error.
|
||||
throw new Error(
|
||||
`utxo ${i} does not have a txid or tx_hash property.`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the UTXO has a vout or tx_pos property.
|
||||
if (!Number.isInteger(utxo.vout)) {
|
||||
if (Number.isInteger(utxo.tx_pos)) {
|
||||
utxo.vout = utxo.tx_pos
|
||||
@@ -964,10 +1132,14 @@ class Utils {
|
||||
// to display the unknown state.
|
||||
if (
|
||||
!err.message ||
|
||||
(err.message.indexOf("scriptpubkey not op_return") === -1 &&
|
||||
err.message.indexOf("lokad id") === -1)
|
||||
(err.message.indexOf('scriptpubkey not op_return') === -1 &&
|
||||
err.message.indexOf('lokad id') === -1 &&
|
||||
err.message.indexOf('trailing data') === -1)
|
||||
) {
|
||||
// console.log(`error from decodeOpReturn(${utxo.txid}): `, err)
|
||||
// console.log(
|
||||
// 'unknown error from decodeOpReturn(). Marking as \'null\'',
|
||||
// err
|
||||
// )
|
||||
|
||||
utxo.isValid = null
|
||||
outAry.push(utxo)
|
||||
@@ -976,6 +1148,7 @@ class Utils {
|
||||
// an SLP UTXO.
|
||||
// Mark as false and continue the loop.
|
||||
} else {
|
||||
// console.log('marking as invalid')
|
||||
utxo.isValid = false
|
||||
outAry.push(utxo)
|
||||
}
|
||||
@@ -990,7 +1163,7 @@ class Utils {
|
||||
|
||||
// If there is an OP_RETURN, attempt to decode it.
|
||||
// Handle Genesis SLP transactions.
|
||||
if (txType === "genesis") {
|
||||
if (txType === 'genesis') {
|
||||
if (
|
||||
utxo.vout !== slpData.mintBatonVout && // UTXO is not a mint baton output.
|
||||
utxo.vout !== 1 // UTXO is not the reciever of the genesis or mint tokens.
|
||||
@@ -999,18 +1172,18 @@ class Utils {
|
||||
// outAry[i] = false
|
||||
utxo.isValid = false
|
||||
outAry[i] = utxo
|
||||
}
|
||||
|
||||
// If this is a valid SLP UTXO, then return the decoded OP_RETURN data.
|
||||
else {
|
||||
} else {
|
||||
// If this is a valid SLP UTXO, then return the decoded OP_RETURN data.
|
||||
// Minting Baton
|
||||
if (utxo.vout === slpData.mintBatonVout) {
|
||||
utxo.utxoType = "minting-baton"
|
||||
}
|
||||
// Tokens
|
||||
else {
|
||||
utxo.utxoType = "token"
|
||||
utxo.tokenQty = slpData.qty / Math.pow(10, slpData.decimals)
|
||||
utxo.utxoType = 'minting-baton'
|
||||
} else {
|
||||
// Tokens
|
||||
|
||||
utxo.utxoType = 'token'
|
||||
utxo.tokenQty = new BigNumber(slpData.qty)
|
||||
.div(Math.pow(10, slpData.decimals))
|
||||
.toString()
|
||||
}
|
||||
|
||||
utxo.tokenId = utxo.txid
|
||||
@@ -1027,7 +1200,7 @@ class Utils {
|
||||
}
|
||||
|
||||
// Handle Mint SLP transactions.
|
||||
if (txType === "mint") {
|
||||
if (txType === 'mint') {
|
||||
if (
|
||||
utxo.vout !== slpData.mintBatonVout && // UTXO is not a mint baton output.
|
||||
utxo.vout !== 1 // UTXO is not the reciever of the genesis or mint tokens.
|
||||
@@ -1036,10 +1209,9 @@ class Utils {
|
||||
// outAry[i] = false
|
||||
utxo.isValid = false
|
||||
outAry[i] = utxo
|
||||
}
|
||||
} else {
|
||||
// If UTXO passes validation, then return formatted token data.
|
||||
|
||||
// If UTXO passes validation, then return formatted token data.
|
||||
else {
|
||||
const genesisData = await this.decodeOpReturn(
|
||||
slpData.tokenId,
|
||||
decodeOpReturnCache
|
||||
@@ -1048,16 +1220,18 @@ class Utils {
|
||||
|
||||
// Minting Baton
|
||||
if (utxo.vout === slpData.mintBatonVout) {
|
||||
utxo.utxoType = "minting-baton"
|
||||
}
|
||||
// Tokens
|
||||
else {
|
||||
utxo.utxoType = "token"
|
||||
utxo.tokenQty = slpData.qty / Math.pow(10, genesisData.decimals)
|
||||
utxo.utxoType = 'minting-baton'
|
||||
} else {
|
||||
// Tokens
|
||||
|
||||
utxo.utxoType = 'token'
|
||||
utxo.tokenQty = new BigNumber(slpData.qty)
|
||||
.div(Math.pow(10, genesisData.decimals))
|
||||
.toString()
|
||||
}
|
||||
|
||||
// Hydrate the UTXO object with information about the SLP token.
|
||||
utxo.transactionType = "mint"
|
||||
utxo.transactionType = 'mint'
|
||||
utxo.tokenId = slpData.tokenId
|
||||
utxo.tokenType = slpData.tokenType
|
||||
|
||||
@@ -1074,23 +1248,22 @@ class Utils {
|
||||
}
|
||||
|
||||
// Handle Send SLP transactions.
|
||||
if (txType === "send") {
|
||||
if (txType === 'send') {
|
||||
// Filter out any vouts that match.
|
||||
// const voutMatch = slpData.spendData.filter(x => utxo.vout === x.vout)
|
||||
// console.log(`voutMatch: ${JSON.stringify(voutMatch, null, 2)}`)
|
||||
|
||||
// Figure out what token quantity is represented by this utxo.
|
||||
const tokenQty = slpData.amounts[utxo.vout - 1]
|
||||
// console.log(`tokenQty: `, tokenQty)
|
||||
// console.log('tokenQty: ', tokenQty)
|
||||
|
||||
if (!tokenQty) {
|
||||
// outAry[i] = false
|
||||
utxo.isValid = false
|
||||
outAry[i] = utxo
|
||||
}
|
||||
} else {
|
||||
// If UTXO passes validation, then return formatted token data.
|
||||
|
||||
// If UTXO passes validation, then return formatted token data.
|
||||
else {
|
||||
const genesisData = await this.decodeOpReturn(
|
||||
slpData.tokenId,
|
||||
decodeOpReturnCache
|
||||
@@ -1100,8 +1273,8 @@ class Utils {
|
||||
// console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
|
||||
|
||||
// Hydrate the UTXO object with information about the SLP token.
|
||||
utxo.utxoType = "token"
|
||||
utxo.transactionType = "send"
|
||||
utxo.utxoType = 'token'
|
||||
utxo.transactionType = 'send'
|
||||
utxo.tokenId = slpData.tokenId
|
||||
utxo.tokenTicker = genesisData.ticker
|
||||
utxo.tokenName = genesisData.name
|
||||
@@ -1111,7 +1284,12 @@ class Utils {
|
||||
utxo.tokenType = slpData.tokenType
|
||||
|
||||
// Calculate the real token quantity.
|
||||
utxo.tokenQty = tokenQty / Math.pow(10, genesisData.decimals)
|
||||
|
||||
const tokenQtyBig = new BigNumber(tokenQty).div(
|
||||
Math.pow(10, genesisData.decimals)
|
||||
)
|
||||
// console.log(`tokenQtyBig`, tokenQtyBig.toString())
|
||||
utxo.tokenQty = tokenQtyBig.toString()
|
||||
|
||||
// console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
|
||||
|
||||
@@ -1119,16 +1297,128 @@ class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, validate the SLP txid with SLPDB.
|
||||
// *After* the UTXO has been hydrated with SLP data,
|
||||
// validate the TXID with SLPDB.
|
||||
if (outAry[i].tokenType) {
|
||||
var isValid = cachedTxValidation[utxo.txid]
|
||||
if (isValid == null) {
|
||||
// Only execute this block if the current UTXO has a 'tokenType'
|
||||
// property. i.e. it has been successfully hydrated with SLP
|
||||
// information.
|
||||
|
||||
// CT 12/13/2020: Disabling the cache until I get processing of tokens
|
||||
// to be more stable.
|
||||
// If the value has been cached, use the cached version first.
|
||||
let isValid = cachedTxValidation[utxo.txid]
|
||||
if (!isValid) isValid = null
|
||||
// let isValid = null
|
||||
|
||||
// There are two possible responses from SLPDB. If SLPDB is functioning
|
||||
// correctly, then validateTxid() will return this:
|
||||
// isValid: [
|
||||
// {
|
||||
// "txid": "ff0c0354f8d3ddb34fa36f73494eb58ea24f8b8da6904aa8ed43b7a74886c583",
|
||||
// "valid": true
|
||||
// }
|
||||
// ]
|
||||
//
|
||||
// If SLPDB has fallen behind real-time processing, it will return this:
|
||||
// isValid: [
|
||||
// null
|
||||
// ]
|
||||
//
|
||||
// Note: validateTxid3() has the same output as validateTxid().
|
||||
// validateTxid2() uses slp-validate, which has a different output format.
|
||||
|
||||
// If not in the cache, try the general SLPDB.
|
||||
if (isValid === null) {
|
||||
// console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
|
||||
isValid = await this.validateTxid(utxo.txid)
|
||||
cachedTxValidation[utxo.txid] = isValid
|
||||
// console.log(
|
||||
// `validateTxid() isValid: ${JSON.stringify(isValid, null, 2)}`
|
||||
// )
|
||||
|
||||
// Handle corner case where SLPDB returns an array with a null element.
|
||||
if (isValid[0] === null) {
|
||||
isValid = [{ txid: utxo.txid, valid: null }]
|
||||
}
|
||||
|
||||
isValid = isValid[0].valid
|
||||
|
||||
// Save the result to the local cache.
|
||||
// cachedTxValidation[utxo.txid] = isValid
|
||||
}
|
||||
// console.log(`isValid: ${JSON.stringify(isValid, null, 2)}`)
|
||||
|
||||
outAry[i].isValid = isValid[0].valid
|
||||
// console.log(
|
||||
// `pre-validateTxid3() isValid: ${JSON.stringify(isValid, null, 2)}`
|
||||
// )
|
||||
|
||||
// If still null, check the whitelist SLPDB
|
||||
if (isValid === null) {
|
||||
// console.log(
|
||||
// `checking against whitelist SLPDB. outAry[${i}]: ${JSON.stringify(
|
||||
// outAry[i],
|
||||
// null,
|
||||
// 2
|
||||
// )}`
|
||||
// )
|
||||
|
||||
// Figure out if the token UTXO is in the whitelist.
|
||||
let utxoInWhitelist = false
|
||||
for (let j = 0; j < this.whitelist.length; j++) {
|
||||
if (outAry[i].tokenId === this.whitelist[j].tokenId) {
|
||||
utxoInWhitelist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If the utxo.tokenId is in the whitelist, check the validity with
|
||||
// the whitelist SLPDB. This should still be functioning properly
|
||||
// if the general SLPDB is not.
|
||||
if (utxoInWhitelist) {
|
||||
isValid = await this.validateTxid3(utxo.txid)
|
||||
|
||||
// console.log(
|
||||
// `whitelist-SLPDB for ${utxo.txid}: ${JSON.stringify(
|
||||
// isValid,
|
||||
// null,
|
||||
// 2
|
||||
// )}`
|
||||
// )
|
||||
|
||||
if (isValid[0] !== null) isValid = isValid[0].valid
|
||||
|
||||
// Save the result to the local cache.
|
||||
// cachedTxValidation[utxo.txid] = isValid
|
||||
}
|
||||
}
|
||||
|
||||
// console.log(
|
||||
// `pre-validateTxid2() isValid: ${JSON.stringify(isValid, null, 2)}`
|
||||
// )
|
||||
|
||||
// If still null, as a last resort, check it against slp-validate
|
||||
if (isValid === null) {
|
||||
try {
|
||||
isValid = await this.validateTxid2(utxo.txid)
|
||||
} catch (err) {
|
||||
// Mark as invalid if validateTxid2() throws an error.
|
||||
isValid = null
|
||||
}
|
||||
// console.log(
|
||||
// `slp-validate isValid: ${JSON.stringify(isValid, null, 2)}`
|
||||
// )
|
||||
|
||||
if (isValid !== null) isValid = isValid.isValid
|
||||
|
||||
// Save the result to the local cache.
|
||||
// cachedTxValidation[utxo.txid] = isValid
|
||||
}
|
||||
|
||||
// console.log(`isValid: ${JSON.stringify(isValid, null, 2)}`)
|
||||
outAry[i].isValid = isValid
|
||||
|
||||
// Save the txid to the local cache to reduce API calls.
|
||||
cachedTxValidation[utxo.txid] = isValid
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1304,12 +1594,12 @@ class Utils {
|
||||
*/
|
||||
// Same as tokenUtxoDetails(), but reduces API calls by having bch-api server
|
||||
// do the heavy lifting.
|
||||
async hydrateUtxos(utxos) {
|
||||
async hydrateUtxos (utxos) {
|
||||
try {
|
||||
// Throw error if input is not an array.
|
||||
if (!Array.isArray(utxos)) throw new Error("Input must be an array.")
|
||||
if (!Array.isArray(utxos)) throw new Error('Input must be an array.')
|
||||
|
||||
const response = await axios.post(
|
||||
const response = await _this.axios.post(
|
||||
`${this.restURL}slp/hydrateUtxos`,
|
||||
{
|
||||
utxos: utxos
|
||||
@@ -1323,6 +1613,48 @@ class Utils {
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.Utils.getStatus() getStatus()
|
||||
* @apiName getStatus
|
||||
* @apiGroup SLP Utils
|
||||
* @apiDescription Get the status and health of the SLPDB connected to bch-api.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*
|
||||
* // Get the current blockheight of the SLPDB indexer.
|
||||
* (async () => {
|
||||
* try {
|
||||
* let validated = await bchjs.SLP.Utils.validateTxid(
|
||||
* "df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb"
|
||||
* );
|
||||
* console.log(validated);
|
||||
* } catch (error) {
|
||||
* console.error(error);
|
||||
* }
|
||||
* })();
|
||||
*
|
||||
* // returns
|
||||
* [ { txid:
|
||||
* 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
|
||||
* valid: true } ]
|
||||
*
|
||||
*/
|
||||
async getStatus (txid) {
|
||||
const path = `${this.restURL}slp/status`
|
||||
|
||||
try {
|
||||
const response = await _this.axios.get(path, _this.axiosOptions)
|
||||
// console.log(
|
||||
// `getStatus response.data: ${JSON.stringify(response.data, null, 2)}`
|
||||
// )
|
||||
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Utils
|
||||
|
||||
+7
-8
@@ -1,15 +1,15 @@
|
||||
const io = require("socket.io-client")
|
||||
const io = require('socket.io-client')
|
||||
|
||||
class Socket {
|
||||
constructor(config = {}) {
|
||||
if (typeof config === "string") {
|
||||
constructor (config = {}) {
|
||||
if (typeof config === 'string') {
|
||||
// TODO remove this check in v2.0
|
||||
this.socket = io(`${config}`)
|
||||
} else {
|
||||
if (config.restURL) {
|
||||
this.socket = io(`${config.restURL}`)
|
||||
} else {
|
||||
const restURL = "https://rest.bitcoin.com"
|
||||
const restURL = 'https://rest.bitcoin.com'
|
||||
this.socket = io(`${restURL}`)
|
||||
}
|
||||
|
||||
@@ -17,12 +17,11 @@ class Socket {
|
||||
}
|
||||
}
|
||||
|
||||
listen(endpoint, cb) {
|
||||
listen (endpoint, cb) {
|
||||
this.socket.emit(endpoint)
|
||||
|
||||
if (endpoint === "blocks") this.socket.on("blocks", msg => cb(msg))
|
||||
else if (endpoint === "transactions")
|
||||
this.socket.on("transactions", msg => cb(msg))
|
||||
if (endpoint === 'blocks') this.socket.on('blocks', msg => cb(msg))
|
||||
else if (endpoint === 'transactions') { this.socket.on('transactions', msg => cb(msg)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-17
@@ -1,18 +1,16 @@
|
||||
const Bitcoin = require("bitcoincashjs-lib")
|
||||
const coininfo = require("coininfo")
|
||||
const bip66 = require("bip66")
|
||||
const bip68 = require("bc-bip68")
|
||||
const Bitcoin = require('@psf/bitcoincashjs-lib')
|
||||
const coininfo = require('@psf/coininfo')
|
||||
const bip66 = require('bip66')
|
||||
const bip68 = require('bc-bip68')
|
||||
|
||||
class TransactionBuilder {
|
||||
static setAddress(address) {
|
||||
static setAddress (address) {
|
||||
TransactionBuilder._address = address
|
||||
}
|
||||
|
||||
constructor(network = "mainnet") {
|
||||
constructor (network = 'mainnet') {
|
||||
let bitcoincash
|
||||
if (network === "bitcoincash" || network === "mainnet")
|
||||
bitcoincash = coininfo.bitcoincash.main
|
||||
else bitcoincash = coininfo.bitcoincash.test
|
||||
if (network === 'bitcoincash' || network === 'mainnet') { bitcoincash = coininfo.bitcoincash.main } else bitcoincash = coininfo.bitcoincash.test
|
||||
|
||||
const bitcoincashBitcoinJSLib = bitcoincash.toBitcoinJS()
|
||||
this.transaction = new Bitcoin.TransactionBuilder(bitcoincashBitcoinJSLib)
|
||||
@@ -33,7 +31,7 @@ class TransactionBuilder {
|
||||
this.bip66 = bip66
|
||||
this.bip68 = bip68
|
||||
this.p2shInput = false
|
||||
this.tx
|
||||
// this.tx
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,23 +46,24 @@ class TransactionBuilder {
|
||||
* // add input with txid and index of vout
|
||||
* transactionBuilder.addInput(txid, 0);
|
||||
*/
|
||||
addInput(txHash, vout, sequence = this.DEFAULT_SEQUENCE, prevOutScript) {
|
||||
addInput (txHash, vout, sequence = this.DEFAULT_SEQUENCE, prevOutScript) {
|
||||
this.transaction.addInput(txHash, vout, sequence, prevOutScript)
|
||||
}
|
||||
|
||||
addInputScript(vout, script) {
|
||||
addInputScript (vout, script) {
|
||||
this.tx = this.transaction.buildIncomplete()
|
||||
this.tx.setInputScript(vout, script)
|
||||
this.p2shInput = true
|
||||
}
|
||||
|
||||
addInputScripts(scripts) {
|
||||
addInputScripts (scripts) {
|
||||
this.tx = this.transaction.buildIncomplete()
|
||||
scripts.forEach(script => {
|
||||
this.tx.setInputScript(script.vout, script.script)
|
||||
})
|
||||
this.p2shInput = true
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Transaction-Builder.addOutput() addOutput()
|
||||
* @apiName AddOutput
|
||||
@@ -79,7 +78,7 @@ class TransactionBuilder {
|
||||
* // add output w/ address and amount to send
|
||||
* transactionBuilder.addOutput('bitcoincash:qpuax2tarq33f86wccwlx8ge7tad2wgvqgjqlwshpw', sendAmount);
|
||||
*/
|
||||
addOutput(scriptPubKey, amount) {
|
||||
addOutput (scriptPubKey, amount) {
|
||||
try {
|
||||
this.transaction.addOutput(
|
||||
TransactionBuilder._address.toLegacyAddress(scriptPubKey),
|
||||
@@ -89,6 +88,7 @@ class TransactionBuilder {
|
||||
this.transaction.addOutput(scriptPubKey, amount)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Transaction-Builder.setLockTime() setLockTime()
|
||||
* @apiName SetLockTime
|
||||
@@ -104,9 +104,10 @@ class TransactionBuilder {
|
||||
* transactionBuilder.addOutput('bitcoincash:qpuax2tarq33f86wccwlx8ge7tad2wgvqgjqlwshpw', sendAmount);
|
||||
* transactionBuilder.setLockTime(50000)
|
||||
*/
|
||||
setLockTime(locktime) {
|
||||
setLockTime (locktime) {
|
||||
this.transaction.setLockTime(locktime)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Transaction-Builder.sign() sign()
|
||||
* @apiName Sign.
|
||||
@@ -124,7 +125,7 @@ class TransactionBuilder {
|
||||
* // sign w/ keyPair
|
||||
* transactionBuilder.sign(0, keyPair, redeemScript, transactionBuilder.hashTypes.SIGHASH_ALL, originalAmount, transactionBuilder.signatureAlgorithms.SCHNORR);
|
||||
*/
|
||||
sign(
|
||||
sign (
|
||||
vin,
|
||||
keyPair,
|
||||
redeemScript,
|
||||
@@ -144,6 +145,7 @@ class TransactionBuilder {
|
||||
signatureAlgorithm
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Transaction-Builder.build() build()
|
||||
* @apiName Build.
|
||||
@@ -154,7 +156,7 @@ class TransactionBuilder {
|
||||
* // build tx
|
||||
* let tx = bchjs.transactionBuilder.build();
|
||||
*/
|
||||
build() {
|
||||
build () {
|
||||
if (this.p2shInput === true) return this.tx
|
||||
|
||||
return this.transaction.build()
|
||||
|
||||
+20
-10
@@ -1,16 +1,26 @@
|
||||
const axios = require("axios")
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
|
||||
class Util {
|
||||
constructor(config) {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.authToken = config.authToken
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,10 +72,10 @@ class Util {
|
||||
* // iscompressed: true,
|
||||
* // account: 'Test' }]
|
||||
*/
|
||||
async validateAddress(address) {
|
||||
async validateAddress (address) {
|
||||
try {
|
||||
// Single block
|
||||
if (typeof address === "string") {
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}util/validateAddress/${address}`,
|
||||
_this.axiosOptions
|
||||
@@ -75,7 +85,7 @@ class Util {
|
||||
// Array of blocks.
|
||||
} else if (Array.isArray(address)) {
|
||||
const options = {
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
url: `${this.restURL}util/validateAddress`,
|
||||
data: {
|
||||
addresses: address
|
||||
@@ -89,7 +99,7 @@ class Util {
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error(`Input must be a string or array of strings.`)
|
||||
throw new Error('Input must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
// import BCHWalletBridge from "bch-wallet-bridge.js"
|
||||
class Wallet {
|
||||
constructor(walletProvider) {
|
||||
// this.bchWalletBridge = new BCHWalletBridge(walletProvider)
|
||||
}
|
||||
|
||||
setWalletProvider(walletProvider) {
|
||||
this.bchWalletBridge.walletProvider = walletProvider
|
||||
}
|
||||
|
||||
getAddress(changeType, index, dAppId) {
|
||||
return this.bchWalletBridge.getAddress(changeType, index, dAppId)
|
||||
}
|
||||
|
||||
getAddressIndex(changeType, dAppId) {
|
||||
return this.bchWalletBridge.getAddressIndex(changeType, dAppId)
|
||||
}
|
||||
|
||||
getAddresses(changeType, startIndex, size, dAppId) {
|
||||
return this.bchWalletBridge.getAddresses(
|
||||
changeType,
|
||||
startIndex,
|
||||
size,
|
||||
dAppId
|
||||
)
|
||||
}
|
||||
|
||||
getRedeemScript(p2shAddress, dAppId) {
|
||||
return this.bchWalletBridge.getRedeemScript(p2shAddress, dAppId)
|
||||
}
|
||||
|
||||
getRedeemScripts(dAppId) {
|
||||
return this.bchWalletBridge.getRedeemScripts(dAppId)
|
||||
}
|
||||
|
||||
addRedeemScript(redeemScript, dAppId) {
|
||||
return this.bchWalletBridge.addRedeemScript(redeemScript, dAppId)
|
||||
}
|
||||
|
||||
getUtxos(dAppId) {
|
||||
return this.bchWalletBridge.getUtxos(dAppId)
|
||||
}
|
||||
|
||||
getBalance(dAppId) {
|
||||
return this.bchWalletBridge.getBalance(dAppId)
|
||||
}
|
||||
|
||||
sign(address, dataToSign) {
|
||||
return this.bchWalletBridge.sign(address, dataToSign)
|
||||
}
|
||||
|
||||
buildTransaction(outputs, dAppId) {
|
||||
return this.bchWalletBridge.buildTransaction(outputs, dAppId)
|
||||
}
|
||||
|
||||
getProtocolVersion() {
|
||||
return this.bchWalletBridge.getProtocolVersion()
|
||||
}
|
||||
|
||||
getNetwork() {
|
||||
return this.bchWalletBridge.getNetwork()
|
||||
}
|
||||
|
||||
getFeePerByte() {
|
||||
return this.bchWalletBridge.getFeePerByte()
|
||||
}
|
||||
|
||||
getDefaultDAppId() {
|
||||
return this.bchWalletBridge.getDefaultDAppId()
|
||||
}
|
||||
|
||||
setDefaultDAppId(dAppId) {
|
||||
return this.bchWalletBridge.setDefaultDAppId(dAppId)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Wallet
|
||||
@@ -2,17 +2,17 @@
|
||||
A Mocha test file for running end-to-end (e2e) tests.
|
||||
*/
|
||||
|
||||
//const mocha = require("mocha")
|
||||
const assert = require("chai").assert
|
||||
// const mocha = require("mocha")
|
||||
const assert = require('chai').assert
|
||||
|
||||
const sendToken = require("./send-token/send-token")
|
||||
const sendToken = require('./send-token/send-token')
|
||||
|
||||
describe("#end-to-end tests", () => {
|
||||
describe("#send-tokens", () => {
|
||||
it("SLPDB should update balances in less than 10 seconds", async () => {
|
||||
describe('#end-to-end tests', () => {
|
||||
describe('#send-tokens', () => {
|
||||
it('SLPDB should update balances in less than 10 seconds', async () => {
|
||||
const result = await sendToken.sendTokenTest()
|
||||
|
||||
assert(result, true, "True expected if test passed successfully.")
|
||||
assert(result, true, 'True expected if test passed successfully.')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
IPFS is working.
|
||||
*/
|
||||
|
||||
process.env.IPFS_API = `http://localhost:5001`
|
||||
process.env.IPFS_API = 'http://localhost:5001'
|
||||
// process.env.IPFS_API = `https://ipfs-api.fullstack.cash`
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const BCHJS = require('../../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe(`#IPFS`, () => {
|
||||
it("should upload a file to the server", async () => {
|
||||
const path = `${__dirname}/ipfs-e2e.js`
|
||||
describe('#IPFS', () => {
|
||||
it('should upload a file to the server', async () => {
|
||||
const path = `${__dirname.toString()}/ipfs-e2e.js`
|
||||
|
||||
const fileModel = await bchjs.IPFS.createFileModel(path)
|
||||
console.log(`fileModel: ${JSON.stringify(fileModel, null, 2)}`)
|
||||
|
||||
@@ -5,38 +5,44 @@
|
||||
To Run Test:
|
||||
- Update the RESTURL for bch-api you want to test against.
|
||||
- Ensure the BCHJSTOKEN environment variable is set to an empty string.
|
||||
- If working with bch-api locally, eliminate the local IP address from the
|
||||
whitelist in bch-api/src/middleware/route-ratelimit.js
|
||||
|
||||
Run this test with this command:
|
||||
mocha --timeout=30000 anonymous-rate-limits.js
|
||||
*/
|
||||
|
||||
const assert = require("chai").assert
|
||||
const assert = require('chai').assert
|
||||
|
||||
const RESTURL = `https://api.fullstack.cash/v3/`
|
||||
// const RESTURL = `http://localhost:3000/v3/`
|
||||
// const RESTURL = `https://abc.fullstack.cash/v4/`
|
||||
const RESTURL = 'https://bchn.fullstack.cash/v4/'
|
||||
// const RESTURL = `http://localhost:3000/v4/`
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const BCHJS = require('../../../src/bch-js')
|
||||
const bchjs = new BCHJS({ restURL: RESTURL })
|
||||
|
||||
describe("#anonymous rate limits", () => {
|
||||
it("should allow an anonymous call to a full node endpoint", async () => {
|
||||
describe('#anonymous rate limits', () => {
|
||||
it('should allow an anonymous call to a full node endpoint', async () => {
|
||||
const result = await bchjs.Control.getNetworkInfo()
|
||||
|
||||
assert.property(result, "version")
|
||||
assert.property(result, 'version')
|
||||
}).timeout(5000)
|
||||
|
||||
it("should allow an anonymous call to an indexer", async () => {
|
||||
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
it('should allow an anonymous call to an indexer', async () => {
|
||||
const addr = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
|
||||
const result = await bchjs.Electrumx.balance(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "balance")
|
||||
assert.property(result, 'balance')
|
||||
}).timeout(5000)
|
||||
|
||||
it("should throw error when rate limit exceeded", async () => {
|
||||
it('should throw error when rate limit exceeded', async () => {
|
||||
try {
|
||||
for (let i = 0; i < 22; i++) await bchjs.Control.getNetworkInfo()
|
||||
for (let i = 0; i < 35; i++) await bchjs.Control.getNetworkInfo()
|
||||
|
||||
assert.fail("Unexpected result")
|
||||
assert.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
assert.include(err.error, "Too many requests")
|
||||
assert.include(err.error, 'Too many requests')
|
||||
}
|
||||
}).timeout(20000)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Mocha test that verifies that the bch-api server is enforcing its
|
||||
access rules for Basic Authentication.
|
||||
|
||||
To Run Test:
|
||||
- Update the restURL for bch-api you want to test against.
|
||||
- Update the PRO_PASS value with a current PRO_PASSES string used by bch-api.
|
||||
*/
|
||||
|
||||
const assert = require('chai').assert
|
||||
|
||||
const PRO_PASS = 'testpassword'
|
||||
|
||||
const BCHJS = require('../../../src/bch-js')
|
||||
const bchjs = new BCHJS({
|
||||
// restURL: `https://bchn.fullstack.cash/v4/`,
|
||||
restURL: 'https://abc.fullstack.cash/v4/',
|
||||
// restURL: `http://localhost:3000/v4/`,
|
||||
authPass: PRO_PASS
|
||||
})
|
||||
|
||||
describe('#Basic Authentication rate limits', () => {
|
||||
it('should allow more than 20 RPM to full node', async () => {
|
||||
for (let i = 0; i < 22; i++) {
|
||||
const result = await bchjs.Control.getNetworkInfo()
|
||||
|
||||
if (i === 5) {
|
||||
// console.log(`validating 5th call: ${i}`)
|
||||
assert.property(result, 'version', 'more than 3 calls allowed')
|
||||
}
|
||||
|
||||
if (i === 15) {
|
||||
// console.log(`validating 5th call: ${i}`)
|
||||
assert.property(result, 'version', 'more than 10 calls allowed')
|
||||
}
|
||||
}
|
||||
}).timeout(45000)
|
||||
|
||||
it('should allow more than 20 RPM to an indexer', async () => {
|
||||
const addr = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
|
||||
|
||||
for (let i = 0; i < 22; i++) {
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
|
||||
if (i === 5) {
|
||||
// console.log(`validating 5th call: ${i}`)
|
||||
assert.property(result, 'balance', 'more than 3 calls allowed')
|
||||
}
|
||||
|
||||
if (i === 15) {
|
||||
// console.log(`validating 5th call: ${i}`)
|
||||
assert.property(result, 'balance', 'more than 10 calls allowed')
|
||||
}
|
||||
}
|
||||
}).timeout(45000)
|
||||
})
|
||||
@@ -1,4 +1,8 @@
|
||||
/*
|
||||
CT 11/11/2020:
|
||||
There is no longer a free tier. These tests have been deprecated.
|
||||
|
||||
--------
|
||||
Mocha test that verifies that the bch-api server is enforcing its
|
||||
FREE access rules
|
||||
|
||||
@@ -7,59 +11,59 @@
|
||||
- Update the JWT_TOKEN value with a current free-level JWT token.
|
||||
*/
|
||||
|
||||
const assert = require("chai").assert
|
||||
const assert = require('chai').assert
|
||||
|
||||
const JWT_TOKEN =
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2YyMDIyMWMxMDAxMmFkOTQwMSIsImVtYWlsIjoiZGVtb0BkZW1vLmNvbSIsImFwaUxldmVsIjoxMCwicmF0ZUxpbWl0IjozLCJpYXQiOjE2MDQ4NTQ2OTEsImV4cCI6MTYwNzQ0NjY5MX0.iwse0z0KDKHx9graCxcOwj6lSlfKQAb1zLhmjvygvts"
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2YyMDIyMWMxMDAxMmFkOTQwMSIsImVtYWlsIjoiZGVtb0BkZW1vLmNvbSIsImFwaUxldmVsIjoxMCwicmF0ZUxpbWl0IjozLCJpYXQiOjE2MDQ4NTQ2OTEsImV4cCI6MTYwNzQ0NjY5MX0.iwse0z0KDKHx9graCxcOwj6lSlfKQAb1zLhmjvygvts'
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const BCHJS = require('../../../src/bch-js')
|
||||
const bchjs = new BCHJS({
|
||||
restURL: `https://api.fullstack.cash/v3/`,
|
||||
// restURL: `http://localhost:3000/v3/`,
|
||||
restURL: 'https://api.fullstack.cash/v4/',
|
||||
// restURL: `http://localhost:3000/v4/`,
|
||||
apiToken: JWT_TOKEN
|
||||
})
|
||||
|
||||
describe("#free rate limits", () => {
|
||||
it("should allow an free call to an indexer", async () => {
|
||||
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
|
||||
describe('#free rate limits', () => {
|
||||
it('should allow an free call to an indexer', async () => {
|
||||
const addr = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "balance")
|
||||
assert.property(result, 'balance')
|
||||
}).timeout(5000)
|
||||
|
||||
it("should allow up to 10 RPM to indexer, then throw error", async () => {
|
||||
it('should allow up to 10 RPM to indexer, then throw error', async () => {
|
||||
try {
|
||||
const addr = "bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0"
|
||||
const addr = 'bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0'
|
||||
|
||||
for (let i = 0; i < 15; i++) {
|
||||
const result = await await bchjs.Blockbook.balance(addr)
|
||||
|
||||
if (i === 5) {
|
||||
// console.log(`validating 5th call: ${i}`)
|
||||
assert.property(result, "address", "more than 3 calls allowed")
|
||||
assert.property(result, 'address', 'more than 3 calls allowed')
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.error,
|
||||
"currently 10 requests",
|
||||
"more than 10 not allowed"
|
||||
'currently 10 requests',
|
||||
'more than 10 not allowed'
|
||||
)
|
||||
assert.include(err.error, 10)
|
||||
assert.notInclude(err.error, 3)
|
||||
}
|
||||
}).timeout(20000)
|
||||
|
||||
it("should allow up to 10 RPM to full node, then throw error", async () => {
|
||||
it('should allow up to 10 RPM to full node, then throw error', async () => {
|
||||
try {
|
||||
for (let i = 0; i < 15; i++) {
|
||||
const result = await bchjs.Control.getNetworkInfo()
|
||||
|
||||
if (i === 5) {
|
||||
// console.log(`validating 5th call: ${i}`)
|
||||
assert.property(result, "version", "more than 3 calls allowed")
|
||||
assert.property(result, 'version', 'more than 3 calls allowed')
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -67,22 +71,22 @@ describe("#free rate limits", () => {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.error,
|
||||
"currently 10 requests",
|
||||
"more than 10 not allowed"
|
||||
'currently 10 requests',
|
||||
'more than 10 not allowed'
|
||||
)
|
||||
assert.include(err.error, 10)
|
||||
assert.notInclude(err.error, 3)
|
||||
}
|
||||
}).timeout(20000)
|
||||
|
||||
it("should throw error when rate limit exceeded 20 RPM for indexer endpoints", async () => {
|
||||
it('should throw error when rate limit exceeded 20 RPM for indexer endpoints', async () => {
|
||||
try {
|
||||
for (let i = 0; i < 22; i++) await bchjs.Control.getNetworkInfo()
|
||||
|
||||
assert.fail("unexpected result")
|
||||
assert.fail('unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.error, "Too many requests")
|
||||
assert.include(err.error, 'Too many requests')
|
||||
}
|
||||
}).timeout(20000)
|
||||
})
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
/*
|
||||
CT 11/11/2020:
|
||||
There is no longer a free tier. These tests have been deprecated.
|
||||
|
||||
----
|
||||
Mocha test that verifies that the bch-api server is enforcing its
|
||||
full-node access rules
|
||||
|
||||
@@ -7,25 +11,26 @@
|
||||
- Update the JWT_TOKEN value with a paid tier JWT token.
|
||||
*/
|
||||
|
||||
const assert = require("chai").assert
|
||||
const assert = require('chai').assert
|
||||
|
||||
const JWT_TOKEN =
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M"
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M'
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const BCHJS = require('../../../src/bch-js')
|
||||
const bchjs = new BCHJS({
|
||||
restURL: `https://api.fullstack.cash/v3/`,
|
||||
// restURL: `http://localhost:3000/v3/`,
|
||||
// restURL: `https://bchn.fullstack.cash/v4/`,
|
||||
restURL: 'https:/abc.fullstack.cash/v4/',
|
||||
// restURL: `http://localhost:3000/v4/`,
|
||||
apiToken: JWT_TOKEN
|
||||
})
|
||||
|
||||
describe("#full node rate limits", () => {
|
||||
it("should allow an free call to an indexer", async () => {
|
||||
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
describe('#full node rate limits', () => {
|
||||
it('should allow an free call to an indexer', async () => {
|
||||
const addr = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
|
||||
const result = await bchjs.Electrumx.balance(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "balance")
|
||||
assert.property(result, 'balance')
|
||||
}).timeout(5000)
|
||||
|
||||
// CT 11/8/20: New rate limits make this test invalid.
|
||||
@@ -42,30 +47,30 @@ describe("#full node rate limits", () => {
|
||||
// }
|
||||
// }).timeout(10000)
|
||||
|
||||
it("should allow more than 20 RPM to full node", async () => {
|
||||
it('should allow more than 20 RPM to full node', async () => {
|
||||
for (let i = 0; i < 22; i++) {
|
||||
const result = await bchjs.Control.getNetworkInfo()
|
||||
|
||||
if (i === 5) {
|
||||
// console.log(`validating 5th call: ${i}`)
|
||||
assert.property(result, "version", "more than 3 calls allowed")
|
||||
assert.property(result, 'version', 'more than 3 calls allowed')
|
||||
}
|
||||
|
||||
if (i === 15) {
|
||||
// console.log(`validating 5th call: ${i}`)
|
||||
assert.property(result, "version", "more than 10 calls allowed")
|
||||
assert.property(result, 'version', 'more than 10 calls allowed')
|
||||
}
|
||||
}
|
||||
}).timeout(20000)
|
||||
|
||||
it("should throw error for more than 100 RPM to fullnode", async () => {
|
||||
it('should throw error for more than 100 RPM to fullnode', async () => {
|
||||
try {
|
||||
console.log(`This test usually doesn't pass, because of latency.`)
|
||||
console.log('This test usually doesn\'t pass, because of latency.')
|
||||
for (let i = 0; i < 100; i++) await bchjs.Control.getNetworkInfo()
|
||||
} catch (err) {
|
||||
// console.log(`validating after 10th call`)
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.error, "Too many requests")
|
||||
assert.include(err.error, 'Too many requests')
|
||||
assert.include(err.error, 100)
|
||||
}
|
||||
}).timeout(45000)
|
||||
|
||||
@@ -7,49 +7,50 @@
|
||||
- Update the JWT_TOKEN value with a current indexer-level JWT token.
|
||||
*/
|
||||
|
||||
const assert = require("chai").assert
|
||||
const assert = require('chai').assert
|
||||
|
||||
const JWT_TOKEN =
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M"
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlODhhY2JmMDIyMWMxMDAxMmFkOTNmZiIsImVtYWlsIjoiY2hyaXMudHJvdXRuZXJAZ21haWwuY29tIiwiYXBpTGV2ZWwiOjQwLCJyYXRlTGltaXQiOjMsImlhdCI6MTYwMzIyNzEwNCwiZXhwIjoxNjA1ODE5MTA0fQ.CV36grzdD36Ht3BwZGHG4XU40CVDzMRw9Ars1x1r27M'
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const BCHJS = require('../../../src/bch-js')
|
||||
const bchjs = new BCHJS({
|
||||
restURL: `https://api.fullstack.cash/v3/`,
|
||||
// restURL: `http://localhost:3000/v3/`,
|
||||
// restURL: `https://bchn.fullstack.cash/v4/`,
|
||||
restURL: 'https://abc.fullstack.cash/v4/',
|
||||
// restURL: `http://localhost:3000/v4/`,
|
||||
apiToken: JWT_TOKEN
|
||||
})
|
||||
|
||||
describe("#full node rate limits", () => {
|
||||
it("should allow more than 20 RPM to full node", async () => {
|
||||
describe('#Indexer rate limits', () => {
|
||||
it('should allow more than 20 RPM to full node', async () => {
|
||||
for (let i = 0; i < 22; i++) {
|
||||
const result = await bchjs.Control.getNetworkInfo()
|
||||
|
||||
if (i === 5) {
|
||||
// console.log(`validating 5th call: ${i}`)
|
||||
assert.property(result, "version", "more than 3 calls allowed")
|
||||
assert.property(result, 'version', 'more than 3 calls allowed')
|
||||
}
|
||||
|
||||
if (i === 15) {
|
||||
// console.log(`validating 5th call: ${i}`)
|
||||
assert.property(result, "version", "more than 10 calls allowed")
|
||||
assert.property(result, 'version', 'more than 10 calls allowed')
|
||||
}
|
||||
}
|
||||
}).timeout(45000)
|
||||
|
||||
it("should allow more than 20 RPM to an indexer", async () => {
|
||||
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
|
||||
it('should allow more than 20 RPM to an indexer', async () => {
|
||||
const addr = 'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf'
|
||||
|
||||
for (let i = 0; i < 22; i++) {
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
const result = await bchjs.Electrumx.balance(addr)
|
||||
|
||||
if (i === 5) {
|
||||
// console.log(`validating 5th call: ${i}`)
|
||||
assert.property(result, "balance", "more than 3 calls allowed")
|
||||
assert.property(result, 'balance', 'more than 3 calls allowed')
|
||||
}
|
||||
|
||||
if (i === 15) {
|
||||
// console.log(`validating 5th call: ${i}`)
|
||||
assert.property(result, "balance", "more than 10 calls allowed")
|
||||
assert.property(result, 'balance', 'more than 10 calls allowed')
|
||||
}
|
||||
}
|
||||
}).timeout(45000)
|
||||
|
||||
@@ -13,24 +13,25 @@
|
||||
*/
|
||||
|
||||
// Replace the address below with the address you want to send the BCH to.
|
||||
const RECV_ADDR1 = `bchtest:qzfn2mly05t6fjsh5kjj0dqq0jjtct27ng089dgg05`
|
||||
const RECV_ADDR2 = `bchtest:qz6yw0kqgfkknfy6jh2jvlfnkzmre3lt2u0pgcckdk`
|
||||
const RECV_ADDR1 = 'bchtest:qzfn2mly05t6fjsh5kjj0dqq0jjtct27ng089dgg05'
|
||||
const RECV_ADDR2 = 'bchtest:qz6yw0kqgfkknfy6jh2jvlfnkzmre3lt2u0pgcckdk'
|
||||
const SATOSHIS_TO_SEND = 1000
|
||||
|
||||
// Instantiate BITBOX.
|
||||
const bitboxLib = "../../../lib/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 BITBOX = new BITBOXSDK({ restURL: 'https://trest.bitcoin.com/v2/' })
|
||||
// const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" })
|
||||
|
||||
const util = require("util")
|
||||
// const util = require('util')
|
||||
|
||||
// Open the wallet generated with create-wallet.
|
||||
let walletInfo = {}
|
||||
try {
|
||||
var walletInfo = require(`./wallet.json`)
|
||||
walletInfo = require('./wallet.json')
|
||||
} catch (err) {
|
||||
console.log(
|
||||
`Could not open wallet.json. Generate a wallet with create-wallet first.`
|
||||
'Could not open wallet.json. Generate a wallet with create-wallet first.'
|
||||
)
|
||||
process.exit(0)
|
||||
}
|
||||
@@ -38,7 +39,7 @@ try {
|
||||
const SEND_ADDR = walletInfo.cashAddress
|
||||
const SEND_MNEMONIC = walletInfo.mnemonic
|
||||
|
||||
async function testSend() {
|
||||
async function testSend () {
|
||||
try {
|
||||
const hex1 = await buildTx1(RECV_ADDR1)
|
||||
const hex2 = await buildTx2(RECV_ADDR2)
|
||||
@@ -51,15 +52,15 @@ async function testSend() {
|
||||
hex2
|
||||
])
|
||||
console.log(`Transaction IDs: ${JSON.stringify(broadcast, null, 2)}`)
|
||||
console.log(`Should return an array of TXID strings.`)
|
||||
console.log('Should return an array of TXID strings.')
|
||||
} catch (err) {
|
||||
console.log(`Error in testSend: `, err)
|
||||
console.log('Error in testSend: ', err)
|
||||
}
|
||||
}
|
||||
testSend()
|
||||
|
||||
// Build a TX hex with the largest UTXO.
|
||||
async function buildTx1(recAddr) {
|
||||
async function buildTx1 (recAddr) {
|
||||
try {
|
||||
// Get the balance of the sending address.
|
||||
const balance = await getBCHBalance(SEND_ADDR, false)
|
||||
@@ -68,7 +69,7 @@ async function buildTx1(recAddr) {
|
||||
|
||||
// Exit if the balance is zero.
|
||||
if (balance <= 0.0) {
|
||||
console.log(`Balance of sending address is zero. Exiting.`)
|
||||
console.log('Balance of sending address is zero. Exiting.')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
@@ -77,16 +78,17 @@ async function buildTx1(recAddr) {
|
||||
console.log(`Sender Legacy Address: ${SEND_ADDR_LEGACY}`)
|
||||
console.log(`Receiver Legacy Address: ${RECV_ADDR_LEGACY}`)
|
||||
|
||||
const balance2 = await getBCHBalance(recAddr, false)
|
||||
//console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`)
|
||||
// const balance2 = await getBCHBalance(recAddr, false)
|
||||
// console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`)
|
||||
await getBCHBalance(recAddr, false)
|
||||
|
||||
const u = await BITBOX.Address.utxo(SEND_ADDR)
|
||||
//console.log(`u: ${JSON.stringify(u, null, 2)}`)
|
||||
// console.log(`u: ${JSON.stringify(u, null, 2)}`)
|
||||
const utxo = findBiggestUtxo(u.utxos)
|
||||
console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
|
||||
|
||||
// instance of transaction builder
|
||||
const transactionBuilder = new BITBOX.TransactionBuilder("testnet")
|
||||
const transactionBuilder = new BITBOX.TransactionBuilder('testnet')
|
||||
|
||||
const satoshisToSend = SATOSHIS_TO_SEND
|
||||
const originalAmount = utxo.satoshis
|
||||
@@ -137,13 +139,13 @@ async function buildTx1(recAddr) {
|
||||
|
||||
return hex
|
||||
} catch (err) {
|
||||
console.log(`Error in buildTx().`)
|
||||
console.log('Error in buildTx().')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// Build a TX hex with the SECOND largest UTXO.
|
||||
async function buildTx2(recAddr) {
|
||||
async function buildTx2 (recAddr) {
|
||||
try {
|
||||
// Get the balance of the sending address.
|
||||
const balance = await getBCHBalance(SEND_ADDR, false)
|
||||
@@ -152,7 +154,7 @@ async function buildTx2(recAddr) {
|
||||
|
||||
// Exit if the balance is zero.
|
||||
if (balance <= 0.0) {
|
||||
console.log(`Balance of sending address is zero. Exiting.`)
|
||||
console.log('Balance of sending address is zero. Exiting.')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
@@ -161,16 +163,17 @@ async function buildTx2(recAddr) {
|
||||
console.log(`Sender Legacy Address: ${SEND_ADDR_LEGACY}`)
|
||||
console.log(`Receiver Legacy Address: ${RECV_ADDR_LEGACY}`)
|
||||
|
||||
const balance2 = await getBCHBalance(recAddr, false)
|
||||
//console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`)
|
||||
// const balance2 = await getBCHBalance(recAddr, false)
|
||||
// console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`)
|
||||
await getBCHBalance(recAddr, false)
|
||||
|
||||
const u = await BITBOX.Address.utxo(SEND_ADDR)
|
||||
//console.log(`u: ${JSON.stringify(u, null, 2)}`)
|
||||
// console.log(`u: ${JSON.stringify(u, null, 2)}`)
|
||||
const utxo = findNextBiggestUtxo(u.utxos)
|
||||
console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
|
||||
|
||||
// instance of transaction builder
|
||||
const transactionBuilder = new BITBOX.TransactionBuilder("testnet")
|
||||
const transactionBuilder = new BITBOX.TransactionBuilder('testnet')
|
||||
|
||||
const satoshisToSend = SATOSHIS_TO_SEND
|
||||
const originalAmount = utxo.satoshis
|
||||
@@ -221,30 +224,30 @@ async function buildTx2(recAddr) {
|
||||
|
||||
return hex
|
||||
} catch (err) {
|
||||
console.log(`Error in buildTx().`)
|
||||
console.log('Error in buildTx().')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a change address from a Mnemonic of a private key.
|
||||
function changeAddrFromMnemonic(mnemonic) {
|
||||
function changeAddrFromMnemonic (mnemonic) {
|
||||
// root seed buffer
|
||||
const rootSeed = BITBOX.Mnemonic.toSeed(mnemonic)
|
||||
|
||||
// master HDNode
|
||||
const masterHDNode = BITBOX.HDNode.fromSeed(rootSeed, "testnet")
|
||||
const masterHDNode = BITBOX.HDNode.fromSeed(rootSeed, 'testnet')
|
||||
|
||||
// HDNode of BIP44 account
|
||||
const account = BITBOX.HDNode.derivePath(masterHDNode, "m/44'/145'/0'")
|
||||
|
||||
// derive the first external change address HDNode which is going to spend utxo
|
||||
const change = BITBOX.HDNode.derivePath(account, "0/0")
|
||||
const change = BITBOX.HDNode.derivePath(account, '0/0')
|
||||
|
||||
return change
|
||||
}
|
||||
|
||||
// Get the balance in BCH of a BCH address.
|
||||
async function getBCHBalance(addr, verbose) {
|
||||
async function getBCHBalance (addr, verbose) {
|
||||
try {
|
||||
const result = await BITBOX.Address.details(addr)
|
||||
|
||||
@@ -254,16 +257,16 @@ async function getBCHBalance(addr, verbose) {
|
||||
|
||||
return bchBalance.balance
|
||||
} catch (err) {
|
||||
console.error(`Error in getBCHBalance: `, err)
|
||||
console.error('Error in getBCHBalance: ', err)
|
||||
console.log(`addr: ${addr}`)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the utxo with the biggest balance from an array of utxos.
|
||||
function findBiggestUtxo(utxos) {
|
||||
function findBiggestUtxo (utxos) {
|
||||
// Sort the utxos by the amount of satoshis, largest first.
|
||||
utxos.sort(function(a, b) {
|
||||
utxos.sort(function (a, b) {
|
||||
return b.satoshis - a.satoshis
|
||||
})
|
||||
|
||||
@@ -271,9 +274,9 @@ function findBiggestUtxo(utxos) {
|
||||
}
|
||||
|
||||
// Returns the utxo with the 2nd biggest balance from an array of utxos.
|
||||
function findNextBiggestUtxo(utxos) {
|
||||
function findNextBiggestUtxo (utxos) {
|
||||
// Sort the utxos by the amount of satoshis, largest first.
|
||||
utxos.sort(function(a, b) {
|
||||
utxos.sort(function (a, b) {
|
||||
return b.satoshis - a.satoshis
|
||||
})
|
||||
|
||||
|
||||
@@ -13,23 +13,24 @@
|
||||
*/
|
||||
|
||||
// Replace the address below with the address you want to send the BCH to.
|
||||
const RECV_ADDR1 = `bchtest:qzfn2mly05t6fjsh5kjj0dqq0jjtct27ng089dgg05`
|
||||
const RECV_ADDR1 = 'bchtest:qzfn2mly05t6fjsh5kjj0dqq0jjtct27ng089dgg05'
|
||||
const SATOSHIS_TO_SEND = 1000
|
||||
|
||||
// Instantiate BITBOX.
|
||||
const bitboxLib = "../../../lib/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 BITBOX = new BITBOXSDK({ restURL: 'https://trest.bitcoin.com/v2/' })
|
||||
// const BITBOX = new BITBOXSDK({ restURL: "http://localhost:3000/v2/" })
|
||||
|
||||
const util = require("util")
|
||||
// const util = require('util')
|
||||
|
||||
// Open the wallet generated with create-wallet.
|
||||
let walletInfo = {}
|
||||
try {
|
||||
var walletInfo = require(`./wallet.json`)
|
||||
walletInfo = require('./wallet.json')
|
||||
} catch (err) {
|
||||
console.log(
|
||||
`Could not open wallet.json. Generate a wallet with create-wallet first.`
|
||||
'Could not open wallet.json. Generate a wallet with create-wallet first.'
|
||||
)
|
||||
process.exit(0)
|
||||
}
|
||||
@@ -37,26 +38,26 @@ try {
|
||||
const SEND_ADDR = walletInfo.cashAddress
|
||||
const SEND_MNEMONIC = walletInfo.mnemonic
|
||||
|
||||
async function testSend() {
|
||||
async function testSend () {
|
||||
try {
|
||||
const hex1 = await buildTx1(RECV_ADDR1)
|
||||
//const hex2 = await buildTx2(RECV_ADDR2)
|
||||
// const hex2 = await buildTx2(RECV_ADDR2)
|
||||
|
||||
console.log(`hex1: ${hex1}\n\n`)
|
||||
//console.log(`hex2: ${hex2}\n\n`)
|
||||
// console.log(`hex2: ${hex2}\n\n`)
|
||||
|
||||
const broadcast = await BITBOX.RawTransactions.sendRawTransaction(hex1)
|
||||
|
||||
console.log(`Transaction IDs: ${JSON.stringify(broadcast, null, 2)}`)
|
||||
console.log(`Should return a TXID string.`)
|
||||
console.log('Should return a TXID string.')
|
||||
} catch (err) {
|
||||
console.log(`Error in testSend: `, err)
|
||||
console.log('Error in testSend: ', err)
|
||||
}
|
||||
}
|
||||
testSend()
|
||||
|
||||
// Build a TX hex with the largest UTXO.
|
||||
async function buildTx1(recAddr) {
|
||||
async function buildTx1 (recAddr) {
|
||||
try {
|
||||
// Get the balance of the sending address.
|
||||
const balance = await getBCHBalance(SEND_ADDR, false)
|
||||
@@ -65,7 +66,7 @@ async function buildTx1(recAddr) {
|
||||
|
||||
// Exit if the balance is zero.
|
||||
if (balance <= 0.0) {
|
||||
console.log(`Balance of sending address is zero. Exiting.`)
|
||||
console.log('Balance of sending address is zero. Exiting.')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
@@ -74,16 +75,17 @@ async function buildTx1(recAddr) {
|
||||
console.log(`Sender Legacy Address: ${SEND_ADDR_LEGACY}`)
|
||||
console.log(`Receiver Legacy Address: ${RECV_ADDR_LEGACY}`)
|
||||
|
||||
const balance2 = await getBCHBalance(recAddr, false)
|
||||
//console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`)
|
||||
// const balance2 = await getBCHBalance(recAddr, false)
|
||||
// console.log(`Balance of recieving address ${recAddr} is ${balance2} BCH.`)
|
||||
await getBCHBalance(recAddr, false)
|
||||
|
||||
const u = await BITBOX.Address.utxo(SEND_ADDR)
|
||||
//console.log(`u: ${JSON.stringify(u, null, 2)}`)
|
||||
// console.log(`u: ${JSON.stringify(u, null, 2)}`)
|
||||
const utxo = findBiggestUtxo(u.utxos)
|
||||
console.log(`utxo: ${JSON.stringify(utxo, null, 2)}`)
|
||||
|
||||
// instance of transaction builder
|
||||
const transactionBuilder = new BITBOX.TransactionBuilder("testnet")
|
||||
const transactionBuilder = new BITBOX.TransactionBuilder('testnet')
|
||||
|
||||
const satoshisToSend = SATOSHIS_TO_SEND
|
||||
const originalAmount = utxo.satoshis
|
||||
@@ -134,30 +136,30 @@ async function buildTx1(recAddr) {
|
||||
|
||||
return hex
|
||||
} catch (err) {
|
||||
console.log(`Error in buildTx().`)
|
||||
console.log('Error in buildTx().')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a change address from a Mnemonic of a private key.
|
||||
function changeAddrFromMnemonic(mnemonic) {
|
||||
function changeAddrFromMnemonic (mnemonic) {
|
||||
// root seed buffer
|
||||
const rootSeed = BITBOX.Mnemonic.toSeed(mnemonic)
|
||||
|
||||
// master HDNode
|
||||
const masterHDNode = BITBOX.HDNode.fromSeed(rootSeed, "testnet")
|
||||
const masterHDNode = BITBOX.HDNode.fromSeed(rootSeed, 'testnet')
|
||||
|
||||
// HDNode of BIP44 account
|
||||
const account = BITBOX.HDNode.derivePath(masterHDNode, "m/44'/145'/0'")
|
||||
|
||||
// derive the first external change address HDNode which is going to spend utxo
|
||||
const change = BITBOX.HDNode.derivePath(account, "0/0")
|
||||
const change = BITBOX.HDNode.derivePath(account, '0/0')
|
||||
|
||||
return change
|
||||
}
|
||||
|
||||
// Get the balance in BCH of a BCH address.
|
||||
async function getBCHBalance(addr, verbose) {
|
||||
async function getBCHBalance (addr, verbose) {
|
||||
try {
|
||||
const result = await BITBOX.Address.details(addr)
|
||||
|
||||
@@ -167,16 +169,16 @@ async function getBCHBalance(addr, verbose) {
|
||||
|
||||
return bchBalance.balance
|
||||
} catch (err) {
|
||||
console.error(`Error in getBCHBalance: `, err)
|
||||
console.error('Error in getBCHBalance: ', err)
|
||||
console.log(`addr: ${addr}`)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the utxo with the biggest balance from an array of utxos.
|
||||
function findBiggestUtxo(utxos) {
|
||||
function findBiggestUtxo (utxos) {
|
||||
// Sort the utxos by the amount of satoshis, largest first.
|
||||
utxos.sort(function(a, b) {
|
||||
utxos.sort(function (a, b) {
|
||||
return b.satoshis - a.satoshis
|
||||
})
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
@@ -18,22 +18,22 @@ util.inspect.defaultOptions = {
|
||||
// const SLPSDK = require("../../../lib/SLP")
|
||||
// const slpsdk = new SLPSDK()
|
||||
|
||||
const WALLET1 = `../wallet1.json`
|
||||
const WALLET2 = `../wallet2.json`
|
||||
const WALLET1 = '../wallet1.json'
|
||||
const WALLET2 = '../wallet2.json'
|
||||
|
||||
const lib = require("../util/e2e-util")
|
||||
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() {
|
||||
async function sendTokenTest () {
|
||||
try {
|
||||
// Open the sending wallet.
|
||||
const sendWallet = await lib.openWallet(WALLET1)
|
||||
//console.log(`sendWallet: ${JSON.stringify(walletInfo, null, 2)}`)
|
||||
// console.log(`sendWallet: ${JSON.stringify(walletInfo, null, 2)}`)
|
||||
|
||||
// Open the recieving wallet.
|
||||
const recvWallet = await lib.openWallet(WALLET2)
|
||||
//console.log(`recvWallet: ${JSON.stringify(walletInfo, null, 2)}`)
|
||||
// console.log(`recvWallet: ${JSON.stringify(walletInfo, null, 2)}`)
|
||||
|
||||
// Get the balance of the recieving wallet.
|
||||
// const testTokens = recvWallet.tokenBalance.filter(
|
||||
@@ -46,7 +46,7 @@ async function sendTokenTest() {
|
||||
|
||||
// Send a token to the recieving wallet.
|
||||
await lib.sendToken(sendWallet, recvWallet)
|
||||
console.log(`Sent test token.`)
|
||||
console.log('Sent test token.')
|
||||
|
||||
// Track the time until the balance for the recieving wallet has been updated.
|
||||
const startTime = new Date()
|
||||
@@ -56,7 +56,7 @@ async function sendTokenTest() {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
await sleep(waitTime) // Wait for a while before checking
|
||||
|
||||
console.log(`Checking token balance...`)
|
||||
console.log('Checking token balance...')
|
||||
newBalance = await lib.getTestTokenBalance(recvWallet)
|
||||
|
||||
// Break out of the loop once a new balance is detected.
|
||||
@@ -65,12 +65,12 @@ async function sendTokenTest() {
|
||||
// Provide high-level warnings.
|
||||
const secondsPassed = (i * waitTime) / 1000
|
||||
if (secondsPassed > 60 * 10) {
|
||||
console.log(`More than 10 minutes passed.`)
|
||||
console.log('More than 10 minutes passed.')
|
||||
return false // Fail the test.
|
||||
} else if (secondsPassed > 60 * 5) {
|
||||
console.log(`More than 5 minutes passed.`)
|
||||
console.log('More than 5 minutes passed.')
|
||||
} else if (secondsPassed > 60) {
|
||||
console.log(`More than 1 minute passed.`)
|
||||
console.log('More than 1 minute passed.')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,13 +85,13 @@ async function sendTokenTest() {
|
||||
|
||||
return deltaTime // Return the time in minutes it took for SLPDB to update.
|
||||
} catch (err) {
|
||||
console.log(`Error in e2e/send-token.js/sendTokenTest(): `, err)
|
||||
console.log('Error in e2e/send-token.js/sendTokenTest(): ', err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Promise based sleep function.
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
|
||||
+19
-18
@@ -10,19 +10,19 @@ module.exports = {
|
||||
threeDecimals
|
||||
}
|
||||
|
||||
const SLPSDK = require("../../../lib/SLP")
|
||||
const SLPSDK = require('../../../lib/SLP')
|
||||
const slpsdk = new SLPSDK()
|
||||
|
||||
const testTokenId =
|
||||
"cc1b2084a9c43bb5a633df7f38201adde5c5f5cef2fed945d12f8dcd4e505c67"
|
||||
'cc1b2084a9c43bb5a633df7f38201adde5c5f5cef2fed945d12f8dcd4e505c67'
|
||||
|
||||
// Open a wallet and return an object with its address, BCH balance, and SLP
|
||||
// token balance.
|
||||
async function openWallet(filename) {
|
||||
async function openWallet (filename) {
|
||||
try {
|
||||
walletInfo = require(filename)
|
||||
const walletInfo = require(filename)
|
||||
|
||||
//const walletBalance = await getBalance(walletInfo)
|
||||
// const walletBalance = await getBalance(walletInfo)
|
||||
// const walletBalance = await slpsdk.Utils.balancesForAddress(
|
||||
// walletInfo.slpAddress
|
||||
// )
|
||||
@@ -40,7 +40,7 @@ async function openWallet(filename) {
|
||||
}
|
||||
|
||||
// Send a token from wallet1 to wallet2.
|
||||
async function sendToken(wallet1, wallet2) {
|
||||
async function sendToken (wallet1, wallet2) {
|
||||
try {
|
||||
const mnemonic = wallet1.mnemonic
|
||||
|
||||
@@ -53,11 +53,11 @@ async function sendToken(wallet1, wallet2) {
|
||||
// HDNode of BIP44 account
|
||||
const account = slpsdk.HDNode.derivePath(masterHDNode, "m/44'/145'/0'")
|
||||
|
||||
const change = slpsdk.HDNode.derivePath(account, "0/0")
|
||||
const change = slpsdk.HDNode.derivePath(account, '0/0')
|
||||
|
||||
// get the cash address
|
||||
//const cashAddress = slpsdk.HDNode.toCashAddress(change)
|
||||
//const slpAddress = slpsdk.HDNode.toSLPAddress(change)
|
||||
// const cashAddress = slpsdk.HDNode.toCashAddress(change)
|
||||
// const slpAddress = slpsdk.HDNode.toSLPAddress(change)
|
||||
|
||||
const fundingAddress = wallet1.slpAddress
|
||||
const fundingWif = slpsdk.HDNode.toWIF(change) // <-- compressed WIF format
|
||||
@@ -71,25 +71,26 @@ async function sendToken(wallet1, wallet2) {
|
||||
tokenReceiverAddress,
|
||||
bchChangeReceiverAddress,
|
||||
tokenId:
|
||||
"cc1b2084a9c43bb5a633df7f38201adde5c5f5cef2fed945d12f8dcd4e505c67",
|
||||
'cc1b2084a9c43bb5a633df7f38201adde5c5f5cef2fed945d12f8dcd4e505c67',
|
||||
amount: 1
|
||||
}
|
||||
|
||||
//console.log(`createConfig: ${util.inspect(createConfig)}`)
|
||||
// console.log(`createConfig: ${util.inspect(createConfig)}`)
|
||||
|
||||
// Generate, sign, and broadcast a hex-encoded transaction for sending
|
||||
// the tokens.
|
||||
const sendTxId = await slpsdk.TokenType1.send(sendConfig)
|
||||
// const sendTxId = await slpsdk.TokenType1.send(sendConfig)
|
||||
await slpsdk.TokenType1.send(sendConfig)
|
||||
|
||||
//console.log(`sendTxId: ${sendTxId}`)
|
||||
// console.log(`sendTxId: ${sendTxId}`)
|
||||
} catch (err) {
|
||||
console.log(`Error in e2e-util.js/sendToken()`)
|
||||
console.log('Error in e2e-util.js/sendToken()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// Returns just the test token balance for a wallet.
|
||||
async function getTestTokenBalance(walletData) {
|
||||
async function getTestTokenBalance (walletData) {
|
||||
try {
|
||||
const tokenBalance = await slpsdk.Util.balancesForAddress(
|
||||
walletData.slpAddress
|
||||
@@ -100,20 +101,20 @@ async function getTestTokenBalance(walletData) {
|
||||
|
||||
return testTokens[0].balance
|
||||
} catch (err) {
|
||||
console.log(`Error in e2e-util.js/getTestTokenBalance()`)
|
||||
console.log('Error in e2e-util.js/getTestTokenBalance()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// Round a number to three decimal places.
|
||||
function threeDecimals(inNum) {
|
||||
function threeDecimals (inNum) {
|
||||
try {
|
||||
let tempNum = inNum * 1000
|
||||
tempNum = Math.round(tempNum)
|
||||
tempNum = tempNum / 1000
|
||||
return tempNum
|
||||
} catch (err) {
|
||||
console.log(`Error in e2e-util.js/threeDecimals()`)
|
||||
console.log('Error in e2e-util.js/threeDecimals()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,331 +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 BCHJS = require("../../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 3
|
||||
}
|
||||
|
||||
describe(`#blockchain`, () => {
|
||||
describe(`#getBestBlockHash`, () => {
|
||||
it(`should GET best block hash`, async () => {
|
||||
const result = await bchjs.Blockchain.getBestBlockHash()
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isString(result)
|
||||
assert.equal(result.length, 64, "Specific hash length")
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getBlockHeader", () => {
|
||||
it(`should GET block header for a single hash`, async () => {
|
||||
const hash =
|
||||
"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"
|
||||
|
||||
const result = await bchjs.Blockchain.getBlockHeader(hash)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"hash",
|
||||
"confirmations",
|
||||
"height",
|
||||
"version",
|
||||
"versionHex",
|
||||
"merkleroot",
|
||||
"time",
|
||||
"mediantime",
|
||||
"nonce",
|
||||
"bits",
|
||||
"difficulty",
|
||||
"chainwork",
|
||||
"previousblockhash",
|
||||
"nextblockhash",
|
||||
"nTx"
|
||||
])
|
||||
})
|
||||
|
||||
it(`should GET block headers for an array of hashes`, async () => {
|
||||
const hash = [
|
||||
"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201",
|
||||
"00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3"
|
||||
]
|
||||
|
||||
const result = await bchjs.Blockchain.getBlockHeader(hash)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], [
|
||||
"hash",
|
||||
"confirmations",
|
||||
"height",
|
||||
"version",
|
||||
"versionHex",
|
||||
"merkleroot",
|
||||
"time",
|
||||
"mediantime",
|
||||
"nonce",
|
||||
"bits",
|
||||
"difficulty",
|
||||
"chainwork",
|
||||
"previousblockhash",
|
||||
"nextblockhash",
|
||||
"nTx"
|
||||
])
|
||||
})
|
||||
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
try {
|
||||
const hash = 12345
|
||||
|
||||
await bchjs.Blockchain.getBlockHeader(hash)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input hash must be a string or array of strings`
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) {
|
||||
data.push(
|
||||
"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"
|
||||
)
|
||||
}
|
||||
|
||||
const result = await bchjs.Blockchain.getBlockHeader(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getMempoolEntry", () => {
|
||||
/*
|
||||
// To run this test, the txid must be unconfirmed.
|
||||
const txid =
|
||||
"defea04c38ee00cf73ad402984714ed22dc0dd99b2ae5cb50d791d94343ba79b"
|
||||
|
||||
it(`should GET single mempool entry`, async () => {
|
||||
const result = await bchjs.Blockchain.getMempoolEntry(txid)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"size",
|
||||
"fee",
|
||||
"modifiedfee",
|
||||
"time",
|
||||
"height",
|
||||
"startingpriority",
|
||||
"currentpriority",
|
||||
"descendantcount",
|
||||
"descendantsize",
|
||||
"descendantfees",
|
||||
"ancestorcount",
|
||||
"ancestorsize",
|
||||
"ancestorfees",
|
||||
"depends"
|
||||
])
|
||||
})
|
||||
|
||||
it(`should get an array of mempool entries`, async () => {
|
||||
const result = await bchjs.Blockchain.getMempoolEntry([txid, txid])
|
||||
console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"size",
|
||||
"fee",
|
||||
"modifiedfee",
|
||||
"time",
|
||||
"height",
|
||||
"startingpriority",
|
||||
"currentpriority",
|
||||
"descendantcount",
|
||||
"descendantsize",
|
||||
"descendantfees",
|
||||
"ancestorcount",
|
||||
"ancestorsize",
|
||||
"ancestorfees",
|
||||
"depends"
|
||||
])
|
||||
})
|
||||
*/
|
||||
|
||||
it(`should throw an error if txid is not in mempool`, async () => {
|
||||
try {
|
||||
const txid =
|
||||
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
|
||||
|
||||
await bchjs.Blockchain.getMempoolEntry(txid)
|
||||
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: ${util.inspect(err)}`)
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, `Transaction not in mempool`)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw an error for improper single input`, async () => {
|
||||
try {
|
||||
const txid = 12345
|
||||
|
||||
await bchjs.Blockchain.getMempoolEntry(txid)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input must be a string or array of strings`
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#getTxOutProof`, () => {
|
||||
it(`should get single tx out proof`, async () => {
|
||||
const txid =
|
||||
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
|
||||
|
||||
const result = await bchjs.Blockchain.getTxOutProof(txid)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isString(result)
|
||||
})
|
||||
|
||||
it(`should get an array of tx out proofs`, async () => {
|
||||
const txid = [
|
||||
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7",
|
||||
"fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"
|
||||
]
|
||||
|
||||
const result = await bchjs.Blockchain.getTxOutProof(txid)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isString(result[0])
|
||||
})
|
||||
|
||||
it(`should throw an error for improper single input`, async () => {
|
||||
try {
|
||||
const txid = 12345
|
||||
|
||||
await bchjs.Blockchain.getTxOutProof(txid)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input must be a string or array of strings`
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#verifyTxOutProof`, () => {
|
||||
const mockTxOutProof =
|
||||
"0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01"
|
||||
|
||||
it(`should verify a single proof`, async () => {
|
||||
const result = await bchjs.Blockchain.verifyTxOutProof(mockTxOutProof)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isString(result[0])
|
||||
assert.equal(
|
||||
result[0],
|
||||
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
|
||||
)
|
||||
})
|
||||
|
||||
it(`should verify an array of proofs`, async () => {
|
||||
const proofs = [mockTxOutProof, mockTxOutProof]
|
||||
const result = await bchjs.Blockchain.verifyTxOutProof(proofs)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isString(result[0])
|
||||
assert.equal(
|
||||
result[0],
|
||||
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
|
||||
)
|
||||
})
|
||||
|
||||
it(`should throw an error for improper single input`, async () => {
|
||||
try {
|
||||
const txid = 12345
|
||||
|
||||
await bchjs.Blockchain.verifyTxOutProof(txid)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input must be a string or array of strings`
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) data.push(mockTxOutProof)
|
||||
|
||||
const result = await bchjs.Blockchain.verifyTxOutProof(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getTxOut", () => {
|
||||
it("should get information on an unspent tx", async () => {
|
||||
const result = await bchjs.Blockchain.getTxOut(
|
||||
"62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8",
|
||||
0,
|
||||
true
|
||||
)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"bestblock",
|
||||
"confirmations",
|
||||
"value",
|
||||
"scriptPubKey",
|
||||
"coinbase"
|
||||
])
|
||||
})
|
||||
|
||||
it("should get information on a spent tx", async () => {
|
||||
const result = await bchjs.Blockchain.getTxOut(
|
||||
"87380e52d151856b23173d6d8a3db01b984c6b50f77ea045a5a1cf4f54497871",
|
||||
0,
|
||||
true
|
||||
)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.equal(result, null)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
Integration tests for bchjs control library.
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe(`#control`, () => {
|
||||
describe(`#getNetworkInfo`, () => {
|
||||
it("should get info on the full node", async () => {
|
||||
const result = await bchjs.Control.getNetworkInfo()
|
||||
console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "version")
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,356 +0,0 @@
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const sinon = require("sinon")
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe(`#ElectrumX`, () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe(`#utxo`, () => {
|
||||
it(`should GET utxos for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
|
||||
const result = await bchjs.Electrumx.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "utxos")
|
||||
assert.isArray(result.utxos)
|
||||
|
||||
assert.property(result.utxos[0], "height")
|
||||
assert.property(result.utxos[0], "tx_hash")
|
||||
assert.property(result.utxos[0], "tx_pos")
|
||||
assert.property(result.utxos[0], "value")
|
||||
})
|
||||
|
||||
it(`should POST request for UTXOs for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "utxos")
|
||||
assert.isArray(result.utxos)
|
||||
|
||||
assert.property(result.utxos[0], "utxos")
|
||||
assert.isArray(result.utxos[0].utxos)
|
||||
assert.property(result.utxos[0], "address")
|
||||
|
||||
assert.property(result.utxos[0].utxos[0], "height")
|
||||
assert.property(result.utxos[0].utxos[0], "tx_hash")
|
||||
assert.property(result.utxos[0].utxos[0], "tx_pos")
|
||||
assert.property(result.utxos[0].utxos[0], "value")
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
|
||||
|
||||
const result = await bchjs.Electrumx.utxo(addr)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#balance`, () => {
|
||||
it(`should GET balance for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
|
||||
const result = await bchjs.Electrumx.balance(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "balance")
|
||||
assert.property(result.balance, "confirmed")
|
||||
assert.property(result.balance, "unconfirmed")
|
||||
})
|
||||
|
||||
it(`should POST request for balances for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.balance(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "balances")
|
||||
assert.isArray(result.balances)
|
||||
|
||||
assert.property(result.balances[0], "address")
|
||||
assert.property(result.balances[0], "balance")
|
||||
assert.property(result.balances[0].balance, "confirmed")
|
||||
assert.property(result.balances[0].balance, "unconfirmed")
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
|
||||
|
||||
const result = await bchjs.Electrumx.balance(addr)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#transactions`, () => {
|
||||
it(`should GET transaction history for a single address`, async () => {
|
||||
const addr = "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
|
||||
const result = await bchjs.Electrumx.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "transactions")
|
||||
assert.isArray(result.transactions)
|
||||
assert.property(result.transactions[0], "height")
|
||||
assert.property(result.transactions[0], "tx_hash")
|
||||
})
|
||||
|
||||
it(`should POST request for transaction history for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "transactions")
|
||||
assert.isArray(result.transactions)
|
||||
|
||||
assert.property(result.transactions[0], "address")
|
||||
assert.property(result.transactions[0], "transactions")
|
||||
assert.isArray(result.transactions[0].transactions)
|
||||
assert.property(result.transactions[0].transactions[0], "height")
|
||||
assert.property(result.transactions[0].transactions[0], "tx_hash")
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0")
|
||||
|
||||
const result = await bchjs.Electrumx.transactions(addr)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#unconfirmed`, () => {
|
||||
// These tests won't work because unconfirmed transactions are transient in nature.
|
||||
/*
|
||||
it(`should GET unconfirmed UTXOs (mempool) for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqy6qwk3wpne95hhv8uzwr4cn8m7c06cqgchl77dnv"
|
||||
|
||||
const result = await bchjs.Electrumx.unconfirmed(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "utxos")
|
||||
assert.isArray(result.utxos)
|
||||
|
||||
assert.property(result.utxos[0], "height")
|
||||
assert.property(result.utxos[0], "tx_hash")
|
||||
assert.property(result.utxos[0], "fee")
|
||||
})
|
||||
|
||||
it(`should POST request for unconfirmed UTXOs (mempool) for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qqy6qwk3wpne95hhv8uzwr4cn8m7c06cqgchl77dnv",
|
||||
"bitcoincash:qpyrtsl9msdu2klgfpcmn2v5r22w9rk24g8pal74ts"
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.unconfirmed(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "utxos")
|
||||
assert.isArray(result.utxos)
|
||||
|
||||
assert.property(result.utxos[0], "utxos")
|
||||
assert.isArray(result.utxos[0].utxos)
|
||||
assert.property(result.utxos[0], "address")
|
||||
|
||||
assert.property(result.utxos[0].utxos[0], "height")
|
||||
assert.property(result.utxos[0].utxos[0], "tx_hash")
|
||||
assert.property(result.utxos[0].utxos[0], "fee")
|
||||
})
|
||||
*/
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
|
||||
|
||||
await bchjs.Electrumx.unconfirmed(addr)
|
||||
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#blockHeader`, () => {
|
||||
it(`should GET block headers for given height and count`, async () => {
|
||||
const height = 42
|
||||
const count = 2
|
||||
|
||||
const result = await bchjs.Electrumx.blockHeader(height, count)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "headers")
|
||||
assert.isArray(result.headers)
|
||||
assert.equal(result.headers.length, 2)
|
||||
})
|
||||
|
||||
it(`should GET block headers for given height with default count = 1`, async () => {
|
||||
const height = 42
|
||||
|
||||
const result = await bchjs.Electrumx.blockHeader(height)
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "headers")
|
||||
assert.isArray(result.headers)
|
||||
assert.equal(result.headers.length, 1)
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#txData`, () => {
|
||||
it(`should GET details for a single transaction`, async () => {
|
||||
const txid =
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
|
||||
const result = await bchjs.Electrumx.txData(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "details")
|
||||
assert.isObject(result.details)
|
||||
|
||||
assert.property(result.details, "blockhash")
|
||||
assert.property(result.details, "hash")
|
||||
assert.property(result.details, "hex")
|
||||
assert.property(result.details, "vin")
|
||||
assert.property(result.details, "vout")
|
||||
assert.equal(result.details.hash, txid)
|
||||
})
|
||||
|
||||
it(`should POST details for an array of transactions`, async () => {
|
||||
const txids = [
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.txData(txids)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "transactions")
|
||||
assert.isArray(result.transactions)
|
||||
|
||||
assert.property(result.transactions[0], "txid")
|
||||
assert.property(result.transactions[0], "details")
|
||||
|
||||
assert.property(result.transactions[0].details, "blockhash")
|
||||
assert.property(result.transactions[0].details, "hash")
|
||||
assert.property(result.transactions[0].details, "hex")
|
||||
assert.property(result.transactions[0].details, "vin")
|
||||
assert.property(result.transactions[0].details, "vout")
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const txids = []
|
||||
for (let i = 0; i < 25; i++) {
|
||||
txids.push(
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
)
|
||||
}
|
||||
|
||||
await bchjs.Electrumx.txData(txids)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#broadcast`, () => {
|
||||
it(`should broadcast a single transaction`, async () => {
|
||||
const txHex =
|
||||
"020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000"
|
||||
|
||||
try {
|
||||
await bchjs.Electrumx.broadcast(txHex)
|
||||
} catch (err) {
|
||||
assert.property(err, "success")
|
||||
assert.equal(err.success, false)
|
||||
assert.include(
|
||||
err.error,
|
||||
"the transaction was rejected by network rules"
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,31 +0,0 @@
|
||||
const assert = require("chai").assert
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe("#Encryption", () => {
|
||||
describe("#getPubKey", () => {
|
||||
it("should get a public key", async () => {
|
||||
const addr = "bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq"
|
||||
|
||||
const result = await bchjs.encryption.getPubKey(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, true)
|
||||
assert.property(result, "publicKey")
|
||||
})
|
||||
|
||||
it("should report when public key can not be found", async () => {
|
||||
const addr = "bitcoincash:qrgqqkky28jdkv3w0ctrah0mz3jcsnsklc34gtukrh"
|
||||
|
||||
const result = await bchjs.encryption.getPubKey(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.equal(result.success, false)
|
||||
assert.property(result, "publicKey")
|
||||
assert.equal(result.publicKey, "not found")
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,129 +0,0 @@
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const sinon = require("sinon")
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const bchjs = new BCHJS({ ninsightURL: "https://rest.bitcoin.com/v2" })
|
||||
|
||||
describe(`#Ninsight`, () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe(`#utxo`, () => {
|
||||
it(`should GET utxos for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
|
||||
const result = await bchjs.Ninsight.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result[0], "utxos")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "slpAddress")
|
||||
assert.property(result[0], "scriptPubKey")
|
||||
assert.property(result[0], "asm")
|
||||
|
||||
assert.isArray(result[0].utxos)
|
||||
|
||||
assert.property(result[0].utxos[0], "txid")
|
||||
assert.property(result[0].utxos[0], "vout")
|
||||
assert.property(result[0].utxos[0], "amount")
|
||||
assert.property(result[0].utxos[0], "satoshis")
|
||||
assert.property(result[0].utxos[0], "height")
|
||||
assert.property(result[0].utxos[0], "confirmations")
|
||||
})
|
||||
|
||||
it(`should POST utxo details for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7",
|
||||
"bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr"
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isArray(result[0].utxos)
|
||||
|
||||
assert.property(result[0], "utxos")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "slpAddress")
|
||||
assert.property(result[0], "scriptPubKey")
|
||||
assert.property(result[0], "asm")
|
||||
})
|
||||
})
|
||||
describe(`#transactions`, () => {
|
||||
it(`should POST transactions history for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
|
||||
const result = await bchjs.Ninsight.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "txs")
|
||||
assert.isArray(result[0].txs)
|
||||
assert.property(result[0].txs[0], "txid")
|
||||
assert.property(result[0].txs[0], "vin")
|
||||
assert.property(result[0].txs[0], "vout")
|
||||
})
|
||||
it(`should POST transactions history for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7",
|
||||
"bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr"
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "txs")
|
||||
assert.isArray(result[0].txs)
|
||||
assert.property(result[0].txs[0], "txid")
|
||||
assert.property(result[0].txs[0], "vin")
|
||||
assert.property(result[0].txs[0], "vout")
|
||||
})
|
||||
})
|
||||
describe(`#txDetails`, () => {
|
||||
it(`should POST transactions details for a single address`, async () => {
|
||||
const txid = "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"
|
||||
|
||||
const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], "txid")
|
||||
assert.property(result[0], "version")
|
||||
assert.property(result[0], "locktime")
|
||||
assert.property(result[0], "vin")
|
||||
assert.property(result[0], "vout")
|
||||
assert.property(result[0], "blockhash")
|
||||
assert.property(result[0], "blockheight")
|
||||
assert.property(result[0], "confirmations")
|
||||
assert.property(result[0], "time")
|
||||
assert.property(result[0], "blocktime")
|
||||
assert.property(result[0], "isCoinBase")
|
||||
assert.property(result[0], "valueOut")
|
||||
assert.property(result[0], "size")
|
||||
})
|
||||
it(`should POST transactions details for an array of addresses`, async () => {
|
||||
const txid = [
|
||||
"fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33",
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], "txid")
|
||||
assert.property(result[0], "vin")
|
||||
assert.property(result[0], "vout")
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
tests for OpenBazaar library.
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe(`#OpenBazaar`, () => {
|
||||
describe(`#Balance`, () => {
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
try {
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.OpenBazaar.balance(addr)
|
||||
// assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: `, err)
|
||||
assert.include(err.message, `Input address must be a string`)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should GET balance for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
|
||||
const result = await bchjs.OpenBazaar.balance(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"page",
|
||||
"totalPages",
|
||||
"itemsOnPage",
|
||||
"addrStr",
|
||||
"balance",
|
||||
"totalReceived",
|
||||
"totalSent",
|
||||
"unconfirmedBalance",
|
||||
"unconfirmedTxApperances",
|
||||
"txApperances",
|
||||
"transactions"
|
||||
])
|
||||
assert.isArray(result.transactions)
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#utxo`, () => {
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
try {
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.OpenBazaar.utxo(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: `, err)
|
||||
assert.include(err.message, `Input address must be a string`)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should GET utxos for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
|
||||
const result = await bchjs.OpenBazaar.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], [
|
||||
"txid",
|
||||
"vout",
|
||||
"amount",
|
||||
"height",
|
||||
"confirmations",
|
||||
"satoshis"
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#tx`, () => {
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
try {
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.OpenBazaar.tx(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: `, err)
|
||||
assert.include(err.message, `Input txid must be a string`)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should GET transactions for a single address`, async () => {
|
||||
const addr =
|
||||
"2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7"
|
||||
|
||||
const result = await bchjs.OpenBazaar.tx(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"txid",
|
||||
"version",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"blockheight",
|
||||
"confirmations",
|
||||
"blocktime",
|
||||
"valueOut",
|
||||
"valueIn",
|
||||
"fees",
|
||||
"hex",
|
||||
"time"
|
||||
])
|
||||
assert.isArray(result.vin)
|
||||
assert.isArray(result.vout)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,33 +0,0 @@
|
||||
const assert = require("chai").assert
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe("#price", () => {
|
||||
describe("#current", () => {
|
||||
describe("#single currency", () => {
|
||||
it("should get current price for single currency", async () => {
|
||||
const result = await bchjs.Price.current("usd")
|
||||
assert.notEqual(0, result)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getUsd", () => {
|
||||
it("should get the USD price of BCH", async () => {
|
||||
const result = await bchjs.Price.getUsd()
|
||||
// console.log(result)
|
||||
|
||||
assert.isNumber(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#rates", () => {
|
||||
it("should get the price of BCH in several currencies", async () => {
|
||||
const result = await bchjs.Price.rates()
|
||||
// console.log(result)
|
||||
|
||||
assert.property(result, "USD")
|
||||
assert.property(result, "CAD")
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,329 +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", () => {
|
||||
describe("#decodeRawTransaction", () => {
|
||||
it("should decode tx for a single hex", async () => {
|
||||
const hex =
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeRawTransaction(hex)
|
||||
//console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout"
|
||||
])
|
||||
assert.isArray(result.vin)
|
||||
assert.isArray(result.vout)
|
||||
})
|
||||
|
||||
it("should decode an array of tx hexes", async () => {
|
||||
const hexes = [
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000",
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
]
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeRawTransaction(hexes)
|
||||
//console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout"
|
||||
])
|
||||
assert.isArray(result[0].vin)
|
||||
assert.isArray(result[0].vout)
|
||||
})
|
||||
|
||||
it(`should throw an error for improper single input`, async () => {
|
||||
try {
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.RawTransactions.decodeRawTransaction(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input must be a string or array of strings.`
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) {
|
||||
data.push(
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
)
|
||||
}
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeRawTransaction(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getRawTransaction", () => {
|
||||
it("should decode a single txid, with concise output", async () => {
|
||||
const txid =
|
||||
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1"
|
||||
const verbose = false
|
||||
|
||||
const result = await bchjs.RawTransactions.getRawTransaction(
|
||||
txid,
|
||||
verbose
|
||||
)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isString(result)
|
||||
})
|
||||
|
||||
it("should decode a single txid, with verbose output", async () => {
|
||||
const txid =
|
||||
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1"
|
||||
const verbose = true
|
||||
|
||||
const result = await bchjs.RawTransactions.getRawTransaction(
|
||||
txid,
|
||||
verbose
|
||||
)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"hex",
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"confirmations",
|
||||
"time",
|
||||
"blocktime"
|
||||
])
|
||||
assert.isArray(result.vin)
|
||||
assert.isArray(result.vout)
|
||||
})
|
||||
|
||||
it("should decode an array of txids, with a concise output", async () => {
|
||||
const txid = [
|
||||
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1",
|
||||
"b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f"
|
||||
]
|
||||
const verbose = false
|
||||
|
||||
const result = await bchjs.RawTransactions.getRawTransaction(
|
||||
txid,
|
||||
verbose
|
||||
)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isString(result[0])
|
||||
})
|
||||
|
||||
it("should decode an array of txids, with a verbose output", async () => {
|
||||
const txid = [
|
||||
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1",
|
||||
"b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f"
|
||||
]
|
||||
const verbose = true
|
||||
|
||||
const result = await bchjs.RawTransactions.getRawTransaction(
|
||||
txid,
|
||||
verbose
|
||||
)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"hex",
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"confirmations",
|
||||
"time",
|
||||
"blocktime"
|
||||
])
|
||||
assert.isArray(result[0].vin)
|
||||
assert.isArray(result[0].vout)
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const dataMock =
|
||||
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1"
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) data.push(dataMock)
|
||||
|
||||
const result = await bchjs.RawTransactions.getRawTransaction(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#decodeScript", () => {
|
||||
it("should decode script for a single hex", async () => {
|
||||
const hex =
|
||||
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeScript(hex)
|
||||
//console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["asm", "type", "p2sh"])
|
||||
})
|
||||
|
||||
// CT 2/20/19 - Waiting for this PR to be merged complete the test:
|
||||
// https://github.com/Bitcoin-com/rest.bitcoin.com/pull/312
|
||||
/*
|
||||
it("should decode an array of tx hexes", async () => {
|
||||
const hexes = [
|
||||
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16",
|
||||
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
|
||||
]
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeScript(hexes)
|
||||
console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
})
|
||||
*/
|
||||
/*
|
||||
it(`should throw an error for improper single input`, async () => {
|
||||
try {
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.RawTransactions.decodeRawTransaction(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input must be a string or array of strings.`
|
||||
)
|
||||
}
|
||||
})
|
||||
*/
|
||||
})
|
||||
|
||||
/*
|
||||
Testing sentRawTransaction isn't really possible with an integration test,
|
||||
as the endpoint really needs an e2e test to be properly tested. The tests
|
||||
below expect error messages returned from the server, but at least test
|
||||
that the server is responding on those endpoints, and responds consistently.
|
||||
*/
|
||||
describe("sendRawTransaction", () => {
|
||||
it("should send a single transaction hex", async () => {
|
||||
try {
|
||||
const hex =
|
||||
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
|
||||
|
||||
await bchjs.RawTransactions.sendRawTransaction(hex)
|
||||
//console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.fail("Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: ${util.inspect(err)}`)
|
||||
|
||||
assert.hasAllKeys(err, ["error"])
|
||||
assert.include(err.error, "Missing inputs")
|
||||
}
|
||||
})
|
||||
|
||||
it("should send an array of tx hexes", async () => {
|
||||
try {
|
||||
const hexes = [
|
||||
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000",
|
||||
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
|
||||
]
|
||||
|
||||
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
|
||||
console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.fail("Unexpected result!")
|
||||
} catch (err) {
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
|
||||
assert.hasAllKeys(err, ["error"])
|
||||
assert.include(err.error, "Missing inputs")
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw an error for improper single input`, async () => {
|
||||
try {
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.RawTransactions.sendRawTransaction(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input hex must be a string or array of strings`
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const dataMock =
|
||||
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) data.push(dataMock)
|
||||
|
||||
const result = await bchjs.RawTransactions.sendRawTransaction(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,700 +0,0 @@
|
||||
/*
|
||||
Integration tests for the bchjs covering SLP tokens.
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
let bchjs
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 1
|
||||
}
|
||||
|
||||
describe(`#SLP`, () => {
|
||||
// before(() => {
|
||||
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
|
||||
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
|
||||
// })
|
||||
|
||||
beforeEach(async () => {
|
||||
// Introduce a delay so that the BVT doesn't trip the rate limits.
|
||||
await sleep(1000)
|
||||
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
|
||||
describe("#util", () => {
|
||||
describe("#list", () => {
|
||||
it(`should get information on the Spice token`, async () => {
|
||||
const tokenId = `4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf`
|
||||
|
||||
const result = await bchjs.SLP.Utils.list(tokenId)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"decimals",
|
||||
"timestamp",
|
||||
"timestamp_unix",
|
||||
"versionType",
|
||||
"documentUri",
|
||||
"symbol",
|
||||
"name",
|
||||
"containsBaton",
|
||||
"id",
|
||||
"documentHash",
|
||||
"initialTokenQty",
|
||||
"blockCreated",
|
||||
"blockLastActiveSend",
|
||||
"blockLastActiveMint",
|
||||
"txnsSinceGenesis",
|
||||
"validAddress",
|
||||
"totalMinted",
|
||||
"totalBurned",
|
||||
"circulatingSupply",
|
||||
"mintingBatonStatus"
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
// describe("#decodeOpReturn", () => {
|
||||
// it("should decode the OP_RETURN for a SEND txid", async () => {
|
||||
// const txid =
|
||||
// "266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1"
|
||||
//
|
||||
// const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
//
|
||||
// assert.hasAllKeys(result, [
|
||||
// "tokenType",
|
||||
// "transactionType",
|
||||
// "tokenId",
|
||||
// "spendData"
|
||||
// ])
|
||||
// })
|
||||
//
|
||||
// it("should decode the OP_RETURN for a GENESIS txid", async () => {
|
||||
// const txid =
|
||||
// "497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
||||
//
|
||||
// const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
//
|
||||
// assert.hasAllKeys(result, [
|
||||
// "tokenType",
|
||||
// "transactionType",
|
||||
// "ticker",
|
||||
// "name",
|
||||
// "documentUrl",
|
||||
// "documentHash",
|
||||
// "decimals",
|
||||
// "mintBatonVout",
|
||||
// "initialQty",
|
||||
// "tokensSentTo",
|
||||
// "batonHolder"
|
||||
// ])
|
||||
// })
|
||||
//
|
||||
// it("should decode the OP_RETURN for a MINT txid", async () => {
|
||||
// const txid =
|
||||
// "65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4"
|
||||
//
|
||||
// const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
//
|
||||
// assert.hasAllKeys(result, [
|
||||
// "tokenType",
|
||||
// "transactionType",
|
||||
// "tokenId",
|
||||
// "mintBatonVout",
|
||||
// "batonStillExists",
|
||||
// "quantity",
|
||||
// "tokensSentTo",
|
||||
// "batonHolder"
|
||||
// ])
|
||||
// })
|
||||
//
|
||||
// it("should throw an error for a non-SLP transaction", async () => {
|
||||
// try {
|
||||
// const txid =
|
||||
// "3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec"
|
||||
//
|
||||
// await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
//
|
||||
// assert.equal(true, false, "Unexpected result")
|
||||
// } catch (err) {
|
||||
// // console.log(`err: `, err)
|
||||
// assert.include(err.message, "Not an OP_RETURN")
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
|
||||
describe("#decodeOpReturn", () => {
|
||||
it("should decode the OP_RETURN for a SEND txid", async () => {
|
||||
const txid =
|
||||
"266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1"
|
||||
|
||||
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["tokenType", "txType", "tokenId", "amounts"])
|
||||
assert.equal(
|
||||
result.tokenId,
|
||||
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
||||
)
|
||||
|
||||
// Verify outputs
|
||||
assert.equal(result.amounts.length, 2)
|
||||
assert.equal(result.amounts[0], "100000000")
|
||||
assert.equal(result.amounts[1], "99883300000000")
|
||||
})
|
||||
|
||||
it("should decode the OP_RETURN for a GENESIS txid", async () => {
|
||||
const txid =
|
||||
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
||||
|
||||
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"tokenType",
|
||||
"txType",
|
||||
"tokenId",
|
||||
"ticker",
|
||||
"name",
|
||||
"documentUri",
|
||||
"documentHash",
|
||||
"decimals",
|
||||
"mintBatonVout",
|
||||
"qty"
|
||||
])
|
||||
assert.equal(
|
||||
result.tokenId,
|
||||
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
||||
)
|
||||
assert.equal(result.txType, "GENESIS")
|
||||
assert.equal(result.ticker, "TOK-CH")
|
||||
assert.equal(result.name, "TokyoCash")
|
||||
})
|
||||
|
||||
it("should decode the OP_RETURN for a MINT txid", async () => {
|
||||
const txid =
|
||||
"65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4"
|
||||
|
||||
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"tokenType",
|
||||
"txType",
|
||||
"tokenId",
|
||||
"mintBatonVout",
|
||||
"qty"
|
||||
])
|
||||
})
|
||||
|
||||
it("should throw an error for a non-SLP transaction", async () => {
|
||||
try {
|
||||
const txid =
|
||||
"3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec"
|
||||
|
||||
await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
|
||||
assert.equal(true, false, "Unexpected result")
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.message, "scriptpubkey not op_return")
|
||||
}
|
||||
})
|
||||
|
||||
// Note: This TX is interpreted as valid by the original decodeOpReturn().
|
||||
// Fixing this issue and related issues was the reason for creating the
|
||||
// decodeOpReturn2() method using the slp-parser library.
|
||||
it("should throw error for invalid SLP transaction", async () => {
|
||||
try {
|
||||
const txid =
|
||||
"a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415"
|
||||
|
||||
await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.message, "amount string size not 8 bytes")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#tokenUtxoDetails", () => {
|
||||
// // This captures an important corner-case. When an SLP token is created, the
|
||||
// // change UTXO will contain the same SLP txid, but it is not an SLP UTXO.
|
||||
it("should return details on minting baton from genesis transaction", async () => {
|
||||
const utxos = [
|
||||
{
|
||||
txid:
|
||||
"bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90",
|
||||
vout: 3,
|
||||
amount: 0.00002015,
|
||||
satoshis: 2015,
|
||||
height: 594892,
|
||||
confirmations: 5
|
||||
},
|
||||
{
|
||||
txid:
|
||||
"bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90",
|
||||
vout: 2,
|
||||
amount: 0.00000546,
|
||||
satoshis: 546,
|
||||
height: 594892,
|
||||
confirmations: 5
|
||||
}
|
||||
]
|
||||
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.equal(data[0].isValid, false, "Change UTXO marked as false.")
|
||||
|
||||
assert.property(data[1], "txid")
|
||||
assert.property(data[1], "vout")
|
||||
assert.property(data[1], "amount")
|
||||
assert.property(data[1], "satoshis")
|
||||
assert.property(data[1], "height")
|
||||
assert.property(data[1], "confirmations")
|
||||
assert.property(data[1], "utxoType")
|
||||
assert.property(data[1], "tokenId")
|
||||
assert.property(data[1], "tokenTicker")
|
||||
assert.property(data[1], "tokenName")
|
||||
assert.property(data[1], "tokenDocumentUrl")
|
||||
assert.property(data[1], "tokenDocumentHash")
|
||||
assert.property(data[1], "decimals")
|
||||
assert.property(data[1], "isValid")
|
||||
assert.equal(data[1].isValid, true)
|
||||
})
|
||||
|
||||
it("should return details for a MINT token utxo", async () => {
|
||||
// Mock the call to REST API
|
||||
|
||||
const utxos = [
|
||||
{
|
||||
txid:
|
||||
"cf4b922d1e1aa56b52d752d4206e1448ea76c3ebe69b3b97d8f8f65413bd5c76",
|
||||
vout: 1,
|
||||
amount: 0.00000546,
|
||||
satoshis: 546,
|
||||
height: 600297,
|
||||
confirmations: 76
|
||||
}
|
||||
]
|
||||
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.property(data[0], "txid")
|
||||
assert.property(data[0], "vout")
|
||||
assert.property(data[0], "amount")
|
||||
assert.property(data[0], "satoshis")
|
||||
assert.property(data[0], "height")
|
||||
assert.property(data[0], "confirmations")
|
||||
assert.property(data[0], "utxoType")
|
||||
assert.property(data[0], "transactionType")
|
||||
assert.property(data[0], "tokenId")
|
||||
assert.property(data[0], "tokenTicker")
|
||||
assert.property(data[0], "tokenName")
|
||||
assert.property(data[0], "tokenDocumentUrl")
|
||||
assert.property(data[0], "tokenDocumentHash")
|
||||
assert.property(data[0], "decimals")
|
||||
assert.property(data[0], "mintBatonVout")
|
||||
assert.property(data[0], "tokenQty")
|
||||
assert.property(data[0], "isValid")
|
||||
assert.equal(data[0].isValid, true)
|
||||
})
|
||||
|
||||
it("should return details for a simple SEND SLP token utxo", async () => {
|
||||
const utxos = [
|
||||
{
|
||||
txid:
|
||||
"fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb",
|
||||
vout: 1,
|
||||
amount: 0.00000546,
|
||||
satoshis: 546,
|
||||
height: 596089,
|
||||
confirmations: 748
|
||||
}
|
||||
]
|
||||
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.property(data[0], "txid")
|
||||
assert.property(data[0], "vout")
|
||||
assert.property(data[0], "amount")
|
||||
assert.property(data[0], "satoshis")
|
||||
assert.property(data[0], "height")
|
||||
assert.property(data[0], "confirmations")
|
||||
assert.property(data[0], "utxoType")
|
||||
assert.property(data[0], "tokenId")
|
||||
assert.property(data[0], "tokenTicker")
|
||||
assert.property(data[0], "tokenName")
|
||||
assert.property(data[0], "tokenDocumentUrl")
|
||||
assert.property(data[0], "tokenDocumentHash")
|
||||
assert.property(data[0], "decimals")
|
||||
assert.property(data[0], "tokenQty")
|
||||
assert.property(data[0], "isValid")
|
||||
assert.equal(data[0].isValid, true)
|
||||
})
|
||||
|
||||
it("should handle BCH and SLP utxos in the same TX", async () => {
|
||||
const utxos = [
|
||||
{
|
||||
txid:
|
||||
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
|
||||
vout: 3,
|
||||
value: "6816",
|
||||
height: 606848,
|
||||
confirmations: 13,
|
||||
satoshis: 6816
|
||||
},
|
||||
{
|
||||
txid:
|
||||
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
|
||||
vout: 2,
|
||||
value: "546",
|
||||
height: 606848,
|
||||
confirmations: 13,
|
||||
satoshis: 546
|
||||
}
|
||||
]
|
||||
|
||||
const result = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.equal(result.length, 2)
|
||||
assert.equal(result[0].isValid, false)
|
||||
assert.equal(result[1].isValid, true)
|
||||
})
|
||||
|
||||
it("should handle problematic utxos", async () => {
|
||||
const utxos = [
|
||||
{
|
||||
txid:
|
||||
"0e3a217fc22612002031d317b4cecd9b692b66b52951a67b23c43041aefa3959",
|
||||
vout: 0,
|
||||
amount: 0.00018362,
|
||||
satoshis: 18362,
|
||||
height: 613483,
|
||||
confirmations: 124
|
||||
},
|
||||
{
|
||||
txid:
|
||||
"67fd3c7c3a6eb0fea9ab311b91039545086220f7eeeefa367fa28e6e43009f19",
|
||||
vout: 1,
|
||||
amount: 0.00000546,
|
||||
satoshis: 546,
|
||||
height: 612075,
|
||||
confirmations: 1532
|
||||
}
|
||||
]
|
||||
|
||||
const result = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.equal(result.length, 2)
|
||||
assert.equal(result[0].isValid, false)
|
||||
assert.equal(result[1].isValid, true)
|
||||
})
|
||||
|
||||
it("should return false for BCH-only UTXOs", async () => {
|
||||
const utxos = [
|
||||
{
|
||||
txid:
|
||||
"a937f792c7c9eb23b4f344ce5c233d1ac0909217d0a504d71e6b1e4efb864a3b",
|
||||
vout: 0,
|
||||
amount: 0.00001,
|
||||
satoshis: 1000,
|
||||
confirmations: 0,
|
||||
ts: 1578424704
|
||||
},
|
||||
{
|
||||
txid:
|
||||
"53fd141c2e999e080a5860887441a2c45e9cbe262027e2bd2ac998fc76e43c44",
|
||||
vout: 0,
|
||||
amount: 0.00001,
|
||||
satoshis: 1000,
|
||||
confirmations: 0,
|
||||
ts: 1578424634
|
||||
}
|
||||
]
|
||||
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.isArray(data)
|
||||
assert.equal(data[0].isValid, false)
|
||||
assert.equal(data[1].isValid, false)
|
||||
})
|
||||
|
||||
it("should handle a dust attack", async () => {
|
||||
// it("#dustattack", async () => {
|
||||
const utxos = [
|
||||
{
|
||||
height: 655965,
|
||||
tx_hash:
|
||||
"a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e",
|
||||
tx_pos: 151,
|
||||
value: 547,
|
||||
satoshis: 547,
|
||||
txid:
|
||||
"a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e",
|
||||
vout: 151,
|
||||
address: "bitcoincash:qq4dw3sm8qvglspy6w2qg0u2ugsy9zcfcqrpeflwww",
|
||||
hdIndex: 11
|
||||
}
|
||||
]
|
||||
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.equal(data[0].isValid, false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#balancesForAddress", () => {
|
||||
it(`should throw an error if input is not a string or array of strings`, async () => {
|
||||
try {
|
||||
const address = 1234
|
||||
|
||||
await bchjs.SLP.Utils.balancesForAddress(address)
|
||||
|
||||
assert.equal(true, false, "Uh oh. Code path should not end here.")
|
||||
} catch (err) {
|
||||
//console.log(`Error: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input address must be a string or array of strings`
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should fetch all balances for address: simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9`, async () => {
|
||||
const balances = await bchjs.SLP.Utils.balancesForAddress(
|
||||
"simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9"
|
||||
)
|
||||
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
|
||||
|
||||
assert.isArray(balances)
|
||||
assert.hasAllKeys(balances[0], [
|
||||
"tokenId",
|
||||
"balanceString",
|
||||
"balance",
|
||||
"decimalCount",
|
||||
"slpAddress"
|
||||
])
|
||||
})
|
||||
|
||||
it(`should fetch balances for multiple addresses`, async () => {
|
||||
const addresses = [
|
||||
"simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9",
|
||||
"simpleledger:qqss4zp80hn6szsa4jg2s9fupe7g5tcg5ucdyl3r57"
|
||||
]
|
||||
|
||||
const balances = await bchjs.SLP.Utils.balancesForAddress(addresses)
|
||||
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
|
||||
|
||||
assert.isArray(balances)
|
||||
assert.isArray(balances[0])
|
||||
assert.hasAllKeys(balances[0][0], [
|
||||
"tokenId",
|
||||
"balanceString",
|
||||
"balance",
|
||||
"decimalCount",
|
||||
"slpAddress"
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("#hydrateUtxos", () => {
|
||||
it("should throw an error if input is not an array", async () => {
|
||||
try {
|
||||
const utxos = 1234
|
||||
|
||||
await bchjs.SLP.Utils.hydrateUtxos(utxos)
|
||||
|
||||
assert.equal(true, false, "Uh oh. Code path should not end here.")
|
||||
} catch (err) {
|
||||
// console.log(`Error: `, err)
|
||||
assert.include(err.message, `Input must be an array.`)
|
||||
}
|
||||
})
|
||||
|
||||
it("should hydrate UTXOs", async () => {
|
||||
const utxos = [
|
||||
{
|
||||
utxos: [
|
||||
{
|
||||
txid:
|
||||
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
|
||||
vout: 3,
|
||||
value: "6816",
|
||||
height: 606848,
|
||||
confirmations: 13,
|
||||
satoshis: 6816
|
||||
},
|
||||
{
|
||||
txid:
|
||||
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
|
||||
vout: 2,
|
||||
value: "546",
|
||||
height: 606848,
|
||||
confirmations: 13,
|
||||
satoshis: 546
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const result = await bchjs.SLP.Utils.hydrateUtxos(utxos)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
// Test the general structure of the output.
|
||||
assert.isArray(result.slpUtxos)
|
||||
assert.equal(result.slpUtxos.length, 1)
|
||||
assert.equal(result.slpUtxos[0].utxos.length, 2)
|
||||
|
||||
// Test the non-slp UTXO.
|
||||
assert.property(result.slpUtxos[0].utxos[0], "txid")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "vout")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "value")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "height")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "confirmations")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "satoshis")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "isValid")
|
||||
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
|
||||
|
||||
// Test the slp UTXO.
|
||||
assert.property(result.slpUtxos[0].utxos[1], "txid")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "vout")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "value")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "height")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "confirmations")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "satoshis")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "isValid")
|
||||
assert.equal(result.slpUtxos[0].utxos[1].isValid, true)
|
||||
assert.property(result.slpUtxos[0].utxos[1], "transactionType")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenId")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenTicker")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenName")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenDocumentUrl")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenDocumentHash")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "decimals")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenType")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenQty")
|
||||
})
|
||||
|
||||
it("should process data directly from Electrumx", async () => {
|
||||
const addrs = [
|
||||
"bitcoincash:qqnt53cfw990u6y38xgezm0lfa8hknw0wueezcpagp",
|
||||
"bitcoincash:qrh3qgtax6adegzc7zxm6m4sgrv9wq28yqnfn33ce5",
|
||||
"bitcoincash:qqcaee5w4ws77n8s2gzy6fwtma6uxd7ctq8553e495"
|
||||
]
|
||||
|
||||
const utxos = await bchjs.Electrumx.utxo(addrs)
|
||||
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
|
||||
const result = await bchjs.SLP.Utils.hydrateUtxos(utxos.utxos)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
// Test the general structure of the output.
|
||||
assert.isArray(result.slpUtxos)
|
||||
assert.equal(result.slpUtxos.length, 3)
|
||||
assert.equal(result.slpUtxos[0].utxos.length, 1)
|
||||
assert.equal(result.slpUtxos[1].utxos.length, 1)
|
||||
assert.equal(result.slpUtxos[2].utxos.length, 2)
|
||||
|
||||
try {
|
||||
// Test the expected values.
|
||||
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
|
||||
assert.equal(result.slpUtxos[1].utxos[0].isValid, true)
|
||||
assert.equal(result.slpUtxos[1].utxos[0].tokenTicker, "TROUT")
|
||||
assert.equal(result.slpUtxos[2].utxos[0].isValid, false)
|
||||
assert.equal(result.slpUtxos[2].utxos[1].isValid, true)
|
||||
assert.equal(result.slpUtxos[2].utxos[1].tokenTicker, "VALENTINE")
|
||||
} catch (err) {
|
||||
console.error(
|
||||
'The hydrateUtxos call may hitting rate limits, or SLPDB may be having issues if "isValid" results are "null"'
|
||||
)
|
||||
console.log("Error: ", err)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#validateTxid2", () => {
|
||||
it("should invalidate a known invalid TXID", async () => {
|
||||
const txid =
|
||||
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a"
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "txid")
|
||||
assert.equal(result.txid, txid)
|
||||
|
||||
assert.property(result, "isValid")
|
||||
assert.equal(result.isValid, false)
|
||||
})
|
||||
|
||||
it("should validate a known valid TXID", async () => {
|
||||
const txid =
|
||||
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488"
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "txid")
|
||||
assert.equal(result.txid, txid)
|
||||
|
||||
assert.property(result, "isValid")
|
||||
assert.equal(result.isValid, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#tokentype1", () => {
|
||||
describe("#getHexOpReturn", () => {
|
||||
it("should return OP_RETURN object ", async () => {
|
||||
const tokenUtxos = [
|
||||
{
|
||||
tokenId:
|
||||
"0a321bff9761f28e06a268b14711274bb77617410a16807bd0437ef234a072b1",
|
||||
decimals: 0,
|
||||
tokenQty: 2
|
||||
}
|
||||
]
|
||||
const sendQty = 1.5
|
||||
|
||||
const result = await bchjs.SLP.TokenType1.getHexOpReturn(
|
||||
tokenUtxos,
|
||||
sendQty
|
||||
)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "script")
|
||||
assert.isString(result.script)
|
||||
|
||||
assert.property(result, "outputs")
|
||||
assert.isNumber(result.outputs)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Promise-based sleep function
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -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 BCHJS = require("../../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 3
|
||||
}
|
||||
|
||||
describe(`#util`, () => {
|
||||
describe(`#validateAddress`, () => {
|
||||
it(`should return false for testnet addr on mainnet`, async () => {
|
||||
const address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
|
||||
|
||||
const result = await bchjs.Util.validateAddress(address)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["isvalid"])
|
||||
assert.equal(result.isvalid, false)
|
||||
})
|
||||
|
||||
it(`should return false for bad address`, async () => {
|
||||
const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peu`
|
||||
|
||||
const result = await bchjs.Util.validateAddress(address)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["isvalid"])
|
||||
assert.equal(result.isvalid, false)
|
||||
})
|
||||
|
||||
it(`should validate valid address`, async () => {
|
||||
const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`
|
||||
|
||||
const result = await bchjs.Util.validateAddress(address)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"isvalid",
|
||||
"address",
|
||||
"scriptPubKey",
|
||||
//"ismine",
|
||||
//"iswatchonly",
|
||||
"isscript"
|
||||
])
|
||||
assert.equal(result.isvalid, true)
|
||||
})
|
||||
|
||||
it(`should validate an array of addresses`, async () => {
|
||||
const address = [
|
||||
`bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`,
|
||||
`bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`
|
||||
]
|
||||
|
||||
const result = await bchjs.Util.validateAddress(address)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"isvalid",
|
||||
"address",
|
||||
"scriptPubKey",
|
||||
//"ismine",
|
||||
//"iswatchonly",
|
||||
"isscript"
|
||||
])
|
||||
})
|
||||
|
||||
it(`should throw an error for improper single input`, async () => {
|
||||
try {
|
||||
const address = 15432
|
||||
|
||||
await bchjs.Util.validateAddress(address)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input must be a string or array of strings.`
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const dataMock = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) data.push(dataMock)
|
||||
|
||||
const result = await bchjs.Util.validateAddress(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
Integration tests for the Blockbook library.
|
||||
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
//const axios = require("axios")
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 3
|
||||
}
|
||||
|
||||
describe(`#Blockbook`, () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
describe(`#Balance`, () => {
|
||||
it(`should GET balance for a single address`, async () => {
|
||||
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
|
||||
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"page",
|
||||
"totalPages",
|
||||
"itemsOnPage",
|
||||
"address",
|
||||
"balance",
|
||||
"totalReceived",
|
||||
"totalSent",
|
||||
"unconfirmedBalance",
|
||||
"unconfirmedTxs",
|
||||
"txs",
|
||||
"txids"
|
||||
])
|
||||
assert.isArray(result.txids)
|
||||
})
|
||||
|
||||
it(`should POST request balances for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
]
|
||||
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"page",
|
||||
"totalPages",
|
||||
"itemsOnPage",
|
||||
"address",
|
||||
"balance",
|
||||
"totalReceived",
|
||||
"totalSent",
|
||||
"unconfirmedBalance",
|
||||
"unconfirmedTxs",
|
||||
"txs",
|
||||
"txids"
|
||||
])
|
||||
assert.isArray(result[0].txids)
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
|
||||
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#utxo`, () => {
|
||||
it(`should GET utxos for a single address`, async () => {
|
||||
const addr = "bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7"
|
||||
|
||||
const result = await bchjs.Blockbook.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"txid",
|
||||
"vout",
|
||||
"value",
|
||||
"height",
|
||||
"confirmations"
|
||||
])
|
||||
})
|
||||
|
||||
it(`should POST utxo details for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7",
|
||||
"bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr"
|
||||
]
|
||||
|
||||
const result = await bchjs.Blockbook.utxo(addr)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isArray(result[0])
|
||||
assert.hasAnyKeys(result[0][0], [
|
||||
"txid",
|
||||
"vout",
|
||||
"value",
|
||||
"height",
|
||||
"confirmations"
|
||||
])
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr")
|
||||
|
||||
const result = await bchjs.Blockbook.utxo(addr)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -7,109 +7,109 @@
|
||||
of an e2e test to be properly tested.
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 3
|
||||
}
|
||||
|
||||
describe(`#blockchain`, () => {
|
||||
describe('#blockchain', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
describe(`#getBestBlockHash`, () => {
|
||||
it(`should GET best block hash`, async () => {
|
||||
describe('#getBestBlockHash', () => {
|
||||
it('should GET best block hash', async () => {
|
||||
const result = await bchjs.Blockchain.getBestBlockHash()
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isString(result)
|
||||
assert.equal(result.length, 64, "Specific hash length")
|
||||
assert.equal(result.length, 64, 'Specific hash length')
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getBlockHeader", () => {
|
||||
it(`should GET block header for a single hash`, async () => {
|
||||
describe('#getBlockHeader', () => {
|
||||
it('should GET block header for a single hash', async () => {
|
||||
const hash =
|
||||
"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"
|
||||
'000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201'
|
||||
|
||||
const result = await bchjs.Blockchain.getBlockHeader(hash)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"hash",
|
||||
"confirmations",
|
||||
"height",
|
||||
"version",
|
||||
"versionHex",
|
||||
"merkleroot",
|
||||
"time",
|
||||
"mediantime",
|
||||
"nonce",
|
||||
"bits",
|
||||
"difficulty",
|
||||
"chainwork",
|
||||
"previousblockhash",
|
||||
"nextblockhash",
|
||||
"nTx"
|
||||
'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 () => {
|
||||
it('should GET block headers for an array of hashes', async () => {
|
||||
const hash = [
|
||||
"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201",
|
||||
"00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3"
|
||||
'000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201',
|
||||
'00000000000000000568f0a96bf4348847bc84e455cbfec389f27311037a20f3'
|
||||
]
|
||||
|
||||
const result = await bchjs.Blockchain.getBlockHeader(hash)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], [
|
||||
"hash",
|
||||
"confirmations",
|
||||
"height",
|
||||
"version",
|
||||
"versionHex",
|
||||
"merkleroot",
|
||||
"time",
|
||||
"mediantime",
|
||||
"nonce",
|
||||
"bits",
|
||||
"difficulty",
|
||||
"chainwork",
|
||||
"previousblockhash",
|
||||
"nextblockhash",
|
||||
"nTx"
|
||||
'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 () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) {
|
||||
data.push(
|
||||
"000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201"
|
||||
'000000000000000005e14d3f9fdfb70745308706615cfa9edca4f4558332b201'
|
||||
)
|
||||
}
|
||||
|
||||
const result = await bchjs.Blockchain.getBlockHeader(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getMempoolEntry", () => {
|
||||
describe('#getMempoolEntry', () => {
|
||||
/*
|
||||
// To run this test, the txid must be unconfirmed.
|
||||
const txid =
|
||||
@@ -161,77 +161,77 @@ describe(`#blockchain`, () => {
|
||||
})
|
||||
*/
|
||||
|
||||
it(`should throw an error if txid is not in mempool`, async () => {
|
||||
it('should throw an error if txid is not in mempool', async () => {
|
||||
try {
|
||||
const txid =
|
||||
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
|
||||
'03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7'
|
||||
|
||||
await bchjs.Blockchain.getMempoolEntry(txid)
|
||||
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
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`)
|
||||
// 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 () => {
|
||||
describe('#getTxOutProof', () => {
|
||||
it('should get single tx out proof', async () => {
|
||||
const txid =
|
||||
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
|
||||
'03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7'
|
||||
|
||||
const result = await bchjs.Blockchain.getTxOutProof(txid)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isString(result)
|
||||
})
|
||||
|
||||
it(`should get an array of tx out proofs`, async () => {
|
||||
it('should get an array of tx out proofs', async () => {
|
||||
const txid = [
|
||||
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7",
|
||||
"fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"
|
||||
'03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7',
|
||||
'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33'
|
||||
]
|
||||
|
||||
const result = await bchjs.Blockchain.getTxOutProof(txid)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isString(result[0])
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#verifyTxOutProof`, () => {
|
||||
describe('#verifyTxOutProof', () => {
|
||||
const mockTxOutProof =
|
||||
"0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01"
|
||||
'0000002086a4a3161f9ba2174883ec0b93acceac3b2f37b36ed1f90000000000000000009cb02406d1094ecf3e0b4c0ca7c585125e721147c39daf6b48c90b512741e13a12333e5cb38705180f441d8c7100000008fee9b60f1edb57e5712839186277ed39e0a004a32be9096ee47472efde8eae62f789f9d7a9f59d0ea7093dea1e0c65ff0b953f1d8cf3d47f92e732ca0295f603c272d5f4a63509f7a887f2549d78af7444aa0ecbb4f66d9cbe13bc6a89f59e05a199df8325d490818ffefe6b6321d32d7496a68580459836c0183f89082fc1b491cc91b23ecdcaa4c347bf599a62904d61f1c15b400ebbd5c90149010c139d9c1e31b774b796977393a238080ab477e1d240d0c4f155d36f519668f49bae6bd8cd5b8e40522edf76faa09cca6188d83ff13af6967cc6a569d1a5e9aeb1fdb7f531ddd2d0cbb81879741d5f38166ac1932136264366a4065cc96a42e41f96294f02df01'
|
||||
|
||||
it(`should verify a single proof`, async () => {
|
||||
it('should verify a single proof', async () => {
|
||||
const result = await bchjs.Blockchain.verifyTxOutProof(mockTxOutProof)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isString(result[0])
|
||||
assert.equal(
|
||||
result[0],
|
||||
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
|
||||
'03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7'
|
||||
)
|
||||
})
|
||||
|
||||
it(`should verify an array of proofs`, async () => {
|
||||
it('should verify an array of proofs', async () => {
|
||||
const proofs = [mockTxOutProof, mockTxOutProof]
|
||||
const result = await bchjs.Blockchain.verifyTxOutProof(proofs)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isString(result[0])
|
||||
assert.equal(
|
||||
result[0],
|
||||
"03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7"
|
||||
'03f69502ca32e7927fd4f38c1d3f950bff650c1eea3d09a70e9df5a9d7f989f7'
|
||||
)
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) data.push(mockTxOutProof)
|
||||
@@ -239,35 +239,35 @@ describe(`#blockchain`, () => {
|
||||
const result = await bchjs.Blockchain.verifyTxOutProof(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getTxOut", () => {
|
||||
it("should get information on an unspent tx", async () => {
|
||||
describe('#getTxOut', () => {
|
||||
it('should get information on an unspent tx', async () => {
|
||||
const result = await bchjs.Blockchain.getTxOut(
|
||||
"62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8",
|
||||
'62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8',
|
||||
0,
|
||||
true
|
||||
)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"bestblock",
|
||||
"confirmations",
|
||||
"value",
|
||||
"scriptPubKey",
|
||||
"coinbase"
|
||||
'bestblock',
|
||||
'confirmations',
|
||||
'value',
|
||||
'scriptPubKey',
|
||||
'coinbase'
|
||||
])
|
||||
})
|
||||
|
||||
it("should get information on a spent tx", async () => {
|
||||
it('should get information on a spent tx', async () => {
|
||||
const result = await bchjs.Blockchain.getTxOut(
|
||||
"87380e52d151856b23173d6d8a3db01b984c6b50f77ea045a5a1cf4f54497871",
|
||||
'87380e52d151856b23173d6d8a3db01b984c6b50f77ea045a5a1cf4f54497871',
|
||||
0,
|
||||
true
|
||||
)
|
||||
@@ -278,6 +278,6 @@ describe(`#blockchain`, () => {
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Integration tests for the bchjs. Only covers calls made to
|
||||
rest.bitcoin.com.
|
||||
|
||||
TODO
|
||||
*/
|
||||
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 3
|
||||
}
|
||||
|
||||
describe('#rawtransaction', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
/*
|
||||
Testing sentRawTransaction isn't really possible with an integration test,
|
||||
as the endpoint really needs an e2e test to be properly tested. The tests
|
||||
below expect error messages returned from the server, but at least test
|
||||
that the server is responding on those endpoints, and responds consistently.
|
||||
*/
|
||||
describe('sendRawTransaction', () => {
|
||||
it('should send a single transaction hex', async () => {
|
||||
try {
|
||||
const hex =
|
||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
||||
|
||||
await bchjs.RawTransactions.sendRawTransaction(hex)
|
||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
|
||||
assert.hasAllKeys(err, ['error'])
|
||||
assert.include(err.error, 'bad-txns-inputs-missingorspent')
|
||||
}
|
||||
})
|
||||
|
||||
it('should send an array of tx hexes', async () => {
|
||||
try {
|
||||
const hexes = [
|
||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
|
||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
||||
]
|
||||
|
||||
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
|
||||
console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
} catch (err) {
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
|
||||
assert.hasAllKeys(err, ['error'])
|
||||
assert.include(err.error, 'bad-txns-inputs-missingorspent')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
Integration tests for the bchjs covering SLP tokens.
|
||||
These tests are specific to the ABC chain.
|
||||
*/
|
||||
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
let bchjs
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 1
|
||||
}
|
||||
|
||||
describe('#SLP', () => {
|
||||
// before(() => {
|
||||
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
|
||||
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
|
||||
// })
|
||||
|
||||
beforeEach(async () => {
|
||||
// Introduce a delay so that the BVT doesn't trip the rate limits.
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
|
||||
describe('#util', () => {
|
||||
describe('#tokenUtxoDetails', () => {
|
||||
it('should handle a range of UTXO types', async () => {
|
||||
const utxos = [
|
||||
// Malformed SLP tx
|
||||
{
|
||||
note: 'Malformed SLP tx',
|
||||
tx_hash:
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Normal TX (non-SLP)
|
||||
{
|
||||
note: 'Normal TX (non-SLP)',
|
||||
tx_hash:
|
||||
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
||||
tx_pos: 0,
|
||||
value: 400000
|
||||
},
|
||||
// Valid PSF SLP tx
|
||||
{
|
||||
note: 'Valid PSF SLP tx',
|
||||
tx_hash:
|
||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Valid SLP token not in whitelist
|
||||
{
|
||||
note: 'Valid SLP token not in whitelist',
|
||||
tx_hash:
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Token send on BCHN network.
|
||||
{
|
||||
note: 'Token send on BCHN network',
|
||||
tx_hash:
|
||||
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Token send on ABC network.
|
||||
{
|
||||
note: 'Token send on ABC network',
|
||||
tx_hash:
|
||||
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Known invalid SLP token send of PSF tokens.
|
||||
{
|
||||
note: 'Known invalid SLP token send of PSF tokens',
|
||||
tx_hash:
|
||||
'2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
}
|
||||
]
|
||||
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
// Malformed SLP tx
|
||||
assert.equal(data[0].tx_hash, utxos[0].tx_hash)
|
||||
assert.equal(data[0].isValid, false)
|
||||
|
||||
// Normal TX (non-SLP)
|
||||
assert.equal(data[1].tx_hash, utxos[1].tx_hash)
|
||||
assert.equal(data[1].isValid, false)
|
||||
|
||||
// Valid PSF SLP tx
|
||||
assert.equal(data[2].tx_hash, utxos[2].tx_hash)
|
||||
assert.equal(data[2].isValid, true)
|
||||
|
||||
// Valid SLP token not in whitelist
|
||||
assert.equal(data[3].tx_hash, utxos[3].tx_hash)
|
||||
assert.equal(data[3].isValid, true)
|
||||
|
||||
// Token send on BCHN network
|
||||
assert.equal(data[4].tx_hash, utxos[4].tx_hash)
|
||||
assert.equal(data[4].isValid, null)
|
||||
|
||||
// Token send on ABC network
|
||||
assert.equal(data[5].tx_hash, utxos[5].tx_hash)
|
||||
assert.equal(data[5].isValid, true)
|
||||
|
||||
// Known invalid SLP token send of PSF tokens
|
||||
assert.equal(data[6].tx_hash, utxos[6].tx_hash)
|
||||
assert.equal(data[6].isValid, false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#validateTxid3', () => {
|
||||
it('should invalidate a known invalid TXID', async () => {
|
||||
const txid =
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid3(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
|
||||
assert.property(result[0], 'txid')
|
||||
assert.equal(result[0].txid, txid)
|
||||
|
||||
assert.property(result[0], 'valid')
|
||||
assert.equal(result[0].valid, null)
|
||||
})
|
||||
|
||||
it('should validate a known valid TXID', async () => {
|
||||
const txid =
|
||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd'
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid3(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
|
||||
assert.property(result[0], 'txid')
|
||||
assert.equal(result[0].txid, txid)
|
||||
|
||||
assert.property(result[0], 'valid')
|
||||
assert.equal(result[0].valid, true)
|
||||
})
|
||||
|
||||
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
|
||||
const txids = [
|
||||
// Malformed SLP tx
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
||||
// Normal TX (non-SLP)
|
||||
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
||||
// Valid PSF SLP tx
|
||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
||||
// Valid SLP token not in whitelist
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
||||
// Unprocessed SLP TX
|
||||
// "a0d6406eecfd8634158efa9314ff15b4cbf451938e9dc7b5678c46b41eabc6ed" // Mint baton
|
||||
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019'
|
||||
]
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid3(txids)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.equal(result[0].valid, null)
|
||||
assert.equal(result[1].valid, null)
|
||||
assert.equal(result[2].valid, true)
|
||||
assert.equal(result[3].valid, true)
|
||||
assert.equal(result[4].valid, null)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#validateTxid', () => {
|
||||
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
|
||||
const txids = [
|
||||
// Malformed SLP tx
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
||||
// Normal TX (non-SLP)
|
||||
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
||||
// Valid PSF SLP tx
|
||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
||||
// Valid SLP token not in whitelist
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
||||
// Token send on BCHN network.
|
||||
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
|
||||
// Token send on ABC network.
|
||||
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d'
|
||||
]
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid(txids)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.equal(result[0].valid, null)
|
||||
assert.equal(result[1].valid, null)
|
||||
assert.equal(result[2].valid, true)
|
||||
assert.equal(result[3].valid, true)
|
||||
assert.equal(result[4].valid, null)
|
||||
assert.equal(result[5].valid, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Promise-based sleep function
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Integration tests for the bchjs. Only covers calls made to
|
||||
rest.bitcoin.com.
|
||||
|
||||
TODO
|
||||
*/
|
||||
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 3
|
||||
}
|
||||
|
||||
describe('#rawtransaction', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
/*
|
||||
Testing sentRawTransaction isn't really possible with an integration test,
|
||||
as the endpoint really needs an e2e test to be properly tested. The tests
|
||||
below expect error messages returned from the server, but at least test
|
||||
that the server is responding on those endpoints, and responds consistently.
|
||||
*/
|
||||
describe('sendRawTransaction', () => {
|
||||
it('should send a single transaction hex', async () => {
|
||||
try {
|
||||
const hex =
|
||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
||||
|
||||
await bchjs.RawTransactions.sendRawTransaction(hex)
|
||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
|
||||
assert.hasAllKeys(err, ['error'])
|
||||
assert.include(err.error, 'Missing inputs')
|
||||
}
|
||||
})
|
||||
|
||||
it('should send an array of tx hexes', async () => {
|
||||
try {
|
||||
const hexes = [
|
||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
|
||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
||||
]
|
||||
|
||||
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
|
||||
console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
} catch (err) {
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
|
||||
assert.hasAllKeys(err, ['error'])
|
||||
assert.include(err.error, 'Missing inputs')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
Integration tests for the bchjs covering SLP tokens.
|
||||
These tests are specific to the ABC chain.
|
||||
*/
|
||||
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
let bchjs
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 1
|
||||
}
|
||||
|
||||
describe('#SLP', () => {
|
||||
// before(() => {
|
||||
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
|
||||
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
|
||||
// })
|
||||
|
||||
beforeEach(async () => {
|
||||
// Introduce a delay so that the BVT doesn't trip the rate limits.
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
|
||||
describe('#util', () => {
|
||||
describe('#tokenUtxoDetails', () => {
|
||||
it('should handle a range of UTXO types', async () => {
|
||||
const utxos = [
|
||||
// Malformed SLP tx
|
||||
{
|
||||
note: 'Malformed SLP tx',
|
||||
tx_hash:
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Normal TX (non-SLP)
|
||||
{
|
||||
note: 'Normal TX (non-SLP)',
|
||||
tx_hash:
|
||||
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
||||
tx_pos: 0,
|
||||
value: 400000
|
||||
},
|
||||
// Valid PSF SLP tx
|
||||
{
|
||||
note: 'Valid PSF SLP tx',
|
||||
tx_hash:
|
||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Valid SLP token not in whitelist
|
||||
{
|
||||
note: 'Valid SLP token not in whitelist',
|
||||
tx_hash:
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Token send on BCHN network.
|
||||
{
|
||||
note: 'Token send on BCHN network',
|
||||
tx_hash:
|
||||
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Token send on ABC network.
|
||||
{
|
||||
note: 'Token send on ABC network',
|
||||
tx_hash:
|
||||
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Known invalid SLP token send of PSF tokens.
|
||||
{
|
||||
note: 'Known invalid SLP token send of PSF tokens',
|
||||
tx_hash:
|
||||
'2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
}
|
||||
]
|
||||
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
// Malformed SLP tx
|
||||
assert.equal(data[0].tx_hash, utxos[0].tx_hash)
|
||||
assert.equal(data[0].isValid, false)
|
||||
|
||||
// Normal TX (non-SLP)
|
||||
assert.equal(data[1].tx_hash, utxos[1].tx_hash)
|
||||
assert.equal(data[1].isValid, false)
|
||||
|
||||
// Valid PSF SLP tx
|
||||
assert.equal(data[2].tx_hash, utxos[2].tx_hash)
|
||||
assert.equal(data[2].isValid, true)
|
||||
|
||||
// Valid SLP token not in whitelist
|
||||
assert.equal(data[3].tx_hash, utxos[3].tx_hash)
|
||||
assert.equal(data[3].isValid, true)
|
||||
|
||||
// Token send on BCHN network
|
||||
assert.equal(data[4].tx_hash, utxos[4].tx_hash)
|
||||
assert.equal(data[4].isValid, true)
|
||||
|
||||
// Token send on ABC network
|
||||
assert.equal(data[5].tx_hash, utxos[5].tx_hash)
|
||||
assert.equal(data[5].isValid, null)
|
||||
|
||||
// Known invalid SLP token send of PSF tokens
|
||||
assert.equal(data[6].tx_hash, utxos[6].tx_hash)
|
||||
assert.equal(data[6].isValid, false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#validateTxid3', () => {
|
||||
it('should invalidate a known invalid TXID', async () => {
|
||||
const txid =
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid3(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
|
||||
assert.property(result[0], 'txid')
|
||||
assert.equal(result[0].txid, txid)
|
||||
|
||||
assert.property(result[0], 'valid')
|
||||
assert.equal(result[0].valid, null)
|
||||
})
|
||||
|
||||
it('should validate a known valid TXID', async () => {
|
||||
const txid =
|
||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd'
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid3(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
|
||||
assert.property(result[0], 'txid')
|
||||
assert.equal(result[0].txid, txid)
|
||||
|
||||
assert.property(result[0], 'valid')
|
||||
assert.equal(result[0].valid, true)
|
||||
})
|
||||
|
||||
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
|
||||
const txids = [
|
||||
// Malformed SLP tx
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
||||
// Normal TX (non-SLP)
|
||||
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
||||
// Valid PSF SLP tx
|
||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
||||
// Valid SLP token not in whitelist
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
||||
// Unprocessed SLP TX
|
||||
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019'
|
||||
]
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid3(txids)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
|
||||
assert.equal(result[0].txid, txids[0])
|
||||
assert.equal(result[0].valid, null)
|
||||
|
||||
assert.equal(result[1].txid, txids[1])
|
||||
assert.equal(result[1].valid, null)
|
||||
|
||||
assert.equal(result[2].txid, txids[2])
|
||||
assert.equal(result[2].valid, true)
|
||||
|
||||
// True in validateTxid() but null in validateTxid3()
|
||||
assert.equal(result[3].txid, txids[3])
|
||||
assert.equal(result[3].valid, null)
|
||||
|
||||
// Note: This should change from null to true once SLPDB finishes indexing.
|
||||
assert.equal(result[4].txid, txids[4])
|
||||
assert.equal(result[4].valid, null)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#validateTxid', () => {
|
||||
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
|
||||
const txids = [
|
||||
// Malformed SLP tx
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
||||
// Normal TX (non-SLP)
|
||||
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
||||
// Valid PSF SLP tx
|
||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
||||
// Valid SLP token not in whitelist
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
||||
// Token send on BCHN network.
|
||||
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
|
||||
// Token send on ABC network.
|
||||
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d'
|
||||
]
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid(txids)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
|
||||
assert.equal(result[0].txid, txids[0])
|
||||
assert.equal(result[0].valid, null)
|
||||
|
||||
assert.equal(result[1].txid, txids[1])
|
||||
assert.equal(result[1].valid, null)
|
||||
|
||||
assert.equal(result[2].txid, txids[2])
|
||||
assert.equal(result[2].valid, true)
|
||||
|
||||
// True in validateTxid() but null in validateTxid3()
|
||||
assert.equal(result[3].txid, txids[3])
|
||||
assert.equal(result[3].valid, true)
|
||||
|
||||
assert.equal(result[4].txid, txids[4])
|
||||
assert.equal(result[4].valid, true)
|
||||
|
||||
assert.equal(result[5].txid, txids[5])
|
||||
assert.equal(result[5].valid, null)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Promise-based sleep function
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
+73
-73
@@ -7,116 +7,116 @@
|
||||
of an e2e test to be properly tested.
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: "https://testnet3.fullstack.cash/v3/"
|
||||
: 'https://testnet3.fullstack.cash/v4/'
|
||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 3
|
||||
}
|
||||
|
||||
describe("#blockchain", () => {
|
||||
describe('#blockchain', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
describe("#getBestBlockHash", () => {
|
||||
it("should GET best block hash", async () => {
|
||||
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")
|
||||
assert.equal(result.length, 64, 'Specific hash length')
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getBlockHeader", () => {
|
||||
it("should GET block header for a single hash", async () => {
|
||||
describe('#getBlockHeader', () => {
|
||||
it('should GET block header for a single hash', async () => {
|
||||
const hash =
|
||||
"000000000000c57178ace90210289e6b5383134c5b5306e1cdd8395176e10aaf"
|
||||
'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"
|
||||
'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 () => {
|
||||
it('should GET block headers for an array of hashes', async () => {
|
||||
const hash = [
|
||||
"000000000000c57178ace90210289e6b5383134c5b5306e1cdd8395176e10aaf",
|
||||
"00000000000b7db4cbae48d852fcbef32f728014582094ad613fe12af6600ff2"
|
||||
'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"
|
||||
'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 () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) {
|
||||
data.push(
|
||||
"00000000000b7db4cbae48d852fcbef32f728014582094ad613fe12af6600ff2"
|
||||
'00000000000b7db4cbae48d852fcbef32f728014582094ad613fe12af6600ff2'
|
||||
)
|
||||
}
|
||||
|
||||
await bchjs.Blockchain.getBlockHeader(data)
|
||||
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getMempoolEntry", () => {
|
||||
describe('#getMempoolEntry', () => {
|
||||
/*
|
||||
// To run this test, the txid must be unconfirmed.
|
||||
const txid =
|
||||
@@ -168,26 +168,26 @@ describe("#blockchain", () => {
|
||||
})
|
||||
*/
|
||||
|
||||
it("should throw an error if txid is not in mempool", async () => {
|
||||
it('should throw an error if txid is not in mempool', async () => {
|
||||
try {
|
||||
const txid =
|
||||
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
|
||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
|
||||
|
||||
await bchjs.Blockchain.getMempoolEntry(txid)
|
||||
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
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")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Transaction not in mempool')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getTxOutProof", () => {
|
||||
it("should get single tx out proof", async () => {
|
||||
describe('#getTxOutProof', () => {
|
||||
it('should get single tx out proof', async () => {
|
||||
const txid =
|
||||
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
|
||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
|
||||
|
||||
const result = await bchjs.Blockchain.getTxOutProof(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
@@ -195,10 +195,10 @@ describe("#blockchain", () => {
|
||||
assert.isString(result)
|
||||
})
|
||||
|
||||
it("should get an array of tx out proofs", async () => {
|
||||
it('should get an array of tx out proofs', async () => {
|
||||
const txid = [
|
||||
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04",
|
||||
"fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752"
|
||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04',
|
||||
'fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752'
|
||||
]
|
||||
|
||||
const result = await bchjs.Blockchain.getTxOutProof(txid)
|
||||
@@ -209,11 +209,11 @@ describe("#blockchain", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#verifyTxOutProof", () => {
|
||||
describe('#verifyTxOutProof', () => {
|
||||
const mockTxOutProof =
|
||||
"00000020ac86ce8f2bda235c0dc135d18f6a777c44b121e8f41db8a51ca65000000000000cd4de3c49337712f3a1092c47c3bf73ec2f9b1cfd289ee991ede0b6eab4df229d5b8c5dffff001d82ce005b0700000003ec55d9142eac2c1d2229e5af24898b2590c111b62e2787fa1998d3d713fd432fd557124ed758fa156a6cdc6d317d5575aec2b86dfb159c62ecb4743f28bef1cb52e7a32fbec31e367ec152fdb952f75ee75bd8575f97b394093dbb0e6c694ffc0135"
|
||||
'00000020ac86ce8f2bda235c0dc135d18f6a777c44b121e8f41db8a51ca65000000000000cd4de3c49337712f3a1092c47c3bf73ec2f9b1cfd289ee991ede0b6eab4df229d5b8c5dffff001d82ce005b0700000003ec55d9142eac2c1d2229e5af24898b2590c111b62e2787fa1998d3d713fd432fd557124ed758fa156a6cdc6d317d5575aec2b86dfb159c62ecb4743f28bef1cb52e7a32fbec31e367ec152fdb952f75ee75bd8575f97b394093dbb0e6c694ffc0135'
|
||||
|
||||
it("should verify a single proof", async () => {
|
||||
it('should verify a single proof', async () => {
|
||||
const result = await bchjs.Blockchain.verifyTxOutProof(mockTxOutProof)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
@@ -221,11 +221,11 @@ describe("#blockchain", () => {
|
||||
assert.isString(result[0])
|
||||
assert.equal(
|
||||
result[0],
|
||||
"fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752"
|
||||
'fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752'
|
||||
)
|
||||
})
|
||||
|
||||
it("should verify an array of proofs", async () => {
|
||||
it('should verify an array of proofs', async () => {
|
||||
const proofs = [mockTxOutProof, mockTxOutProof]
|
||||
const result = await bchjs.Blockchain.verifyTxOutProof(proofs)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
@@ -234,11 +234,11 @@ describe("#blockchain", () => {
|
||||
assert.isString(result[0])
|
||||
assert.equal(
|
||||
result[0],
|
||||
"fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752"
|
||||
'fc4f696c0ebb3d0994b3975f57d85be75ef752b9fd52c17e361ec3be2fa3e752'
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw error on array size rate limit", async () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) data.push(mockTxOutProof)
|
||||
@@ -246,15 +246,15 @@ describe("#blockchain", () => {
|
||||
const result = await bchjs.Blockchain.verifyTxOutProof(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -2,31 +2,31 @@
|
||||
Integration tests for bchjs control library.
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: `https://testnet3.fullstack.cash/v3/`
|
||||
: 'https://testnet3.fullstack.cash/v4/'
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
|
||||
describe(`#control`, () => {
|
||||
describe('#control', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
describe(`#getNetworkInfo`, () => {
|
||||
it("should get info on the full node", async () => {
|
||||
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")
|
||||
assert.property(result, 'version')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
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/v4/'
|
||||
|
||||
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(1000)
|
||||
})
|
||||
|
||||
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,
|
||||
'the transaction was rejected by network rules'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const sinon = require('sinon')
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS({ ninsightURL: 'https://trest.bitcoin.com/v2' })
|
||||
|
||||
describe('#Ninsight', () => {
|
||||
let sandbox
|
||||
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#utxo', () => {
|
||||
it('should GET utxos for a single address', async () => {
|
||||
const addr = 'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr'
|
||||
|
||||
const result = await bchjs.Ninsight.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result[0], 'utxos')
|
||||
assert.property(result[0], 'legacyAddress')
|
||||
assert.property(result[0], 'cashAddress')
|
||||
assert.property(result[0], 'slpAddress')
|
||||
assert.property(result[0], 'scriptPubKey')
|
||||
assert.property(result[0], 'asm')
|
||||
|
||||
assert.isArray(result[0].utxos)
|
||||
|
||||
assert.property(result[0].utxos[0], 'txid')
|
||||
assert.property(result[0].utxos[0], 'vout')
|
||||
assert.property(result[0].utxos[0], 'amount')
|
||||
assert.property(result[0].utxos[0], 'satoshis')
|
||||
assert.property(result[0].utxos[0], 'height')
|
||||
assert.property(result[0].utxos[0], 'confirmations')
|
||||
})
|
||||
|
||||
it('should POST utxo details for an array of addresses', async () => {
|
||||
const addr = [
|
||||
'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr',
|
||||
'bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul'
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isArray(result[0].utxos)
|
||||
|
||||
assert.property(result[0], 'utxos')
|
||||
assert.property(result[0], 'legacyAddress')
|
||||
assert.property(result[0], 'cashAddress')
|
||||
assert.property(result[0], 'slpAddress')
|
||||
assert.property(result[0], 'scriptPubKey')
|
||||
assert.property(result[0], 'asm')
|
||||
|
||||
// assert.hasAnyKeys(result[0][0], [
|
||||
// "txid",
|
||||
// "vout",
|
||||
// "value",
|
||||
// "height",
|
||||
// "confirmations"
|
||||
// ])
|
||||
})
|
||||
})
|
||||
describe('#transactions', () => {
|
||||
it('should POST transactions history for a single address', async () => {
|
||||
const addr = 'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr'
|
||||
|
||||
const result = await bchjs.Ninsight.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'cashAddress')
|
||||
assert.property(result[0], 'legacyAddress')
|
||||
assert.property(result[0], 'txs')
|
||||
assert.isArray(result[0].txs)
|
||||
assert.property(result[0].txs[0], 'txid')
|
||||
assert.property(result[0].txs[0], 'vin')
|
||||
assert.property(result[0].txs[0], 'vout')
|
||||
})
|
||||
it('should POST transactions history for an array of addresses', async () => {
|
||||
const addr = [
|
||||
'bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr',
|
||||
'bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul'
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'cashAddress')
|
||||
assert.property(result[0], 'legacyAddress')
|
||||
assert.property(result[0], 'txs')
|
||||
assert.isArray(result[0].txs)
|
||||
assert.property(result[0].txs[0], 'txid')
|
||||
assert.property(result[0].txs[0], 'vin')
|
||||
assert.property(result[0].txs[0], 'vout')
|
||||
})
|
||||
})
|
||||
describe('#txDetails', () => {
|
||||
it('should POST transactions details for a single address', async () => {
|
||||
const txid =
|
||||
'76856d82e00b2696acd8d989e1fa6c46b431005046a285ce905814cac0ff8fea'
|
||||
|
||||
const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'txid')
|
||||
assert.property(result[0], 'version')
|
||||
assert.property(result[0], 'locktime')
|
||||
assert.property(result[0], 'vin')
|
||||
assert.property(result[0], 'vout')
|
||||
assert.property(result[0], 'blockhash')
|
||||
assert.property(result[0], 'blockheight')
|
||||
assert.property(result[0], 'confirmations')
|
||||
assert.property(result[0], 'time')
|
||||
assert.property(result[0], 'blocktime')
|
||||
assert.property(result[0], 'valueOut')
|
||||
assert.property(result[0], 'size')
|
||||
})
|
||||
it('should POST transactions details for an array of addresses', async () => {
|
||||
const txid = [
|
||||
'f191d1062789d7071da6f2168ba306869a829294f6b1c09d03492db4ca3a8e77',
|
||||
'76856d82e00b2696acd8d989e1fa6c46b431005046a285ce905814cac0ff8fea'
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'txid')
|
||||
assert.property(result[0], 'vin')
|
||||
assert.property(result[0], 'vout')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
+101
-101
@@ -5,143 +5,143 @@
|
||||
TODO
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: `https://testnet3.fullstack.cash/v3/`
|
||||
: 'https://testnet3.fullstack.cash/v4/'
|
||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 3
|
||||
}
|
||||
|
||||
describe("#rawtransaction", () => {
|
||||
describe('#rawtransaction', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
describe("#decodeRawTransaction", () => {
|
||||
it("should decode tx for a single hex", async () => {
|
||||
describe('#decodeRawTransaction', () => {
|
||||
it('should decode tx for a single hex', async () => {
|
||||
const hex =
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000'
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeRawTransaction(hex)
|
||||
//console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout"
|
||||
'txid',
|
||||
'hash',
|
||||
'size',
|
||||
'version',
|
||||
'locktime',
|
||||
'vin',
|
||||
'vout'
|
||||
])
|
||||
assert.isArray(result.vin)
|
||||
assert.isArray(result.vout)
|
||||
})
|
||||
|
||||
it("should decode an array of tx hexes", async () => {
|
||||
it('should decode an array of tx hexes', async () => {
|
||||
const hexes = [
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000",
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000',
|
||||
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000'
|
||||
]
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeRawTransaction(hexes)
|
||||
//console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout"
|
||||
'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 () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) {
|
||||
data.push(
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000'
|
||||
)
|
||||
}
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeRawTransaction(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getRawTransaction", () => {
|
||||
it("should decode a single txid, with concise output", async () => {
|
||||
describe('#getRawTransaction', () => {
|
||||
it('should decode a single txid, with 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)}`)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isString(result)
|
||||
})
|
||||
|
||||
it("should decode a single txid, with verbose output", async () => {
|
||||
it('should decode a single txid, with 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)}`)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"hex",
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"confirmations",
|
||||
"time",
|
||||
"blocktime"
|
||||
'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 () => {
|
||||
it('should decode an array of txids, with a concise output', async () => {
|
||||
const txid = [
|
||||
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04",
|
||||
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
|
||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04',
|
||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
|
||||
]
|
||||
const verbose = false
|
||||
|
||||
@@ -149,16 +149,16 @@ describe("#rawtransaction", () => {
|
||||
txid,
|
||||
verbose
|
||||
)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// 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 () => {
|
||||
it('should decode an array of txids, with a verbose output', async () => {
|
||||
const txid = [
|
||||
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04",
|
||||
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
|
||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04',
|
||||
'1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04'
|
||||
]
|
||||
const verbose = true
|
||||
|
||||
@@ -166,54 +166,54 @@ describe("#rawtransaction", () => {
|
||||
txid,
|
||||
verbose
|
||||
)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// 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"
|
||||
'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 () => {
|
||||
it('should throw error on array size limit', async () => {
|
||||
try {
|
||||
const dataMock =
|
||||
"1f121fb6a33f48cd426dde06aa20ce589dd97becabb835a8d33071cbf40c7d04"
|
||||
'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!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#decodeScript", () => {
|
||||
it("should decode script for a single hex", async () => {
|
||||
describe('#decodeScript', () => {
|
||||
it('should decode script for a single hex', async () => {
|
||||
const hex =
|
||||
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
|
||||
'4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16'
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeScript(hex)
|
||||
//console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["asm", "type", "p2sh"])
|
||||
assert.hasAllKeys(result, ['asm', 'type', 'p2sh'])
|
||||
})
|
||||
|
||||
// CT 2/20/19 - Waiting for this PR to be merged complete the test:
|
||||
@@ -237,29 +237,29 @@ describe("#rawtransaction", () => {
|
||||
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 () => {
|
||||
describe('sendRawTransaction', () => {
|
||||
it('should send a single transaction hex', async () => {
|
||||
try {
|
||||
const hex =
|
||||
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
|
||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
||||
|
||||
await bchjs.RawTransactions.sendRawTransaction(hex)
|
||||
//console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
//console.log(`err: ${util.inspect(err)}`)
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
|
||||
assert.hasAllKeys(err, ["error"])
|
||||
assert.include(err.error, "bad-txns-inputs-missingorspent (code 16)")
|
||||
assert.hasAllKeys(err, ['error'])
|
||||
assert.include(err.error, 'Missing inputs')
|
||||
}
|
||||
})
|
||||
|
||||
it("should send an array of tx hexes", async () => {
|
||||
it('should send an array of tx hexes', async () => {
|
||||
try {
|
||||
const hexes = [
|
||||
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000",
|
||||
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
|
||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
|
||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
||||
]
|
||||
|
||||
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
|
||||
@@ -267,30 +267,30 @@ describe("#rawtransaction", () => {
|
||||
} catch (err) {
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
|
||||
assert.hasAllKeys(err, ["error"])
|
||||
assert.include(err.error, "bad-txns-inputs-missingorspent (code 16)")
|
||||
assert.hasAllKeys(err, ['error'])
|
||||
assert.include(err.error, 'Missing inputs')
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const dataMock =
|
||||
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
|
||||
'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!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -2,132 +2,119 @@
|
||||
Integration tests for the bchjs covering SLP tokens.
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: `https://testnet3.fullstack.cash/v3/`
|
||||
: 'https://testnet3.fullstack.cash/v4/'
|
||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 1
|
||||
}
|
||||
|
||||
describe(`#SLP`, () => {
|
||||
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(1000)
|
||||
})
|
||||
|
||||
describe("#util", () => {
|
||||
it(`should get information on the Oasis token`, async () => {
|
||||
const tokenId = `a371e9934c7695d08a5eb7f31d3bceb4f3644860cc67520cda1e149423b9ec39`
|
||||
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)}`)
|
||||
// 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"
|
||||
'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 () => {
|
||||
describe('#decodeOpReturn', () => {
|
||||
it('should decode the OP_RETURN for a SEND txid', async () => {
|
||||
const txid =
|
||||
"ad28116e0818339342dddfc5f58ca8a5379ceb9679b4e4cbd72f4de905415ec1"
|
||||
'ad28116e0818339342dddfc5f58ca8a5379ceb9679b4e4cbd72f4de905415ec1'
|
||||
|
||||
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["amounts", "tokenType", "tokenId", "txType"])
|
||||
assert.hasAllKeys(result, ['amounts', 'tokenType', 'tokenId', 'txType'])
|
||||
})
|
||||
})
|
||||
|
||||
describe("#balancesForAddress", () => {
|
||||
it(`should fetch all balances for address: slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9`, async () => {
|
||||
// Mock the call to rest.bitcoin.com
|
||||
if (process.env.TEST === "unit") {
|
||||
sandbox
|
||||
.stub(axios, "get")
|
||||
.resolves({ data: mockData.balancesForAddress })
|
||||
}
|
||||
|
||||
describe('#balancesForAddress', () => {
|
||||
it('should fetch all balances for address: slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9', async () => {
|
||||
const balances = await bchjs.SLP.Utils.balancesForAddress(
|
||||
"slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9"
|
||||
'slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9'
|
||||
)
|
||||
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
|
||||
|
||||
assert.isArray(balances)
|
||||
assert.hasAllKeys(balances[0], [
|
||||
"tokenId",
|
||||
"balanceString",
|
||||
"balance",
|
||||
"decimalCount",
|
||||
"slpAddress"
|
||||
'tokenId',
|
||||
'balanceString',
|
||||
'balance',
|
||||
'decimalCount',
|
||||
'slpAddress'
|
||||
])
|
||||
})
|
||||
|
||||
it(`should fetch balances for multiple addresses`, async () => {
|
||||
it('should fetch balances for multiple addresses', async () => {
|
||||
const addresses = [
|
||||
"slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9",
|
||||
"slptest:qr5uy4h8ysyhwkp9s245scckdnc7teyjqc5ft2z43h"
|
||||
'slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9',
|
||||
'slptest:qr5uy4h8ysyhwkp9s245scckdnc7teyjqc5ft2z43h'
|
||||
]
|
||||
|
||||
// Mock the call to rest.bitcoin.com
|
||||
if (process.env.TEST === "unit") {
|
||||
sandbox
|
||||
.stub(axios, "post")
|
||||
.resolves({ data: mockData.balancesForAddresses })
|
||||
}
|
||||
|
||||
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"
|
||||
'tokenId',
|
||||
'balanceString',
|
||||
'balance',
|
||||
'decimalCount',
|
||||
'slpAddress'
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("#tokenUtxoDetails", () => {
|
||||
it("should hydrate UTXOs", async () => {
|
||||
describe('#tokenUtxoDetails', () => {
|
||||
it('should hydrate UTXOs', async () => {
|
||||
const bchAddr = bchjs.SLP.Address.toCashAddress(
|
||||
"slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9"
|
||||
'slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9'
|
||||
)
|
||||
|
||||
const utxos = await bchjs.Electrumx.utxo([bchAddr])
|
||||
@@ -145,12 +132,12 @@ describe(`#SLP`, () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#hydrateUtxos", () => {
|
||||
describe('#hydrateUtxos', () => {
|
||||
// This test will error out if the LOCAL_RESTURL settings is not set properly
|
||||
// in bch-api.
|
||||
it("should hydrate UTXOs", async () => {
|
||||
it('should hydrate UTXOs', async () => {
|
||||
const bchAddr = bchjs.SLP.Address.toCashAddress(
|
||||
"slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9"
|
||||
'slptest:qz0kc67pm4emjyr3gaaa2wstdaykg9m4yqwlzpj3w9'
|
||||
)
|
||||
|
||||
const utxos = await bchjs.Electrumx.utxo([bchAddr])
|
||||
@@ -166,10 +153,10 @@ describe(`#SLP`, () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#validateTxid2", () => {
|
||||
it("should validate a token txid", async () => {
|
||||
describe('#validateTxid2', () => {
|
||||
it('should validate a token txid', async () => {
|
||||
const txid =
|
||||
"ad28116e0818339342dddfc5f58ca8a5379ceb9679b4e4cbd72f4de905415ec1"
|
||||
'ad28116e0818339342dddfc5f58ca8a5379ceb9679b4e4cbd72f4de905415ec1'
|
||||
|
||||
const validated = await bchjs.SLP.Utils.validateTxid(txid)
|
||||
// console.log(validated)
|
||||
@@ -180,6 +167,6 @@ describe(`#SLP`, () => {
|
||||
})
|
||||
|
||||
// Promise-based sleep function
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
export RESTURL=https://free-test.fullstack.cash/v3/
|
||||
export RESTURL=https://free-test.fullstack.cash/v4/
|
||||
export NETWORK=testnet
|
||||
export IS_USING_FREE_TIER=true
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
Integration tests for the bchjs. Only covers calls made to
|
||||
rest.bitcoin.com.
|
||||
*/
|
||||
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: 'https://testnet3.fullstack.cash/v4/'
|
||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
|
||||
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(1000)
|
||||
})
|
||||
|
||||
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,26 +2,26 @@
|
||||
Integration tests for bchjs control library.
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe(`#control`, () => {
|
||||
describe('#control', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
describe(`#getNetworkInfo`, () => {
|
||||
it("should get info on the full node", async () => {
|
||||
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")
|
||||
assert.property(result, 'version')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
+129
-128
@@ -1,11 +1,11 @@
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const sinon = require("sinon")
|
||||
const sinon = require('sinon')
|
||||
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe(`#ElectrumX`, () => {
|
||||
describe('#ElectrumX', () => {
|
||||
let sandbox
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -16,176 +16,178 @@ describe(`#ElectrumX`, () => {
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe(`#utxo`, () => {
|
||||
it(`should GET utxos for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
describe('#utxo', () => {
|
||||
it('should GET utxos for a single address', async () => {
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.Electrumx.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "utxos")
|
||||
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")
|
||||
assert.property(result.utxos[0], 'height')
|
||||
assert.property(result.utxos[0], 'tx_hash')
|
||||
assert.property(result.utxos[0], 'tx_pos')
|
||||
assert.property(result.utxos[0], 'value')
|
||||
})
|
||||
|
||||
it(`should POST request for UTXOs for an array of addresses`, async () => {
|
||||
it('should POST request for UTXOs for an array of addresses', async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
|
||||
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "utxos")
|
||||
assert.property(result, 'utxos')
|
||||
assert.isArray(result.utxos)
|
||||
|
||||
assert.property(result.utxos[0], "utxos")
|
||||
assert.property(result.utxos[0], 'utxos')
|
||||
assert.isArray(result.utxos[0].utxos)
|
||||
assert.property(result.utxos[0], "address")
|
||||
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")
|
||||
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 () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
|
||||
for (let i = 0; i < 25; i++) { addr.push('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf') }
|
||||
|
||||
const result = await bchjs.Electrumx.utxo(addr)
|
||||
// const result = await bchjs.Electrumx.utxo(addr)
|
||||
await bchjs.Electrumx.utxo(addr)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
// 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")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#balance`, () => {
|
||||
it(`should GET balance for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
describe('#balance', () => {
|
||||
it('should GET balance for a single address', async () => {
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.Electrumx.balance(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "balance")
|
||||
assert.property(result.balance, "confirmed")
|
||||
assert.property(result.balance, "unconfirmed")
|
||||
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 () => {
|
||||
it('should POST request for balances for an array of addresses', async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
|
||||
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.balance(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "balances")
|
||||
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")
|
||||
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 () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
|
||||
for (let i = 0; i < 25; i++) { addr.push('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf') }
|
||||
|
||||
const result = await bchjs.Electrumx.balance(addr)
|
||||
// const result = await bchjs.Electrumx.balance(addr)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
await bchjs.Electrumx.balance(addr)
|
||||
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#transactions`, () => {
|
||||
it(`should GET transaction history for a single address`, async () => {
|
||||
const addr = "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
describe('#transactions', () => {
|
||||
it('should GET transaction history for a single address', async () => {
|
||||
const addr = 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
||||
|
||||
const result = await bchjs.Electrumx.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "transactions")
|
||||
assert.property(result, 'transactions')
|
||||
assert.isArray(result.transactions)
|
||||
assert.property(result.transactions[0], "height")
|
||||
assert.property(result.transactions[0], "tx_hash")
|
||||
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 () => {
|
||||
it('should POST request for transaction history for an array of addresses', async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
'bitcoincash:qrl2nlsaayk6ekxn80pq0ks32dya8xfclyktem2mqj',
|
||||
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "transactions")
|
||||
assert.property(result, 'transactions')
|
||||
assert.isArray(result.transactions)
|
||||
|
||||
assert.property(result.transactions[0], "address")
|
||||
assert.property(result.transactions[0], "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")
|
||||
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 () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0")
|
||||
for (let i = 0; i < 25; i++) { addr.push('bitcoincash:qrehqueqhw629p6e57994436w730t4rzasnly00ht0') }
|
||||
|
||||
const result = await bchjs.Electrumx.transactions(addr)
|
||||
// const result = await bchjs.Electrumx.transactions(addr)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
await bchjs.Electrumx.transactions(addr)
|
||||
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#unconfirmed`, () => {
|
||||
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 () => {
|
||||
@@ -230,137 +232,136 @@ describe(`#ElectrumX`, () => {
|
||||
})
|
||||
*/
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
|
||||
for (let i = 0; i < 25; i++) { addr.push('bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf') }
|
||||
|
||||
await bchjs.Electrumx.unconfirmed(addr)
|
||||
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#blockHeader`, () => {
|
||||
it(`should GET block headers for given height and count`, async () => {
|
||||
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.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "headers")
|
||||
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 () => {
|
||||
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.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "headers")
|
||||
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 () => {
|
||||
describe('#txData', () => {
|
||||
it('should GET details for a single transaction', async () => {
|
||||
const txid =
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
|
||||
|
||||
const result = await bchjs.Electrumx.txData(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "details")
|
||||
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.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 () => {
|
||||
it('should POST details for an array of transactions', async () => {
|
||||
const txids = [
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251',
|
||||
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.txData(txids)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "transactions")
|
||||
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], '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")
|
||||
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 () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const txids = []
|
||||
for (let i = 0; i < 25; i++) {
|
||||
txids.push(
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
|
||||
)
|
||||
}
|
||||
|
||||
await bchjs.Electrumx.txData(txids)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
// 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")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#broadcast`, () => {
|
||||
it(`should broadcast a single transaction`, async () => {
|
||||
describe('#broadcast', () => {
|
||||
it('should broadcast a single transaction', async () => {
|
||||
const txHex =
|
||||
"020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000"
|
||||
'020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000'
|
||||
|
||||
try {
|
||||
await bchjs.Electrumx.broadcast(txHex)
|
||||
} catch (err) {
|
||||
assert.property(err, "success")
|
||||
assert.property(err, 'success')
|
||||
assert.equal(err.success, false)
|
||||
assert.include(
|
||||
err.error,
|
||||
"the transaction was rejected by network rules"
|
||||
'the transaction was rejected by network rules'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
const assert = require("chai").assert
|
||||
const assert = require('chai').assert
|
||||
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe("#Encryption", () => {
|
||||
describe('#Encryption', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
describe("#getPubKey", () => {
|
||||
it("should get a public key", async () => {
|
||||
const addr = "bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq"
|
||||
describe('#getPubKey', () => {
|
||||
it('should get a public key', async () => {
|
||||
const addr = 'bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq'
|
||||
|
||||
const result = await bchjs.encryption.getPubKey(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
assert.property(result, "publicKey")
|
||||
assert.property(result, 'publicKey')
|
||||
})
|
||||
|
||||
it("should report when public key can not be found", async () => {
|
||||
const addr = "bitcoincash:qrgqqkky28jdkv3w0ctrah0mz3jcsnsklc34gtukrh"
|
||||
it('should report when public key can not be found', async () => {
|
||||
const addr = 'bitcoincash:qrgqqkky28jdkv3w0ctrah0mz3jcsnsklc34gtukrh'
|
||||
|
||||
const result = await bchjs.encryption.getPubKey(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, false)
|
||||
assert.property(result, "publicKey")
|
||||
assert.equal(result.publicKey, "not found")
|
||||
assert.property(result, 'publicKey')
|
||||
assert.equal(result.publicKey, 'not found')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Integration tests for the bchjs. Only covers calls made to
|
||||
rest.bitcoin.com.
|
||||
|
||||
TODO
|
||||
*/
|
||||
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 3
|
||||
}
|
||||
|
||||
describe('#rawtransaction', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
/*
|
||||
Testing sentRawTransaction isn't really possible with an integration test,
|
||||
as the endpoint really needs an e2e test to be properly tested. The tests
|
||||
below expect error messages returned from the server, but at least test
|
||||
that the server is responding on those endpoints, and responds consistently.
|
||||
*/
|
||||
describe('sendRawTransaction', () => {
|
||||
it('should send a single transaction hex', async () => {
|
||||
try {
|
||||
const hex =
|
||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
||||
|
||||
await bchjs.RawTransactions.sendRawTransaction(hex)
|
||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
|
||||
assert.hasAllKeys(err, ['error'])
|
||||
assert.include(err.error, 'Missing inputs')
|
||||
}
|
||||
})
|
||||
|
||||
it('should send an array of tx hexes', async () => {
|
||||
try {
|
||||
const hexes = [
|
||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000',
|
||||
'01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000'
|
||||
]
|
||||
|
||||
const result = await bchjs.RawTransactions.sendRawTransaction(hexes)
|
||||
console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
} catch (err) {
|
||||
// console.log(`err: ${util.inspect(err)}`)
|
||||
|
||||
assert.hasAllKeys(err, ['error'])
|
||||
assert.include(err.error, 'Missing inputs')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
Integration tests for the bchjs covering SLP tokens.
|
||||
These tests are specific to the ABC chain.
|
||||
*/
|
||||
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
let bchjs
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 1
|
||||
}
|
||||
|
||||
describe('#SLP', () => {
|
||||
// before(() => {
|
||||
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
|
||||
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
|
||||
// })
|
||||
|
||||
beforeEach(async () => {
|
||||
// Introduce a delay so that the BVT doesn't trip the rate limits.
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
|
||||
describe('#util', () => {
|
||||
describe('#tokenUtxoDetails', () => {
|
||||
it('should handle a range of UTXO types', async () => {
|
||||
const utxos = [
|
||||
// Malformed SLP tx
|
||||
{
|
||||
note: 'Malformed SLP tx',
|
||||
tx_hash:
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Normal TX (non-SLP)
|
||||
{
|
||||
note: 'Normal TX (non-SLP)',
|
||||
tx_hash:
|
||||
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
||||
tx_pos: 0,
|
||||
value: 400000
|
||||
},
|
||||
// Valid PSF SLP tx
|
||||
{
|
||||
note: 'Valid PSF SLP tx',
|
||||
tx_hash:
|
||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Valid SLP token not in whitelist
|
||||
{
|
||||
note: 'Valid SLP token not in whitelist',
|
||||
tx_hash:
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Token send on BCHN network.
|
||||
{
|
||||
note: 'Token send on BCHN network',
|
||||
tx_hash:
|
||||
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Token send on ABC network.
|
||||
{
|
||||
note: 'Token send on ABC network',
|
||||
tx_hash:
|
||||
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
// Known invalid SLP token send of PSF tokens.
|
||||
{
|
||||
note: 'Known invalid SLP token send of PSF tokens',
|
||||
tx_hash:
|
||||
'2bf691ad3679d928fef880b8a45b93b233f8fa0d0a92cf792313dbe77b1deb74',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
}
|
||||
]
|
||||
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
// Malformed SLP tx
|
||||
assert.equal(data[0].tx_hash, utxos[0].tx_hash)
|
||||
assert.equal(data[0].isValid, false)
|
||||
|
||||
// Normal TX (non-SLP)
|
||||
assert.equal(data[1].tx_hash, utxos[1].tx_hash)
|
||||
assert.equal(data[1].isValid, false)
|
||||
|
||||
// Valid PSF SLP tx
|
||||
assert.equal(data[2].tx_hash, utxos[2].tx_hash)
|
||||
assert.equal(data[2].isValid, true)
|
||||
|
||||
// Valid SLP token not in whitelist
|
||||
assert.equal(data[3].tx_hash, utxos[3].tx_hash)
|
||||
assert.equal(data[3].isValid, true)
|
||||
|
||||
// Token send on BCHN network
|
||||
assert.equal(data[4].tx_hash, utxos[4].tx_hash)
|
||||
assert.equal(data[4].isValid, true)
|
||||
|
||||
// Token send on ABC network
|
||||
assert.equal(data[5].tx_hash, utxos[5].tx_hash)
|
||||
assert.equal(data[5].isValid, null)
|
||||
|
||||
// Known invalid SLP token send of PSF tokens
|
||||
assert.equal(data[6].tx_hash, utxos[6].tx_hash)
|
||||
assert.equal(data[6].isValid, false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#validateTxid3', () => {
|
||||
it('should invalidate a known invalid TXID', async () => {
|
||||
const txid =
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid3(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
|
||||
assert.property(result[0], 'txid')
|
||||
assert.equal(result[0].txid, txid)
|
||||
|
||||
assert.property(result[0], 'valid')
|
||||
assert.equal(result[0].valid, null)
|
||||
})
|
||||
|
||||
it('should validate a known valid TXID', async () => {
|
||||
const txid =
|
||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd'
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid3(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
|
||||
assert.property(result[0], 'txid')
|
||||
assert.equal(result[0].txid, txid)
|
||||
|
||||
assert.property(result[0], 'valid')
|
||||
assert.equal(result[0].valid, true)
|
||||
})
|
||||
|
||||
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
|
||||
const txids = [
|
||||
// Malformed SLP tx
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
||||
// Normal TX (non-SLP)
|
||||
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
||||
// Valid PSF SLP tx
|
||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
||||
// Valid SLP token not in whitelist
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
||||
// Unprocessed SLP TX
|
||||
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019'
|
||||
]
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid3(txids)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
|
||||
assert.equal(result[0].txid, txids[0])
|
||||
assert.equal(result[0].valid, null)
|
||||
|
||||
assert.equal(result[1].txid, txids[1])
|
||||
assert.equal(result[1].valid, null)
|
||||
|
||||
assert.equal(result[2].txid, txids[2])
|
||||
assert.equal(result[2].valid, true)
|
||||
|
||||
// True in validateTxid()
|
||||
assert.equal(result[3].txid, txids[3])
|
||||
assert.equal(result[3].valid, true)
|
||||
|
||||
assert.equal(result[4].txid, txids[4])
|
||||
assert.equal(result[4].valid, true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#validateTxid', () => {
|
||||
it('should handle a mix of valid, invalid, and non-SLP txs', async () => {
|
||||
const txids = [
|
||||
// Malformed SLP tx
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
||||
// Normal TX (non-SLP)
|
||||
'01cdaec2f8b311fc2d6ecc930247bd45fa696dc204ab684596e281fe1b06c1f0',
|
||||
// Valid PSF SLP tx
|
||||
'daf4d8b8045e7a90b7af81bfe2370178f687da0e545511bce1c9ae539eba5ffd',
|
||||
// Valid SLP token not in whitelist
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
||||
// Token send on BCHN network.
|
||||
'402c663379d9699b6e2dd38737061e5888c5a49fca77c97ab98e79e08959e019',
|
||||
// Token send on ABC network.
|
||||
'336bfe2168aac4c3303508a9e8548a0d33797a83b85b76a12d845c8d6674f79d'
|
||||
]
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid(txids)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
|
||||
assert.equal(result[0].txid, txids[0])
|
||||
assert.equal(result[0].valid, null)
|
||||
|
||||
assert.equal(result[1].txid, txids[1])
|
||||
assert.equal(result[1].valid, null)
|
||||
|
||||
assert.equal(result[2].txid, txids[2])
|
||||
assert.equal(result[2].valid, true)
|
||||
|
||||
// True in validateTxid() but null in validateTxid3()
|
||||
assert.equal(result[3].txid, txids[3])
|
||||
assert.equal(result[3].valid, true)
|
||||
|
||||
assert.equal(result[4].txid, txids[4])
|
||||
assert.equal(result[4].valid, true)
|
||||
|
||||
assert.equal(result[5].txid, txids[5])
|
||||
assert.equal(result[5].valid, null)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Promise-based sleep function
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const sinon = require("sinon")
|
||||
const sinon = require('sinon')
|
||||
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const bchjs = new BCHJS({ ninsightURL: "https://rest.bitcoin.com/v2" })
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS({ ninsightURL: 'https://rest.bitcoin.com/v2' })
|
||||
|
||||
describe(`#Ninsight`, () => {
|
||||
describe('#Ninsight', () => {
|
||||
let sandbox
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -16,34 +16,34 @@ describe(`#Ninsight`, () => {
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe(`#utxo`, () => {
|
||||
it(`should GET utxos for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
describe('#utxo', () => {
|
||||
it('should GET utxos for a single address', async () => {
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.Ninsight.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result[0], "utxos")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "slpAddress")
|
||||
assert.property(result[0], "scriptPubKey")
|
||||
assert.property(result[0], "asm")
|
||||
assert.property(result[0], 'utxos')
|
||||
assert.property(result[0], 'legacyAddress')
|
||||
assert.property(result[0], 'cashAddress')
|
||||
assert.property(result[0], 'slpAddress')
|
||||
assert.property(result[0], 'scriptPubKey')
|
||||
assert.property(result[0], 'asm')
|
||||
|
||||
assert.isArray(result[0].utxos)
|
||||
|
||||
assert.property(result[0].utxos[0], "txid")
|
||||
assert.property(result[0].utxos[0], "vout")
|
||||
assert.property(result[0].utxos[0], "amount")
|
||||
assert.property(result[0].utxos[0], "satoshis")
|
||||
assert.property(result[0].utxos[0], "height")
|
||||
assert.property(result[0].utxos[0], "confirmations")
|
||||
assert.property(result[0].utxos[0], 'txid')
|
||||
assert.property(result[0].utxos[0], 'vout')
|
||||
assert.property(result[0].utxos[0], 'amount')
|
||||
assert.property(result[0].utxos[0], 'satoshis')
|
||||
assert.property(result[0].utxos[0], 'height')
|
||||
assert.property(result[0].utxos[0], 'confirmations')
|
||||
})
|
||||
|
||||
it(`should POST utxo details for an array of addresses`, async () => {
|
||||
it('should POST utxo details for an array of addresses', async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7",
|
||||
"bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr"
|
||||
'bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7',
|
||||
'bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr'
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.utxo(addr)
|
||||
@@ -52,87 +52,87 @@ describe(`#Ninsight`, () => {
|
||||
assert.isArray(result)
|
||||
assert.isArray(result[0].utxos)
|
||||
|
||||
assert.property(result[0], "utxos")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "slpAddress")
|
||||
assert.property(result[0], "scriptPubKey")
|
||||
assert.property(result[0], "asm")
|
||||
assert.property(result[0], 'utxos')
|
||||
assert.property(result[0], 'legacyAddress')
|
||||
assert.property(result[0], 'cashAddress')
|
||||
assert.property(result[0], 'slpAddress')
|
||||
assert.property(result[0], 'scriptPubKey')
|
||||
assert.property(result[0], 'asm')
|
||||
})
|
||||
})
|
||||
describe(`#transactions`, () => {
|
||||
it(`should POST transactions history for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
describe('#transactions', () => {
|
||||
it('should POST transactions history for a single address', async () => {
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.Ninsight.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "txs")
|
||||
assert.property(result[0], 'cashAddress')
|
||||
assert.property(result[0], 'legacyAddress')
|
||||
assert.property(result[0], 'txs')
|
||||
assert.isArray(result[0].txs)
|
||||
assert.property(result[0].txs[0], "txid")
|
||||
assert.property(result[0].txs[0], "vin")
|
||||
assert.property(result[0].txs[0], "vout")
|
||||
assert.property(result[0].txs[0], 'txid')
|
||||
assert.property(result[0].txs[0], 'vin')
|
||||
assert.property(result[0].txs[0], 'vout')
|
||||
})
|
||||
it(`should POST transactions history for an array of addresses`, async () => {
|
||||
it('should POST transactions history for an array of addresses', async () => {
|
||||
const addr = [
|
||||
"bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7",
|
||||
"bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr"
|
||||
'bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7',
|
||||
'bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr'
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "txs")
|
||||
assert.property(result[0], 'cashAddress')
|
||||
assert.property(result[0], 'legacyAddress')
|
||||
assert.property(result[0], 'txs')
|
||||
assert.isArray(result[0].txs)
|
||||
assert.property(result[0].txs[0], "txid")
|
||||
assert.property(result[0].txs[0], "vin")
|
||||
assert.property(result[0].txs[0], "vout")
|
||||
assert.property(result[0].txs[0], 'txid')
|
||||
assert.property(result[0].txs[0], 'vin')
|
||||
assert.property(result[0].txs[0], 'vout')
|
||||
})
|
||||
})
|
||||
describe(`#txDetails`, () => {
|
||||
it(`should POST transactions details for a single address`, async () => {
|
||||
const txid = "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"
|
||||
describe('#txDetails', () => {
|
||||
it('should POST transactions details for a single address', async () => {
|
||||
const txid = 'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33'
|
||||
|
||||
const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], "txid")
|
||||
assert.property(result[0], "version")
|
||||
assert.property(result[0], "locktime")
|
||||
assert.property(result[0], "vin")
|
||||
assert.property(result[0], "vout")
|
||||
assert.property(result[0], "blockhash")
|
||||
assert.property(result[0], "blockheight")
|
||||
assert.property(result[0], "confirmations")
|
||||
assert.property(result[0], "time")
|
||||
assert.property(result[0], "blocktime")
|
||||
assert.property(result[0], "valueOut")
|
||||
assert.property(result[0], "size")
|
||||
assert.property(result[0], 'txid')
|
||||
assert.property(result[0], 'version')
|
||||
assert.property(result[0], 'locktime')
|
||||
assert.property(result[0], 'vin')
|
||||
assert.property(result[0], 'vout')
|
||||
assert.property(result[0], 'blockhash')
|
||||
assert.property(result[0], 'blockheight')
|
||||
assert.property(result[0], 'confirmations')
|
||||
assert.property(result[0], 'time')
|
||||
assert.property(result[0], 'blocktime')
|
||||
assert.property(result[0], 'valueOut')
|
||||
assert.property(result[0], 'size')
|
||||
})
|
||||
it(`should POST transactions details for an array of addresses`, async () => {
|
||||
it('should POST transactions details for an array of addresses', async () => {
|
||||
const txid = [
|
||||
"fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33",
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33',
|
||||
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], "txid")
|
||||
assert.property(result[0], "vin")
|
||||
assert.property(result[0], "vout")
|
||||
assert.property(result[0], 'txid')
|
||||
assert.property(result[0], 'vin')
|
||||
assert.property(result[0], 'vout')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
@@ -2,81 +2,81 @@
|
||||
tests for OpenBazaar library.
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe(`#OpenBazaar`, () => {
|
||||
describe('#OpenBazaar', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
describe(`#Balance`, () => {
|
||||
it(`should GET balance for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
describe('#Balance', () => {
|
||||
it('should GET balance for a single address', async () => {
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.OpenBazaar.balance(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"page",
|
||||
"totalPages",
|
||||
"itemsOnPage",
|
||||
"addrStr",
|
||||
"balance",
|
||||
"totalReceived",
|
||||
"totalSent",
|
||||
"unconfirmedBalance",
|
||||
"unconfirmedTxApperances",
|
||||
"txApperances",
|
||||
"transactions"
|
||||
'page',
|
||||
'totalPages',
|
||||
'itemsOnPage',
|
||||
'addrStr',
|
||||
'balance',
|
||||
'totalReceived',
|
||||
'totalSent',
|
||||
'unconfirmedBalance',
|
||||
'unconfirmedTxApperances',
|
||||
'txApperances',
|
||||
'transactions'
|
||||
])
|
||||
assert.isArray(result.transactions)
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#utxo`, () => {
|
||||
it(`should GET utxos for a single address`, async () => {
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
describe('#utxo', () => {
|
||||
it('should GET utxos for a single address', async () => {
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.OpenBazaar.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAllKeys(result[0], [
|
||||
"txid",
|
||||
"vout",
|
||||
"amount",
|
||||
"height",
|
||||
"confirmations",
|
||||
"satoshis"
|
||||
'txid',
|
||||
'vout',
|
||||
'amount',
|
||||
'height',
|
||||
'confirmations',
|
||||
'satoshis'
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#tx`, () => {
|
||||
it(`should GET transactions for a single address`, async () => {
|
||||
describe('#tx', () => {
|
||||
it('should GET transactions for a single address', async () => {
|
||||
const addr =
|
||||
"2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7"
|
||||
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7'
|
||||
|
||||
const result = await bchjs.OpenBazaar.tx(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"txid",
|
||||
"version",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"blockheight",
|
||||
"confirmations",
|
||||
"blocktime",
|
||||
"valueOut",
|
||||
"valueIn",
|
||||
"fees",
|
||||
"hex",
|
||||
"time"
|
||||
'txid',
|
||||
'version',
|
||||
'vin',
|
||||
'vout',
|
||||
'blockhash',
|
||||
'blockheight',
|
||||
'confirmations',
|
||||
'blocktime',
|
||||
'valueOut',
|
||||
'valueIn',
|
||||
'fees',
|
||||
'hex',
|
||||
'time'
|
||||
])
|
||||
assert.isArray(result.vin)
|
||||
assert.isArray(result.vout)
|
||||
@@ -84,6 +84,6 @@ describe(`#OpenBazaar`, () => {
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
+23
-14
@@ -1,23 +1,23 @@
|
||||
const assert = require("chai").assert
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const assert = require('chai').assert
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe("#price", () => {
|
||||
describe('#price', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
describe("#current", () => {
|
||||
describe("#single currency", () => {
|
||||
it("should get current price for single currency", async () => {
|
||||
const result = await bchjs.Price.current("usd")
|
||||
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 () => {
|
||||
describe('#getUsd', () => {
|
||||
it('should get the USD price of BCH', async () => {
|
||||
const result = await bchjs.Price.getUsd()
|
||||
// console.log(result)
|
||||
|
||||
@@ -25,17 +25,26 @@ describe("#price", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#rates", () => {
|
||||
it("should get the price of BCH in several currencies", async () => {
|
||||
describe('#getBchaUsd', () => {
|
||||
it('should get the USD price of BCHA', async () => {
|
||||
const result = await bchjs.Price.getBchaUsd()
|
||||
console.log(result)
|
||||
|
||||
assert.isNumber(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#rates', () => {
|
||||
it('should get the price of BCH in several currencies', async () => {
|
||||
const result = await bchjs.Price.rates()
|
||||
// console.log(result)
|
||||
|
||||
assert.property(result, "USD")
|
||||
assert.property(result, "CAD")
|
||||
assert.property(result, 'USD')
|
||||
assert.property(result, 'CAD')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
@@ -5,136 +5,136 @@
|
||||
TODO
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 3
|
||||
}
|
||||
|
||||
describe("#rawtransaction", () => {
|
||||
describe('#rawtransaction', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
describe("#decodeRawTransaction", () => {
|
||||
it("should decode tx for a single hex", async () => {
|
||||
describe('#decodeRawTransaction', () => {
|
||||
it('should decode tx for a single hex', async () => {
|
||||
const hex =
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000'
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeRawTransaction(hex)
|
||||
//console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout"
|
||||
'txid',
|
||||
'hash',
|
||||
'size',
|
||||
'version',
|
||||
'locktime',
|
||||
'vin',
|
||||
'vout'
|
||||
])
|
||||
assert.isArray(result.vin)
|
||||
assert.isArray(result.vout)
|
||||
})
|
||||
|
||||
it("should decode an array of tx hexes", async () => {
|
||||
it('should decode an array of tx hexes', async () => {
|
||||
const hexes = [
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000",
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000',
|
||||
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000'
|
||||
]
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeRawTransaction(hexes)
|
||||
//console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout"
|
||||
'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 () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) {
|
||||
data.push(
|
||||
"0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000"
|
||||
'0200000001b9b598d7d6d72fc486b2b3a3c03c79b5bade6ec9a77ced850515ab5e64edcc21010000006b483045022100a7b1b08956abb8d6f322aa709d8583c8ea492ba0585f1a6f4f9983520af74a5a0220411aee4a9a54effab617b0508c504c31681b15f9b187179b4874257badd4139041210360cfc66fdacb650bc4c83b4e351805181ee696b7d5ab4667c57b2786f51c413dffffffff0210270000000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac786e9800000000001976a914eb4b180def88e3f5625b2d8ae2c098ff7d85f66488ac00000000'
|
||||
)
|
||||
}
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeRawTransaction(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getRawTransaction", () => {
|
||||
it("should decode a single txid, with concise output", async () => {
|
||||
describe('#getRawTransaction', () => {
|
||||
it('should decode a single txid, with concise output', async () => {
|
||||
const txid =
|
||||
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1"
|
||||
'23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1'
|
||||
const verbose = false
|
||||
|
||||
const result = await bchjs.RawTransactions.getRawTransaction(
|
||||
txid,
|
||||
verbose
|
||||
)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isString(result)
|
||||
})
|
||||
|
||||
it("should decode a single txid, with verbose output", async () => {
|
||||
it('should decode a single txid, with verbose output', async () => {
|
||||
const txid =
|
||||
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1"
|
||||
'23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1'
|
||||
const verbose = true
|
||||
|
||||
const result = await bchjs.RawTransactions.getRawTransaction(
|
||||
txid,
|
||||
verbose
|
||||
)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"hex",
|
||||
"txid",
|
||||
"hash",
|
||||
"size",
|
||||
"version",
|
||||
"locktime",
|
||||
"vin",
|
||||
"vout",
|
||||
"blockhash",
|
||||
"confirmations",
|
||||
"time",
|
||||
"blocktime"
|
||||
'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 () => {
|
||||
it('should decode an array of txids, with a concise output', async () => {
|
||||
const txid = [
|
||||
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1",
|
||||
"b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f"
|
||||
'23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1',
|
||||
'b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f'
|
||||
]
|
||||
const verbose = false
|
||||
|
||||
@@ -142,16 +142,16 @@ describe("#rawtransaction", () => {
|
||||
txid,
|
||||
verbose
|
||||
)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// 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 () => {
|
||||
it('should decode an array of txids, with a verbose output', async () => {
|
||||
const txid = [
|
||||
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1",
|
||||
"b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f"
|
||||
'23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1',
|
||||
'b25d24fbb42d84812ed2cb55797f10fdec41afc7906ab563d1ec8c8676a2037f'
|
||||
]
|
||||
const verbose = true
|
||||
|
||||
@@ -159,54 +159,54 @@ describe("#rawtransaction", () => {
|
||||
txid,
|
||||
verbose
|
||||
)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// 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"
|
||||
'hex',
|
||||
'txid',
|
||||
'hash',
|
||||
'size',
|
||||
'version',
|
||||
'locktime',
|
||||
'vin',
|
||||
'vout',
|
||||
'blockhash',
|
||||
'confirmations',
|
||||
'time',
|
||||
'blocktime'
|
||||
])
|
||||
assert.isArray(result[0].vin)
|
||||
assert.isArray(result[0].vout)
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const dataMock =
|
||||
"23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1"
|
||||
'23213453b4642a73b4fc30d3112d72549ca153a8707255b14373b59e43558de1'
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) data.push(dataMock)
|
||||
|
||||
const result = await bchjs.RawTransactions.getRawTransaction(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#decodeScript", () => {
|
||||
it("should decode script for a single hex", async () => {
|
||||
describe('#decodeScript', () => {
|
||||
it('should decode script for a single hex', async () => {
|
||||
const hex =
|
||||
"4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16"
|
||||
'4830450221009a51e00ec3524a7389592bc27bea4af5104a59510f5f0cfafa64bbd5c164ca2e02206c2a8bbb47eabdeed52f17d7df668d521600286406930426e3a9415fe10ed592012102e6e1423f7abde8b70bca3e78a7d030e5efabd3eb35c19302542b5fe7879c1a16'
|
||||
|
||||
const result = await bchjs.RawTransactions.decodeScript(hex)
|
||||
//console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["asm", "type", "p2sh"])
|
||||
assert.hasAllKeys(result, ['asm', 'type', 'p2sh'])
|
||||
})
|
||||
|
||||
// CT 2/20/19 - Waiting for this PR to be merged complete the test:
|
||||
@@ -230,60 +230,26 @@ describe("#rawtransaction", () => {
|
||||
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 (code 16)")
|
||||
}
|
||||
})
|
||||
|
||||
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 (code 16)")
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
describe('sendRawTransaction', () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const dataMock =
|
||||
"01000000013ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a000000006a4730440220540986d1c58d6e76f8f05501c520c38ce55393d0ed7ed3c3a82c69af04221232022058ea43ed6c05fec0eccce749a63332ed4525460105346f11108b9c26df93cd72012103083dfc5a0254613941ddc91af39ff90cd711cdcde03a87b144b883b524660c39ffffffff01807c814a000000001976a914d7e7c4e0b70eaa67ceff9d2823d1bbb9f6df9a5188ac00000000"
|
||||
'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!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
+306
-205
@@ -2,21 +2,21 @@
|
||||
Integration tests for the bchjs covering SLP tokens.
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
let bchjs
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 1
|
||||
}
|
||||
|
||||
describe(`#SLP`, () => {
|
||||
describe('#SLP', () => {
|
||||
// before(() => {
|
||||
// console.log(`bchjs.SLP.restURL: ${bchjs.SLP.restURL}`)
|
||||
// console.log(`bchjs.SLP.apiToken: ${bchjs.SLP.apiToken}`)
|
||||
@@ -29,35 +29,35 @@ describe(`#SLP`, () => {
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
|
||||
describe("#util", () => {
|
||||
describe("#list", () => {
|
||||
it(`should get information on the Spice token`, async () => {
|
||||
const tokenId = `4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf`
|
||||
describe('#util', () => {
|
||||
describe('#list', () => {
|
||||
it('should get information on the Spice token', async () => {
|
||||
const tokenId = '4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf'
|
||||
|
||||
const result = await bchjs.SLP.Utils.list(tokenId)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// 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"
|
||||
'decimals',
|
||||
'timestamp',
|
||||
'timestamp_unix',
|
||||
'versionType',
|
||||
'documentUri',
|
||||
'symbol',
|
||||
'name',
|
||||
'containsBaton',
|
||||
'id',
|
||||
'documentHash',
|
||||
'initialTokenQty',
|
||||
'blockCreated',
|
||||
'blockLastActiveSend',
|
||||
'blockLastActiveMint',
|
||||
'txnsSinceGenesis',
|
||||
'validAddress',
|
||||
'totalMinted',
|
||||
'totalBurned',
|
||||
'circulatingSupply',
|
||||
'mintingBatonStatus'
|
||||
])
|
||||
})
|
||||
})
|
||||
@@ -134,109 +134,109 @@ describe(`#SLP`, () => {
|
||||
// })
|
||||
// })
|
||||
|
||||
describe("#decodeOpReturn", () => {
|
||||
it("should decode the OP_RETURN for a SEND txid", async () => {
|
||||
describe('#decodeOpReturn', () => {
|
||||
it('should decode the OP_RETURN for a SEND txid', async () => {
|
||||
const txid =
|
||||
"266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1"
|
||||
'266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1'
|
||||
|
||||
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["tokenType", "txType", "tokenId", "amounts"])
|
||||
assert.hasAllKeys(result, ['tokenType', 'txType', 'tokenId', 'amounts'])
|
||||
assert.equal(
|
||||
result.tokenId,
|
||||
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
||||
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
|
||||
)
|
||||
|
||||
// Verify outputs
|
||||
assert.equal(result.amounts.length, 2)
|
||||
assert.equal(result.amounts[0], "100000000")
|
||||
assert.equal(result.amounts[1], "99883300000000")
|
||||
assert.equal(result.amounts[0], '100000000')
|
||||
assert.equal(result.amounts[1], '99883300000000')
|
||||
})
|
||||
|
||||
it("should decode the OP_RETURN for a GENESIS txid", async () => {
|
||||
it('should decode the OP_RETURN for a GENESIS txid', async () => {
|
||||
const txid =
|
||||
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
||||
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
|
||||
|
||||
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"tokenType",
|
||||
"txType",
|
||||
"tokenId",
|
||||
"ticker",
|
||||
"name",
|
||||
"documentUri",
|
||||
"documentHash",
|
||||
"decimals",
|
||||
"mintBatonVout",
|
||||
"qty"
|
||||
'tokenType',
|
||||
'txType',
|
||||
'tokenId',
|
||||
'ticker',
|
||||
'name',
|
||||
'documentUri',
|
||||
'documentHash',
|
||||
'decimals',
|
||||
'mintBatonVout',
|
||||
'qty'
|
||||
])
|
||||
assert.equal(
|
||||
result.tokenId,
|
||||
"497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7"
|
||||
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
|
||||
)
|
||||
assert.equal(result.txType, "GENESIS")
|
||||
assert.equal(result.ticker, "TOK-CH")
|
||||
assert.equal(result.name, "TokyoCash")
|
||||
assert.equal(result.txType, 'GENESIS')
|
||||
assert.equal(result.ticker, 'TOK-CH')
|
||||
assert.equal(result.name, 'TokyoCash')
|
||||
})
|
||||
|
||||
it("should decode the OP_RETURN for a MINT txid", async () => {
|
||||
it('should decode the OP_RETURN for a MINT txid', async () => {
|
||||
const txid =
|
||||
"65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4"
|
||||
'65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4'
|
||||
|
||||
const result = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
"tokenType",
|
||||
"txType",
|
||||
"tokenId",
|
||||
"mintBatonVout",
|
||||
"qty"
|
||||
'tokenType',
|
||||
'txType',
|
||||
'tokenId',
|
||||
'mintBatonVout',
|
||||
'qty'
|
||||
])
|
||||
})
|
||||
|
||||
it("should throw an error for a non-SLP transaction", async () => {
|
||||
it('should throw an error for a non-SLP transaction', async () => {
|
||||
try {
|
||||
const txid =
|
||||
"3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec"
|
||||
'3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec'
|
||||
|
||||
await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
|
||||
assert.equal(true, false, "Unexpected result")
|
||||
assert.equal(true, false, 'Unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.message, "scriptpubkey not op_return")
|
||||
assert.include(err.message, 'scriptpubkey not op_return')
|
||||
}
|
||||
})
|
||||
|
||||
// Note: This TX is interpreted as valid by the original decodeOpReturn().
|
||||
// Fixing this issue and related issues was the reason for creating the
|
||||
// decodeOpReturn2() method using the slp-parser library.
|
||||
it("should throw error for invalid SLP transaction", async () => {
|
||||
it('should throw error for invalid SLP transaction', async () => {
|
||||
try {
|
||||
const txid =
|
||||
"a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415"
|
||||
'a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415'
|
||||
|
||||
await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.message, "amount string size not 8 bytes")
|
||||
assert.include(err.message, 'amount string size not 8 bytes')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("#tokenUtxoDetails", () => {
|
||||
describe('#tokenUtxoDetails', () => {
|
||||
// // This captures an important corner-case. When an SLP token is created, the
|
||||
// // change UTXO will contain the same SLP txid, but it is not an SLP UTXO.
|
||||
it("should return details on minting baton from genesis transaction", async () => {
|
||||
it('should return details on minting baton from genesis transaction', async () => {
|
||||
const utxos = [
|
||||
{
|
||||
txid:
|
||||
"bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90",
|
||||
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
|
||||
vout: 3,
|
||||
amount: 0.00002015,
|
||||
satoshis: 2015,
|
||||
@@ -245,7 +245,7 @@ describe(`#SLP`, () => {
|
||||
},
|
||||
{
|
||||
txid:
|
||||
"bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90",
|
||||
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90',
|
||||
vout: 2,
|
||||
amount: 0.00000546,
|
||||
satoshis: 546,
|
||||
@@ -257,32 +257,32 @@ describe(`#SLP`, () => {
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.equal(data[0].isValid, false, "Change UTXO marked as false.")
|
||||
assert.equal(data[0].isValid, false, 'Change UTXO marked as false.')
|
||||
|
||||
assert.property(data[1], "txid")
|
||||
assert.property(data[1], "vout")
|
||||
assert.property(data[1], "amount")
|
||||
assert.property(data[1], "satoshis")
|
||||
assert.property(data[1], "height")
|
||||
assert.property(data[1], "confirmations")
|
||||
assert.property(data[1], "utxoType")
|
||||
assert.property(data[1], "tokenId")
|
||||
assert.property(data[1], "tokenTicker")
|
||||
assert.property(data[1], "tokenName")
|
||||
assert.property(data[1], "tokenDocumentUrl")
|
||||
assert.property(data[1], "tokenDocumentHash")
|
||||
assert.property(data[1], "decimals")
|
||||
assert.property(data[1], "isValid")
|
||||
assert.property(data[1], 'txid')
|
||||
assert.property(data[1], 'vout')
|
||||
assert.property(data[1], 'amount')
|
||||
assert.property(data[1], 'satoshis')
|
||||
assert.property(data[1], 'height')
|
||||
assert.property(data[1], 'confirmations')
|
||||
assert.property(data[1], 'utxoType')
|
||||
assert.property(data[1], 'tokenId')
|
||||
assert.property(data[1], 'tokenTicker')
|
||||
assert.property(data[1], 'tokenName')
|
||||
assert.property(data[1], 'tokenDocumentUrl')
|
||||
assert.property(data[1], 'tokenDocumentHash')
|
||||
assert.property(data[1], 'decimals')
|
||||
assert.property(data[1], 'isValid')
|
||||
assert.equal(data[1].isValid, true)
|
||||
})
|
||||
|
||||
it("should return details for a MINT token utxo", async () => {
|
||||
it('should return details for a MINT token utxo', async () => {
|
||||
// Mock the call to REST API
|
||||
|
||||
const utxos = [
|
||||
{
|
||||
txid:
|
||||
"cf4b922d1e1aa56b52d752d4206e1448ea76c3ebe69b3b97d8f8f65413bd5c76",
|
||||
'cf4b922d1e1aa56b52d752d4206e1448ea76c3ebe69b3b97d8f8f65413bd5c76',
|
||||
vout: 1,
|
||||
amount: 0.00000546,
|
||||
satoshis: 546,
|
||||
@@ -294,31 +294,31 @@ describe(`#SLP`, () => {
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.property(data[0], "txid")
|
||||
assert.property(data[0], "vout")
|
||||
assert.property(data[0], "amount")
|
||||
assert.property(data[0], "satoshis")
|
||||
assert.property(data[0], "height")
|
||||
assert.property(data[0], "confirmations")
|
||||
assert.property(data[0], "utxoType")
|
||||
assert.property(data[0], "transactionType")
|
||||
assert.property(data[0], "tokenId")
|
||||
assert.property(data[0], "tokenTicker")
|
||||
assert.property(data[0], "tokenName")
|
||||
assert.property(data[0], "tokenDocumentUrl")
|
||||
assert.property(data[0], "tokenDocumentHash")
|
||||
assert.property(data[0], "decimals")
|
||||
assert.property(data[0], "mintBatonVout")
|
||||
assert.property(data[0], "tokenQty")
|
||||
assert.property(data[0], "isValid")
|
||||
assert.property(data[0], 'txid')
|
||||
assert.property(data[0], 'vout')
|
||||
assert.property(data[0], 'amount')
|
||||
assert.property(data[0], 'satoshis')
|
||||
assert.property(data[0], 'height')
|
||||
assert.property(data[0], 'confirmations')
|
||||
assert.property(data[0], 'utxoType')
|
||||
assert.property(data[0], 'transactionType')
|
||||
assert.property(data[0], 'tokenId')
|
||||
assert.property(data[0], 'tokenTicker')
|
||||
assert.property(data[0], 'tokenName')
|
||||
assert.property(data[0], 'tokenDocumentUrl')
|
||||
assert.property(data[0], 'tokenDocumentHash')
|
||||
assert.property(data[0], 'decimals')
|
||||
assert.property(data[0], 'mintBatonVout')
|
||||
assert.property(data[0], 'tokenQty')
|
||||
assert.property(data[0], 'isValid')
|
||||
assert.equal(data[0].isValid, true)
|
||||
})
|
||||
|
||||
it("should return details for a simple SEND SLP token utxo", async () => {
|
||||
it('should return details for a simple SEND SLP token utxo', async () => {
|
||||
const utxos = [
|
||||
{
|
||||
txid:
|
||||
"fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb",
|
||||
'fde117b1f176b231e2fa9a6cb022e0f7c31c288221df6bcb05f8b7d040ca87cb',
|
||||
vout: 1,
|
||||
amount: 0.00000546,
|
||||
satoshis: 546,
|
||||
@@ -330,40 +330,40 @@ describe(`#SLP`, () => {
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.property(data[0], "txid")
|
||||
assert.property(data[0], "vout")
|
||||
assert.property(data[0], "amount")
|
||||
assert.property(data[0], "satoshis")
|
||||
assert.property(data[0], "height")
|
||||
assert.property(data[0], "confirmations")
|
||||
assert.property(data[0], "utxoType")
|
||||
assert.property(data[0], "tokenId")
|
||||
assert.property(data[0], "tokenTicker")
|
||||
assert.property(data[0], "tokenName")
|
||||
assert.property(data[0], "tokenDocumentUrl")
|
||||
assert.property(data[0], "tokenDocumentHash")
|
||||
assert.property(data[0], "decimals")
|
||||
assert.property(data[0], "tokenQty")
|
||||
assert.property(data[0], "isValid")
|
||||
assert.property(data[0], 'txid')
|
||||
assert.property(data[0], 'vout')
|
||||
assert.property(data[0], 'amount')
|
||||
assert.property(data[0], 'satoshis')
|
||||
assert.property(data[0], 'height')
|
||||
assert.property(data[0], 'confirmations')
|
||||
assert.property(data[0], 'utxoType')
|
||||
assert.property(data[0], 'tokenId')
|
||||
assert.property(data[0], 'tokenTicker')
|
||||
assert.property(data[0], 'tokenName')
|
||||
assert.property(data[0], 'tokenDocumentUrl')
|
||||
assert.property(data[0], 'tokenDocumentHash')
|
||||
assert.property(data[0], 'decimals')
|
||||
assert.property(data[0], 'tokenQty')
|
||||
assert.property(data[0], 'isValid')
|
||||
assert.equal(data[0].isValid, true)
|
||||
})
|
||||
|
||||
it("should handle BCH and SLP utxos in the same TX", async () => {
|
||||
it('should handle BCH and SLP utxos in the same TX', async () => {
|
||||
const utxos = [
|
||||
{
|
||||
txid:
|
||||
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
|
||||
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
|
||||
vout: 3,
|
||||
value: "6816",
|
||||
value: '6816',
|
||||
height: 606848,
|
||||
confirmations: 13,
|
||||
satoshis: 6816
|
||||
},
|
||||
{
|
||||
txid:
|
||||
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
|
||||
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
|
||||
vout: 2,
|
||||
value: "546",
|
||||
value: '546',
|
||||
height: 606848,
|
||||
confirmations: 13,
|
||||
satoshis: 546
|
||||
@@ -379,11 +379,11 @@ describe(`#SLP`, () => {
|
||||
assert.equal(result[1].isValid, true)
|
||||
})
|
||||
|
||||
it("should handle problematic utxos", async () => {
|
||||
it('should handle problematic utxos', async () => {
|
||||
const utxos = [
|
||||
{
|
||||
txid:
|
||||
"0e3a217fc22612002031d317b4cecd9b692b66b52951a67b23c43041aefa3959",
|
||||
'0e3a217fc22612002031d317b4cecd9b692b66b52951a67b23c43041aefa3959',
|
||||
vout: 0,
|
||||
amount: 0.00018362,
|
||||
satoshis: 18362,
|
||||
@@ -392,7 +392,7 @@ describe(`#SLP`, () => {
|
||||
},
|
||||
{
|
||||
txid:
|
||||
"67fd3c7c3a6eb0fea9ab311b91039545086220f7eeeefa367fa28e6e43009f19",
|
||||
'67fd3c7c3a6eb0fea9ab311b91039545086220f7eeeefa367fa28e6e43009f19',
|
||||
vout: 1,
|
||||
amount: 0.00000546,
|
||||
satoshis: 546,
|
||||
@@ -410,11 +410,11 @@ describe(`#SLP`, () => {
|
||||
assert.equal(result[1].isValid, true)
|
||||
})
|
||||
|
||||
it("should return false for BCH-only UTXOs", async () => {
|
||||
it('should return false for BCH-only UTXOs', async () => {
|
||||
const utxos = [
|
||||
{
|
||||
txid:
|
||||
"a937f792c7c9eb23b4f344ce5c233d1ac0909217d0a504d71e6b1e4efb864a3b",
|
||||
'a937f792c7c9eb23b4f344ce5c233d1ac0909217d0a504d71e6b1e4efb864a3b',
|
||||
vout: 0,
|
||||
amount: 0.00001,
|
||||
satoshis: 1000,
|
||||
@@ -423,7 +423,7 @@ describe(`#SLP`, () => {
|
||||
},
|
||||
{
|
||||
txid:
|
||||
"53fd141c2e999e080a5860887441a2c45e9cbe262027e2bd2ac998fc76e43c44",
|
||||
'53fd141c2e999e080a5860887441a2c45e9cbe262027e2bd2ac998fc76e43c44',
|
||||
vout: 0,
|
||||
amount: 0.00001,
|
||||
satoshis: 1000,
|
||||
@@ -440,20 +440,20 @@ describe(`#SLP`, () => {
|
||||
assert.equal(data[1].isValid, false)
|
||||
})
|
||||
|
||||
it("should handle a dust attack", async () => {
|
||||
it('should handle a dust attack', async () => {
|
||||
// it("#dustattack", async () => {
|
||||
const utxos = [
|
||||
{
|
||||
height: 655965,
|
||||
tx_hash:
|
||||
"a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e",
|
||||
'a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e',
|
||||
tx_pos: 151,
|
||||
value: 547,
|
||||
satoshis: 547,
|
||||
txid:
|
||||
"a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e",
|
||||
'a675af87dcd8d39be782737aa52e0076b52eb2f5ce355ffcb5567a64dd96b77e',
|
||||
vout: 151,
|
||||
address: "bitcoincash:qq4dw3sm8qvglspy6w2qg0u2ugsy9zcfcqrpeflwww",
|
||||
address: 'bitcoincash:qq4dw3sm8qvglspy6w2qg0u2ugsy9zcfcqrpeflwww',
|
||||
hdIndex: 11
|
||||
}
|
||||
]
|
||||
@@ -463,29 +463,54 @@ describe(`#SLP`, () => {
|
||||
|
||||
assert.equal(data[0].isValid, false)
|
||||
})
|
||||
|
||||
it('should handle null SLPDB validations', async () => {
|
||||
const utxos = [
|
||||
{
|
||||
height: 665577,
|
||||
tx_hash:
|
||||
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
{
|
||||
height: 665577,
|
||||
tx_hash:
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
}
|
||||
]
|
||||
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetails(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.isArray(data)
|
||||
// assert.equal(data[0].isValid, null)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#balancesForAddress", () => {
|
||||
it(`should fetch all balances for address: simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9`, async () => {
|
||||
describe('#balancesForAddress', () => {
|
||||
it('should fetch all balances for address: simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9', async () => {
|
||||
const balances = await bchjs.SLP.Utils.balancesForAddress(
|
||||
"simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9"
|
||||
'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
||||
)
|
||||
// console.log(`balances: ${JSON.stringify(balances, null, 2)}`)
|
||||
|
||||
assert.isArray(balances)
|
||||
assert.hasAllKeys(balances[0], [
|
||||
"tokenId",
|
||||
"balanceString",
|
||||
"balance",
|
||||
"decimalCount",
|
||||
"slpAddress"
|
||||
'tokenId',
|
||||
'balanceString',
|
||||
'balance',
|
||||
'decimalCount',
|
||||
'slpAddress'
|
||||
])
|
||||
})
|
||||
|
||||
it(`should fetch balances for multiple addresses`, async () => {
|
||||
it('should fetch balances for multiple addresses', async () => {
|
||||
const addresses = [
|
||||
"simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9",
|
||||
"simpleledger:qqss4zp80hn6szsa4jg2s9fupe7g5tcg5ucdyl3r57"
|
||||
'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9',
|
||||
'simpleledger:qqss4zp80hn6szsa4jg2s9fupe7g5tcg5ucdyl3r57'
|
||||
]
|
||||
|
||||
const balances = await bchjs.SLP.Utils.balancesForAddress(addresses)
|
||||
@@ -494,34 +519,34 @@ describe(`#SLP`, () => {
|
||||
assert.isArray(balances)
|
||||
assert.isArray(balances[0])
|
||||
assert.hasAllKeys(balances[0][0], [
|
||||
"tokenId",
|
||||
"balanceString",
|
||||
"balance",
|
||||
"decimalCount",
|
||||
"slpAddress"
|
||||
'tokenId',
|
||||
'balanceString',
|
||||
'balance',
|
||||
'decimalCount',
|
||||
'slpAddress'
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe("#hydrateUtxos", () => {
|
||||
it("should hydrate UTXOs", async () => {
|
||||
describe('#hydrateUtxos', () => {
|
||||
it('should hydrate UTXOs', async () => {
|
||||
const utxos = [
|
||||
{
|
||||
utxos: [
|
||||
{
|
||||
txid:
|
||||
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
|
||||
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
|
||||
vout: 3,
|
||||
value: "6816",
|
||||
value: '6816',
|
||||
height: 606848,
|
||||
confirmations: 13,
|
||||
satoshis: 6816
|
||||
},
|
||||
{
|
||||
txid:
|
||||
"d56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56",
|
||||
'd56a2b446d8149c39ca7e06163fe8097168c3604915f631bc58777d669135a56',
|
||||
vout: 2,
|
||||
value: "546",
|
||||
value: '546',
|
||||
height: 606848,
|
||||
confirmations: 13,
|
||||
satoshis: 546
|
||||
@@ -539,40 +564,40 @@ describe(`#SLP`, () => {
|
||||
assert.equal(result.slpUtxos[0].utxos.length, 2)
|
||||
|
||||
// Test the non-slp UTXO.
|
||||
assert.property(result.slpUtxos[0].utxos[0], "txid")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "vout")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "value")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "height")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "confirmations")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "satoshis")
|
||||
assert.property(result.slpUtxos[0].utxos[0], "isValid")
|
||||
assert.property(result.slpUtxos[0].utxos[0], 'txid')
|
||||
assert.property(result.slpUtxos[0].utxos[0], 'vout')
|
||||
assert.property(result.slpUtxos[0].utxos[0], 'value')
|
||||
assert.property(result.slpUtxos[0].utxos[0], 'height')
|
||||
assert.property(result.slpUtxos[0].utxos[0], 'confirmations')
|
||||
assert.property(result.slpUtxos[0].utxos[0], 'satoshis')
|
||||
assert.property(result.slpUtxos[0].utxos[0], 'isValid')
|
||||
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
|
||||
|
||||
// Test the slp UTXO.
|
||||
assert.property(result.slpUtxos[0].utxos[1], "txid")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "vout")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "value")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "height")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "confirmations")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "satoshis")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "isValid")
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'txid')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'vout')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'value')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'height')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'confirmations')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'satoshis')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'isValid')
|
||||
assert.equal(result.slpUtxos[0].utxos[1].isValid, true)
|
||||
assert.property(result.slpUtxos[0].utxos[1], "transactionType")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenId")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenTicker")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenName")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenDocumentUrl")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenDocumentHash")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "decimals")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenType")
|
||||
assert.property(result.slpUtxos[0].utxos[1], "tokenQty")
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'transactionType')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'tokenId')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'tokenTicker')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'tokenName')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'tokenDocumentUrl')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'tokenDocumentHash')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'decimals')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'tokenType')
|
||||
assert.property(result.slpUtxos[0].utxos[1], 'tokenQty')
|
||||
})
|
||||
|
||||
it("should process data directly from Electrumx", async () => {
|
||||
it('should process data directly from Electrumx', async () => {
|
||||
const addrs = [
|
||||
"bitcoincash:qqnt53cfw990u6y38xgezm0lfa8hknw0wueezcpagp",
|
||||
"bitcoincash:qrh3qgtax6adegzc7zxm6m4sgrv9wq28yqnfn33ce5",
|
||||
"bitcoincash:qqcaee5w4ws77n8s2gzy6fwtma6uxd7ctq8553e495"
|
||||
'bitcoincash:qqnt53cfw990u6y38xgezm0lfa8hknw0wueezcpagp',
|
||||
'bitcoincash:qrh3qgtax6adegzc7zxm6m4sgrv9wq28yqnfn33ce5',
|
||||
'bitcoincash:qqcaee5w4ws77n8s2gzy6fwtma6uxd7ctq8553e495'
|
||||
]
|
||||
|
||||
const utxos = await bchjs.Electrumx.utxo(addrs)
|
||||
@@ -592,58 +617,134 @@ describe(`#SLP`, () => {
|
||||
// Test the expected values.
|
||||
assert.equal(result.slpUtxos[0].utxos[0].isValid, false)
|
||||
assert.equal(result.slpUtxos[1].utxos[0].isValid, true)
|
||||
assert.equal(result.slpUtxos[1].utxos[0].tokenTicker, "TROUT")
|
||||
assert.equal(result.slpUtxos[1].utxos[0].tokenTicker, 'TROUT')
|
||||
assert.equal(result.slpUtxos[2].utxos[0].isValid, false)
|
||||
assert.equal(result.slpUtxos[2].utxos[1].isValid, true)
|
||||
assert.equal(result.slpUtxos[2].utxos[1].tokenTicker, "VALENTINE")
|
||||
assert.equal(result.slpUtxos[2].utxos[1].tokenTicker, 'VALENTINE')
|
||||
} catch (err) {
|
||||
console.error(
|
||||
'The hydrateUtxos call may hitting rate limits, or SLPDB may be having issues if "isValid" results are "null"'
|
||||
)
|
||||
console.log("Error: ", err)
|
||||
console.log('Error: ', err)
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle null SLPDB validations', async () => {
|
||||
const utxos = [
|
||||
{
|
||||
height: 665577,
|
||||
tx_hash:
|
||||
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
{
|
||||
height: 665577,
|
||||
tx_hash:
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
}
|
||||
]
|
||||
|
||||
const data = await bchjs.SLP.Utils.hydrateUtxos([{ utxos: utxos }])
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.isArray(data.slpUtxos)
|
||||
assert.equal(data.slpUtxos[0].isValid, null)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#validateTxid2", () => {
|
||||
it("should invalidate a known invalid TXID", async () => {
|
||||
describe('#validateTxid', () => {
|
||||
// This test is not necessary.
|
||||
it('should handle a null response from SLPDB', async () => {
|
||||
const txid =
|
||||
"f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a"
|
||||
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419'
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.equal(result[0].txid, txid)
|
||||
// assert.equal(result[0].valid, null)
|
||||
})
|
||||
|
||||
it('should handle a null response from SLPDB', async () => {
|
||||
const txid = [
|
||||
'4b89405c54d1c0bde8aa476a47561a42a6e7a5e927daa2ec69d428810eae3419',
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488'
|
||||
]
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.equal(result[0].txid, txid[0])
|
||||
// assert.equal(result[0].valid, null)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#validateTxid2', () => {
|
||||
it('should invalidate a known invalid TXID', async () => {
|
||||
const txid =
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "txid")
|
||||
assert.property(result, 'txid')
|
||||
assert.equal(result.txid, txid)
|
||||
|
||||
assert.property(result, "isValid")
|
||||
assert.property(result, 'isValid')
|
||||
assert.equal(result.isValid, false)
|
||||
})
|
||||
|
||||
it("should validate a known valid TXID", async () => {
|
||||
it('should validate a known valid TXID', async () => {
|
||||
const txid =
|
||||
"3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488"
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488'
|
||||
|
||||
const result = await bchjs.SLP.Utils.validateTxid2(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "txid")
|
||||
assert.property(result, 'txid')
|
||||
assert.equal(result.txid, txid)
|
||||
|
||||
assert.property(result, "isValid")
|
||||
assert.property(result, 'isValid')
|
||||
assert.equal(result.isValid, true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getWhitelist', () => {
|
||||
it('should get the whitelist', async () => {
|
||||
const result = await bchjs.SLP.Utils.getWhitelist()
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'name')
|
||||
assert.property(result[1], 'tokenId')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getStatus', () => {
|
||||
it('should return the current block height of the SLPDB indexer', async () => {
|
||||
const result = await bchjs.SLP.Utils.getStatus()
|
||||
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, 'bchBlockHeight')
|
||||
assert.property(result, 'slpProcessedBlockHeight')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#tokentype1", () => {
|
||||
describe("#getHexOpReturn", () => {
|
||||
it("should return OP_RETURN object ", async () => {
|
||||
describe('#tokentype1', () => {
|
||||
describe('#getHexOpReturn', () => {
|
||||
it('should return OP_RETURN object ', async () => {
|
||||
const tokenUtxos = [
|
||||
{
|
||||
tokenId:
|
||||
"0a321bff9761f28e06a268b14711274bb77617410a16807bd0437ef234a072b1",
|
||||
decimals: 0,
|
||||
'38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0',
|
||||
decimals: 8,
|
||||
tokenQty: 2
|
||||
}
|
||||
]
|
||||
@@ -655,10 +756,10 @@ describe(`#SLP`, () => {
|
||||
)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "script")
|
||||
assert.property(result, 'script')
|
||||
assert.isString(result.script)
|
||||
|
||||
assert.property(result, "outputs")
|
||||
assert.property(result, 'outputs')
|
||||
assert.isNumber(result.outputs)
|
||||
})
|
||||
})
|
||||
@@ -666,6 +767,6 @@ describe(`#SLP`, () => {
|
||||
})
|
||||
|
||||
// Promise-based sleep function
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export RESTURL=https://bchn.fullstack.cash/v3/
|
||||
#export RESTURL=http://localhost:3000/v3/
|
||||
#export IS_USING_FREE_TIER=true
|
||||
|
||||
cd test/integration/bchn/
|
||||
mocha --timeout 30000 blockchain.js control.js encryption.js electrumx.js ninsight.js openbazaar.js price.js rawtransaction.js slp.js util.js
|
||||
@@ -1,186 +0,0 @@
|
||||
/*
|
||||
Integration tests for the Blockbook library.
|
||||
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: `https://testnet3.fullstack.cash/v3/`
|
||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
// const bchjs = new BCHJS({ restURL: RESTURL })
|
||||
//const axios = require("axios")
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 3
|
||||
}
|
||||
|
||||
describe(`#Blockbook`, () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
describe(`#Balance`, () => {
|
||||
it(`should GET balance for a single address`, async () => {
|
||||
const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
|
||||
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"page",
|
||||
"totalPages",
|
||||
"itemsOnPage",
|
||||
"address",
|
||||
"balance",
|
||||
"totalReceived",
|
||||
"totalSent",
|
||||
"unconfirmedBalance",
|
||||
"unconfirmedTxs",
|
||||
"txs",
|
||||
"txids"
|
||||
])
|
||||
assert.isArray(result.txids)
|
||||
})
|
||||
|
||||
it(`should POST request balances for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2",
|
||||
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
|
||||
]
|
||||
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"page",
|
||||
"totalPages",
|
||||
"itemsOnPage",
|
||||
"address",
|
||||
"balance",
|
||||
"totalReceived",
|
||||
"totalSent",
|
||||
"unconfirmedBalance",
|
||||
"unconfirmedTxs",
|
||||
"txs",
|
||||
"txids"
|
||||
])
|
||||
assert.isArray(result[0].txids)
|
||||
})
|
||||
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
try {
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.Blockbook.balance(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input address must be a string or array of strings`
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2")
|
||||
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#utxo`, () => {
|
||||
it(`should GET utxos for a single address`, async () => {
|
||||
const addr = "bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
|
||||
|
||||
const result = await bchjs.Blockbook.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"txid",
|
||||
"vout",
|
||||
"value",
|
||||
"height",
|
||||
"confirmations"
|
||||
])
|
||||
})
|
||||
|
||||
it(`should POST utxo details for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2",
|
||||
"bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2"
|
||||
]
|
||||
|
||||
const result = await bchjs.Blockbook.utxo(addr)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isArray(result[0])
|
||||
assert.hasAnyKeys(result[0][0], [
|
||||
"txid",
|
||||
"vout",
|
||||
"value",
|
||||
"height",
|
||||
"confirmations"
|
||||
])
|
||||
})
|
||||
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
try {
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.Blockbook.utxo(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input address must be a string or array of strings`
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2")
|
||||
|
||||
await bchjs.Blockbook.utxo(addr)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -1,370 +0,0 @@
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const sinon = require("sinon")
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: `https://testnet3.fullstack.cash/v3/`
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
|
||||
describe(`#ElectrumX`, () => {
|
||||
let sandbox
|
||||
|
||||
beforeEach(async () => {
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
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)}`)
|
||||
|
||||
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,
|
||||
"the transaction was rejected by network rules"
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const sinon = require("sinon")
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
const bchjs = new BCHJS({ ninsightURL: "https://trest.bitcoin.com/v2" })
|
||||
|
||||
describe(`#Ninsight`, () => {
|
||||
let sandbox
|
||||
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe(`#utxo`, () => {
|
||||
it(`should GET utxos for a single address`, async () => {
|
||||
const addr = "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr"
|
||||
|
||||
const result = await bchjs.Ninsight.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result[0], "utxos")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "slpAddress")
|
||||
assert.property(result[0], "scriptPubKey")
|
||||
assert.property(result[0], "asm")
|
||||
|
||||
assert.isArray(result[0].utxos)
|
||||
|
||||
assert.property(result[0].utxos[0], "txid")
|
||||
assert.property(result[0].utxos[0], "vout")
|
||||
assert.property(result[0].utxos[0], "amount")
|
||||
assert.property(result[0].utxos[0], "satoshis")
|
||||
assert.property(result[0].utxos[0], "height")
|
||||
assert.property(result[0].utxos[0], "confirmations")
|
||||
})
|
||||
|
||||
it(`should POST utxo details for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
|
||||
"bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isArray(result[0].utxos)
|
||||
|
||||
assert.property(result[0], "utxos")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "slpAddress")
|
||||
assert.property(result[0], "scriptPubKey")
|
||||
assert.property(result[0], "asm")
|
||||
|
||||
// assert.hasAnyKeys(result[0][0], [
|
||||
// "txid",
|
||||
// "vout",
|
||||
// "value",
|
||||
// "height",
|
||||
// "confirmations"
|
||||
// ])
|
||||
})
|
||||
})
|
||||
describe(`#transactions`, () => {
|
||||
it(`should POST transactions history for a single address`, async () => {
|
||||
const addr = "bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr"
|
||||
|
||||
const result = await bchjs.Ninsight.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "txs")
|
||||
assert.isArray(result[0].txs)
|
||||
assert.property(result[0].txs[0], "txid")
|
||||
assert.property(result[0].txs[0], "vin")
|
||||
assert.property(result[0].txs[0], "vout")
|
||||
})
|
||||
it(`should POST transactions history for an array of addresses`, async () => {
|
||||
const addr = [
|
||||
"bchtest:qzjtnzcvzxx7s0na88yrg3zl28wwvfp97538sgrrmr",
|
||||
"bchtest:qp6hgvevf4gzz6l7pgcte3gaaud9km0l459fa23dul"
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], "cashAddress")
|
||||
assert.property(result[0], "legacyAddress")
|
||||
assert.property(result[0], "txs")
|
||||
assert.isArray(result[0].txs)
|
||||
assert.property(result[0].txs[0], "txid")
|
||||
assert.property(result[0].txs[0], "vin")
|
||||
assert.property(result[0].txs[0], "vout")
|
||||
})
|
||||
})
|
||||
describe(`#txDetails`, () => {
|
||||
it(`should POST transactions details for a single address`, async () => {
|
||||
const txid = "76856d82e00b2696acd8d989e1fa6c46b431005046a285ce905814cac0ff8fea"
|
||||
|
||||
const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], "txid")
|
||||
assert.property(result[0], "version")
|
||||
assert.property(result[0], "locktime")
|
||||
assert.property(result[0], "vin")
|
||||
assert.property(result[0], "vout")
|
||||
assert.property(result[0], "blockhash")
|
||||
assert.property(result[0], "blockheight")
|
||||
assert.property(result[0], "confirmations")
|
||||
assert.property(result[0], "time")
|
||||
assert.property(result[0], "blocktime")
|
||||
assert.property(result[0], "valueOut")
|
||||
assert.property(result[0], "size")
|
||||
})
|
||||
it(`should POST transactions details for an array of addresses`, async () => {
|
||||
const txid = [
|
||||
"f191d1062789d7071da6f2168ba306869a829294f6b1c09d03492db4ca3a8e77",
|
||||
"76856d82e00b2696acd8d989e1fa6c46b431005046a285ce905814cac0ff8fea"
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], "txid")
|
||||
assert.property(result[0], "vin")
|
||||
assert.property(result[0], "vout")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -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/v3/`
|
||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
||||
|
||||
const BCHJS = require("../../../src/bch-js")
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v3/` })
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
|
||||
// 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(1000)
|
||||
})
|
||||
|
||||
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))
|
||||
}
|
||||
+38
-38
@@ -3,100 +3,100 @@
|
||||
rest.bitcoin.com.
|
||||
*/
|
||||
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require("util")
|
||||
const util = require('util')
|
||||
util.inspect.defaultOptions = {
|
||||
showHidden: true,
|
||||
colors: true,
|
||||
depth: 3
|
||||
}
|
||||
|
||||
describe(`#util`, () => {
|
||||
describe('#util', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
})
|
||||
|
||||
describe(`#validateAddress`, () => {
|
||||
it(`should return false for testnet addr on mainnet`, async () => {
|
||||
const address = `bchtest:qqqk4y6lsl5da64sg5qc3xezmplyu5kmpyz2ysaa5y`
|
||||
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)}`)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["isvalid"])
|
||||
assert.hasAllKeys(result, ['isvalid'])
|
||||
assert.equal(result.isvalid, false)
|
||||
})
|
||||
|
||||
it(`should return false for bad address`, async () => {
|
||||
const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peu`
|
||||
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)}`)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, ["isvalid"])
|
||||
assert.hasAllKeys(result, ['isvalid'])
|
||||
assert.equal(result.isvalid, false)
|
||||
})
|
||||
|
||||
it(`should validate valid address`, async () => {
|
||||
const address = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`
|
||||
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)}`)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"isvalid",
|
||||
"address",
|
||||
"scriptPubKey",
|
||||
//"ismine",
|
||||
//"iswatchonly",
|
||||
"isscript"
|
||||
'isvalid',
|
||||
'address',
|
||||
'scriptPubKey',
|
||||
// "ismine",
|
||||
// "iswatchonly",
|
||||
'isscript'
|
||||
])
|
||||
assert.equal(result.isvalid, true)
|
||||
})
|
||||
|
||||
it(`should validate an array of addresses`, async () => {
|
||||
it('should validate an array of addresses', async () => {
|
||||
const address = [
|
||||
`bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`,
|
||||
`bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`
|
||||
'bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z',
|
||||
'bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z'
|
||||
]
|
||||
|
||||
const result = await bchjs.Util.validateAddress(address)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"isvalid",
|
||||
"address",
|
||||
"scriptPubKey",
|
||||
//"ismine",
|
||||
//"iswatchonly",
|
||||
"isscript"
|
||||
'isvalid',
|
||||
'address',
|
||||
'scriptPubKey',
|
||||
// "ismine",
|
||||
// "iswatchonly",
|
||||
'isscript'
|
||||
])
|
||||
})
|
||||
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const dataMock = `bitcoincash:qp4k8fjtgunhdr7yq30ha4peuwupzan2vcnwrmpy0z`
|
||||
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!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
assert.include(err.error, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep(ms) {
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
+803
-770
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
|
||||
// Used for debugging and iterrogating JS objects.
|
||||
const util = require("util")
|
||||
util.inspect.defaultOptions = { depth: 1 }
|
||||
|
||||
describe(`#BitboxShim`, () => {
|
||||
it("should create the shim library", () => {
|
||||
const BitboxShim = BCHJS.BitboxShim()
|
||||
const bitbox = new BitboxShim()
|
||||
|
||||
//console.log(`bitbox.Address: ${util.inspect(bitbox.Address)}`)
|
||||
|
||||
assert.hasAnyKeys(bitbox.Address, [
|
||||
// "details",
|
||||
// "utxo",
|
||||
// "unconfirmed",
|
||||
// "transactions",
|
||||
// "toLegacyAddress"
|
||||
"restURL"
|
||||
])
|
||||
})
|
||||
})
|
||||
+56
-56
@@ -1,7 +1,13 @@
|
||||
const fixtures = require("./fixtures/bitcoincash.json")
|
||||
const assert = require("assert")
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
// Public npm libraries
|
||||
const assert = require('assert')
|
||||
|
||||
// Mocks
|
||||
const fixtures = require('./fixtures/bitcoincash.json')
|
||||
|
||||
// Unit under test (uut)
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
// const bchjs = new BCHJS()
|
||||
let bchjs
|
||||
|
||||
// TODO
|
||||
// 1. generate testnet p2sh
|
||||
@@ -19,29 +25,27 @@ const bchjs = new BCHJS()
|
||||
// * confirm xpriv generates WIF
|
||||
// 6. More error test cases.
|
||||
|
||||
describe("#BitcoinCash", () => {
|
||||
describe("price conversion", () => {
|
||||
describe("#toBitcoinCash", () => {
|
||||
describe('#BitcoinCash', () => {
|
||||
beforeEach(() => {
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
|
||||
describe('price conversion', () => {
|
||||
it('should exercise toBitcoinCash', () => {
|
||||
fixtures.conversion.toBCH.satoshis.forEach(satoshi => {
|
||||
it(`should convert ${satoshi[0]} Satoshis to ${
|
||||
satoshi[1]
|
||||
} $BCH`, () => {
|
||||
it(`should convert ${satoshi[0]} Satoshis to ${satoshi[1]} $BCH`, () => {
|
||||
assert.equal(bchjs.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1])
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.conversion.toBCH.strings.forEach(satoshi => {
|
||||
it(`should convert "${satoshi[0]}" Satoshis as a string to ${
|
||||
satoshi[1]
|
||||
} $BCH`, () => {
|
||||
it(`should convert "${satoshi[0]}" Satoshis as a string to ${satoshi[1]} $BCH`, () => {
|
||||
assert.equal(bchjs.BitcoinCash.toBitcoinCash(satoshi[0]), satoshi[1])
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.conversion.toBCH.not.forEach(bch => {
|
||||
it(`converts ${bch[0]} to Bitcoin Cash, not to ${
|
||||
bch[1]
|
||||
} Satoshi`, () => {
|
||||
it(`converts ${bch[0]} to Bitcoin Cash, not to ${bch[1]} Satoshi`, () => {
|
||||
assert.notEqual(bchjs.BitcoinCash.toBitcoinCash(bch[0]), bch[1])
|
||||
})
|
||||
})
|
||||
@@ -53,7 +57,7 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#toSatoshi", () => {
|
||||
it('should exercise toSatoshi', () => {
|
||||
fixtures.conversion.toSatoshi.bch.forEach(bch => {
|
||||
it(`should convert ${bch[0]} $BCH to ${bch[1]} Satoshis`, () => {
|
||||
assert.equal(bchjs.BitcoinCash.toSatoshi(bch[0]), bch[1])
|
||||
@@ -61,17 +65,13 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
|
||||
fixtures.conversion.toSatoshi.strings.forEach(bch => {
|
||||
it(`should convert "${bch[0]}" $BCH as a string to ${
|
||||
bch[1]
|
||||
} Satoshis`, () => {
|
||||
it(`should convert "${bch[0]}" $BCH as a string to ${bch[1]} Satoshis`, () => {
|
||||
assert.equal(bchjs.BitcoinCash.toSatoshi(bch[0]), bch[1])
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.conversion.toSatoshi.not.forEach(satoshi => {
|
||||
it(`converts ${satoshi[0]} to Satoshi, not to ${
|
||||
satoshi[1]
|
||||
} Bitcoin Cash`, () => {
|
||||
it(`converts ${satoshi[0]} to Satoshi, not to ${satoshi[1]} Bitcoin Cash`, () => {
|
||||
assert.notEqual(bchjs.BitcoinCash.toSatoshi(satoshi[0]), satoshi[1])
|
||||
})
|
||||
})
|
||||
@@ -83,7 +83,7 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#satsToBits", () => {
|
||||
it('should exercise satsToBits', () => {
|
||||
fixtures.conversion.satsToBits.bch.forEach(bch => {
|
||||
it(`should convert ${bch[0]} BCH to ${bch[1]} bits`, () => {
|
||||
assert.equal(
|
||||
@@ -94,9 +94,7 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
|
||||
fixtures.conversion.satsToBits.strings.forEach(bch => {
|
||||
it(`should convert "${bch[0]}" BCH as a string to ${
|
||||
bch[1]
|
||||
} bits`, () => {
|
||||
it(`should convert "${bch[0]}" BCH as a string to ${bch[1]} bits`, () => {
|
||||
assert.equal(
|
||||
bchjs.BitcoinCash.satsToBits(bchjs.BitcoinCash.toSatoshi(bch[0])),
|
||||
bch[1]
|
||||
@@ -120,8 +118,8 @@ describe("#BitcoinCash", () => {
|
||||
// });
|
||||
})
|
||||
|
||||
describe("sign and verify messages", () => {
|
||||
describe("#signMessageWithPrivKey", () => {
|
||||
describe('sign and verify messages', () => {
|
||||
it('should exercise signMessageWithPrivKey', () => {
|
||||
fixtures.signatures.sign.forEach(sign => {
|
||||
it(`should sign a message w/ ${sign.network} ${sign.privateKeyWIF}`, () => {
|
||||
const privateKeyWIF = sign.privateKeyWIF
|
||||
@@ -135,7 +133,7 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#verifyMessage", () => {
|
||||
it('shoudl exercise verifyMessage', () => {
|
||||
fixtures.signatures.verify.forEach(sign => {
|
||||
it(`should verify a valid signed message from ${sign.network} cashaddr address ${sign.address}`, () => {
|
||||
assert.equal(
|
||||
@@ -149,28 +147,30 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.signatures.verify.forEach(sign => {
|
||||
const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
|
||||
it(`should verify a valid signed message from ${sign.network} legacy address ${legacyAddress}`, () => {
|
||||
assert.equal(
|
||||
bchjs.BitcoinCash.verifyMessage(
|
||||
legacyAddress,
|
||||
sign.signature,
|
||||
sign.message
|
||||
),
|
||||
true
|
||||
)
|
||||
it('should verify legacy addresses', () => {
|
||||
fixtures.signatures.verify.forEach(sign => {
|
||||
const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
|
||||
it(`should verify a valid signed message from ${sign.network} legacy address ${legacyAddress}`, () => {
|
||||
assert.equal(
|
||||
bchjs.BitcoinCash.verifyMessage(
|
||||
legacyAddress,
|
||||
sign.signature,
|
||||
sign.message
|
||||
),
|
||||
true
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.signatures.verify.forEach(sign => {
|
||||
const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
|
||||
// const legacyAddress = bchjs.Address.toLegacyAddress(sign.address)
|
||||
it(`should not verify an invalid signed message from ${sign.network} cashaddr address ${sign.address}`, () => {
|
||||
assert.equal(
|
||||
bchjs.BitcoinCash.verifyMessage(
|
||||
sign.address,
|
||||
sign.signature,
|
||||
"nope"
|
||||
'nope'
|
||||
),
|
||||
false
|
||||
)
|
||||
@@ -179,8 +179,8 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("encode and decode to base58Check", () => {
|
||||
describe("#encodeBase58Check", () => {
|
||||
describe('encode and decode to base58Check', () => {
|
||||
describe('#encodeBase58Check', () => {
|
||||
fixtures.encodeBase58Check.forEach((base58Check, i) => {
|
||||
it(`encode ${base58Check.hex} as base58Check ${base58Check.base58Check}`, () => {
|
||||
assert.equal(
|
||||
@@ -191,7 +191,7 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#decodeBase58Check", () => {
|
||||
describe('#decodeBase58Check', () => {
|
||||
fixtures.encodeBase58Check.forEach((base58Check, i) => {
|
||||
it(`decode ${base58Check.base58Check} as ${base58Check.hex}`, () => {
|
||||
assert.equal(
|
||||
@@ -203,8 +203,8 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("encode and decode BIP21 urls", () => {
|
||||
describe("#encodeBIP21", () => {
|
||||
describe('encode and decode BIP21 urls', () => {
|
||||
describe('#encodeBIP21', () => {
|
||||
fixtures.bip21.valid.forEach((bip21, i) => {
|
||||
it(`encode ${bip21.address} as url`, () => {
|
||||
const url = bchjs.BitcoinCash.encodeBIP21(
|
||||
@@ -226,7 +226,7 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#decodeBIP21", () => {
|
||||
describe('#decodeBIP21', () => {
|
||||
fixtures.bip21.valid.forEach((bip21, i) => {
|
||||
it(`decodes ${bip21.url}`, () => {
|
||||
const decoded = bchjs.BitcoinCash.decodeBIP21(bip21.url)
|
||||
@@ -252,9 +252,9 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getByteCount", () => {
|
||||
describe('#getByteCount', () => {
|
||||
fixtures.getByteCount.forEach(fixture => {
|
||||
it(`get byte count`, () => {
|
||||
it('get byte count', () => {
|
||||
const byteCount = bchjs.BitcoinCash.getByteCount(
|
||||
fixture.inputs,
|
||||
fixture.outputs
|
||||
@@ -264,8 +264,8 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#bip38", () => {
|
||||
describe("#encryptBIP38", () => {
|
||||
describe('#bip38', () => {
|
||||
describe('#encryptBIP38', () => {
|
||||
fixtures.bip38.encrypt.mainnet.forEach(fixture => {
|
||||
it(`BIP 38 encrypt wif ${fixture.wif} with password ${fixture.password} on mainnet`, () => {
|
||||
const encryptedKey = bchjs.BitcoinCash.encryptBIP38(
|
||||
@@ -287,13 +287,13 @@ describe("#BitcoinCash", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#decryptBIP38", () => {
|
||||
describe('#decryptBIP38', () => {
|
||||
fixtures.bip38.decrypt.mainnet.forEach(fixture => {
|
||||
it(`BIP 38 decrypt encrypted key ${fixture.encryptedKey} on mainnet`, () => {
|
||||
const wif = bchjs.BitcoinCash.decryptBIP38(
|
||||
fixture.encryptedKey,
|
||||
fixture.password,
|
||||
"mainnet"
|
||||
'mainnet'
|
||||
)
|
||||
assert.equal(wif, fixture.wif)
|
||||
})
|
||||
@@ -304,7 +304,7 @@ describe("#BitcoinCash", () => {
|
||||
const wif = bchjs.BitcoinCash.decryptBIP38(
|
||||
fixture.encryptedKey,
|
||||
fixture.password,
|
||||
"testnet"
|
||||
'testnet'
|
||||
)
|
||||
assert.equal(wif, fixture.wif)
|
||||
})
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
const chai = require("chai")
|
||||
const assert = chai.assert
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
const axios = require("axios")
|
||||
const sinon = require("sinon")
|
||||
|
||||
const mockData = require("./fixtures/blockbook-mock")
|
||||
|
||||
describe(`#Blockbook`, () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe(`#Balance`, () => {
|
||||
it(`should GET balance for a single address`, async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "get").resolves({ data: mockData.balance })
|
||||
|
||||
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
|
||||
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.hasAnyKeys(result, [
|
||||
"page",
|
||||
"totalPages",
|
||||
"itemsOnPage",
|
||||
"address",
|
||||
"balance",
|
||||
"totalReceived",
|
||||
"totalSent",
|
||||
"unconfirmedBalance",
|
||||
"unconfirmedTxs",
|
||||
"txs",
|
||||
"txids"
|
||||
])
|
||||
assert.isArray(result.txids)
|
||||
})
|
||||
|
||||
it(`should POST request balances for an array of addresses`, async () => {
|
||||
// Stub the network call.
|
||||
sandbox
|
||||
.stub(axios, "post")
|
||||
.resolves({ data: [mockData.balance, mockData.balance] })
|
||||
|
||||
const addr = [
|
||||
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
]
|
||||
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
//console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"page",
|
||||
"totalPages",
|
||||
"itemsOnPage",
|
||||
"address",
|
||||
"balance",
|
||||
"totalReceived",
|
||||
"totalSent",
|
||||
"unconfirmedBalance",
|
||||
"unconfirmedTxs",
|
||||
"txs",
|
||||
"txids"
|
||||
])
|
||||
assert.isArray(result[0].txids)
|
||||
})
|
||||
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
try {
|
||||
// Stub the network call.
|
||||
sandbox
|
||||
.stub(axios, "post")
|
||||
.throws(`Input address must be a string or array of strings`)
|
||||
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.Blockbook.balance(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input address must be a string or array of strings`
|
||||
)
|
||||
}
|
||||
})
|
||||
/*
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "post").throws(`Array too large`)
|
||||
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
|
||||
|
||||
const result = await bchjs.Blockbook.balance(addr)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
*/
|
||||
})
|
||||
|
||||
describe(`#utxo`, () => {
|
||||
it(`should GET utxos for a single address`, async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "get").resolves({ data: mockData.utxo })
|
||||
|
||||
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
|
||||
|
||||
const result = await bchjs.Blockbook.utxo(addr)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"txid",
|
||||
"vout",
|
||||
"value",
|
||||
"height",
|
||||
"confirmations"
|
||||
])
|
||||
})
|
||||
|
||||
it(`should POST utxo details for an array of addresses`, async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "post").resolves({ data: mockData.utxos })
|
||||
|
||||
const addr = [
|
||||
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
]
|
||||
|
||||
const result = await bchjs.Blockbook.utxo(addr)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.isArray(result[0])
|
||||
assert.hasAnyKeys(result[0][0], [
|
||||
"txid",
|
||||
"vout",
|
||||
"value",
|
||||
"height",
|
||||
"confirmations"
|
||||
])
|
||||
})
|
||||
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
try {
|
||||
// Stub the network call.
|
||||
sandbox
|
||||
.stub(axios, "post")
|
||||
.throws(`Input address must be a string or array of strings`)
|
||||
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.Blockbook.utxo(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
//console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input address must be a string or array of strings`
|
||||
)
|
||||
}
|
||||
})
|
||||
/*
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
|
||||
|
||||
const result = await bchjs.Blockbook.utxo(addr)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
*/
|
||||
})
|
||||
|
||||
describe(`#tx`, () => {
|
||||
it(`should GET tx details for a single txid`, async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "get").resolves({ data: mockData.utxo })
|
||||
|
||||
const addr = "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf"
|
||||
|
||||
const result = await bchjs.Blockbook.utxo(addr)
|
||||
//console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.hasAnyKeys(result[0], [
|
||||
"txid",
|
||||
"vout",
|
||||
"value",
|
||||
"height",
|
||||
"confirmations"
|
||||
])
|
||||
})
|
||||
|
||||
// it(`should POST utxo details for an array of addresses`, async () => {
|
||||
// // Stub the network call.
|
||||
// sandbox.stub(axios, "post").resolves({ data: mockData.utxos })
|
||||
//
|
||||
// const addr = [
|
||||
// "bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
// "bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
// ]
|
||||
//
|
||||
// const result = await bchjs.Blockbook.utxo(addr)
|
||||
// //console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
//
|
||||
// assert.isArray(result)
|
||||
// assert.isArray(result[0])
|
||||
// assert.hasAnyKeys(result[0][0], [
|
||||
// "txid",
|
||||
// "vout",
|
||||
// "value",
|
||||
// "height",
|
||||
// "confirmations"
|
||||
// ])
|
||||
// })
|
||||
|
||||
// it(`should throw an error for improper input`, async () => {
|
||||
// try {
|
||||
// // Stub the network call.
|
||||
// sandbox
|
||||
// .stub(axios, "post")
|
||||
// .throws(`Input address must be a string or array of strings`)
|
||||
//
|
||||
// const addr = 12345
|
||||
//
|
||||
// await bchjs.Blockbook.utxo(addr)
|
||||
// assert.equal(true, false, "Unexpected result!")
|
||||
// } catch (err) {
|
||||
// //console.log(`err: `, err)
|
||||
// assert.include(
|
||||
// err.message,
|
||||
// `Input address must be a string or array of strings`
|
||||
// )
|
||||
// }
|
||||
// })
|
||||
|
||||
/*
|
||||
it(`should throw error on array size rate limit`, async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++)
|
||||
addr.push("bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf")
|
||||
|
||||
const result = await bchjs.Blockbook.utxo(addr)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ["error"])
|
||||
assert.include(err.error, "Array too large")
|
||||
}
|
||||
})
|
||||
*/
|
||||
})
|
||||
})
|
||||
+149
-146
@@ -1,102 +1,102 @@
|
||||
const assert = require("assert")
|
||||
const assert2 = require("chai").assert
|
||||
const axios = require("axios")
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
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")
|
||||
const sinon = require('sinon')
|
||||
|
||||
const mockData = require("./fixtures/blockchain-mock")
|
||||
const mockData = require('./fixtures/blockchain-mock')
|
||||
|
||||
describe("#Blockchain", () => {
|
||||
describe("#getBestBlockHash", () => {
|
||||
describe('#Blockchain', () => {
|
||||
describe('#getBestBlockHash', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
it("should get best block hash", done => {
|
||||
const resolved = new Promise(r =>
|
||||
r({
|
||||
it('should get best block hash', done => {
|
||||
const resolved = new Promise(resolve =>
|
||||
resolve({
|
||||
data:
|
||||
"0000000000000000005f1f550d3d8b142b684277016ebd00fa29c668606ae52d"
|
||||
'0000000000000000005f1f550d3d8b142b684277016ebd00fa29c668606ae52d'
|
||||
})
|
||||
)
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getBestBlockHash()
|
||||
.then(result => {
|
||||
const hash =
|
||||
"0000000000000000005f1f550d3d8b142b684277016ebd00fa29c668606ae52d"
|
||||
assert.equal(hash, result)
|
||||
'0000000000000000005f1f550d3d8b142b684277016ebd00fa29c668606ae52d'
|
||||
assert.strictEqual(hash, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getBlock", () => {
|
||||
describe('#getBlock', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
const data = {
|
||||
hash: "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09",
|
||||
hash: '00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09',
|
||||
confirmations: 526807,
|
||||
size: 216,
|
||||
height: 1000,
|
||||
version: 1,
|
||||
versionHex: "00000001",
|
||||
versionHex: '00000001',
|
||||
merkleroot:
|
||||
"fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33",
|
||||
tx: ["fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33"],
|
||||
'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33',
|
||||
tx: ['fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33'],
|
||||
time: 1232346882,
|
||||
mediantime: 1232344831,
|
||||
nonce: 2595206198,
|
||||
bits: "1d00ffff",
|
||||
bits: '1d00ffff',
|
||||
difficulty: 1,
|
||||
chainwork:
|
||||
"000000000000000000000000000000000000000000000000000003e903e903e9",
|
||||
'000000000000000000000000000000000000000000000000000003e903e903e9',
|
||||
previousblockhash:
|
||||
"0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d",
|
||||
'0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d',
|
||||
nextblockhash:
|
||||
"00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6"
|
||||
'00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6'
|
||||
}
|
||||
|
||||
it("should get block by hash", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should get block by hash', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getBlock(
|
||||
"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"
|
||||
'00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09'
|
||||
)
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getBlockchainInfo", () => {
|
||||
describe('#getBlockchainInfo', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
const data = {
|
||||
chain: "main",
|
||||
chain: 'main',
|
||||
blocks: 527810,
|
||||
headers: 527810,
|
||||
bestblockhash:
|
||||
"000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0",
|
||||
'000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0',
|
||||
difficulty: 576023394804.6666,
|
||||
mediantime: 1524878499,
|
||||
verificationprogress: 0.9999990106793685,
|
||||
chainwork:
|
||||
"00000000000000000000000000000000000000000096da5b040913fa09249b4e",
|
||||
'00000000000000000000000000000000000000000096da5b040913fa09249b4e',
|
||||
pruned: false,
|
||||
softforks: [
|
||||
{ id: "bip34", version: 2, reject: [Object] },
|
||||
{ id: "bip66", version: 3, reject: [Object] },
|
||||
{ id: "bip65", version: 4, reject: [Object] }
|
||||
{ id: 'bip34', version: 2, reject: [Object] },
|
||||
{ id: 'bip66', version: 3, reject: [Object] },
|
||||
{ id: 'bip65', version: 4, reject: [Object] }
|
||||
],
|
||||
bip9_softforks: {
|
||||
csv: {
|
||||
status: "active",
|
||||
status: 'active',
|
||||
startTime: 1462060800,
|
||||
timeout: 1493596800,
|
||||
since: 419328
|
||||
@@ -104,178 +104,178 @@ describe("#Blockchain", () => {
|
||||
}
|
||||
}
|
||||
|
||||
it("should get blockchain info", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should get blockchain info', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getBlockchainInfo()
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getBlockCount", () => {
|
||||
describe('#getBlockCount', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
const data = 527810
|
||||
|
||||
it("should get block count", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should get block count', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getBlockCount()
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getBlockHash", () => {
|
||||
describe('#getBlockHash', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
const data =
|
||||
"000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0"
|
||||
'000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0'
|
||||
|
||||
it("should get block hash by height", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should get block hash by height', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getBlockHash(527810)
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getBlockHeader", () => {
|
||||
describe('#getBlockHeader', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
const data = {
|
||||
hash: "000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0",
|
||||
hash: '000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0',
|
||||
confirmations: 1,
|
||||
height: 527810,
|
||||
version: 536870912,
|
||||
versionHex: "20000000",
|
||||
versionHex: '20000000',
|
||||
merkleroot:
|
||||
"9298432bbebe4638456aa19cb7ef91639da87668a285d88d0ecd6080424d223b",
|
||||
'9298432bbebe4638456aa19cb7ef91639da87668a285d88d0ecd6080424d223b',
|
||||
time: 1524881438,
|
||||
mediantime: 1524878499,
|
||||
nonce: 3326843941,
|
||||
bits: "1801e8a5",
|
||||
bits: '1801e8a5',
|
||||
difficulty: 576023394804.6666,
|
||||
chainwork:
|
||||
"00000000000000000000000000000000000000000096da5b040913fa09249b4e",
|
||||
'00000000000000000000000000000000000000000096da5b040913fa09249b4e',
|
||||
previousblockhash:
|
||||
"000000000000000000b33251708bc7a7b4540e61880d8c376e8e2db6a19a4789"
|
||||
'000000000000000000b33251708bc7a7b4540e61880d8c376e8e2db6a19a4789'
|
||||
}
|
||||
|
||||
it("should get block header by hash", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should get block header by hash', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getBlockHeader(
|
||||
"000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0",
|
||||
'000000000000000001d127592d091d4c45062504663c9acab27a1b16c028e3c0',
|
||||
true
|
||||
)
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getDifficulty", () => {
|
||||
describe('#getDifficulty', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
const data = "577528469277.1339"
|
||||
const data = '577528469277.1339'
|
||||
|
||||
it("should get difficulty", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should get difficulty', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getDifficulty()
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getMempoolAncestors", () => {
|
||||
describe('#getMempoolAncestors', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
const data = "Transaction not in mempool"
|
||||
const data = 'Transaction not in mempool'
|
||||
|
||||
it("should get mempool ancestors", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should get mempool ancestors', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getMempoolAncestors(
|
||||
"daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88",
|
||||
'daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88',
|
||||
true
|
||||
)
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getMempoolDescendants", () => {
|
||||
describe('#getMempoolDescendants', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
const data = {
|
||||
result: "Transaction not in mempool"
|
||||
result: 'Transaction not in mempool'
|
||||
}
|
||||
|
||||
it("should get mempool descendants", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should get mempool descendants', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getMempoolDescendants(
|
||||
"daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88",
|
||||
'daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88',
|
||||
true
|
||||
)
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getMempoolEntry", () => {
|
||||
describe('#getMempoolEntry', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
const data = {
|
||||
result: "Transaction not in mempool"
|
||||
result: 'Transaction not in mempool'
|
||||
}
|
||||
|
||||
it("should get mempool entry", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should get mempool entry', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getMempoolEntry(
|
||||
"daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88"
|
||||
'daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88'
|
||||
)
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getMempoolInfo", () => {
|
||||
describe('#getMempoolInfo', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
@@ -289,19 +289,19 @@ describe("#Blockchain", () => {
|
||||
}
|
||||
}
|
||||
|
||||
it("should get mempool info", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should get mempool info', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getMempoolInfo()
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getRawMempool", () => {
|
||||
describe('#getRawMempool', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
@@ -310,7 +310,7 @@ describe("#Blockchain", () => {
|
||||
transactions: [
|
||||
{
|
||||
txid:
|
||||
"ab36d68dd0a618592fe34e4a898e8beeeb4049133547dbb16f9338384084af96",
|
||||
'ab36d68dd0a618592fe34e4a898e8beeeb4049133547dbb16f9338384084af96',
|
||||
size: 191,
|
||||
fee: 0.00047703,
|
||||
modifiedfee: 0.00047703,
|
||||
@@ -330,19 +330,19 @@ describe("#Blockchain", () => {
|
||||
}
|
||||
}
|
||||
|
||||
it("should get mempool info", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should get mempool info', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getRawMempool()
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getTxOut", () => {
|
||||
describe('#getTxOut', () => {
|
||||
// TODO finish this test
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
@@ -351,63 +351,66 @@ describe("#Blockchain", () => {
|
||||
// result: {}
|
||||
// }
|
||||
|
||||
it("should throw an error for improper txid.", async () => {
|
||||
it('should throw an error for improper txid.', async () => {
|
||||
try {
|
||||
await bchjs.Blockchain.getTxOut("badtxid")
|
||||
await bchjs.Blockchain.getTxOut('badtxid')
|
||||
} catch (err) {
|
||||
assert2.include(err.message, "txid needs to be a proper transaction ID")
|
||||
assert2.include(
|
||||
err.message,
|
||||
'txid needs to be a proper transaction ID'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it("should throw an error if no vout value is provided.", async () => {
|
||||
it('should throw an error if no vout value is provided.', async () => {
|
||||
try {
|
||||
await bchjs.Blockchain.getTxOut(
|
||||
"daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88"
|
||||
'daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88'
|
||||
)
|
||||
} catch (err) {
|
||||
assert2.include(err.message, "n must be an integer")
|
||||
assert2.include(err.message, 'n must be an integer')
|
||||
}
|
||||
})
|
||||
|
||||
it("should throw an error if include_mempool is not a boolean", async () => {
|
||||
it('should throw an error if include_mempool is not a boolean', async () => {
|
||||
try {
|
||||
await bchjs.Blockchain.getTxOut(
|
||||
"daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88",
|
||||
'daf58932cb91619304dd4cbd03c7202e89ad7d6cbd6e2209e5f64ce3b6ed7c88',
|
||||
0,
|
||||
"bad value"
|
||||
'bad value'
|
||||
)
|
||||
} catch (err) {
|
||||
assert2.include(
|
||||
err.message,
|
||||
"include_mempool input must be of type boolean"
|
||||
'includeMempool input must be of type boolean'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it("should get information on an unspent tx", async () => {
|
||||
sandbox.stub(axios, "post").resolves({ data: mockData.txOutUnspent })
|
||||
it('should get information on an unspent tx', async () => {
|
||||
sandbox.stub(axios, 'post').resolves({ data: mockData.txOutUnspent })
|
||||
|
||||
const result = await bchjs.Blockchain.getTxOut(
|
||||
"62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8",
|
||||
'62a3ea958a463a372bc0caf2c374a7f60be9c624be63a0db8db78f05809df6d8',
|
||||
0,
|
||||
true
|
||||
)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert2.hasAllKeys(result, [
|
||||
"bestblock",
|
||||
"confirmations",
|
||||
"value",
|
||||
"scriptPubKey",
|
||||
"coinbase"
|
||||
'bestblock',
|
||||
'confirmations',
|
||||
'value',
|
||||
'scriptPubKey',
|
||||
'coinbase'
|
||||
])
|
||||
})
|
||||
|
||||
it("should get information on a spent tx", async () => {
|
||||
sandbox.stub(axios, "post").resolves({ data: null })
|
||||
it('should get information on a spent tx', async () => {
|
||||
sandbox.stub(axios, 'post').resolves({ data: null })
|
||||
|
||||
const result = await bchjs.Blockchain.getTxOut(
|
||||
"87380e52d151856b23173d6d8a3db01b984c6b50f77ea045a5a1cf4f54497871",
|
||||
'87380e52d151856b23173d6d8a3db01b984c6b50f77ea045a5a1cf4f54497871',
|
||||
0,
|
||||
true
|
||||
)
|
||||
@@ -417,7 +420,7 @@ describe("#Blockchain", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#preciousBlock", () => {
|
||||
describe('#preciousBlock', () => {
|
||||
// TODO finish this test
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
@@ -426,67 +429,67 @@ describe("#Blockchain", () => {
|
||||
result: {}
|
||||
}
|
||||
|
||||
it("should get TODO", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should get TODO', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.preciousBlock()
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#pruneBlockchain", () => {
|
||||
describe('#pruneBlockchain', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
const data = "Cannot prune blocks because node is not in prune mode."
|
||||
const data = 'Cannot prune blocks because node is not in prune mode.'
|
||||
|
||||
it("should prune blockchain", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "post").returns(resolved)
|
||||
it('should prune blockchain', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'post').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.pruneBlockchain(507)
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#verifyChain", () => {
|
||||
describe('#verifyChain', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
const data = true
|
||||
|
||||
it("should verify blockchain", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should verify blockchain', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.verifyChain(3, 6)
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#verifyTxOutProof", () => {
|
||||
describe('#verifyTxOutProof', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
const data = "proof must be hexadecimal string (not '')"
|
||||
|
||||
it("should verify utxo proof", done => {
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
it('should verify utxo proof', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.verifyTxOutProof("3")
|
||||
bchjs.Blockchain.verifyTxOutProof('3')
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
|
||||
+17
-17
@@ -1,46 +1,46 @@
|
||||
const assert = require("assert")
|
||||
const axios = require("axios")
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const assert = require('assert')
|
||||
const axios = require('axios')
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
const sinon = require("sinon")
|
||||
const sinon = require('sinon')
|
||||
|
||||
describe("#Control", () => {
|
||||
describe("#getNetworkInfo", () => {
|
||||
describe('#Control', () => {
|
||||
describe('#getNetworkInfo', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
it("should get info", done => {
|
||||
it('should get info', done => {
|
||||
const data = {
|
||||
version: 170000,
|
||||
protocolversion: 70015,
|
||||
blocks: 527813,
|
||||
timeoffset: 0,
|
||||
connections: 21,
|
||||
proxy: "",
|
||||
proxy: '',
|
||||
difficulty: 581086703759.5878,
|
||||
testnet: false,
|
||||
paytxfee: 0,
|
||||
relayfee: 0.00001,
|
||||
errors: ""
|
||||
errors: ''
|
||||
}
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Control.getNetworkInfo()
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#getMemoryInfo", () => {
|
||||
describe('#getMemoryInfo', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
it("should get memory info", done => {
|
||||
it('should get memory info', done => {
|
||||
const data = {
|
||||
locked: {
|
||||
used: 0,
|
||||
@@ -51,12 +51,12 @@ describe("#Control", () => {
|
||||
chunks_free: 1
|
||||
}
|
||||
}
|
||||
const resolved = new Promise(r => r({ data: data }))
|
||||
sandbox.stub(axios, "get").returns(resolved)
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
|
||||
bchjs.Control.getMemoryInfo()
|
||||
.then(result => {
|
||||
assert.deepEqual(data, result)
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
|
||||
+35
-35
@@ -1,97 +1,97 @@
|
||||
const fixtures = require("./fixtures/crypto.json")
|
||||
const assert = require("assert")
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
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
|
||||
const Buffer = require('safe-buffer').Buffer
|
||||
|
||||
describe("#Crypto", () => {
|
||||
describe("#sha256", () => {
|
||||
describe('#Crypto', () => {
|
||||
describe('#sha256', () => {
|
||||
fixtures.sha256.forEach(fixture => {
|
||||
it(`should create SHA256Hash hex encoded ${fixture.hash} from ${fixture.hex}`, () => {
|
||||
const data = Buffer.from(fixture.hex, "hex")
|
||||
const sha256Hash = bchjs.Crypto.sha256(data).toString("hex")
|
||||
const data = Buffer.from(fixture.hex, 'hex')
|
||||
const sha256Hash = bchjs.Crypto.sha256(data).toString('hex')
|
||||
assert.equal(sha256Hash, fixture.hash)
|
||||
})
|
||||
|
||||
it(`should create 64 character SHA256Hash hex encoded`, () => {
|
||||
const data = Buffer.from(fixture.hex, "hex")
|
||||
const sha256Hash = bchjs.Crypto.sha256(data).toString("hex")
|
||||
it('should create 64 character SHA256Hash hex encoded', () => {
|
||||
const data = Buffer.from(fixture.hex, 'hex')
|
||||
const sha256Hash = bchjs.Crypto.sha256(data).toString('hex')
|
||||
assert.equal(sha256Hash.length, 64)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#ripemd160", () => {
|
||||
describe('#ripemd160', () => {
|
||||
fixtures.ripemd160.forEach(fixture => {
|
||||
it(`should create RIPEMD160Hash hex encoded ${fixture.hash} from ${fixture.hex}`, () => {
|
||||
const data = Buffer.from(fixture.hex, "hex")
|
||||
const ripemd160 = bchjs.Crypto.ripemd160(data).toString("hex")
|
||||
const data = Buffer.from(fixture.hex, 'hex')
|
||||
const ripemd160 = bchjs.Crypto.ripemd160(data).toString('hex')
|
||||
assert.equal(ripemd160, fixture.hash)
|
||||
})
|
||||
|
||||
it(`should create 64 character RIPEMD160Hash hex encoded`, () => {
|
||||
const data = Buffer.from(fixture.hex, "hex")
|
||||
const ripemd160 = bchjs.Crypto.ripemd160(data).toString("hex")
|
||||
it('should create 64 character RIPEMD160Hash hex encoded', () => {
|
||||
const data = Buffer.from(fixture.hex, 'hex')
|
||||
const ripemd160 = bchjs.Crypto.ripemd160(data).toString('hex')
|
||||
assert.equal(ripemd160.length, 40)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#hash256", () => {
|
||||
describe('#hash256', () => {
|
||||
fixtures.hash256.forEach(fixture => {
|
||||
it(`should create double SHA256 Hash hex encoded ${fixture.hash} from ${fixture.hex}`, () => {
|
||||
const data = Buffer.from(fixture.hex, "hex")
|
||||
const hash256 = bchjs.Crypto.hash256(data).toString("hex")
|
||||
const data = Buffer.from(fixture.hex, 'hex')
|
||||
const hash256 = bchjs.Crypto.hash256(data).toString('hex')
|
||||
assert.equal(hash256, fixture.hash)
|
||||
})
|
||||
|
||||
it(`should create 64 character SHA256 Hash hex encoded`, () => {
|
||||
const data = Buffer.from(fixture.hex, "hex")
|
||||
const hash256 = bchjs.Crypto.hash256(data).toString("hex")
|
||||
it('should create 64 character SHA256 Hash hex encoded', () => {
|
||||
const data = Buffer.from(fixture.hex, 'hex')
|
||||
const hash256 = bchjs.Crypto.hash256(data).toString('hex')
|
||||
assert.equal(hash256.length, 64)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#hash160", () => {
|
||||
describe('#hash160', () => {
|
||||
fixtures.hash160.forEach(fixture => {
|
||||
it(`should create RIPEMD160(SHA256()) hex encoded ${fixture.hash} from ${fixture.hex}`, () => {
|
||||
const data = Buffer.from(fixture.hex, "hex")
|
||||
const hash160 = bchjs.Crypto.hash160(data).toString("hex")
|
||||
const data = Buffer.from(fixture.hex, 'hex')
|
||||
const hash160 = bchjs.Crypto.hash160(data).toString('hex')
|
||||
assert.equal(hash160, fixture.hash)
|
||||
})
|
||||
|
||||
it(`should create 64 character SHA256Hash hex encoded`, () => {
|
||||
const data = Buffer.from(fixture.hex, "hex")
|
||||
const hash160 = bchjs.Crypto.hash160(data).toString("hex")
|
||||
it('should create 64 character SHA256Hash hex encoded', () => {
|
||||
const data = Buffer.from(fixture.hex, 'hex')
|
||||
const hash160 = bchjs.Crypto.hash160(data).toString('hex')
|
||||
assert.equal(hash160.length, 40)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#randomBytes", () => {
|
||||
describe('#randomBytes', () => {
|
||||
for (let i = 0; i < 6; i++) {
|
||||
it("should return 16 bytes of entropy hex encoded", () => {
|
||||
it('should return 16 bytes of entropy hex encoded', () => {
|
||||
const entropy = bchjs.Crypto.randomBytes(16)
|
||||
assert.equal(Buffer.byteLength(entropy), 16)
|
||||
})
|
||||
|
||||
it("should return 20 bytes of entropy hex encoded", () => {
|
||||
it('should return 20 bytes of entropy hex encoded', () => {
|
||||
const entropy = bchjs.Crypto.randomBytes(20)
|
||||
assert.equal(Buffer.byteLength(entropy), 20)
|
||||
})
|
||||
|
||||
it("should return 24 bytes of entropy hex encoded", () => {
|
||||
it('should return 24 bytes of entropy hex encoded', () => {
|
||||
const entropy = bchjs.Crypto.randomBytes(24)
|
||||
assert.equal(Buffer.byteLength(entropy), 24)
|
||||
})
|
||||
|
||||
it("should return 28 bytes of entropy hex encoded", () => {
|
||||
it('should return 28 bytes of entropy hex encoded', () => {
|
||||
const entropy = bchjs.Crypto.randomBytes(28)
|
||||
assert.equal(Buffer.byteLength(entropy), 28)
|
||||
})
|
||||
|
||||
it("should return 32 bytes of entropy hex encoded", () => {
|
||||
it('should return 32 bytes of entropy hex encoded', () => {
|
||||
const entropy = bchjs.Crypto.randomBytes(32)
|
||||
assert.equal(Buffer.byteLength(entropy), 32)
|
||||
})
|
||||
|
||||
+37
-30
@@ -1,18 +1,25 @@
|
||||
const assert = require("assert")
|
||||
// Public npm libraries.
|
||||
const assert = require('assert')
|
||||
const Buffer = require('safe-buffer').Buffer
|
||||
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const bchjs = new BCHJS()
|
||||
// Mocks
|
||||
const fixtures = require('./fixtures/ecpair.json')
|
||||
|
||||
const Buffer = require("safe-buffer").Buffer
|
||||
// Unit under test (uut)
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
// const bchjs = new BCHJS()
|
||||
let bchjs
|
||||
|
||||
const fixtures = require("./fixtures/ecpair.json")
|
||||
describe('#ECPair', () => {
|
||||
beforeEach(() => {
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
|
||||
describe("#ECPair", () => {
|
||||
describe("#fromWIF", () => {
|
||||
describe('#fromWIF', () => {
|
||||
fixtures.fromWIF.forEach(fixture => {
|
||||
it(`should create ECPair from WIF ${fixture.privateKeyWIF}`, () => {
|
||||
const ecpair = bchjs.ECPair.fromWIF(fixture.privateKeyWIF)
|
||||
assert.equal(typeof ecpair, "object")
|
||||
assert.equal(typeof ecpair, 'object')
|
||||
})
|
||||
|
||||
it(`should get ${fixture.legacy} legacy address`, () => {
|
||||
@@ -35,7 +42,7 @@ describe("#ECPair", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#toWIF", () => {
|
||||
describe('#toWIF', () => {
|
||||
fixtures.toWIF.forEach(fixture => {
|
||||
it(`should get WIF ${fixture.privateKeyWIF} from ECPair`, () => {
|
||||
const ecpair = bchjs.ECPair.fromWIF(fixture.privateKeyWIF)
|
||||
@@ -45,32 +52,32 @@ describe("#ECPair", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#fromPublicKey", () => {
|
||||
describe('#fromPublicKey', () => {
|
||||
fixtures.fromPublicKey.forEach(fixture => {
|
||||
it(`should create ECPair from public key buffer`, () => {
|
||||
it('should create ECPair from public key buffer', () => {
|
||||
const ecpair = bchjs.ECPair.fromPublicKey(
|
||||
Buffer.from(fixture.pubkeyHex, "hex")
|
||||
Buffer.from(fixture.pubkeyHex, 'hex')
|
||||
)
|
||||
assert.equal(typeof ecpair, "object")
|
||||
assert.equal(typeof ecpair, 'object')
|
||||
})
|
||||
|
||||
it(`should get ${fixture.legacy} legacy address`, () => {
|
||||
const ecpair = bchjs.ECPair.fromPublicKey(
|
||||
Buffer.from(fixture.pubkeyHex, "hex")
|
||||
Buffer.from(fixture.pubkeyHex, 'hex')
|
||||
)
|
||||
assert.equal(bchjs.HDNode.toLegacyAddress(ecpair), fixture.legacy)
|
||||
})
|
||||
|
||||
it(`should get ${fixture.cashAddr} cash address`, () => {
|
||||
const ecpair = bchjs.ECPair.fromPublicKey(
|
||||
Buffer.from(fixture.pubkeyHex, "hex")
|
||||
Buffer.from(fixture.pubkeyHex, 'hex')
|
||||
)
|
||||
assert.equal(bchjs.HDNode.toCashAddress(ecpair), fixture.cashAddr)
|
||||
})
|
||||
|
||||
it(`should get ${fixture.regtestAddr} cash address`, () => {
|
||||
const ecpair = bchjs.ECPair.fromPublicKey(
|
||||
Buffer.from(fixture.pubkeyHex, "hex")
|
||||
Buffer.from(fixture.pubkeyHex, 'hex')
|
||||
)
|
||||
assert.equal(
|
||||
bchjs.HDNode.toCashAddress(ecpair, true),
|
||||
@@ -80,19 +87,19 @@ describe("#ECPair", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#toPublicKey", () => {
|
||||
describe('#toPublicKey', () => {
|
||||
fixtures.toPublicKey.forEach(fixture => {
|
||||
it(`should create a public key buffer from an ECPair`, () => {
|
||||
it('should create a public key buffer from an ECPair', () => {
|
||||
const ecpair = bchjs.ECPair.fromPublicKey(
|
||||
Buffer.from(fixture.pubkeyHex, "hex")
|
||||
Buffer.from(fixture.pubkeyHex, 'hex')
|
||||
)
|
||||
const pubkeyBuffer = bchjs.ECPair.toPublicKey(ecpair)
|
||||
assert.equal(typeof pubkeyBuffer, "object")
|
||||
assert.equal(typeof pubkeyBuffer, 'object')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#toLegacyAddress", () => {
|
||||
describe('#toLegacyAddress', () => {
|
||||
fixtures.toLegacyAddress.forEach(fixture => {
|
||||
it(`should create legacy address ${fixture.legacy} from an ECPair`, () => {
|
||||
const ecpair = bchjs.ECPair.fromWIF(fixture.privateKeyWIF)
|
||||
@@ -102,7 +109,7 @@ describe("#ECPair", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#toCashAddress", () => {
|
||||
describe('#toCashAddress', () => {
|
||||
fixtures.toCashAddress.forEach(fixture => {
|
||||
it(`should create cash address ${fixture.cashAddr} from an ECPair`, () => {
|
||||
const ecpair = bchjs.ECPair.fromWIF(fixture.privateKeyWIF)
|
||||
@@ -120,23 +127,23 @@ describe("#ECPair", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("#sign", () => {
|
||||
describe('#sign', () => {
|
||||
fixtures.sign.forEach(fixture => {
|
||||
it(`should sign 32 byte hash buffer`, () => {
|
||||
it('should sign 32 byte hash buffer', () => {
|
||||
const ecpair = bchjs.ECPair.fromWIF(fixture.privateKeyWIF)
|
||||
const buf = Buffer.from(bchjs.Crypto.sha256(fixture.data), "hex")
|
||||
const buf = Buffer.from(bchjs.Crypto.sha256(fixture.data), 'hex')
|
||||
const signatureBuf = bchjs.ECPair.sign(ecpair, buf)
|
||||
assert.equal(typeof signatureBuf, "object")
|
||||
assert.equal(typeof signatureBuf, 'object')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("#verify", () => {
|
||||
describe('#verify', () => {
|
||||
fixtures.verify.forEach(fixture => {
|
||||
it(`should verify signed 32 byte hash buffer`, () => {
|
||||
it('should verify signed 32 byte hash buffer', () => {
|
||||
const ecpair1 = bchjs.ECPair.fromWIF(fixture.privateKeyWIF1)
|
||||
//const ecpair2 = bchjs.ECPair.fromWIF(fixture.privateKeyWIF2)
|
||||
const buf = Buffer.from(bchjs.Crypto.sha256(fixture.data), "hex")
|
||||
// const ecpair2 = bchjs.ECPair.fromWIF(fixture.privateKeyWIF2)
|
||||
const buf = Buffer.from(bchjs.Crypto.sha256(fixture.data), 'hex')
|
||||
const signature = bchjs.ECPair.sign(ecpair1, buf)
|
||||
const verify = bchjs.ECPair.verify(ecpair1, buf, signature)
|
||||
assert.equal(verify, true)
|
||||
|
||||
+145
-145
@@ -1,275 +1,275 @@
|
||||
const chai = require("chai")
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const axios = require("axios")
|
||||
const sinon = require("sinon")
|
||||
const axios = require('axios')
|
||||
const sinon = require('sinon')
|
||||
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
const mockData = require("./fixtures/electrumx-mock")
|
||||
const mockData = require('./fixtures/electrumx-mock')
|
||||
|
||||
describe(`#ElectrumX`, () => {
|
||||
describe('#ElectrumX', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe(`#utxo`, () => {
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
describe('#utxo', () => {
|
||||
it('should throw an error for improper input', async () => {
|
||||
try {
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.Electrumx.utxo(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input address must be a string or array of strings`
|
||||
'Input address must be a string or array of strings'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should GET utxos for a single address`, async () => {
|
||||
it('should GET utxos for a single address', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "get").resolves({ data: mockData.utxo })
|
||||
sandbox.stub(axios, 'get').resolves({ data: mockData.utxo })
|
||||
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.Electrumx.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "utxos")
|
||||
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")
|
||||
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 () => {
|
||||
it('should POST utxo details for an array of addresses', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "post").resolves({ data: mockData.utxos })
|
||||
sandbox.stub(axios, 'post').resolves({ data: mockData.utxos })
|
||||
|
||||
const addr = [
|
||||
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
|
||||
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.utxo(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "utxos")
|
||||
assert.property(result, 'utxos')
|
||||
assert.isArray(result.utxos)
|
||||
|
||||
assert.property(result.utxos[0], "utxos")
|
||||
assert.property(result.utxos[0], 'utxos')
|
||||
assert.isArray(result.utxos[0].utxos)
|
||||
assert.property(result.utxos[0], "address")
|
||||
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")
|
||||
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')
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#balance`, () => {
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
describe('#balance', () => {
|
||||
it('should throw an error for improper input', async () => {
|
||||
try {
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.Electrumx.balance(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input address must be a string or array of strings`
|
||||
'Input address must be a string or array of strings'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should GET balance for a single address`, async () => {
|
||||
it('should GET balance for a single address', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "get").resolves({ data: mockData.balance })
|
||||
sandbox.stub(axios, 'get').resolves({ data: mockData.balance })
|
||||
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.Electrumx.balance(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "balance")
|
||||
assert.property(result.balance, "confirmed")
|
||||
assert.property(result.balance, "unconfirmed")
|
||||
assert.property(result, 'balance')
|
||||
assert.property(result.balance, 'confirmed')
|
||||
assert.property(result.balance, 'unconfirmed')
|
||||
})
|
||||
|
||||
it(`should POST balance for an array of addresses`, async () => {
|
||||
it('should POST balance for an array of addresses', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "post").resolves({ data: mockData.balances })
|
||||
sandbox.stub(axios, 'post').resolves({ data: mockData.balances })
|
||||
|
||||
const addr = [
|
||||
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
|
||||
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.balance(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "balances")
|
||||
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")
|
||||
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')
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#transactions`, () => {
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
describe('#transactions', () => {
|
||||
it('should throw an error for improper input', async () => {
|
||||
try {
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.Electrumx.transactions(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input address must be a string or array of strings`
|
||||
'Input address must be a string or array of strings'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should GET transactions for a single address`, async () => {
|
||||
it('should GET transactions for a single address', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "get").resolves({ data: mockData.transaction })
|
||||
sandbox.stub(axios, 'get').resolves({ data: mockData.transaction })
|
||||
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.Electrumx.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "transactions")
|
||||
assert.property(result, 'transactions')
|
||||
assert.isArray(result.transactions)
|
||||
assert.property(result.transactions[0], "height")
|
||||
assert.property(result.transactions[0], "tx_hash")
|
||||
assert.property(result.transactions[0], 'height')
|
||||
assert.property(result.transactions[0], 'tx_hash')
|
||||
})
|
||||
|
||||
it(`should POST transaction history for an array of addresses`, async () => {
|
||||
it('should POST transaction history for an array of addresses', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "post").resolves({ data: mockData.transactions })
|
||||
sandbox.stub(axios, 'post').resolves({ data: mockData.transactions })
|
||||
|
||||
const addr = [
|
||||
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
|
||||
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.transactions(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "transactions")
|
||||
assert.property(result, 'transactions')
|
||||
assert.isArray(result.transactions)
|
||||
|
||||
assert.property(result.transactions[0], "address")
|
||||
assert.property(result.transactions[0], "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")
|
||||
assert.property(result.transactions[0].transactions[0], 'height')
|
||||
assert.property(result.transactions[0].transactions[0], 'tx_hash')
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#unconfirmed`, () => {
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
describe('#unconfirmed', () => {
|
||||
it('should throw an error for improper input', async () => {
|
||||
try {
|
||||
const addr = 12345
|
||||
|
||||
await bchjs.Electrumx.unconfirmed(addr)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input address must be a string or array of strings`
|
||||
'Input address must be a string or array of strings'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should GET unconfirmed utxos for a single address`, async () => {
|
||||
it('should GET unconfirmed utxos for a single address', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "get").resolves({ data: mockData.unconfirmed })
|
||||
sandbox.stub(axios, 'get').resolves({ data: mockData.unconfirmed })
|
||||
|
||||
const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.Electrumx.unconfirmed(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "utxos")
|
||||
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")
|
||||
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 () => {
|
||||
it('should POST unconfirmed utxo details for an array of addresses', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "post").resolves({ data: mockData.unconfirmedArray })
|
||||
sandbox.stub(axios, 'post').resolves({ data: mockData.unconfirmedArray })
|
||||
|
||||
const addr = [
|
||||
"bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
"bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v"
|
||||
'bitcoincash:qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
|
||||
'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.unconfirmed(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "utxos")
|
||||
assert.property(result, 'utxos')
|
||||
assert.isArray(result.utxos)
|
||||
|
||||
assert.property(result.utxos[0], "utxos")
|
||||
assert.property(result.utxos[0], 'utxos')
|
||||
assert.isArray(result.utxos[0].utxos)
|
||||
assert.property(result.utxos[0], "address")
|
||||
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")
|
||||
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')
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#blockHeader`, () => {
|
||||
it(`should throw an error for improper height input`, async () => {
|
||||
describe('#blockHeader', () => {
|
||||
it('should throw an error for improper height input', async () => {
|
||||
try {
|
||||
// Mock network calls.
|
||||
sandbox.stub(axios, "get").rejects({
|
||||
sandbox.stub(axios, 'get').rejects({
|
||||
response: {
|
||||
data: {
|
||||
success: false,
|
||||
error: "height must be a positive number"
|
||||
error: 'height must be a positive number'
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -277,21 +277,21 @@ describe(`#ElectrumX`, () => {
|
||||
const height = -10
|
||||
await bchjs.Electrumx.blockHeader(height)
|
||||
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.message, `height must be a positive number`)
|
||||
assert.include(err.message, 'height must be a positive number')
|
||||
}
|
||||
})
|
||||
|
||||
it(`should throw an error for improper count input`, async () => {
|
||||
it('should throw an error for improper count input', async () => {
|
||||
try {
|
||||
// Mock network calls.
|
||||
sandbox.stub(axios, "get").rejects({
|
||||
sandbox.stub(axios, 'get').rejects({
|
||||
response: {
|
||||
data: {
|
||||
success: false,
|
||||
error: "count must be a positive number"
|
||||
error: 'count must be a positive number'
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -300,16 +300,16 @@ describe(`#ElectrumX`, () => {
|
||||
const count = -10
|
||||
|
||||
await bchjs.Electrumx.blockHeader(height, count)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.message, `count must be a positive number`)
|
||||
assert.include(err.message, 'count must be a positive number')
|
||||
}
|
||||
})
|
||||
|
||||
it(`should GET block headers for a given height`, async () => {
|
||||
it('should GET block headers for a given height', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "get").resolves({ data: mockData.blockHeaders })
|
||||
sandbox.stub(axios, 'get').resolves({ data: mockData.blockHeaders })
|
||||
|
||||
const height = 42
|
||||
|
||||
@@ -320,101 +320,101 @@ describe(`#ElectrumX`, () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe(`#txData`, () => {
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
describe('#txData', () => {
|
||||
it('should throw an error for improper input', async () => {
|
||||
try {
|
||||
const txid = 12345
|
||||
|
||||
await bchjs.Electrumx.txData(txid)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
`Input txId must be a string or array of strings`
|
||||
'Input txId must be a string or array of strings'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it(`should GET details data for a single transaction`, async () => {
|
||||
it('should GET details data for a single transaction', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "get").resolves({ data: mockData.details })
|
||||
sandbox.stub(axios, 'get').resolves({ data: mockData.details })
|
||||
|
||||
const txid =
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
|
||||
|
||||
const result = await bchjs.Electrumx.txData(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "details")
|
||||
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.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 () => {
|
||||
it('should POST details for an array of transactions', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "post").resolves({ data: mockData.detailsArray })
|
||||
sandbox.stub(axios, 'post').resolves({ data: mockData.detailsArray })
|
||||
|
||||
const txids = [
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251",
|
||||
"4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251"
|
||||
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251',
|
||||
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
|
||||
]
|
||||
|
||||
const result = await bchjs.Electrumx.txData(txids)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "transactions")
|
||||
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], '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")
|
||||
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')
|
||||
|
||||
assert.equal(result.transactions.length, 2, "2 outputs for 2 inputs")
|
||||
assert.equal(result.transactions.length, 2, '2 outputs for 2 inputs')
|
||||
})
|
||||
})
|
||||
describe(`#broadcast`, () => {
|
||||
it(`should throw an error for improper input`, async () => {
|
||||
describe('#broadcast', () => {
|
||||
it('should throw an error for improper input', async () => {
|
||||
try {
|
||||
const txHex = 12345
|
||||
|
||||
await bchjs.Electrumx.broadcast(txHex)
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(err.message, `Input txHex must be a string.`)
|
||||
assert.include(err.message, 'Input txHex must be a string.')
|
||||
}
|
||||
})
|
||||
it(`should broadcast a single transaction`, async () => {
|
||||
it('should broadcast a single transaction', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, "post").resolves({ data: mockData.broadcast })
|
||||
sandbox.stub(axios, 'post').resolves({ data: mockData.broadcast })
|
||||
|
||||
const tx = mockData.details
|
||||
const txid = tx.details.txid
|
||||
const result = await bchjs.Electrumx.broadcast(tx.details.hex)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
|
||||
assert.property(result, "txid")
|
||||
assert.property(result, 'txid')
|
||||
assert.equal(result.txid, txid)
|
||||
})
|
||||
})
|
||||
|
||||
+20
-20
@@ -1,13 +1,13 @@
|
||||
const assert = require("chai").assert
|
||||
const sinon = require("sinon")
|
||||
const assert = require('chai').assert
|
||||
const sinon = require('sinon')
|
||||
|
||||
const BCHJS = require("../../src/bch-js")
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
// const bchjs = new BCHJS()
|
||||
let bchjs
|
||||
|
||||
const mockData = require("./fixtures/encryption-mock")
|
||||
const mockData = require('./fixtures/encryption-mock')
|
||||
|
||||
describe("#Encryption", () => {
|
||||
describe('#Encryption', () => {
|
||||
let sandbox
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -17,52 +17,52 @@ describe("#Encryption", () => {
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe("#getPubKey", () => {
|
||||
it("should throw error if BCH address is not provided.", async () => {
|
||||
describe('#getPubKey', () => {
|
||||
it('should throw error if BCH address is not provided.', async () => {
|
||||
try {
|
||||
await bchjs.encryption.getPubKey()
|
||||
|
||||
assert.equal(true, false, "Unexpected result!")
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
"Input must be a valid Bitcoin Cash address"
|
||||
'Input must be a valid Bitcoin Cash address'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it("should report when public key can not be found", async () => {
|
||||
it('should report when public key can not be found', async () => {
|
||||
// Stub the network call.
|
||||
sandbox
|
||||
.stub(bchjs.encryption.axios, "get")
|
||||
.stub(bchjs.encryption.axios, 'get')
|
||||
.resolves({ data: mockData.failureMock })
|
||||
|
||||
const addr = "bitcoincash:qpxqr2pmcverj4vukgjqssvk2zju8tp9xsgz2nqagx"
|
||||
const addr = 'bitcoincash:qpxqr2pmcverj4vukgjqssvk2zju8tp9xsgz2nqagx'
|
||||
|
||||
const result = await bchjs.encryption.getPubKey(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, false)
|
||||
assert.property(result, "publicKey")
|
||||
assert.equal(result.publicKey, "not found")
|
||||
assert.property(result, 'publicKey')
|
||||
assert.equal(result.publicKey, 'not found')
|
||||
})
|
||||
|
||||
it("should get a public key", async () => {
|
||||
it('should get a public key', async () => {
|
||||
// Stub the network call.
|
||||
sandbox
|
||||
.stub(bchjs.encryption.axios, "get")
|
||||
.stub(bchjs.encryption.axios, 'get')
|
||||
.resolves({ data: mockData.successMock })
|
||||
|
||||
const addr = "bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq"
|
||||
const addr = 'bitcoincash:qpf8jv9hmqcda0502gjp7nm3g24y5h5s4unutghsxq'
|
||||
|
||||
const result = await bchjs.encryption.getPubKey(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, "success")
|
||||
assert.property(result, 'success')
|
||||
assert.equal(result.success, true)
|
||||
assert.property(result, "publicKey")
|
||||
assert.property(result, 'publicKey')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,34 +6,34 @@ const balance = { confirmed: 230000, unconfirmed: 0, balance: 230000 }
|
||||
|
||||
const utxo = [
|
||||
{
|
||||
_id: "5cecdd39a9f1235e2a3d409a",
|
||||
chain: "BCH",
|
||||
network: "mainnet",
|
||||
_id: '5cecdd39a9f1235e2a3d409a',
|
||||
chain: 'BCH',
|
||||
network: 'mainnet',
|
||||
coinbase: false,
|
||||
mintIndex: 0,
|
||||
spentTxid: "",
|
||||
spentTxid: '',
|
||||
mintTxid:
|
||||
"27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c",
|
||||
'27ec8512c1a9ee9e9ae9b98eb60375f1d2bd60e2e76a1eff5a45afdbc517cf9c',
|
||||
mintHeight: 560430,
|
||||
spentHeight: -2,
|
||||
address: "qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
script: "76a914db6ea94fa26b7272dc5e1487c35f258391e0f38788ac",
|
||||
address: 'qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
|
||||
script: '76a914db6ea94fa26b7272dc5e1487c35f258391e0f38788ac',
|
||||
value: 100000,
|
||||
confirmations: -1
|
||||
},
|
||||
{
|
||||
_id: "5cecdd1ca9f1235e2a3b6349",
|
||||
chain: "BCH",
|
||||
network: "mainnet",
|
||||
_id: '5cecdd1ca9f1235e2a3b6349',
|
||||
chain: 'BCH',
|
||||
network: 'mainnet',
|
||||
coinbase: false,
|
||||
mintIndex: 0,
|
||||
spentTxid: "",
|
||||
spentTxid: '',
|
||||
mintTxid:
|
||||
"6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d",
|
||||
'6e1ae1bf7db6de799ec1c05ab2816ac65549bd80141567af088e6f291385b07d',
|
||||
mintHeight: 560039,
|
||||
spentHeight: -2,
|
||||
address: "qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf",
|
||||
script: "76a914db6ea94fa26b7272dc5e1487c35f258391e0f38788ac",
|
||||
address: 'qrdka2205f4hyukutc2g0s6lykperc8nsu5u2ddpqf',
|
||||
script: '76a914db6ea94fa26b7272dc5e1487c35f258391e0f38788ac',
|
||||
value: 130000,
|
||||
confirmations: -1
|
||||
}
|
||||
|
||||
@@ -4,24 +4,24 @@
|
||||
|
||||
module.exports = {
|
||||
details: {
|
||||
hash: "000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0",
|
||||
hash: '000000001c6aeec19265e9cc3ded8ba5ef5e63fae7747f30bf9c02c7bc8883f0',
|
||||
size: 216,
|
||||
height: 507,
|
||||
version: 1,
|
||||
merkleroot:
|
||||
"a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8",
|
||||
tx: ["a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8"],
|
||||
'a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8',
|
||||
tx: ['a85fa3d831ab6b0305e7ff88d2d4941e25a810d4461635df51490653822071a8'],
|
||||
time: 1231973656,
|
||||
nonce: 330467862,
|
||||
bits: "1d00ffff",
|
||||
bits: '1d00ffff',
|
||||
difficulty: 1,
|
||||
chainwork:
|
||||
"000000000000000000000000000000000000000000000000000001fc01fc01fc",
|
||||
'000000000000000000000000000000000000000000000000000001fc01fc01fc',
|
||||
confirmations: 585104,
|
||||
previousblockhash:
|
||||
"00000000a99525c043fd7e323414b60add43c254c44860094048f9c01e9a5fdd",
|
||||
'00000000a99525c043fd7e323414b60add43c254c44860094048f9c01e9a5fdd',
|
||||
nextblockhash:
|
||||
"000000000d550f4161f2702165fdd782ec72ff9c541f864ebb8256b662b7e51a",
|
||||
'000000000d550f4161f2702165fdd782ec72ff9c541f864ebb8256b662b7e51a',
|
||||
reward: 50,
|
||||
isMainChain: true,
|
||||
poolInfo: {}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user