diff --git a/src/ninsight.js b/src/ninsight.js index 250a22b..b9c2068 100644 --- a/src/ninsight.js +++ b/src/ninsight.js @@ -50,14 +50,16 @@ class Ninsight { * // { * // "txid": "d31dc2cf66fe4d3d3ae18e1065def58a64920746b1702b52f060e5edeea9883b", * // "vout": 1, - * // "value": "1000000", + * // "amount": 0.03608203, + * // "satoshis": 3608203, * // "height": 585570, * // "confirmations": 10392 * // }, * // { * // "txid": "41e9a118765ecf7a1ba4487c0863e23dba343cc5880381a72f0365ac2546c5fa", * // "vout": 0, - * // "value": "1000000", + * // "amount": 0.03608203, + * // "satoshis": 3608203, * // "height": 577125, * // "confirmations": 18837 * // } @@ -97,6 +99,73 @@ class Ninsight { } } + /** + * @api Ninsight.unconfirmed() unconfirmed() + * @apiName Ninsight Unconfirmed Utxo + * @apiGroup Ninsight + * @apiDescription Returns a list of unconfirmed UTXOs for an address. + * + * @apiExample Example usage: + * (async () => { + * try { + * let utxo = await bchjs.Ninsight.unconfirmed('bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c'); + * console.log(utxo); + * } catch(error) { + * console.error(error) + * } + * })() + * + * // [ + * // { + * // "txid": "d31dc2cf66fe4d3d3ae18e1065def58a64920746b1702b52f060e5edeea9883b", + * // "vout": 1, + * // "amount": 0.03608203, + * // "satoshis": 3608203, + * // "confirmations": 0 + * // "ts": 1559670801 + * // }, + * // { + * // "txid": "41e9a118765ecf7a1ba4487c0863e23dba343cc5880381a72f0365ac2546c5fa", + * // "vout": 0, + * // "amount": 0.03608203, + * // "satoshis": 3608203, + * // "confirmations": 0 + * // "ts": 1559670902 + * // } + * // ] + * + */ + async unconfirmed(address) { + try { + if (typeof address === "string") { + const response = await axios.post( + `${this.ninsightURL}/address/unconfirmed`, + { + addresses: [address] + }, + _this.axiosOptions + ) + + return response.data + } else if (Array.isArray(address)) { + const response = await axios.post( + `${this.ninsightURL}/address/unconfirmed`, + { + addresses: address + }, + _this.axiosOptions + ) + + return response.data + } + + throw new Error(`Input address must be a string or array of strings.`) + } catch (error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + } + /** * @api Ninsight.transactions() transactions() * @apiName Ninsight TX History diff --git a/test/unit/fixtures/ninsight-mock.js b/test/unit/fixtures/ninsight-mock.js index e3b6470..ca6e1cd 100644 --- a/test/unit/fixtures/ninsight-mock.js +++ b/test/unit/fixtures/ninsight-mock.js @@ -21,12 +21,31 @@ const utxo = { "OP_DUP OP_HASH160 2fe2c4c5ef359bb2fe1a849f891cecffbcfb4f77 OP_EQUALVERIFY OP_CHECKSIG" } +const unconfirmed = { + utxos: [ + { + txid: "3904ffe6f8fba4ceda5e887130f60fcb18bdc7dcee10392a57f89475c5c108f1", + vout: 0, + amount: 0.03608203, + satoshis: 3608203, + confirmations: 0, + ts: 1559670801 + } + ], + legacyAddress: "1AyWs8U4HUnTLmxxFiGoJbsXauRsvBrcKW", + cashAddress: "bitcoincash:qpkkjkhe29mqhqmu3evtq3dsnruuzl3rku6usknlh5", + slpAddress: "simpleledger:qpkkjkhe29mqhqmu3evtq3dsnruuzl3rkuk8mdxlf2", + scriptPubKey: "76a9146d695af951760b837c8e58b045b098f9c17e23b788ac" +} + +const utxoPost = [utxo, utxo] +const unconfirmedPost = [unconfirmed, unconfirmed] + const transactions = { pagesTotal: 1, txs: [ { - txid: - "ec7bc8349386e3e1939bbdc4f8092fdbdd6a380734e68486b558cd594c451d5b", + txid: "ec7bc8349386e3e1939bbdc4f8092fdbdd6a380734e68486b558cd594c451d5b", version: 2, locktime: 0, vin: [ @@ -95,12 +114,13 @@ const transactions = { currentPage: 0 } -const utxoPost = [utxo, utxo] const transactionsPost = [transactions, transactions] module.exports = { utxo, utxoPost, + unconfirmed, + unconfirmedPost, transactions, transactionsPost } diff --git a/test/unit/ninsight.js b/test/unit/ninsight.js index 8f7ebe8..67916e0 100644 --- a/test/unit/ninsight.js +++ b/test/unit/ninsight.js @@ -78,6 +78,70 @@ describe(`#Ninsight`, () => { assert.property(result[0], "asm") }) }) + + describe("#unconfirmed", () => { + it("should throw an error for improper input", async () => { + try { + const addr = 12345 + + await bchjs.Ninsight.unconfirmed(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + assert.include( + err.message, + "Input address must be a string or array of strings." + ) + } + }) + + it(`should POST utxos for a single address`, async () => { + // Stub the network call. + sandbox.stub(axios, "post").resolves({ data: mockData.unconfirmed }) + + const addr = "bitcoincash:qpkkjkhe29mqhqmu3evtq3dsnruuzl3rku6usknlh5" + + const result = await bchjs.Ninsight.unconfirmed(addr) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.property(result, "utxos") + assert.property(result, "legacyAddress") + assert.property(result, "cashAddress") + assert.property(result, "slpAddress") + assert.property(result, "scriptPubKey") + + assert.isArray(result.utxos) + + assert.property(result.utxos[0], "txid") + assert.property(result.utxos[0], "vout") + assert.property(result.utxos[0], "amount") + assert.property(result.utxos[0], "satoshis") + assert.property(result.utxos[0], "confirmations") + assert.property(result.utxos[0], "ts") + }) + + it(`should POST utxo details for an array of addresses`, async () => { + // Mock the network call. + sandbox.stub(axios, "post").resolves({ data: mockData.unconfirmedPost }) + + const addr = [ + "bitcoincash:qpkkjkhe29mqhqmu3evtq3dsnruuzl3rku6usknlh5", + "bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr" + ] + + const result = await bchjs.Ninsight.unconfirmed(addr) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.isArray(result[0].utxos) + + assert.property(result[0], "utxos") + assert.property(result[0], "legacyAddress") + assert.property(result[0], "cashAddress") + assert.property(result[0], "slpAddress") + assert.property(result[0], "scriptPubKey") + }) + }) + describe(`#transactions`, () => { it(`should throw an error for improper input`, async () => { try {