Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

dashsight

Package Overview
Dependencies
Maintainers
2
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dashsight - npm Package Compare versions

Comparing version 1.6.0 to 1.6.1

6

bin/ws-listen.js

@@ -62,8 +62,2 @@ #!/usr/bin/env node

console.error(err.stack || err);
if (err.response) {
console.error(err.response.statusCode);
console.error(err.response.statusText);
console.error(err.response.headers);
console.error(err.response.body);
}
});

170

dashsight.js

@@ -8,2 +8,12 @@ (function (exports) {

/**
* @type {RequestInit} defaultOpts
*/
let defaultOpts = {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
};
const DUFFS = 100000000;

@@ -22,6 +32,10 @@

/** @typedef {import('./').GetCoreUtxos} GetCoreUtxos */
/** @typedef {import('./').GetMultiCoreUtxos} GetMultiCoreUtxos */
/** @typedef {import('./').InstantBalance} InstantBalance */
/** @typedef {import('./').GetInstantBalance} GetInstantBalance */
/** @typedef {import('./').GetInstantBalances} GetInstantBalances */
/** @typedef {import('./').GetTx} GetTx */
/** @typedef {import('./').GetTxs} GetTxs */
/** @typedef {import('./').GetUtxos} GetUtxos */
/** @typedef {import('./').GetAllUtxos} GetAllUtxos */
/** @typedef {import('./').ToCoreUtxo} ToCoreUtxo */

@@ -103,2 +117,35 @@ /** @typedef {import('./').ToCoreUtxos} ToCoreUtxos */

/** @type {GetInstantBalances} */
insight.getInstantBalances = async function (addresses) {
let utxos = await insight.getAllUtxos(addresses);
/** @type {Record<String, InstantBalance>} */
let balanceOfAddrs = {}
utxos?.forEach(function (utxo) {
let balanceDuffs = utxo.satoshis || 0
let balanceDash = (balanceDuffs / DUFFS).toFixed(8);
/** @type {InstantBalance | any} */
let utxoAddrSum = balanceOfAddrs[utxo.address] || {}
let balance = utxoAddrSum.balance || 0
let balanceSat = utxoAddrSum.balanceSat || 0
let _utxoCount = utxoAddrSum._utxoCount || 0
let _utxoAmounts = utxoAddrSum._utxoAmounts || []
_utxoAmounts.push(utxo.satoshis)
utxoAddrSum = {
addrStr: utxo.address,
balance: balance + parseFloat(balanceDash),
balanceSat: balanceSat + balanceDuffs,
_utxoCount: _utxoCount + 1,
_utxoAmounts: _utxoAmounts,
}
balanceOfAddrs[utxo.address] = utxoAddrSum
});
return Object.values(balanceOfAddrs);
};
/** @type {GetUtxos} */

@@ -110,6 +157,39 @@ insight.getUtxos = async function (address) {

/** @type Array<InsightUtxo> */
let utxos = utxoResp.body;
let utxos = await utxoResp.json();
return utxos;
};
/** @type {(addresses: string | string[]) => String} */
insight._joinAddrs = function (addresses) {
let addrs = addresses
if (Array.isArray(addrs)) {
addrs = addrs.join(",")
}
return addrs
};
/** @type {GetAllUtxos} */
insight.getAllUtxos = async function (addresses) {
let addrs = insight._joinAddrs(addresses)
// GET `${insightBaseUrl}/addrs/${addrs}/utxo`
// also works unless you have too many addrs
// then you get a `414 URI Too Long` error
let utxoUrl = `${insightBaseUrl}/addrs/utxo`;
// thus POST is used
let utxoResp = await Dashsight.fetch(utxoUrl, {
method: 'POST',
body: {
// @ts-ignore
addrs,
},
});
/** @type Array<InsightUtxo> */
let utxos = await utxoResp.json();
return utxos;
};
/** @type {GetCoreUtxos} */

@@ -127,2 +207,8 @@ insight.getCoreUtxos = async function (address) {

/** @type {GetMultiCoreUtxos} */
insight.getMultiCoreUtxos = async function (addresses) {
let utxos = await insight.getAllUtxos(addresses);
return insight.toCoreUtxos(utxos);
};
/** @type {GetTx} */

@@ -133,5 +219,4 @@ insight.getTx = async function (txid) {

/** @type {InsightTx} */
//@ts-ignore
let data = txResp.body;
/** @type InsightTx */
let data = await txResp.json();
return data;

@@ -146,4 +231,3 @@ };

/** @type {InsightTxResponse} */
//@ts-ignore
let body = txResp.body;
let body = await txResp.json();

@@ -165,7 +249,7 @@ let data = await getAllPages(body, addr, maxPages);

);
let nextBody = nextResp.body;
nextResp = await nextResp.json();
// Note: this could still be wrong, but I don't think we have
// a better way to page so... whatever
// @ts-ignore
body.txs = body.txs.concat(nextBody?.txs);
body.txs = body.txs.concat(nextResp?.txs);
}

@@ -192,3 +276,3 @@ return body;

}
return txResp.body;
return txResp.json();
};

@@ -225,4 +309,4 @@

// consumed as an input
tx.vout.forEach(addUnspentOutputs);
tx.vin.forEach(removeSpentOutputs);
tx.vout.forEach(addUnspentOutputs);

@@ -287,68 +371,15 @@ /**

/** @type {HeadersInit} */
let defaultHeaders = {
Accept: "application/json",
"Content-Type": "application/json",
};
/**
* @param {String | URL | Request} url
* @param {RequestInit} [_opts]
* @param {RequestInit} [opts]
*/
Dashsight.fetch = async function dashfetch(url, _opts) {
let opts = Object.assign({ headers: {} }, _opts);
Object.assign(opts.headers, defaultHeaders, _opts?.headers);
Dashsight.fetch = async function dashfetch(url, opts) {
opts = Object.assign({}, defaultOpts, opts);
if (opts.body) {
//@ts-ignore
let contentType = opts.headers["Content-Type"] || "";
let isJson = contentType.startsWith("application/json");
if (isJson) {
opts.body = JSON.stringify(opts.body);
}
opts.body = JSON.stringify(opts.body);
}
let resp = await fetch(url, opts);
let headers = Object.fromEntries(resp.headers.entries());
let rawBody = await resp.text();
let contentType = resp.headers.get("content-type") || "";
let isJson = contentType.startsWith("application/json");
/** @type {Object|Array<any>|String} */
let body = rawBody;
if (isJson) {
try {
body = JSON.parse(rawBody);
} catch (e) {
// ignore
}
}
let response = {
ok: resp.ok,
statusCode: resp.status, // backwards compat
statusText: resp.statusText,
headers: headers,
body: body,
toJSON: function () {
return {
ok: response.ok,
statusCode: response.statusCode,
statusText: response.statusText,
headers: headers,
body: body,
};
},
get status() {
console.warn(
"deprecated: please use either 'statusText' or 'statusCode' (node.js and browser both have 'status', but flipped)",
);
return resp.statusText;
},
_request: opts,
_response: resp,
};
if (resp.ok) {
return response;
return resp;
}

@@ -359,5 +390,4 @@

);
// @ts-ignore
err.response = response;
err.response = resp.json();
throw err;

@@ -364,0 +394,0 @@ };

@@ -11,3 +11,3 @@ (function (exports) {

* @prop {String} [baseUrl] - (deprecated by dashsocketBaseUrl) ex: https://insight.dash.org
* @prop {import('./').CookieStore?} cookieStore - only needed for insight APIs hosted behind an AWS load balancer
* @prop {CookieStore} cookieStore - only needed for insight APIs hosted behind an AWS load balancer
* @prop {Boolean} debug

@@ -51,6 +51,9 @@ * @prop {Function} onClose

let sidResp = await Ws.fetch(sidUrl);
let sidResp = await window.fetch(sidUrl, {
mode: "cors",
credentials: "include",
});
if (!sidResp.ok) {
let err = new Error("bad response");
//@ts-ignore
// TODO make error type consistent between browser and node?
err.response = sidResp;

@@ -61,3 +64,4 @@ throw err;

// ex: `97:0{"sid":"xxxx",...}`
let session = parseSession(sidResp.body || "");
let msg = await sidResp.text();
let session = parseSession(msg);
return session;

@@ -77,4 +81,6 @@ };

let subResp = await Ws.fetch(subUrl, {
let subResp = await window.fetch(subUrl, {
method: "POST",
mode: "cors",
credentials: "include",
headers: {

@@ -92,3 +98,3 @@ "Content-Type": "text/plain;charset=UTF-8",

return subResp.body;
return await subResp.text();
};

@@ -293,3 +299,3 @@

* @param {String} msg
* @returns {import('./').SocketIoHello}
* @returns {SocketIoHello}
*/

@@ -454,58 +460,2 @@ function parseSession(msg) {

};
/** @type {RequestInit} */
let defaultRequest = {
mode: "cors",
credentials: "include",
};
/**
* @param {String | URL | Request} url
* @param {RequestInit} [_opts]
*/
Ws.fetch = async function dashfetch(url, _opts) {
let opts = Object.assign(defaultRequest, _opts);
let resp = await fetch(url, opts);
// this will not have arrays, only strings
let headers = Object.fromEntries(resp.headers.entries());
let body = await resp.text();
let response = {
ok: resp.ok,
statusCode: resp.status, // backwards compat
statusText: resp.statusText,
headers: headers,
body: body,
toJSON: function () {
return {
ok: response.ok,
statusCode: response.statusCode,
statusText: response.statusText,
headers: headers,
body: body,
};
},
get status() {
console.warn(
"deprecated: please use either 'statusText' or 'statusCode' (node.js and browser both have 'status', but flipped)",
);
return resp.statusText;
},
_request: opts,
_response: resp,
};
if (resp.ok) {
return response;
}
let err = new Error(
`http request was ${resp.status}, not ok. See err.response for details.`,
);
// @ts-ignore
err.response = response;
throw err;
};
})(("undefined" !== typeof module && module.exports) || window);

@@ -9,6 +9,9 @@ "use strict";

* @prop {GetCoreUtxos} getCoreUtxos
* @prop {GetMultiCoreUtxos} getMultiCoreUtxos
* @prop {GetInstantBalance} getInstantBalance
* @prop {GetInstantBalances} getInstantBalances
* @prop {GetTx} getTx
* @prop {GetTxs} getTxs
* @prop {GetUtxos} getUtxos
* @prop {GetAllUtxos} getAllUtxos
* @prop {InstantSend} instantSend

@@ -33,2 +36,9 @@ * @prop {ToCoreUtxos} toCoreUtxos

/**
* Instant Balance is accurate with Instant Send
* @callback GetInstantBalances
* @param {String | Array<String>} addresses
* @returns {Promise<Array<InstantBalance>>}
*/
/**
* @callback GetUtxos

@@ -40,2 +50,8 @@ * @param {String} address

/**
* @callback GetAllUtxos
* @param {String | Array<String>} addresses
* @returns {Promise<Array<InsightUtxo>>}
*/
/**
* @callback GetCoreUtxos

@@ -49,2 +65,11 @@ * @param {String} address

/**
* @callback GetMultiCoreUtxos
* @param {String | Array<String>} addresses
* @returns {Promise<Array<CoreUtxo>>}
*
* @TODO handle multiple input addresses
*/
/**
* @callback GetTx

@@ -51,0 +76,0 @@ * @param {String} txid

{
"name": "dashsight",
"version": "1.6.0",
"version": "1.6.1",
"description": "SDK for Dash's flavor of the Insight API",

@@ -53,6 +53,7 @@ "main": "index.js",

"optionalDependencies": {
"dotenv": "^16.0.1",
"tough-cookie": "^4.1.2",
"ws": "^8.13.0"
"dotenv": "^16.0.1"
},
"dependencies": {
"dashtx": "^0.9.0-3"
},
"devDependencies": {

@@ -62,6 +63,4 @@ "@dashincubator/base58check": "^1.3.1",

"@dashincubator/secp256k1": "^1.7.1-1",
"@types/tough-cookie": "^4.0.2",
"dashtx": "^0.9.0-3"
},
"dependencies": {}
"@types/tough-cookie": "^4.0.2"
}
}

@@ -7,12 +7,6 @@ # [dashsight.js](https://github.com/dashhive/dashsight.js)

```sh
npm install --save dashsight@1.x
```bash
npm install --save dashsight
```
To use `WebSocket`s in Node.js:
```sh
npm install --save tough-cookie@4.x ws@8.x
```
# Usage

@@ -298,80 +292,8 @@

Send a signed transaction to Dash's Insight API for relay and broadcast to the
Send a _signed transaction_ to Dash's Insight API for relay and broadcast to the
Dash network.
See **full examples** in:
- [./examples/balance-transfer.js](/examples/balance-transfer.js).
- [./examples/multi-send.js](/examples/multi-send.js).
Abridged Example:
```js
"use strict";
let txHex = 'xxxxxxxx...';
let DashTx = require("dashtx");
let dashTx = DashTx.create({
version: 3,
sign: signTx,
toPublicKey: toPublicKey,
addrToPubKeyHash: addrToPubKeyHash,
});
async function signTx({ privateKey, hash }) {
let sigOpts = { canonical: true };
let sigBuf = await Secp256k1.sign(hash, privateKey, sigOpts);
return sigBuf;
}
async function toPublicKey(privKeyBuf) {
let Secp256k1 = require("@dashincubator/secp256k1");
let isCompressed = true;
let pubBuf = Secp256k1.getPublicKey(privKeyBuf, isCompressed);
return pubBuf;
}
async function addrToPubKeyHash(addr) {
let Base58Check = require("@dashincubator/base58check").Base58Check;
let b58c = Base58Check.create({
pubKeyHashVersion: "4c",
privateKeyVersion: "cc",
});
let parts = await b58c.verify(addr);
return parts.pubKeyHash;
}
// keys that correspond to the available utxos
let privateKeys = {
XmCyQ6qARLWXap74QubFMunngoiiA1QgCL: "YOUR_PRIVATE_KEY_HERE",
};
let coreUtxos = [
{
address: "XmCyQ6qARLWXap74QubFMunngoiiA1QgCL",
outputIndex: 0,
satoshis: 99809,
script: "76a91473640d816ff4161d8c881da78983903bf9eba2d988ac",
txId: "f92e66edc9c8da41de71073ef08d62c56f8752a3f4e29ced6c515e0b1c074a38",
},
];
let payments = [
{ address: `Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`, satoshis: 10000000 },
];
let txInfo = {
inputs: coreUtxos,
outputs: payments,
};
let keys = coreUtxos.map(function (utxo) {
let privHex = privateKeys[utxo.address];
let privBuf = Tx.utils.hexToU8(privHex);
return privBuf;
});
let tx = dashTx.hashAndSignAll(txInfo, keys);
let txHex = tx.transaction;
let result = await dashsight.instantSend(txHex);

@@ -382,7 +304,6 @@

Example transaction hex:
Example transaction hex (input): \
(inspect at <https://live.blockcypher.com/dash/decodetx/>)
```txt
```text
030000000187ab81e88e2c19ca354f33f14d5b43b60d171ac851eb97dddd271b510cadbdb0000000

@@ -400,1 +321,7 @@ 006b483045022100ec38c77b9f285d4c9aeeba36c1fac51bb88f7443185caf7eec21b170cc5d4062

```
Guides & Code Examples for creating and signing `txHex`:
- [How to create a txHex with DashTx + DashKeys](https://github.com/dashhive/DashSight.js/issues/27)
- [Balance Transfer + DashSight: ./examples/balance-transfer.js](/examples/balance-transfer.js).
- [Multi-Payout + DashSight: ./examples/multi-send.js](/examples/multi-send.js).
"use strict";
/** @type {import('../').CookieStore} */
/** @type CookieStore */
let Cookies = module.exports;

@@ -11,5 +11,3 @@

let jar = new Cookie.CookieJar(/*cookies_store*/);
//@ts-ignore
jar.setCookieAsync = require("util").promisify(jar.setCookie);
//@ts-ignore
jar.getCookiesAsync = require("util").promisify(jar.getCookies);

@@ -24,25 +22,19 @@ //cookies_store.saveAsync = require("util").promisify(cookies_store.save);

Cookies.set = async function _setCookie(url, resp) {
/** @type {Array<String>} */
let cookies;
let moreCookies = resp.headers["set-cookie"];
if (!moreCookies) {
return;
if (resp.headers["set-cookie"]) {
if (Array.isArray(resp.headers["set-cookie"])) {
cookies = resp.headers["set-cookie"].map(Cookie.parse);
} else {
cookies = [Cookie.parse(resp.headers["set-cookie"])];
}
}
if (!Array.isArray(moreCookies)) {
moreCookies = [moreCookies];
}
//@ts-ignore
cookies = moreCookies.map(Cookie.parse);
// let Cookie = //require('set-cookie-parser');
// Cookie.parse(resp, { decodeValues: true });
let ps = cookies.map(async function (cookie) {
//console.log('DEBUG cookie:', cookie.toJSON());
let jarOpts = { now: new Date() };
//@ts-ignore
await jar.setCookieAsync(cookie, url, jarOpts);
});
await Promise.all(ps);
await Promise.all(
cookies.map(async function (cookie) {
//console.log('DEBUG cookie:', cookie.toJSON());
await jar.setCookieAsync(cookie, url, { now: new Date() });
}),
);
//await cookies_store.saveAsync();

@@ -56,6 +48,3 @@ };

Cookies.get = async function _getCookie(url) {
//@ts-ignore
let cookieObj = await jar.getCookiesAsync(url);
let cookieStr = cookieObj.toString();
return cookieStr;
return (await jar.getCookiesAsync(url)).toString();
};

@@ -12,3 +12,3 @@ "use strict";

* @prop {String} [baseUrl] - (deprecated by dashsocketBaseUrl) ex: https://insight.dash.org
* @prop {import('../').CookieStore} cookieStore - only needed for insight APIs hosted behind an AWS load balancer
* @prop {CookieStore} cookieStore - only needed for insight APIs hosted behind an AWS load balancer
* @prop {Boolean} debug

@@ -52,15 +52,18 @@ * @prop {Function} onClose

let cookiesStr = await cookieStore.get(sidUrl);
let sidResp = await Ws.fetch(sidUrl, {
let cookies = await cookieStore.get(sidUrl);
let sidResp = await fetch(sidUrl, {
//agent: httpAgent,
//@ts-ignore - request function is not typed correctly
headers: {
Cookie: cookiesStr,
Cookie: cookies,
},
});
if (!sidResp.ok) {
console.error(await sidResp.json());
throw new Error("bad response");
}
await cookieStore.set(sidUrl, sidResp);
// ex: `97:0{"sid":"xxxx",...}`
let msg = sidResp.body || "";
let msg = await sidResp.json();
let colonIndex = msg.indexOf(":");

@@ -97,4 +100,4 @@ // 0 is CONNECT, which will always follow our first message

let cookiesStr = await cookieStore.get(subUrl);
let subResp = await Ws.fetch(subUrl, {
let cookies = await cookieStore.get(subUrl);
let subResp = await fetch(subUrl, {
//agent: httpAgent,

@@ -104,11 +107,14 @@ method: "POST",

"Content-Type": "text/plain;charset=UTF-8",
Cookie: cookiesStr,
Cookie: cookies,
},
body: body,
});
if (!subResp.ok) {
console.error(await subResp.json());
throw new Error("bad response");
}
await cookieStore.set(subUrl, subResp);
// "ok"
return subResp.body;
return await subResp.json();
};

@@ -148,5 +154,4 @@

let url = `ws${dashsocketBaseUrlPart}/?EIO=3&transport=websocket&sid=${sid}`;
let sidUrl = `${dashsocketBaseUrl}/`;
let cookiesStr = await cookieStore.get(sidUrl);
let cookies = await cookieStore.get(`${dashsocketBaseUrl}/`);
let ws = new WSClient(url, {

@@ -157,3 +162,3 @@ //agent: httpAgent,

headers: {
Cookie: cookiesStr,
Cookie: cookies,
},

@@ -173,23 +178,8 @@ });

onError(err);
return;
} else {
console.error("WebSocket Error:");
console.error(err);
}
console.error("WebSocket Error:");
console.error(err);
});
ws.once("unexpected-response", function (req, res) {
let err = new Error("unexpected-response");
//@ts-ignore
err.response = res;
if (onError) {
onError(err);
return;
}
console.error("WebSocket Unexpected Response:");
console.error(err);
});
ws.once("message", function message(data) {

@@ -281,3 +271,3 @@ if ("3probe" === data.toString()) {

/** @type {import('../').InsightPush} */
/** @type {InsightPush} */
let [evname, data] = JSON.parse(msg.slice(2));

@@ -324,3 +314,3 @@ if (onMessage) {

* @param {String} evname
* @param {import('../').InsightSocketEventData} data
* @param {InsightSocketEventData} data
*/

@@ -381,4 +371,4 @@

* @param {Number} [maxTxLockWait]
* @param {Partial<WsOpts>} [opts]
* @returns {Promise<import('../').SocketPayment>}
* @param {WsOpts} [opts]
* @returns {Promise<SocketPayment>}
*/

@@ -397,3 +387,3 @@ Ws.waitForVout = async function (

// Listen for Response
/** @type {import('../').SocketPayment} */
/** @type SocketPayment */
let mempoolTx;

@@ -404,3 +394,3 @@ return await Ws.listen(dashsocketBaseUrl, findResponse, opts);

* @param {String} evname
* @param {import('../').InsightSocketEventData} data
* @param {InsightSocketEventData} data
*/

@@ -422,33 +412,30 @@ function findResponse(evname, data) {

// TODO should fetch tx and match hotwallet as vin
data.vout.some(
/** @param {Record<String,Number>} vout */
function (vout) {
if (!(addr in vout)) {
return false;
}
data.vout.some(function (vout) {
if (!(addr in vout)) {
return false;
}
let duffs = vout[addr];
if (amount && duffs !== amount) {
return false;
}
let duffs = vout[addr];
if (amount && duffs !== amount) {
return false;
}
let newTx = {
address: addr,
timestamp: now,
txid: data.txid,
satoshis: duffs,
txlock: data.txlock,
};
let newTx = {
address: addr,
timestamp: now,
txid: data.txid,
satoshis: duffs,
txlock: data.txlock,
};
if ("txlock" !== evname) {
if (!mempoolTx) {
mempoolTx = newTx;
}
return false;
if ("txlock" !== evname) {
if (!mempoolTx) {
mempoolTx = newTx;
}
return false;
}
result = newTx;
return true;
},
);
result = newTx;
return true;
});

@@ -459,76 +446,2 @@ return result;

/** @type {RequestInit} */
let defaultRequest = {
mode: "cors",
credentials: "include",
};
/**
* @param {String | URL | Request} url
* @param {RequestInit} [_opts]
*/
Ws.fetch = async function dashfetch(url, _opts) {
let opts = Object.assign(defaultRequest, _opts);
let resp = await fetch(url, opts);
/** @type {Record<String,String|Array<String>>} */
let headers = {};
// for the Set-Cookie headers through AWS load balancer
let headerEntries = resp.headers.entries();
for (let [key, value] of headerEntries) {
if (!headers[key]) {
headers[key] = value;
continue;
}
let isArray = Array.isArray(headers[key]);
if (!isArray) {
//@ts-ignore
headers[key] = [headers[key]];
}
//@ts-ignore
headers[key].push(value);
}
let body = await resp.text();
let response = {
ok: resp.ok,
statusCode: resp.status, // backwards compat
statusText: resp.statusText,
headers: headers,
body: body,
toJSON: function () {
return {
ok: response.ok,
statusCode: response.statusCode,
statusText: response.statusText,
headers: response.headers,
body: response.body,
};
},
get status() {
console.warn(
"deprecated: please use either 'statusText' or 'statusCode' (node.js and browser both have 'status', but flipped)",
);
return resp.statusText;
},
_request: opts,
_response: resp,
};
if (resp.ok) {
return response;
}
let err = new Error(
`http request was ${resp.status}, not ok. See err.response for details.`,
);
// @ts-ignore
err.response = response;
throw err;
};
/*

@@ -535,0 +448,0 @@ async function sleep(ms) {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc