From 30604591bd0a0a62e42c5f5df810d26cde84d3c5 Mon Sep 17 00:00:00 2001 From: Daniel Gonzalez Date: Mon, 17 Jan 2022 13:37:29 -0400 Subject: [PATCH 1/3] feat(indexer): Added PSF SLP Indexer to bch-js --- src/bch-js.js | 3 + src/psf-slp-indexer.js | 292 +++++++++++++++++++++ test/unit/fixtures/psf-slp-indexer-mock.js | 130 +++++++++ test/unit/psf-slp-indexer.js | 273 +++++++++++++++++++ 4 files changed, 698 insertions(+) create mode 100644 src/psf-slp-indexer.js create mode 100644 test/unit/fixtures/psf-slp-indexer-mock.js create mode 100644 test/unit/psf-slp-indexer.js diff --git a/src/bch-js.js b/src/bch-js.js index 649aba4..9fc7be1 100644 --- a/src/bch-js.js +++ b/src/bch-js.js @@ -38,6 +38,7 @@ const Ecash = require('./ecash') // Indexers const Ninsight = require('./ninsight') const Electrumx = require('./electrumx') +const PsfSlpIndexer = require('./psf-slp-indexer') class BCHJS { constructor (config) { @@ -120,6 +121,8 @@ class BCHJS { this.DSProof = new DSProof(libConfig) this.eCash = new Ecash() + + this.PsfSlpIndexer = new PsfSlpIndexer(libConfig) } } diff --git a/src/psf-slp-indexer.js b/src/psf-slp-indexer.js new file mode 100644 index 0000000..f85af80 --- /dev/null +++ b/src/psf-slp-indexer.js @@ -0,0 +1,292 @@ +/* + This library interacts with the PSF slp indexer REST API endpoints operated + by FullStack.cash +*/ +// Public npm libraries +const axios = require('axios') + +// let _this + +class PsfSlpIndexer { + constructor (config) { + this.restURL = config.restURL + this.apiToken = config.apiToken + this.authToken = config.authToken + + if (this.authToken) { + // Add Basic Authentication token to the authorization header. + this.axiosOptions = { + headers: { + authorization: this.authToken + } + } + } else { + // Add JWT token to the authorization header. + this.axiosOptions = { + headers: { + authorization: `Token ${this.apiToken}` + } + } + } + + // _this = this + } + + /** + * @api PsfSlpIndexer.status() status() + * @apiName Status + * @apiGroup PSF SLP + * @apiDescription Return status from psf slp indexer. + * + * @apiExample Example usage: + * (async () => { + * try { + * let status = await bchjs.PsfSlpIndexer.status(); + * console.log(status); + * } catch(error) { + * console.error(error) + * } + * })() + * + * { + * "status": { + * "startBlockHeight": 543376, + * "syncedBlockHeight": 723249, + * "chainBlockHeight": 722679 + * } + * } + * + */ + async status () { + try { + const response = await axios.get( + `${this.restURL}psf/slp/status`, + this.axiosOptions + ) + return response.data + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + /** + * @api PsfSlpIndexer.balance() balance() + * @apiName SLP Balance + * @apiGroup PSF SLP + * @apiDescription Return slp balance for a single address. + * + * @apiExample Example usage: + * (async () => { + * try { + * let balance = await bchjs.PsfSlpIndexer.balance('bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n'); + * console.log(balance); + * } catch(error) { + * console.error(error) + * } + * })() + * + * { + * balance: { + * utxos: [ + * { + * txid: 'a24a6a4abf06fabd799ecea4f8fac6a9ff21e6a8dd6169a3c2ebc03665329db9', + * vout: 1, + * type: 'token', + * qty: '1800', + * tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * address: 'bitcoincash:qrqy3kj7r822ps6628vwqq5k8hyjl6ey3y4eea2m4s' + * } + * ], + * txs: [ + * { + * txid: '078b2c48ed1db0d5d5996f2889b8d847a49200d0a781f6aa6752f740f312688f', + * height: 717796 + * }, + * { + * txid: 'a24a6a4abf06fabd799ecea4f8fac6a9ff21e6a8dd6169a3c2ebc03665329db9', + * height: 717832 + * } + * ], + * balances: [ + * { + * tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * qty: '1800' + * } + * ] + * } + * } + * + */ + async balance (address) { + try { + // Handle single address. + if (typeof address === 'string') { + const response = await axios.post( + `${this.restURL}psf/slp/address`, + { address }, + this.axiosOptions + ) + return response.data + } + throw new Error('Input address must be a string.') + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + /** + * @api PsfSlpIndexer.tokenStats() tokenStats() + * @apiName Token Stats + * @apiGroup PSF SLP + * @apiDescription Return list stats for a single slp token. + * + * @apiExample Example usage: + * (async () => { + * try { + * let tokenStats = await bchjs.PsfSlpIndexer.tokenStats('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'); + * console.log(tokenStats); + * } catch(error) { + * console.error(error) + * } + * })() + * + * { + * tokenData: { + * type: 1, + * ticker: 'TROUT', + * name: "Trout's test token", + * tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * documentUri: 'troutsblog.com', + * documentHash: '', + * decimals: 2, + * mintBatonIsActive: true, + * tokensInCirculationBN: '100098953386', + * tokensInCirculationStr: '100098953386', + * blockCreated: 622414, + * totalBurned: '1046614', + * totalMinted: '100100000000' + * txs: [ + * { + * txid: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * height: 622414, + * type: 'GENESIS', + * qty: '100000000000' + * } + * ] + * } + * } + * + */ + + async tokenStats (tokenId) { + try { + // Handle single address. + if (typeof tokenId === 'string') { + const response = await axios.post( + `${this.restURL}psf/slp/token`, + { tokenId }, + this.axiosOptions + ) + return response.data + } + throw new Error('Input tokenId must be a string.') + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + + /** + * @api PsfSlpIndexer.txId() txId() + * @apiName SLP Transaction Data + * @apiGroup PSF SLP + * @apiDescription Return slp transaction data. + * + * @apiExample Example usage: + * (async () => { + * try { + * let txData = await bchjs.PsfSlpIndexer.txId('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'); + * console.log(txData); + * } catch(error) { + * console.error(error) + * } + * })() + * + * { + * txData: { + * txid: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * hash: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * version: 2, + * size: 339, + * locktime: 0, + * vin: [ + * { + * txid: '8370db30d94761ab9a11b71ecd22541151bf6125c8c613f0f6fab8ab794565a7', + * vout: 0, + * scriptSig: { + * asm: '304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4[ALL|FORKID] 02791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851', + * hex: '47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851' + * }, + * sequence: 4294967295, + * address: 'bitcoincash:qpvsg9vl9a5mlf37a7n3yce6pktdctn73qwgaqm3wq', + * value: 0.00051303, + * tokenQty: 0, + * tokenQtyStr: '0', + * tokenId: null + * } + * ], + * vout: [ + * { + * value: 0, + * n: 0, + * scriptPubKey: { + * asm: 'OP_RETURN 5262419 1 47454e45534953 54524f5554 54726f75742773207465737420746f6b656e 74726f757473626c6f672e636f6d 0 2 2 000000174876e800', + * hex: '6a04534c500001010747454e455349530554524f55541254726f75742773207465737420746f6b656e0e74726f757473626c6f672e636f6d4c000102010208000000174876e800', + * type: 'nulldata' + * }, + * tokenQtyStr: '0', + * tokenQty: 0 + * } + * ], + * hex: '0200000001a7654579abb8faf6f013c6c82561bf51115422cd1eb7119aab6147d930db7083000000006a47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851ffffffff040000000000000000476a04534c500001010747454e455349530554524f55541254726f75742773207465737420746f6b656e0e74726f757473626c6f672e636f6d4c000102010208000000174876e80022020000000000001976a914db4d39ceb7794ffe5d06855f249e1d3a7f1b024088ac22020000000000001976a914db4d39ceb7794ffe5d06855f249e1d3a7f1b024088accec20000000000001976a9145904159f2f69bfa63eefa712633a0d96dc2e7e8888ac00000000', + * blockhash: '0000000000000000009f65225a3e12e23a7ea057c869047e0f36563a1f410267', + * confirmations: 97398, + * time: 1581773131, + * blocktime: 1581773131, + * blockheight: 622414, + * isSlpTx: true, + * tokenTxType: 'GENESIS', + * tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * tokenType: 1, + * tokenTicker: 'TROUT', + * tokenName: "Trout's test token", + * tokenDecimals: 2, + * tokenUri: 'troutsblog.com', + * tokenDocHash: '', + * isValidSlp: true + * } + * } + * + */ + async txId (txid) { + try { + // Handle single address. + if (typeof txid === 'string') { + const response = await axios.post( + `${this.restURL}psf/slp/txid`, + { txid }, + this.axiosOptions + ) + return response.data + } + throw new Error('Input txid must be a string.') + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } +} + +module.exports = PsfSlpIndexer diff --git a/test/unit/fixtures/psf-slp-indexer-mock.js b/test/unit/fixtures/psf-slp-indexer-mock.js new file mode 100644 index 0000000..c5541a0 --- /dev/null +++ b/test/unit/fixtures/psf-slp-indexer-mock.js @@ -0,0 +1,130 @@ +/* + Mocking data for unit tests for the PSF SLP INDEXER library. +*/ + +'use strict' + +const tokenStats = { + tokenData: { + type: 1, + ticker: 'TP03', + name: 'Test Plugin 03', + tokenId: '13cad617d523c8eb4ab11fff19c010e0e0a4ea4360b58e0c8c955a45a146a669', + documentUri: 'fullstack.cash', + documentHash: '', + decimals: 0, + mintBatonIsActive: false, + tokensInCirculationBN: '1', + tokensInCirculationStr: '1', + blockCreated: 722420, + totalBurned: '0', + totalMinted: '1', + txs: [ + { + txid: '13cad617d523c8eb4ab11fff19c010e0e0a4ea4360b58e0c8c955a45a146a669', + height: 722420, + type: 'GENESIS', + qty: '1' + } + ] + } +} + +const txData = { + txData: { + txid: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + hash: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + version: 2, + size: 339, + locktime: 0, + vin: [ + { + txid: '8370db30d94761ab9a11b71ecd22541151bf6125c8c613f0f6fab8ab794565a7', + vout: 0, + scriptSig: { + asm: '304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4[ALL|FORKID] 02791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851', + hex: '47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851' + }, + sequence: 4294967295, + address: 'bitcoincash:qpvsg9vl9a5mlf37a7n3yce6pktdctn73qwgaqm3wq', + value: 0.00051303, + tokenQty: 0, + tokenQtyStr: '0', + tokenId: null + } + ], + vout: [ + { + value: 0, + n: 0, + scriptPubKey: { + asm: 'OP_RETURN 5262419 1 47454e45534953 54524f5554 54726f75742773207465737420746f6b656e 74726f757473626c6f672e636f6d 0 2 2 000000174876e800', + hex: '6a04534c500001010747454e455349530554524f55541254726f75742773207465737420746f6b656e0e74726f757473626c6f672e636f6d4c000102010208000000174876e800', + type: 'nulldata' + }, + tokenQtyStr: '0', + tokenQty: 0 + } + ], + hex: '0200000001a7654579abb8faf6f013c6c82561bf51115422cd1eb7119aab6147d930db7083000000006a47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851ffffffff040000000000000000476a04534c500001010747454e455349530554524f55541254726f75742773207465737420746f6b656e0e74726f757473626c6f672e636f6d4c000102010208000000174876e80022020000000000001976a914db4d39ceb7794ffe5d06855f249e1d3a7f1b024088ac22020000000000001976a914db4d39ceb7794ffe5d06855f249e1d3a7f1b024088accec20000000000001976a9145904159f2f69bfa63eefa712633a0d96dc2e7e8888ac00000000', + blockhash: '0000000000000000009f65225a3e12e23a7ea057c869047e0f36563a1f410267', + confirmations: 97398, + time: 1581773131, + blocktime: 1581773131, + blockheight: 622414, + isSlpTx: true, + tokenTxType: 'GENESIS', + tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + tokenType: 1, + tokenTicker: 'TROUT', + tokenName: "Trout's test token", + tokenDecimals: 2, + tokenUri: 'troutsblog.com', + tokenDocHash: '', + isValidSlp: true + } +} +const balance = { + balance: { + utxos: [ + { + txid: 'a24a6a4abf06fabd799ecea4f8fac6a9ff21e6a8dd6169a3c2ebc03665329db9', + vout: 1, + type: 'token', + qty: '1800', + tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + address: 'bitcoincash:qrqy3kj7r822ps6628vwqq5k8hyjl6ey3y4eea2m4s' + } + ], + txs: [ + { + txid: '078b2c48ed1db0d5d5996f2889b8d847a49200d0a781f6aa6752f740f312688f', + height: 717796 + }, + { + txid: 'a24a6a4abf06fabd799ecea4f8fac6a9ff21e6a8dd6169a3c2ebc03665329db9', + height: 717832 + } + ], + balances: [ + { + tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + qty: '1800' + } + ] + } +} + +const status = { + status: { + startBlockHeight: 543376, + syncedBlockHeight: 722860, + chainBlockHeight: 722679 + } +} +module.exports = { + tokenStats, + txData, + balance, + status +} diff --git a/test/unit/psf-slp-indexer.js b/test/unit/psf-slp-indexer.js new file mode 100644 index 0000000..1ce97e4 --- /dev/null +++ b/test/unit/psf-slp-indexer.js @@ -0,0 +1,273 @@ +const chai = require('chai') +const assert = chai.assert +const axios = require('axios') +const sinon = require('sinon') + +const BCHJS = require('../../src/bch-js') +const bchjs = new BCHJS() + +const mockData = require('./fixtures/psf-slp-indexer-mock') + +describe('#PsfSlpIndexer', () => { + let sandbox + beforeEach(() => (sandbox = sinon.createSandbox())) + afterEach(() => sandbox.restore()) + + describe('#status', () => { + it('should GET status', async () => { + // Stub the network call. + sandbox.stub(axios, 'get').resolves({ data: mockData.status }) + + const result = await bchjs.PsfSlpIndexer.status() + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + assert.property(result, 'status') + assert.property(result.status, 'startBlockHeight') + assert.property(result.status, 'syncedBlockHeight') + assert.property(result.status, 'chainBlockHeight') + }) + + it('should handle axios error', async () => { + try { + // Stub the network call. + sandbox.stub(axios, 'get').throws(new Error('test error')) + + await bchjs.PsfSlpIndexer.status() + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + assert.equal(true, false, 'Unexpected result!') + } catch (err) { + assert.include( + err.message, + 'test error' + ) + } + }) + it('should handle request error', async () => { + try { + // Stub the network call. + const testErr = new Error() + testErr.response = { data: { status: 422 } } + sandbox.stub(axios, 'get').throws(testErr) + + await bchjs.PsfSlpIndexer.status() + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + assert.equal(true, false, 'Unexpected result!') + } catch (err) { + assert.equal(err.status, 422) + } + }) + }) + + describe('#balance', () => { + it('should GET balance', async () => { + // Stub the network call. + sandbox.stub(axios, 'post').resolves({ data: mockData.balance }) + const addr = 'bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n' + const result = await bchjs.PsfSlpIndexer.balance(addr) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + assert.property(result, 'balance') + + assert.property(result.balance, 'utxos') + assert.property(result.balance, 'txs') + assert.property(result.balance, 'balances') + assert.isArray(result.balance.utxos) + assert.isArray(result.balance.txs) + assert.isArray(result.balance.balances) + }) + it('should throw an error for improper input', async () => { + try { + const addr = 12345 + + await bchjs.PsfSlpIndexer.balance(addr) + assert.equal(true, false, 'Unexpected result!') + } catch (err) { + // console.log(`err: `, err) + assert.include( + err.message, + 'Input address must be a string.' + ) + } + }) + it('should handle axios error', async () => { + try { + // Stub the network call. + sandbox.stub(axios, 'post').throws(new Error('test error')) + + const addr = 'bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n' + + await bchjs.PsfSlpIndexer.balance(addr) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + assert.equal(true, false, 'Unexpected result!') + } catch (err) { + assert.include( + err.message, + 'test error' + ) + } + }) + it('should handle request error', async () => { + try { + // Stub the network call. + const testErr = new Error() + testErr.response = { data: { status: 422 } } + sandbox.stub(axios, 'post').throws(testErr) + + const addr = 'bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n' + + await bchjs.PsfSlpIndexer.balance(addr) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + assert.equal(true, false, 'Unexpected result!') + } catch (err) { + assert.equal(err.status, 422) + } + }) + }) + + describe('#tokenStats', () => { + it('should GET token stats', async () => { + // Stub the network call. + sandbox.stub(axios, 'post').resolves({ data: mockData.tokenStats }) + + const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' + const result = await bchjs.PsfSlpIndexer.tokenStats(tokenId) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + assert.property(result, 'tokenData') + assert.property(result.tokenData, 'type') + assert.property(result.tokenData, 'ticker') + assert.property(result.tokenData, 'name') + assert.property(result.tokenData, 'tokenId') + assert.property(result.tokenData, 'documentUri') + assert.property(result.tokenData, 'documentHash') + assert.property(result.tokenData, 'decimals') + assert.property(result.tokenData, 'mintBatonIsActive') + assert.property(result.tokenData, 'tokensInCirculationBN') + assert.property(result.tokenData, 'tokensInCirculationStr') + assert.property(result.tokenData, 'blockCreated') + assert.property(result.tokenData, 'totalBurned') + assert.property(result.tokenData, 'totalMinted') + assert.property(result.tokenData, 'txs') + }) + it('should throw an error for improper input', async () => { + try { + const tokenId = 12345 + + await bchjs.PsfSlpIndexer.tokenStats(tokenId) + assert.equal(true, false, 'Unexpected result!') + } catch (err) { + // console.log(`err: `, err) + assert.include( + err.message, + 'Input tokenId must be a string.' + ) + } + }) + it('should handle axios error', async () => { + try { + // Stub the network call. + sandbox.stub(axios, 'post').throws(new Error('test error')) + + const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' + await bchjs.PsfSlpIndexer.tokenStats(tokenId) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + assert.equal(true, false, 'Unexpected result!') + } catch (err) { + assert.include( + err.message, + 'test error' + ) + } + }) + it('should handle request error', async () => { + try { + // Stub the network call. + const testErr = new Error() + testErr.response = { data: { status: 422 } } + sandbox.stub(axios, 'post').throws(testErr) + + const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' + await bchjs.PsfSlpIndexer.tokenStats(tokenId) + assert.equal(true, false, 'Unexpected result!') + } catch (err) { + assert.equal(err.status, 422) + } + }) + }) + + describe('#txId', () => { + it('should GET transaction data', async () => { + // Stub the network call. + sandbox.stub(axios, 'post').resolves({ data: mockData.txData }) + + const txid = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' + const result = await bchjs.PsfSlpIndexer.txId(txid) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + assert.property(result, 'txData') + assert.property(result.txData, 'txid') + assert.property(result.txData, 'hash') + assert.property(result.txData, 'version') + assert.property(result.txData, 'size') + assert.property(result.txData, 'locktime') + assert.property(result.txData, 'vin') + assert.property(result.txData, 'vout') + assert.property(result.txData, 'hex') + assert.property(result.txData, 'blockhash') + assert.property(result.txData, 'confirmations') + assert.property(result.txData, 'time') + assert.property(result.txData, 'blocktime') + assert.property(result.txData, 'blockheight') + assert.property(result.txData, 'isSlpTx') + assert.property(result.txData, 'tokenTxType') + assert.property(result.txData, 'tokenId') + assert.property(result.txData, 'tokenType') + assert.property(result.txData, 'tokenTicker') + assert.property(result.txData, 'tokenName') + assert.property(result.txData, 'tokenDecimals') + assert.property(result.txData, 'tokenUri') + assert.property(result.txData, 'tokenDocHash') + assert.property(result.txData, 'isValidSlp') + }) + it('should throw an error for improper input', async () => { + try { + const txid = 12345 + + await bchjs.PsfSlpIndexer.txId(txid) + assert.equal(true, false, 'Unexpected result!') + } catch (err) { + // console.log(`err: `, err) + assert.include( + err.message, + 'Input txid must be a string.' + ) + } + }) + it('should handle axios error', async () => { + try { + // Stub the network call. + sandbox.stub(axios, 'post').throws(new Error('test error')) + + const txid = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' + await bchjs.PsfSlpIndexer.txId(txid) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + assert.equal(true, false, 'Unexpected result!') + } catch (err) { + assert.include( + err.message, + 'test error' + ) + } + }) + it('should handle request error', async () => { + try { + // Stub the network call. + const testErr = new Error() + testErr.response = { data: { status: 422 } } + sandbox.stub(axios, 'post').throws(testErr) + + const txid = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' + await bchjs.PsfSlpIndexer.txId(txid) + assert.equal(true, false, 'Unexpected result!') + } catch (err) { + assert.equal(err.status, 422) + } + }) + }) +}) From dd5de1424ca33c26f4d05056fe227127940d2fb7 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Mon, 17 Jan 2022 14:33:49 -0800 Subject: [PATCH 2/3] fix(PsfSlpIndexer.tx): Renaming txId() to tx() --- src/psf-slp-indexer.js | 370 +++++++++--------- .../bchn/psf-slp-indexer.integration.js | 60 +++ test/unit/psf-slp-indexer.js | 63 ++- 3 files changed, 269 insertions(+), 224 deletions(-) create mode 100644 test/integration/chains/bchn/psf-slp-indexer.integration.js diff --git a/src/psf-slp-indexer.js b/src/psf-slp-indexer.js index f85af80..7a614ac 100644 --- a/src/psf-slp-indexer.js +++ b/src/psf-slp-indexer.js @@ -33,30 +33,30 @@ class PsfSlpIndexer { } /** - * @api PsfSlpIndexer.status() status() - * @apiName Status - * @apiGroup PSF SLP - * @apiDescription Return status from psf slp indexer. - * - * @apiExample Example usage: - * (async () => { - * try { - * let status = await bchjs.PsfSlpIndexer.status(); - * console.log(status); - * } catch(error) { - * console.error(error) - * } - * })() - * - * { - * "status": { - * "startBlockHeight": 543376, - * "syncedBlockHeight": 723249, - * "chainBlockHeight": 722679 - * } - * } - * - */ + * @api PsfSlpIndexer.status() status() + * @apiName Status + * @apiGroup PSF SLP + * @apiDescription Return status from psf slp indexer. + * + * @apiExample Example usage: + * (async () => { + * try { + * let status = await bchjs.PsfSlpIndexer.status(); + * console.log(status); + * } catch(error) { + * console.error(error) + * } + * })() + * + * { + * "status": { + * "startBlockHeight": 543376, + * "syncedBlockHeight": 723249, + * "chainBlockHeight": 722679 + * } + * } + * + */ async status () { try { const response = await axios.get( @@ -71,53 +71,53 @@ class PsfSlpIndexer { } /** - * @api PsfSlpIndexer.balance() balance() - * @apiName SLP Balance - * @apiGroup PSF SLP - * @apiDescription Return slp balance for a single address. - * - * @apiExample Example usage: - * (async () => { - * try { - * let balance = await bchjs.PsfSlpIndexer.balance('bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n'); - * console.log(balance); - * } catch(error) { - * console.error(error) - * } - * })() - * - * { - * balance: { - * utxos: [ - * { - * txid: 'a24a6a4abf06fabd799ecea4f8fac6a9ff21e6a8dd6169a3c2ebc03665329db9', - * vout: 1, - * type: 'token', - * qty: '1800', - * tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', - * address: 'bitcoincash:qrqy3kj7r822ps6628vwqq5k8hyjl6ey3y4eea2m4s' - * } - * ], - * txs: [ - * { - * txid: '078b2c48ed1db0d5d5996f2889b8d847a49200d0a781f6aa6752f740f312688f', - * height: 717796 - * }, - * { - * txid: 'a24a6a4abf06fabd799ecea4f8fac6a9ff21e6a8dd6169a3c2ebc03665329db9', - * height: 717832 - * } - * ], - * balances: [ - * { - * tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', - * qty: '1800' - * } - * ] - * } - * } - * - */ + * @api PsfSlpIndexer.balance() balance() + * @apiName SLP Balance + * @apiGroup PSF SLP + * @apiDescription Return slp balance for a single address. + * + * @apiExample Example usage: + * (async () => { + * try { + * let balance = await bchjs.PsfSlpIndexer.balance('bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n'); + * console.log(balance); + * } catch(error) { + * console.error(error) + * } + * })() + * + * { + * balance: { + * utxos: [ + * { + * txid: 'a24a6a4abf06fabd799ecea4f8fac6a9ff21e6a8dd6169a3c2ebc03665329db9', + * vout: 1, + * type: 'token', + * qty: '1800', + * tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * address: 'bitcoincash:qrqy3kj7r822ps6628vwqq5k8hyjl6ey3y4eea2m4s' + * } + * ], + * txs: [ + * { + * txid: '078b2c48ed1db0d5d5996f2889b8d847a49200d0a781f6aa6752f740f312688f', + * height: 717796 + * }, + * { + * txid: 'a24a6a4abf06fabd799ecea4f8fac6a9ff21e6a8dd6169a3c2ebc03665329db9', + * height: 717832 + * } + * ], + * balances: [ + * { + * tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * qty: '1800' + * } + * ] + * } + * } + * + */ async balance (address) { try { // Handle single address. @@ -137,48 +137,48 @@ class PsfSlpIndexer { } /** - * @api PsfSlpIndexer.tokenStats() tokenStats() - * @apiName Token Stats - * @apiGroup PSF SLP - * @apiDescription Return list stats for a single slp token. - * - * @apiExample Example usage: - * (async () => { - * try { - * let tokenStats = await bchjs.PsfSlpIndexer.tokenStats('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'); - * console.log(tokenStats); - * } catch(error) { - * console.error(error) - * } - * })() - * - * { - * tokenData: { - * type: 1, - * ticker: 'TROUT', - * name: "Trout's test token", - * tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', - * documentUri: 'troutsblog.com', - * documentHash: '', - * decimals: 2, - * mintBatonIsActive: true, - * tokensInCirculationBN: '100098953386', - * tokensInCirculationStr: '100098953386', - * blockCreated: 622414, - * totalBurned: '1046614', - * totalMinted: '100100000000' - * txs: [ - * { - * txid: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', - * height: 622414, - * type: 'GENESIS', - * qty: '100000000000' - * } - * ] - * } - * } - * - */ + * @api PsfSlpIndexer.tokenStats() tokenStats() + * @apiName Token Stats + * @apiGroup PSF SLP + * @apiDescription Return list stats for a single slp token. + * + * @apiExample Example usage: + * (async () => { + * try { + * let tokenStats = await bchjs.PsfSlpIndexer.tokenStats('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'); + * console.log(tokenStats); + * } catch(error) { + * console.error(error) + * } + * })() + * + * { + * tokenData: { + * type: 1, + * ticker: 'TROUT', + * name: "Trout's test token", + * tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * documentUri: 'troutsblog.com', + * documentHash: '', + * decimals: 2, + * mintBatonIsActive: true, + * tokensInCirculationBN: '100098953386', + * tokensInCirculationStr: '100098953386', + * blockCreated: 622414, + * totalBurned: '1046614', + * totalMinted: '100100000000' + * txs: [ + * { + * txid: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * height: 622414, + * type: 'GENESIS', + * qty: '100000000000' + * } + * ] + * } + * } + * + */ async tokenStats (tokenId) { try { @@ -199,78 +199,78 @@ class PsfSlpIndexer { } /** - * @api PsfSlpIndexer.txId() txId() - * @apiName SLP Transaction Data - * @apiGroup PSF SLP - * @apiDescription Return slp transaction data. - * - * @apiExample Example usage: - * (async () => { - * try { - * let txData = await bchjs.PsfSlpIndexer.txId('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'); - * console.log(txData); - * } catch(error) { - * console.error(error) - * } - * })() - * - * { - * txData: { - * txid: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', - * hash: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', - * version: 2, - * size: 339, - * locktime: 0, - * vin: [ - * { - * txid: '8370db30d94761ab9a11b71ecd22541151bf6125c8c613f0f6fab8ab794565a7', - * vout: 0, - * scriptSig: { - * asm: '304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4[ALL|FORKID] 02791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851', - * hex: '47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851' - * }, - * sequence: 4294967295, - * address: 'bitcoincash:qpvsg9vl9a5mlf37a7n3yce6pktdctn73qwgaqm3wq', - * value: 0.00051303, - * tokenQty: 0, - * tokenQtyStr: '0', - * tokenId: null - * } - * ], - * vout: [ - * { - * value: 0, - * n: 0, - * scriptPubKey: { - * asm: 'OP_RETURN 5262419 1 47454e45534953 54524f5554 54726f75742773207465737420746f6b656e 74726f757473626c6f672e636f6d 0 2 2 000000174876e800', - * hex: '6a04534c500001010747454e455349530554524f55541254726f75742773207465737420746f6b656e0e74726f757473626c6f672e636f6d4c000102010208000000174876e800', - * type: 'nulldata' - * }, - * tokenQtyStr: '0', - * tokenQty: 0 - * } - * ], - * hex: '0200000001a7654579abb8faf6f013c6c82561bf51115422cd1eb7119aab6147d930db7083000000006a47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851ffffffff040000000000000000476a04534c500001010747454e455349530554524f55541254726f75742773207465737420746f6b656e0e74726f757473626c6f672e636f6d4c000102010208000000174876e80022020000000000001976a914db4d39ceb7794ffe5d06855f249e1d3a7f1b024088ac22020000000000001976a914db4d39ceb7794ffe5d06855f249e1d3a7f1b024088accec20000000000001976a9145904159f2f69bfa63eefa712633a0d96dc2e7e8888ac00000000', - * blockhash: '0000000000000000009f65225a3e12e23a7ea057c869047e0f36563a1f410267', - * confirmations: 97398, - * time: 1581773131, - * blocktime: 1581773131, - * blockheight: 622414, - * isSlpTx: true, - * tokenTxType: 'GENESIS', - * tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', - * tokenType: 1, - * tokenTicker: 'TROUT', - * tokenName: "Trout's test token", - * tokenDecimals: 2, - * tokenUri: 'troutsblog.com', - * tokenDocHash: '', - * isValidSlp: true - * } - * } - * - */ - async txId (txid) { + * @api PsfSlpIndexer.tx() tx() + * @apiName SLP Transaction Data + * @apiGroup PSF SLP + * @apiDescription Return slp transaction data. + * + * @apiExample Example usage: + * (async () => { + * try { + * let txData = await bchjs.PsfSlpIndexer.tx('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2'); + * console.log(txData); + * } catch(error) { + * console.error(error) + * } + * })() + * + * { + * txData: { + * txid: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * hash: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * version: 2, + * size: 339, + * locktime: 0, + * vin: [ + * { + * txid: '8370db30d94761ab9a11b71ecd22541151bf6125c8c613f0f6fab8ab794565a7', + * vout: 0, + * scriptSig: { + * asm: '304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4[ALL|FORKID] 02791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851', + * hex: '47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851' + * }, + * sequence: 4294967295, + * address: 'bitcoincash:qpvsg9vl9a5mlf37a7n3yce6pktdctn73qwgaqm3wq', + * value: 0.00051303, + * tokenQty: 0, + * tokenQtyStr: '0', + * tokenId: null + * } + * ], + * vout: [ + * { + * value: 0, + * n: 0, + * scriptPubKey: { + * asm: 'OP_RETURN 5262419 1 47454e45534953 54524f5554 54726f75742773207465737420746f6b656e 74726f757473626c6f672e636f6d 0 2 2 000000174876e800', + * hex: '6a04534c500001010747454e455349530554524f55541254726f75742773207465737420746f6b656e0e74726f757473626c6f672e636f6d4c000102010208000000174876e800', + * type: 'nulldata' + * }, + * tokenQtyStr: '0', + * tokenQty: 0 + * } + * ], + * hex: '0200000001a7654579abb8faf6f013c6c82561bf51115422cd1eb7119aab6147d930db7083000000006a47304402207e9631c53dfc8a9a793d1916469628c6b7c5780c01c2f676d51ef21b0ba4926f022069feb471ec869a49f8d108d0aaba04e7cd36e60a7500109d86537f55698930d4412102791b19a39165dbd83403d6df268d44fd621da30581b0b6e5cb15a7101ed58851ffffffff040000000000000000476a04534c500001010747454e455349530554524f55541254726f75742773207465737420746f6b656e0e74726f757473626c6f672e636f6d4c000102010208000000174876e80022020000000000001976a914db4d39ceb7794ffe5d06855f249e1d3a7f1b024088ac22020000000000001976a914db4d39ceb7794ffe5d06855f249e1d3a7f1b024088accec20000000000001976a9145904159f2f69bfa63eefa712633a0d96dc2e7e8888ac00000000', + * blockhash: '0000000000000000009f65225a3e12e23a7ea057c869047e0f36563a1f410267', + * confirmations: 97398, + * time: 1581773131, + * blocktime: 1581773131, + * blockheight: 622414, + * isSlpTx: true, + * tokenTxType: 'GENESIS', + * tokenId: 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', + * tokenType: 1, + * tokenTicker: 'TROUT', + * tokenName: "Trout's test token", + * tokenDecimals: 2, + * tokenUri: 'troutsblog.com', + * tokenDocHash: '', + * isValidSlp: true + * } + * } + * + */ + async tx (txid) { try { // Handle single address. if (typeof txid === 'string') { diff --git a/test/integration/chains/bchn/psf-slp-indexer.integration.js b/test/integration/chains/bchn/psf-slp-indexer.integration.js new file mode 100644 index 0000000..8166552 --- /dev/null +++ b/test/integration/chains/bchn/psf-slp-indexer.integration.js @@ -0,0 +1,60 @@ +/* + Integration tests for the psf-slp-indexer.js library +*/ + +const assert = require('chai').assert + +const BCHJS = require('../../../../src/bch-js') +let bchjs + +describe('#psf-slp-indexer', () => { + beforeEach(async () => { + // Introduce a delay so that the BVT doesn't trip the rate limits. + if (process.env.IS_USING_FREE_TIER) await sleep(3000) + + bchjs = new BCHJS() + }) + + describe('#status', () => { + it('should return the status of the indexer.', async () => { + const result = await bchjs.PsfSlpIndexer.status() + // console.log('result: ', result) + + assert.property(result.status, 'startBlockHeight') + assert.property(result.status, 'syncedBlockHeight') + assert.property(result.status, 'chainBlockHeight') + }) + }) + + describe('#balance', () => { + it('should get balance data for an address.', async () => { + const addr = 'bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n' + + const result = await bchjs.PsfSlpIndexer.balance(addr) + // console.log('result: ', result) + + assert.property(result.balance, 'utxos') + assert.property(result.balance, 'txs') + assert.property(result.balance, 'balances') + }) + }) + + describe('#tokenStats', () => { + it('should get stats on a token', async () => { + const tokenId = + '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0' + + const result = await bchjs.PsfSlpIndexer.tokenStats(tokenId) + console.log('result: ', result) + + assert.property(result.tokenData, 'documentUri') + assert.property(result.tokenData, 'txs') + assert.property(result.tokenData, 'totalBurned') + }) + }) +}) + +// Promise-based sleep function +function sleep (ms) { + return new Promise(resolve => setTimeout(resolve, ms)) +} diff --git a/test/unit/psf-slp-indexer.js b/test/unit/psf-slp-indexer.js index 1ce97e4..f695cc7 100644 --- a/test/unit/psf-slp-indexer.js +++ b/test/unit/psf-slp-indexer.js @@ -35,10 +35,7 @@ describe('#PsfSlpIndexer', () => { // console.log(`result: ${JSON.stringify(result, null, 2)}`) assert.equal(true, false, 'Unexpected result!') } catch (err) { - assert.include( - err.message, - 'test error' - ) + assert.include(err.message, 'test error') } }) it('should handle request error', async () => { @@ -81,10 +78,7 @@ describe('#PsfSlpIndexer', () => { assert.equal(true, false, 'Unexpected result!') } catch (err) { // console.log(`err: `, err) - assert.include( - err.message, - 'Input address must be a string.' - ) + assert.include(err.message, 'Input address must be a string.') } }) it('should handle axios error', async () => { @@ -98,10 +92,7 @@ describe('#PsfSlpIndexer', () => { // console.log(`result: ${JSON.stringify(result, null, 2)}`) assert.equal(true, false, 'Unexpected result!') } catch (err) { - assert.include( - err.message, - 'test error' - ) + assert.include(err.message, 'test error') } }) it('should handle request error', async () => { @@ -127,7 +118,8 @@ describe('#PsfSlpIndexer', () => { // Stub the network call. sandbox.stub(axios, 'post').resolves({ data: mockData.tokenStats }) - const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' + const tokenId = + 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' const result = await bchjs.PsfSlpIndexer.tokenStats(tokenId) // console.log(`result: ${JSON.stringify(result, null, 2)}`) assert.property(result, 'tokenData') @@ -154,10 +146,7 @@ describe('#PsfSlpIndexer', () => { assert.equal(true, false, 'Unexpected result!') } catch (err) { // console.log(`err: `, err) - assert.include( - err.message, - 'Input tokenId must be a string.' - ) + assert.include(err.message, 'Input tokenId must be a string.') } }) it('should handle axios error', async () => { @@ -165,15 +154,13 @@ describe('#PsfSlpIndexer', () => { // Stub the network call. sandbox.stub(axios, 'post').throws(new Error('test error')) - const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' + const tokenId = + 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' await bchjs.PsfSlpIndexer.tokenStats(tokenId) // console.log(`result: ${JSON.stringify(result, null, 2)}`) assert.equal(true, false, 'Unexpected result!') } catch (err) { - assert.include( - err.message, - 'test error' - ) + assert.include(err.message, 'test error') } }) it('should handle request error', async () => { @@ -183,7 +170,8 @@ describe('#PsfSlpIndexer', () => { testErr.response = { data: { status: 422 } } sandbox.stub(axios, 'post').throws(testErr) - const tokenId = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' + const tokenId = + 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' await bchjs.PsfSlpIndexer.tokenStats(tokenId) assert.equal(true, false, 'Unexpected result!') } catch (err) { @@ -192,13 +180,14 @@ describe('#PsfSlpIndexer', () => { }) }) - describe('#txId', () => { + describe('#tx', () => { it('should GET transaction data', async () => { // Stub the network call. sandbox.stub(axios, 'post').resolves({ data: mockData.txData }) - const txid = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' - const result = await bchjs.PsfSlpIndexer.txId(txid) + const txid = + 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' + const result = await bchjs.PsfSlpIndexer.tx(txid) // console.log(`result: ${JSON.stringify(result, null, 2)}`) assert.property(result, 'txData') assert.property(result.txData, 'txid') @@ -229,14 +218,11 @@ describe('#PsfSlpIndexer', () => { try { const txid = 12345 - await bchjs.PsfSlpIndexer.txId(txid) + await bchjs.PsfSlpIndexer.tx(txid) assert.equal(true, false, 'Unexpected result!') } catch (err) { // console.log(`err: `, err) - assert.include( - err.message, - 'Input txid must be a string.' - ) + assert.include(err.message, 'Input txid must be a string.') } }) it('should handle axios error', async () => { @@ -244,15 +230,13 @@ describe('#PsfSlpIndexer', () => { // Stub the network call. sandbox.stub(axios, 'post').throws(new Error('test error')) - const txid = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' - await bchjs.PsfSlpIndexer.txId(txid) + const txid = + 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' + await bchjs.PsfSlpIndexer.tx(txid) // console.log(`result: ${JSON.stringify(result, null, 2)}`) assert.equal(true, false, 'Unexpected result!') } catch (err) { - assert.include( - err.message, - 'test error' - ) + assert.include(err.message, 'test error') } }) it('should handle request error', async () => { @@ -262,8 +246,9 @@ describe('#PsfSlpIndexer', () => { testErr.response = { data: { status: 422 } } sandbox.stub(axios, 'post').throws(testErr) - const txid = 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' - await bchjs.PsfSlpIndexer.txId(txid) + const txid = + 'a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2' + await bchjs.PsfSlpIndexer.tx(txid) assert.equal(true, false, 'Unexpected result!') } catch (err) { assert.equal(err.status, 422) From 7f4745f83cdf36a988174e1e9bf89de6a5db5ef8 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Mon, 17 Jan 2022 14:39:52 -0800 Subject: [PATCH 3/3] fix(psf-slp-indexer): Added integration tests --- .../chains/bchn/psf-slp-indexer.integration.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test/integration/chains/bchn/psf-slp-indexer.integration.js b/test/integration/chains/bchn/psf-slp-indexer.integration.js index 8166552..979510d 100644 --- a/test/integration/chains/bchn/psf-slp-indexer.integration.js +++ b/test/integration/chains/bchn/psf-slp-indexer.integration.js @@ -45,13 +45,27 @@ describe('#psf-slp-indexer', () => { '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0' const result = await bchjs.PsfSlpIndexer.tokenStats(tokenId) - console.log('result: ', result) + // console.log('result: ', result) assert.property(result.tokenData, 'documentUri') assert.property(result.tokenData, 'txs') assert.property(result.tokenData, 'totalBurned') }) }) + + describe('#tx', () => { + it('should get hydrated tx data', async () => { + const txid = + '83361c34cac2ea7f9ca287fca57a96cc0763719f0cdf4850f9696c1e68eb635c' + + const result = await bchjs.PsfSlpIndexer.tx(txid) + // console.log('result: ', result) + + assert.property(result.txData, 'vin') + assert.property(result.txData, 'vout') + assert.property(result.txData, 'isValidSlp') + }) + }) }) // Promise-based sleep function