Compare commits

...
43 Commits
Author SHA1 Message Date
Chris Troutner f84862d875 Merge pull request #124 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Added NFT child test case
2021-02-27 13:12:30 -08:00
Chris Troutner 179d924899 Adding respond.data in error 2021-02-27 13:10:33 -08:00
Chris Troutner 676fb85abf fix(decodeOpReturn): Added NFT child test case 2021-02-27 12:58:40 -08:00
Chris Troutner d59c1fe445 Merge pull request #123 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Trying different error configuration
2021-02-27 10:03:58 -08:00
Chris Troutner 0a34611557 fix(decodeOpReturn): Trying different error configuration 2021-02-27 10:02:12 -08:00
Chris Troutner c13b029e99 Merge pull request #122 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Replacing error message with better one
2021-02-27 09:47:20 -08:00
Chris Troutner b038e9a7fd fix(decodeOpReturn): Replacing error message with better one 2021-02-27 09:45:24 -08:00
Chris Troutner 7b728fb45d Merge pull request #121 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Adding additional debugging for errors
2021-02-27 09:33:00 -08:00
Chris Troutner d4dbce8df0 fix(decodeOpReturn): Adding additional debugging for errors 2021-02-27 09:31:16 -08:00
Chris Troutner 2419aeceaa Merge pull request #120 from Permissionless-Software-Foundation/ct-unstable
fix(_hydrateUtxo): Adding more debugging
2021-02-27 09:09:58 -08:00
Chris Troutner 158b009069 fix(_hydrateUtxo): Adding more debugging 2021-02-27 09:07:50 -08:00
Chris Troutner f3c3250a69 Merge pull request #119 from Permissionless-Software-Foundation/ct-unstable
fix(_hydrateUtxo): Debugging error handling
2021-02-27 09:00:20 -08:00
Chris Troutner 5ae4db88c3 Merge branch 'master' into ct-unstable 2021-02-27 08:58:23 -08:00
Chris Troutner 33e161df26 fix(_hydrateUtxo): Debugging error handling 2021-02-27 08:58:12 -08:00
Chris Troutner 81c910361c Merge pull request #118 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Debugging error handling by decodeOpReturn()
2021-02-27 08:41:57 -08:00
Chris Troutner 9751a39538 Merge branch 'master' into ct-unstable 2021-02-27 08:38:38 -08:00
Chris Troutner 7058f77ee9 fix(decodeOpReturn): Debugging error handling by decodeOpReturn() 2021-02-27 08:37:29 -08:00
Chris Troutner ad580d67a4 Adding decatur test script 2021-02-27 08:23:07 -08:00
Chris Troutner acc0300a44 Merge pull request #117 from Permissionless-Software-Foundation/ct-unstable
fix(bip32-utils): Bumping to v1.0.0 with updated keccak
2021-02-24 18:56:39 -08:00
Chris Troutner 4e1b806230 fix(bip32-utils): Bumping to v1.0.0 with updated keccak 2021-02-24 18:53:20 -08:00
Chris Troutner 357e350176 Merge pull request #116 from Permissionless-Software-Foundation/ct-unstable
fix(electrumx): Adding usrObj to Electrumx.Transactions()
2021-02-24 17:59:35 -08:00
Chris Troutner f6140acc76 fix(electrumx): Adding usrObj to Electrumx.Transactions() 2021-02-24 17:53:53 -08:00
Chris Troutner df65b12aab Merge pull request #115 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): replacing ip with usrObj
2021-02-24 16:44:58 -08:00
Chris Troutner 754b4cd807 fix(decodeOpReturn): replacing ip with usrObj 2021-02-24 16:42:54 -08:00
Chris Troutner 3c6079e54c Merge pull request #114 from Permissionless-Software-Foundation/ct-unstable
fix(usrObj): Fixing typo of usbObj to usrObj
2021-02-24 16:37:09 -08:00
Chris Troutner 18621cd76c fix(usrObj): Fixing typo of usbObj to usrObj 2021-02-24 16:35:09 -08:00
Chris Troutner 456159a4cc Merge pull request #113 from Permissionless-Software-Foundation/ct-unstable
fix(usbObj): Passing a usrObj when bch-api calls bch-js
2021-02-24 16:29:54 -08:00
Chris Troutner 33e723befe fix(usbObj): Passing a usrObj when bch-api calls bch-js 2021-02-24 16:27:49 -08:00
Chris Troutner 30fdee1920 Merge pull request #112 from Permissionless-Software-Foundation/ct-unstable
fix(decodeOpReturn): Switching to POST from GET to getRawTx call
2021-02-24 15:14:51 -08:00
Chris Troutner feb336c331 fix(decodeOpReturn): Switching to POST from GET to getRawTx call 2021-02-24 15:11:58 -08:00
Chris Troutner 8bacc0a991 Merge pull request #111 from Permissionless-Software-Foundation/ct-unstable
fix(ip): Renaming origin to ip
2021-02-24 14:10:07 -08:00
Chris Troutner d22f1ec8a6 fix(ip): Renaming origin to ip 2021-02-24 14:05:25 -08:00
Chris Troutner 7eb3a796b8 Merge pull request #110 from Permissionless-Software-Foundation/ct-unstable
fix(origin): Testing idea around passing origin when bch-api calls bc…
2021-02-24 13:29:05 -08:00
Chris Troutner 9919f811b0 fix(origin): Testing idea around passing origin when bch-api calls bch-js 2021-02-24 13:26:08 -08:00
Chris Troutner e7854481a0 Merge pull request #109 from Permissionless-Software-Foundation/ct-unstable
fix(dependencies): Removing several unused dependencies
2021-02-23 10:29:22 -08:00
Chris Troutner 0b406c467e fix(dependencies): Removing more unnecessary dependencies 2021-02-23 10:26:12 -08:00
Chris Troutner e41217b710 fix(dependencies): Removing several unused dependencies 2021-02-23 09:04:49 -08:00
Chris Troutner c22ce8d57d fix(dependencies): Ran npm audit with 0 vulns 2021-02-23 08:46:27 -08:00
Chris Troutner bf3612583e Merge pull request #108 from Permissionless-Software-Foundation/ct-unstable
Sleep: Adding a Promise-based wait function to Util lib
2021-02-15 15:28:26 -08:00
Chris Troutner ef56452ec9 feat(sleep): Adding sleep function to Util lib 2021-02-15 15:16:30 -08:00
Chris Troutner b3be470c0e fix(utxo.get()): Fixing ABC integration test 2021-02-15 15:12:39 -08:00
Chris Troutner 7274475898 Merge pull request #107 from Permissionless-Software-Foundation/ct-unstable
fix(package-lock.json): Updating package-lock.json
2021-02-13 17:46:19 -08:00
Chris Troutner 7bb347a833 fix(package-lock.json): Updating package-lock.json 2021-02-13 17:44:14 -08:00
13 changed files with 4590 additions and 5852 deletions
+4293 -5719
View File
File diff suppressed because it is too large Load Diff
+8 -21
View File
@@ -16,8 +16,11 @@
"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:temp": "export RESTURL=https://bchn.fullstack.cash/v4/ && mocha --timeout 30000 -g '#UTXO' test/integration/chains/bchn/",
"test:temp2": "mocha --timeout=30000 -g '#Util' test/unit/",
"test:integration:decatur:bchn": "export RESTURL=http://192.168.0.36:3000/v4/ && mocha --timeout 30000 test/integration/",
"test:temp": "export RESTURL=http://localhost:3000/v4/ && mocha --timeout 30000 -g '#hydrateUtxos' test/integration/",
"test:temp2": "mocha --timeout=30000 -g '#decodeOpReturn' test/unit/",
"test:temp3": "export RESTURL=https://bchn.fullstack.cash/v4/ && mocha --timeout 30000 -g '#hydrateUtxos' test/integration/",
"test:temp4": "export RESTURL=http://localhost:3000/v4/ && 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",
@@ -31,13 +34,12 @@
},
"dependencies": {
"@psf/bip21": "^2.0.1",
"@psf/bip32-utils": "^0.13.1",
"@psf/bip32-utils": "^1.0.0",
"@psf/bitcoincash-ops": "^2.0.0",
"@psf/bitcoincashjs-lib": "^4.0.2",
"@psf/coininfo": "^4.0.0",
"@uppy/core": "^1.10.4",
"@uppy/tus": "^1.5.12",
"assert": "^2.0.0",
"axios": "^0.21.1",
"bc-bip68": "^1.0.5",
"bchaddrjs-slp": "^0.2.5",
@@ -49,33 +51,18 @@
"bip66": "^1.1.5",
"bitcoinjs-message": "^2.0.0",
"bs58": "^4.0.1",
"buffer": "^5.1.0",
"cashaddrjs": "^0.3.3",
"chalk": "^2.3.0",
"clear": "0.1.0",
"commander": "^3.0.0",
"cp-file": "^7.0.0",
"ecurve": "^1.0.6",
"figlet": "^1.2.0",
"git-clone": "^0.1.0",
"ini": "^1.3.8",
"mkdirp": "^0.5.1",
"node-cmd": "^3.0.0",
"node-emoji": "^1.8.1",
"qrcode": "^1.4.1",
"randombytes": "^2.0.6",
"repl.history": "^0.1.4",
"safe-buffer": "^5.1.2",
"satoshi-bitcoin": "^1.0.4",
"slp-mdm": "0.0.6",
"slp-parser": "0.0.4",
"socket.io": "^2.1.1",
"socket.io-client": "^2.1.1",
"touch": "^3.1.0",
"wif": "^2.0.6"
},
"devDependencies": {
"apidoc": "^0.17.7",
"assert": "^2.0.0",
"chai": "^4.1.2",
"coveralls": "^3.0.2",
"eslint": "5.16.0",
@@ -90,7 +77,7 @@
"node-mocks-http": "^1.7.0",
"nyc": "^14.1.0",
"prettier": "^1.18.2",
"semantic-release": "^17.3.1",
"semantic-release": "^17.3.9",
"sinon": "^7.3.2",
"standard": "^16.0.3"
},
-2
View File
@@ -26,7 +26,6 @@ const TransactionBuilder = require('./transaction-builder')
const ECPair = require('./ecpair')
const Script = require('./script')
const Price = require('./price')
const Socket = require('./socket')
const Schnorr = require('./schnorr')
const SLP = require('./slp/slp')
const IPFS = require('./ipfs')
@@ -107,7 +106,6 @@ class BCHJS {
this.TransactionBuilder = TransactionBuilder
this.TransactionBuilder.setAddress(this.Address)
this.Util = new Util(libConfig)
this.Socket = Socket
this.Schnorr = new Schnorr(libConfig)
this.SLP = new SLP(libConfig)
+3 -2
View File
@@ -284,7 +284,7 @@ class ElectrumX {
* }
*
*/
async transactions (address) {
async transactions (address, usrObj = null) {
try {
// Handle single address.
if (typeof address === 'string') {
@@ -299,7 +299,8 @@ class ElectrumX {
const response = await axios.post(
`${this.restURL}electrumx/transactions`,
{
addresses: address
addresses: address,
usrObj // pass user data when making an internal call.
},
_this.axiosOptions
)
+3 -2
View File
@@ -263,7 +263,7 @@ class RawTransactions {
* // time: 1547752564,
* // blocktime: 1547752564 } ]
*/
async getRawTransaction (txid, verbose = false) {
async getRawTransaction (txid, verbose = false, usrObj = null) {
try {
if (typeof txid === 'string') {
const response = await axios.get(
@@ -278,7 +278,8 @@ class RawTransactions {
url: `${this.restURL}rawtransactions/getRawTransaction`,
data: {
txids: txid,
verbose: verbose
verbose: verbose,
usrObj // pass user data when making an internal call.
},
headers: _this.axiosOptions.headers
}
+84 -28
View File
@@ -436,10 +436,11 @@ class Utils {
// will be like the examples above. If SLPDB has fallen behind real-time
// processing, it will return this output:
// [ null ]
async validateTxid (txid) {
async validateTxid (txid, usrObj = null) {
const path = `${this.restURL}slp/validateTxid`
// console.log(`txid: ${JSON.stringify(txid, null, 2)}`)
// console.log(`validateTxid usrObj: ${JSON.stringify(usrObj, null, 2)}`)
// Handle a single TXID or an array of TXIDs.
let txids
@@ -450,7 +451,8 @@ class Utils {
const response = await _this.axios.post(
path,
{
txids: txids
txids: txids,
usrObj // pass user data when making an internal call.
},
_this.axiosOptions
)
@@ -649,11 +651,12 @@ class Utils {
* '00ea27261196a411776f81029c0ebe34362936b4a9847deb1f7a40a02b3a1476',
* valid: true } ]
*/
async validateTxid3 (txid) {
async validateTxid3 (txid, usrObj = null) {
const path = `${this.restURL}slp/validateTxid3`
// console.log(`txid: ${JSON.stringify(txid, null, 2)}`)
// console.log(`path: ${JSON.stringify(path, null, 2)}`)
// console.log('validateTxid3 usrObj: ', usrObj)
// Handle a single TXID or an array of TXIDs.
let txids
@@ -664,7 +667,8 @@ class Utils {
const response = await _this.axios.post(
path,
{
txids: txids
txids: txids,
usrObj // pass user data when making an internal call.
},
_this.axiosOptions
)
@@ -922,7 +926,7 @@ class Utils {
*
*/
// Reimplementation of decodeOpReturn() using slp-parser.
async decodeOpReturn (txid, cache = null) {
async decodeOpReturn (txid, cache = null, usrObj = null) {
// The cache object is an in-memory cache (JS Object) that can be passed
// into this function. It helps if multiple vouts from the same TXID are
// being evaluated. In that case, it can significantly reduce the number
@@ -939,16 +943,31 @@ class Utils {
if (cachedVal) return cachedVal
}
// console.log(`decodeOpReturn usrObj: ${JSON.stringify(usrObj, null, 2)}`)
try {
// Validate the txid input.
if (!txid || txid === '' || typeof txid !== 'string') {
throw new Error('txid string must be included.')
}
// 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/${txid}?verbose=true`
const response = await _this.axios.get(path, _this.axiosOptions)
const txDetails = response.data
// const path = `${this.restURL}rawtransactions/getRawTransaction/${txid}?verbose=true`
// const response = await _this.axios.get(path, _this.axiosOptions)
// const txDetails = response.data
const path = `${this.restURL}rawtransactions/getRawTransaction`
const response = await _this.axios.post(
path,
{
verbose: true,
txids: [txid],
usrObj // pass user data when making an internal call.
},
_this.axiosOptions
)
const txDetails = response.data[0]
// console.log(`txDetails: ${JSON.stringify(txDetails, null, 2)}`)
// SLP spec expects OP_RETURN to be the first output of the transaction.
@@ -995,8 +1014,21 @@ class Utils {
return tokenData
} catch (error) {
// console.log('decodeOpReturn error: ', error)
if (error.response && error.response.data) throw error.response.data
console.log('decodeOpReturn error: ', error)
console.log(`decodeOpReturn error.message: ${error.message}`)
if (error.response && error.response.data) {
// throw error.response.data
// error.bchApiMessage = error.message
// error.message = error.response.data
// error.data = error.response.data
console.log(
`decodeOpReturn error.response.data: ${JSON.stringify(
error.response.data
)}`
)
}
throw error
}
}
@@ -1019,6 +1051,9 @@ class Utils {
* then SLPDB has not yet processed that txid and validity has not been confirmed,
* or a 429 rate-limit error was enountered during the processing of the request.
*
* This is an API-heavy call. If you get a lot of null values, then slow down
* the calls or request info on fewer UTXOs at a time.
*
* @apiExample Example usage:
*
* (async () => {
@@ -1058,11 +1093,13 @@ class Utils {
// https://github.com/Bitcoin-com/slp-sdk/issues/84
// CT 5/31/20: Refactored to use slp-parse library.
async tokenUtxoDetails (utxos) {
async tokenUtxoDetails (utxos, usrObj = null) {
try {
// Throw error if input is not an array.
if (!Array.isArray(utxos)) throw new Error('Input must be an array.')
// console.log(`tokenUtxoDetails usrObj: ${JSON.stringify(usrObj, null, 2)}`)
// Loop through each element in the array and validate the input before
// further processing.
for (let i = 0; i < utxos.length; i++) {
@@ -1094,7 +1131,7 @@ class Utils {
}
// Hydrate each UTXO with data from SLP OP_REUTRNs.
const outAry = await this._hydrateUtxo(utxos)
const outAry = await this._hydrateUtxo(utxos, usrObj)
// console.log(`outAry: ${JSON.stringify(outAry, null, 2)}`)
// *After* each UTXO has been hydrated with SLP data,
@@ -1110,7 +1147,7 @@ class Utils {
// information.
// Validate using a 'waterfall' of validators.
utxo.isValid = await this.waterfallValidateTxid(utxo.txid)
utxo.isValid = await this.waterfallValidateTxid(utxo.txid, usrObj)
// console.log(`isValid: ${JSON.stringify(utxo.isValid, null, 2)}`)
}
}
@@ -1214,10 +1251,17 @@ class Utils {
// This is a private function that is called by tokenUtxoDetails().
// It loops through an array of UTXOs and tries to hydrate them with SLP
// token information from the OP_RETURN data.
async _hydrateUtxo (utxos) {
//
// This function makes several calls to decodeOpReturn() to retrieve SLP
// token data. If that call throws an error due to hitting rate limits, this
// function will not throw an error. Instead, it will mark the `isValid`
// property as `null`
async _hydrateUtxo (utxos, usrObj = null) {
try {
const decodeOpReturnCache = {}
// console.log(`_hydrateUtxo usrObj: ${JSON.stringify(usrObj, null, 2)}`)
// Output Array
const outAry = []
@@ -1230,10 +1274,17 @@ class Utils {
// If there is no OP_RETURN, mark the UTXO as false.
let slpData = false
try {
slpData = await this.decodeOpReturn(utxo.txid, decodeOpReturnCache)
slpData = await this.decodeOpReturn(
utxo.txid,
decodeOpReturnCache,
usrObj // pass user data when making an internal call.
)
// console.log(`slpData: ${JSON.stringify(slpData, null, 2)}`)
} catch (err) {
// console.log(`error from decodeOpReturn(${utxo.txid}): `, err)
console.log(
`error in _hydrateUtxo() from decodeOpReturn(${utxo.txid}): `,
err
)
// An error will be thrown if the txid is not SLP.
// If error is for some other reason, like a 429 error, mark utxo as 'null'
@@ -1244,10 +1295,10 @@ class Utils {
err.message.indexOf('lokad id') === -1 &&
err.message.indexOf('trailing data') === -1)
) {
// console.log(
// 'unknown error from decodeOpReturn(). Marking as \'null\'',
// err
// )
console.log(
"unknown error from decodeOpReturn(). Marking as 'null'",
err
)
utxo.isValid = null
outAry.push(utxo)
@@ -1256,7 +1307,7 @@ class Utils {
// an SLP UTXO.
// Mark as false and continue the loop.
} else {
// console.log('marking as invalid')
console.log('marking as invalid')
utxo.isValid = false
outAry.push(utxo)
}
@@ -1320,7 +1371,8 @@ class Utils {
const genesisData = await this.decodeOpReturn(
slpData.tokenId,
decodeOpReturnCache
decodeOpReturnCache,
usrObj // pass user data when making an internal call.
)
// console.log(`genesisData: ${JSON.stringify(genesisData, null, 2)}`)
@@ -1372,7 +1424,8 @@ class Utils {
const genesisData = await this.decodeOpReturn(
slpData.tokenId,
decodeOpReturnCache
decodeOpReturnCache,
usrObj // pass user data when making an internal call.
)
// console.log(`genesisData: ${JSON.stringify(genesisData, null, 2)}`)
@@ -1406,6 +1459,7 @@ class Utils {
return outAry
} catch (error) {
console.log('_hydrateUtxo error: ', error)
if (error.response && error.response.data) throw error.response.data
throw error
}
@@ -1447,8 +1501,7 @@ class Utils {
* // returns
* true
*/
async waterfallValidateTxid (txid) {
async waterfallValidateTxid (txid, usrObj = null) {
try {
// console.log('txid: ', txid)
@@ -1480,7 +1533,7 @@ class Utils {
// validateTxid2() uses slp-validate, which has a different output format.
// Validate against the whitelist SLPDB first.
const whitelistResult = await this.validateTxid3(txid)
const whitelistResult = await this.validateTxid3(txid, usrObj)
// console.log(
// `whitelist-SLPDB for ${txid}: ${JSON.stringify(
// whitelistResult,
@@ -1501,7 +1554,7 @@ class Utils {
}
// Try the general SLPDB, if the whitelist returned null.
const generalResult = await this.validateTxid(txid)
const generalResult = await this.validateTxid(txid, usrObj)
// console.log(
// `validateTxid() isValid: ${JSON.stringify(generalResult, null, 2)}`
// )
@@ -1563,11 +1616,14 @@ class Utils {
* set to false.
* If the UTXO is part of an SLP transaction, it will return the UTXO object
* with additional SLP information attached. An `isValid` property will be included.
* If its value is true, the UTXO is a valid SLP UTXO. \
* If its value is true, the UTXO is a valid SLP UTXO.
* If the isValid value is null,
* then SLPDB has not yet processed that txid and validity has not been confirmed,
* or a 429 rate-limit error was enountered during the processing of the request.
*
* This is an API-heavy call. If you get a lot of null values, then slow down
* the calls or request info on fewer UTXOs at a time.
*
* @apiExample Example usage:
*
* (async () => {
-28
View File
@@ -1,28 +0,0 @@
const io = require('socket.io-client')
class Socket {
constructor (config = {}) {
if (typeof config === 'string') {
// TODO remove this check in v2.0
this.socket = io(`${config}`)
} else {
if (config.restURL) {
this.socket = io(`${config.restURL}`)
} else {
const restURL = 'https://rest.bitcoin.com'
this.socket = io(`${restURL}`)
}
if (config.callback) config.callback()
}
}
listen (endpoint, cb) {
this.socket.emit(endpoint)
if (endpoint === 'blocks') this.socket.on('blocks', msg => cb(msg))
else if (endpoint === 'transactions') { this.socket.on('transactions', msg => cb(msg)) }
}
}
module.exports = Socket
+24
View File
@@ -150,6 +150,30 @@ class Util {
}
}
/**
* @api util.sleep() sleep()
* @apiName sleep
* @apiGroup Util
* @apiDescription Promise-based delay.
* Expects an integer as input, which represents milliseconds. This function
* will return a Promise that resolves that many milliseconds later.
*
*
* @apiExample Example usage:
* (async () => {
* try {
* const tenSeconds = 10000
* await bchjs.Util.sleep(tenSeconds)
* } catch(error) {
* console.error(error)
* }
* })()
*
*/
sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
/**
* @api util.validateAddress() validateAddress()
* @apiName Validate Address.
@@ -22,9 +22,13 @@ describe('#UTXO', () => {
const result = await bchjs.Utxo.get(addr)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.isArray(result.bchUtxos)
assert.isArray(result.slpUtxos)
assert.isArray(result.nullUtxos)
assert.isArray(result)
assert.property(result[0], 'address')
assert.property(result[0], 'bchUtxos')
assert.property(result[0], 'nullUtxos')
assert.property(result[0], 'slpUtxos')
assert.isArray(result[0].bchUtxos)
assert.isArray(result[0].nullUtxos)
})
})
})
@@ -112,7 +112,7 @@ describe('#UTXO', () => {
// console.log(`utxos: ${JSON.stringify(utxos, null, 2)}`)
const result = bchjs.Utxo.findBiggestUtxo(utxos[0].bchUtxos)
console.log(`result: ${JSON.stringify(result, null, 2)}`)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.property(result, 'satoshis')
assert.equal(result.satoshis, 800)
+23
View File
@@ -228,6 +228,29 @@ describe('#SLP', () => {
assert.include(err.message, 'amount string size not 8 bytes')
}
})
it('should decode a NFT Child transaction', async () => {
const txid =
'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b'
const data = await bchjs.SLP.Utils.decodeOpReturn(txid)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.property(data, 'tokenType')
assert.property(data, 'txType')
assert.property(data, 'ticker')
assert.property(data, 'name')
assert.property(data, 'tokenId')
assert.property(data, 'documentUri')
assert.property(data, 'documentHash')
assert.property(data, 'decimals')
assert.property(data, 'mintBatonVout')
assert.property(data, 'qty')
assert.equal(data.tokenType, 65)
assert.equal(data.mintBatonVout, 0)
assert.equal(data.qty, '1')
})
})
describe('#tokenUtxoDetails', () => {
+80 -1
View File
@@ -1290,6 +1290,83 @@ const slpdbStatus = {
}
}
const txDetailsSLPNftChild = {
txid: 'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b',
hash: 'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b',
version: 2,
size: 453,
locktime: 0,
vin: [
{
txid: 'a9a2458a0f9f0761d5b8725c256f2e7fa35b9de4dec6f47b46e9f20d92d0e395',
vout: 1,
scriptSig: {
asm:
'3045022100890ff2f80f3c184419ba03a575b9d159c0a5edfa817e4548cfdb6c74d16ce8d202205a8237d2139196716c273fe80506896d369a0022bb54401e2eadb364286a9f07[ALL|FORKID] 03136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623b',
hex:
'483045022100890ff2f80f3c184419ba03a575b9d159c0a5edfa817e4548cfdb6c74d16ce8d202205a8237d2139196716c273fe80506896d369a0022bb54401e2eadb364286a9f07412103136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623b'
},
sequence: 4294967295
},
{
txid: 'a9a2458a0f9f0761d5b8725c256f2e7fa35b9de4dec6f47b46e9f20d92d0e395',
vout: 3,
scriptSig: {
asm:
'304402203905a61ec4e3567f7cad7eb514132e5b32d8a1d77c8838baac1b34b735282a5f022044da6130b5cc41b65615b17df6610087fe1baedd1a3a9f37552b56ea8d36d026[ALL|FORKID] 03136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623b',
hex:
'47304402203905a61ec4e3567f7cad7eb514132e5b32d8a1d77c8838baac1b34b735282a5f022044da6130b5cc41b65615b17df6610087fe1baedd1a3a9f37552b56ea8d36d026412103136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623b'
},
sequence: 4294967295
}
],
vout: [
{
value: 0,
n: 0,
scriptPubKey: {
asm:
'OP_RETURN 5262419 65 47454e45534953 4e4654303034 4e4654204368696c64 68747470733a2f2f46756c6c537461636b2e63617368 0 0 0 0000000000000001',
hex:
'6a04534c500001410747454e45534953064e4654303034094e4654204368696c641668747470733a2f2f46756c6c537461636b2e636173684c0001004c00080000000000000001',
type: 'nulldata'
}
},
{
value: 0.00000546,
n: 1,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 f6fc6bce702ef779d2373aa4356a32113d95e674 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914f6fc6bce702ef779d2373aa4356a32113d95e67488ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qrm0c67wwqh0w7wjxua2gdt2xggnm90xws00a3lezv']
}
},
{
value: 0.0003923,
n: 2,
scriptPubKey: {
asm:
'OP_DUP OP_HASH160 f6fc6bce702ef779d2373aa4356a32113d95e674 OP_EQUALVERIFY OP_CHECKSIG',
hex: '76a914f6fc6bce702ef779d2373aa4356a32113d95e67488ac',
reqSigs: 1,
type: 'pubkeyhash',
addresses: ['bitcoincash:qrm0c67wwqh0w7wjxua2gdt2xggnm90xws00a3lezv']
}
}
],
hex:
'020000000295e3d0920df2e9467bf4c6dee49d5ba37f2e6f255c72b8d561079f0f8a45a2a9010000006b483045022100890ff2f80f3c184419ba03a575b9d159c0a5edfa817e4548cfdb6c74d16ce8d202205a8237d2139196716c273fe80506896d369a0022bb54401e2eadb364286a9f07412103136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623bffffffff95e3d0920df2e9467bf4c6dee49d5ba37f2e6f255c72b8d561079f0f8a45a2a9030000006a47304402203905a61ec4e3567f7cad7eb514132e5b32d8a1d77c8838baac1b34b735282a5f022044da6130b5cc41b65615b17df6610087fe1baedd1a3a9f37552b56ea8d36d026412103136d9ec06adef1c9154105950e82d470d290aa019ed34a5e3bbd0b679805623bffffffff030000000000000000476a04534c500001410747454e45534953064e4654303034094e4654204368696c641668747470733a2f2f46756c6c537461636b2e636173684c0001004c0008000000000000000122020000000000001976a914f6fc6bce702ef779d2373aa4356a32113d95e67488ac3e990000000000001976a914f6fc6bce702ef779d2373aa4356a32113d95e67488ac00000000',
blockhash: '000000000000000001360fe42629f4136e9adec53546b278de0e7ef788eed328',
confirmations: 2113,
time: 1613181364,
blocktime: 1613181364
}
const mock429Error = new Error('Request failed with status code 429')
module.exports = {
mockList,
mockToken,
@@ -1311,6 +1388,7 @@ module.exports = {
txDetailsSLPGenesisNoBaton,
txDetailsSLPSendAlt,
txDetailsSLPNftGenesis,
txDetailsSLPNftChild,
mockTxDetails,
mockDualValidation,
mockDualOpData,
@@ -1320,5 +1398,6 @@ module.exports = {
mockValidateTxid3Invalid,
whitelist,
slpdbStatus,
mockValidateTxidArray
mockValidateTxidArray,
mock429Error
}
+64 -45
View File
@@ -273,8 +273,8 @@ describe('#SLP Utils', () => {
try {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.nonSLPTxDetailsWithoutOpReturn })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.nonSLPTxDetailsWithoutOpReturn] })
const txid =
'3793d4906654f648e659f384c0f40b19c8f10c1e9fb72232a9b8edd61abaa1ec'
@@ -292,8 +292,8 @@ describe('#SLP Utils', () => {
try {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.nonSLPTxDetailsWithOpReturn })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.nonSLPTxDetailsWithOpReturn] })
const txid =
'2ff74c48a5d657cf45f699601990bffbbe7a2a516d5480674cbf6c6a4497908f'
@@ -310,8 +310,8 @@ describe('#SLP Utils', () => {
it('should decode a genesis transaction', async () => {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.txDetailsSLPGenesis })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPGenesis] })
const txid =
'bd158c564dd4ef54305b14f44f8e94c44b649f246dab14bcb42fb0d0078b8a90'
@@ -336,8 +336,8 @@ describe('#SLP Utils', () => {
it('should decode a mint transaction', async () => {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.txDetailsSLPMint })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPMint] })
const txid =
'65f21bbfcd545e5eb515e38e861a9dfe2378aaa2c4e458eb9e59e4d40e38f3a4'
@@ -357,8 +357,8 @@ describe('#SLP Utils', () => {
it('should decode a send transaction', async () => {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.txDetailsSLPSend })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPSend] })
const txid =
'4f922565af664b6fdf0a1ba3924487344be721b3d8815c62cafc8a51e04a8afa'
@@ -372,8 +372,8 @@ describe('#SLP Utils', () => {
it('should properly decode a Genesis transaction with no minting baton', async () => {
// Mock the call to the REST API.
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.txDetailsSLPGenesisNoBaton })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPGenesisNoBaton] })
const txid =
'497291b8a1dfe69c8daea50677a3d31a5ef0e9484d8bebb610dac64bbc202fb7'
@@ -387,8 +387,8 @@ describe('#SLP Utils', () => {
it('should decode a send transaction with alternate encoding', async () => {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.txDetailsSLPSendAlt })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPSendAlt] })
const txid =
'd94357179775425ebc59c93173bd6dc9854095f090a2eb9dcfe9797398bc8eae'
@@ -411,8 +411,8 @@ describe('#SLP Utils', () => {
try {
// Mock the call to the REST API
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.mockInvalidSlpSend })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.mockInvalidSlpSend] })
const txid =
'a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415'
@@ -428,8 +428,8 @@ describe('#SLP Utils', () => {
it('should decode a NFT Parent transaction', async () => {
// Mock the call to the REST API.
sandbox
.stub(uut.Utils.axios, 'get')
.resolves({ data: mockData.txDetailsSLPNftGenesis })
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPNftGenesis] })
const txid =
'4ef6eb92950a13a69e97c2c02c7967d806aa874c0e2a6b5546a8880f2cd14bc4'
@@ -453,33 +453,52 @@ describe('#SLP Utils', () => {
assert.equal(data.qty, 1)
})
// it("should decode a NFT Child transaction", async () => {
// // Mock the call to the REST API.
// // sandbox
// // .stub(uut.Utils.axios, "get")
// // .resolves({ data: mockData.txDetailsSLPNftGenesis })
//
// const txid =
// "3de3766b10506c9156533f1639979e49d1884521543c13e4af73647df1ed3f76"
//
// const data = await uut.Utils.decodeOpReturn(txid)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
//
// // assert.property(data, "tokenType")
// // assert.property(data, "txType")
// // assert.property(data, "ticker")
// // assert.property(data, "name")
// // assert.property(data, "tokenId")
// // assert.property(data, "documentUri")
// // assert.property(data, "documentHash")
// // assert.property(data, "decimals")
// // assert.property(data, "mintBatonVout")
// // assert.property(data, "qty")
// //
// // assert.equal(data.tokenType, 129)
// // assert.equal(data.mintBatonVout, 2)
// // assert.equal(data.qty, 1)
// })
it('should decode a NFT Child transaction', async () => {
// Mock the call to the REST API.
sandbox
.stub(uut.Utils.axios, 'post')
.resolves({ data: [mockData.txDetailsSLPNftChild] })
const txid =
'eeddccc4d716f04157ea132ac93a48040fea34a6b57f3d8f0cccb7d1a731ab2b'
const data = await uut.Utils.decodeOpReturn(txid)
// console.log(`data: ${JSON.stringify(data, null, 2)}`)
assert.property(data, 'tokenType')
assert.property(data, 'txType')
assert.property(data, 'ticker')
assert.property(data, 'name')
assert.property(data, 'tokenId')
assert.property(data, 'documentUri')
assert.property(data, 'documentHash')
assert.property(data, 'decimals')
assert.property(data, 'mintBatonVout')
assert.property(data, 'qty')
assert.equal(data.tokenType, 65)
assert.equal(data.mintBatonVout, 0)
assert.equal(data.qty, '1')
})
// 429 means the user is exceeding the rate limits.
it('should throw error when axios returns 429 status', async () => {
try {
// Mock the call to the REST API
sandbox.stub(uut.Utils.axios, 'post').rejects(mockData.mock429Error)
const txid =
'a60a522cc11ad7011b74e57fbabbd99296e4b9346bcb175dcf84efb737030415'
await uut.Utils.decodeOpReturn(txid)
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
assert.fail('Unexpect result')
} catch (err) {
console.log('err: ', err)
// assert.include(err.message, 'amount string size not 8 bytes')
}
})
})
describe('#tokenUtxoDetails', () => {