Compare commits

...
72 Commits
Author SHA1 Message Date
Chris Troutner 52c1ebdafe Merge pull request #182 from Permissionless-Software-Foundation/ct-unstable
fix(Transaction.get()): Fixing bug in previous PR
2021-10-21 19:45:36 -07:00
Chris Troutner 2e56d66f48 fix(Transaction.get()): Fixing bug in previous PR 2021-10-21 19:42:12 -07:00
Chris Troutner 9cf6c7e7a7 Merge pull request #181 from Permissionless-Software-Foundation/ct-unstable
fix(Transaction.get()): Adding support for MINT corner-case
2021-10-21 19:15:08 -07:00
Chris Troutner 43043672c6 linting 2021-10-21 19:12:10 -07:00
Chris Troutner 4f4b2c864d fix(Transaction.get()): Adding support for MINT corner-case 2021-10-21 19:11:55 -07:00
Chris Troutner 951fea8f9b Merge pull request #180 from Permissionless-Software-Foundation/ct-unstable
fix(npm): Ran npm audit fix, to fix vulns
2021-10-16 09:49:50 -07:00
Chris Troutner 6d75dceffb fix(npm): Ran npm audit fix, to fix vulns 2021-10-16 09:46:55 -07:00
Chris Troutner 3a491c7aba Merge pull request #178 from Permissionless-Software-Foundation/ct-unstable
fix(generateGenesisOpReturn): Fixing bug when 0 decimal
2021-10-14 13:08:31 -07:00
Chris Troutner f03c020e4f fix(generateGenesisOpReturn): Fixing bug when 0 decimal 2021-10-14 13:06:15 -07:00
Chris Troutner 4aeb1148e5 Merge pull request #177 from Permissionless-Software-Foundation/review01
added toEcashAddress() & ecashtoCashAddress() for ecash format support
2021-10-04 07:55:41 -07:00
Chris Troutner f03ee13a1e Merge pull request #175 from mr-zwets/master
conversion between bitcoincash: and ecash:
2021-10-04 06:55:48 -07:00
mr-zwets cb98773d6a Merge branch 'Permissionless-Software-Foundation:master' into master 2021-09-23 07:43:07 +02:00
Chris Troutner c593d68ee5 Merge pull request #176 from Permissionless-Software-Foundation/ct-unstable
Improvements to Transaction.get()
2021-09-22 17:36:30 -07:00
Chris Troutner dc7d3a9339 fix(Transaction.get): Using BigNumber for better tokenqty calc 2021-09-22 17:33:27 -07:00
Chris Troutner 6f4cc0f439 fix(Transaction.get): Fixed bug when Genesis TX was input to queried TX 2021-09-22 16:58:14 -07:00
Chris Troutner 7aa0fa865e fix(decodeOpReturn): Fixed api docs 2021-09-22 15:40:23 -07:00
mathi e8b6d7fb36 added toEcashAddress() & ecashtoCashAddress() for ecash format support 2021-09-22 14:38:54 +02:00
Chris Troutner b13ef94ea3 Merge pull request #174 from Permissionless-Software-Foundation/ct-unstable
fix(npm): Ran npm audit fix, 0 vulns
2021-09-20 16:07:18 -07:00
Chris Troutner 912f899f4e fix(npm): Ran npm audit fix, 0 vulns 2021-09-20 16:04:14 -07:00
Chris Troutner 9063d8da0b Merge pull request #173 from Permissionless-Software-Foundation/feat/ecash-price
Feat/ecash price
2021-09-20 16:00:32 -07:00
Chris Troutner f4e2bd96f0 fix(XEC price): Fixing BCHA XEC price feeds 2021-09-20 15:56:42 -07:00
Chris Troutner 1c898a4ad3 Removing ninsight from integration tests 2021-09-20 15:54:54 -07:00
Chris Troutner c4db813f76 Merge pull request #172 from mr-zwets/master
changed getBchaUsd which returns the price for the BCHA denomination, added getXecUsd for the XEC denomination
2021-09-20 15:33:30 -07:00
mathi 38b96b441f changed getBchaUsd so it returns the BCHA denomination, added getXecUsd 2021-09-20 22:13:24 +02:00
Chris Troutner c94f78f510 Merge pull request #170 from Permissionless-Software-Foundation/ct-unstable
fix(minimal-slp-wallet): Fixed code that was breaking minimal-slp-wal…
2021-08-12 09:16:52 -07:00
Chris Troutner 6de2b712ec fix(minimal-slp-wallet): Fixed code that was breaking minimal-slp-wallet build 2021-08-12 09:14:29 -07:00
Chris Troutner 6f681fd7b0 Merge pull request #169 from Permissionless-Software-Foundation/ct-unstable
fix(npm): Ran npm audit fix. 0 vulns
2021-08-09 17:59:43 -07:00
Chris Troutner 9a82effb2b fix(npm): Ran npm audit fix. 0 vulns 2021-08-09 17:41:38 -07:00
Chris Troutner 955a5e428e Merge pull request #168 from Permissionless-Software-Foundation/ct-unstable
fix(getRawTransaction): Fixing integration test
2021-08-09 14:56:52 -07:00
Chris Troutner 44c3bf44f9 fix(getRawTransaction): Fixing integration test 2021-08-09 14:54:49 -07:00
Chris Troutner 31ce84abb0 Merge pull request #167 from Permissionless-Software-Foundation/ct-unstable
fix(waterfallValidateTxid): Skipping validateTxid3() if it throws an error
2021-08-09 10:39:18 -07:00
Chris Troutner 40fa4b6bc1 linting 2021-08-09 10:36:07 -07:00
Chris Troutner 8c5e111d60 fix(waterfallValidateTxid): Skipping validateTxid3() if it throws an error 2021-08-09 10:35:51 -07:00
Chris Troutner 8965dfc57f Merge pull request #166 from Permissionless-Software-Foundation/ct-unstable
fix(apiToken): Changed _this.axiosOptions to this.axiosOptions
2021-08-08 20:06:05 -07:00
Chris Troutner 93904a632f fix(apiToken): Changed _this.axiosOptions to this.axiosOptions 2021-08-08 20:01:38 -07:00
Chris Troutner 851d4c404c fix(rate limits): Fixing more bugs with rate limit handling axios.options 2021-08-08 19:51:01 -07:00
Chris Troutner 44bac45c32 Updating README 2021-08-08 18:42:04 -07:00
Chris Troutner 95ee8054be Merge pull request #165 from Permissionless-Software-Foundation/ct-unstable
fix(Transactions.get()): Adding extra error handling for rate limits
2021-08-08 18:40:43 -07:00
Chris Troutner 547b28cac8 fix(Transactions.get()): Adding extra error handling for rate limits 2021-08-08 18:38:46 -07:00
Chris Troutner 40ba334a41 Merge pull request #163 from Permissionless-Software-Foundation/ct-unstable
fix(validateTxid3): Throwing an error when rate limit encountered.
2021-08-08 18:06:52 -07:00
Chris Troutner ffd8ccaf2b fix(validateTxid3): Throwing an error when rate limit encountered. 2021-08-08 18:04:39 -07:00
Chris Troutner 9a16c0c6d6 Merge pull request #162 from Permissionless-Software-Foundation/ct-unstable
fix(raw-transaction): Fixing JWT token bug
2021-08-07 12:48:00 -07:00
Chris Troutner 52a891fd78 fix(raw-transaction): Fixing JWT token bug 2021-08-07 12:41:24 -07:00
Chris Troutner c09df08429 fix(npm): Ran npm audit fix 2021-07-16 15:56:36 -07:00
Chris Troutner 4dc88c0af3 Merge pull request #160 from Permissionless-Software-Foundation/ct-unstable
fix(transactions): Adding better error messages
2021-07-16 15:20:12 -07:00
Chris Troutner 85caa9556b fix(transactions): Adding better error messages 2021-07-16 15:18:35 -07:00
Chris Troutner bbdc417eb2 Merge pull request #159 from Permissionless-Software-Foundation/ct-unstable
Updating README
2021-07-12 19:57:47 -07:00
Chris Troutner cc3bc002e7 Updating README 2021-07-12 19:52:29 -07:00
Chris Troutner a75e1ab633 Merge pull request #158 from Permissionless-Software-Foundation/ct-unstable
fix(dsproof): Adding documentation
2021-06-22 15:49:17 -07:00
Chris Troutner 8c5f1e2274 fix(dsproof): Adding documentation 2021-06-22 15:47:22 -07:00
Chris Troutner c30e76c942 Merge pull request #157 from Permissionless-Software-Foundation/dh-dsproof
feat(DSProof): Added DSProof to bch-js
2021-06-22 12:28:40 -07:00
Chris Troutner a575621c50 Fixing ABC integration tests 2021-06-22 12:24:29 -07:00
Daniel Gonzalez d3a0c5948a feat(DSProof): Added DSProof to bch-js 2021-06-19 22:40:16 -04:00
Chris Troutner 61bb509195 Merge pull request #156 from Permissionless-Software-Foundation/ct-unstable
fix(raw-transactions): Adding better error handling for rate-limits
2021-06-19 10:43:24 -07:00
Chris Troutner a18e549694 fix(raw-transactions): Adding better error handling for rate-limits 2021-06-19 10:41:49 -07:00
Chris Troutner 7d53f47d8a Merge pull request #155 from Permissionless-Software-Foundation/ct-unstable
fix(error): Adding additional rate limit error handling
2021-06-19 10:09:51 -07:00
Chris Troutner e8e615795d fix(error): Adding additional rate limit error handling 2021-06-19 10:08:28 -07:00
Chris Troutner 5759b096d5 Merge pull request #153 from Permissionless-Software-Foundation/ct-unstable
fix(errors): Throwing rate limit errors as Error objects
2021-06-19 09:44:11 -07:00
Chris Troutner 5b300f68b2 fix(errors): Throwing rate limit errors as Error objects 2021-06-19 09:42:36 -07:00
Chris Troutner 3cce6f9754 Merge pull request #152 from Permissionless-Software-Foundation/ct-unstable
fix(testnet): Fixing testnet integration test
2021-06-18 09:43:06 -07:00
Chris Troutner 3da04d9327 fix(testnet): Fixing testnet integration test 2021-06-18 09:32:07 -07:00
Chris Troutner 79091815a2 Merge pull request #151 from Permissionless-Software-Foundation/ct-unstable
fix(Electrumx): Fixing integration test
2021-06-17 07:19:55 -07:00
Chris Troutner 258144d26d fix(Electrumx): Fixing integration test 2021-06-17 07:16:48 -07:00
Chris Troutner 4c4a45841b Merge pull request #150 from Permissionless-Software-Foundation/ct-unstable
fix(package.json): Using /v5 in npm scripts
2021-06-16 19:17:14 -07:00
Chris Troutner 010afd10a3 Merge branch 'master' into ct-unstable 2021-06-16 19:13:03 -07:00
Chris Troutner 82b4d2ab9e fix(package.json): Using /v5 in npm scripts 2021-06-16 19:12:48 -07:00
Chris Troutner 8eb6a21dc2 Merge pull request #149 from Permissionless-Software-Foundation/ct-unstable
feat(/v5 REST API): Using the new v5 route in bch-api
2021-06-16 19:03:45 -07:00
Chris Troutner 5f2a762d4f feat(/v5 REST API): Using the new v5 route in bch-api 2021-06-16 17:00:08 -07:00
Chris Troutner 24e2c78d03 Merge pull request #148 from Permissionless-Software-Foundation/ct-unstable
fix(testnet): Removing testnet ninsight tests as they rarely pass
2021-05-22 07:58:39 -07:00
Chris Troutner eab02fdbc9 fix(testnet): Removing testnet ninsight tests as they rarely pass 2021-05-22 07:55:02 -07:00
Chris Troutner f7bd9c75db Merge pull request #147 from Permissionless-Software-Foundation/ct-unstable
fix(nft docs): Fixing a typo in docs
2021-05-21 15:54:07 -07:00
Chris Troutner 2a96f3a4f5 fix(nft docs): Fixing a typo in docs 2021-05-21 15:51:43 -07:00
52 changed files with 5729 additions and 8871 deletions
+3 -7
View File
@@ -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.
})
```
+4677 -8329
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -11,19 +11,19 @@
"scripts": {
"test": "nyc mocha --trace-warnings --unhandled-rejections=strict --timeout 30000 test/unit/",
"test:integration": "npm run test:integration:bchn",
"test:integration:nft": "export RESTURL=https://bchn.fullstack.cash/v4/ && 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/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:abc": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
"test:integration:local:bchn": "export 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/chains/testnet",
"test:integration:decatur:bchn": "export RESTURL=http://192.168.0.36:3000/v4/ && mocha --timeout 30000 test/integration/",
"test:integration:temp:bchn": "export RESTURL=http://157.90.174.219:3000/v4/ && mocha --timeout 30000 test/integration/",
"test:temp": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 -g '#Encryption' test/integration/",
"test:integration:local:abc": "export RESTURL=http://localhost:3000/v5/ && mocha --timeout 30000 test/integration && mocha --timeout 30000 test/integration/chains/abc/",
"test:integration:local: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/v4/ && mocha --timeout 30000 -g '#Transaction' test/integration/",
"test:temp4": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 -g '#decodeOpReturn' test/integration/",
"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",
@@ -54,7 +54,7 @@
"bip66": "^1.1.5",
"bitcoinjs-message": "^2.0.0",
"bs58": "^4.0.1",
"cashaddrjs": "^0.3.3",
"ecashaddrjs": "^1.0.7",
"ini": "^1.3.8",
"randombytes": "^2.0.6",
"safe-buffer": "^5.1.2",
@@ -76,9 +76,9 @@
"eslint-plugin-standard": "^4.0.0",
"husky": "^4.3.6",
"lodash.clonedeep": "^4.5.0",
"mocha": "^6.1.4",
"mocha": "^9.1.3",
"node-mocks-http": "^1.7.0",
"nyc": "^14.1.0",
"nyc": "^15.1.0",
"prettier": "^1.18.2",
"semantic-release": "^17.3.9",
"sinon": "^7.3.2",
+75 -2
View File
@@ -1,12 +1,12 @@
// const axios = require("axios")
const Bitcoin = require('@psf/bitcoincashjs-lib')
const cashaddr = require('cashaddrjs')
const cashaddr = require('ecashaddrjs')
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
@@ -129,6 +129,63 @@ class Address {
return cashAddress.split(':')[1]
}
/**
* @api Address.toEcashAddress() toEcashAddress()
* @apiName toEcashAddress
* @apiGroup Address
* @apiDescription Convert legacy to cashAddress format
*
* @apiExample Example usage:
* // mainnet
* bchjs.Address.toEcashAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2')
* // ecash:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
*
* // mainnet no prefix
* bchjs.Address.toEcashAddress('bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2', false)
* // qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da
*
*/
toEcashAddress (address, prefix = true) {
const decoded = this._decode(address)
const ecashAddress = cashaddr.encode(
'ecash',
decoded.type,
decoded.hash
)
if (prefix) return ecashAddress
return ecashAddress.split(':')[1]
}
/**
* @api Address.ecashtoCashAddress() ecashtoCashAddress()
* @apiName ecashtoCashAddress
* @apiGroup Address
* @apiDescription Convert legacy to cashAddress format
*
* @apiExample Example usage:
* // mainnet
* bchjs.Address.ecashtoCashAddress('ecash:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da')
* // bitcoincash:qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2
*
* // mainnet no prefix
* bchjs.Address.ecashtoCashAddress('ecash:qq50d800hgunr8u4trz3uuppspk3mds0dyug2v69da', false)
* // qq50d800hgunr8u4trz3uuppspk3mds0dy9978plt2
*/
ecashtoCashAddress (address, prefix = true) {
const decoded = this._decodeEcashAddress(address)
const cashAddress = cashaddr.encode(
'bitcoincash',
decoded.type,
decoded.hash
)
if (prefix) return cashAddress
return cashAddress.split(':')[1]
}
// Converts any address format to hash160
toHash160 (address) {
const legacyAddress = this.toLegacyAddress(address)
@@ -271,6 +328,22 @@ class Address {
throw new Error(`Invalid format : ${address}`)
}
_decodeEcashAddress (address) {
if (address.indexOf(':') !== -1) {
const decoded = cashaddr.decode(address)
decoded.format = 'cashaddr'
return decoded
}
try {
const decoded = cashaddr.decode(`ecash:${address}`)
decoded.format = 'cashaddr'
return decoded
} catch (error) {}
throw new Error(`Invalid format : ${address}`)
}
/**
* @api Address.isLegacyAddress() isLegacyAddress()
* @apiName isLegacyAddress
+5 -2
View File
@@ -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')
@@ -32,6 +32,7 @@ const IPFS = require('./ipfs')
const Encryption = require('./encryption')
const Utxo = require('./utxo')
const Transaction = require('./transaction')
const DSProof = require('./dsproof')
// Indexers
const Ninsight = require('./ninsight')
@@ -115,6 +116,8 @@ class BCHJS {
this.IPFS = new IPFS()
this.Utxo = new Utxo(libConfig)
this.Transaction = new Transaction(libConfig)
this.DSProof = new DSProof(libConfig)
}
}
+26 -26
View File
@@ -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) {
@@ -112,7 +112,7 @@ class Blockchain {
blockhash,
verbosity
},
_this.axiosOptions
this.axiosOptions
)
return response.data
} catch (error) {
@@ -162,7 +162,7 @@ class Blockchain {
try {
const response = await axios.get(
`${this.restURL}blockchain/getBlockchainInfo`,
_this.axiosOptions
this.axiosOptions
)
return response.data
} catch (error) {
@@ -193,7 +193,7 @@ class Blockchain {
try {
const response = await axios.get(
`${this.restURL}blockchain/getBlockCount`,
_this.axiosOptions
this.axiosOptions
)
return response.data
} catch (error) {
@@ -226,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) {
@@ -273,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
@@ -287,7 +287,7 @@ class Blockchain {
hashes: hash,
verbose: verbose
},
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -334,7 +334,7 @@ class Blockchain {
try {
const response = await axios.get(
`${this.restURL}blockchain/getChainTips`,
_this.axiosOptions
this.axiosOptions
)
return response.data
} catch (error) {
@@ -366,7 +366,7 @@ class Blockchain {
try {
const response = await axios.get(
`${this.restURL}blockchain/getDifficulty`,
_this.axiosOptions
this.axiosOptions
)
return response.data
} catch (error) {
@@ -382,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) {
@@ -397,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) {
@@ -494,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
@@ -505,7 +505,7 @@ class Blockchain {
{
txids: txid
},
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -545,7 +545,7 @@ class Blockchain {
try {
const response = await axios.get(
`${this.restURL}blockchain/getMempoolInfo`,
_this.axiosOptions
this.axiosOptions
)
return response.data
} catch (error) {
@@ -592,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) {
@@ -636,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`,
@@ -645,7 +645,7 @@ class Blockchain {
vout: n,
mempool: includeMempool
},
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -698,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.
@@ -709,7 +709,7 @@ class Blockchain {
{
txids: txids
},
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -726,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) {
@@ -739,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) {
@@ -752,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) {
@@ -804,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
@@ -816,7 +816,7 @@ class Blockchain {
{
proofs: proof
},
_this.axiosOptions
this.axiosOptions
)
return response.data
+4 -4
View File
@@ -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) {
+81
View File
@@ -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
+14 -14
View File
@@ -8,7 +8,7 @@ const axios = require('axios')
// Local libraries.
const Blockchain = require('./blockchain')
let _this
// let _this
class ElectrumX {
constructor (config) {
@@ -34,7 +34,7 @@ class ElectrumX {
this.blockchain = new Blockchain(config)
_this = this
// _this = this
}
/**
@@ -108,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
@@ -119,7 +119,7 @@ class ElectrumX {
{
addresses: address
},
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -192,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
@@ -203,7 +203,7 @@ class ElectrumX {
{
addresses: address
},
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -290,7 +290,7 @@ class ElectrumX {
if (typeof address === 'string') {
const response = await axios.get(
`${this.restURL}electrumx/transactions/${address}`,
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -302,7 +302,7 @@ class ElectrumX {
addresses: address,
usrObj // pass user data when making an internal call.
},
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -383,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
@@ -394,7 +394,7 @@ class ElectrumX {
{
addresses: address
},
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -452,7 +452,7 @@ 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) {
@@ -543,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)) {
@@ -552,7 +552,7 @@ class ElectrumX {
{
txids: txid
},
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -592,7 +592,7 @@ class ElectrumX {
const response = await axios.post(
`${this.restURL}electrumx/tx/broadcast`,
{ txHex },
_this.axiosOptions
this.axiosOptions
)
return response.data
+4 -2
View File
@@ -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
View File
@@ -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) {
+6 -6
View File
@@ -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
View File
@@ -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
+48 -9
View File
@@ -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,51 @@ 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)}`)
@@ -181,7 +220,7 @@ class Price {
try {
const response = await this.axios.get(
`${this.restURL}price/bchusd`,
_this.axiosOptions
this.axiosOptions
)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
+51 -21
View File
@@ -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,7 +111,7 @@ class RawTransactions {
data: {
hexes: hex
},
headers: _this.axiosOptions.headers
headers: this.axiosOptions.headers
}
const response = await axios(options)
@@ -120,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
}
}
@@ -165,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
@@ -176,7 +177,7 @@ class RawTransactions {
data: {
hexes: script
},
headers: _this.axiosOptions.headers
headers: this.axiosOptions.headers
}
const response = await axios(options)
@@ -185,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
}
}
@@ -257,9 +259,13 @@ class RawTransactions {
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
@@ -272,7 +278,7 @@ class RawTransactions {
verbose: verbose,
usrObj // pass user data when making an internal call.
},
headers: _this.axiosOptions.headers
headers: this.axiosOptions.headers
}
const response = await axios(options)
@@ -281,8 +287,14 @@ 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
}
}
@@ -307,6 +319,9 @@ class RawTransactions {
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)
@@ -326,8 +341,14 @@ class RawTransactions {
return retArray
} 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
}
}
@@ -361,7 +382,9 @@ class RawTransactions {
async getTxData (txid) {
try {
if (typeof txid !== 'string') {
throw new Error('Input must be a string or array of strings.')
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.
@@ -379,8 +402,14 @@ class RawTransactions {
return txDetails
} 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
}
}
@@ -422,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') {
@@ -443,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
}
}
+8 -8
View File
@@ -17,7 +17,7 @@ const Address = require('./address')
// const BigNumber = require('bignumber.js')
const slpMdm = require('slp-mdm')
let _this
// let _this
// const addy = new Address()
let addy
const TransactionBuilder = require('../transaction-builder')
@@ -31,7 +31,7 @@ class Nft1 {
// Instantiate the transaction builder.
TransactionBuilder.setAddress(addy)
_this = this
// _this = this
}
/**
@@ -421,9 +421,9 @@ class Nft1 {
}
/**
* @api SLP.Nft1.listNFTGroupChildren() listNFTGroupChildren()
* @api SLP.NFT1.listNFTGroupChildren() listNFTGroupChildren()
* @apiName listNFTGroupChildren
* @apiGroup SLP Nft1
* @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)
*
@@ -446,7 +446,7 @@ class Nft1 {
if (typeof groupId === 'string') {
const response = await axios.get(
`${this.restURL}slp/nftChildren/${groupId}`,
_this.axiosOptions
this.axiosOptions
)
return response.data
}
@@ -460,9 +460,9 @@ class Nft1 {
}
/**
* @api SLP.Nft1.parentNFTGroup() parentNFTGroup()
* @api SLP.NFT1.parentNFTGroup() parentNFTGroup()
* @apiName parentNFTGroup
* @apiGroup SLP Nft1
* @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)
*
@@ -498,7 +498,7 @@ class Nft1 {
if (typeof tokenId === 'string') {
const response = await axios.get(
`${this.restURL}slp/nftGroup/${tokenId}`,
_this.axiosOptions
this.axiosOptions
)
return response.data
}
+18 -12
View File
@@ -125,13 +125,13 @@ class TokenType1 {
// 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.
@@ -285,9 +287,15 @@ class TokenType1 {
try {
// TODO: Add input validation.
let baseQty = new BigNumber(configObj.initialQty).times(
10 ** configObj.decimals
)
let baseQty
if (configObj.decimals !== 0) {
baseQty = new BigNumber(configObj.initialQty).times(
10 ** configObj.decimals
)
} else {
baseQty = new BigNumber(configObj.initialQty)
}
baseQty = baseQty.absoluteValue()
baseQty = Math.floor(baseQty)
baseQty = baseQty.toString()
@@ -378,9 +386,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 +460,7 @@ class TokenType1 {
const result = await _this.axios.post(
`${this.restURL}slp/generatesendopreturn`,
data,
_this.axiosOptions
this.axiosOptions
)
const slpSendObj = result.data
+38 -19
View File
@@ -217,14 +217,14 @@ class Utils {
try {
let response
if (method === 'get') {
response = await _this.axios.get(path, _this.axiosOptions)
response = await _this.axios.get(path, this.axiosOptions)
} else {
response = await _this.axios.post(
path,
{
tokenIds: id
},
_this.axiosOptions
this.axiosOptions
)
}
return response.data
@@ -315,7 +315,7 @@ class Utils {
if (typeof address === 'string') {
const path = `${this.restURL}slp/balancesForAddress/${address}`
const response = await _this.axios.get(path, _this.axiosOptions)
const response = await _this.axios.get(path, this.axiosOptions)
return response.data
// Array of addresses.
@@ -328,7 +328,7 @@ class Utils {
{
addresses: address
},
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -380,7 +380,7 @@ class Utils {
try {
const path = `${this.restURL}slp/balancesForToken/${tokenId}`
const response = await _this.axios.get(path, _this.axiosOptions)
const response = await _this.axios.get(path, this.axiosOptions)
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
@@ -450,13 +450,14 @@ class Utils {
else txids = txid
try {
// console.log('validateTxid() this.axiosOptions: ', this.axiosOptions)
const response = await _this.axios.post(
path,
{
txids: txids,
usrObj // pass user data when making an internal call.
},
_this.axiosOptions
this.axiosOptions
)
// console.log(
// `validateTxid response.data: ${JSON.stringify(response.data, null, 2)}`
@@ -520,7 +521,8 @@ class Utils {
const path = `${this.restURL}slp/validateTxid2/${txid}`
const response = await _this.axios.get(path, _this.axiosOptions)
// console.log('validateTxid2() this.axiosOptions: ', this.axiosOptions)
const response = await _this.axios.get(path, this.axiosOptions)
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
@@ -589,7 +591,7 @@ class Utils {
// Retrieve the whitelist from the REST API if we haven't gotten it yet.
if (this.whitelist.length === 0) {
const response = await _this.axios.get(path, _this.axiosOptions)
const response = await _this.axios.get(path, this.axiosOptions)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
this.whitelist = response.data
@@ -666,13 +668,14 @@ class Utils {
else txids = txid
try {
// console.log('validateTxid3() this.axiosOptions: ', this.axiosOptions)
const response = await _this.axios.post(
path,
{
txids: txids,
usrObj // pass user data when making an internal call.
},
_this.axiosOptions
this.axiosOptions
)
// console.log(`response.data: ${JSON.stringify(response.data, null, 2)}`)
@@ -680,6 +683,14 @@ class Utils {
return validatedTxids
} catch (error) {
// console.log('validateTxid3 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)
}
// Not sure if this can be safely deprecated?
if (error.response && error.response.data) throw error.response.data
throw error
}
@@ -724,7 +735,7 @@ class Utils {
try {
const path = `${this.restURL}slp/tokenStats/${tokenId}`
const response = await _this.axios.get(path, _this.axiosOptions)
const response = await _this.axios.get(path, this.axiosOptions)
return response.data
} catch (error) {
@@ -795,7 +806,7 @@ class Utils {
try {
const path = `${this.restURL}slp/transactions/${tokenId}/${address}`
const response = await _this.axios.get(path, _this.axiosOptions)
const response = await _this.axios.get(path, this.axiosOptions)
return response.data
} catch (error) {
@@ -835,7 +846,7 @@ class Utils {
try {
const path = `${this.restURL}slp/burnTotal/${transactionId}`
const response = await _this.axios.get(path, _this.axiosOptions)
const response = await _this.axios.get(path, this.axiosOptions)
return response.data
} catch (error) {
@@ -879,7 +890,7 @@ class Utils {
// console.log(`this.restURL: ${this.restURL}`)
const path = `${this.restURL}slp/txDetails/${txid}`
const response = await _this.axios.get(path, _this.axiosOptions)
const response = await _this.axios.get(path, this.axiosOptions)
return response.data
} catch (error) {
if (error.response && error.response.data) throw error.response.data
@@ -910,7 +921,7 @@ class Utils {
* const txid =
* "266844d53e46bbd7dd37134688dffea6e54d944edff27a0add63dd0908839bc1"
*
* const data = await slp.Utils.decodeOpReturn2(txid)
* const data = await bchjs.SLP.Utils.decodeOpReturn(txid)
*
* console.log(`Decoded OP_RETURN data: ${JSON.stringify(data,null,2)}`)
* } catch (error) {
@@ -959,14 +970,15 @@ class Utils {
// CT: 2/24/21 Deprected GET in favor of POST, to pass IP address.
// Retrieve the transaction object from the full node.
const path = `${this.restURL}rawtransactions/getRawTransaction`
const response = await _this.axios.post(
// console.log('decodeOpReturn() this.axiosOptions: ', this.axiosOptions)
const response = await this.axios.post(
path,
{
verbose: true,
txids: [txid],
usrObj // pass user data when making an internal call.
},
_this.axiosOptions
this.axiosOptions
)
const txDetails = response.data[0]
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
@@ -1639,6 +1651,11 @@ class Utils {
// could not be validated.
return isValid
} catch (error) {
// This case handles rate limit errors.
if (error.response && error.response.data && error.response.data.error) {
throw new Error(error.response.data.error)
}
// console.log('Error in waterfallValidateTxid()')
if (error.response && error.response.data) throw error.response.data
throw error
@@ -1836,11 +1853,13 @@ class Utils {
utxos: utxos,
usrObj
},
_this.axiosOptions
this.axiosOptions
)
return response.data
} catch (error) {
console.log('Error in hydrateUtxos(): ', error)
if (error.response && error.response.data) {
throw new Error(JSON.stringify(error.response.data, null, 2))
}
@@ -1874,7 +1893,7 @@ class Utils {
{
utxos: utxos
},
_this.axiosOptions
this.axiosOptions
)
return response.data
@@ -1914,7 +1933,7 @@ class Utils {
const path = `${this.restURL}slp/status`
try {
const response = await _this.axios.get(path, _this.axiosOptions)
const response = await _this.axios.get(path, this.axiosOptions)
// console.log(
// `getStatus response.data: ${JSON.stringify(response.data, null, 2)}`
// )
+72 -12
View File
@@ -4,6 +4,7 @@
const RawTransaction = require('./raw-transactions')
const SlpUtils = require('./slp/utils')
const BigNumber = require('bignumber.js')
class Transaction {
constructor (config) {
@@ -37,7 +38,9 @@ class Transaction {
async get (txid) {
try {
if (typeof txid !== 'string') {
throw new Error('Input must be a string or array of strings.')
throw new Error(
'Input to Transaction.get() must be a string containing a TXID.'
)
}
const txDetails = await this.rawTransaction.getTxData(txid)
@@ -73,9 +76,18 @@ class Transaction {
// 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)
// const realQty = Number(rawQty) / Math.pow(10, txDetails.tokenDecimals)
txDetails.vout[i + 1].tokenQty = realQty
// 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.
@@ -99,17 +111,53 @@ class Transaction {
// `vin[${i}] tokenData: ${JSON.stringify(inTokenData, null, 2)}`
// )
// 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.
const tokenQty = inTokenData.amounts[thisVin.vout - 1]
// console.log(`tokenQty: ${JSON.stringify(tokenQty, 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 if (inTokenData.txType === 'MINT') {
// vout=1 (second output) recieves the newly minted tokens.
if (i === 1) {
tokenQty = inTokenData.qty
} else {
tokenQty = null
}
//
} else {
console.log(
'Unexpected code path in Transaction.get(). What is the txType?'
)
console.log(inTokenData)
throw new Error('Unexpected code path')
}
if (tokenQty) {
const realQty =
Number(tokenQty) / Math.pow(10, txDetails.tokenDecimals)
// const realQty =
// Number(tokenQty) / Math.pow(10, txDetails.tokenDecimals)
thisVin.tokenQty = realQty
// 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
@@ -129,6 +177,11 @@ class Transaction {
} 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
@@ -136,7 +189,14 @@ class Transaction {
return txDetails
} catch (err) {
console.error('Error in transactions.js/get()')
// 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
}
}
+8 -8
View File
@@ -1,6 +1,6 @@
const axios = require('axios')
let _this
// let _this
class Util {
constructor (config) {
@@ -24,11 +24,11 @@ class Util {
}
}
_this = this
// _this = this
}
/**
* @api util.floor8() floor8()
* @api Util.floor8() floor8()
* @apiName floor8
* @apiGroup Util
* @apiDescription Round a number down to 8 decimal places.
@@ -63,7 +63,7 @@ class Util {
}
/**
* @api util.floor2() floor2()
* @api Util.floor2() floor2()
* @apiName floor2
* @apiGroup Util
* @apiDescription Round a number down to 2 decimal places.
@@ -98,7 +98,7 @@ class Util {
}
/**
* @api util.chunk20() chunk20()
* @api Util.chunk20() chunk20()
* @apiName chunk20
* @apiGroup Util
* @apiDescription chunk up an array into multiple arrays of 20 elements each.
@@ -151,7 +151,7 @@ class Util {
}
/**
* @api util.sleep() sleep()
* @api Util.sleep() sleep()
* @apiName sleep
* @apiGroup Util
* @apiDescription Promise-based delay.
@@ -175,7 +175,7 @@ class Util {
}
/**
* @api util.validateAddress() validateAddress()
* @api Util.validateAddress() validateAddress()
* @apiName Validate Address.
* @apiGroup Util
* @apiDescription Return information about the given bitcoin address.
@@ -225,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
+2
View File
@@ -276,6 +276,8 @@ class UTXO {
return retAry
} catch (err) {
console.error('Error in bchjs.utxo.get()')
if (err.error) throw new Error(err.error)
throw err
}
}
@@ -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
})
+2 -2
View File
@@ -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`)
+3 -3
View File
@@ -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
})
+1 -1
View File
@@ -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', () => {
@@ -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)
})
/*
+1 -1
View File
@@ -25,7 +25,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(1500)
bchjs = new BCHJS({ restURL: process.env.RESTURL })
})
@@ -11,7 +11,7 @@ describe('#UTXO', () => {
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)
})
describe('#get', () => {
+25
View File
@@ -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)
})
})
})
@@ -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', () => {
+2 -2
View File
@@ -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', () => {
+15 -7
View File
@@ -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'
)
}
-147
View File
@@ -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', () => {
+3 -3
View File
@@ -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
+3 -3
View File
@@ -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', () => {
+1 -1
View File
@@ -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', () => {
+4 -2
View File
@@ -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())
@@ -359,10 +359,12 @@ 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'
)
}
+1 -1
View File
@@ -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', () => {
-138
View File
@@ -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 -1
View File
@@ -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', () => {
+10 -6
View File
@@ -19,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', () => {
@@ -191,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')
}
})
})
@@ -251,9 +250,13 @@ describe('#rawtransaction', () => {
describe('#_getInputAddrs', () => {
it('should return an array of input addresses', async () => {
// const txid = '32233db13f2ae6d82b6262f335643dccf09fc0bcfcef4bc3fbe023355f02e112'
const txid = '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const txid =
'05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const txDetails = await bchjs.RawTransactions.getRawTransaction(txid, true)
const txDetails = await bchjs.RawTransactions.getRawTransaction(
txid,
true
)
const result = await bchjs.RawTransactions._getInputAddrs(txDetails)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
@@ -268,7 +271,8 @@ describe('#rawtransaction', () => {
describe('#getTxData', () => {
it('should return tx data with input addresses', async () => {
const txid = '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const txid =
'05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const result = await bchjs.RawTransactions.getTxData(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
+1 -1
View File
@@ -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', () => {
+66
View File
@@ -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')
}
})
})
})
+19
View File
@@ -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
}
+252 -1
View File
@@ -175,10 +175,261 @@ const mockOpReturnData03 = {
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
}
const mintTestInputTx = {
txid: '4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa',
hash: '4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa',
version: 1,
size: 585,
locktime: 543613,
vin: [
{
txid: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
vout: 1,
scriptSig: {
asm: '3045022100e3d5f9a48f9aa1cf7e9ed1992e0281e7300b734ba0e4bd5bb9265b2be60bd71002200ccde53ce7ea9da9df3e834f234f3bea65c2e58c96f8436f93333fd8946a1db2[ALL|FORKID] 02056220984cc2cf5261a27d4f66d31c9ef601a688ca1a5ab81e55b6f0d311be74',
hex: '483045022100e3d5f9a48f9aa1cf7e9ed1992e0281e7300b734ba0e4bd5bb9265b2be60bd71002200ccde53ce7ea9da9df3e834f234f3bea65c2e58c96f8436f93333fd8946a1db2412102056220984cc2cf5261a27d4f66d31c9ef601a688ca1a5ab81e55b6f0d311be74'
},
sequence: 4294967294,
address: 'bitcoincash:qpaf9wltgmpjlg2vxwwu7zdw5y4z7m277ckxn8cufl',
value: 0.00000546,
tokenQtyStr: '43545.34534',
tokenQty: 43545.34534
},
{
txid: 'ee9d3cf5153599c134147e3fac9844c68e216843f4452a1ce15a29452af6db34',
vout: 1,
scriptSig: {
asm: '3045022100bb90d52be9b568f643fdb1a302e9f063be27a9f914e2a6b192cbabf2cbdeaf9302203c275fc8d1b82390bc1726390d361c5266056bddd54dec23efa207c79eacea4a[ALL|FORKID] 024146cfcd0c02e99d6451dc48ad0f97114aeda18fe55c52a10bfc0490f314e6a2',
hex: '483045022100bb90d52be9b568f643fdb1a302e9f063be27a9f914e2a6b192cbabf2cbdeaf9302203c275fc8d1b82390bc1726390d361c5266056bddd54dec23efa207c79eacea4a4121024146cfcd0c02e99d6451dc48ad0f97114aeda18fe55c52a10bfc0490f314e6a2'
},
sequence: 4294967294,
address: 'bitcoincash:qqf89zzwd0fqc3npkks997r5l7dpfjf9kgx2rqu500',
value: 0.00000546,
tokenQtyStr: '2.34123',
tokenQty: 2.34123
},
{
txid: 'ee9d3cf5153599c134147e3fac9844c68e216843f4452a1ce15a29452af6db34',
vout: 3,
scriptSig: {
asm: '3044022029ab770c249f467b40bb90410429f6d657f9be299baa19a6838d04d972436b450220143660297e8e836bc16d317649fad8c310bdadb4fb61d4e9f6ba11203abe5dae[ALL|FORKID] 02eed4ac9dda3405d9b1ccbbf09f8056f3e7c615924274bd5643238b543d0a1d56',
hex: '473044022029ab770c249f467b40bb90410429f6d657f9be299baa19a6838d04d972436b450220143660297e8e836bc16d317649fad8c310bdadb4fb61d4e9f6ba11203abe5dae412102eed4ac9dda3405d9b1ccbbf09f8056f3e7c615924274bd5643238b543d0a1d56'
},
sequence: 4294967294,
address: 'bitcoincash:qqt30r33k0jx3sxe34tmupaujpaljnglmvqgrrfp2x',
value: 0.00054848,
tokenQtyStr: '2.34123',
tokenQty: 2.34123
}
],
vout: [
{
value: 0,
n: 0,
scriptPubKey: {
asm: 'OP_RETURN 5262419 1 1145980243 938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8 0000000103907f11',
hex: '6a04534c500001010453454e4420938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8080000000103907f11',
type: 'nulldata'
},
tokenQty: null
},
{
value: 0.00000546,
n: 1,
scriptPubKey: {
asm: 'OP_DUP OP_HASH160 059775ff94f65c04e8a6847e74eb9809d8cd779b OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914059775ff94f65c04e8a6847e74eb9809d8cd779b88ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: [
'bitcoincash:qqzewa0ljnm9cp8g56z8ua8tnqya3nthnvhv5hpu8y'
]
},
tokenQtyStr: '43547.68657',
tokenQty: 43547.68657
},
{
value: 0.00054808,
n: 2,
scriptPubKey: {
asm: 'OP_DUP OP_HASH160 0e330dc9009e1e07831f5a22d4ade8977ab674c8 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a9140e330dc9009e1e07831f5a22d4ade8977ab674c888ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: [
'bitcoincash:qq8rxrwfqz0pupurradz949dazth4dn5eqs3mhrucv'
]
},
tokenQty: null
}
],
hex: '0100000003f8cda53b43b0ea49991a9bc6c74eb901d2a8b964bc7b8987d76789618ec18c93010000006b483045022100e3d5f9a48f9aa1cf7e9ed1992e0281e7300b734ba0e4bd5bb9265b2be60bd71002200ccde53ce7ea9da9df3e834f234f3bea65c2e58c96f8436f93333fd8946a1db2412102056220984cc2cf5261a27d4f66d31c9ef601a688ca1a5ab81e55b6f0d311be74feffffff34dbf62a45295ae11c2a45f44368218ec64498ac3f7e1434c1993515f53c9dee010000006b483045022100bb90d52be9b568f643fdb1a302e9f063be27a9f914e2a6b192cbabf2cbdeaf9302203c275fc8d1b82390bc1726390d361c5266056bddd54dec23efa207c79eacea4a4121024146cfcd0c02e99d6451dc48ad0f97114aeda18fe55c52a10bfc0490f314e6a2feffffff34dbf62a45295ae11c2a45f44368218ec64498ac3f7e1434c1993515f53c9dee030000006a473044022029ab770c249f467b40bb90410429f6d657f9be299baa19a6838d04d972436b450220143660297e8e836bc16d317649fad8c310bdadb4fb61d4e9f6ba11203abe5dae412102eed4ac9dda3405d9b1ccbbf09f8056f3e7c615924274bd5643238b543d0a1d56feffffff030000000000000000376a04534c500001010453454e4420938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8080000000103907f1122020000000000001976a914059775ff94f65c04e8a6847e74eb9809d8cd779b88ac18d60000000000001976a9140e330dc9009e1e07831f5a22d4ade8977ab674c888ac7d4b0800',
blockhash: '00000000000000000140f0d813052da59c811a936494a8d8b2d60b215d19e3dc',
confirmations: 167007,
time: 1534391953,
blocktime: 1534391953,
isValidSLPTx: true,
tokenTxType: 'SEND',
tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
tokenTicker: 'Bubb2',
tokenName: 'the new bubbles!',
tokenDecimals: 5,
tokenUri: '',
tokenDocHash: ''
}
const genesisTestOpReturnData01 = {
tokenType: 1,
txType: 'SEND',
tokenId: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
amounts: ['5000000', '5000000']
}
const genesisTestOpReturnData02 = {
tokenType: 1,
txType: 'GENESIS',
ticker: '',
name: '',
tokenId: '323a1e35ae0b356316093d20f2d9fbc995d19314b5c0148b78dc8d9c0dab9d35',
documentUri: '',
documentHash: '',
decimals: 0,
mintBatonVout: 2,
qty: '10000000'
}
const mintTestOpReturnData01 = {
tokenType: 1,
txType: 'SEND',
tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
amounts: [
'4354768657'
]
}
const mintTestOpReturnData02 = {
tokenType: 1,
txType: 'GENESIS',
ticker: 'Bubb2',
name: 'the new bubbles!',
tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
documentUri: '',
documentHash: '',
decimals: 5,
mintBatonVout: 2,
qty: '4354534534'
}
const mintTestOpReturnData03 = {
tokenType: 1,
txType: 'MINT',
tokenId: '938cc18e618967d787897bbc64b9a8d201b94ec7c69b1a9949eab0433ba5cdf8',
mintBatonVout: 2,
qty: '234123'
}
module.exports = {
nonSlpTxDetails,
slpTxDetails,
mockOpReturnData01,
mockOpReturnData02,
mockOpReturnData03
mockOpReturnData03,
genesisTestInputTx,
mintTestInputTx,
genesisTestOpReturnData01,
genesisTestOpReturnData02,
mintTestOpReturnData01,
mintTestOpReturnData02,
mintTestOpReturnData03
}
+14 -5
View File
@@ -171,10 +171,15 @@ describe('#RawTransactions', () => {
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)
sandbox
.stub(bchjs.RawTransactions, 'getRawTransaction')
.resolves(mockData.mockTx)
sandbox
.stub(bchjs.RawTransactions, '_getInputAddrs')
.resolves(mockData.mockGetInputAddrsOutput)
const txid = '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const txid =
'05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const result = await bchjs.RawTransactions.getTxData(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
@@ -190,7 +195,10 @@ describe('#RawTransactions', () => {
} catch (err) {
// console.log(err)
assert2.include(err.message, 'Input must be a string or array of strings')
assert2.include(
err.message,
'Input to raw-transaction.js/getTxData() must be a string containg a TXID.'
)
}
})
@@ -201,7 +209,8 @@ describe('#RawTransactions', () => {
.stub(bchjs.RawTransactions, 'getRawTransaction')
.rejects(new Error('test error'))
const txid = '05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
const txid =
'05f7d4a4e25f53d63a360434eb54f221abf159112b7fffc91da1072a079cded3'
await bchjs.RawTransactions.getTxData(txid)
+20 -18
View File
@@ -10,7 +10,7 @@ let uut
const REST_URL = process.env.RESTURL
? process.env.RESTURL
: 'https://bchn.fullstack.cash/v4/'
: 'https://bchn.fullstack.cash/v5/'
// Mock data used for unit tests
const mockDataLib = require('./fixtures/slp/mock-utils')
@@ -2281,23 +2281,25 @@ describe('#SLP Utils', () => {
assert.equal(result, true)
})
it('catches and throws an error', async () => {
try {
const txid = 'fakeTxid'
// Force an error
sandbox
.stub(uut.Utils, 'validateTxid3')
.rejects(new Error('fake error'))
await await uut.Utils.waterfallValidateTxid(txid)
assert.fail('Unexpected result')
} catch (err) {
// console.log(`err.message: ${err.message}`)
assert.include(err.message, 'fake error')
}
})
// CT 08-09-21 Changed behavior. validateTxid3() is now wrapped in a
// try/catch statement that exits quietly if there is an error.
// it('catches and throws an error', async () => {
// try {
// const txid = 'fakeTxid'
//
// // Force an error
// sandbox
// .stub(uut.Utils, 'validateTxid3')
// .rejects(new Error('fake error'))
//
// await await uut.Utils.waterfallValidateTxid(txid)
//
// assert.fail('Unexpected result')
// } catch (err) {
// // console.log(`err.message: ${err.message}`)
// assert.include(err.message, 'fake error')
// }
// })
})
describe('#getWhitelist', () => {
+99 -1
View File
@@ -25,7 +25,7 @@ describe('#TransactionLib', () => {
} catch (err) {
assert.include(
err.message,
'Input must be a string or array of strings.'
'Input to Transaction.get() must be a string containing a TXID.'
)
}
})
@@ -115,5 +115,103 @@ describe('#TransactionLib', () => {
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)
})
it('should get input details when input is a mint tx', async () => {
// Mock dependencies
sandbox
.stub(bchjs.Transaction.rawTransaction, 'getTxData')
.resolves(mockData.mintTestInputTx)
sandbox
.stub(bchjs.Transaction.slpUtils, 'decodeOpReturn')
.onCall(0)
.resolves(mockData.mintTestOpReturnData01)
.onCall(1)
.resolves(mockData.mintTestOpReturnData02)
.onCall(2)
.resolves(mockData.mintTestOpReturnData02)
.onCall(3)
.resolves(mockData.mintTestOpReturnData03)
.onCall(4)
.resolves(mockData.mintTestOpReturnData03)
sandbox
.stub(bchjs.Transaction.slpUtils, 'waterfallValidateTxid')
.resolves(true)
const txid =
'4640a734063ea79fa587a3cac38a70a2f6f3db0011e23514024185982110d0fa'
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 Mint input have the proper values.
assert.equal(result.vin[0].tokenQty, 43545.34534)
assert.equal(result.vin[1].tokenQty, 2.34123)
assert.equal(result.vin[2].tokenQty, null)
})
})
})