feat: a pretty decent, tested, working SDK + CLI
[crowdnode.js/.git] / lib / insight.js
1 "use strict";
2
3 let Insight = module.exports;
4
5 let request = require("./request.js");
6
7 /**
8  * @param {Object} opts
9  * @param {String} opts.baseUrl
10  */
11 Insight.create = function ({ baseUrl }) {
12   let insight = {};
13
14   /**
15    * Don't use this with instantSend
16    * @param {String} address
17    * @returns {Promise<InsightBalance>}
18    */
19   insight.getBalance = async function (address) {
20     console.warn(`warn: getBalance(pubkey) doesn't account for instantSend,`);
21     console.warn(`      consider (await getUtxos()).reduce(countSatoshis)`);
22     let txUrl = `${baseUrl}/insight-api/addr/${address}/?noTxList=1`;
23     let txResp = await request({ url: txUrl, json: true });
24
25     /** @type {InsightBalance} */
26     let data = txResp.body;
27     return data;
28   };
29
30   /**
31    * @param {String} address
32    * @returns {Promise<Array<InsightUtxo>>}
33    */
34   insight.getUtxos = async function (address) {
35     let utxoUrl = `${baseUrl}/insight-api/addr/${address}/utxo`;
36     let utxoResp = await request({ url: utxoUrl, json: true });
37
38     /** @type Array<InsightUtxo> */
39     let utxos = utxoResp.body;
40     return utxos;
41   };
42
43   /**
44    * @param {String} txid
45    * @returns {Promise<InsightTx>}
46    */
47   insight.getTx = async function (txid) {
48     let txUrl = `${baseUrl}/insight-api/tx/${txid}`;
49     let txResp = await request({ url: txUrl, json: true });
50
51     /** @type InsightTx */
52     let data = txResp.body;
53     return data;
54   };
55
56   /**
57    * @param {String} addr
58    * @param {Number} maxPages
59    * @returns {Promise<InsightTxResponse>}
60    */
61   insight.getTxs = async function (addr, maxPages) {
62     let txUrl = `${baseUrl}/insight-api/txs?address=${addr}&pageNum=0`;
63     let txResp = await request({ url: txUrl, json: true });
64
65     /** @type {InsightTxResponse} */
66     let body = txResp.body;
67
68     let data = await getAllPages(body, addr, maxPages);
69     return data;
70   };
71
72   /**
73    * @param {InsightTxResponse} body
74    * @param {String} addr
75    * @param {Number} maxPages
76    */
77   async function getAllPages(body, addr, maxPages) {
78     let pagesTotal = Math.min(body.pagesTotal, maxPages);
79     for (let cursor = 1; cursor < pagesTotal; cursor += 1) {
80       let nextResp = await request({
81         url: `${baseUrl}/insight-api/txs?address=${addr}&pageNum=${cursor}`,
82         json: true,
83       });
84       // Note: this could still be wrong, but I don't think we have
85       // a better way to page so... whatever
86       body.txs = body.txs.concat(nextResp.body.txs);
87     }
88     return body;
89   }
90
91   /**
92    * @param {String} hexTx
93    */
94   insight.instantSend = async function (hexTx) {
95     let instUrl = `${baseUrl}/insight-api-dash/tx/sendix`;
96     let reqObj = {
97       method: "POST",
98       url: instUrl,
99       form: {
100         rawtx: hexTx,
101       },
102     };
103     let txResp = await request(reqObj);
104     if (!txResp.ok) {
105       // TODO better error check
106       throw new Error(JSON.stringify(txResp.body, null, 2));
107     }
108     return txResp.toJSON();
109   };
110
111   return insight;
112 };