mirror of
https://github.com/Permissionless-Software-Foundation/bch-js.git
synced 2026-09-22 00:52:01 -07:00
Compare commits
214
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c593d68ee5 | ||
|
|
dc7d3a9339 | ||
|
|
6f4cc0f439 | ||
|
|
7aa0fa865e | ||
|
|
b13ef94ea3 | ||
|
|
912f899f4e | ||
|
|
9063d8da0b | ||
|
|
f4e2bd96f0 | ||
|
|
1c898a4ad3 | ||
|
|
c4db813f76 | ||
|
|
38b96b441f | ||
|
|
c94f78f510 | ||
|
|
6de2b712ec | ||
|
|
6f681fd7b0 | ||
|
|
9a82effb2b | ||
|
|
955a5e428e | ||
|
|
44c3bf44f9 | ||
|
|
31ce84abb0 | ||
|
|
40fa4b6bc1 | ||
|
|
8c5e111d60 | ||
|
|
8965dfc57f | ||
|
|
93904a632f | ||
|
|
851d4c404c | ||
|
|
44bac45c32 | ||
|
|
95ee8054be | ||
|
|
547b28cac8 | ||
|
|
40ba334a41 | ||
|
|
ffd8ccaf2b | ||
|
|
9a16c0c6d6 | ||
|
|
52a891fd78 | ||
|
|
c09df08429 | ||
|
|
4dc88c0af3 | ||
|
|
85caa9556b | ||
|
|
bbdc417eb2 | ||
|
|
cc3bc002e7 | ||
|
|
a75e1ab633 | ||
|
|
8c5f1e2274 | ||
|
|
c30e76c942 | ||
|
|
a575621c50 | ||
|
|
d3a0c5948a | ||
|
|
61bb509195 | ||
|
|
a18e549694 | ||
|
|
7d53f47d8a | ||
|
|
e8e615795d | ||
|
|
5759b096d5 | ||
|
|
5b300f68b2 | ||
|
|
3cce6f9754 | ||
|
|
3da04d9327 | ||
|
|
79091815a2 | ||
|
|
258144d26d | ||
|
|
4c4a45841b | ||
|
|
010afd10a3 | ||
|
|
82b4d2ab9e | ||
|
|
8eb6a21dc2 | ||
|
|
5f2a762d4f | ||
|
|
24e2c78d03 | ||
|
|
eab02fdbc9 | ||
|
|
f7bd9c75db | ||
|
|
2a96f3a4f5 | ||
|
|
3dc4a8ba6f | ||
|
|
65916f2c5c | ||
|
|
18188bfdce | ||
|
|
45acc2b0b7 | ||
|
|
31913c3fb7 | ||
|
|
2311643398 | ||
|
|
7501aa0238 | ||
|
|
92a89a543d | ||
|
|
cdf8171994 | ||
|
|
385baf0afd | ||
|
|
9a9aababd2 | ||
|
|
c228acd28a | ||
|
|
c1c140bdce | ||
|
|
54d9b80f26 | ||
|
|
961a190309 | ||
|
|
2d2a91dfde | ||
|
|
fbac18d456 | ||
|
|
62ae67ceab | ||
|
|
8e64d854cf | ||
|
|
5fe8e515ff | ||
|
|
f11297339b | ||
|
|
61d52c8ebe | ||
|
|
d89bbe0bf6 | ||
|
|
2a1c2500e6 | ||
|
|
8879a5170a | ||
|
|
b29cb7c12b | ||
|
|
69fa10d3a6 | ||
|
|
d16431d165 | ||
|
|
faa2972460 | ||
|
|
5d3ea2b559 | ||
|
|
40fa6440f4 | ||
|
|
ce951afddb | ||
|
|
d2e847d3fb | ||
|
|
fe697455c0 | ||
|
|
25832d52fd | ||
|
|
9d0840c2fe | ||
|
|
74dc3e7e1d | ||
|
|
171786a470 | ||
|
|
5cbd685060 | ||
|
|
ef05aff7a3 | ||
|
|
3f01fdba7c | ||
|
|
232747280e | ||
|
|
e96da1615b | ||
|
|
9538501f01 | ||
|
|
0a4fee5716 | ||
|
|
cec79be4fa | ||
|
|
c839f0b891 | ||
|
|
24d629ebe1 | ||
|
|
f729918385 | ||
|
|
b7ab02c0ed | ||
|
|
1c291880e0 | ||
|
|
09b79c4d3e | ||
|
|
828f6a1b1c | ||
|
|
1b8727da55 | ||
|
|
f84862d875 | ||
|
|
179d924899 | ||
|
|
676fb85abf | ||
|
|
d59c1fe445 | ||
|
|
0a34611557 | ||
|
|
c13b029e99 | ||
|
|
b038e9a7fd | ||
|
|
7b728fb45d | ||
|
|
d4dbce8df0 | ||
|
|
2419aeceaa | ||
|
|
158b009069 | ||
|
|
f3c3250a69 | ||
|
|
5ae4db88c3 | ||
|
|
33e161df26 | ||
|
|
81c910361c | ||
|
|
9751a39538 | ||
|
|
7058f77ee9 | ||
|
|
ad580d67a4 | ||
|
|
acc0300a44 | ||
|
|
4e1b806230 | ||
|
|
357e350176 | ||
|
|
f6140acc76 | ||
|
|
df65b12aab | ||
|
|
754b4cd807 | ||
|
|
3c6079e54c | ||
|
|
18621cd76c | ||
|
|
456159a4cc | ||
|
|
33e723befe | ||
|
|
30fdee1920 | ||
|
|
feb336c331 | ||
|
|
8bacc0a991 | ||
|
|
d22f1ec8a6 | ||
|
|
7eb3a796b8 | ||
|
|
9919f811b0 | ||
|
|
e7854481a0 | ||
|
|
0b406c467e | ||
|
|
e41217b710 | ||
|
|
c22ce8d57d | ||
|
|
bf3612583e | ||
|
|
ef56452ec9 | ||
|
|
b3be470c0e | ||
|
|
7274475898 | ||
|
|
7bb347a833 | ||
|
|
fadceedd00 | ||
|
|
7f4ef60f8e | ||
|
|
81e54e0590 | ||
|
|
1d5e3da976 | ||
|
|
2cff305f46 | ||
|
|
9495381cf4 | ||
|
|
32f89346c3 | ||
|
|
e8582fd0ab | ||
|
|
7049b96df1 | ||
|
|
9cc6824591 | ||
|
|
bb82d520ed | ||
|
|
fef05124f1 | ||
|
|
978db07526 | ||
|
|
68bab5dd26 | ||
|
|
20e685206d | ||
|
|
e90afac701 | ||
|
|
96f96f837e | ||
|
|
03be1d5838 | ||
|
|
6b6bfa2ae2 | ||
|
|
da3af3656a | ||
|
|
26fdb5c5d5 | ||
|
|
86d71d0f49 | ||
|
|
86351aaf4f | ||
|
|
36432af7d5 | ||
|
|
95c88b5f29 | ||
|
|
28f563b58c | ||
|
|
79ea4b77b9 | ||
|
|
d37a2f8139 | ||
|
|
3b873b6064 | ||
|
|
687b5bca02 | ||
|
|
b80697500c | ||
|
|
626d27033e | ||
|
|
ce2ee3fc1b | ||
|
|
4768dcadc6 | ||
|
|
5fef09edbf | ||
|
|
37109cd7ef | ||
|
|
83d523260d | ||
|
|
8768a810c7 | ||
|
|
8832bfc8df | ||
|
|
a5208110b9 | ||
|
|
99ad7cd87f | ||
|
|
68ae084fb0 | ||
|
|
b0b0e17abc | ||
|
|
a54306e382 | ||
|
|
1860232fa6 | ||
|
|
d8437cf3fb | ||
|
|
338788c46d | ||
|
|
cad2c6378e | ||
|
|
2e6938e21f | ||
|
|
1e13c71715 | ||
|
|
d4b0807d16 | ||
|
|
611c7977ef | ||
|
|
39ac634675 | ||
|
|
278a54bd9b | ||
|
|
30b1f71d81 | ||
|
|
e7d7fc1019 | ||
|
|
524da532e2 | ||
|
|
e2ba265878 |
@@ -3,6 +3,7 @@ node_modules/*
|
||||
wallet-info.txt
|
||||
wallet.json
|
||||
integration-test-sweet.sh
|
||||
integration-test-ss.sh
|
||||
|
||||
docs/
|
||||
coverage/
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
Copyright 2020 Chris Troutner
|
||||
Copyright 2021 Chris Troutner
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# bch-js
|
||||
|
||||
[](https://travis-ci.org/Permissionless-Software-Foundation/bch-js)
|
||||
[](https://www.npmjs.com/package/@psf/bch-js)
|
||||
[](https://npmjs.org/package/@psf/bch-js)
|
||||
[](https://github.com/Permissionless-Software-Foundation/bch-js/blob/master/LICENSE.md)
|
||||
[](https://github.com/feross/standard)
|
||||
|
||||
[bch-js](https://www.npmjs.com/package/@psf/bch-js) is a JavaScript npm library for creating web and mobile apps that can interact with the Bitcoin Cash (BCH) blockchains. It can be used for free, but requires an account on [FullStack.cash](https://fullstack.cash) for increased rate limits. Learn more from [this article](https://troutsblog.com/research/bitcoin-cash/how-to-bch-full-stack-developer) about Full Stack Bitcoin Cash development.
|
||||
|
||||
@@ -33,17 +33,13 @@ Here are two YouTube walk-through videos to help you get started:
|
||||
```
|
||||
const BCHJS = require("@psf/bch-js")
|
||||
let bchjs = new BCHJS() // Defaults to BCHN network.
|
||||
|
||||
// testnet
|
||||
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/v4/
|
||||
- ABC Mainnet REST API server: https://abc.fullstack.cash/v4/
|
||||
- Testnet3 REST API server: https://testnet3.fullstack.cash/v4/
|
||||
- BCHN Mainnet REST API server: https://bchn.fullstack.cash/v5/
|
||||
- ABC Mainnet REST API server: https://abc.fullstack.cash/v5/
|
||||
- Check server status: https://metrics.fullstack.cash
|
||||
|
||||
### API Key
|
||||
@@ -57,7 +53,7 @@ rate limits when interacting with the back end server. See [this article](https:
|
||||
```
|
||||
const BCHJS = require("@psf/bch-js")
|
||||
let bchjs = new BCHJS({
|
||||
restURL: 'https://bchn.fullstack.cash/v3/',
|
||||
restURL: 'https://bchn.fullstack.cash/v5/',
|
||||
apiToken: 'eyJhbGciO...' // Your JWT token here.
|
||||
})
|
||||
```
|
||||
@@ -117,7 +113,7 @@ Have questions? Need help? Join our community support
|
||||
|
||||
Copies of this repository are also published on [IPFS](https://ipfs.io).
|
||||
|
||||
- v3.8.10: QmauhggzKDo9A9je5y2K6WRAp32JmGRFCw2ZFTiSnW8yot
|
||||
- v4.5.4: QmWv3pxJy3MH8vU5nLUVyzqFxfNKXLQQEnz1rgStNuQijd
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
Examples have been moved to this repository:
|
||||
Examples have been moved to this repository
|
||||
|
||||
https://github.com/Permissionless-Software-Foundation/bch-js-examples
|
||||
|
||||
Generated
+18320
-3486
File diff suppressed because it is too large
Load Diff
+22
-32
@@ -4,20 +4,26 @@
|
||||
"description": "The FullStack.cash JavaScript library for Bitcoin Cash and SLP Tokens",
|
||||
"author": "Chris Troutner <chris.troutner@gmail.com>",
|
||||
"contributors": [
|
||||
"Gabriel Cardona <gabriel@bitcoin.com>"
|
||||
"Gabriel Cardona <gabriel@bitcoin.com>",
|
||||
"Stoyan Zhekov <zh@zhware.net>"
|
||||
],
|
||||
"main": "src/bch-js",
|
||||
"scripts": {
|
||||
"test": "nyc mocha --trace-warnings --unhandled-rejections=strict --timeout 30000 test/unit/",
|
||||
"test:integration": "npm run test:integration:bchn",
|
||||
"test:integration: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:nft": "export RESTURL=https://bchn.fullstack.cash/v5/ && export IS_USING_FREE_TIER=true && mocha --timeout 30000 -g '#nft1' test/integration/chains/bchn/slp.js",
|
||||
"test:integration:abc": "export RESTURL=https://abc.fullstack.cash/v5/ && 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/v5/ && 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/",
|
||||
"test:integration:local:abc": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
|
||||
"test:integration:local:bchn": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 test/integration/ && mocha --timeout 30000 test/integration/chains/bchn/",
|
||||
"test:integration:local:testnet": "RESTURL=http://localhost:4000/v5/ mocha --timeout 30000 test/integration/chains/testnet",
|
||||
"test:integration:decatur:bchn": "export RESTURL=http://192.168.0.36:3000/v5/ && mocha --timeout 30000 test/integration/",
|
||||
"test:integration:temp:bchn": "export RESTURL=http://157.90.174.219:3000/v5/ && mocha --timeout 30000 test/integration/",
|
||||
"test:temp": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 -g '#Encryption' test/integration/",
|
||||
"test:temp2": "mocha --timeout=30000 -g '#TransactionLib' test/unit/",
|
||||
"test:temp3": "export RESTURL=https://bchn.fullstack.cash/v5/ && mocha --timeout 30000 -g '#DSProof' test/integration/chains/",
|
||||
"test:temp4": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 -g '#decodeOpReturn' test/integration/",
|
||||
"coverage": "nyc report --reporter=text-lcov | coveralls",
|
||||
"coverage:report": "nyc --reporter=html mocha --timeout 25000 test/unit/",
|
||||
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
|
||||
@@ -30,52 +36,36 @@
|
||||
"url": "git+https://github.com/Permissionless-Software-Foundation/bch-js.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@psf/bip21": "^2.0.1",
|
||||
"@psf/bip32-utils": "^1.0.0",
|
||||
"@psf/bitcoincash-ops": "^2.0.0",
|
||||
"@psf/bitcoincashjs-lib": "^4.0.2",
|
||||
"@psf/coininfo": "^4.0.0",
|
||||
"@uppy/core": "^1.10.4",
|
||||
"@uppy/tus": "^1.5.12",
|
||||
"apidoc": "^0.25.0",
|
||||
"assert": "^2.0.0",
|
||||
"axios": "^0.21.1",
|
||||
"bc-bip68": "^1.0.5",
|
||||
"bchaddrjs-slp": "^0.2.5",
|
||||
"bigi": "^1.4.2",
|
||||
"bignumber.js": "^9.0.0",
|
||||
"bip-schnorr": "^0.3.0",
|
||||
"@psf/bip21": "^2.0.1",
|
||||
"@psf/bip32-utils": "^0.13.1",
|
||||
"bip38": "^2.0.2",
|
||||
"bip39": "^3.0.2",
|
||||
"bip66": "^1.1.5",
|
||||
"@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",
|
||||
"@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.8",
|
||||
"mkdirp": "^0.5.1",
|
||||
"node-cmd": "^3.0.0",
|
||||
"node-emoji": "^1.8.1",
|
||||
"qrcode": "^1.4.1",
|
||||
"randombytes": "^2.0.6",
|
||||
"repl.history": "^0.1.4",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"satoshi-bitcoin": "^1.0.4",
|
||||
"slp-mdm": "0.0.6",
|
||||
"slp-parser": "0.0.4",
|
||||
"socket.io": "^2.1.1",
|
||||
"socket.io-client": "^2.1.1",
|
||||
"touch": "^3.1.0",
|
||||
"wif": "^2.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"apidoc": "^0.17.7",
|
||||
"assert": "^2.0.0",
|
||||
"chai": "^4.1.2",
|
||||
"coveralls": "^3.0.2",
|
||||
"eslint": "5.16.0",
|
||||
@@ -90,7 +80,7 @@
|
||||
"node-mocks-http": "^1.7.0",
|
||||
"nyc": "^14.1.0",
|
||||
"prettier": "^1.18.2",
|
||||
"semantic-release": "^17.3.1",
|
||||
"semantic-release": "^17.3.9",
|
||||
"sinon": "^7.3.2",
|
||||
"standard": "^16.0.3"
|
||||
},
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ const coininfo = require('@psf/coininfo')
|
||||
class Address {
|
||||
constructor (config) {
|
||||
const tmp = {}
|
||||
if (!config || !config.restURL) tmp.restURL = 'https://api.bchjs.cash/v4/'
|
||||
if (!config || !config.restURL) tmp.restURL = 'https://api.bchjs.cash/v5/'
|
||||
else tmp.restURL = config.restURL
|
||||
|
||||
this.restURL = tmp.restURL
|
||||
|
||||
+24
-11
@@ -7,8 +7,8 @@
|
||||
*/
|
||||
|
||||
// bch-api mainnet.
|
||||
const DEFAULT_REST_API = 'https://api.fullstack.cash/v4/'
|
||||
// const DEFAULT_REST_API = "http://localhost:3000/v4/"
|
||||
const DEFAULT_REST_API = 'https://api.fullstack.cash/v5/'
|
||||
// const DEFAULT_REST_API = "http://localhost:3000/v5/"
|
||||
|
||||
// local deps
|
||||
const BitcoinCash = require('./bitcoincash')
|
||||
@@ -26,29 +26,42 @@ 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')
|
||||
const Utxo = require('./utxo')
|
||||
const Transaction = require('./transaction')
|
||||
const DSProof = require('./dsproof')
|
||||
|
||||
// Indexers
|
||||
const OpenBazaar = require('./openbazaar')
|
||||
const Ninsight = require('./ninsight')
|
||||
const Electrumx = require('./electrumx')
|
||||
|
||||
class BCHJS {
|
||||
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 }
|
||||
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 }
|
||||
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 = ''
|
||||
@@ -68,9 +81,6 @@ class BCHJS {
|
||||
|
||||
// console.log(`apiToken: ${this.apiToken}`)
|
||||
|
||||
// Populate OpenBazaar endpoints
|
||||
this.OpenBazaar = new OpenBazaar(libConfig)
|
||||
|
||||
// Bitcoin.com Ninsight indexer
|
||||
this.Ninsight = new Ninsight(config)
|
||||
|
||||
@@ -98,13 +108,16 @@ class BCHJS {
|
||||
this.TransactionBuilder = TransactionBuilder
|
||||
this.TransactionBuilder.setAddress(this.Address)
|
||||
this.Util = new Util(libConfig)
|
||||
this.Socket = Socket
|
||||
this.Schnorr = new Schnorr(libConfig)
|
||||
|
||||
this.SLP = new SLP(libConfig)
|
||||
this.SLP.HDNode = this.HDNode
|
||||
|
||||
this.IPFS = new IPFS()
|
||||
this.Utxo = new Utxo(libConfig)
|
||||
this.Transaction = new Transaction(libConfig)
|
||||
|
||||
this.DSProof = new DSProof(libConfig)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+58
-48
@@ -5,7 +5,7 @@
|
||||
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
// let _this
|
||||
|
||||
class Blockchain {
|
||||
constructor (config) {
|
||||
@@ -29,7 +29,7 @@ class Blockchain {
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
// _this = this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +54,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getBestBlockHash`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -68,8 +68,8 @@ class Blockchain {
|
||||
* @apiName getBlock
|
||||
* @apiGroup Blockchain
|
||||
* @apiDescription
|
||||
* If verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'. If verbose is true, returns an Object with information about block hash.
|
||||
*
|
||||
* If verbose is 0, returns a string that is serialized, hex-encoded data for block 'hash'. If verbose is 1, returns an Object with information about block hash.
|
||||
* If verbose is 2, returns an Object with information about block hash and information about tx.
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
@@ -80,29 +80,39 @@ class Blockchain {
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // { hash: '00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09',
|
||||
* // confirmations: 528236,
|
||||
* // size: 216,
|
||||
* // height: 1000,
|
||||
* // version: 1,
|
||||
* // versionHex: '00000001',
|
||||
* // merkleroot: 'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33',
|
||||
* // tx:
|
||||
* // [ 'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33' ],
|
||||
* // time: 1232346882,
|
||||
* // mediantime: 1232344831,
|
||||
* // nonce: 2595206198,
|
||||
* // bits: '1d00ffff',
|
||||
* // difficulty: 1,
|
||||
* // chainwork: '000000000000000000000000000000000000000000000000000003e903e903e9',
|
||||
* // previousblockhash: '0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d',
|
||||
* // nextblockhash: '00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6' }
|
||||
* // {
|
||||
* // hash: '00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09',
|
||||
* // confirmations: 528236,
|
||||
* // size: 216,
|
||||
* // height: 1000,
|
||||
* // version: 1,
|
||||
* // versionHex: '00000001',
|
||||
* // merkleroot: 'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33',
|
||||
* // tx:
|
||||
* // [ 'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33' ],
|
||||
* // time: 1232346882,
|
||||
* // mediantime: 1232344831,
|
||||
* // nonce: 2595206198,
|
||||
* // bits: '1d00ffff',
|
||||
* // difficulty: 1,
|
||||
* // chainwork: '000000000000000000000000000000000000000000000000000003e903e903e9',
|
||||
* // previousblockhash: '0000000008e647742775a230787d66fdf92c46a48c896bfbc85cdc8acc67e87d',
|
||||
* // nextblockhash: '00000000a2887344f8db859e372e7e4bc26b23b9de340f725afbf2edb265b4c6'
|
||||
* // }
|
||||
*/
|
||||
async getBlock (blockhash, verbose = true) {
|
||||
async getBlock (blockhash, verbosity = 1) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getBlock/${blockhash}?verbose=${verbose}`,
|
||||
_this.axiosOptions
|
||||
// Input validation
|
||||
if (!blockhash || typeof blockhash !== 'string') {
|
||||
throw new Error('blockhash must be a string')
|
||||
}
|
||||
const response = await axios.post(
|
||||
`${this.restURL}blockchain/getblock`,
|
||||
{
|
||||
blockhash,
|
||||
verbosity
|
||||
},
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -152,7 +162,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getBlockchainInfo`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -183,7 +193,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getBlockCount`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -216,7 +226,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getBlockHash/${height}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -263,7 +273,7 @@ class Blockchain {
|
||||
if (typeof hash === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getBlockHeader/${hash}?verbose=${verbose}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -277,7 +287,7 @@ class Blockchain {
|
||||
hashes: hash,
|
||||
verbose: verbose
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -324,7 +334,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getChainTips`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -356,7 +366,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getDifficulty`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -372,7 +382,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getMempoolAncestors/${txid}?verbose=${verbose}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -387,7 +397,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getMempoolDescendants/${txid}?verbose=${verbose}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -484,7 +494,7 @@ class Blockchain {
|
||||
if (typeof txid === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getMempoolEntry/${txid}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -495,7 +505,7 @@ class Blockchain {
|
||||
{
|
||||
txids: txid
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -535,7 +545,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getMempoolInfo`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -582,7 +592,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/getRawMempool?vebose=${verbose}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -626,7 +636,7 @@ class Blockchain {
|
||||
// Send the request to the REST API.
|
||||
// const response = await axios.get(
|
||||
// `${this.restURL}blockchain/getTxOut/${txid}/${n}?includeMempool=${includeMempool}`,
|
||||
// _this.axiosOptions
|
||||
// this.axiosOptions
|
||||
// )
|
||||
const response = await axios.post(
|
||||
`${this.restURL}blockchain/getTxOut`,
|
||||
@@ -635,7 +645,7 @@ class Blockchain {
|
||||
vout: n,
|
||||
mempool: includeMempool
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -688,7 +698,7 @@ class Blockchain {
|
||||
const path = `${this.restURL}blockchain/getTxOutProof/${txids}`
|
||||
// if (blockhash) path = `${path}?blockhash=${blockhash}`
|
||||
|
||||
const response = await axios.get(path, _this.axiosOptions)
|
||||
const response = await axios.get(path, this.axiosOptions)
|
||||
return response.data
|
||||
|
||||
// Array of txids.
|
||||
@@ -699,7 +709,7 @@ class Blockchain {
|
||||
{
|
||||
txids: txids
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -716,7 +726,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/preciousBlock/${blockhash}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -729,7 +739,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}blockchain/pruneBlockchain/${height}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -742,7 +752,7 @@ class Blockchain {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/verifyChain?checklevel=${checklevel}&nblocks=${nblocks}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -794,7 +804,7 @@ class Blockchain {
|
||||
if (typeof proof === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}blockchain/verifyTxOutProof/${proof}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
|
||||
@@ -806,7 +816,7 @@ class Blockchain {
|
||||
{
|
||||
proofs: proof
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
|
||||
+4
-4
@@ -4,7 +4,7 @@
|
||||
|
||||
const axios = require('axios')
|
||||
|
||||
let _this // Global reference to the instance of this class.
|
||||
// let _this // Global reference to the instance of this class.
|
||||
|
||||
class Control {
|
||||
constructor (config) {
|
||||
@@ -28,7 +28,7 @@ class Control {
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
// _this = this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,7 +81,7 @@ class Control {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}control/getNetworkInfo`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -94,7 +94,7 @@ class Control {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}control/getMemoryInfo`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
|
||||
class DSProof {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
this.authToken = config.authToken
|
||||
this.axios = axios
|
||||
|
||||
if (this.authToken) {
|
||||
// Add Basic Authentication token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: this.authToken
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
}
|
||||
|
||||
/**
|
||||
* @api DSProof.getDSProof() getDSProof()
|
||||
* @apiName getDSProof
|
||||
* @apiGroup DSProof
|
||||
* @apiDescription Checks if a transaction generated a double-spend proof.
|
||||
*
|
||||
* If a double-spend is attempted, one of the transactions will generate a
|
||||
* 'double spend proof'. This call can be used to check if a transaction
|
||||
* generated such a proof.
|
||||
*
|
||||
* Merchants should wait 3-5 seconds after receiving notification of a
|
||||
* transaction before calling this endpoint, to see if the TXID generated a
|
||||
* proof. If this method returns no data, then the TX can be considered 'safe'
|
||||
* and not a double spend. If proof data is returned by this method, then
|
||||
* the transaction generated a proof and can be considered a 'double spend'.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* const txid = 'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'
|
||||
* const result = await bchjs.DSProof.getDSProof(txid)
|
||||
* console.log(result);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // returns
|
||||
* null
|
||||
*/
|
||||
async getDSProof (txid) {
|
||||
try {
|
||||
if (!txid) {
|
||||
throw new Error('txid is required')
|
||||
}
|
||||
if (txid.length !== 64) {
|
||||
throw new Error(`txid must be of length 64 (not ${txid.length})`)
|
||||
}
|
||||
const response = await _this.axios.get(
|
||||
`${this.restURL}dsproof/getdsproof/${txid}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DSProof
|
||||
+125
-18
@@ -2,10 +2,13 @@
|
||||
This library interacts with the ElectrumX bch-api REST API endpoints operated
|
||||
by FullStack.cash
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
// Local libraries.
|
||||
const Blockchain = require('./blockchain')
|
||||
|
||||
// let _this
|
||||
|
||||
class ElectrumX {
|
||||
constructor (config) {
|
||||
@@ -29,7 +32,9 @@ class ElectrumX {
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
this.blockchain = new Blockchain(config)
|
||||
|
||||
// _this = this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +108,7 @@ class ElectrumX {
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/utxos/${address}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
|
||||
@@ -114,7 +119,7 @@ class ElectrumX {
|
||||
{
|
||||
addresses: address
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -187,7 +192,7 @@ class ElectrumX {
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/balance/${address}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
|
||||
@@ -198,7 +203,7 @@ class ElectrumX {
|
||||
{
|
||||
addresses: address
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -279,13 +284,13 @@ class ElectrumX {
|
||||
* }
|
||||
*
|
||||
*/
|
||||
async transactions (address) {
|
||||
async transactions (address, usrObj = null) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/transactions/${address}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
|
||||
@@ -294,9 +299,10 @@ class ElectrumX {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}electrumx/transactions`,
|
||||
{
|
||||
addresses: address
|
||||
addresses: address,
|
||||
usrObj // pass user data when making an internal call.
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -377,7 +383,7 @@ class ElectrumX {
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/unconfirmed/${address}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
|
||||
@@ -388,7 +394,7 @@ class ElectrumX {
|
||||
{
|
||||
addresses: address
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -446,13 +452,15 @@ class ElectrumX {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/block/headers/${height}?count=${count}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} 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
|
||||
}
|
||||
@@ -535,7 +543,7 @@ class ElectrumX {
|
||||
if (typeof txid === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}electrumx/tx/data/${txid}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} else if (Array.isArray(txid)) {
|
||||
@@ -544,7 +552,7 @@ class ElectrumX {
|
||||
{
|
||||
txids: txid
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -584,7 +592,7 @@ class ElectrumX {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}electrumx/tx/broadcast`,
|
||||
{ txHex },
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -596,6 +604,105 @@ class ElectrumX {
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Electrumx.sortConfTxs() sortConfTxs()
|
||||
* @apiName ElectrumX sortConfTxs
|
||||
* @apiGroup ElectrumX
|
||||
* @apiDescription Sort the output of Electrum.transactions() by block height.
|
||||
*
|
||||
* A simple sort function for the output of Electrum.transactions(). Ignores
|
||||
* unconfirmed transactions.
|
||||
*
|
||||
* Sorts in 'DESCENDING' order by default, or 'ASCENDING' can be specified.
|
||||
* Descending makes the first element the newest (largest block height).
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* const txs = await bchjs.Electrumx.transactions('bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v')
|
||||
* const sortedTxs = bchjs.Electrumx.sortConfTxs(txs.transactions, 'ASCENDING')
|
||||
* console.log(sortedTxs)
|
||||
* })()
|
||||
*
|
||||
* // [
|
||||
* // {
|
||||
* // "height": 560430,
|
||||
* // "tx_hash": "3e1f3e882be9c03897eeb197224bf87f312be556a89f4308fabeeeabcf9bc851"
|
||||
* // },
|
||||
* // {
|
||||
* // "height": 560534,
|
||||
* // "tx_hash": "4ebbeaac51ce141e262964e3a0ce11b96ca72c0dffe9b4127ce80135f503a280"
|
||||
* // }
|
||||
* // ]
|
||||
*/
|
||||
// Sort confirmed Transactions by the block height
|
||||
sortConfTxs (txs, sortingOrder = 'DESCENDING') {
|
||||
try {
|
||||
// Filter out unconfirmed transactions, with a height of 0 or less.
|
||||
txs = txs.filter(elem => elem.height > 0)
|
||||
|
||||
if (sortingOrder === 'DESCENDING') {
|
||||
return txs.sort((a, b) => b.height - a.height)
|
||||
}
|
||||
return txs.sort((a, b) => a.height - b.height)
|
||||
} catch (err) {
|
||||
console.log('Error in util.js/sortConfTxs()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Electrumx.sortAllTxs() sortAllTxs()
|
||||
* @apiName ElectrumX sortAllTxs
|
||||
* @apiGroup ElectrumX
|
||||
* @apiDescription Sort the output of Electrum.transactions() by block height.
|
||||
*
|
||||
* A simple sort function for the output of Electrum.transactions().
|
||||
* Assumes that unconfirmed transactions will make it into the next block. Any
|
||||
* unconfirmed transactions have their block height with the height of the next
|
||||
* block. Returns a Promise.
|
||||
*
|
||||
* Sorts in 'ASCENDING' order by default, or 'DESCENDING' can be specified.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* const txs = await bchjs.Electrumx.transactions('bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v')
|
||||
* const sortedTxs = await bchjs.Electrumx.sortAllTxs(txs.transactions, 'ASCENDING')
|
||||
* console.log(sortedTxs)
|
||||
* })()
|
||||
*
|
||||
* // [
|
||||
* // {
|
||||
* // "height": 560430,
|
||||
* // "tx_hash": "3e1f3e882be9c03897eeb197224bf87f312be556a89f4308fabeeeabcf9bc851"
|
||||
* // },
|
||||
* // {
|
||||
* // "height": 560534,
|
||||
* // "tx_hash": "4ebbeaac51ce141e262964e3a0ce11b96ca72c0dffe9b4127ce80135f503a280"
|
||||
* // }
|
||||
* // ]
|
||||
*/
|
||||
// Substitute zero-conf txs with the current block-height + 1
|
||||
async sortAllTxs (txs, sortingOrder = 'DESCENDING') {
|
||||
try {
|
||||
// Calculate the height of the next block
|
||||
const nextBlock = (await this.blockchain.getBlockCount()) + 1
|
||||
|
||||
// Replace the height of any zero-conf transactions with the height of
|
||||
// the next block.
|
||||
const modifiedTxs = txs.map(elem => {
|
||||
if (elem.height <= 0) elem.height = nextBlock
|
||||
return elem
|
||||
})
|
||||
// console.log(`modifiedTxs: ${JSON.stringify(modifiedTxs, null, 2)}`)
|
||||
|
||||
// Sort the modified array of transactions.
|
||||
return this.sortConfTxs(modifiedTxs, sortingOrder)
|
||||
} catch (err) {
|
||||
console.log('Error in util.js/sort0ConfTxs')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ElectrumX
|
||||
|
||||
+4
-2
@@ -35,11 +35,13 @@ class Encryption {
|
||||
// Search the blockchain for a public key associated with a BCH address.
|
||||
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}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
// let _this
|
||||
|
||||
class Generating {
|
||||
constructor (config) {
|
||||
@@ -24,14 +24,14 @@ class Generating {
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
// _this = this
|
||||
}
|
||||
|
||||
async generateToAddress (blocks, address, maxtries = 1000000) {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${this.restURL}generating/generateToAddress/${blocks}/${address}?maxtries=${maxtries}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
|
||||
+22
-22
@@ -19,7 +19,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* bchjs.HDNode.fromSeed(seedBuffer);
|
||||
*
|
||||
@@ -28,7 +28,7 @@ class HDNode {
|
||||
* // create mnemonic from entropy
|
||||
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* bchjs.HDNode.fromSeed(seedBuffer);
|
||||
*/
|
||||
@@ -54,7 +54,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // to legacy address
|
||||
@@ -66,7 +66,7 @@ class HDNode {
|
||||
* // create mnemonic from entropy
|
||||
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // to cash address
|
||||
@@ -88,7 +88,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // to cash address
|
||||
@@ -100,7 +100,7 @@ class HDNode {
|
||||
* // create mnemonic from entropy
|
||||
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // to cash address
|
||||
@@ -121,7 +121,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.SLP.HDNode.fromSeed(seedBuffer);
|
||||
* // to cash address
|
||||
@@ -133,7 +133,7 @@ class HDNode {
|
||||
* // create mnemonic from entropy
|
||||
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.SLP.HDNode.fromSeed(seedBuffer);
|
||||
* // to cash address
|
||||
@@ -156,7 +156,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // to WIF
|
||||
@@ -168,7 +168,7 @@ class HDNode {
|
||||
* // create mnemonic from entropy
|
||||
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // to WIF
|
||||
@@ -190,7 +190,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // to extended public key
|
||||
@@ -202,7 +202,7 @@ class HDNode {
|
||||
* // create mnemonic from entropy
|
||||
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // to extended public key
|
||||
@@ -224,7 +224,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // to extended private key
|
||||
@@ -236,7 +236,7 @@ class HDNode {
|
||||
* // create mnemonic from entropy
|
||||
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // to extended private key
|
||||
@@ -258,7 +258,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create root seed buffer from mnemonic
|
||||
* let rootSeed= bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let rootSeed= await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from root seed
|
||||
* let hdNode = bchjs.HDNode.fromSeed(rootSeed);
|
||||
* // create public key buffer from HDNode
|
||||
@@ -269,7 +269,7 @@ class HDNode {
|
||||
* // create mnemonic from entropy
|
||||
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // create public key buffer from HDNode
|
||||
@@ -290,7 +290,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create root seed buffer from mnemonic
|
||||
* let rootSeed= bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let rootSeed= await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from root seed
|
||||
* let hdNode = bchjs.HDNode.fromSeed(rootSeed);
|
||||
* // create public key buffer from HDNode
|
||||
@@ -302,7 +302,7 @@ class HDNode {
|
||||
* // create mnemonic from entropy
|
||||
* let mnemonic = bchjs.Mnemonic.fromEntropy(entropy);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // create public key buffer from HDNode
|
||||
@@ -370,7 +370,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // derive hardened child HDNode
|
||||
@@ -391,7 +391,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // derive unhardened child HDNode
|
||||
@@ -412,7 +412,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create seed buffer from mnemonic
|
||||
* let seedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let seedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create HDNode from seed buffer
|
||||
* let hdNode = bchjs.HDNode.fromSeed(seedBuffer);
|
||||
* // derive hardened child HDNode
|
||||
@@ -615,7 +615,7 @@ class HDNode {
|
||||
* // create mnemonic
|
||||
* let mnemonic = bchjs.Mnemonic.generate(128);
|
||||
* // create root seed buffer
|
||||
* let rootSeedBuffer = bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* let rootSeedBuffer = await bchjs.Mnemonic.toSeed(mnemonic);
|
||||
* // create master hd node
|
||||
* let masterHDNode = bchjs.HDNode.fromSeed(rootSeedBuffer);
|
||||
* // derive child node
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ class IPFS {
|
||||
constructor (config) {
|
||||
this.IPFS_API = process.env.IPFS_API
|
||||
? process.env.IPFS_API
|
||||
: 'https://ipfs-api.fullstack.cash'
|
||||
: 'https://ipfs-file-upload.fullstackcash.nl'
|
||||
// : `http://localhost:5001`
|
||||
|
||||
// Default options when calling axios.
|
||||
|
||||
+6
-6
@@ -1,6 +1,6 @@
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
// let _this
|
||||
|
||||
class Mining {
|
||||
constructor (config) {
|
||||
@@ -24,14 +24,14 @@ class Mining {
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
// _this = this
|
||||
}
|
||||
|
||||
async getBlockTemplate (templateRequest) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}mining/getBlockTemplate/${templateRequest}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -44,7 +44,7 @@ class Mining {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}mining/getMiningInfo`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -57,7 +57,7 @@ class Mining {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}mining/getNetworkHashps?nblocks=${nblocks}&height=${height}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
@@ -71,7 +71,7 @@ class Mining {
|
||||
if (parameters) path = `${path}?parameters=${parameters}`
|
||||
|
||||
try {
|
||||
const response = await axios.post(path, _this.axiosOptions)
|
||||
const response = await axios.post(path, this.axiosOptions)
|
||||
return response.data
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
|
||||
+10
-10
@@ -5,7 +5,7 @@
|
||||
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
// let _this
|
||||
|
||||
class Ninsight {
|
||||
constructor (config) {
|
||||
@@ -27,7 +27,7 @@ class Ninsight {
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
// _this = this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +75,7 @@ class Ninsight {
|
||||
{
|
||||
addresses: [address]
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
|
||||
@@ -86,7 +86,7 @@ class Ninsight {
|
||||
{
|
||||
addresses: address
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -143,7 +143,7 @@ class Ninsight {
|
||||
{
|
||||
addresses: [address]
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -153,7 +153,7 @@ class Ninsight {
|
||||
{
|
||||
addresses: address
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -219,7 +219,7 @@ class Ninsight {
|
||||
{
|
||||
addresses: [address]
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -229,7 +229,7 @@ class Ninsight {
|
||||
{
|
||||
addresses: address
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -292,7 +292,7 @@ class Ninsight {
|
||||
{
|
||||
txids: [txid]
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -302,7 +302,7 @@ class Ninsight {
|
||||
{
|
||||
txids: txid
|
||||
},
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
|
||||
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
This library interacts with the public REST API endpoints that OpenBazaar
|
||||
provides for their application.
|
||||
*/
|
||||
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
|
||||
class OpenBazaar {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
|
||||
// Add JWT token to the authorization header.
|
||||
this.axiosOptions = {
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
}
|
||||
|
||||
/**
|
||||
* @api OpenBazaar.balance() balance()
|
||||
* @apiName OpenBazaar Balance
|
||||
* @apiGroup OpenBazaar
|
||||
* @apiDescription Return Balance about an address.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* let balance = await bchjs.OpenBazaar.balance('bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9');
|
||||
* console.log(balance)
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* {
|
||||
* page: 1,
|
||||
* totalPages: 1,
|
||||
* itemsOnPage: 1000,
|
||||
* addrStr: "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9",
|
||||
* balance: "0.00001",
|
||||
* totalReceived: "0.00001",
|
||||
* totalSent: "0",
|
||||
* unconfirmedBalance: "0",
|
||||
* unconfirmedTxApperances: 0,
|
||||
* txApperances: 1,
|
||||
* transactions: [
|
||||
* "2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7"
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
*/
|
||||
async balance (address) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === 'string') {
|
||||
let response
|
||||
if (process.env.NETWORK === 'testnet') {
|
||||
response = await axios.get(
|
||||
`https://tbch.blockbook.api.openbazaar.org/api/address/${address}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
} else {
|
||||
response = await axios.get(
|
||||
`https://bch.blockbook.api.openbazaar.org/api/address/${address}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
}
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error('Input address must be a string.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api OpenBazaar.utxo() utxo()
|
||||
* @apiName OpenBazaar Utxo
|
||||
* @apiGroup OpenBazaar
|
||||
* @apiDescription Return list of uxto for address.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* let utxo = await bchjs.OpenBazaar.utxo('bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9');
|
||||
* console.log(utxo);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* [
|
||||
* {
|
||||
* txid: "2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7",
|
||||
* vout: 0,
|
||||
* amount: "0.00001",
|
||||
* satoshis: 1000,
|
||||
* height: 602405,
|
||||
* confirmations: 11
|
||||
* }
|
||||
* ]
|
||||
*/
|
||||
async utxo (address) {
|
||||
try {
|
||||
// Handle single address.
|
||||
if (typeof address === 'string') {
|
||||
let response
|
||||
if (process.env.NETWORK === 'testnet') {
|
||||
response = await axios.get(
|
||||
`https://tbch.blockbook.api.openbazaar.org/api/utxo/${address}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
} else {
|
||||
response = await axios.get(
|
||||
`https://bch.blockbook.api.openbazaar.org/api/utxo/${address}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
}
|
||||
return response.data
|
||||
}
|
||||
throw new Error('Input address must be a string.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api OpenBazaar.tx() tx()
|
||||
* @apiName OpenBazaar Tx
|
||||
* @apiGroup OpenBazaar
|
||||
* @apiDescription Get details on a transaction.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* let txDetails = await bchjs.OpenBazaar.tx(`2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7`);
|
||||
* console.log(txDetails);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
*{
|
||||
* txid: "2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7",
|
||||
* version: 2,
|
||||
* vin: [
|
||||
* {
|
||||
* txid: "5f09d317e24c5d376f737a2711f3bd1d381abdb41743fff3819b4f76382e1eac",
|
||||
* vout: 1,
|
||||
* sequence: 4294967295,
|
||||
* n: 0,
|
||||
* scriptSig: {
|
||||
* hex:
|
||||
* "473044022000dd11c41a472f2e54348db996e60864d489429f12d1e044d49ff600b880c9590220715a926404bb0e2731a3795afb341ec1dad3f84ead7d27cd31fcc59abb14738c4121038476128287ac37c7a3cf7e8625fd5f024db1bc3d8e37395abe7bf42fda78d0d9"
|
||||
* },
|
||||
* addresses: ["bitcoincash:qqxy8hycqe89j7wa79gnggq6z3gaqu2uvqy26xehfe"],
|
||||
* value: "0.00047504"
|
||||
* }
|
||||
* ],
|
||||
* vout: [
|
||||
* {
|
||||
* value: "0.00001",
|
||||
* n: 0,
|
||||
* scriptPubKey: {
|
||||
* hex: "76a9142fe2c4c5ef359bb2fe1a849f891cecffbcfb4f7788ac",
|
||||
* addresses: ["bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9"]
|
||||
* },
|
||||
* spent: false
|
||||
* },
|
||||
* {
|
||||
* value: "0.00046256",
|
||||
* n: 1,
|
||||
* scriptPubKey: {
|
||||
* hex: "76a9142dbf5e1804c39a497b908c876097d63210c8490288ac",
|
||||
* addresses: ["bitcoincash:qqkm7hscqnpe5jtmjzxgwcyh6ceppjzfqg3jdn422e"]
|
||||
* },
|
||||
* spent: false
|
||||
* }
|
||||
* ],
|
||||
* blockhash: "0000000000000000010903a1fc4274499037c9339be9ec7338ee980331c20ce5",
|
||||
* blockheight: 602405,
|
||||
* confirmations: 11,
|
||||
* blocktime: 1569792892,
|
||||
* valueOut: "0.00047256",
|
||||
* valueIn: "0.00047504",
|
||||
* fees: "0.00000248",
|
||||
* hex:
|
||||
* "0200000001ac1e2e38764f9b81f3ff4317b4bd1a381dbdf311277a736f375d4ce217d3095f010000006a473044022000dd11c41a472f2e54348db996e60864d489429f12d1e044d49ff600b880c9590220715a926404bb0e2731a3795afb341ec1dad3f84ead7d27cd31fcc59abb14738c4121038476128287ac37c7a3cf7e8625fd5f024db1bc3d8e37395abe7bf42fda78d0d9ffffffff02e8030000000000001976a9142fe2c4c5ef359bb2fe1a849f891cecffbcfb4f7788acb0b40000000000001976a9142dbf5e1804c39a497b908c876097d63210c8490288ac00000000"
|
||||
* }
|
||||
*
|
||||
*/
|
||||
async tx (txid) {
|
||||
try {
|
||||
// Handle single txid.
|
||||
if (typeof txid === 'string') {
|
||||
let response
|
||||
if (process.env.NETWORK === 'testnet') {
|
||||
response = await axios.get(
|
||||
`https://tbch.blockbook.api.openbazaar.org/api/tx/${txid}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
} else {
|
||||
response = await axios.get(
|
||||
`https://bch.blockbook.api.openbazaar.org/api/tx/${txid}`,
|
||||
_this.axiosOptions
|
||||
)
|
||||
}
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error('Input txid must be a string.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = OpenBazaar
|
||||
+82
-8
@@ -1,10 +1,10 @@
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
// let _this
|
||||
|
||||
class Price {
|
||||
constructor (config) {
|
||||
_this = this
|
||||
// _this = this
|
||||
|
||||
this.restURL = config.restURL
|
||||
this.apiToken = config.apiToken
|
||||
@@ -68,7 +68,7 @@ class Price {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/usd`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
@@ -111,7 +111,7 @@ class Price {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/rates`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
@@ -127,8 +127,9 @@ class Price {
|
||||
* @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.
|
||||
* This endpoint gets the USD price of XEC from the Coinex API. The price
|
||||
* denominated in BCHA comes from bch-api, so it has a better chance of
|
||||
* working in Tor.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*(async () => {
|
||||
@@ -140,13 +141,86 @@ class Price {
|
||||
* }
|
||||
*})()
|
||||
*
|
||||
* // 18.81
|
||||
* // 212.34
|
||||
*/
|
||||
async getBchaUsd () {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/bchausd`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
const bchaPrice = response.data.usd * 1000000
|
||||
// Convert XEC denomination to BCHA denomination
|
||||
|
||||
return bchaPrice
|
||||
} catch (err) {
|
||||
if (err.response && err.response.data) throw err.response.data
|
||||
else throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api price.getXecUsd() getXecUsd()
|
||||
* @apiName Price getXecUsd()
|
||||
* @apiGroup Price
|
||||
* @apiDescription Return current price of XEC in USD.
|
||||
* This endpoint gets the USD price of XEC from the Coinex API. The price
|
||||
* comes from bch-api, so it has a better chance of working in Tor.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*(async () => {
|
||||
* try {
|
||||
* let current = await bchjs.Price.getXecUsd();
|
||||
* console.log(current);
|
||||
* } catch(err) {
|
||||
* console.err(err)
|
||||
* }
|
||||
*})()
|
||||
*
|
||||
* // 0.00021234
|
||||
*/
|
||||
async getXecUsd () {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/bchausd`,
|
||||
this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
return response.data.usd
|
||||
} catch (err) {
|
||||
if (err.response && err.response.data) throw err.response.data
|
||||
else throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api price.getBchUsd() getBchUsd()
|
||||
* @apiName Price getBchUsd()
|
||||
* @apiGroup Price
|
||||
* @apiDescription Return current price of BCH in USD.
|
||||
* This endpoint gets the USD price of BCH 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.getBchUsd();
|
||||
* console.log(current);
|
||||
* } catch(err) {
|
||||
* console.err(err)
|
||||
* }
|
||||
*})()
|
||||
*
|
||||
* // 512.81
|
||||
*/
|
||||
async getBchUsd () {
|
||||
try {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}price/bchusd`,
|
||||
this.axiosOptions
|
||||
)
|
||||
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
|
||||
|
||||
|
||||
+147
-22
@@ -1,6 +1,6 @@
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
// let _this
|
||||
|
||||
class RawTransactions {
|
||||
constructor (config) {
|
||||
@@ -27,7 +27,7 @@ class RawTransactions {
|
||||
// Encapsulate dependencies
|
||||
this.axios = axios
|
||||
|
||||
_this = this
|
||||
// this = this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,7 +98,7 @@ class RawTransactions {
|
||||
if (typeof hex === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}rawtransactions/decodeRawTransaction/${hex}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -111,9 +111,7 @@ class RawTransactions {
|
||||
data: {
|
||||
hexes: hex
|
||||
},
|
||||
headers: {
|
||||
authorization: `Token ${_this.apiToken}`
|
||||
}
|
||||
headers: this.axiosOptions.headers
|
||||
}
|
||||
const response = await axios(options)
|
||||
|
||||
@@ -122,7 +120,8 @@ class RawTransactions {
|
||||
|
||||
throw new Error('Input must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
if (error.error) throw new Error(error.error)
|
||||
else if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
@@ -167,7 +166,7 @@ class RawTransactions {
|
||||
if (typeof script === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}rawtransactions/decodeScript/${script}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -178,9 +177,7 @@ class RawTransactions {
|
||||
data: {
|
||||
hexes: script
|
||||
},
|
||||
headers: {
|
||||
authorization: `Token ${this.apiToken}`
|
||||
}
|
||||
headers: this.axiosOptions.headers
|
||||
}
|
||||
const response = await axios(options)
|
||||
|
||||
@@ -189,7 +186,8 @@ class RawTransactions {
|
||||
|
||||
throw new Error('Input must be a string or array of strings.')
|
||||
} catch (error) {
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
if (error.error) throw new Error(error.error)
|
||||
else if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
@@ -258,12 +256,16 @@ class RawTransactions {
|
||||
* // time: 1547752564,
|
||||
* // blocktime: 1547752564 } ]
|
||||
*/
|
||||
async getRawTransaction (txid, verbose = false) {
|
||||
async getRawTransaction (txid, verbose = false, usrObj = null) {
|
||||
try {
|
||||
if (typeof txid === 'string') {
|
||||
// console.log(
|
||||
// 'getRawTransaction() this.axiosOptions: ',
|
||||
// this.axiosOptions
|
||||
// )
|
||||
const response = await axios.get(
|
||||
`${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=${verbose}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
return response.data
|
||||
@@ -273,9 +275,10 @@ class RawTransactions {
|
||||
url: `${this.restURL}rawtransactions/getRawTransaction`,
|
||||
data: {
|
||||
txids: txid,
|
||||
verbose: verbose
|
||||
verbose: verbose,
|
||||
usrObj // pass user data when making an internal call.
|
||||
},
|
||||
headers: _this.axiosOptions.headers
|
||||
headers: this.axiosOptions.headers
|
||||
}
|
||||
const response = await axios(options)
|
||||
|
||||
@@ -284,8 +287,129 @@ class RawTransactions {
|
||||
|
||||
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
|
||||
if (error.error) throw new Error(error.error)
|
||||
|
||||
// This case handles rate limit errors.
|
||||
if (error.response && error.response.data && error.response.data.error) {
|
||||
throw new Error(error.response.data.error)
|
||||
} else if (error.response && error.response.data) {
|
||||
throw error.response.data
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
// Given verbose transaction details, this function retrieves the transaction
|
||||
// data for the inputs (the parent transactions). It returns an array of
|
||||
// objects. Each object corresponds to a transaction input, and contains
|
||||
// the address that generated that input UTXO.
|
||||
//
|
||||
// Assumes a single TX. Does not yet work with an array of TXs.
|
||||
// This function returns an array of objects, each object if formated as follows:
|
||||
// {
|
||||
// vin: 0, // The position of the input for the given txid
|
||||
// address: bitcoincash:qzhrpmu7nruyfcemeanqh5leuqcnf6zkjq4qm9nqh0
|
||||
// }
|
||||
async _getInputAddrs (txDetails) {
|
||||
try {
|
||||
const retArray = [] // Return array
|
||||
|
||||
for (let i = 0; i < txDetails.vin.length; i++) {
|
||||
// The first input represents the sender of the BCH or tokens.
|
||||
const vin = txDetails.vin[i]
|
||||
const inputTxid = vin.txid
|
||||
const inputVout = vin.vout
|
||||
|
||||
// TODO: Coinbase TXs have no input transaction. Figure out how to
|
||||
// handle this corner case.
|
||||
|
||||
// Get the TX details for the input, in order to retrieve the address of
|
||||
// the sender.
|
||||
const txDetailsParent = await this.getRawTransaction(inputTxid, true)
|
||||
// console.log(
|
||||
// `txDetailsParent: ${JSON.stringify(txDetailsParent, null, 2)}`
|
||||
// )
|
||||
|
||||
// The vout from the previous tx that represents the sender.
|
||||
const voutSender = txDetailsParent.vout[inputVout]
|
||||
|
||||
retArray.push({
|
||||
vin: i,
|
||||
address: voutSender.scriptPubKey.addresses[0],
|
||||
value: voutSender.value
|
||||
})
|
||||
}
|
||||
|
||||
return retArray
|
||||
} catch (error) {
|
||||
if (error.error) throw new Error(error.error)
|
||||
|
||||
// This case handles rate limit errors.
|
||||
if (error.response && error.response.data && error.response.data.error) {
|
||||
throw new Error(error.response.data.error)
|
||||
} else if (error.response && error.response.data) {
|
||||
throw error.response.data
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api RawTransactions.getTxData() getTxData()
|
||||
* @apiName getTxData
|
||||
* @apiGroup RawTransactions
|
||||
* @apiDescription
|
||||
* Returns an object of transaction data, including addresses for input UTXOs.
|
||||
*
|
||||
* This function is equivalent to running `getRawTransaction (txid, true)`,
|
||||
* execept the `vin` array will be populated with an `address` property that
|
||||
* contains the `bitcoincash:` address of the sender for each input.
|
||||
*
|
||||
* This function will only work with a single txid. It does not yet support an
|
||||
* array of TXIDs.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* let txData = await bchjs.RawTransactions.getTxData("0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098");
|
||||
* console.log(txData);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*/
|
||||
// Equivalent to running: async getRawTransaction (txid, verbose = true)
|
||||
// Only handles a single TXID (not arrays).
|
||||
// Appends the BCH address to the inputs of the transaction.
|
||||
async getTxData (txid) {
|
||||
try {
|
||||
if (typeof txid !== 'string') {
|
||||
throw new Error(
|
||||
'Input to raw-transaction.js/getTxData() must be a string containg a TXID.'
|
||||
)
|
||||
}
|
||||
|
||||
// Get the TX details for the transaction under consideration.
|
||||
const txDetails = await this.getRawTransaction(txid, true)
|
||||
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
|
||||
|
||||
const inAddrs = await this._getInputAddrs(txDetails)
|
||||
// console.log(`inAddrs: ${JSON.stringify(inAddrs, null, 2)}`)
|
||||
|
||||
// Add the input address to the transaction data.
|
||||
for (let i = 0; i < inAddrs.length; i++) {
|
||||
txDetails.vin[i].address = inAddrs[i].address
|
||||
txDetails.vin[i].value = inAddrs[i].value
|
||||
}
|
||||
|
||||
return txDetails
|
||||
} catch (error) {
|
||||
if (error.error) throw new Error(error.error)
|
||||
|
||||
// This case handles rate limit errors.
|
||||
if (error.response && error.response.data && error.response.data.error) {
|
||||
throw new Error(error.response.data.error)
|
||||
} else if (error.response && error.response.data) {
|
||||
throw error.response.data
|
||||
} else throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,7 +451,7 @@ class RawTransactions {
|
||||
if (typeof hex === 'string') {
|
||||
const response = await this.axios.get(
|
||||
`${this.restURL}rawtransactions/sendRawTransaction/${hex}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
if (response.data === '66: insufficient priority') {
|
||||
@@ -348,16 +472,17 @@ class RawTransactions {
|
||||
data: {
|
||||
hexes: hex
|
||||
},
|
||||
headers: _this.axiosOptions.headers
|
||||
headers: this.axiosOptions.headers
|
||||
}
|
||||
const response = await _this.axios(options)
|
||||
const response = await this.axios(options)
|
||||
|
||||
return response.data
|
||||
}
|
||||
|
||||
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
|
||||
if (error.error) throw new Error(error.error)
|
||||
else if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
+100
-2
@@ -8,16 +8,21 @@
|
||||
(Parent) token.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
const axios = require('axios')
|
||||
|
||||
// Local libraries.
|
||||
const Address = require('./address')
|
||||
|
||||
// const BigNumber = require('bignumber.js')
|
||||
const slpMdm = require('slp-mdm')
|
||||
|
||||
// let _this
|
||||
// const addy = new Address()
|
||||
let addy
|
||||
const TransactionBuilder = require('../transaction-builder')
|
||||
|
||||
class TokenType1 {
|
||||
class Nft1 {
|
||||
constructor (config) {
|
||||
this.restURL = config.restURL
|
||||
|
||||
@@ -25,6 +30,8 @@ class TokenType1 {
|
||||
|
||||
// Instantiate the transaction builder.
|
||||
TransactionBuilder.setAddress(addy)
|
||||
|
||||
// _this = this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,6 +419,97 @@ class TokenType1 {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.NFT1.listNFTGroupChildren() listNFTGroupChildren()
|
||||
* @apiName listNFTGroupChildren
|
||||
* @apiGroup SLP NFT1
|
||||
* @apiDescription Return list of NFT children tokens in a NFT Group.
|
||||
* It's assumed provided groupId parameter is for an NFT Group token (type=129)
|
||||
*
|
||||
* Returns an Array with GENESIS transaction IDs of the children tokens.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*
|
||||
* const groupId = '68cd33ecd909068fbea318ae5ff1d6207cf754e53b191327d6d73b6916424c0a'
|
||||
* const children = await bchjs.SLP.Nft1.listNFTGroupChildren(groupId)
|
||||
*
|
||||
* children = {
|
||||
* "nftChildren": [
|
||||
* "45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a9",
|
||||
* "928ce61fe1006b1325a0ba0dce700bf83986a6f0691ba26e121c9ac035d12a55"
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
async listNFTGroupChildren (groupId) {
|
||||
try {
|
||||
if (typeof groupId === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}slp/nftChildren/${groupId}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error('groupId must be a string.')
|
||||
} catch (error) {
|
||||
// console.log('Error in listNFTGroupChildren()')
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api SLP.NFT1.parentNFTGroup() parentNFTGroup()
|
||||
* @apiName parentNFTGroup
|
||||
* @apiGroup SLP NFT1
|
||||
* @apiDescription Return parent NFT Group information for a given NFT child token.
|
||||
* It's assumed provided groupId parameter is for an NFT Child token (type=65)
|
||||
*
|
||||
* Returns a JSON with NFT group information.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
*
|
||||
* const tokenId = '45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a9'
|
||||
* const group = await bchjs.SLP.Nft1.parentNFTGroup(tokenId)
|
||||
*
|
||||
* group = {
|
||||
* "nftGroup": {
|
||||
* "decimals": 0,
|
||||
* "timestamp": "2021-05-03 10:36:01",
|
||||
* "timestamp_unix": 1620038161,
|
||||
* "versionType": 129,
|
||||
* "documentUri": "psfoundation.cash",
|
||||
* "symbol": "PSF.TEST.GROUP",
|
||||
* "name": "PSF Test NFT Group",
|
||||
* "containsBaton": true,
|
||||
* "id": "68cd33ecd909068fbea318ae5ff1d6207cf754e53b191327d6d73b6916424c0a",
|
||||
* "documentHash": null,
|
||||
* "initialTokenQty": 1000000,
|
||||
* "blockCreated": 686117,
|
||||
* "totalMinted": null,
|
||||
* "totalBurned": null,
|
||||
* "circulatingSupply": null
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
async parentNFTGroup (tokenId) {
|
||||
try {
|
||||
if (typeof tokenId === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}slp/nftGroup/${tokenId}`,
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
}
|
||||
|
||||
throw new Error('tokenId must be a string.')
|
||||
} catch (error) {
|
||||
// console.log('Error in parentNFTGroup()')
|
||||
if (error.response && error.response.data) throw error.response.data
|
||||
else throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TokenType1
|
||||
module.exports = Nft1
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ class SLP {
|
||||
this.Address = new Address(config)
|
||||
this.ECPair = ECPair
|
||||
this.TokenType1 = new TokenType1(config)
|
||||
this.NFT1 = new NFT1(this.restURL)
|
||||
this.NFT1 = new NFT1(config)
|
||||
this.Utils = new Utils(config)
|
||||
}
|
||||
}
|
||||
|
||||
+11
-11
@@ -118,20 +118,20 @@ class TokenType1 {
|
||||
|
||||
// Convert the send quantity to the format expected by slp-mdm.
|
||||
const baseQty = sendQtyBig.toString()
|
||||
console.log('baseQty: ', baseQty)
|
||||
// console.log('baseQty: ', baseQty)
|
||||
|
||||
// Convert the change quantity to the format expected by slp-mdm.
|
||||
const baseChange = change.toString()
|
||||
console.log('baseChange: ', baseChange)
|
||||
// console.log('baseChange: ', baseChange)
|
||||
|
||||
// Check for potential burns
|
||||
const outputQty = new BigNumber(baseChange).plus(
|
||||
new BigNumber(baseQty)
|
||||
)
|
||||
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')
|
||||
throw new Error(
|
||||
'Token transaction inputs do not match outputs, cannot send transaction'
|
||||
)
|
||||
}
|
||||
|
||||
// Generate the OP_RETURN as a Buffer.
|
||||
@@ -152,7 +152,9 @@ class TokenType1 {
|
||||
const tokenSingleOutputError =
|
||||
noChangeOutputQty.minus(noChangeInputQty).toString() !== '0'
|
||||
if (tokenSingleOutputError) {
|
||||
throw new Error('Token transaction inputs do not match outputs, cannot send transaction')
|
||||
throw new Error(
|
||||
'Token transaction inputs do not match outputs, cannot send transaction'
|
||||
)
|
||||
}
|
||||
|
||||
// Generate the OP_RETURN as a Buffer.
|
||||
@@ -378,9 +380,7 @@ class TokenType1 {
|
||||
|
||||
// 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.'
|
||||
)
|
||||
throw new Error('Minting baton could not be found in tokenUtxos array.')
|
||||
}
|
||||
|
||||
const tokenId = mintBatonUtxo.tokenId
|
||||
@@ -454,7 +454,7 @@ class TokenType1 {
|
||||
const result = await _this.axios.post(
|
||||
`${this.restURL}slp/generatesendopreturn`,
|
||||
data,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
|
||||
const slpSendObj = result.data
|
||||
|
||||
+505
-216
File diff suppressed because it is too large
Load Diff
@@ -1,28 +0,0 @@
|
||||
const io = require('socket.io-client')
|
||||
|
||||
class Socket {
|
||||
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'
|
||||
this.socket = io(`${restURL}`)
|
||||
}
|
||||
|
||||
if (config.callback) config.callback()
|
||||
}
|
||||
}
|
||||
|
||||
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)) }
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Socket
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
High-level functions for working with Transactions
|
||||
*/
|
||||
|
||||
const RawTransaction = require('./raw-transactions')
|
||||
const SlpUtils = require('./slp/utils')
|
||||
const BigNumber = require('bignumber.js')
|
||||
|
||||
class Transaction {
|
||||
constructor (config) {
|
||||
// Encapsulate dependencies
|
||||
this.slpUtils = new SlpUtils(config)
|
||||
this.rawTransaction = new RawTransaction(config)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Transaction.get() get()
|
||||
* @apiName get
|
||||
* @apiGroup Transaction
|
||||
* @apiDescription
|
||||
* Returns an object of transaction data, including addresses for input UTXOs.
|
||||
* If it is a SLP token transaction, the token information for inputs and
|
||||
* outputs will also be included.
|
||||
*
|
||||
* This is an API heavy call. This function will only work with a single txid.
|
||||
* It does not yet support an array of TXIDs.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* let txData = await bchjs.Transaction.get("0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098");
|
||||
* console.log(txData);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*/
|
||||
async get (txid) {
|
||||
try {
|
||||
if (typeof txid !== 'string') {
|
||||
throw new Error(
|
||||
'Input to Transaction.get() must be a string containing a TXID.'
|
||||
)
|
||||
}
|
||||
|
||||
const txDetails = await this.rawTransaction.getTxData(txid)
|
||||
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
|
||||
|
||||
// Setup default SLP properties.
|
||||
txDetails.isValidSLPTx = false
|
||||
|
||||
// First get the token information for the output. If that fails, then
|
||||
// this is not an SLP transaction, and this method can return false.
|
||||
let outTokenData
|
||||
try {
|
||||
outTokenData = await this.slpUtils.decodeOpReturn(txid)
|
||||
// console.log(`outTokenData: ${JSON.stringify(outTokenData, null, 2)}`)
|
||||
|
||||
// Get Genesis data for this token.
|
||||
const genesisData = await this.slpUtils.decodeOpReturn(
|
||||
outTokenData.tokenId
|
||||
// decodeOpReturnCache
|
||||
// usrObj // pass user data when making an internal call.
|
||||
)
|
||||
// console.log(`genesisData: ${JSON.stringify(genesisData, null, 2)}`)
|
||||
|
||||
// Add token information to the tx details object.
|
||||
txDetails.tokenTxType = outTokenData.txType
|
||||
txDetails.tokenId = outTokenData.tokenId
|
||||
txDetails.tokenTicker = genesisData.ticker
|
||||
txDetails.tokenName = genesisData.name
|
||||
txDetails.tokenDecimals = genesisData.decimals
|
||||
txDetails.tokenUri = genesisData.documentUri
|
||||
txDetails.tokenDocHash = genesisData.documentHash
|
||||
|
||||
// Add the token quantity to each output.
|
||||
for (let i = 0; i < outTokenData.amounts.length; i++) {
|
||||
const rawQty = outTokenData.amounts[i]
|
||||
// const realQty = Number(rawQty) / Math.pow(10, txDetails.tokenDecimals)
|
||||
|
||||
// Calculate the real quantity using a BigNumber, then convert it to a
|
||||
// floating point number.
|
||||
let realQty = new BigNumber(rawQty).dividedBy(
|
||||
10 ** parseInt(txDetails.tokenDecimals)
|
||||
)
|
||||
realQty = realQty.toString()
|
||||
// realQty = parseFloat(realQty)
|
||||
|
||||
txDetails.vout[i + 1].tokenQtyStr = realQty
|
||||
txDetails.vout[i + 1].tokenQty = parseFloat(realQty)
|
||||
}
|
||||
|
||||
// Add tokenQty = null to any outputs that don't have a value.
|
||||
for (let i = 0; i < txDetails.vout.length; i++) {
|
||||
const thisVout = txDetails.vout[i]
|
||||
|
||||
if (!thisVout.tokenQty && thisVout.tokenQty !== 0) {
|
||||
thisVout.tokenQty = null
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through each input and retrieve the token data.
|
||||
for (let i = 0; i < txDetails.vin.length; i++) {
|
||||
const thisVin = txDetails.vin[i]
|
||||
|
||||
try {
|
||||
// If decodeOpReturn() throws an error, then this input is not
|
||||
// from an SLP transaction and can be ignored.
|
||||
const inTokenData = await this.slpUtils.decodeOpReturn(thisVin.txid)
|
||||
// console.log(
|
||||
// `vin[${i}] tokenData: ${JSON.stringify(inTokenData, null, 2)}`
|
||||
// )
|
||||
|
||||
let tokenQty = 0
|
||||
if (inTokenData.txType === 'SEND') {
|
||||
// Get the appropriate vout token amount. This may throw an error,
|
||||
// which means this Vin is not actually a token UTXO, it was just
|
||||
// associated with a previous token TX.
|
||||
tokenQty = inTokenData.amounts[thisVin.vout - 1]
|
||||
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
|
||||
|
||||
//
|
||||
} else if (inTokenData.txType === 'GENESIS') {
|
||||
// Only vout[1] of a Genesis transaction represents the tokens.
|
||||
// Any other outputs in that transaction are normal BCH UTXOs.
|
||||
if (thisVin.vout === 1) {
|
||||
tokenQty = inTokenData.qty
|
||||
// console.log(`tokenQty: ${JSON.stringify(tokenQty, null, 2)}`)
|
||||
}
|
||||
|
||||
//
|
||||
} else {
|
||||
console.log(
|
||||
'Unexpected code path in Transaction.get(). Is this a MINT transaction?'
|
||||
)
|
||||
console.log(inTokenData)
|
||||
throw new Error('Unexpected code path')
|
||||
}
|
||||
|
||||
if (tokenQty) {
|
||||
// const realQty =
|
||||
// Number(tokenQty) / Math.pow(10, txDetails.tokenDecimals)
|
||||
|
||||
// Calculate the real quantity using a BigNumber, then convert it to a
|
||||
// floating point number.
|
||||
let realQty = new BigNumber(tokenQty).dividedBy(
|
||||
10 ** parseInt(txDetails.tokenDecimals)
|
||||
)
|
||||
realQty = realQty.toString()
|
||||
// realQty = parseFloat(realQty)
|
||||
|
||||
thisVin.tokenQtyStr = realQty
|
||||
thisVin.tokenQty = parseFloat(realQty)
|
||||
// txDetails.vin[i].tokenQty = tokenQty
|
||||
} else {
|
||||
thisVin.tokenQty = null
|
||||
}
|
||||
} catch (err) {
|
||||
// If decodeOpReturn() throws an error, then this input is not
|
||||
// from an SLP transaction and can be ignored.
|
||||
// thisVin.tokenQty = null
|
||||
thisVin.tokenQty = null
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, validate the SLP TX.
|
||||
// this.slpUtils.waterfallValidateTxid(txid, usrObj)
|
||||
txDetails.isValidSLPTx = await this.slpUtils.waterfallValidateTxid(txid)
|
||||
} catch (err) {
|
||||
// console.log('Error: ', err)
|
||||
|
||||
// This case handles rate limit errors.
|
||||
if (err.response && err.response.data && err.response.data.error) {
|
||||
throw new Error(err.response.data.error)
|
||||
}
|
||||
|
||||
// If decoding the op_return fails, then it's not an SLP transaction,
|
||||
// and the non-hyrated TX details can be returned.
|
||||
return txDetails
|
||||
}
|
||||
|
||||
return txDetails
|
||||
} catch (err) {
|
||||
// console.error('Error in transactions.js/get(): ', err)
|
||||
|
||||
// This case handles rate limit errors.
|
||||
if (err.response && err.response.data && err.response.data.error) {
|
||||
throw new Error(err.response.data.error)
|
||||
}
|
||||
|
||||
if (err.error) throw new Error(err.error)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Transaction
|
||||
+151
-4
@@ -1,6 +1,6 @@
|
||||
const axios = require('axios')
|
||||
|
||||
let _this
|
||||
// let _this
|
||||
|
||||
class Util {
|
||||
constructor (config) {
|
||||
@@ -24,11 +24,158 @@ class Util {
|
||||
}
|
||||
}
|
||||
|
||||
_this = this
|
||||
// _this = this
|
||||
}
|
||||
|
||||
/**
|
||||
* @api util.validateAddress() validateAddress()
|
||||
* @api Util.floor8() floor8()
|
||||
* @apiName floor8
|
||||
* @apiGroup Util
|
||||
* @apiDescription Round a number down to 8 decimal places.
|
||||
*
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* const num = 1.234567891111
|
||||
* const result = bchjs.Util.floor8(num)
|
||||
* console.log(result)
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // returns
|
||||
* 1.23456789
|
||||
*/
|
||||
// floor8 - round to 8 decimal places
|
||||
// Takes a number and returns it, rounded to the nearest 8 decimal place.
|
||||
floor8 (num) {
|
||||
const thisNum = Number(num)
|
||||
|
||||
if (isNaN(thisNum)) throw new Error('input must be a number')
|
||||
|
||||
let tempNum = thisNum * 100000000
|
||||
tempNum = Math.floor(tempNum)
|
||||
tempNum = tempNum / 100000000
|
||||
|
||||
return tempNum
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Util.floor2() floor2()
|
||||
* @apiName floor2
|
||||
* @apiGroup Util
|
||||
* @apiDescription Round a number down to 2 decimal places.
|
||||
*
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* const num = 1.234567891111
|
||||
* const result = bchjs.Util.floor2(num)
|
||||
* console.log(result)
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // returns
|
||||
* 1.23
|
||||
*/
|
||||
// floor2 - round down to 2 decimal places
|
||||
// Takes a number and returns it, rounded to the nearest 2 decimal place.
|
||||
floor2 (num) {
|
||||
const thisNum = Number(num)
|
||||
|
||||
if (isNaN(thisNum)) throw new Error('input must be a number')
|
||||
|
||||
let tempNum = thisNum * 100
|
||||
tempNum = Math.floor(tempNum)
|
||||
tempNum = tempNum / 100
|
||||
|
||||
return tempNum
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Util.chunk20() chunk20()
|
||||
* @apiName chunk20
|
||||
* @apiGroup Util
|
||||
* @apiDescription chunk up an array into multiple arrays of 20 elements each.
|
||||
* Input: arrayToSlice - a one-dimensional array of elements.
|
||||
* Returns a two-dimensional array. An array of 20-element arrays.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* const bigArray = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]
|
||||
*
|
||||
* const chunked = bchjs.Util.chunk20(bigArray)
|
||||
* console.log(chunked)
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // returns
|
||||
* [
|
||||
* [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],
|
||||
* [20,21,22,23,24,25,26]
|
||||
* ]
|
||||
*/
|
||||
// chunk20 - chunk up an array into multiple arrays of 20 elements each.
|
||||
// Input: arrayToSlice - a one-dimensional array of elements.
|
||||
// Returns a two-dimensional array. An array of 20-element arrays.
|
||||
chunk20 (arrayToSlice) {
|
||||
try {
|
||||
// Validate inputs
|
||||
if (!Array.isArray(arrayToSlice)) {
|
||||
throw new Error('input must be an array')
|
||||
}
|
||||
|
||||
let offset = 0
|
||||
const result = []
|
||||
|
||||
// Loop over the array and slice off chunks of 20 elements.
|
||||
while (offset < arrayToSlice.length) {
|
||||
const chunk = arrayToSlice.slice(offset, offset + 20)
|
||||
result.push(chunk)
|
||||
offset = offset + 20
|
||||
}
|
||||
|
||||
return result
|
||||
} catch (err) {
|
||||
console.error('Error in chunk20()')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Util.sleep() sleep()
|
||||
* @apiName sleep
|
||||
* @apiGroup Util
|
||||
* @apiDescription Promise-based delay.
|
||||
* Expects an integer as input, which represents milliseconds. This function
|
||||
* will return a Promise that resolves that many milliseconds later.
|
||||
*
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* const tenSeconds = 10000
|
||||
* await bchjs.Util.sleep(tenSeconds)
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
*/
|
||||
sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Util.validateAddress() validateAddress()
|
||||
* @apiName Validate Address.
|
||||
* @apiGroup Util
|
||||
* @apiDescription Return information about the given bitcoin address.
|
||||
@@ -78,7 +225,7 @@ class Util {
|
||||
if (typeof address === 'string') {
|
||||
const response = await axios.get(
|
||||
`${this.restURL}util/validateAddress/${address}`,
|
||||
_this.axiosOptions
|
||||
this.axiosOptions
|
||||
)
|
||||
return response.data
|
||||
|
||||
|
||||
+350
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
High-level functions for working with UTXOs
|
||||
|
||||
TODO:
|
||||
- Make a getWL() clone of get(), but uses hydrateUtxosWL()
|
||||
*/
|
||||
|
||||
// Local libraries
|
||||
const Electrumx = require('./electrumx')
|
||||
const Slp = require('./slp/slp')
|
||||
|
||||
class UTXO {
|
||||
constructor (config) {
|
||||
// Encapsulate dependencies for easier mocking.
|
||||
this.electrumx = new Electrumx(config)
|
||||
this.slp = new Slp(config)
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Utxo.get() get()
|
||||
* @apiName get
|
||||
* @apiGroup UTXO
|
||||
* @apiDescription Get UTXOs for an address
|
||||
*
|
||||
* Given an address, this function will return an object with thre following
|
||||
* properties:
|
||||
* - address: "" - the address these UTXOs are associated with
|
||||
* - bchUtxos: [] - UTXOs confirmed to be spendable as normal BCH
|
||||
* - nullUtxo: [] - UTXOs that did not pass SLP validation. Should be ignored and
|
||||
* not spent, to be safe.
|
||||
* - slpUtxos: {} - UTXOs confirmed to be colored as valid SLP tokens
|
||||
* - type1: {}
|
||||
* - tokens: [] - SLP token Type 1 tokens.
|
||||
* - mintBatons: [] - SLP token Type 1 mint batons.
|
||||
* - nft: {}
|
||||
* - tokens: [] - NFT tokens
|
||||
* - groupTokens: [] - NFT Group tokens, used to create NFT tokens.
|
||||
* - groupMintBatons: [] - Minting baton to create more NFT Group tokens.
|
||||
*
|
||||
* Note: You can pass in an optional second Boolean argument. The default
|
||||
* `false` will use the normal waterfall validation method. Set to `true`,
|
||||
* SLP UTXOs will be validated with the whitelist filtered SLPDB. This will
|
||||
* result is many more UTXOs in the `nullUtxos` array.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* let utxos = await bchjs.Utxo.get('simpleledger:qrm0c67wwqh0w7wjxua2gdt2xggnm90xwsr5k22euj');
|
||||
* console.log(utxos);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // returns
|
||||
* [
|
||||
* {
|
||||
* "address": "bitcoincash:qrm0c67wwqh0w7wjxua2gdt2xggnm90xws00a3lezv",
|
||||
* "bchUtxos": [
|
||||
* {
|
||||
* "height": 674513,
|
||||
* "tx_hash": "705bcc442e5a2770e560b528f52a47b1dcc9ce9ab6a8de9dfdefa55177f00d04",
|
||||
* "tx_pos": 3,
|
||||
* "value": 38134,
|
||||
* "txid": "705bcc442e5a2770e560b528f52a47b1dcc9ce9ab6a8de9dfdefa55177f00d04",
|
||||
* "vout": 3,
|
||||
* "isValid": false
|
||||
* }
|
||||
* ],
|
||||
* "nullUtxos": [],
|
||||
* "slpUtxos": {
|
||||
* "type1": {
|
||||
* "mintBatons": [
|
||||
* {
|
||||
* "height": 674512,
|
||||
* "tx_hash": "acbb0d3ceef55aa3e5fafc19335ae4bf2f8edba3c0567547dfd402391db32230",
|
||||
* "tx_pos": 2,
|
||||
* "value": 546,
|
||||
* "txid": "acbb0d3ceef55aa3e5fafc19335ae4bf2f8edba3c0567547dfd402391db32230",
|
||||
* "vout": 2,
|
||||
* "utxoType": "minting-baton",
|
||||
* "tokenId": "acbb0d3ceef55aa3e5fafc19335ae4bf2f8edba3c0567547dfd402391db32230",
|
||||
* "tokenTicker": "SLPTEST",
|
||||
* "tokenName": "SLP Test Token",
|
||||
* "tokenDocumentUrl": "https://FullStack.cash",
|
||||
* "tokenDocumentHash": "",
|
||||
* "decimals": 8,
|
||||
* "tokenType": 1,
|
||||
* "isValid": true
|
||||
* }
|
||||
* ],
|
||||
* "tokens": [
|
||||
* {
|
||||
* "height": 674512,
|
||||
* "tx_hash": "acbb0d3ceef55aa3e5fafc19335ae4bf2f8edba3c0567547dfd402391db32230",
|
||||
* "tx_pos": 1,
|
||||
* "value": 546,
|
||||
* "txid": "acbb0d3ceef55aa3e5fafc19335ae4bf2f8edba3c0567547dfd402391db32230",
|
||||
* "vout": 1,
|
||||
* "utxoType": "token",
|
||||
* "tokenQty": "100",
|
||||
* "tokenId": "acbb0d3ceef55aa3e5fafc19335ae4bf2f8edba3c0567547dfd402391db32230",
|
||||
* "tokenTicker": "SLPTEST",
|
||||
* "tokenName": "SLP Test Token",
|
||||
* "tokenDocumentUrl": "https://FullStack.cash",
|
||||
* "tokenDocumentHash": "",
|
||||
* "decimals": 8,
|
||||
* "tokenType": 1,
|
||||
* "isValid": true
|
||||
* }
|
||||
* ]
|
||||
* },
|
||||
* "nft": {
|
||||
* "groupMintBatons": [
|
||||
* {
|
||||
* "height": 674513,
|
||||
* "tx_hash": "705bcc442e5a2770e560b528f52a47b1dcc9ce9ab6a8de9dfdefa55177f00d04",
|
||||
* "tx_pos": 2,
|
||||
* "value": 546,
|
||||
* "txid": "705bcc442e5a2770e560b528f52a47b1dcc9ce9ab6a8de9dfdefa55177f00d04",
|
||||
* "vout": 2,
|
||||
* "utxoType": "minting-baton",
|
||||
* "transactionType": "mint",
|
||||
* "tokenId": "a9a2458a0f9f0761d5b8725c256f2e7fa35b9de4dec6f47b46e9f20d92d0e395",
|
||||
* "tokenType": 129,
|
||||
* "tokenTicker": "NFTGT",
|
||||
* "tokenName": "NFT Test Group Token",
|
||||
* "tokenDocumentUrl": "https://FullStack.cash",
|
||||
* "tokenDocumentHash": "",
|
||||
* "decimals": 0,
|
||||
* "mintBatonVout": 2,
|
||||
* "isValid": true
|
||||
* }
|
||||
* ],
|
||||
* "groupTokens": [
|
||||
* {
|
||||
* "height": 674513,
|
||||
* "tx_hash": "705bcc442e5a2770e560b528f52a47b1dcc9ce9ab6a8de9dfdefa55177f00d04",
|
||||
* "tx_pos": 1,
|
||||
* "value": 546,
|
||||
* "txid": "705bcc442e5a2770e560b528f52a47b1dcc9ce9ab6a8de9dfdefa55177f00d04",
|
||||
* "vout": 1,
|
||||
* "utxoType": "token",
|
||||
* "tokenQty": "10",
|
||||
* "transactionType": "mint",
|
||||
* "tokenId": "a9a2458a0f9f0761d5b8725c256f2e7fa35b9de4dec6f47b46e9f20d92d0e395",
|
||||
* "tokenType": 129,
|
||||
* "tokenTicker": "NFTGT",
|
||||
* "tokenName": "NFT Test Group Token",
|
||||
* "tokenDocumentUrl": "https://FullStack.cash",
|
||||
* "tokenDocumentHash": "",
|
||||
* "decimals": 0,
|
||||
* "mintBatonVout": 2,
|
||||
* "isValid": true
|
||||
* }
|
||||
* ],
|
||||
* "tokens": [
|
||||
* {
|
||||
* "height": 674512,
|
||||
* "tx_hash": "eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b",
|
||||
* "tx_pos": 1,
|
||||
* "value": 546,
|
||||
* "txid": "eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b",
|
||||
* "vout": 1,
|
||||
* "utxoType": "token",
|
||||
* "tokenQty": "1",
|
||||
* "tokenId": "eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b",
|
||||
* "tokenTicker": "NFT004",
|
||||
* "tokenName": "NFT Child",
|
||||
* "tokenDocumentUrl": "https://FullStack.cash",
|
||||
* "tokenDocumentHash": "",
|
||||
* "decimals": 0,
|
||||
* "tokenType": 65,
|
||||
* "isValid": true
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
*
|
||||
*/
|
||||
async get (address, useWhitelist = false) {
|
||||
try {
|
||||
// Convert address to an array if it is a string.
|
||||
if (typeof address === 'string') address = [address]
|
||||
|
||||
// Throw an error if there are more than 20 addresses passed in at a time.
|
||||
if (address.length > 20) throw new Error('Too many elements, 20 max.')
|
||||
|
||||
// Covert each address to a BCH address.
|
||||
const addr = address.map(elem => this.slp.Address.toCashAddress(elem))
|
||||
|
||||
// Get the UTXOs associated with the address.
|
||||
const utxoData = await this.electrumx.utxo(addr)
|
||||
// console.log(`utxoData: ${JSON.stringify(utxoData, null, 2)}`)
|
||||
|
||||
// Hydate the utxos with token information.
|
||||
let hydratedUtxos
|
||||
if (useWhitelist) {
|
||||
hydratedUtxos = await this.slp.Utils.hydrateUtxosWL(utxoData.utxos)
|
||||
} else {
|
||||
hydratedUtxos = await this.slp.Utils.hydrateUtxos(utxoData.utxos)
|
||||
}
|
||||
// console.log(`hydratedUtxos: ${JSON.stringify(hydratedUtxos, null, 2)}`)
|
||||
|
||||
const retAry = [] // Return array
|
||||
|
||||
// Loop through each address.
|
||||
for (let i = 0; i < hydratedUtxos.slpUtxos.length; i++) {
|
||||
const thisAddr = hydratedUtxos.slpUtxos[i]
|
||||
|
||||
const addrObj = {
|
||||
address: thisAddr.address
|
||||
}
|
||||
|
||||
// Filter out the different types of UTXOs.
|
||||
addrObj.bchUtxos = thisAddr.utxos.filter(elem => elem.isValid === false)
|
||||
addrObj.nullUtxos = thisAddr.utxos.filter(elem => elem.isValid === null)
|
||||
|
||||
// Break down the SLP UTXOs.
|
||||
addrObj.slpUtxos = {
|
||||
type1: {},
|
||||
nft: {}
|
||||
}
|
||||
|
||||
// Token Type 1 Minting Batons.
|
||||
addrObj.slpUtxos.type1.mintBatons = thisAddr.utxos.filter(elem => {
|
||||
const isValid = elem.isValid === true
|
||||
const tokenTypeIs1 = elem.tokenType === 1
|
||||
const isMintingBaton = elem.utxoType === 'minting-baton'
|
||||
|
||||
return isValid && tokenTypeIs1 && isMintingBaton
|
||||
})
|
||||
|
||||
// Token Type 1 tokens.
|
||||
addrObj.slpUtxos.type1.tokens = thisAddr.utxos.filter(elem => {
|
||||
const isValid = elem.isValid === true
|
||||
const tokenTypeIs1 = elem.tokenType === 1
|
||||
const isToken = elem.utxoType === 'token'
|
||||
|
||||
return isValid && tokenTypeIs1 && isToken
|
||||
})
|
||||
|
||||
// NFT Group Minting Batons
|
||||
addrObj.slpUtxos.nft.groupMintBatons = thisAddr.utxos.filter(elem => {
|
||||
const isValid = elem.isValid === true
|
||||
const tokenTypeIs129 = elem.tokenType === 129
|
||||
const isMintingBaton = elem.utxoType === 'minting-baton'
|
||||
|
||||
return isValid && tokenTypeIs129 && isMintingBaton
|
||||
})
|
||||
|
||||
// NFT Group tokens
|
||||
addrObj.slpUtxos.nft.groupTokens = thisAddr.utxos.filter(elem => {
|
||||
const isValid = elem.isValid === true
|
||||
const tokenTypeIs129 = elem.tokenType === 129
|
||||
const isToken = elem.utxoType === 'token'
|
||||
|
||||
return isValid && tokenTypeIs129 && isToken
|
||||
})
|
||||
|
||||
// NFT (Child) tokens
|
||||
addrObj.slpUtxos.nft.tokens = thisAddr.utxos.filter(elem => {
|
||||
const isValid = elem.isValid === true
|
||||
const tokenTypeIs65 = elem.tokenType === 65
|
||||
const isToken = elem.utxoType === 'token'
|
||||
|
||||
return isValid && tokenTypeIs65 && isToken
|
||||
})
|
||||
|
||||
retAry.push(addrObj)
|
||||
}
|
||||
|
||||
return retAry
|
||||
} catch (err) {
|
||||
console.error('Error in bchjs.utxo.get()')
|
||||
|
||||
if (err.error) throw new Error(err.error)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api Utxo.findBiggestUtxo() findBiggestUtxo()
|
||||
* @apiName findBiggestUtxo
|
||||
* @apiGroup UTXO
|
||||
* @apiDescription Get the biggest UTXO in an array.
|
||||
*
|
||||
* Given an array of BCH UTXOs, this method will return the biggest UTXO.
|
||||
* This is often the simplest way to pick a UTXO for generating a transaction.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* (async () => {
|
||||
* try {
|
||||
* const utxos = await bchjs.Utxo.get('bitcoincash:qq54fgjn3hz0357n8a6guy4demw9xfkjk5jcj0xr0z');
|
||||
* const utxo = bchjs.Utxo.findBiggestUtxo(utxos[0].bchUtxos)
|
||||
* console.log(utxo);
|
||||
* } catch(error) {
|
||||
* console.error(error)
|
||||
* }
|
||||
* })()
|
||||
*
|
||||
* // returns
|
||||
* {
|
||||
* "height": 655431,
|
||||
* "tx_hash": "7a091716f8137e94f87e7760648cd34a17e32754ef95f7c7bda38a635c9b2b1b",
|
||||
* "tx_pos": 0,
|
||||
* "value": 800,
|
||||
* "txid": "7a091716f8137e94f87e7760648cd34a17e32754ef95f7c7bda38a635c9b2b1b",
|
||||
* "vout": 0,
|
||||
* "isValid": false,
|
||||
* "satoshis": 800
|
||||
* }
|
||||
*/
|
||||
// Returns the utxo with the biggest balance from an array of utxos.
|
||||
findBiggestUtxo (utxos) {
|
||||
let largestAmount = 0
|
||||
let largestIndex = 0
|
||||
|
||||
if (!Array.isArray(utxos)) {
|
||||
throw new Error('utxos input to findBiggestUtxo() must be an array')
|
||||
}
|
||||
|
||||
for (let i = 0; i < utxos.length; i++) {
|
||||
const thisUtxo = utxos[i]
|
||||
|
||||
// Give Elecrumx utxos a satoshis property.
|
||||
if (thisUtxo.value) {
|
||||
if (!thisUtxo.satoshis) thisUtxo.satoshis = Number(thisUtxo.value)
|
||||
}
|
||||
|
||||
if (!thisUtxo.satoshis) {
|
||||
throw new Error(
|
||||
'UTXOs require a satoshis or value property for findBiggestUtxo()'
|
||||
)
|
||||
}
|
||||
|
||||
if (thisUtxo.satoshis > largestAmount) {
|
||||
largestAmount = thisUtxo.satoshis
|
||||
largestIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
return utxos[largestIndex]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UTXO
|
||||
@@ -14,9 +14,9 @@
|
||||
|
||||
const assert = require('chai').assert
|
||||
|
||||
// const RESTURL = `https://abc.fullstack.cash/v4/`
|
||||
const RESTURL = 'https://bchn.fullstack.cash/v4/'
|
||||
// const RESTURL = `http://localhost:3000/v4/`
|
||||
// const RESTURL = `https://abc.fullstack.cash/v5/`
|
||||
const RESTURL = 'https://bchn.fullstack.cash/v5/'
|
||||
// const RESTURL = `http://localhost:3000/v5/`
|
||||
|
||||
const BCHJS = require('../../../src/bch-js')
|
||||
const bchjs = new BCHJS({ restURL: RESTURL })
|
||||
|
||||
@@ -13,9 +13,9 @@ 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/`,
|
||||
// restURL: `https://bchn.fullstack.cash/v5/`,
|
||||
restURL: 'https://abc.fullstack.cash/v5/',
|
||||
// restURL: `http://localhost:3000/v5/`,
|
||||
authPass: PRO_PASS
|
||||
})
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ const JWT_TOKEN =
|
||||
|
||||
const BCHJS = require('../../../src/bch-js')
|
||||
const bchjs = new BCHJS({
|
||||
restURL: 'https://api.fullstack.cash/v4/',
|
||||
// restURL: `http://localhost:3000/v4/`,
|
||||
restURL: 'https://api.fullstack.cash/v5/',
|
||||
// restURL: `http://localhost:3000/v5/`,
|
||||
apiToken: JWT_TOKEN
|
||||
})
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ const JWT_TOKEN =
|
||||
|
||||
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/`,
|
||||
// restURL: `https://bchn.fullstack.cash/v5/`,
|
||||
restURL: 'https:/abc.fullstack.cash/v5/',
|
||||
// restURL: `http://localhost:3000/v5/`,
|
||||
apiToken: JWT_TOKEN
|
||||
})
|
||||
|
||||
@@ -65,7 +65,7 @@ describe('#full node rate limits', () => {
|
||||
|
||||
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`)
|
||||
|
||||
@@ -14,9 +14,9 @@ const JWT_TOKEN =
|
||||
|
||||
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/`,
|
||||
// restURL: `https://bchn.fullstack.cash/v5/`,
|
||||
restURL: 'https://abc.fullstack.cash/v5/',
|
||||
// restURL: `http://localhost:3000/v5/`,
|
||||
apiToken: JWT_TOKEN
|
||||
})
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ util.inspect.defaultOptions = {
|
||||
|
||||
describe('#blockchain', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
describe('#getBestBlockHash', () => {
|
||||
@@ -276,6 +276,43 @@ describe('#blockchain', () => {
|
||||
assert.equal(result, null)
|
||||
})
|
||||
})
|
||||
describe('#getBlock', () => {
|
||||
it('should get block information with default verbosity', async () => {
|
||||
const blockhash =
|
||||
'0000000000000000008e8d83cba6d45a9314bc2ef4538d4e0577c6bed8593536'
|
||||
const result = await bchjs.Blockchain.getBlock(blockhash)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
'hash',
|
||||
'confirmations',
|
||||
'size',
|
||||
'height',
|
||||
'version',
|
||||
'versionHex',
|
||||
'merkleroot',
|
||||
'tx',
|
||||
'time',
|
||||
'mediantime',
|
||||
'nonce',
|
||||
'bits',
|
||||
'difficulty',
|
||||
'chainwork',
|
||||
'nTx',
|
||||
'previousblockhash',
|
||||
'nextblockhash'
|
||||
])
|
||||
assert.isArray(result.tx)
|
||||
})
|
||||
|
||||
it('should get block information with verbosity 0', async () => {
|
||||
const blockhash =
|
||||
'0000000000000000008e8d83cba6d45a9314bc2ef4538d4e0577c6bed8593536'
|
||||
const verbosity = 0
|
||||
const result = await bchjs.Blockchain.getBlock(blockhash, verbosity)
|
||||
|
||||
assert.isString(result)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
const chai = require('chai')
|
||||
const assert = chai.assert
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
const bchjs = new BCHJS({ restURL: process.env.RESTURL })
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
const util = require('util')
|
||||
@@ -20,7 +20,7 @@ util.inspect.defaultOptions = {
|
||||
|
||||
describe('#rawtransaction', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
/*
|
||||
@@ -44,6 +44,7 @@ describe('#rawtransaction', () => {
|
||||
|
||||
assert.hasAllKeys(err, ['error'])
|
||||
assert.include(err.error, 'bad-txns-inputs-missingorspent')
|
||||
// assert.include(err.error, 'Missing inputs')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -61,6 +62,7 @@ describe('#rawtransaction', () => {
|
||||
|
||||
assert.hasAllKeys(err, ['error'])
|
||||
assert.include(err.error, 'bad-txns-inputs-missingorspent')
|
||||
// assert.include(err.error, 'Missing inputs')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -25,9 +25,9 @@ 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)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
|
||||
bchjs = new BCHJS()
|
||||
bchjs = new BCHJS({ restURL: process.env.RESTURL })
|
||||
})
|
||||
|
||||
describe('#util', () => {
|
||||
@@ -113,6 +113,7 @@ describe('#SLP', () => {
|
||||
|
||||
// Token send on BCHN network
|
||||
assert.equal(data[4].tx_hash, utxos[4].tx_hash)
|
||||
// assert.equal(data[4].isValid, true)
|
||||
assert.equal(data[4].isValid, null)
|
||||
|
||||
// Token send on ABC network
|
||||
@@ -180,6 +181,7 @@ describe('#SLP', () => {
|
||||
assert.equal(result[0].valid, null)
|
||||
assert.equal(result[1].valid, null)
|
||||
assert.equal(result[2].valid, true)
|
||||
// assert.equal(result[2].valid, null)
|
||||
assert.equal(result[3].valid, true)
|
||||
assert.equal(result[4].valid, null)
|
||||
})
|
||||
@@ -209,6 +211,7 @@ describe('#SLP', () => {
|
||||
assert.equal(result[0].valid, null)
|
||||
assert.equal(result[1].valid, null)
|
||||
assert.equal(result[2].valid, true)
|
||||
// assert.equal(result[2].valid, null)
|
||||
assert.equal(result[3].valid, true)
|
||||
assert.equal(result[4].valid, null)
|
||||
assert.equal(result[5].valid, true)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Integration tests for the utxo.js library.
|
||||
*/
|
||||
|
||||
const assert = require('chai').assert
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe('#UTXO', () => {
|
||||
beforeEach(async () => {
|
||||
// sandbox = sinon.createSandbox()
|
||||
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
describe('#get', () => {
|
||||
it('should get hydrated and filtered UTXOs for an address', async () => {
|
||||
// const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
const addr = 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
||||
|
||||
const result = await bchjs.Utxo.get(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
+1
-1
@@ -20,7 +20,7 @@ util.inspect.defaultOptions = {
|
||||
|
||||
describe('#rawtransaction', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
|
||||
})
|
||||
|
||||
/*
|
||||
+29
-2
@@ -25,12 +25,37 @@ 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)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
|
||||
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
|
||||
describe('#util', () => {
|
||||
describe('#decodeOpReturn', () => {
|
||||
it('should decode a NFT Child transaction', async () => {
|
||||
const txid =
|
||||
'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b'
|
||||
|
||||
const data = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.property(data, 'tokenType')
|
||||
assert.property(data, 'txType')
|
||||
assert.property(data, 'ticker')
|
||||
assert.property(data, 'name')
|
||||
assert.property(data, 'tokenId')
|
||||
assert.property(data, 'documentUri')
|
||||
assert.property(data, 'documentHash')
|
||||
assert.property(data, 'decimals')
|
||||
assert.property(data, 'mintBatonVout')
|
||||
assert.property(data, 'qty')
|
||||
|
||||
assert.equal(data.tokenType, 65)
|
||||
assert.equal(data.mintBatonVout, 0)
|
||||
assert.equal(data.qty, '1')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#tokenUtxoDetails', () => {
|
||||
it('should handle a range of UTXO types', async () => {
|
||||
const utxos = [
|
||||
@@ -186,11 +211,13 @@ describe('#SLP', () => {
|
||||
assert.equal(result[2].txid, txids[2])
|
||||
assert.equal(result[2].valid, true)
|
||||
|
||||
// True in validateTxid()
|
||||
// True in validateTxid() (no whitelist SLPDB) but null in validateTxid3()
|
||||
assert.equal(result[3].txid, txids[3])
|
||||
assert.equal(result[3].valid, true)
|
||||
|
||||
// Note: This should change from null to true once SLPDB finishes indexing.
|
||||
assert.equal(result[4].txid, txids[4])
|
||||
// True when no whitelist SLPDB is used.
|
||||
assert.equal(result[4].valid, true)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
Integration tests for the utxo.js library.
|
||||
*/
|
||||
|
||||
const assert = require('chai').assert
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe('#UTXO', () => {
|
||||
beforeEach(async () => {
|
||||
// sandbox = sinon.createSandbox()
|
||||
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
|
||||
})
|
||||
|
||||
describe('#get', () => {
|
||||
it('should get hydrated and filtered UTXOs for an address', async () => {
|
||||
// const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
const addr = 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
||||
|
||||
const result = await bchjs.Utxo.get(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
})
|
||||
|
||||
it('should handle an array of addresses', async () => {
|
||||
const addr = [
|
||||
'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9',
|
||||
'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
]
|
||||
|
||||
const result = await bchjs.Utxo.get(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
})
|
||||
|
||||
it('should handle NFTs and minting batons', async () => {
|
||||
const addr = 'simpleledger:qrm0c67wwqh0w7wjxua2gdt2xggnm90xwsr5k22euj'
|
||||
|
||||
const result = await bchjs.Utxo.get(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
|
||||
assert.isArray(result[0].slpUtxos.type1.mintBatons)
|
||||
assert.isArray(result[0].slpUtxos.type1.tokens)
|
||||
assert.isArray(result[0].slpUtxos.nft.groupMintBatons)
|
||||
assert.isArray(result[0].slpUtxos.nft.groupTokens)
|
||||
assert.isArray(result[0].slpUtxos.nft.tokens)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#findBiggestUtxo', () => {
|
||||
it('should sort UTXOs from Electrumx', async () => {
|
||||
const addr = 'bitcoincash:qq54fgjn3hz0357n8a6guy4demw9xfkjk5jcj0xr0z'
|
||||
|
||||
const electrumxUtxos = await bchjs.Electrumx.utxo(addr)
|
||||
// console.log(`Electrumx utxos: ${JSON.stringify(electrumxUtxos, null, 2)}`)
|
||||
|
||||
const result = bchjs.Utxo.findBiggestUtxo(electrumxUtxos.utxos)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, 'satoshis')
|
||||
assert.equal(result.satoshis, 800)
|
||||
})
|
||||
|
||||
it('should sort UTXOs from Utxos.get()', async () => {
|
||||
const addr = 'bitcoincash:qq54fgjn3hz0357n8a6guy4demw9xfkjk5jcj0xr0z'
|
||||
|
||||
const utxos = await bchjs.Utxo.get(addr)
|
||||
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
|
||||
const result = bchjs.Utxo.findBiggestUtxo(utxos[0].bchUtxos)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, 'satoshis')
|
||||
assert.equal(result.satoshis, 800)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Integration tests for bchjs dsproof library.
|
||||
*/
|
||||
|
||||
const assert = require('chai').assert
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe('#DSProof', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await bchjs.Util.sleep(1000)
|
||||
})
|
||||
|
||||
describe('#getDSProof', () => {
|
||||
it('should get TX info from the full node', async () => {
|
||||
const txid =
|
||||
'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'
|
||||
const result = await bchjs.DSProof.getDSProof(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.equal(result, null)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -20,7 +20,7 @@ util.inspect.defaultOptions = {
|
||||
|
||||
describe('#rawtransaction', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
|
||||
})
|
||||
|
||||
/*
|
||||
|
||||
@@ -25,12 +25,37 @@ 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)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
|
||||
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
|
||||
describe('#util', () => {
|
||||
describe('#decodeOpReturn', () => {
|
||||
it('should decode a NFT Child transaction', async () => {
|
||||
const txid =
|
||||
'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b'
|
||||
|
||||
const data = await bchjs.SLP.Utils.decodeOpReturn(txid)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.property(data, 'tokenType')
|
||||
assert.property(data, 'txType')
|
||||
assert.property(data, 'ticker')
|
||||
assert.property(data, 'name')
|
||||
assert.property(data, 'tokenId')
|
||||
assert.property(data, 'documentUri')
|
||||
assert.property(data, 'documentHash')
|
||||
assert.property(data, 'decimals')
|
||||
assert.property(data, 'mintBatonVout')
|
||||
assert.property(data, 'qty')
|
||||
|
||||
assert.equal(data.tokenType, 65)
|
||||
assert.equal(data.mintBatonVout, 0)
|
||||
assert.equal(data.qty, '1')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#tokenUtxoDetails', () => {
|
||||
it('should handle a range of UTXO types', async () => {
|
||||
const utxos = [
|
||||
@@ -239,6 +264,31 @@ describe('#SLP', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
describe('#nft1', () => {
|
||||
describe('#listNFTGroupChildren', () => {
|
||||
it('should return array of children GENESIS transactions IDs', async () => {
|
||||
const groupId = '68cd33ecd909068fbea318ae5ff1d6207cf754e53b191327d6d73b6916424c0a'
|
||||
const result = await bchjs.SLP.NFT1.listNFTGroupChildren(groupId)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
assert.property(result, 'nftChildren')
|
||||
assert.isArray(result.nftChildren)
|
||||
})
|
||||
})
|
||||
describe('#parentNFTGroup', () => {
|
||||
it('should return parent NFT group information', async () => {
|
||||
const tokenId = '45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a9'
|
||||
const result = await bchjs.SLP.NFT1.parentNFTGroup(tokenId)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
assert.property(result, 'nftGroup')
|
||||
assert.property(result.nftGroup, 'id')
|
||||
assert.property(result.nftGroup, 'name')
|
||||
assert.property(result.nftGroup, 'symbol')
|
||||
assert.property(result.nftGroup, 'documentUri')
|
||||
assert.property(result.nftGroup, 'versionType')
|
||||
assert.property(result.nftGroup, 'initialTokenQty')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Promise-based sleep function
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Integration tests for the utxo.js library.
|
||||
*/
|
||||
|
||||
const assert = require('chai').assert
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe('#UTXO', () => {
|
||||
beforeEach(async () => {
|
||||
// sandbox = sinon.createSandbox()
|
||||
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
|
||||
})
|
||||
|
||||
describe('#get', () => {
|
||||
it('should get hydrated and filtered UTXOs for an address', async () => {
|
||||
// const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
const addr = 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
||||
|
||||
const result = await bchjs.Utxo.get(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
})
|
||||
|
||||
it('should handle an array of addresses', async () => {
|
||||
const addr = [
|
||||
'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9',
|
||||
'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
]
|
||||
|
||||
const result = await bchjs.Utxo.get(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
})
|
||||
|
||||
it('should handle NFTs and minting batons', async () => {
|
||||
const addr = 'simpleledger:qrm0c67wwqh0w7wjxua2gdt2xggnm90xwsr5k22euj'
|
||||
|
||||
const result = await bchjs.Utxo.get(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
|
||||
assert.isArray(result[0].slpUtxos.type1.mintBatons)
|
||||
assert.isArray(result[0].slpUtxos.type1.tokens)
|
||||
assert.isArray(result[0].slpUtxos.nft.groupMintBatons)
|
||||
assert.isArray(result[0].slpUtxos.nft.groupTokens)
|
||||
assert.isArray(result[0].slpUtxos.nft.tokens)
|
||||
})
|
||||
|
||||
it('should use the whitelist when flag is set', async () => {
|
||||
const addr = 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
||||
const useWhitelist = true
|
||||
|
||||
const result = await bchjs.Utxo.get(addr, useWhitelist)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
|
||||
// Most token UTXOs should end up in the nullUtxos array.
|
||||
assert.isAbove(result[0].bchUtxos.length, 0)
|
||||
assert.isAbove(result[0].nullUtxos.length, 1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#findBiggestUtxo', () => {
|
||||
it('should sort UTXOs from Electrumx', async () => {
|
||||
const addr = 'bitcoincash:qq54fgjn3hz0357n8a6guy4demw9xfkjk5jcj0xr0z'
|
||||
|
||||
const electrumxUtxos = await bchjs.Electrumx.utxo(addr)
|
||||
// console.log(`Electrumx utxos: ${JSON.stringify(electrumxUtxos, null, 2)}`)
|
||||
|
||||
const result = bchjs.Utxo.findBiggestUtxo(electrumxUtxos.utxos)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, 'satoshis')
|
||||
assert.equal(result.satoshis, 800)
|
||||
})
|
||||
|
||||
it('should sort UTXOs from Utxos.get()', async () => {
|
||||
const addr = 'bitcoincash:qq54fgjn3hz0357n8a6guy4demw9xfkjk5jcj0xr0z'
|
||||
|
||||
const utxos = await bchjs.Utxo.get(addr)
|
||||
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
|
||||
|
||||
const result = bchjs.Utxo.findBiggestUtxo(utxos[0].bchUtxos)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, 'satoshis')
|
||||
assert.equal(result.satoshis, 800)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -12,11 +12,11 @@ const assert = chai.assert
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: 'https://testnet3.fullstack.cash/v4/'
|
||||
: 'https://testnet3.fullstack.cash/v5/'
|
||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v5/` })
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
@@ -29,7 +29,7 @@ util.inspect.defaultOptions = {
|
||||
|
||||
describe('#blockchain', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
describe('#getBestBlockHash', () => {
|
||||
|
||||
@@ -7,14 +7,14 @@ const assert = chai.assert
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: 'https://testnet3.fullstack.cash/v4/'
|
||||
: 'https://testnet3.fullstack.cash/v5/'
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
|
||||
describe('#control', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
describe('#getNetworkInfo', () => {
|
||||
|
||||
@@ -5,7 +5,7 @@ const util = require('util')
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: 'https://testnet3.fullstack.cash/v4/'
|
||||
: 'https://testnet3.fullstack.cash/v5/'
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
@@ -16,7 +16,7 @@ describe('#ElectrumX', () => {
|
||||
beforeEach(async () => {
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
@@ -68,7 +68,9 @@ describe('#ElectrumX', () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++) { addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2') }
|
||||
for (let i = 0; i < 25; i++) {
|
||||
addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2')
|
||||
}
|
||||
|
||||
// const result = await bchjs.Electrumx.utxo(addr)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
@@ -121,7 +123,9 @@ describe('#ElectrumX', () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++) { addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2') }
|
||||
for (let i = 0; i < 25; i++) {
|
||||
addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2')
|
||||
}
|
||||
|
||||
const result = await bchjs.Electrumx.balance(addr)
|
||||
|
||||
@@ -175,7 +179,9 @@ describe('#ElectrumX', () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++) { addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2') }
|
||||
for (let i = 0; i < 25; i++) {
|
||||
addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2')
|
||||
}
|
||||
|
||||
const result = await bchjs.Electrumx.transactions(addr)
|
||||
|
||||
@@ -236,7 +242,9 @@ describe('#ElectrumX', () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const addr = []
|
||||
for (let i = 0; i < 25; i++) { addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2') }
|
||||
for (let i = 0; i < 25; i++) {
|
||||
addr.push('bchtest:qrvn2n228aa39xupcw9jw0d3fj8axxky656e4j62z2')
|
||||
}
|
||||
|
||||
await bchjs.Electrumx.unconfirmed(addr)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
@@ -355,7 +363,7 @@ describe('#ElectrumX', () => {
|
||||
assert.property(err, 'success')
|
||||
assert.equal(err.success, false)
|
||||
assert.include(
|
||||
err.error,
|
||||
err.error.error,
|
||||
'the transaction was rejected by network rules'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,147 +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))
|
||||
}
|
||||
@@ -10,11 +10,11 @@ const assert = chai.assert
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: 'https://testnet3.fullstack.cash/v4/'
|
||||
: 'https://testnet3.fullstack.cash/v5/'
|
||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v5/` })
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
@@ -27,7 +27,7 @@ util.inspect.defaultOptions = {
|
||||
|
||||
describe('#rawtransaction', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
describe('#decodeRawTransaction', () => {
|
||||
|
||||
@@ -7,11 +7,11 @@ const assert = chai.assert
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: 'https://testnet3.fullstack.cash/v4/'
|
||||
: 'https://testnet3.fullstack.cash/v5/'
|
||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v5/` })
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
@@ -25,7 +25,7 @@ util.inspect.defaultOptions = {
|
||||
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)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
describe('#util', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
export RESTURL=https://free-test.fullstack.cash/v4/
|
||||
export RESTURL=https://free-test.fullstack.cash/v5/
|
||||
export NETWORK=testnet
|
||||
export IS_USING_FREE_TIER=true
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ const assert = chai.assert
|
||||
|
||||
const RESTURL = process.env.RESTURL
|
||||
? process.env.RESTURL
|
||||
: 'https://testnet3.fullstack.cash/v4/'
|
||||
: 'https://testnet3.fullstack.cash/v5/'
|
||||
// if (process.env.RESTURL) RESTURL = process.env.RESTURL
|
||||
|
||||
const BCHJS = require('../../../../src/bch-js')
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v4/` })
|
||||
// const bchjs = new BCHJS({ restURL: `https://testnet.bchjs.cash/v5/` })
|
||||
const bchjs = new BCHJS({ restURL: RESTURL, apiToken: process.env.BCHJSTOKEN })
|
||||
|
||||
// Inspect utility used for debugging.
|
||||
@@ -25,7 +25,7 @@ util.inspect.defaultOptions = {
|
||||
|
||||
describe('#util', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
describe('#validateAddress', () => {
|
||||
|
||||
@@ -9,7 +9,7 @@ const bchjs = new BCHJS()
|
||||
|
||||
describe('#control', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
describe('#getNetworkInfo', () => {
|
||||
|
||||
@@ -11,7 +11,7 @@ describe('#ElectrumX', () => {
|
||||
beforeEach(async () => {
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
@@ -63,7 +63,9 @@ describe('#ElectrumX', () => {
|
||||
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)
|
||||
await bchjs.Electrumx.utxo(addr)
|
||||
@@ -116,7 +118,9 @@ describe('#ElectrumX', () => {
|
||||
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)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
@@ -172,7 +176,9 @@ describe('#ElectrumX', () => {
|
||||
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)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
@@ -235,7 +241,9 @@ describe('#ElectrumX', () => {
|
||||
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)
|
||||
|
||||
@@ -351,15 +359,33 @@ describe('#ElectrumX', () => {
|
||||
try {
|
||||
await bchjs.Electrumx.broadcast(txHex)
|
||||
} catch (err) {
|
||||
// console.log('err: ', err)
|
||||
|
||||
assert.property(err, 'success')
|
||||
assert.equal(err.success, false)
|
||||
assert.include(
|
||||
err.error,
|
||||
err.error.error,
|
||||
'the transaction was rejected by network rules'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#sortAllTxs', () => {
|
||||
it('should GET transaction history for a single address', async () => {
|
||||
const addr = 'bitcoincash:qpdh9s677ya8tnx7zdhfrn8qfyvy22wj4qa7nwqa5v'
|
||||
|
||||
const txs = await bchjs.Electrumx.transactions(addr)
|
||||
const sortedTransactions = await bchjs.Electrumx.sortAllTxs(
|
||||
txs.transactions
|
||||
)
|
||||
// console.log(
|
||||
// `sortedTransactions: ${JSON.stringify(sortedTransactions, null, 2)}`
|
||||
// )
|
||||
|
||||
assert.isAbove(sortedTransactions[0].height, sortedTransactions[1].height)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
|
||||
@@ -5,7 +5,7 @@ const bchjs = new BCHJS()
|
||||
|
||||
describe('#Encryption', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
describe('#getPubKey', () => {
|
||||
|
||||
@@ -1,138 +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(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 = '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], 'valueOut')
|
||||
assert.property(result[0], 'size')
|
||||
})
|
||||
it('should POST transactions details for an array of addresses', async () => {
|
||||
const txid = [
|
||||
'fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33',
|
||||
'4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251'
|
||||
]
|
||||
|
||||
const result = await bchjs.Ninsight.txDetails(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'txid')
|
||||
assert.property(result[0], 'vin')
|
||||
assert.property(result[0], 'vout')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -1,89 +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', () => {
|
||||
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'
|
||||
|
||||
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 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 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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -4,7 +4,7 @@ const bchjs = new BCHJS()
|
||||
|
||||
describe('#price', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
describe('#current', () => {
|
||||
@@ -33,6 +33,14 @@ describe('#price', () => {
|
||||
assert.isNumber(result)
|
||||
})
|
||||
})
|
||||
describe('#getBchUsd', () => {
|
||||
it('should get the USD price of BCH', async () => {
|
||||
const result = await bchjs.Price.getBchUsd()
|
||||
console.log(result)
|
||||
|
||||
assert.isNumber(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#rates', () => {
|
||||
it('should get the price of BCH in several currencies', async () => {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
Integration tests for the bchjs. Only covers calls made to
|
||||
rest.bitcoin.com.
|
||||
Integration tests for the bchjs.
|
||||
|
||||
TODO
|
||||
*/
|
||||
@@ -20,7 +19,7 @@ util.inspect.defaultOptions = {
|
||||
|
||||
describe('#rawtransaction', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
describe('#decodeRawTransaction', () => {
|
||||
@@ -192,8 +191,7 @@ describe('#rawtransaction', () => {
|
||||
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.include(err.message, 'Array too large')
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -230,7 +228,7 @@ 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', () => {
|
||||
describe('#sendRawTransaction', () => {
|
||||
it('should throw error on array size rate limit', async () => {
|
||||
try {
|
||||
const dataMock =
|
||||
@@ -238,9 +236,9 @@ describe('#rawtransaction', () => {
|
||||
const data = []
|
||||
for (let i = 0; i < 25; i++) data.push(dataMock)
|
||||
|
||||
const result = await bchjs.RawTransactions.sendRawTransaction(data)
|
||||
await bchjs.RawTransactions.sendRawTransaction(data)
|
||||
|
||||
console.log(`result: ${util.inspect(result)}`)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.hasAnyKeys(err, ['error'])
|
||||
@@ -248,6 +246,65 @@ describe('#rawtransaction', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#_getInputAddrs', () => {
|
||||
it('should return an array of input addresses', async () => {
|
||||
// const txid = '32233db13f2ae6d82b6262f335643dccf09fc0bcfcef4bc3fbe023355f02e112'
|
||||
const txid =
|
||||
'05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
|
||||
|
||||
const txDetails = await bchjs.RawTransactions.getRawTransaction(
|
||||
txid,
|
||||
true
|
||||
)
|
||||
|
||||
const result = await bchjs.RawTransactions._getInputAddrs(txDetails)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.equal(result.length, 1)
|
||||
assert.property(result[0], 'vin')
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'value')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getTxData', () => {
|
||||
it('should return tx data with input addresses', async () => {
|
||||
const txid =
|
||||
'05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
|
||||
|
||||
const result = await bchjs.RawTransactions.getTxData(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result.vin[0], 'address')
|
||||
assert.property(result.vin[0], 'value')
|
||||
})
|
||||
})
|
||||
|
||||
// describe('#getTxDataSlp', () => {
|
||||
// it('should return tx data with SLP information', async () => {
|
||||
// const txid = 'b438855cfcab64516b44097d7212df9cdb99226c8d7c7ab504d35fcfd834cb5b'
|
||||
//
|
||||
// const result = await bchjs.RawTransactions.getTxDataSlp(txid)
|
||||
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
//
|
||||
// assert.property(result.vin[0], 'address')
|
||||
// assert.property(result.vin[0], 'tokenQty')
|
||||
//
|
||||
// assert.equal(result.vin[0].tokenQty, null)
|
||||
// assert.equal(result.vin[1].tokenQty, '100000000000')
|
||||
// })
|
||||
//
|
||||
// it('should handle non-slp tx', async () => {
|
||||
// const txid = '04a6aca328af2445327015895b8da9766093b1989b52e477559759eb8072fc0a'
|
||||
//
|
||||
// const result = await bchjs.RawTransactions.getTxDataSlp(txid)
|
||||
// // console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
//
|
||||
// assert.equal(result, false)
|
||||
// })
|
||||
// })
|
||||
})
|
||||
|
||||
function sleep (ms) {
|
||||
|
||||
+229
-3
@@ -24,7 +24,7 @@ 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)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(3000)
|
||||
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
@@ -32,7 +32,8 @@ describe('#SLP', () => {
|
||||
describe('#util', () => {
|
||||
describe('#list', () => {
|
||||
it('should get information on the Spice token', async () => {
|
||||
const tokenId = '4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf'
|
||||
const tokenId =
|
||||
'4de69e374a8ed21cbddd47f2338cc0f479dc58daa2bbe11cd604ca488eca0ddf'
|
||||
|
||||
const result = await bchjs.SLP.Utils.list(tokenId)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
@@ -490,6 +491,116 @@ describe('#SLP', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#tokenUtxoDetailsWL', () => {
|
||||
it('should return details for a simple SEND SLP token utxo', async () => {
|
||||
const utxos = [
|
||||
{
|
||||
height: 660554,
|
||||
tx_hash:
|
||||
'89b3f0c84efe8b01b24e2d7ac08636de5781f31dbb84478e3de868ca0a7ed93a',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
}
|
||||
]
|
||||
|
||||
const data = await bchjs.SLP.Utils.tokenUtxoDetailsWL(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.property(data[0], 'txid')
|
||||
assert.property(data[0], 'vout')
|
||||
assert.property(data[0], 'height')
|
||||
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 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.tokenUtxoDetailsWL(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.tokenUtxoDetailsWL(utxos)
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
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.tokenUtxoDetailsWL(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 () => {
|
||||
const balances = await bchjs.SLP.Utils.balancesForAddress(
|
||||
@@ -528,7 +639,7 @@ describe('#SLP', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#hydrateUtxos', () => {
|
||||
describe('#hydrateUtxos-', () => {
|
||||
it('should hydrate UTXOs', async () => {
|
||||
const utxos = [
|
||||
{
|
||||
@@ -655,6 +766,99 @@ describe('#SLP', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#hydrateUtxosWL', () => {
|
||||
it('should hydrate UTXOs', async () => {
|
||||
const utxos = [
|
||||
{
|
||||
utxos: [
|
||||
{
|
||||
txid:
|
||||
'89b3f0c84efe8b01b24e2d7ac08636de5781f31dbb84478e3de868ca0a7ed93a',
|
||||
vout: 1,
|
||||
value: 546
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const result = await bchjs.SLP.Utils.hydrateUtxosWL(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, 1)
|
||||
|
||||
// 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], 'isValid')
|
||||
assert.equal(result.slpUtxos[0].utxos[0].isValid, true)
|
||||
})
|
||||
|
||||
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.hydrateUtxosWL(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, null)
|
||||
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)
|
||||
}
|
||||
})
|
||||
|
||||
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.hydrateUtxosWL([{ utxos: utxos }])
|
||||
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
|
||||
|
||||
assert.isArray(data.slpUtxos)
|
||||
assert.equal(data.slpUtxos[0].isValid, null)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#validateTxid', () => {
|
||||
// This test is not necessary.
|
||||
it('should handle a null response from SLPDB', async () => {
|
||||
@@ -735,6 +939,28 @@ describe('#SLP', () => {
|
||||
assert.property(result, 'slpProcessedBlockHeight')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#waterfallValidateTxid', () => {
|
||||
it('should validate known good txid not in whitelist', async () => {
|
||||
const txid =
|
||||
'3a4b628cbcc183ab376d44ce5252325f042268307ffa4a53443e92b6d24fb488'
|
||||
|
||||
const result = await bchjs.SLP.Utils.waterfallValidateTxid(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
|
||||
it('should invalidate a known invalid TXID', async () => {
|
||||
const txid =
|
||||
'f7e5199ef6669ad4d078093b3ad56e355b6ab84567e59ad0f08a5ad0244f783a'
|
||||
|
||||
const result = await bchjs.SLP.Utils.waterfallValidateTxid(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.equal(result, false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('#tokentype1', () => {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Integration tests for the transaction.js library.
|
||||
*/
|
||||
|
||||
const assert = require('chai').assert
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
describe('#Transaction', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await bchjs.Util.sleep(1000)
|
||||
})
|
||||
|
||||
describe('#get', () => {
|
||||
it('should get details about a non-SLP transaction', async () => {
|
||||
const txid =
|
||||
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7'
|
||||
|
||||
const result = await bchjs.Transaction.get(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
// Assert that there are stanardized properties.
|
||||
assert.property(result, 'txid')
|
||||
assert.property(result, 'vin')
|
||||
assert.property(result, 'vout')
|
||||
assert.property(result.vout[0], 'value')
|
||||
assert.property(result.vout[0].scriptPubKey, 'addresses')
|
||||
|
||||
// Assert that added properties exist.
|
||||
assert.property(result.vin[0], 'address')
|
||||
assert.property(result.vin[0], 'value')
|
||||
assert.property(result, 'isValidSLPTx')
|
||||
assert.equal(result.isValidSLPTx, false)
|
||||
})
|
||||
|
||||
it('should get details about a SLP transaction', async () => {
|
||||
const txid =
|
||||
'266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1'
|
||||
|
||||
const result = await bchjs.Transaction.get(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
// Assert that there are stanardized properties.
|
||||
assert.property(result, 'txid')
|
||||
assert.property(result, 'vin')
|
||||
assert.property(result, 'vout')
|
||||
assert.property(result.vout[0], 'value')
|
||||
assert.property(result.vout[1].scriptPubKey, 'addresses')
|
||||
|
||||
// Assert that added properties exist.
|
||||
assert.property(result.vout[0], 'tokenQty')
|
||||
assert.equal(result.vout[0].tokenQty, null)
|
||||
assert.property(result.vin[0], 'address')
|
||||
assert.property(result.vin[0], 'value')
|
||||
assert.property(result.vin[0], 'tokenQty')
|
||||
assert.property(result, 'isValidSLPTx')
|
||||
assert.equal(result.isValidSLPTx, true)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -18,7 +18,7 @@ util.inspect.defaultOptions = {
|
||||
|
||||
describe('#util', () => {
|
||||
beforeEach(async () => {
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1000)
|
||||
if (process.env.IS_USING_FREE_TIER) await sleep(1500)
|
||||
})
|
||||
|
||||
describe('#validateAddress', () => {
|
||||
|
||||
+28
-7
@@ -61,16 +61,40 @@ describe('#Blockchain', () => {
|
||||
|
||||
it('should get block by hash', done => {
|
||||
const resolved = new Promise(resolve => resolve({ data: data }))
|
||||
sandbox.stub(axios, 'get').returns(resolved)
|
||||
sandbox.stub(axios, 'post').returns(resolved)
|
||||
|
||||
bchjs.Blockchain.getBlock(
|
||||
const blockhash =
|
||||
'00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09'
|
||||
)
|
||||
bchjs.Blockchain.getBlock(blockhash)
|
||||
.then(result => {
|
||||
assert.deepStrictEqual(data, result)
|
||||
})
|
||||
.then(done, done)
|
||||
})
|
||||
it('should throw error if blockhash is not provided', async () => {
|
||||
try {
|
||||
await bchjs.Blockchain.getBlock()
|
||||
assert2.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
assert2.include(err.message, 'blockhash must be a string')
|
||||
}
|
||||
})
|
||||
it('should handle response error', async () => {
|
||||
try {
|
||||
const error = new Error()
|
||||
error.response = {
|
||||
data: 'Test Error'
|
||||
}
|
||||
sandbox.stub(axios, 'post').throws(error)
|
||||
|
||||
const blockhash =
|
||||
'00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09'
|
||||
await bchjs.Blockchain.getBlock(blockhash)
|
||||
assert2.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
assert2.include(err, 'Test Error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getBlockchainInfo', () => {
|
||||
@@ -355,10 +379,7 @@ describe('#Blockchain', () => {
|
||||
try {
|
||||
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')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ const bchjs = new BCHJS()
|
||||
const sinon = require('sinon')
|
||||
|
||||
describe('#Control', () => {
|
||||
describe('#getNetworkInfo', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#getNetworkInfo', () => {
|
||||
it('should get info', done => {
|
||||
const data = {
|
||||
version: 170000,
|
||||
@@ -36,10 +36,6 @@ describe('#Control', () => {
|
||||
})
|
||||
|
||||
describe('#getMemoryInfo', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
it('should get memory info', done => {
|
||||
const data = {
|
||||
locked: {
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// Public npm libraries
|
||||
const assert = require('chai').assert
|
||||
const sinon = require('sinon')
|
||||
|
||||
// Unit under test (uut)
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const mockData = require('./fixtures/dsproof-mock')
|
||||
|
||||
let bchjs
|
||||
const txid = 'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'
|
||||
describe('#DSProof', () => {
|
||||
let sandbox
|
||||
beforeEach(() => {
|
||||
bchjs = new BCHJS()
|
||||
sandbox = sinon.createSandbox()
|
||||
})
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#getDSProof', () => {
|
||||
it('should throw error if input is not provided', async () => {
|
||||
try {
|
||||
await bchjs.DSProof.getDSProof()
|
||||
assert.equal(false, true, 'unexpected error')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'txid is required')
|
||||
}
|
||||
})
|
||||
it('should throw error txid is invalid', async () => {
|
||||
try {
|
||||
await bchjs.DSProof.getDSProof('txid')
|
||||
assert.equal(false, true, 'unexpected error')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'txid must be of length 64')
|
||||
}
|
||||
})
|
||||
it('should handle error', async () => {
|
||||
try {
|
||||
sandbox.stub(bchjs.DSProof.axios, 'get').throws(new Error('test error'))
|
||||
await bchjs.DSProof.getDSProof(txid)
|
||||
|
||||
assert.equal(false, true, 'unexpected error')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
it('should get double spend proof', async () => {
|
||||
try {
|
||||
sandbox
|
||||
.stub(bchjs.DSProof.axios, 'get')
|
||||
.resolves({ data: mockData.dsproof })
|
||||
const result = await bchjs.DSProof.getDSProof(txid)
|
||||
|
||||
assert.property(result, 'dspid')
|
||||
assert.property(result, 'txid')
|
||||
assert.property(result, 'outpoint')
|
||||
assert.property(result, 'path')
|
||||
assert.property(result, 'descendants')
|
||||
|
||||
assert.property(result.outpoint, 'txid')
|
||||
assert.property(result.outpoint, 'vout')
|
||||
} catch (error) {
|
||||
assert.equal(false, true, 'unexpected error')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -390,6 +390,7 @@ describe('#ElectrumX', () => {
|
||||
assert.equal(result.transactions.length, 2, '2 outputs for 2 inputs')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#broadcast', () => {
|
||||
it('should throw an error for improper input', async () => {
|
||||
try {
|
||||
@@ -402,6 +403,7 @@ describe('#ElectrumX', () => {
|
||||
assert.include(err.message, 'Input txHex must be a string.')
|
||||
}
|
||||
})
|
||||
|
||||
it('should broadcast a single transaction', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, 'post').resolves({ data: mockData.broadcast })
|
||||
@@ -418,4 +420,75 @@ describe('#ElectrumX', () => {
|
||||
assert.equal(result.txid, txid)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#sortConfTxs', () => {
|
||||
it('should sort in ascending order', () => {
|
||||
const result = bchjs.Electrumx.sortConfTxs(mockData.transaction.transactions, 'ASCENDING')
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isBelow(result[0].height, result[1].height)
|
||||
})
|
||||
|
||||
it('should sort in descending order by default', () => {
|
||||
const result = bchjs.Electrumx.sortConfTxs(mockData.transaction.transactions)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isAbove(result[0].height, result[1].height)
|
||||
})
|
||||
|
||||
it('should ignore unconfirmed txs', () => {
|
||||
const result = bchjs.Electrumx.sortConfTxs(mockData.txHistoryWithUnconfirmed.transactions)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isAbove(result[0].height, 0)
|
||||
})
|
||||
|
||||
it('should handle errors', () => {
|
||||
try {
|
||||
bchjs.Electrumx.sortConfTxs('abc')
|
||||
|
||||
assert.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(err.message)
|
||||
assert.equal(err.message, 'txs.filter is not a function')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// These tests use mocked data that contains unconfirmed transactions.
|
||||
describe('#sortAllTxs', () => {
|
||||
it('should sort in ascending', async () => {
|
||||
// Stub network calls
|
||||
sandbox.stub(bchjs.Electrumx.blockchain, 'getBlockCount').resolves(672141)
|
||||
|
||||
const result = await bchjs.Electrumx.sortAllTxs(mockData.txHistoryWithUnconfirmed.transactions, 'ASCENDING')
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isBelow(result[0].height, result[1].height)
|
||||
})
|
||||
|
||||
it('should sort in descending order by default', async () => {
|
||||
// Stub network calls
|
||||
sandbox.stub(bchjs.Electrumx.blockchain, 'getBlockCount').resolves(672141)
|
||||
|
||||
const result = await bchjs.Electrumx.sortAllTxs(mockData.txHistoryWithUnconfirmed.transactions)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isAbove(result[1].height, result[2].height)
|
||||
})
|
||||
|
||||
it('should handle errors', async () => {
|
||||
try {
|
||||
// Stub network calls
|
||||
sandbox.stub(bchjs.Electrumx.blockchain, 'getBlockCount').resolves(672141)
|
||||
|
||||
await bchjs.Electrumx.sortAllTxs('abc')
|
||||
|
||||
assert.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(err.message)
|
||||
assert.equal(err.message, 'txs.map is not a function')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Mock data used for unit testing.
|
||||
*/
|
||||
const dsproof = {
|
||||
dspid: '6234fff2a9dbcaa50e2c50d74e1d725a2bed1757d7a05a2db7a82df659554397',
|
||||
txid: 'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e',
|
||||
outpoint: {
|
||||
txid: '17ebef34f7e9a0692317dd6fbb43ffccff45b7d688a2a754dbccfc5e6d93ce3e',
|
||||
vout: 1
|
||||
},
|
||||
path: ['ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'],
|
||||
descendants: [
|
||||
'ee0df780b58f6f24467605b2589c44c3a50fc849fb8f91b89669a4ae0d86bc7e'
|
||||
]
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
dsproof
|
||||
}
|
||||
@@ -168,7 +168,8 @@ const txDetails = {
|
||||
blocktime: 1578327094,
|
||||
confirmations: 31861,
|
||||
hash: '4db095f34d632a4daf942142c291f1f2abb5ba2e1ccac919d85bdc2f671fb251',
|
||||
hex: '020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000',
|
||||
hex:
|
||||
'020000000265d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667010000006441dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309ffffffff65d13ef402840c8a51f39779afb7ae4d49e4b0a3c24a3d0e7742038f2c679667000000006441347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954ffffffff035ac355000000000017a914189ce02e332548f4804bac65cba68202c9dbf822878dfd0800000000001976a914285bb350881b21ac89724c6fb6dc914d096cd53b88acf9ef3100000000001976a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac00000000',
|
||||
locktime: 0,
|
||||
size: 392,
|
||||
time: 1578327094,
|
||||
@@ -177,8 +178,10 @@ const txDetails = {
|
||||
vin: [
|
||||
{
|
||||
scriptSig: {
|
||||
asm: 'dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e[ALL|FORKID] 020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309',
|
||||
hex: '41dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309'
|
||||
asm:
|
||||
'dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e[ALL|FORKID] 020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309',
|
||||
hex:
|
||||
'41dd1dd72770cadede1a7fd0363574846c48468a398ddfa41a9677c74cac8d2652b682743725a3b08c6c2021a629011e11a264d9036e9d5311e35b5f4937ca7b4e4121020797d8fd4d2fa6fd7cdeabe2526bfea2b90525d6e8ad506ec4ee3c53885aa309'
|
||||
},
|
||||
sequence: 4294967295,
|
||||
txid: '6796672c8f0342770e3d4ac2a3b0e4494daeb7af7997f3518a0c8402f43ed165',
|
||||
@@ -186,8 +189,10 @@ const txDetails = {
|
||||
},
|
||||
{
|
||||
scriptSig: {
|
||||
asm: '347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f77[ALL|FORKID] 028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954',
|
||||
hex: '41347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954'
|
||||
asm:
|
||||
'347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f77[ALL|FORKID] 028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954',
|
||||
hex:
|
||||
'41347d7f218c11c04487c1ad8baac28928fb10e5054cd4494b94d078cfa04ccf68e064fb188127ff656c0b98e9ce87f036d183925d0d0860605877d61e90375f774121028a53f95eb631b460854fc836b2e5d31cad16364b4dc3d970babfbdcc3f2e4954'
|
||||
},
|
||||
sequence: 4294967295,
|
||||
txid: '6796672c8f0342770e3d4ac2a3b0e4494daeb7af7997f3518a0c8402f43ed165',
|
||||
@@ -210,7 +215,8 @@ const txDetails = {
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
addresses: ['bitcoincash: qq59hv6s3qdjrtyfwfxxldkuj9xsjmx48vrz882knz'],
|
||||
asm: 'OP_DUP OP_HASH160 285bb350881b21ac89724c6fb6dc914d096cd53b OP_EQUALVERIFY OP_CHECKSIG',
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 285bb350881b21ac89724c6fb6dc914d096cd53b OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a914285bb350881b21ac89724c6fb6dc914d096cd53b88ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash'
|
||||
@@ -221,7 +227,8 @@ const txDetails = {
|
||||
n: 2,
|
||||
scriptPubKey: {
|
||||
addresses: ['bitcoincash: qpzlruwy4xu5rxjs3z37nsj29y7h59gwvsu4ddp0u4'],
|
||||
asm: 'OP_DUP OP_HASH160 45f1f1c4a9b9419a5088a3e9c24a293d7a150e64 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 45f1f1c4a9b9419a5088a3e9c24a293d7a150e64 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a91445f1f1c4a9b9419a5088a3e9c24a293d7a150e6488ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash'
|
||||
@@ -255,6 +262,34 @@ const broadcast = {
|
||||
txid: txDetails.txid
|
||||
}
|
||||
|
||||
const txHistoryWithUnconfirmed = {
|
||||
success: true,
|
||||
transactions: [
|
||||
{
|
||||
height: 668539,
|
||||
tx_hash:
|
||||
'fd9bffca3dd7a2d801c87cb36e8b43949d2e171bb8e25e3d92cf39ac5e2ba179'
|
||||
},
|
||||
{
|
||||
height: 668544,
|
||||
tx_hash:
|
||||
'9d1b438aa55d75da8ebe9dcdfa4fa96714042ce0a19c8f3c10d86e1e3dcbccf5'
|
||||
},
|
||||
{
|
||||
fee: 440,
|
||||
height: 0,
|
||||
tx_hash:
|
||||
'30d3fa9bf78eab2162d4f1894223e417e7275fdf0d590fe5085381dd475ff077'
|
||||
},
|
||||
{
|
||||
fee: 468,
|
||||
height: -1,
|
||||
tx_hash:
|
||||
'4b93c26a4612b6819fde2bf5d1f6387bf92f49a3375c53a472001e7d76a80e59'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
utxo,
|
||||
utxos,
|
||||
@@ -267,5 +302,6 @@ module.exports = {
|
||||
blockHeaders,
|
||||
details,
|
||||
detailsArray,
|
||||
broadcast
|
||||
broadcast,
|
||||
txHistoryWithUnconfirmed
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Mocking data for the RawTransactions unit tests.
|
||||
*/
|
||||
|
||||
const mockTx = {
|
||||
txid: '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3',
|
||||
vin: [
|
||||
{
|
||||
txid: '8a6b3b70569270f0bdbf68fd12a410aef8f7bf044bc88ab02386a1572024b2bd',
|
||||
vout: 0,
|
||||
scriptSig: {
|
||||
asm:
|
||||
'3044022035c42f5b10d412445c5ecc5feea42c7f885c433669306c699da0f687216c61d5022018c81cd0ea68101cf3cbe0af67165fca1ce3d667be69d0c9329f0679bbee6ba0[ALL|FORKID] 030152eb20beaa692daaa1a27596dcc98cc06ccbc6eec23d6182a08c7bdaa29ea9',
|
||||
hex:
|
||||
'473044022035c42f5b10d412445c5ecc5feea42c7f885c433669306c699da0f687216c61d5022018c81cd0ea68101cf3cbe0af67165fca1ce3d667be69d0c9329f0679bbee6ba04121030152eb20beaa692daaa1a27596dcc98cc06ccbc6eec23d6182a08c7bdaa29ea9'
|
||||
},
|
||||
sequence: 4294967295
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const mockParentTx1 = {
|
||||
vout: [
|
||||
{
|
||||
value: 0.04199959,
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 d5258a73b5c8f94c939d7fe96f78ce97906083be OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a914d5258a73b5c8f94c939d7fe96f78ce97906083be88ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qr2jtznnkhy0jnynn4l7jmmce6teqcyrhc8herhlgt']
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 1.66296161,
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 5e95c308c25c74c64c5ffe44a60a4d9b35743e90 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a9145e95c308c25c74c64c5ffe44a60a4d9b35743e9088ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qp0ftscgcfw8f3jvtllyffs2fkdn2ap7jqreakn4ye']
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const mockGetInputAddrsOutput = [
|
||||
{
|
||||
vin: 0,
|
||||
address: 'bitcoincash:qr2jtznnkhy0jnynn4l7jmmce6teqcyrhc8herhlgt'
|
||||
}
|
||||
]
|
||||
|
||||
module.exports = {
|
||||
mockTx,
|
||||
mockParentTx1,
|
||||
mockGetInputAddrsOutput
|
||||
}
|
||||
@@ -119,6 +119,33 @@ const mockTokens = [
|
||||
}
|
||||
]
|
||||
|
||||
const mockNftChildrenList = {
|
||||
nftChildren: [
|
||||
'45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a9',
|
||||
'928ce61fe1006b1325a0ba0dce700bf83986a6f0691ba26e121c9ac035d12a55'
|
||||
]
|
||||
}
|
||||
|
||||
const mockNftGroup = {
|
||||
nftGroup: {
|
||||
decimals: 0,
|
||||
timestamp: '2021-05-03 10:36:01',
|
||||
timestamp_unix: 1620038161,
|
||||
versionType: 129,
|
||||
documentUri: 'psfoundation.cash',
|
||||
symbol: 'PSF.TEST.GROUP',
|
||||
name: 'PSF Test NFT Group',
|
||||
containsBaton: true,
|
||||
id: '68cd33ecd909068fbea318ae5ff1d6207cf754e53b191327d6d73b6916424c0a',
|
||||
documentHash: null,
|
||||
initialTokenQty: 1000000,
|
||||
blockCreated: 686117,
|
||||
totalMinted: null,
|
||||
totalBurned: null,
|
||||
circulatingSupply: null
|
||||
}
|
||||
}
|
||||
|
||||
const balancesForAddress = [
|
||||
{
|
||||
tokenId: 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
|
||||
@@ -1290,10 +1317,106 @@ const slpdbStatus = {
|
||||
}
|
||||
}
|
||||
|
||||
const txDetailsSLPNftChild = {
|
||||
txid: 'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b',
|
||||
hash: 'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b',
|
||||
version: 2,
|
||||
size: 453,
|
||||
locktime: 0,
|
||||
vin: [
|
||||
{
|
||||
txid: 'a9a2458a0f9f0761d5b8725c256f2e7fa35b9de4dec6f47b46e9f20d92d0e395',
|
||||
vout: 1,
|
||||
scriptSig: {
|
||||
asm:
|
||||
'3045022100890ff2f80f3c184419ba03a575b9d159c0a5edfa817e4548cfdb6c74d16ce8d202205a8237d2139196716c273fe80506896d369a0022bb54401e2eadb364286a9f07[ALL|FORKID] 03136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623b',
|
||||
hex:
|
||||
'483045022100890ff2f80f3c184419ba03a575b9d159c0a5edfa817e4548cfdb6c74d16ce8d202205a8237d2139196716c273fe80506896d369a0022bb54401e2eadb364286a9f07412103136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623b'
|
||||
},
|
||||
sequence: 4294967295
|
||||
},
|
||||
{
|
||||
txid: 'a9a2458a0f9f0761d5b8725c256f2e7fa35b9de4dec6f47b46e9f20d92d0e395',
|
||||
vout: 3,
|
||||
scriptSig: {
|
||||
asm:
|
||||
'304402203905a61ec4e3567f7cad7eb514132e5b32d8a1d77c8838baac1b34b735282a5f022044da6130b5cc41b65615b17df6610087fe1baedd1a3a9f37552b56ea8d36d026[ALL|FORKID] 03136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623b',
|
||||
hex:
|
||||
'47304402203905a61ec4e3567f7cad7eb514132e5b32d8a1d77c8838baac1b34b735282a5f022044da6130b5cc41b65615b17df6610087fe1baedd1a3a9f37552b56ea8d36d026412103136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623b'
|
||||
},
|
||||
sequence: 4294967295
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: 0,
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_RETURN 5262419 65 47454e45534953 4e4654303034 4e4654204368696c64 68747470733a2f2f46756c6c537461636b2e63617368 0 0 0 0000000000000001',
|
||||
hex:
|
||||
'6a04534c500001410747454e45534953064e4654303034094e4654204368696c641668747470733a2f2f46756c6c537461636b2e636173684c0001004c00080000000000000001',
|
||||
type: 'nulldata'
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00000546,
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 f6fc6bce702ef779d2373aa4356a32113d95e674 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a914f6fc6bce702ef779d2373aa4356a32113d95e67488ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qrm0c67wwqh0w7wjxua2gdt2xggnm90xws00a3lezv']
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.0003923,
|
||||
n: 2,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 f6fc6bce702ef779d2373aa4356a32113d95e674 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a914f6fc6bce702ef779d2373aa4356a32113d95e67488ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qrm0c67wwqh0w7wjxua2gdt2xggnm90xws00a3lezv']
|
||||
}
|
||||
}
|
||||
],
|
||||
hex:
|
||||
'020000000295e3d0920df2e9467bf4c6dee49d5ba37f2e6f255c72b8d561079f0f8a45a2a9010000006b483045022100890ff2f80f3c184419ba03a575b9d159c0a5edfa817e4548cfdb6c74d16ce8d202205a8237d2139196716c273fe80506896d369a0022bb54401e2eadb364286a9f07412103136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623bffffffff95e3d0920df2e9467bf4c6dee49d5ba37f2e6f255c72b8d561079f0f8a45a2a9030000006a47304402203905a61ec4e3567f7cad7eb514132e5b32d8a1d77c8838baac1b34b735282a5f022044da6130b5cc41b65615b17df6610087fe1baedd1a3a9f37552b56ea8d36d026412103136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623bffffffff030000000000000000476a04534c500001410747454e45534953064e4654303034094e4654204368696c641668747470733a2f2f46756c6c537461636b2e636173684c0001004c0008000000000000000122020000000000001976a914f6fc6bce702ef779d2373aa4356a32113d95e67488ac3e990000000000001976a914f6fc6bce702ef779d2373aa4356a32113d95e67488ac00000000',
|
||||
blockhash: '000000000000000001360fe42629f4136e9adec53546b278de0e7ef788eed328',
|
||||
confirmations: 2113,
|
||||
time: 1613181364,
|
||||
blocktime: 1613181364
|
||||
}
|
||||
|
||||
const mock429Error = new Error('Request failed with status code 429')
|
||||
mock429Error.response = {
|
||||
status: 429,
|
||||
statusText: 'Too Many Requests',
|
||||
data: {
|
||||
error:
|
||||
'Too many requests. Your limits are currently 100 requests per minute. Increase rate limits at https://fullstack.cash'
|
||||
}
|
||||
}
|
||||
|
||||
const mock503Error = new Error('Request failed with status code 503')
|
||||
mock503Error.response = {
|
||||
status: 503,
|
||||
statusText: 'Service Unavailable',
|
||||
data: {
|
||||
error: 'Some error message'
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mockList,
|
||||
mockToken,
|
||||
mockTokens,
|
||||
mockNftChildrenList,
|
||||
mockNftGroup,
|
||||
balancesForAddress,
|
||||
balancesForAddresses,
|
||||
mockRawTx,
|
||||
@@ -1311,6 +1434,7 @@ module.exports = {
|
||||
txDetailsSLPGenesisNoBaton,
|
||||
txDetailsSLPSendAlt,
|
||||
txDetailsSLPNftGenesis,
|
||||
txDetailsSLPNftChild,
|
||||
mockTxDetails,
|
||||
mockDualValidation,
|
||||
mockDualOpData,
|
||||
@@ -1320,5 +1444,7 @@ module.exports = {
|
||||
mockValidateTxid3Invalid,
|
||||
whitelist,
|
||||
slpdbStatus,
|
||||
mockValidateTxidArray
|
||||
mockValidateTxidArray,
|
||||
mock429Error,
|
||||
mock503Error
|
||||
}
|
||||
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
Mocking data used in the transaction-unit.js tests.
|
||||
*/
|
||||
|
||||
const nonSlpTxDetails = {
|
||||
txid: '2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7',
|
||||
hash: '2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7',
|
||||
version: 2,
|
||||
size: 225,
|
||||
locktime: 0,
|
||||
vin: [
|
||||
{
|
||||
txid: '5f09d317e24c5d376f737a2711f3bd1d381abdb41743fff3819b4f76382e1eac',
|
||||
vout: 1,
|
||||
scriptSig: {
|
||||
asm:
|
||||
'3044022000dd11c41a472f2e54348db996e60864d489429f12d1e044d49ff600b880c9590220715a926404bb0e2731a3795afb341ec1dad3f84ead7d27cd31fcc59abb14738c[ALL|FORKID] 038476128287ac37c7a3cf7e8625fd5f024db1bc3d8e37395abe7bf42fda78d0d9',
|
||||
hex:
|
||||
'473044022000dd11c41a472f2e54348db996e60864d489429f12d1e044d49ff600b880c9590220715a926404bb0e2731a3795afb341ec1dad3f84ead7d27cd31fcc59abb14738c4121038476128287ac37c7a3cf7e8625fd5f024db1bc3d8e37395abe7bf42fda78d0d9'
|
||||
},
|
||||
sequence: 4294967295,
|
||||
address: 'bitcoincash:qqxy8hycqe89j7wa79gnggq6z3gaqu2uvqy26xehfe',
|
||||
value: 0.00047504
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: 0.00001,
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 2fe2c4c5ef359bb2fe1a849f891cecffbcfb4f77 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a9142fe2c4c5ef359bb2fe1a849f891cecffbcfb4f7788ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9']
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00046256,
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 2dbf5e1804c39a497b908c876097d63210c84902 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a9142dbf5e1804c39a497b908c876097d63210c8490288ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qqkm7hscqnpe5jtmjzxgwcyh6ceppjzfqg3jdn422e']
|
||||
}
|
||||
}
|
||||
],
|
||||
hex:
|
||||
'0200000001ac1e2e38764f9b81f3ff4317b4bd1a381dbdf311277a736f375d4ce217d3095f010000006a473044022000dd11c41a472f2e54348db996e60864d489429f12d1e044d49ff600b880c9590220715a926404bb0e2731a3795afb341ec1dad3f84ead7d27cd31fcc59abb14738c4121038476128287ac37c7a3cf7e8625fd5f024db1bc3d8e37395abe7bf42fda78d0d9ffffffff02e8030000000000001976a9142fe2c4c5ef359bb2fe1a849f891cecffbcfb4f7788acb0b40000000000001976a9142dbf5e1804c39a497b908c876097d63210c8490288ac00000000',
|
||||
blockhash: '0000000000000000010903a1fc4274499037c9339be9ec7338ee980331c20ce5',
|
||||
confirmations: 77741,
|
||||
time: 1569792892,
|
||||
blocktime: 1569792892
|
||||
}
|
||||
|
||||
const slpTxDetails = {
|
||||
txid: '266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1',
|
||||
hash: '266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1',
|
||||
version: 2,
|
||||
size: 479,
|
||||
locktime: 0,
|
||||
vin: [
|
||||
{
|
||||
txid: 'abc685f1f2a95f51e5e05a350f3fb9c74676e9f78c835b2a019c888ac0a2a736',
|
||||
vout: 2,
|
||||
scriptSig: {
|
||||
asm:
|
||||
'3045022100e5f0f6f1212fcbb10eedb7fdc38fca6e86629b4e7e8356a3ad7371a109fc37a602204bfff37d1a34d2e2908b81c23677706fb59ff4ab639fa3299da6c303de74e1f7[ALL|FORKID] 0245b9b3586fab3cfd46db6d116c4588004fe7fe9798216ccb8e55a89bcebc07ac',
|
||||
hex:
|
||||
'483045022100e5f0f6f1212fcbb10eedb7fdc38fca6e86629b4e7e8356a3ad7371a109fc37a602204bfff37d1a34d2e2908b81c23677706fb59ff4ab639fa3299da6c303de74e1f741210245b9b3586fab3cfd46db6d116c4588004fe7fe9798216ccb8e55a89bcebc07ac'
|
||||
},
|
||||
sequence: 4294967295,
|
||||
address: 'bitcoincash:qzv7t2pzn2d0pklnetdjt65crh6fe8vnhuwvhsk2nn',
|
||||
value: 0.00000546
|
||||
},
|
||||
{
|
||||
txid: '58c8576404c01c23a224053307399483d3a070599b3e9eb6d45be9714b8d6856',
|
||||
vout: 1,
|
||||
scriptSig: {
|
||||
asm:
|
||||
'30430220784f6d81fa8f54db8a4948259e8c15972a0285f8b1640c433d4e9f606dc38f0c021f14eecc2e8af2efede0867ce459c400dde54186a0e64babdbe89f795db12753[ALL|FORKID] 0209ebe6d9da5043945ed1d81bec0fcace299eba05e5f46b72d6838c790d31c505',
|
||||
hex:
|
||||
'4630430220784f6d81fa8f54db8a4948259e8c15972a0285f8b1640c433d4e9f606dc38f0c021f14eecc2e8af2efede0867ce459c400dde54186a0e64babdbe89f795db1275341210209ebe6d9da5043945ed1d81bec0fcace299eba05e5f46b72d6838c790d31c505'
|
||||
},
|
||||
sequence: 4294967295,
|
||||
address: 'bitcoincash:qppzuxemgqyxf07nz3kan33gmc83mf3z3yz295c4s7',
|
||||
value: 0.68369626
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: 0,
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_RETURN 5262419 1 1145980243 497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7 0000000005f5e100 00005ad7e49d9100',
|
||||
hex:
|
||||
'6a04534c500001010453454e4420497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7080000000005f5e1000800005ad7e49d9100',
|
||||
type: 'nulldata'
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00000546,
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 36be3b7d185a85b6cf6fc61d63c16f2f10e54260 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a91436be3b7d185a85b6cf6fc61d63c16f2f10e5426088ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qqmtuwmarpdgtdk0dlrp6c7pduh3pe2zvqrkys2ex8']
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00000546,
|
||||
n: 2,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 99e5a8229a9af0dbf3cadb25ea981df49c9d93bf OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a91499e5a8229a9af0dbf3cadb25ea981df49c9d93bf88ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qzv7t2pzn2d0pklnetdjt65crh6fe8vnhuwvhsk2nn']
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.68368564,
|
||||
n: 3,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 422e1b3b400864bfd3146dd9c628de0f1da62289 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a914422e1b3b400864bfd3146dd9c628de0f1da6228988ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qppzuxemgqyxf07nz3kan33gmc83mf3z3yz295c4s7']
|
||||
}
|
||||
}
|
||||
],
|
||||
hex:
|
||||
'020000000236a7a2c08a889c012a5b838cf7e97646c7b93f0f355ae0e5515fa9f2f185c6ab020000006b483045022100e5f0f6f1212fcbb10eedb7fdc38fca6e86629b4e7e8356a3ad7371a109fc37a602204bfff37d1a34d2e2908b81c23677706fb59ff4ab639fa3299da6c303de74e1f741210245b9b3586fab3cfd46db6d116c4588004fe7fe9798216ccb8e55a89bcebc07acffffffff56688d4b71e95bd4b69e3e9b5970a0d383943907330524a2231cc0046457c85801000000694630430220784f6d81fa8f54db8a4948259e8c15972a0285f8b1640c433d4e9f606dc38f0c021f14eecc2e8af2efede0867ce459c400dde54186a0e64babdbe89f795db1275341210209ebe6d9da5043945ed1d81bec0fcace299eba05e5f46b72d6838c790d31c505ffffffff040000000000000000406a04534c500001010453454e4420497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7080000000005f5e1000800005ad7e49d910022020000000000001976a91436be3b7d185a85b6cf6fc61d63c16f2f10e5426088ac22020000000000001976a91499e5a8229a9af0dbf3cadb25ea981df49c9d93bf88acb4381304000000001976a914422e1b3b400864bfd3146dd9c628de0f1da6228988ac00000000',
|
||||
blockhash: '0000000000000000015284202422a688554b7fc80c54f18122847a99c4f79607',
|
||||
confirmations: 76722,
|
||||
time: 1570392893,
|
||||
blocktime: 1570392893
|
||||
}
|
||||
|
||||
const mockOpReturnData01 = {
|
||||
tokenType: 1,
|
||||
txType: 'SEND',
|
||||
tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
|
||||
amounts: ['100000000', '99883300000000']
|
||||
}
|
||||
|
||||
const mockOpReturnData02 = {
|
||||
tokenType: 1,
|
||||
txType: 'GENESIS',
|
||||
ticker: 'TOK-CH',
|
||||
name: 'TokyoCash',
|
||||
tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
|
||||
documentUri: '',
|
||||
documentHash: '',
|
||||
decimals: 8,
|
||||
mintBatonVout: 0,
|
||||
qty: '2100000000000000'
|
||||
}
|
||||
|
||||
const mockOpReturnData03 = {
|
||||
tokenType: 1,
|
||||
txType: 'SEND',
|
||||
tokenId: '497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7',
|
||||
amounts: ['1000000000', '99883400000000']
|
||||
}
|
||||
|
||||
const genesisTestInputTx = {
|
||||
txid: '874306bda204d3a5dd15e03ea5732cccdca4c33a52df35162cdd64e30ea7f04e',
|
||||
hash: '874306bda204d3a5dd15e03ea5732cccdca4c33a52df35162cdd64e30ea7f04e',
|
||||
version: 1,
|
||||
size: 480,
|
||||
locktime: 543408,
|
||||
vin: [
|
||||
{
|
||||
txid: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
||||
vout: 1,
|
||||
scriptSig: {
|
||||
asm:
|
||||
'30440220268dacee1117975d904dd0d45ef8de42b86030d825a9522bae196a38bbf6b271022001ae1ce2536ab300040e597bcfaa8ef9fb2beaf702d0842f3161aae8e9867f55[ALL|FORKID] 028ff9e32b0dbc82c1d5e0fc945b2537b00420513b10684726f312f1b717c0ae11',
|
||||
hex:
|
||||
'4730440220268dacee1117975d904dd0d45ef8de42b86030d825a9522bae196a38bbf6b271022001ae1ce2536ab300040e597bcfaa8ef9fb2beaf702d0842f3161aae8e9867f554121028ff9e32b0dbc82c1d5e0fc945b2537b00420513b10684726f312f1b717c0ae11'
|
||||
},
|
||||
sequence: 4294967294,
|
||||
address: 'bitcoincash:qp2jesd06k8ycj4wvkpl9lcwaemtr04f5yphjsa07v',
|
||||
value: 0.00000546
|
||||
},
|
||||
{
|
||||
txid: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
||||
vout: 3,
|
||||
scriptSig: {
|
||||
asm:
|
||||
'3045022100fa241bb2de46f68688451bfcae3f165b724e3ccf13b219e7bf2d8d2df7712ad60220353017d6e581a06efce478adfcd2047cea2f92531e283845f3d0a345ef101519[ALL|FORKID] 02cc48ad10516f97e914b8836ff25448d07ad96ebb4704c6a828339880280831bc',
|
||||
hex:
|
||||
'483045022100fa241bb2de46f68688451bfcae3f165b724e3ccf13b219e7bf2d8d2df7712ad60220353017d6e581a06efce478adfcd2047cea2f92531e283845f3d0a345ef101519412102cc48ad10516f97e914b8836ff25448d07ad96ebb4704c6a828339880280831bc'
|
||||
},
|
||||
sequence: 4294967294,
|
||||
address: 'bitcoincash:qppj3euc36x5u6twr5cxrrea2rca53vsfu3dxwr86j',
|
||||
value: 0.00172192
|
||||
}
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: 0,
|
||||
n: 0,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_RETURN 5262419 1 1145980243 323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35 00000000004c4b40 00000000004c4b40',
|
||||
hex:
|
||||
'6a04534c500001010453454e4420323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d350800000000004c4b400800000000004c4b40',
|
||||
type: 'nulldata'
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00000546,
|
||||
n: 1,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 0a74cf9c0fb3f6dd62c3f5eecd1ed6e1051428e0 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a9140a74cf9c0fb3f6dd62c3f5eecd1ed6e1051428e088ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qq98fnuup7eldhtzc067ang76mss29pguqh7qv9eac']
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00000546,
|
||||
n: 2,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 d4548261e1be0de7e50b7511597799ec4af2b173 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a914d4548261e1be0de7e50b7511597799ec4af2b17388ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qr29fqnpuxlqmel9pd63zkthn8ky4u43wv0v7pg5mn']
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 0.00171165,
|
||||
n: 3,
|
||||
scriptPubKey: {
|
||||
asm:
|
||||
'OP_DUP OP_HASH160 d4548261e1be0de7e50b7511597799ec4af2b173 OP_EQUALVERIFY OP_CHECKSIG',
|
||||
hex: '76a914d4548261e1be0de7e50b7511597799ec4af2b17388ac',
|
||||
reqSigs: 1,
|
||||
type: 'pubkeyhash',
|
||||
addresses: ['bitcoincash:qr29fqnpuxlqmel9pd63zkthn8ky4u43wv0v7pg5mn']
|
||||
}
|
||||
}
|
||||
],
|
||||
hex:
|
||||
'0100000002359dab0d9c8ddc788b14c0b51493d195c9fbd9f2203d091663350bae351e3a32010000006a4730440220268dacee1117975d904dd0d45ef8de42b86030d825a9522bae196a38bbf6b271022001ae1ce2536ab300040e597bcfaa8ef9fb2beaf702d0842f3161aae8e9867f554121028ff9e32b0dbc82c1d5e0fc945b2537b00420513b10684726f312f1b717c0ae11feffffff359dab0d9c8ddc788b14c0b51493d195c9fbd9f2203d091663350bae351e3a32030000006b483045022100fa241bb2de46f68688451bfcae3f165b724e3ccf13b219e7bf2d8d2df7712ad60220353017d6e581a06efce478adfcd2047cea2f92531e283845f3d0a345ef101519412102cc48ad10516f97e914b8836ff25448d07ad96ebb4704c6a828339880280831bcfeffffff040000000000000000406a04534c500001010453454e4420323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d350800000000004c4b400800000000004c4b4022020000000000001976a9140a74cf9c0fb3f6dd62c3f5eecd1ed6e1051428e088ac22020000000000001976a914d4548261e1be0de7e50b7511597799ec4af2b17388ac9d9c0200000000001976a914d4548261e1be0de7e50b7511597799ec4af2b17388acb04a0800',
|
||||
blockhash: '000000000000000000292a9c6150fce48e2edd8df346948494fe6249e6e7f63b',
|
||||
confirmations: 163095,
|
||||
time: 1534271330,
|
||||
blocktime: 1534271330
|
||||
}
|
||||
|
||||
genesisTestOpReturnData01 = {
|
||||
tokenType: 1,
|
||||
txType: 'SEND',
|
||||
tokenId: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
||||
amounts: ['5000000', '5000000']
|
||||
}
|
||||
|
||||
genesisTestOpReturnData02 = {
|
||||
tokenType: 1,
|
||||
txType: 'GENESIS',
|
||||
ticker: '',
|
||||
name: '',
|
||||
tokenId: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
|
||||
documentUri: '',
|
||||
documentHash: '',
|
||||
decimals: 0,
|
||||
mintBatonVout: 2,
|
||||
qty: '10000000'
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
nonSlpTxDetails,
|
||||
slpTxDetails,
|
||||
mockOpReturnData01,
|
||||
mockOpReturnData02,
|
||||
mockOpReturnData03,
|
||||
genesisTestInputTx,
|
||||
genesisTestOpReturnData01,
|
||||
genesisTestOpReturnData02
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
const mockUtxoData = {
|
||||
success: true,
|
||||
utxos: [
|
||||
{
|
||||
utxos: [
|
||||
{
|
||||
height: 569108,
|
||||
tx_hash:
|
||||
'384e1b8197e8de7d38f98317af2cf5f6bcb50007c46943b3498a6fab6e8aeb7c',
|
||||
tx_pos: 1,
|
||||
value: 546
|
||||
},
|
||||
{
|
||||
height: 674331,
|
||||
tx_hash:
|
||||
'5e86cd911110e4f5db0cc3e8f459d5e8850b49adf57059a71daee674b2867b31',
|
||||
tx_pos: 0,
|
||||
value: 1000
|
||||
}
|
||||
],
|
||||
address: 'bitcoincash:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvg8nfhq4m'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const mockHydratedUtxos = {
|
||||
slpUtxos: [
|
||||
{
|
||||
utxos: [
|
||||
{
|
||||
height: 569108,
|
||||
tx_hash:
|
||||
'384e1b8197e8de7d38f98317af2cf5f6bcb50007c46943b3498a6fab6e8aeb7c',
|
||||
tx_pos: 1,
|
||||
value: 546,
|
||||
txid:
|
||||
'384e1b8197e8de7d38f98317af2cf5f6bcb50007c46943b3498a6fab6e8aeb7c',
|
||||
vout: 1,
|
||||
utxoType: 'token',
|
||||
transactionType: 'send',
|
||||
tokenId:
|
||||
'a436c8e1b6bee3d701c6044d190f76f774be83c36de8d34a988af4489e86dd37',
|
||||
tokenTicker: 'sleven',
|
||||
tokenName: 'sleven',
|
||||
tokenDocumentUrl: 'sleven',
|
||||
tokenDocumentHash: '',
|
||||
decimals: 7,
|
||||
tokenType: 1,
|
||||
tokenQty: '1',
|
||||
isValid: true
|
||||
},
|
||||
{
|
||||
height: 674331,
|
||||
tx_hash:
|
||||
'5e86cd911110e4f5db0cc3e8f459d5e8850b49adf57059a71daee674b2867b31',
|
||||
tx_pos: 0,
|
||||
value: 1000,
|
||||
txid:
|
||||
'5e86cd911110e4f5db0cc3e8f459d5e8850b49adf57059a71daee674b2867b31',
|
||||
vout: 0,
|
||||
isValid: false
|
||||
}
|
||||
],
|
||||
address: 'bitcoincash:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvg8nfhq4m'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const mockTwoHydratedAddrs = {
|
||||
slpUtxos: [
|
||||
{
|
||||
utxos: [
|
||||
{
|
||||
height: 569108,
|
||||
tx_hash:
|
||||
'384e1b8197e8de7d38f98317af2cf5f6bcb50007c46943b3498a6fab6e8aeb7c',
|
||||
tx_pos: 1,
|
||||
value: 546,
|
||||
txid:
|
||||
'384e1b8197e8de7d38f98317af2cf5f6bcb50007c46943b3498a6fab6e8aeb7c',
|
||||
vout: 1,
|
||||
utxoType: 'token',
|
||||
transactionType: 'send',
|
||||
tokenId:
|
||||
'a436c8e1b6bee3d701c6044d190f76f774be83c36de8d34a988af4489e86dd37',
|
||||
tokenTicker: 'sleven',
|
||||
tokenName: 'sleven',
|
||||
tokenDocumentUrl: 'sleven',
|
||||
tokenDocumentHash: '',
|
||||
decimals: 7,
|
||||
tokenType: 1,
|
||||
tokenQty: '1',
|
||||
isValid: true
|
||||
},
|
||||
{
|
||||
height: 674331,
|
||||
tx_hash:
|
||||
'5e86cd911110e4f5db0cc3e8f459d5e8850b49adf57059a71daee674b2867b31',
|
||||
tx_pos: 0,
|
||||
value: 1000,
|
||||
txid:
|
||||
'5e86cd911110e4f5db0cc3e8f459d5e8850b49adf57059a71daee674b2867b31',
|
||||
vout: 0,
|
||||
isValid: false
|
||||
}
|
||||
],
|
||||
address: 'bitcoincash:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvg8nfhq4m'
|
||||
},
|
||||
{
|
||||
utxos: [
|
||||
{
|
||||
height: 602405,
|
||||
tx_hash:
|
||||
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7',
|
||||
tx_pos: 0,
|
||||
value: 1000,
|
||||
txid:
|
||||
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7',
|
||||
vout: 0,
|
||||
isValid: false
|
||||
}
|
||||
],
|
||||
address: 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const mockEveryUtxoType = {
|
||||
slpUtxos: [
|
||||
{
|
||||
utxos: [
|
||||
{
|
||||
height: 674512,
|
||||
tx_hash:
|
||||
'acbb0d3ceef55aa3e5fafc19335ae4bf2f8edba3c0567547dfd402391db32230',
|
||||
tx_pos: 1,
|
||||
value: 546,
|
||||
txid:
|
||||
'acbb0d3ceef55aa3e5fafc19335ae4bf2f8edba3c0567547dfd402391db32230',
|
||||
vout: 1,
|
||||
utxoType: 'token',
|
||||
tokenQty: '100',
|
||||
tokenId:
|
||||
'acbb0d3ceef55aa3e5fafc19335ae4bf2f8edba3c0567547dfd402391db32230',
|
||||
tokenTicker: 'SLPTEST',
|
||||
tokenName: 'SLP Test Token',
|
||||
tokenDocumentUrl: 'https://FullStack.cash',
|
||||
tokenDocumentHash: '',
|
||||
decimals: 8,
|
||||
tokenType: 1,
|
||||
isValid: true
|
||||
},
|
||||
{
|
||||
height: 674512,
|
||||
tx_hash:
|
||||
'acbb0d3ceef55aa3e5fafc19335ae4bf2f8edba3c0567547dfd402391db32230',
|
||||
tx_pos: 2,
|
||||
value: 546,
|
||||
txid:
|
||||
'acbb0d3ceef55aa3e5fafc19335ae4bf2f8edba3c0567547dfd402391db32230',
|
||||
vout: 2,
|
||||
utxoType: 'minting-baton',
|
||||
tokenId:
|
||||
'acbb0d3ceef55aa3e5fafc19335ae4bf2f8edba3c0567547dfd402391db32230',
|
||||
tokenTicker: 'SLPTEST',
|
||||
tokenName: 'SLP Test Token',
|
||||
tokenDocumentUrl: 'https://FullStack.cash',
|
||||
tokenDocumentHash: '',
|
||||
decimals: 8,
|
||||
tokenType: 1,
|
||||
isValid: true
|
||||
},
|
||||
{
|
||||
height: 674512,
|
||||
tx_hash:
|
||||
'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b',
|
||||
tx_pos: 1,
|
||||
value: 546,
|
||||
txid:
|
||||
'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b',
|
||||
vout: 1,
|
||||
utxoType: 'token',
|
||||
tokenQty: '1',
|
||||
tokenId:
|
||||
'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b',
|
||||
tokenTicker: 'NFT004',
|
||||
tokenName: 'NFT Child',
|
||||
tokenDocumentUrl: 'https://FullStack.cash',
|
||||
tokenDocumentHash: '',
|
||||
decimals: 0,
|
||||
tokenType: 65,
|
||||
isValid: true
|
||||
},
|
||||
{
|
||||
height: 674513,
|
||||
tx_hash:
|
||||
'705bcc442e5a2770e560b528f52a47b1dcc9ce9ab6a8de9dfdefa55177f00d04',
|
||||
tx_pos: 1,
|
||||
value: 546,
|
||||
txid:
|
||||
'705bcc442e5a2770e560b528f52a47b1dcc9ce9ab6a8de9dfdefa55177f00d04',
|
||||
vout: 1,
|
||||
utxoType: 'token',
|
||||
tokenQty: '10',
|
||||
transactionType: 'mint',
|
||||
tokenId:
|
||||
'a9a2458a0f9f0761d5b8725c256f2e7fa35b9de4dec6f47b46e9f20d92d0e395',
|
||||
tokenType: 129,
|
||||
tokenTicker: 'NFTGT',
|
||||
tokenName: 'NFT Test Group Token',
|
||||
tokenDocumentUrl: 'https://FullStack.cash',
|
||||
tokenDocumentHash: '',
|
||||
decimals: 0,
|
||||
mintBatonVout: 2,
|
||||
isValid: true
|
||||
},
|
||||
{
|
||||
height: 674513,
|
||||
tx_hash:
|
||||
'705bcc442e5a2770e560b528f52a47b1dcc9ce9ab6a8de9dfdefa55177f00d04',
|
||||
tx_pos: 2,
|
||||
value: 546,
|
||||
txid:
|
||||
'705bcc442e5a2770e560b528f52a47b1dcc9ce9ab6a8de9dfdefa55177f00d04',
|
||||
vout: 2,
|
||||
utxoType: 'minting-baton',
|
||||
transactionType: 'mint',
|
||||
tokenId:
|
||||
'a9a2458a0f9f0761d5b8725c256f2e7fa35b9de4dec6f47b46e9f20d92d0e395',
|
||||
tokenType: 129,
|
||||
tokenTicker: 'NFTGT',
|
||||
tokenName: 'NFT Test Group Token',
|
||||
tokenDocumentUrl: 'https://FullStack.cash',
|
||||
tokenDocumentHash: '',
|
||||
decimals: 0,
|
||||
mintBatonVout: 2,
|
||||
isValid: true
|
||||
},
|
||||
{
|
||||
height: 674513,
|
||||
tx_hash:
|
||||
'705bcc442e5a2770e560b528f52a47b1dcc9ce9ab6a8de9dfdefa55177f00d04',
|
||||
tx_pos: 3,
|
||||
value: 38134,
|
||||
txid:
|
||||
'705bcc442e5a2770e560b528f52a47b1dcc9ce9ab6a8de9dfdefa55177f00d04',
|
||||
vout: 3,
|
||||
isValid: false
|
||||
}
|
||||
],
|
||||
address: 'bitcoincash:qrm0c67wwqh0w7wjxua2gdt2xggnm90xws00a3lezv'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const electrumxUtxos = {
|
||||
success: true,
|
||||
utxos: [
|
||||
{
|
||||
height: 0,
|
||||
tx_hash:
|
||||
'192f5037bb3822afd92d6b6ab51842a5dcfbe6bff783290057342da1f27ed414',
|
||||
tx_pos: 0,
|
||||
value: 600
|
||||
},
|
||||
{
|
||||
height: 0,
|
||||
tx_hash:
|
||||
'f913646f7c180f8de020cb1387951272e8a3f764a0f88e68f7fc1145a0bf02e9',
|
||||
tx_pos: 0,
|
||||
value: 700
|
||||
},
|
||||
{
|
||||
height: 0,
|
||||
tx_hash:
|
||||
'7a091716f8137e94f87e7760648cd34a17e32754ef95f7c7bda38a635c9b2b1b',
|
||||
tx_pos: 0,
|
||||
value: 800
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mockUtxoData,
|
||||
mockHydratedUtxos,
|
||||
mockTwoHydratedAddrs,
|
||||
mockEveryUtxoType,
|
||||
electrumxUtxos
|
||||
}
|
||||
@@ -1,129 +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/openbazaar-mock')
|
||||
|
||||
describe('#OpenBazaar', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
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 () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, 'get').resolves({ data: mockData.balance })
|
||||
|
||||
const addr = 'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
|
||||
const result = await bchjs.OpenBazaar.balance(addr)
|
||||
// console.log(`result: ${util.inspect(result)}`)
|
||||
|
||||
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 () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, 'get').resolves({ data: mockData.utxo })
|
||||
|
||||
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 txid = 12345
|
||||
|
||||
await bchjs.OpenBazaar.tx(txid)
|
||||
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 tx details for a single txid', async () => {
|
||||
// Stub the network call.
|
||||
sandbox.stub(axios, 'get').resolves({ data: mockData.tx })
|
||||
|
||||
const txid =
|
||||
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7'
|
||||
|
||||
const result = await bchjs.OpenBazaar.tx(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.hasAllKeys(result, [
|
||||
'txid',
|
||||
'version',
|
||||
'vin',
|
||||
'vout',
|
||||
'blockhash',
|
||||
'blockheight',
|
||||
'confirmations',
|
||||
'blocktime',
|
||||
'valueOut',
|
||||
'valueIn',
|
||||
'fees',
|
||||
'hex'
|
||||
])
|
||||
assert.isArray(result.vin)
|
||||
assert.isArray(result.vout)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -67,4 +67,26 @@ describe('#price', () => {
|
||||
assert.isNumber(result)
|
||||
})
|
||||
})
|
||||
describe('#getBchUsd', () => {
|
||||
it('should get the USD price of BCH', async () => {
|
||||
sandbox.stub(bchjs.Price.axios, 'get').resolves({ data: { usd: 510.39 } })
|
||||
|
||||
const result = await bchjs.Price.getBchUsd()
|
||||
// console.log(result)
|
||||
|
||||
assert.isNumber(result)
|
||||
})
|
||||
it('should handle error', async () => {
|
||||
try {
|
||||
sandbox.stub(bchjs.Price.axios, 'get').throws(new Error('test error'))
|
||||
|
||||
await bchjs.Price.getBchUsd()
|
||||
// console.log(result)
|
||||
|
||||
assert.equal(false, true, 'unexpected error')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
TODO:
|
||||
-Create a mocking library of data to compare unit and integration tests.
|
||||
Unit tests for raw-transactions.js library.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
const assert = require('assert')
|
||||
const assert2 = require('chai').assert
|
||||
const axios = require('axios')
|
||||
const sinon = require('sinon')
|
||||
// const nock = require("nock") // HTTP mocking
|
||||
@@ -18,16 +18,19 @@ let bchjs
|
||||
// const util = require("util")
|
||||
// util.inspect.defaultOptions = { depth: 1 }
|
||||
|
||||
const mockData = require('./fixtures/rawtransaction-mock')
|
||||
|
||||
describe('#RawTransactions', () => {
|
||||
let sandbox
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
bchjs = new BCHJS()
|
||||
})
|
||||
|
||||
describe('#decodeRawTransaction', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#decodeRawTransaction', () => {
|
||||
it('should decode raw transaction', done => {
|
||||
const data = {
|
||||
txid:
|
||||
@@ -132,4 +135,91 @@ describe('#RawTransactions', () => {
|
||||
// assert.strictEqual(data, result.data)
|
||||
// })
|
||||
})
|
||||
|
||||
describe('#_getInputAddrs', () => {
|
||||
it('should return an array of input addresses', async () => {
|
||||
sandbox
|
||||
.stub(bchjs.RawTransactions, 'getRawTransaction')
|
||||
.resolves(mockData.mockParentTx1)
|
||||
|
||||
const result = await bchjs.RawTransactions._getInputAddrs(mockData.mockTx)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert2.isArray(result)
|
||||
assert2.equal(result.length, 1)
|
||||
assert2.property(result[0], 'vin')
|
||||
assert2.property(result[0], 'address')
|
||||
})
|
||||
|
||||
it('should catch and throw and error', async () => {
|
||||
try {
|
||||
sandbox
|
||||
.stub(bchjs.RawTransactions, 'getRawTransaction')
|
||||
.rejects(new Error('test error'))
|
||||
|
||||
await bchjs.RawTransactions._getInputAddrs(mockData.mockTx)
|
||||
|
||||
assert.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
|
||||
assert2.equal(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getTxData', () => {
|
||||
it('should return tx data with input addresses', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(bchjs.RawTransactions, 'getRawTransaction')
|
||||
.resolves(mockData.mockTx)
|
||||
sandbox
|
||||
.stub(bchjs.RawTransactions, '_getInputAddrs')
|
||||
.resolves(mockData.mockGetInputAddrsOutput)
|
||||
|
||||
const txid =
|
||||
'05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
|
||||
|
||||
const result = await bchjs.RawTransactions.getTxData(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert2.property(result.vin[0], 'address')
|
||||
})
|
||||
|
||||
it('should throw an error for a non-txid input', async () => {
|
||||
try {
|
||||
await bchjs.RawTransactions.getTxData(1234)
|
||||
|
||||
assert.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
|
||||
assert2.include(
|
||||
err.message,
|
||||
'Input to raw-transaction.js/getTxData() must be a string containg a TXID.'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
// Force a network error.
|
||||
sandbox
|
||||
.stub(bchjs.RawTransactions, 'getRawTransaction')
|
||||
.rejects(new Error('test error'))
|
||||
|
||||
const txid =
|
||||
'05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
|
||||
|
||||
await bchjs.RawTransactions.getTxData(txid)
|
||||
|
||||
assert.fail('Unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
|
||||
assert2.equal(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
+93
-2
@@ -4,7 +4,7 @@
|
||||
|
||||
const assert = require('chai').assert
|
||||
const sinon = require('sinon')
|
||||
// const axios = require("axios")
|
||||
const axios = require('axios')
|
||||
|
||||
// Default to unit tests unless some other value for TEST is passed.
|
||||
if (!process.env.TEST) process.env.TEST = 'unit'
|
||||
@@ -14,7 +14,7 @@ const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
// Mock data used for unit tests
|
||||
// const mockData = require("./fixtures/slp/mock-utils")
|
||||
const mockData = require('./fixtures/slp/mock-utils')
|
||||
|
||||
// Default to unit tests unless some other value for TEST is passed.
|
||||
if (!process.env.TEST) process.env.TEST = 'unit'
|
||||
@@ -253,4 +253,95 @@ describe('#SLP NFT1', () => {
|
||||
assert.isNumber(result.outputs)
|
||||
})
|
||||
})
|
||||
describe('#listNFTGroupChildren', () => {
|
||||
it('should throw an error for improper input', async () => {
|
||||
try {
|
||||
const groupId = 12345
|
||||
|
||||
await bchjs.SLP.NFT1.listNFTGroupChildren(groupId)
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
'groupId must be a string'
|
||||
)
|
||||
}
|
||||
})
|
||||
it('should handle API response error', async () => {
|
||||
try {
|
||||
const error = new Error()
|
||||
error.response = {
|
||||
error: 'NFT group does not exists'
|
||||
}
|
||||
sandbox.stub(axios, 'get').throws(error)
|
||||
|
||||
const groupId = 'non-exists'
|
||||
await bchjs.SLP.NFT1.listNFTGroupChildren(groupId)
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.response,
|
||||
{ error: 'NFT group does not exists' }
|
||||
)
|
||||
}
|
||||
})
|
||||
it('should return array of children GENESIS transactions IDs', async () => {
|
||||
sandbox.stub(axios, 'get').resolves({ data: mockData.mockNftChildrenList })
|
||||
|
||||
const groupId = '68cd33ecd909068fbea318ae5ff1d6207cf754e53b191327d6d73b6916424c0a'
|
||||
const result = await bchjs.SLP.NFT1.listNFTGroupChildren(groupId)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, 'nftChildren')
|
||||
assert.isArray(result.nftChildren)
|
||||
})
|
||||
})
|
||||
describe('#parentNFTGroup', () => {
|
||||
it('should throw an error for improper input', async () => {
|
||||
try {
|
||||
const tokenId = 12345
|
||||
|
||||
await bchjs.SLP.NFT1.parentNFTGroup(tokenId)
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
// console.log(`err: `, err)
|
||||
assert.include(
|
||||
err.message,
|
||||
'tokenId must be a string'
|
||||
)
|
||||
}
|
||||
})
|
||||
it('should handle API response error', async () => {
|
||||
try {
|
||||
const error = new Error()
|
||||
error.response = {
|
||||
error: 'NFT child does not exists'
|
||||
}
|
||||
sandbox.stub(axios, 'get').throws(error)
|
||||
|
||||
const tokenId = 'non-exists'
|
||||
await bchjs.SLP.NFT1.parentNFTGroup(tokenId)
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.response,
|
||||
{ error: 'NFT child does not exists' }
|
||||
)
|
||||
}
|
||||
})
|
||||
it('should return parent NFT group information', async () => {
|
||||
sandbox.stub(axios, 'get').resolves({ data: mockData.mockNftGroup })
|
||||
|
||||
const tokenId = '45a30085691d6ea586e3ec2aa9122e9b0e0d6c3c1fd357decccc15d8efde48a9'
|
||||
const result = await bchjs.SLP.NFT1.parentNFTGroup(tokenId)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, 'nftGroup')
|
||||
assert.property(result.nftGroup, 'id')
|
||||
assert.property(result.nftGroup, 'name')
|
||||
assert.property(result.nftGroup, 'symbol')
|
||||
assert.property(result.nftGroup, 'documentUri')
|
||||
assert.property(result.nftGroup, 'versionType')
|
||||
assert.property(result.nftGroup, 'initialTokenQty')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
+535
-288
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
Unit tests for the transaction.js library.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
const assert = require('chai').assert
|
||||
const sinon = require('sinon')
|
||||
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
const mockData = require('./fixtures/transaction-mock.js')
|
||||
|
||||
describe('#TransactionLib', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#get', () => {
|
||||
it('should throw an error if txid is not specified', async () => {
|
||||
try {
|
||||
await bchjs.Transaction.get()
|
||||
|
||||
assert.fail('Unexpected code path!')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Input to Transaction.get() must be a string containing a TXID.'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should get details about a non-SLP transaction', async () => {
|
||||
const txid =
|
||||
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7'
|
||||
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
||||
.resolves(mockData.nonSlpTxDetails)
|
||||
|
||||
const result = await bchjs.Transaction.get(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
// Assert that there are stanardized properties.
|
||||
assert.property(result, 'txid')
|
||||
assert.property(result, 'vin')
|
||||
assert.property(result, 'vout')
|
||||
assert.property(result.vout[0], 'value')
|
||||
assert.property(result.vout[0].scriptPubKey, 'addresses')
|
||||
|
||||
// Assert that added properties exist.
|
||||
assert.property(result.vin[0], 'address')
|
||||
assert.property(result.vin[0], 'value')
|
||||
assert.property(result, 'isValidSLPTx')
|
||||
assert.equal(result.isValidSLPTx, false)
|
||||
})
|
||||
|
||||
it('should get details about a SLP transaction', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
||||
.resolves(mockData.slpTxDetails)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'decodeOpReturn')
|
||||
.onCall(0)
|
||||
.resolves(mockData.mockOpReturnData01)
|
||||
.onCall(1)
|
||||
.resolves(mockData.mockOpReturnData02)
|
||||
.onCall(2)
|
||||
.resolves(mockData.mockOpReturnData03)
|
||||
.onCall(3)
|
||||
.rejects(new Error('No OP_RETURN'))
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'waterfallValidateTxid')
|
||||
.resolves(true)
|
||||
|
||||
const txid =
|
||||
'266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1'
|
||||
|
||||
const result = await bchjs.Transaction.get(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
// Assert that there are stanardized properties.
|
||||
assert.property(result, 'txid')
|
||||
assert.property(result, 'vin')
|
||||
assert.property(result, 'vout')
|
||||
assert.property(result.vout[0], 'value')
|
||||
assert.property(result.vout[1].scriptPubKey, 'addresses')
|
||||
|
||||
// Assert that added properties exist.
|
||||
assert.property(result.vout[0], 'tokenQty')
|
||||
assert.equal(result.vout[0].tokenQty, null)
|
||||
assert.property(result.vin[0], 'address')
|
||||
assert.property(result.vin[0], 'value')
|
||||
assert.property(result.vin[0], 'tokenQty')
|
||||
assert.property(result, 'isValidSLPTx')
|
||||
assert.equal(result.isValidSLPTx, true)
|
||||
})
|
||||
|
||||
it('should catch and throw error on network error', async () => {
|
||||
try {
|
||||
const txid =
|
||||
'2b37bdb3b63dd0bca720437754a36671431a950e684b64c44ea910ea9d5297c7'
|
||||
|
||||
// Force an error
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
||||
.rejects(new Error('test error'))
|
||||
|
||||
await bchjs.Transaction.get(txid)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
|
||||
// This test case was created in response to a bug. When the input TX
|
||||
// was a Genesis SLP transaction, the inputs of the transaction were not
|
||||
// being hydrated properly.
|
||||
it('should get input details when input is a genesis tx', async () => {
|
||||
// Mock dependencies
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
|
||||
.resolves(mockData.genesisTestInputTx)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'decodeOpReturn')
|
||||
.onCall(0)
|
||||
.resolves(mockData.genesisTestOpReturnData01)
|
||||
.onCall(1)
|
||||
.resolves(mockData.genesisTestOpReturnData02)
|
||||
.onCall(2)
|
||||
.resolves(mockData.genesisTestOpReturnData02)
|
||||
.onCall(3)
|
||||
.resolves(mockData.genesisTestOpReturnData02)
|
||||
sandbox
|
||||
.stub(bchjs.Transaction.slpUtils, 'waterfallValidateTxid')
|
||||
.resolves(true)
|
||||
|
||||
const txid =
|
||||
'874306bda204d3a5dd15e03ea5732cccdca4c33a52df35162cdd64e30ea7f04e'
|
||||
|
||||
const result = await bchjs.Transaction.get(txid)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
// Assert that there are stanardized properties.
|
||||
assert.property(result, 'txid')
|
||||
assert.property(result, 'vin')
|
||||
assert.property(result, 'vout')
|
||||
assert.property(result.vout[0], 'value')
|
||||
assert.property(result.vout[1].scriptPubKey, 'addresses')
|
||||
|
||||
// Assert that added properties exist.
|
||||
assert.property(result.vout[0], 'tokenQty')
|
||||
assert.equal(result.vout[0].tokenQty, null)
|
||||
assert.property(result.vin[0], 'address')
|
||||
assert.property(result.vin[0], 'value')
|
||||
assert.property(result.vin[0], 'tokenQty')
|
||||
assert.property(result, 'isValidSLPTx')
|
||||
assert.equal(result.isValidSLPTx, true)
|
||||
|
||||
// Assert inputs values unique to a Genesis input have the proper values.
|
||||
assert.equal(result.vin[0].tokenQty, 10000000)
|
||||
assert.equal(result.vin[1].tokenQty, null)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,5 @@
|
||||
const assert = require('assert')
|
||||
const assert2 = require('chai').assert
|
||||
const axios = require('axios')
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
@@ -32,4 +33,143 @@ describe('#Util', () => {
|
||||
.then(done, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#floor8', () => {
|
||||
it('should floor a number to 8 decimals', () => {
|
||||
const num = 1.234567891111
|
||||
|
||||
const result = bchjs.Util.floor8(num)
|
||||
// console.log(result)
|
||||
|
||||
assert2.equal(result, 1.23456789)
|
||||
})
|
||||
|
||||
it('should throw an error for non-number input', () => {
|
||||
try {
|
||||
const num = 'string'
|
||||
|
||||
bchjs.Util.floor8(num)
|
||||
|
||||
assert2.equal(true, false, 'Unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert2.include(err.message, 'input must be a number')
|
||||
}
|
||||
})
|
||||
|
||||
it('should not effect a number with less than 8 decimals', () => {
|
||||
const num = 1.23
|
||||
|
||||
const result = bchjs.Util.floor8(num)
|
||||
// console.log(result)
|
||||
|
||||
assert2.equal(result, 1.23)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#floor2', () => {
|
||||
it('should round a number to 2 decimals', () => {
|
||||
const num = 1.234567891111
|
||||
|
||||
const result = bchjs.Util.floor2(num)
|
||||
// console.log(result)
|
||||
|
||||
assert2.equal(result, 1.23)
|
||||
})
|
||||
|
||||
it('should throw an error for non-number input', () => {
|
||||
try {
|
||||
const num = 'string'
|
||||
|
||||
bchjs.Util.floor2(num)
|
||||
|
||||
assert2.equal(true, false, 'Unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert2.include(err.message, 'input must be a number')
|
||||
}
|
||||
})
|
||||
|
||||
it('should not effect a number with less than 8 decimals', () => {
|
||||
const num = 1.2
|
||||
|
||||
const result = bchjs.Util.floor2(num)
|
||||
// console.log(result)
|
||||
|
||||
assert2.equal(result, 1.2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#chunk20', () => {
|
||||
const thirtyFiveElements = [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
31,
|
||||
32,
|
||||
33,
|
||||
34
|
||||
]
|
||||
|
||||
it('should split 35 elements into 2 arrays', () => {
|
||||
const result = bchjs.Util.chunk20(thirtyFiveElements)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert2.isArray(result)
|
||||
assert2.isArray(result[0])
|
||||
assert2.equal(result.length, 2)
|
||||
assert2.equal(result[0].length, 20)
|
||||
})
|
||||
|
||||
it('should return accurately with an array of less than 20 elements', () => {
|
||||
const elems = [0, 1, 2, 3, 4, 5]
|
||||
|
||||
const result = bchjs.Util.chunk20(elems)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert2.isArray(result)
|
||||
assert2.isArray(result[0])
|
||||
assert2.equal(result.length, 1)
|
||||
assert2.equal(result[0].length, 6)
|
||||
})
|
||||
|
||||
it('should throw an error for non-array input', () => {
|
||||
try {
|
||||
bchjs.Util.chunk20('string')
|
||||
|
||||
assert2.equal(true, false, 'Unexpected result')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert2.include(err.message, 'input must be an array')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
Unit tests for the utxo.js library.
|
||||
*/
|
||||
|
||||
const sinon = require('sinon')
|
||||
const assert = require('chai').assert
|
||||
|
||||
const BCHJS = require('../../src/bch-js')
|
||||
const bchjs = new BCHJS()
|
||||
|
||||
const mockData = require('./fixtures/utxo-mocks')
|
||||
|
||||
describe('#utxo', () => {
|
||||
let sandbox
|
||||
beforeEach(() => (sandbox = sinon.createSandbox()))
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#get', () => {
|
||||
it('should get hydrated and filtered UTXOs for an address', async () => {
|
||||
// Mock dependencies.
|
||||
sandbox.stub(bchjs.Utxo.electrumx, 'utxo').resolves(mockData.mockUtxoData)
|
||||
sandbox
|
||||
.stub(bchjs.Utxo.slp.Utils, 'hydrateUtxos')
|
||||
.resolves(mockData.mockHydratedUtxos)
|
||||
|
||||
const addr = 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
||||
|
||||
const result = await bchjs.Utxo.get(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
})
|
||||
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
// Force an error
|
||||
sandbox
|
||||
.stub(bchjs.Utxo.electrumx, 'utxo')
|
||||
.rejects(new Error('test error'))
|
||||
|
||||
const addr = 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
||||
|
||||
await bchjs.Utxo.get(addr)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle an array of addresses', async () => {
|
||||
// Mock dependencies.
|
||||
sandbox.stub(bchjs.Utxo.electrumx, 'utxo').resolves({ utxos: {} })
|
||||
sandbox
|
||||
.stub(bchjs.Utxo.slp.Utils, 'hydrateUtxos')
|
||||
.resolves(mockData.mockTwoHydratedAddrs)
|
||||
|
||||
const addr = [
|
||||
'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9',
|
||||
'bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9'
|
||||
]
|
||||
|
||||
const result = await bchjs.Utxo.get(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.equal(result.length, 2)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
})
|
||||
|
||||
it('should throw an error for array of 21 elements', async () => {
|
||||
try {
|
||||
const addr = 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
||||
|
||||
const addrs = []
|
||||
for (let i = 0; i < 21; i++) {
|
||||
addrs.push(addr)
|
||||
}
|
||||
|
||||
await bchjs.Utxo.get(addrs)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Too many elements, 20 max.')
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle NFTs and minting batons', async () => {
|
||||
// Mock dependencies.
|
||||
sandbox.stub(bchjs.Utxo.electrumx, 'utxo').resolves({ utxos: {} })
|
||||
sandbox
|
||||
.stub(bchjs.Utxo.slp.Utils, 'hydrateUtxos')
|
||||
.resolves(mockData.mockEveryUtxoType)
|
||||
|
||||
const addr = 'simpleledger:qrm0c67wwqh0w7wjxua2gdt2xggnm90xwsr5k22euj'
|
||||
|
||||
const result = await bchjs.Utxo.get(addr)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
|
||||
assert.isArray(result[0].slpUtxos.type1.mintBatons)
|
||||
assert.isArray(result[0].slpUtxos.type1.tokens)
|
||||
assert.isArray(result[0].slpUtxos.nft.groupMintBatons)
|
||||
assert.isArray(result[0].slpUtxos.nft.groupTokens)
|
||||
assert.isArray(result[0].slpUtxos.nft.tokens)
|
||||
})
|
||||
|
||||
it('should use the whitelist when flag is set', async () => {
|
||||
// Mock dependencies.
|
||||
sandbox.stub(bchjs.Utxo.electrumx, 'utxo').resolves(mockData.mockUtxoData)
|
||||
sandbox
|
||||
.stub(bchjs.Utxo.slp.Utils, 'hydrateUtxosWL')
|
||||
.resolves(mockData.mockHydratedUtxos)
|
||||
|
||||
const addr = 'simpleledger:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvyucjzqt9'
|
||||
const useWhitelist = true
|
||||
|
||||
const result = await bchjs.Utxo.get(addr, useWhitelist)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.isArray(result)
|
||||
assert.property(result[0], 'address')
|
||||
assert.property(result[0], 'bchUtxos')
|
||||
assert.property(result[0], 'nullUtxos')
|
||||
assert.property(result[0], 'slpUtxos')
|
||||
assert.isArray(result[0].bchUtxos)
|
||||
assert.isArray(result[0].nullUtxos)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#findBiggestUtxo', () => {
|
||||
it('should throw error for non-array input', async () => {
|
||||
try {
|
||||
await bchjs.Utxo.findBiggestUtxo({})
|
||||
|
||||
assert.equal(true, false, 'Unexpected result!')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'utxos input to findBiggestUtxo() must be an array'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if input does not have a value or satoshis property', async () => {
|
||||
try {
|
||||
const badUtxos = [
|
||||
{
|
||||
height: 0,
|
||||
tx_hash:
|
||||
'192f5037bb3822afd92d6b6ab51842a5dcfbe6bff783290057342da1f27ed414',
|
||||
tx_pos: 0
|
||||
}
|
||||
]
|
||||
|
||||
await bchjs.Utxo.findBiggestUtxo(badUtxos)
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'UTXOs require a satoshis or value property for findBiggestUtxo()'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should sort UTXOs from Electrumx', async () => {
|
||||
const result = bchjs.Utxo.findBiggestUtxo(mockData.electrumxUtxos.utxos)
|
||||
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
||||
|
||||
assert.property(result, 'satoshis')
|
||||
assert.equal(result.satoshis, 800)
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user