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)