diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index d5d0f1ef7..000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "env": { - "es2024": true, - "node": true - }, - "extends": "eslint:recommended", - "overrides": [ - { - "files": ["*.mjs"], - "parserOptions": { - "sourceType": "module" - } - }, - { - "files": ["*.cjs"], - "parserOptions": { - "sourceType": "script" - } - }, - { - "files": [ - "test/{,**/}*.{mjs,cjs,js}" - ], - "env": { - "mocha": true - }, - "globals": { - "register": "readable" - }, - "rules": { - "max-len": "off", - "prefer-arrow-callback": "off", - "no-return-assign": "off" - } - } - ], - "parserOptions": { - "ecmaVersion": "latest", - "ecmaFeatures": { - "globalReturn": true - }, - "requireConfigFile": false, - "sourceType": "script" - }, - "root": true, - "rules": { - "array-bracket-spacing": ["error", "never"], - "arrow-parens": ["error", "as-needed", { - "requireForBlockBody": true - }], - "arrow-spacing": "error", - "block-spacing": ["error", "always"], - "brace-style": ["error", "1tbs"], - "camelcase": ["error", { - "properties": "never" - }], - "comma-dangle": ["error", "never"], - "consistent-return": "error", - "eol-last": ["error", "always"], - "eqeqeq": ["error", "always", { - "null": "ignore" - }], - "func-name-matching": "error", - "indent": ["off", 2, { - "ArrayExpression": "off", - "SwitchCase": 1, - "CallExpression": { - "arguments": "off" - }, - "FunctionDeclaration": { - "parameters": "off" - }, - "FunctionExpression": { - "parameters": "off" - }, - "MemberExpression": "off", - "ObjectExpression": "off", - "ImportDeclaration": "off" - }], - "handle-callback-err": "off", - "linebreak-style": ["error", "unix"], - "max-len": ["error", { - "code": 80, - "ignorePattern": "function \\w+\\(", - "ignoreUrls": true - }], - "max-statements-per-line": ["error", { - "max": 1 - }], - "new-cap": ["error", { - "newIsCap": true, - "capIsNew": false - }], - "new-parens": "error", - "no-buffer-constructor": "error", - "no-console": "off", - "no-extra-semi": "off", - "no-fallthrough": "off", - "no-func-assign": "off", - "no-implicit-coercion": "error", - "no-multi-assign": "error", - "no-multiple-empty-lines": ["error", { - "max": 1 - }], - "no-nested-ternary": "error", - "no-param-reassign": "off", - "no-return-assign": "error", - "no-return-await": "off", - "no-shadow-restricted-names": "error", - "no-tabs": "error", - "no-trailing-spaces": "error", - "no-unused-vars": ["error", { - "vars": "all", - "args": "none", - "ignoreRestSiblings": false - }], - "no-use-before-define": ["error", { - "functions": false, - "classes": false - }], - "no-useless-escape": "off", - "no-var": "error", - "nonblock-statement-body-position": ["error", "below"], - "padded-blocks": ["error", "never"], - "prefer-arrow-callback": "error", - "prefer-const": ["error", { - "destructuring": "all", - "ignoreReadBeforeAssign": true - }], - "prefer-template": "off", - "quotes": ["error", "single"], - "semi": ["error", "always"], - "spaced-comment": ["error", "always", { - "exceptions": ["!"] - }], - "space-before-blocks": "error", - "strict": "error", - "unicode-bom": ["error", "never"], - "valid-jsdoc": "error", - "wrap-iife": ["error", "inside"] - } -} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e469c7ce2..b972c06c4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,11 +13,14 @@ jobs: - name: Setup uses: actions/setup-node@v4 with: - node-version: 18.x + node-version: 22.x - name: Install dependencies run: npm install --location=global bslint @hns-dev/bsdoc + - name: Install bslintrc + run: npm install bslintrc + - name: Lint run: npm run lint @@ -34,7 +37,7 @@ jobs: - name: Setup uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 22.x - name: Install dependencies run: sudo apt-get update && sudo apt-get install -y libunbound-dev | diff --git a/eslint.config.cjs b/eslint.config.cjs new file mode 100644 index 000000000..4dbc390ed --- /dev/null +++ b/eslint.config.cjs @@ -0,0 +1,54 @@ +'use strict'; + +const rc = require('bslintrc'); + +module.exports = [ + rc.configs.recommended, + rc.configs.bcoin, + { + languageOptions: { + globals: { + ...rc.globals.node + }, + ecmaVersion: 'latest' + } + }, + { + files: [ + 'bin/cli', + 'bin/hsd', + 'bin/node', + 'bin/hs-seeder', + 'bin/node', + 'bin/_seeder', + 'bin/spvnode', + 'bin/wallet', + 'bin/hsd-cli', + 'bin/hsw-cli', + 'etc/genesis', + '**/*.cjs', + '**/*.mjs', + '**/*.js', + '*.js', + '*.mjs', + '*.cjs' + ], + languageOptions: { + sourceType: 'commonjs' + } + }, + { + files: ['test/{,**/}*.{js,cjs,mjs}'], + languageOptions: { + globals: { + ...rc.globals.mocha, + register: 'readable' + } + }, + rules: { + 'max-len': 'off', + 'prefer-arrow-callback': 'off', + 'no-return-assign': 'off' + } + } +]; diff --git a/lib/coins/coinview.js b/lib/coins/coinview.js index b958784bd..93daef990 100644 --- a/lib/coins/coinview.js +++ b/lib/coins/coinview.js @@ -313,7 +313,7 @@ class CoinView extends View { * Get an HD path by prevout. * Implemented in {@link WalletCoinView}. * @param {Outpoint} prevout - * @returns {null} + * @returns {*} */ getPath(prevout) { @@ -404,7 +404,7 @@ class CoinView extends View { * Get a single path by input. * Implemented in {@link WalletCoinView}. * @param {Input} input - * @returns {null} + * @returns {*} */ getPathFor(input) { diff --git a/lib/hd/common.js b/lib/hd/common.js index d5b8482cd..0240b0c3a 100644 --- a/lib/hd/common.js +++ b/lib/hd/common.js @@ -118,7 +118,7 @@ common.isMaster = function isMaster(key) { /** * Test whether the key is (most likely) a BIP44 account key. * @param {HDPrivateKey|HDPublicKey} key - * @param {Number?} account + * @param {Number?} [account] * @returns {Boolean} */ diff --git a/lib/hd/public.js b/lib/hd/public.js index f8f263056..84e72007c 100644 --- a/lib/hd/public.js +++ b/lib/hd/public.js @@ -237,7 +237,7 @@ class HDPublicKey extends bio.Struct { /** * Test whether the key is (most likely) a BIP44 account key. * @method - * @param {Number?} account + * @param {Number?} [account] * @returns {Boolean} */ diff --git a/lib/primitives/coin.js b/lib/primitives/coin.js index cb83b7f36..fb97f2730 100644 --- a/lib/primitives/coin.js +++ b/lib/primitives/coin.js @@ -314,6 +314,7 @@ class Coin extends Output { * @param {TX} tx * @param {Number} index * @param {Number} height + * @returns {this} */ fromTX(tx, index, height) { diff --git a/lib/primitives/keyring.js b/lib/primitives/keyring.js index 902015b8d..c0c44782e 100644 --- a/lib/primitives/keyring.js +++ b/lib/primitives/keyring.js @@ -106,6 +106,7 @@ class KeyRing extends bio.Struct { /** * Inject data from private key. * @param {Buffer} key + * @returns {this} */ fromPrivate(key) { diff --git a/lib/wallet/account.js b/lib/wallet/account.js index 582d3a747..84f3f658f 100644 --- a/lib/wallet/account.js +++ b/lib/wallet/account.js @@ -13,7 +13,14 @@ const Path = require('./path'); const common = require('./common'); const Script = require('../script/script'); const WalletKey = require('./walletkey'); -const {HDPublicKey} = require('../hd/hd'); +const HDPublicKey = require('../hd/public'); + +/** @typedef {import('bdb').DB} DB */ +/** @typedef {ReturnType} Batch */ +/** @typedef {import('../types').BufioWriter} BufioWriter */ +/** @typedef {import('./walletdb')} WalletDB */ +/** @typedef {import('./masterkey')} MasterKey */ +/** @typedef {import('../primitives/address')} Address */ /** * Account @@ -28,6 +35,7 @@ class Account extends bio.Struct { /** * Create an account. * @constructor + * @param {WalletDB} wdb * @param {Object} options */ @@ -36,22 +44,28 @@ class Account extends bio.Struct { assert(wdb, 'Database is required.'); + /** @type {WalletDB} */ this.wdb = wdb; this.network = wdb.network; this.wid = 0; + /** @type {String|null} */ this.id = null; this.accountIndex = 0; + /** @type {String|null} */ this.name = null; this.initialized = false; this.watchOnly = false; + /** @type {Account.types} */ this.type = Account.types.PUBKEYHASH; this.m = 1; this.n = 1; this.receiveDepth = 0; this.changeDepth = 0; this.lookahead = 200; + /** @type {HDPublicKey|null} */ this.accountKey = null; + /** @type {HDPublicKey[]} */ this.keys = []; if (options) @@ -60,8 +74,8 @@ class Account extends bio.Struct { /** * Inject properties from options object. - * @private * @param {Object} options + * @returns {this} */ fromOptions(options) { @@ -155,7 +169,7 @@ class Account extends bio.Struct { /** * Inject properties from options object. - * @private + * @param {WalletDB} wdb * @param {Object} options */ @@ -168,6 +182,7 @@ class Account extends bio.Struct { * the first addresses along with the lookahead * addresses). Called automatically from the * walletdb. + * @param {Batch} b * @returns {Promise} */ @@ -193,6 +208,7 @@ class Account extends bio.Struct { * @param {HDPublicKey} key - Account (bip44) * key (can be in base58 form). * @throws Error on non-hdkey/non-accountkey. + * @returns {Boolean} - Whether the key was added. */ pushKey(key) { @@ -230,6 +246,7 @@ class Account extends bio.Struct { * @param {HDPublicKey} key - Account (bip44) * key (can be in base58 form). * @throws Error on non-hdkey/non-accountkey. + * @returns {Boolean} - Whether the key was removed. */ spliceKey(key) { @@ -254,8 +271,9 @@ class Account extends bio.Struct { /** * Add a public account key to the account (multisig). * Saves the key in the wallet database. + * @param {Batch} b * @param {HDPublicKey} key - * @returns {Promise} + * @returns {Promise} */ async addSharedKey(b, key) { @@ -275,7 +293,7 @@ class Account extends bio.Struct { /** * Ensure accounts are not sharing keys. * @private - * @returns {Promise} + * @returns {Promise} */ async hasDuplicate() { @@ -291,8 +309,9 @@ class Account extends bio.Struct { /** * Remove a public account key from the account (multisig). * Remove the key from the wallet database. + * @param {Batch} b * @param {HDPublicKey} key - * @returns {Promise} + * @returns {Boolean} */ removeSharedKey(b, key) { @@ -308,26 +327,29 @@ class Account extends bio.Struct { /** * Create a new receiving address (increments receiveDepth). - * @returns {WalletKey} + * @param {Batch} b + * @returns {Promise} */ - createReceive() { - return this.createKey(0); + createReceive(b) { + return this.createKey(b, 0); } /** * Create a new change address (increments changeDepth). - * @returns {WalletKey} + * @param {Batch} b + * @returns {Promise} */ - createChange() { - return this.createKey(1); + createChange(b) { + return this.createKey(b, 1); } /** * Create a new address (increments depth). - * @param {Boolean} change - * @returns {Promise} - Returns {@link WalletKey}. + * @param {Batch} b + * @param {Number} branch + * @returns {Promise} - Returns {@link WalletKey}. */ async createKey(b, branch) { @@ -360,6 +382,7 @@ class Account extends bio.Struct { /** * Derive a receiving address at `index`. Do not increment depth. * @param {Number} index + * @param {MasterKey} [master] * @returns {WalletKey} */ @@ -370,6 +393,7 @@ class Account extends bio.Struct { /** * Derive a change address at `index`. Do not increment depth. * @param {Number} index + * @param {MasterKey} [master] * @returns {WalletKey} */ @@ -381,7 +405,7 @@ class Account extends bio.Struct { * Derive an address from `path` object. * @param {Path} path * @param {MasterKey} master - * @returns {WalletKey} + * @returns {WalletKey?} */ derivePath(path, master) { @@ -415,6 +439,7 @@ class Account extends bio.Struct { * Derive an address at `index`. Do not increment depth. * @param {Number} branch * @param {Number} index + * @param {MasterKey} [master] * @returns {WalletKey} */ @@ -456,7 +481,8 @@ class Account extends bio.Struct { /** * Save the account to the database. Necessary * when address depth and keys change. - * @returns {Promise} + * @param {Batch} b + * @returns {void} */ save(b) { @@ -465,7 +491,8 @@ class Account extends bio.Struct { /** * Save addresses to path map. - * @param {WalletKey[]} rings + * @param {Batch} b + * @param {WalletKey} ring * @returns {Promise} */ @@ -475,7 +502,8 @@ class Account extends bio.Struct { /** * Save paths to path map. - * @param {Path[]} rings + * @param {Batch} b + * @param {Path} path * @returns {Promise} */ @@ -485,6 +513,7 @@ class Account extends bio.Struct { /** * Initialize address depths (including lookahead). + * @param {Batch} b * @returns {Promise} */ @@ -510,8 +539,9 @@ class Account extends bio.Struct { /** * Allocate new lookahead addresses if necessary. - * @param {Number} receiveDepth - * @param {Number} changeDepth + * @param {Batch} b + * @param {Number} receive + * @param {Number} change * @returns {Promise} */ @@ -558,6 +588,7 @@ class Account extends bio.Struct { /** * Allocate new lookahead addresses. + * @param {Batch} b * @param {Number} lookahead * @returns {Promise} */ @@ -607,7 +638,7 @@ class Account extends bio.Struct { /** * Get current receive key. - * @returns {WalletKey} + * @returns {WalletKey?} */ receiveKey() { @@ -619,7 +650,7 @@ class Account extends bio.Struct { /** * Get current change key. - * @returns {WalletKey} + * @returns {WalletKey?} */ changeKey() { @@ -631,7 +662,7 @@ class Account extends bio.Struct { /** * Get current receive address. - * @returns {Address} + * @returns {Address?} */ receiveAddress() { @@ -645,7 +676,7 @@ class Account extends bio.Struct { /** * Get current change address. - * @returns {Address} + * @returns {Address?} */ changeAddress() { @@ -690,6 +721,7 @@ class Account extends bio.Struct { /** * Convert the account to an object suitable for * serialization. + * @param {Object} [balance=null] * @returns {Object} */ @@ -730,7 +762,8 @@ class Account extends bio.Struct { /** * Serialize the account. - * @returns {Buffer} + * @param {BufioWriter} bw + * @returns {BufioWriter} */ write(bw) { @@ -757,9 +790,7 @@ class Account extends bio.Struct { /** * Inject properties from serialized data. - * @private - * @param {Buffer} data - * @returns {Object} + * @param {bio.BufferReader} br */ read(br) { @@ -837,6 +868,12 @@ function cmp(a, b) { return a.compare(b); } +/** + * @param {HDPublicKey} key + * @param {BufioWriter} bw + * @returns {void} + */ + function writeKey(key, bw) { bw.writeU8(key.depth); bw.writeU32BE(key.parentFingerPrint); @@ -845,6 +882,11 @@ function writeKey(key, bw) { bw.writeBytes(key.publicKey); } +/** + * @param {bio.BufferReader} br + * @returns {HDPublicKey} + */ + function readKey(br) { const key = new HDPublicKey(); key.depth = br.readU8(); diff --git a/lib/wallet/common.js b/lib/wallet/common.js index 367f4b261..836df4b77 100644 --- a/lib/wallet/common.js +++ b/lib/wallet/common.js @@ -8,6 +8,10 @@ const {BufferMap} = require('buffer-map'); +/** @typedef {import('../primitives/tx')} TX */ +/** @typedef {import('../primitives/txmeta')} TXMeta */ +/** @typedef {import('../primitives/coin')} Coin */ + /** * @exports wallet/common */ @@ -52,8 +56,8 @@ common.isName = function isName(key) { /** * Sort an array of transactions by time. - * @param {TX[]} txs - * @returns {TX[]} + * @param {TXMeta[]} txs + * @returns {TXMeta[]} */ common.sortTX = function sortTX(txs) { @@ -64,15 +68,15 @@ common.sortTX = function sortTX(txs) { /** * Sort an array of coins by height. - * @param {Coin[]} txs + * @param {Coin[]} coins * @returns {Coin[]} */ common.sortCoins = function sortCoins(coins) { return coins.sort((a, b) => { - a = a.height === -1 ? 0x7fffffff : a.height; - b = b.height === -1 ? 0x7fffffff : b.height; - return a - b; + const ah = a.height === -1 ? 0x7fffffff : a.height; + const bh = b.height === -1 ? 0x7fffffff : b.height; + return ah - bh; }); }; diff --git a/lib/wallet/masterkey.js b/lib/wallet/masterkey.js index 487247f22..387321f67 100644 --- a/lib/wallet/masterkey.js +++ b/lib/wallet/masterkey.js @@ -22,6 +22,9 @@ const Mnemonic = require('../hd/mnemonic'); const pkg = require('../pkg'); const {encoding} = bio; +/** @typedef {import('../types').BufioWriter} BufioWriter */ +/** @typedef {import('../protocol/network')} Network */ + /** * Master Key * Master BIP32 key which can exist @@ -61,8 +64,8 @@ class MasterKey extends bio.Struct { /** * Inject properties from options object. - * @private * @param {Object} options + * @returns {this} */ fromOptions(options) { @@ -215,7 +218,7 @@ class MasterKey extends bio.Struct { /** * Derive an aes key based on params. - * @param {String|Buffer} passphrase + * @param {String|Buffer} passwd * @returns {Promise} */ @@ -276,7 +279,7 @@ class MasterKey extends bio.Struct { async lock() { const unlock = await this.locker.lock(); try { - return await this._lock(); + return this._lock(); } finally { unlock(); } @@ -320,6 +323,7 @@ class MasterKey extends bio.Struct { /** * Decrypt the key permanently. * @param {Buffer|String} passphrase - Zero this yourself. + * @param {Boolean} [clean=false] * @returns {Promise} */ @@ -336,6 +340,7 @@ class MasterKey extends bio.Struct { * Decrypt the key permanently without a lock. * @private * @param {Buffer|String} passphrase - Zero this yourself. + * @param {Boolean} [clean=false] * @returns {Promise} */ @@ -367,6 +372,7 @@ class MasterKey extends bio.Struct { /** * Encrypt the key permanently. * @param {Buffer|String} passphrase - Zero this yourself. + * @param {Boolean} [clean=false] * @returns {Promise} */ @@ -383,6 +389,7 @@ class MasterKey extends bio.Struct { * Encrypt the key permanently without a lock. * @private * @param {Buffer|String} passphrase - Zero this yourself. + * @param {Boolean} [clean=false] * @returns {Promise} */ @@ -497,7 +504,8 @@ class MasterKey extends bio.Struct { /** * Serialize the key in the form of: * `[enc-flag][iv?][ciphertext?][extended-key?]` - * @returns {Buffer} + * @param {BufioWriter} bw + * @returns {BufioWriter} */ write(bw) { @@ -531,8 +539,8 @@ class MasterKey extends bio.Struct { /** * Inject properties from serialized data. - * @private - * @param {Buffer} raw + * @param {bio.BufferReader} br + * @returns {this} */ read(br) { @@ -566,7 +574,6 @@ class MasterKey extends bio.Struct { /** * Inject properties from an HDPrivateKey. - * @private * @param {HDPrivateKey} key * @param {Mnemonic?} mnemonic */ @@ -593,8 +600,8 @@ class MasterKey extends bio.Struct { /** * Convert master key to a jsonifiable object. - * @param {Network?} network - * @param {Boolean?} unsafe - Whether to include + * @param {Network?} [network] + * @param {Boolean?} [unsafe] - Whether to include * the key data in the JSON. * @returns {Object} */ diff --git a/lib/wallet/path.js b/lib/wallet/path.js index 6b498945a..3b70d8193 100644 --- a/lib/wallet/path.js +++ b/lib/wallet/path.js @@ -13,6 +13,7 @@ const Network = require('../protocol/network'); const {encoding} = bio; /** @typedef {import('../types').NetworkType} NetworkType */ +/** @typedef {import('../types').Hash} Hash */ /** @typedef {import('./account')} Account */ /** @@ -36,6 +37,7 @@ class Path extends bio.Struct { this.keyType = Path.types.HD; + /** @type {String|null} */ this.name = null; // Passed in by caller. this.account = 0; @@ -46,6 +48,7 @@ class Path extends bio.Struct { this.encrypted = false; this.data = null; + /** @type {Hash|null} */ this.hash = null; // Passed in by caller. if (options) @@ -190,7 +193,6 @@ class Path extends bio.Struct { /** * Inject properties from address. - * @private * @param {Account} account * @param {Address} address */ @@ -247,7 +249,7 @@ class Path extends bio.Struct { /** * Convert path to a json-friendly object. - * @param {(String|Network)?} network - Network type. + * @param {(NetworkType|Network)?} [network] - Network type. * @returns {Object} */ @@ -273,7 +275,7 @@ class Path extends bio.Struct { /** * Inject properties from a json object. * @param {Object} json - * @returns {Path} + * @returns {this} */ fromJSON(json) { diff --git a/lib/wallet/paths.js b/lib/wallet/paths.js index af1035ea0..9d3c60aee 100644 --- a/lib/wallet/paths.js +++ b/lib/wallet/paths.js @@ -8,6 +8,8 @@ const assert = require('bsert'); +/** @typedef {import('./path')} Path */ + /** * Paths * Represents the HD paths for coins in a single transaction. diff --git a/lib/wallet/records.js b/lib/wallet/records.js index f5c1f2b44..3d17dc2ef 100644 --- a/lib/wallet/records.js +++ b/lib/wallet/records.js @@ -16,6 +16,10 @@ const util = require('../utils/util'); const TX = require('../primitives/tx'); const consensus = require('../protocol/consensus'); +/** @typedef {import('../types').BufioWriter} BufioWriter */ +/** @typedef {import('../types').Hash} Hash */ +/** @typedef {import('../blockchain/chainentry')} ChainEntry */ + /** * Chain State */ @@ -37,7 +41,8 @@ class ChainState extends bio.Struct { /** * Clone the state. - * @returns {ChainState} + * @param {ChainState} state + * @returns {this} */ inject(state) { @@ -59,8 +64,8 @@ class ChainState extends bio.Struct { /** * Inject properties from serialized data. - * @private - * @param {Buffer} data + * @param {bio.BufferReader} br + * @returns {this} */ read(br) { @@ -73,7 +78,8 @@ class ChainState extends bio.Struct { /** * Serialize the chain state. - * @returns {Buffer} + * @param {BufioWriter} bw + * @returns {BufioWriter} */ write(bw) { @@ -93,9 +99,9 @@ class BlockMeta extends bio.Struct { /** * Create block meta. * @constructor - * @param {Hash} hash - * @param {Number} height - * @param {Number} time + * @param {Hash} [hash] + * @param {Number} [height] + * @param {Number} [time] */ constructor(hash, height, time) { @@ -107,7 +113,8 @@ class BlockMeta extends bio.Struct { /** * Clone the block. - * @returns {BlockMeta} + * @param {BlockMeta} meta + * @returns {this} */ inject(meta) { @@ -179,8 +186,8 @@ class BlockMeta extends bio.Struct { /** * Instantiate block meta from serialized tip data. - * @private - * @param {Buffer} data + * @param {bio.BufferReader} br + * @returns {this} */ read(br) { @@ -201,7 +208,8 @@ class BlockMeta extends bio.Struct { /** * Serialize the block meta. - * @returns {Buffer} + * @param {BufioWriter} bw + * @returns {BufioWriter} */ write(bw) { @@ -262,6 +270,7 @@ class TXRecord extends bio.Struct { this.hash = null; this.mtime = mtime; this.height = -1; + /** @type {Hash?} */ this.block = null; this.index = -1; this.time = 0; @@ -272,9 +281,8 @@ class TXRecord extends bio.Struct { /** * Inject properties from tx and block. - * @private * @param {TX} tx - * @param {Block} [block] + * @param {BlockMeta} [block] * @returns {TXRecord} */ @@ -291,7 +299,7 @@ class TXRecord extends bio.Struct { /** * Instantiate tx record from tx and block. * @param {TX} [tx] - * @param {Block} [block] + * @param {BlockMeta} [block] * @param {Number} [mtime] * @returns {TXRecord} */ @@ -325,7 +333,7 @@ class TXRecord extends bio.Struct { /** * Convert tx record to a block meta. - * @returns {BlockMeta} + * @returns {BlockMeta?} */ getBlock() { @@ -377,7 +385,8 @@ class TXRecord extends bio.Struct { /** * Serialize a transaction to "extended format". - * @returns {Buffer} + * @param {BufioWriter} bw + * @returns {BufioWriter} */ write(bw) { @@ -405,8 +414,8 @@ class TXRecord extends bio.Struct { /** * Inject properties from "extended" format. - * @private - * @param {Buffer} data + * @param {bio.BufferReader} br + * @returns {this} */ read(br) { @@ -441,9 +450,15 @@ class MapRecord extends bio.Struct { constructor() { super(); + /** @type {Set} */ this.wids = new Set(); } + /** + * @param {Number} wid + * @returns {Boolean} - Whether the map did not contain the wid. + */ + add(wid) { if (this.wids.has(wid)) return false; @@ -453,14 +468,29 @@ class MapRecord extends bio.Struct { return true; } + /** + * @param {Number} wid + * @returns {Boolean} - Whether the map contained the wid. + */ + remove(wid) { return this.wids.delete(wid); } + /** + * @param {Number} wid + * @returns {Boolean} - Whether the map contains the wid. + */ + has(wid) { return this.wids.has(wid); } + /** + * @param {BufioWriter} bw + * @returns {BufioWriter} + */ + write(bw) { bw.writeU32(this.wids.size); @@ -470,10 +500,19 @@ class MapRecord extends bio.Struct { return bw; } + /** + * @returns {Number} + */ + getSize() { return 4 + this.wids.size * 4; } + /** + * @param {bio.BufferReader} br + * @returns {this} + */ + read(br) { const count = br.readU32(); diff --git a/lib/wallet/txdb.js b/lib/wallet/txdb.js index 6b5fa1d66..761a8975e 100644 --- a/lib/wallet/txdb.js +++ b/lib/wallet/txdb.js @@ -24,8 +24,20 @@ const NameUndo = require('../covenants/undo'); const {TXRecord} = require('./records'); const {types} = rules; +/** @typedef {import('bdb').DB} DB */ +/** @typedef {ReturnType} Batch */ +/** @typedef {import('../types').Hash} Hash */ +/** @typedef {import('../types').BufioWriter} BufioWriter */ +/** @typedef {import('../types').NetworkType} NetworkType */ +/** @typedef {import('../types').Amount} AmountValue */ +/** @typedef {import('../types').Rate} Rate */ +/** @typedef {import('../protocol/network')} Network */ +/** @typedef {import('../primitives/output')} Output */ +/** @typedef {import('../primitives/tx')} TX */ /** @typedef {import('./records').BlockMeta} BlockMeta */ /** @typedef {import('./walletdb')} WalletDB */ +/** @typedef {import('./wallet')} Wallet */ +/** @typedef {import('./path')} Path */ /** * @typedef {Object} BlockExtraInfo @@ -53,6 +65,7 @@ class TXDB { * Create a TXDB. * @constructor * @param {WalletDB} wdb + * @param {Number} [wid=0] */ constructor(wdb, wid) { @@ -70,6 +83,7 @@ class TXDB { /** * Open TXDB. + * @param {Wallet} wallet * @returns {Promise} */ @@ -86,7 +100,7 @@ class TXDB { * @private * @param {String} event * @param {Object} data - * @param {Details} details + * @param {Details} [details] */ emit(event, data, details) { @@ -115,7 +129,7 @@ class TXDB { * @returns {Promise} */ - hasPath(output) { + async hasPath(output) { const hash = output.getHash(); if (!hash) @@ -126,6 +140,7 @@ class TXDB { /** * Save credit. + * @param {Batch} b * @param {Credit} credit * @param {Path} path */ @@ -141,6 +156,7 @@ class TXDB { /** * Remove credit. + * @param {Batch} b * @param {Credit} credit * @param {Path} path */ @@ -156,6 +172,7 @@ class TXDB { /** * Spend credit. + * @param {Batch} b * @param {Credit} credit * @param {TX} tx * @param {Number} index @@ -170,6 +187,7 @@ class TXDB { /** * Unspend credit. + * @param {Batch} b * @param {TX} tx * @param {Number} index */ @@ -184,6 +202,7 @@ class TXDB { /** * Spend credit by spender/input record. * Add undo coin to the input record. + * @param {Batch} b * @param {Credit} credit * @param {Outpoint} spender */ @@ -194,6 +213,7 @@ class TXDB { /** * Write input record. + * @param {Batch} b * @param {TX} tx * @param {Number} index */ @@ -207,6 +227,7 @@ class TXDB { /** * Remove input record. + * @param {Batch} b * @param {TX} tx * @param {Number} index */ @@ -219,6 +240,7 @@ class TXDB { /** * Update wallet balance. + * @param {Batch} b * @param {BalanceDelta} state */ @@ -233,7 +255,8 @@ class TXDB { * Update account balance. * @param {Batch} b * @param {Number} acct - * @param {BalanceDelta} delta + * @param {Balance} delta - account balance + * @returns {Promise} */ async updateAccountBalance(b, acct, delta) { @@ -272,6 +295,7 @@ class TXDB { /** * Append to global map. + * @param {Batch} b * @param {Number} height * @returns {Promise} */ @@ -282,6 +306,7 @@ class TXDB { /** * Remove from global map. + * @param {Batch} b * @param {Number} height * @returns {Promise} */ @@ -292,6 +317,7 @@ class TXDB { /** * Append to global map. + * @param {Batch} b * @param {Hash} hash * @returns {Promise} */ @@ -302,6 +328,7 @@ class TXDB { /** * Remove from global map. + * @param {Batch} b * @param {Hash} hash * @returns {Promise} */ @@ -312,6 +339,7 @@ class TXDB { /** * Append to global map. + * @param {Batch} b * @param {Hash} hash * @param {Number} index * @returns {Promise} @@ -323,6 +351,7 @@ class TXDB { /** * Remove from global map. + * @param {Batch} b * @param {Hash} hash * @param {Number} index * @returns {Promise} @@ -334,8 +363,8 @@ class TXDB { /** * Append to global map. - * @param {Hash} hash - * @param {Number} index + * @param {Batch} b + * @param {Hash} nameHash * @returns {Promise} */ @@ -345,8 +374,8 @@ class TXDB { /** * Remove from global map. - * @param {Hash} hash - * @param {Number} index + * @param {Batch} b + * @param {Hash} nameHash * @returns {Promise} */ @@ -419,8 +448,8 @@ class TXDB { const raw = Buffer.allocUnsafe(data.length + 32); data.copy(raw, 0); - const size = raw.readUInt32LE(40, true); - raw.writeUInt32LE(size + 1, 40, true); + const size = raw.readUInt32LE(40); + raw.writeUInt32LE(size + 1, 40); hash.copy(raw, data.length); b.put(key, raw); @@ -428,6 +457,7 @@ class TXDB { /** * Remove from the global block record. + * @param {Batch} b * @param {Hash} hash * @param {Number} height * @returns {Promise} @@ -458,6 +488,7 @@ class TXDB { /** * Remove from the global block record. + * @param {Batch} b * @param {Hash} hash * @param {Number} height * @returns {Promise} @@ -599,7 +630,7 @@ class TXDB { /** * Get all bids for name. - * @param {Buffer} nameHash + * @param {Buffer} [nameHash] * @returns {Promise} */ @@ -632,6 +663,7 @@ class TXDB { /** * Remove all bids for name. + * @param {Batch} b * @param {Buffer} nameHash * @returns {Promise} */ @@ -718,8 +750,8 @@ class TXDB { * @param {Buffer} nameHash * @param {Outpoint} outpoint * @param {Object} options - * @param {String} options.name - * @param {Amount} options.value + * @param {Buffer} options.name + * @param {AmountValue} options.value * @param {Number} options.height * @param {Boolean} options.own * @param {Outpoint} options.bidPrevout @@ -757,7 +789,7 @@ class TXDB { /** * Get all reveals by name. - * @param {Buffer} nameHash + * @param {Buffer} [nameHash] * @returns {Promise} */ @@ -917,7 +949,7 @@ class TXDB { /** * Test whether the transaction * has a duplicate open. - * @param {TX} + * @param {TX} tx * @returns {Promise} */ @@ -1590,7 +1622,6 @@ class TXDB { * remove all of its spenders. * @private * @param {TXRecord} wtx - * @param {Number} medianTime * @returns {Promise} */ @@ -1993,11 +2024,11 @@ class TXDB { b.put(layout.Oc.encode(hash), count.encode()); b.put(layout.Oe.encode(hash), fromU32(time)); - b.put(layout.Om.encode(time, count.index, hash)); + b.put(layout.Om.encode(time, count.index, hash), null); for (const [acct] of accounts) { b.put(layout.OT.encode(acct, count.height, count.index), hash); - b.put(layout.OM.encode(acct, time, count.index, hash)); + b.put(layout.OM.encode(acct, time, count.index, hash), null); } this.incrementLatestUnconfirmedTXCount(b, count.index); @@ -2067,11 +2098,11 @@ class TXDB { b.del(layout.Ou.encode(hash)); const time = await this.getUnconfirmedTimeForTX(hash); - b.put(layout.Om.encode(time, count.index, hash)); + b.put(layout.Om.encode(time, count.index, hash), null); for (const [acct] of accounts) { b.put(layout.OT.encode(acct, count.height, count.index), hash); - b.put(layout.OM.encode(acct, time, count.index, hash)); + b.put(layout.OM.encode(acct, time, count.index, hash), null); } } @@ -2134,11 +2165,11 @@ class TXDB { b.put(layout.Oc.encode(hash), count.encode()); const time = blockextra.medianTime; - b.put(layout.Oi.encode(time, height, index, hash)); + b.put(layout.Oi.encode(time, height, index, hash), null); for (const [acct] of accounts) { b.put(layout.OT.encode(acct, height, index), hash); - b.put(layout.OI.encode(acct, time, height, index, hash)); + b.put(layout.OI.encode(acct, time, height, index, hash), null); } } @@ -2228,7 +2259,7 @@ class TXDB { * configurable max of transactions. * @param {Number} acct * @param {Object} options - * @param {Buffer} options.time + * @param {Number} options.time * @param {Number} options.limit * @param {Boolean} options.reverse * @returns {Promise} @@ -2346,7 +2377,7 @@ class TXDB { * and limited at a configurable max of transactions. * @private * @param {Number} acct - * @param {Number} options + * @param {Object} options * @param {Buffer} options.hash * @param {Number} options.limit * @param {Boolean} options.reverse @@ -2454,6 +2485,7 @@ class TXDB { * max transactions. * @param {Number} acct * @param {Object} options + * @param {Number} options.time * @param {Number} options.limit * @param {Boolean} options.reverse * @returns {Promise} @@ -2574,7 +2606,7 @@ class TXDB { * of transactions * @private * @param {Number} acct - * @param {Number} options + * @param {Object} options * @param {Buffer} options.hash * @param {Number} options.limit * @param {Boolean} options.reverse @@ -2643,9 +2675,8 @@ class TXDB { * of that coin that are _not_ confirmed will be removed from * the database. * @private - * @param {Hash} hash - * @param {TX} ref - Reference tx, the tx that double-spent. - * @returns {Promise} - Returns Boolean. + * @param {TXRecord} wtx + * @returns {Promise} */ async removeConflict(wtx) { @@ -2720,7 +2751,7 @@ class TXDB { * Lock balances according to covenant. * Inserting or confirming: TX outputs. * Removing or undoing: Coins spent by the wallet in tx inputs. - * @param {State} state + * @param {BalanceDelta} state * @param {Credit} credit * @param {Path} path * @param {Number} height @@ -2756,7 +2787,7 @@ class TXDB { * Unlock balances according to covenants. * Inserting or confirming: Coins spent by the wallet in TX inputs. * Removing or undoing: TX outputs. - * @param {State} state + * @param {BalanceDelta} state * @param {Credit} credit * @param {Path} path * @param {Number} height @@ -2792,8 +2823,7 @@ class TXDB { * This does not check if the name is owned by the wallet. * @private * @param {Batch} b - * @param {Output} tx - * @param {Path} path + * @param {Output} output * @returns {Promise} */ @@ -3140,9 +3170,6 @@ class TXDB { * Handle reorg'd covenant. * @param {Object} b * @param {TX} tx - * @param {Number} i - * @param {Path} path - * @param {Number} height * @returns {Promise} applied undo. */ @@ -3346,7 +3373,8 @@ class TXDB { /** * Filter array of coins or outpoints * for only unlocked ones. - * @param {Coin[]|Outpoint[]} + * jsdoc can't express this type. + * @param {Coin[]|Outpoint[]} coins * @returns {Coin[]|Outpoint[]} */ @@ -3379,7 +3407,7 @@ class TXDB { * Test whether an account owns a coin. * @param {Number} acct * @param {Hash} hash - * @param {Index} number + * @param {Number} index * @returns {Promise} */ @@ -3537,20 +3565,10 @@ class TXDB { }); } - /** - * Get TX hashes by height. - * @param {Number} height - * @returns {Promise} - */ - - getHeightHashes(height) { - return this.getHeightRangeHashes({ start: height, end: height }); - } - /** * Get unconfirmed transactions. * @param {Number} acct - * @returns {Promise} + * @returns {Promise} */ async getPending(acct) { @@ -3648,7 +3666,7 @@ class TXDB { /** * Get coins. * @param {Number} acct - * @returns {Promise} + * @returns {Promise} */ async getCoins(acct) { @@ -3925,6 +3943,7 @@ class TXDB { /** * Update spent coin height in storage. + * @param {Batch} b * @param {TX} tx - Sending transaction. * @param {Number} index * @param {Number} height @@ -3951,6 +3970,7 @@ class TXDB { /** * Test whether the database has a transaction. * @param {Hash} hash + * @param {Number} index * @returns {Promise} */ @@ -3960,7 +3980,7 @@ class TXDB { /** * Calculate balance. - * @param {Number?} account + * @param {Number} acct * @returns {Promise} */ @@ -4058,7 +4078,7 @@ class TXDB { /** * Dump database (for debugging). - * @returns {bdb.Iterator} + * @returns {Promise} */ async dump() { @@ -4084,7 +4104,7 @@ class Balance extends bio.Struct { /** * Create a balance. * @constructor - * @param {Number} account + * @param {Number} acct */ constructor(acct = -1) { @@ -4133,7 +4153,8 @@ class Balance extends bio.Struct { /** * Serialize balance. - * @returns {Buffer} + * @param {BufioWriter} bw + * @returns {BufioWriter} */ write(bw) { @@ -4148,9 +4169,8 @@ class Balance extends bio.Struct { /** * Inject properties from serialized data. - * @private - * @param {Buffer} data - * @returns {Balance} + * @param {bio.BufferReader} br + * @returns {this} */ read(br) { @@ -4183,7 +4203,7 @@ class Balance extends bio.Struct { /** * Inspect balance. - * @param {String} + * @returns {String} */ format() { @@ -4204,19 +4224,16 @@ class Balance extends bio.Struct { */ class BalanceDelta { - /** @type {Balance} */ - wallet; - - /** @type {Map} */ - accounts; - /** * Create a balance delta. * @constructor */ constructor() { + /** @type {Balance} */ this.wallet = new Balance(); + + /** @type {Map} */ this.accounts = new Map(); } @@ -4224,6 +4241,10 @@ class BalanceDelta { return this.wallet.tx !== 0; } + /** + * @param {Balance} balance + */ + applyTo(balance) { this.wallet.applyTo(balance); } @@ -4283,8 +4304,8 @@ class Credit extends bio.Struct { /** * Create a credit. * @constructor - * @param {Coin} coin - * @param {Boolean?} spent + * @param {Coin?} [coin] + * @param {Boolean?} [spent] */ constructor(coin, spent) { @@ -4296,8 +4317,8 @@ class Credit extends bio.Struct { /** * Inject properties from serialized data. - * @private - * @param {Buffer} data + * @param {bio.BufferReader} br + * @returns {this} */ read(br) { @@ -4318,7 +4339,8 @@ class Credit extends bio.Struct { /** * Serialize credit. - * @returns {Buffer} + * @param {BufioWriter} bw + * @returns {BufioWriter} */ write(bw) { @@ -4333,6 +4355,7 @@ class Credit extends bio.Struct { * @private * @param {TX} tx * @param {Number} index + * @param {Number} height * @returns {Credit} */ @@ -4347,6 +4370,7 @@ class Credit extends bio.Struct { * Instantiate credit from transaction. * @param {TX} tx * @param {Number} index + * @param {Number} height * @returns {Credit} */ @@ -4446,6 +4470,7 @@ class Details { /** * Calculate confirmations. + * @param {Number} height * @returns {Number} */ @@ -4467,7 +4492,7 @@ class Details { /** * Calculate fee. Only works if wallet * owns all inputs. Returns 0 otherwise. - * @returns {Amount} + * @returns {AmountValue} */ getFee() { @@ -4490,7 +4515,7 @@ class Details { /** * Calculate fee rate. Only works if wallet * owns all inputs. Returns 0 otherwise. - * @param {Amount} fee + * @param {AmountValue} fee * @returns {Rate} */ @@ -4500,6 +4525,8 @@ class Details { /** * Convert details to a more json-friendly object. + * @param {(Network|NetworkType)?} [network] + * @param {Number} [height] * @returns {Object} */ @@ -4571,7 +4598,7 @@ class DetailsMember { /** * Convert the member to a more json-friendly object. - * @param {Network} network + * @param {(Network|NetworkType)?} [network] * @returns {Object} */ @@ -4600,9 +4627,9 @@ class BlockRecord extends bio.Struct { /** * Create a block record. * @constructor - * @param {Hash} hash - * @param {Number} height - * @param {Number} time + * @param {Hash} [hash] + * @param {Number} [height] + * @param {Number} [time] */ constructor(hash, height, time) { @@ -4640,8 +4667,8 @@ class BlockRecord extends bio.Struct { /** * Instantiate wallet block from serialized tip data. - * @private * @param {bio.BufferReader} br + * @returns {this} */ read(br) { @@ -4670,7 +4697,8 @@ class BlockRecord extends bio.Struct { /** * Serialize the wallet block as a tip (hash and height). - * @returns {Buffer} + * @param {BufioWriter} bw + * @returns {BufioWriter} */ write(bw) { @@ -4750,10 +4778,19 @@ class BlindBid extends bio.Struct { this.own = false; } + /** + * @returns {Number} + */ + getSize() { return 1 + this.name.length + 45; } + /** + * @param {BufioWriter} bw + * @returns {BufioWriter} + */ + write(bw) { let height = this.height; @@ -4769,6 +4806,11 @@ class BlindBid extends bio.Struct { return bw; } + /** + * @param {bio.BufferReader} br + * @returns {this} + */ + read(br) { this.name = br.readBytes(br.readU8()); this.lockup = br.readU64(); @@ -4811,12 +4853,22 @@ class BlindValue extends bio.Struct { return 40; } + /** + * @param {BufioWriter} bw + * @returns {BufioWriter} + */ + write(bw) { bw.writeU64(this.value); bw.writeBytes(this.nonce); return bw; } + /** + * @param {bio.BufferReader} br + * @returns {this} + */ + read(br) { this.value = br.readU64(); this.nonce = br.readBytes(32); @@ -4851,6 +4903,11 @@ class BidReveal extends bio.Struct { return 1 + this.name.length + 13 + 36; } + /** + * @param {BufioWriter} bw + * @returns {BufioWriter} + */ + write(bw) { let height = this.height; @@ -4867,6 +4924,11 @@ class BidReveal extends bio.Struct { return bw; } + /** + * @param {bio.BufferReader} br + * @returns {this} + */ + read(br) { this.name = br.readBytes(br.readU8()); this.value = br.readU64(); @@ -4905,13 +4967,13 @@ class TXCount { /** * Create tx count record. * @constructor - * @param {Number} height - * @param {Number} index + * @param {Number} [height] + * @param {Number} [index] */ constructor(height, index) { - this.height = height; - this.index = index; + this.height = height || 0; + this.index = index || 0; } /** @@ -4961,7 +5023,7 @@ class TXCount { function fromU32(num) { const data = Buffer.allocUnsafe(4); - data.writeUInt32LE(num, 0, true); + data.writeUInt32LE(num, 0); return data; } diff --git a/lib/wallet/wallet.js b/lib/wallet/wallet.js index 75d3d536e..32f85a70f 100644 --- a/lib/wallet/wallet.js +++ b/lib/wallet/wallet.js @@ -22,6 +22,9 @@ const Script = require('../script/script'); const CoinView = require('../coins/coinview'); const WalletCoinView = require('./walletcoinview'); const WalletKey = require('./walletkey'); +const HDPrivateKey = require('../hd/private'); +const HDPublicKey = require('../hd/public'); +const Mnemonic = require('../hd/mnemonic'); const HD = require('../hd/hd'); const Output = require('../primitives/output'); const Account = require('./account'); @@ -35,15 +38,29 @@ const reserved = require('../covenants/reserved'); const {ownership} = require('../covenants/ownership'); const {states} = require('../covenants/namestate'); const {types} = rules; -const {Mnemonic} = HD; const {BufferSet} = require('buffer-map'); const Coin = require('../primitives/coin'); const Outpoint = require('../primitives/outpoint'); +/** @typedef {import('bdb').DB} DB */ +/** @typedef {ReturnType} Batch */ +/** @typedef {import('../types').Base58String} Base58String */ +/** @typedef {import('../types').Hash} Hash */ +/** @typedef {import('../types').Amount} Amount */ +/** @typedef {import('../types').Rate} Rate */ +/** @typedef {import('../covenants/namestate')} NameState */ +/** @typedef {import('../primitives/tx')} TX */ /** @typedef {import('./records').BlockMeta} BlockMeta */ /** @typedef {import('./records').TXRecord} TXRecord */ -/** @typedef {import('../primitives/tx')} TX */ /** @typedef {import('./txdb').BlockExtraInfo} BlockExtraInfo */ +/** @typedef {import('./txdb').Details} Details */ +/** @typedef {import('./txdb').Credit} Credit */ +/** @typedef {import('./txdb').Balance} Balance */ +/** @typedef {import('./txdb').BlindBid} BlindBid */ +/** @typedef {import('./txdb').BidReveal} BidReveal */ +/** @typedef {import('./txdb').BlindValue} BlindValue */ +/** @typedef {import('./txdb').BlockRecord} BlockRecord */ +/** @typedef {import('./walletdb')} WalletDB */ /* * Constants @@ -67,6 +84,7 @@ class Wallet extends EventEmitter { /** * Create a wallet. * @constructor + * @param {WalletDB} wdb * @param {Object} options */ @@ -83,6 +101,7 @@ class Wallet extends EventEmitter { this.fundLock = new Lock(); this.wid = 0; + /** @type {String|null} */ this.id = null; this.watchOnly = false; this.accountDepth = 0; @@ -101,7 +120,6 @@ class Wallet extends EventEmitter { /** * Inject properties from options object. - * @private * @param {Object} options */ @@ -115,9 +133,9 @@ class Wallet extends EventEmitter { if (key) { if (typeof key === 'string') - key = HD.PrivateKey.fromBase58(key, this.network); + key = HDPrivateKey.fromBase58(key, this.network); - assert(HD.isPrivate(key), + assert(HDPrivateKey.isHDPrivateKey(key), 'Must create wallet with hd private key.'); } else { if (typeof mnemonic === 'string') @@ -126,7 +144,7 @@ class Wallet extends EventEmitter { if (!mnemonic) mnemonic = new Mnemonic({ language: options.language }); - key = HD.fromMnemonic(mnemonic, options.bip39Passphrase); + key = HDPrivateKey.fromMnemonic(mnemonic, options.bip39Passphrase); } this.master.fromKey(key, mnemonic); @@ -200,6 +218,8 @@ class Wallet extends EventEmitter { * the first addresses along with the lookahead * addresses). Called automatically from the * walletdb. + * @param {Object} options + * @param {(String|Buffer)?} [passphrase] * @returns {Promise} */ @@ -253,7 +273,7 @@ class Wallet extends EventEmitter { * Saves the key in the wallet database. * @param {(Number|String)} acct * @param {HDPublicKey} key - * @returns {Promise} + * @returns {Promise} */ async addSharedKey(acct, key) { @@ -270,7 +290,7 @@ class Wallet extends EventEmitter { * @private * @param {(Number|String)} acct * @param {HDPublicKey} key - * @returns {Promise} + * @returns {Promise} */ async _addSharedKey(acct, key) { @@ -290,7 +310,7 @@ class Wallet extends EventEmitter { * Remove a public account key from the wallet (multisig). * @param {(Number|String)} acct * @param {HDPublicKey} key - * @returns {Promise} + * @returns {Promise} */ async removeSharedKey(acct, key) { @@ -307,7 +327,7 @@ class Wallet extends EventEmitter { * @private * @param {(Number|String)} acct * @param {HDPublicKey} key - * @returns {Promise} + * @returns {Promise} */ async _removeSharedKey(acct, key) { @@ -317,7 +337,7 @@ class Wallet extends EventEmitter { throw new Error('Account not found.'); const b = this.db.batch(); - const result = await account.removeSharedKey(b, key); + const result = account.removeSharedKey(b, key); await b.write(); return result; @@ -414,7 +434,7 @@ class Wallet extends EventEmitter { /** * Generate a new token. * @param {(String|Buffer)?} passphrase - * @returns {Promise} + * @returns {Promise} */ async retoken(passphrase) { @@ -430,7 +450,7 @@ class Wallet extends EventEmitter { * Generate a new token without a lock. * @private * @param {(String|Buffer)?} passphrase - * @returns {Promise} + * @returns {Promise} */ async _retoken(passphrase) { @@ -465,7 +485,7 @@ class Wallet extends EventEmitter { /** * Rename account. - * @param {(String|Number)?} acct + * @param {String} acct * @param {String} name * @returns {Promise} */ @@ -482,7 +502,7 @@ class Wallet extends EventEmitter { /** * Rename account without a lock. * @private - * @param {(String|Number)?} acct + * @param {String} acct * @param {String} name * @returns {Promise} */ @@ -567,7 +587,6 @@ class Wallet extends EventEmitter { * Generate the wallet api key if none was passed in. * It is represented as BLAKE2b(m/44'->private|nonce). * @private - * @param {HDPrivateKey} master * @param {Number} nonce * @returns {Buffer} */ @@ -588,7 +607,8 @@ class Wallet extends EventEmitter { /** * Create an account. Requires passphrase if master key is encrypted. * @param {Object} options - See {@link Account} options. - * @returns {Promise} - Returns {@link Account}. + * @param {(String|Buffer)?} [passphrase] + * @returns {Promise} */ async createAccount(options, passphrase) { @@ -603,7 +623,8 @@ class Wallet extends EventEmitter { /** * Create an account without a lock. * @param {Object} options - See {@link Account} options. - * @returns {Promise} - Returns {@link Account}. + * @param {(String|Buffer)?} [passphrase] + * @returns {Promise} */ async _createAccount(options, passphrase) { @@ -622,9 +643,9 @@ class Wallet extends EventEmitter { key = options.accountKey; if (typeof key === 'string') - key = HD.PublicKey.fromBase58(key, this.network); + key = HDPublicKey.fromBase58(key, this.network); - if (!HD.isPublic(key)) + if (!HDPublicKey.isHDPublicKey(key)) throw new Error('Must add HD public keys to watch only wallet.'); } else { assert(this.master.key); @@ -690,7 +711,7 @@ class Wallet extends EventEmitter { * Create an account without a lock. * @param {String|Number} acct * @param {Object} options - * @param {String} [passphrase] + * @param {(String|Buffer)?} [passphrase] * @returns {Promise} */ @@ -716,7 +737,8 @@ class Wallet extends EventEmitter { /** * Ensure an account. Requires passphrase if master key is encrypted. * @param {Object} options - See {@link Account} options. - * @returns {Promise} - Returns {@link Account}. + * @param {(String|Buffer)?} [passphrase] + * @returns {Promise} */ async ensureAccount(options, passphrase) { @@ -731,7 +753,7 @@ class Wallet extends EventEmitter { /** * List account names and indexes from the db. - * @returns {Promise} - Returns Array. + * @returns {Promise} - Returns Array. */ getAccounts() { @@ -741,7 +763,7 @@ class Wallet extends EventEmitter { /** * Get all wallet address hashes. * @param {(String|Number)?} acct - * @returns {Promise} - Returns Array. + * @returns {Promise} */ getAddressHashes(acct) { @@ -753,7 +775,8 @@ class Wallet extends EventEmitter { /** * Get all account address hashes. * @param {String|Number} acct - * @returns {Promise} - Returns Array. + * @returns {Promise} - Returns Array. + * @throws on non-existent account */ async getAccountHashes(acct) { @@ -768,7 +791,7 @@ class Wallet extends EventEmitter { /** * Retrieve an account from the database. * @param {Number|String} acct - * @returns {Promise} + * @returns {Promise} */ async getAccount(acct) { @@ -792,10 +815,10 @@ class Wallet extends EventEmitter { /** * Lookup the corresponding account name's index. * @param {String|Number} acct - Account name/index. - * @returns {Promise} - Returns Number. + * @returns {Promise} */ - getAccountIndex(acct) { + async getAccountIndex(acct) { if (acct == null) return -1; @@ -807,8 +830,8 @@ class Wallet extends EventEmitter { /** * Lookup the corresponding account name's index. - * @param {String|Number} acct - Account name/index. - * @returns {Promise} - Returns Number. + * @param {(String|Number)?} [acct] - Account name/index. + * @returns {Promise} * @throws on non-existent account */ @@ -826,8 +849,8 @@ class Wallet extends EventEmitter { /** * Lookup the corresponding account index's name. - * @param {Number} index - Account index. - * @returns {Promise} - Returns String. + * @param {(String|Number)} index - Account index. + * @returns {Promise} */ async getAccountName(index) { @@ -840,7 +863,7 @@ class Wallet extends EventEmitter { /** * Test whether an account exists. * @param {Number|String} acct - * @returns {Promise} - Returns {@link Boolean}. + * @returns {Promise} */ async hasAccount(acct) { @@ -855,7 +878,7 @@ class Wallet extends EventEmitter { /** * Create a new receiving address (increments receiveDepth). * @param {(Number|String)?} acct - * @returns {Promise} - Returns {@link WalletKey}. + * @returns {Promise} */ createReceive(acct = 0) { @@ -865,7 +888,7 @@ class Wallet extends EventEmitter { /** * Create a new change address (increments changeDepth). * @param {(Number|String)?} acct - * @returns {Promise} - Returns {@link WalletKey}. + * @returns {Promise} */ createChange(acct = 0) { @@ -876,7 +899,7 @@ class Wallet extends EventEmitter { * Create a new address (increments depth). * @param {(Number|String)?} acct * @param {Number} branch - * @returns {Promise} - Returns {@link WalletKey}. + * @returns {Promise} */ async createKey(acct, branch) { @@ -892,8 +915,8 @@ class Wallet extends EventEmitter { * Create a new address (increments depth) without a lock. * @private * @param {(Number|String)?} acct - * @param {Number} branche - * @returns {Promise} - Returns {@link WalletKey}. + * @param {Number} branch + * @returns {Promise} */ async _createKey(acct, branch) { @@ -912,7 +935,8 @@ class Wallet extends EventEmitter { /** * Save the wallet to the database. Necessary * when address depth and keys change. - * @returns {Promise} + * @param {Batch} b + * @returns {void} */ save(b) { @@ -921,7 +945,8 @@ class Wallet extends EventEmitter { /** * Increment the wid depth. - * @returns {Promise} + * @param {Batch} b + * @returns {void} */ increment(b) { @@ -931,7 +956,7 @@ class Wallet extends EventEmitter { /** * Test whether the wallet possesses an address. * @param {Address|Hash} address - * @returns {Promise} - Returns Boolean. + * @returns {Promise} */ async hasAddress(address) { @@ -943,7 +968,7 @@ class Wallet extends EventEmitter { /** * Get path by address hash. * @param {Address|Hash} address - * @returns {Promise} - Returns {@link Path}. + * @returns {Promise} */ async getPath(address) { @@ -955,7 +980,7 @@ class Wallet extends EventEmitter { * Get path by address hash (without account name). * @private * @param {Address|Hash} address - * @returns {Promise} - Returns {@link Path}. + * @returns {Promise} */ async readPath(address) { @@ -966,7 +991,7 @@ class Wallet extends EventEmitter { /** * Test whether the wallet contains a path. * @param {Address|Hash} address - * @returns {Promise} - Returns {Boolean}. + * @returns {Promise} */ async hasPath(address) { @@ -977,7 +1002,7 @@ class Wallet extends EventEmitter { /** * Get all wallet paths. * @param {(String|Number)?} acct - * @returns {Promise} - Returns {@link Path}. + * @returns {Promise} */ async getPaths(acct) { @@ -990,7 +1015,7 @@ class Wallet extends EventEmitter { /** * Get all account paths. * @param {String|Number} acct - * @returns {Promise} - Returns {@link Path}. + * @returns {Promise} */ async getAccountPaths(acct) { @@ -1089,8 +1114,7 @@ class Wallet extends EventEmitter { * Import a keyring (will not exist on derivation chain). * Rescanning must be invoked manually. * @param {(String|Number)?} acct - * @param {WalletKey} ring - * @param {(String|Buffer)?} passphrase + * @param {Address} address * @returns {Promise} */ @@ -1107,8 +1131,7 @@ class Wallet extends EventEmitter { * Import a keyring (will not exist on derivation chain) without a lock. * @private * @param {(String|Number)?} acct - * @param {WalletKey} ring - * @param {(String|Buffer)?} passphrase + * @param {Address} address * @returns {Promise} */ @@ -1174,7 +1197,7 @@ class Wallet extends EventEmitter { * @see MTX#selectCoins * @see MTX#fill * @param {MTX} mtx - _Must_ be a mutable transaction. - * @param {Object?} options + * @param {Object} [options] * @param {(String|Number)?} options.account - If no account is * specified, coins from the entire wallet will be filled. * @param {String?} options.selection - Coin selection priority. Can @@ -1190,6 +1213,7 @@ class Wallet extends EventEmitter { * calculating one. * @param {Number|Boolean} options.subtractFee - Whether to subtract the * fee from existing outputs rather than adding more inputs. + * @param {Boolean} [force] */ async fund(mtx, options, force) { @@ -1206,6 +1230,8 @@ class Wallet extends EventEmitter { * @private * @see MTX#selectCoins * @see MTX#fill + * @param {MTX} mtx + * @param {Object} [options] */ async fill(mtx, options) { @@ -1357,7 +1383,8 @@ class Wallet extends EventEmitter { /** * Make a claim MTX. * @param {String} name - * @returns {Claim} + * @param {Object?} [options] + * @returns {Promise} */ async _createClaim(name, options) { @@ -1482,6 +1509,7 @@ class Wallet extends EventEmitter { * Create and send a claim MTX. * @param {String} name * @param {Object} options + * @returns {Promise} */ async createClaim(name, options) { @@ -1496,8 +1524,8 @@ class Wallet extends EventEmitter { /** * Make a claim proof. * @param {String} name - * @param {Object} options - * @returns {Claim} + * @param {Object?} [options] + * @returns {Promise} */ async makeFakeClaim(name, options) { @@ -1564,7 +1592,7 @@ class Wallet extends EventEmitter { * Make a claim proof. * @param {String} name * @param {Object} options - * @returns {Claim} + * @returns {Promise} */ async makeClaim(name, options) { @@ -1611,6 +1639,7 @@ class Wallet extends EventEmitter { * Create and send a claim proof. * @param {String} name * @param {Object} options + * @returns {Promise} */ async _sendClaim(name, options) { @@ -1623,6 +1652,7 @@ class Wallet extends EventEmitter { * Create and send a claim proof. * @param {String} name * @param {Object} options + * @returns {Promise} */ async sendClaim(name, options) { @@ -1638,7 +1668,7 @@ class Wallet extends EventEmitter { * Make a open MTX. * @param {String} name * @param {Number|String} acct - * @param {MTX?} mtx + * @param {MTX?} [mtx] * @returns {Promise} */ @@ -1689,6 +1719,7 @@ class Wallet extends EventEmitter { if (!mtx) mtx = new MTX(); + mtx.outputs.push(output); if (await this.txdb.isDoubleOpen(mtx)) @@ -1766,8 +1797,8 @@ class Wallet extends EventEmitter { * @param {Number} value * @param {Number} lockup * @param {Number|String} acct - * @param {MTX?} mtx - * @param {Address?} addr + * @param {MTX?} [mtx] + * @param {Address?} [addr] * @returns {Promise} */ @@ -1830,7 +1861,7 @@ class Wallet extends EventEmitter { * @param {Number} value * @param {Number} lockup * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async _createBid(name, value, lockup, options) { @@ -1847,7 +1878,7 @@ class Wallet extends EventEmitter { * @param {Number} value * @param {Number} lockup * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async createBid(name, value, lockup, options) { @@ -1879,6 +1910,7 @@ class Wallet extends EventEmitter { * @param {Number} value * @param {Number} lockup * @param {Object} options + * @returns {Promise} */ async sendBid(name, value, lockup, options) { @@ -1890,6 +1922,12 @@ class Wallet extends EventEmitter { } } + /** + * @typedef {Object} CreateAuctionResults + * @param {MTX} bid + * @param {MTX} reveal + */ + /** * Create and finalize a bid & a reveal (in advance) * MTX with a lock. @@ -1897,9 +1935,7 @@ class Wallet extends EventEmitter { * @param {Number} value * @param {Number} lockup * @param {Object} options - * @returns {Object} output - * @returns {MTX} output.bid - * @returns {MTX} output.reveal + * @returns {Promise} */ async createAuctionTXs(name, value, lockup, options) { @@ -1918,9 +1954,7 @@ class Wallet extends EventEmitter { * @param {Number} value * @param {Number} lockup * @param {Object} options - * @returns {Object} output - * @returns {MTX} output.bid - * @returns {MTX} output.reveal + * @returns {Promise} */ async _createAuctionTXs(name, value, lockup, options) { @@ -1965,17 +1999,19 @@ class Wallet extends EventEmitter { /** * Make a reveal MTX. * @param {String} name - * @param {(Number|String)?} acct - * @param {MTX?} mtx + * @param {(Number|String)?} [acct] + * @param {MTX?} [mtx] * @returns {Promise} */ async makeReveal(name, acct, mtx) { assert(typeof name === 'string'); + let acctno; + if (acct != null) { assert((acct >>> 0) === acct || typeof acct === 'string'); - acct = await this.getAccountIndex(acct); + acctno = await this.getAccountIndex(acct); } if (!rules.verifyName(name)) @@ -2016,8 +2052,10 @@ class Wallet extends EventEmitter { if (!coin) continue; - if (acct != null && !await this.txdb.hasCoinByAccount(acct, hash, index)) - continue; + if (acctno != null) { + if (!await this.txdb.hasCoinByAccount(acctno, hash, index)) + continue; + } // Is local? if (coin.height < ns.height) @@ -2054,7 +2092,7 @@ class Wallet extends EventEmitter { * MTX without a lock. * @param {String} name * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async _createReveal(name, options) { @@ -2069,7 +2107,7 @@ class Wallet extends EventEmitter { * MTX with a lock. * @param {String} name * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async createReveal(name, options) { @@ -2085,6 +2123,7 @@ class Wallet extends EventEmitter { * Create and send a reveal MTX. * @param {String} name * @param {Object} options + * @returns {Promise} */ async _sendReveal(name, options) { @@ -2097,6 +2136,7 @@ class Wallet extends EventEmitter { * Create and send a bid MTX. * @param {String} name * @param {Object} options + * @returns {Promise} */ async sendReveal(name, options) { @@ -2110,8 +2150,8 @@ class Wallet extends EventEmitter { /** * Make a reveal MTX. - * @param {MTX?} mtx - * @param {Number?} witnessSize + * @param {MTX?} [mtx] + * @param {Number?} [witnessSize] * @returns {Promise} */ @@ -2119,6 +2159,7 @@ class Wallet extends EventEmitter { const height = this.wdb.height + 1; const network = this.network; const bids = await this.getBids(); + if (!mtx) mtx = new MTX(); else @@ -2189,7 +2230,7 @@ class Wallet extends EventEmitter { * Create and finalize a reveal all * MTX without a lock. * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async _createRevealAll(options) { @@ -2202,7 +2243,7 @@ class Wallet extends EventEmitter { * Create and finalize a reveal all * MTX with a lock. * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async createRevealAll(options) { @@ -2217,6 +2258,7 @@ class Wallet extends EventEmitter { /** * Create and send a reveal all MTX. * @param {Object} options + * @returns {Promise} */ async _sendRevealAll(options) { @@ -2228,6 +2270,7 @@ class Wallet extends EventEmitter { /** * Create and send a bid MTX. * @param {Object} options + * @returns {Promise} */ async sendRevealAll(options) { @@ -2242,8 +2285,8 @@ class Wallet extends EventEmitter { /** * Make a redeem MTX. * @param {String} name - * @param {(Number|String)?} acct - * @param {MTX?} mtx + * @param {(Number|String)?} [acct] + * @param {MTX?} [mtx] * @returns {Promise} */ @@ -2253,9 +2296,11 @@ class Wallet extends EventEmitter { if (!rules.verifyName(name)) throw new Error(`Invalid name: ${name}.`); + let acctno; + if (acct != null) { assert((acct >>> 0) === acct || typeof acct === 'string'); - acct = await this.getAccountIndex(acct); + acctno = await this.getAccountIndex(acct); } const rawName = Buffer.from(name, 'ascii'); @@ -2294,8 +2339,10 @@ class Wallet extends EventEmitter { if (!coin) continue; - if (acct != null && !await this.txdb.hasCoinByAccount(acct, hash, index)) - continue; + if (acctno != null) { + if (!await this.txdb.hasCoinByAccount(acctno, hash, index)) + continue; + } // Is local? if (coin.height < ns.height) @@ -2323,7 +2370,7 @@ class Wallet extends EventEmitter { * MTX without a lock. * @param {String} name * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async _createRedeem(name, options) { @@ -2338,7 +2385,7 @@ class Wallet extends EventEmitter { * MTX with a lock. * @param {String} name * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async createRedeem(name, options) { @@ -2355,6 +2402,7 @@ class Wallet extends EventEmitter { * MTX without a lock. * @param {String} name * @param {Object} options + * @returns {Promise} */ async _sendRedeem(name, options) { @@ -2368,6 +2416,7 @@ class Wallet extends EventEmitter { * MTX with a lock. * @param {String} name * @param {Object} options + * @returns {Promise} */ async sendRedeem(name, options) { @@ -2381,9 +2430,8 @@ class Wallet extends EventEmitter { /** * Make a redeem MTX. - * @param {String} name - * @param {MTX?} mtx - * @param {Number?} witnessSize + * @param {MTX?} [mtx] + * @param {Number?} [witnessSize] * @returns {Promise} */ @@ -2391,6 +2439,7 @@ class Wallet extends EventEmitter { const height = this.wdb.height + 1; const network = this.network; const reveals = await this.txdb.getReveals(); + if (!mtx) mtx = new MTX(); else @@ -2455,7 +2504,7 @@ class Wallet extends EventEmitter { * Create and finalize a redeem * all MTX without a lock. * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async _createRedeemAll(options) { @@ -2468,7 +2517,7 @@ class Wallet extends EventEmitter { * Create and finalize a redeem * all MTX with a lock. * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async createRedeemAll(options) { @@ -2484,6 +2533,7 @@ class Wallet extends EventEmitter { * Create and send a redeem all * MTX without a lock. * @param {Object} options + * @returns {Promise} */ async _sendRedeemAll(options) { @@ -2496,6 +2546,7 @@ class Wallet extends EventEmitter { * Create and send a redeem all * MTX with a lock. * @param {Object} options + * @returns {Promise} */ async sendRedeemAll(options) { @@ -2512,8 +2563,8 @@ class Wallet extends EventEmitter { * @private * @param {String} name * @param {Resource?} resource - * @param {MTX?} mtx - * @returns {MTX} + * @param {MTX?} [mtx] + * @returns {Promise} */ async _makeRegister(name, resource, mtx) { @@ -2596,7 +2647,7 @@ class Wallet extends EventEmitter { * @param {String} name * @param {Resource} resource * @param {(Number|String)?} acct - * @param {MTX?} mtx + * @param {MTX?} [mtx] * @returns {Promise} */ @@ -2607,9 +2658,11 @@ class Wallet extends EventEmitter { if (!rules.verifyName(name)) throw new Error('Invalid name.'); + let acctno; + if (acct != null) { assert((acct >>> 0) === acct || typeof acct === 'string'); - acct = await this.getAccountIndex(acct); + acctno = await this.getAccountIndex(acct); } const rawName = Buffer.from(name, 'ascii'); @@ -2630,8 +2683,10 @@ class Wallet extends EventEmitter { if (credit.spent) throw new Error(`Credit is already pending for: ${name}.`); - if (acct != null && !await this.txdb.hasCoinByAccount(acct, hash, index)) - throw new Error(`Account does not own name: ${name}.`); + if (acctno != null) { + if (!await this.txdb.hasCoinByAccount(acctno, hash, index)) + throw new Error(`Account does not own name: ${name}.`); + } const coin = credit.coin; @@ -2679,7 +2734,7 @@ class Wallet extends EventEmitter { * @param {String} name * @param {Resource} resource * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async _createUpdate(name, resource, options) { @@ -2695,7 +2750,7 @@ class Wallet extends EventEmitter { * @param {String} name * @param {Resource} resource * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async createUpdate(name, resource, options) { @@ -2713,6 +2768,7 @@ class Wallet extends EventEmitter { * @param {String} name * @param {Resource} resource * @param {Object} options + * @returns {Promise} */ async _sendUpdate(name, resource, options) { @@ -2727,6 +2783,7 @@ class Wallet extends EventEmitter { * @param {String} name * @param {Resource} resource * @param {Object} options + * @returns {Promise} */ async sendUpdate(name, resource, options) { @@ -2743,7 +2800,7 @@ class Wallet extends EventEmitter { * @private * @param {String} name * @param {(Number|String)?} acct - * @param {MTX?} mtx + * @param {MTX?} [mtx] * @returns {Promise} */ @@ -2753,9 +2810,11 @@ class Wallet extends EventEmitter { if (!rules.verifyName(name)) throw new Error(`Invalid name: ${name}.`); + let acctno; + if (acct != null) { assert((acct >>> 0) === acct || typeof acct === 'string'); - acct = await this.getAccountIndex(acct); + acctno = await this.getAccountIndex(acct); } const rawName = Buffer.from(name, 'ascii'); @@ -2786,8 +2845,10 @@ class Wallet extends EventEmitter { if (coin.height < ns.height) throw new Error(`Wallet does not own name: ${name}.`); - if (acct != null && !await this.txdb.hasCoinByAccount(acct, hash, index)) - throw new Error(`Account does not own name: ${name}.`); + if (acctno != null) { + if (!await this.txdb.hasCoinByAccount(acctno, hash, index)) + throw new Error(`Account does not own name: ${name}.`); + } if (!ns.isClosed(height, network)) throw new Error(`Auction is not yet closed: ${name}.`); @@ -2902,7 +2963,7 @@ class Wallet extends EventEmitter { * MTX without a lock. * @param {String} name * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async _createRenewal(name, options) { @@ -2917,7 +2978,7 @@ class Wallet extends EventEmitter { * MTX with a lock. * @param {String} name * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async createRenewal(name, options) { @@ -2934,6 +2995,7 @@ class Wallet extends EventEmitter { * MTX without a lock. * @param {String} name * @param {Object} options + * @returns {Promise} */ async _sendRenewal(name, options) { @@ -2947,6 +3009,7 @@ class Wallet extends EventEmitter { * MTX with a lock. * @param {String} name * @param {Object} options + * @returns {Promise} */ async sendRenewal(name, options) { @@ -2963,7 +3026,7 @@ class Wallet extends EventEmitter { * @param {String} name * @param {Address} address * @param {(Number|String)?} acct - * @param {MTX?} mtx + * @param {MTX?} [mtx] * @returns {Promise} */ @@ -2974,9 +3037,11 @@ class Wallet extends EventEmitter { if (!rules.verifyName(name)) throw new Error(`Invalid name: ${name}.`); + let acctno; + if (acct != null) { assert((acct >>> 0) === acct || typeof acct === 'string'); - acct = await this.getAccountIndex(acct); + acctno = await this.getAccountIndex(acct); } const rawName = Buffer.from(name, 'ascii'); @@ -3006,8 +3071,10 @@ class Wallet extends EventEmitter { if (coin.height < ns.height) throw new Error(`Wallet does not own name: ${name}.`); - if (acct != null && !await this.txdb.hasCoinByAccount(acct, hash, index)) - throw new Error(`Account does not own name: ${name}.`); + if (acctno != null) { + if (!await this.txdb.hasCoinByAccount(acctno, hash, index)) + throw new Error(`Account does not own name: ${name}.`); + } if (!ns.isClosed(height, network)) throw new Error(`Auction is not yet closed: ${name}.`); @@ -3041,7 +3108,7 @@ class Wallet extends EventEmitter { * @param {String} name * @param {Address} address * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async _createTransfer(name, address, options) { @@ -3057,7 +3124,7 @@ class Wallet extends EventEmitter { * @param {String} name * @param {Address} address * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async createTransfer(name, address, options) { @@ -3075,6 +3142,7 @@ class Wallet extends EventEmitter { * @param {String} name * @param {Address} address * @param {Object} options + * @returns {Promise} */ async _sendTransfer(name, address, options) { @@ -3093,6 +3161,7 @@ class Wallet extends EventEmitter { * @param {String} name * @param {Address} address * @param {Object} options + * @returns {Promise} */ async sendTransfer(name, address, options) { @@ -3109,7 +3178,7 @@ class Wallet extends EventEmitter { * @private * @param {String} name * @param {(Number|String)?} acct - * @param {MTX?} mtx + * @param {MTX?} [mtx] * @returns {Promise} */ @@ -3119,9 +3188,11 @@ class Wallet extends EventEmitter { if (!rules.verifyName(name)) throw new Error(`Invalid name: ${name}.`); + let acctno; + if (acct != null) { assert((acct >>> 0) === acct || typeof acct === 'string'); - acct = await this.getAccountIndex(acct); + acctno = await this.getAccountIndex(acct); } const rawName = Buffer.from(name, 'ascii'); @@ -3146,8 +3217,10 @@ class Wallet extends EventEmitter { if (coin.height < ns.height) throw new Error(`Wallet does not own name: ${name}.`); - if (acct != null && !await this.txdb.hasCoinByAccount(acct, hash, index)) - throw new Error(`Account does not own name: ${name}.`); + if (acctno != null) { + if (!await this.txdb.hasCoinByAccount(acctno, hash, index)) + throw new Error(`Account does not own name: ${name}.`); + } if (!ns.isClosed(height, network)) throw new Error(`Auction is not yet closed: ${name}.`); @@ -3173,7 +3246,7 @@ class Wallet extends EventEmitter { * MTX without a lock. * @param {String} name * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async _createCancel(name, options) { @@ -3188,7 +3261,7 @@ class Wallet extends EventEmitter { * MTX with a lock. * @param {String} name * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async createCancel(name, options) { @@ -3205,6 +3278,7 @@ class Wallet extends EventEmitter { * MTX without a lock. * @param {String} name * @param {Object} options + * @returns {Promise} */ async _sendCancel(name, options) { @@ -3218,6 +3292,7 @@ class Wallet extends EventEmitter { * MTX with a lock. * @param {String} name * @param {Object} options + * @returns {Promise} */ async sendCancel(name, options) { @@ -3234,7 +3309,7 @@ class Wallet extends EventEmitter { * @private * @param {String} name * @param {(Number|String)?} acct - * @param {MTX?} mtx + * @param {MTX?} [mtx] * @returns {Promise} */ @@ -3244,9 +3319,11 @@ class Wallet extends EventEmitter { if (!rules.verifyName(name)) throw new Error(`Invalid name: ${name}.`); + let acctno; + if (acct != null) { assert((acct >>> 0) === acct || typeof acct === 'string'); - acct = await this.getAccountIndex(acct); + acctno = await this.getAccountIndex(acct); } const rawName = Buffer.from(name, 'ascii'); @@ -3276,8 +3353,10 @@ class Wallet extends EventEmitter { if (coin.height < ns.height) throw new Error(`Wallet does not own name: ${name}.`); - if (acct != null && !await this.txdb.hasCoinByAccount(acct, hash, index)) - throw new Error(`Account does not own name: ${name}.`); + if (acctno != null) { + if (!await this.txdb.hasCoinByAccount(acctno, hash, index)) + throw new Error(`Account does not own name: ${name}.`); + } if (!ns.isClosed(height, network)) throw new Error(`Auction is not yet closed: ${name}.`); @@ -3401,7 +3480,7 @@ class Wallet extends EventEmitter { * MTX without a lock. * @param {String} name * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async _createFinalize(name, options) { @@ -3416,7 +3495,7 @@ class Wallet extends EventEmitter { * MTX with a lock. * @param {String} name * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async createFinalize(name, options) { @@ -3433,6 +3512,7 @@ class Wallet extends EventEmitter { * MTX without a lock. * @param {String} name * @param {Object} options + * @returns {Promise} */ async _sendFinalize(name, options) { @@ -3446,6 +3526,7 @@ class Wallet extends EventEmitter { * MTX with a lock. * @param {String} name * @param {Object} options + * @returns {Promise} */ async sendFinalize(name, options) { @@ -3461,7 +3542,7 @@ class Wallet extends EventEmitter { * Make a revoke MTX. * @param {String} name * @param {(Number|String)?} acct - * @param {MTX?} mtx + * @param {MTX?} [mtx] * @returns {Promise} */ @@ -3471,9 +3552,11 @@ class Wallet extends EventEmitter { if (!rules.verifyName(name)) throw new Error(`Invalid name: ${name}.`); + let acctno; + if (acct != null) { assert((acct >>> 0) === acct || typeof acct === 'string'); - acct = await this.getAccountIndex(acct); + acctno = await this.getAccountIndex(acct); } const rawName = Buffer.from(name, 'ascii'); @@ -3494,8 +3577,10 @@ class Wallet extends EventEmitter { if (credit.spent) throw new Error(`Credit is already pending for: ${name}.`); - if (acct != null && !await this.txdb.hasCoinByAccount(acct, hash, index)) - throw new Error(`Account does not own name: ${name}.`); + if (acctno != null) { + if (!await this.txdb.hasCoinByAccount(acctno, hash, index)) + throw new Error(`Account does not own name: ${name}.`); + } const coin = credit.coin; @@ -3536,7 +3621,7 @@ class Wallet extends EventEmitter { * MTX without a lock. * @param {String} name * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async _createRevoke(name, options) { @@ -3551,7 +3636,7 @@ class Wallet extends EventEmitter { * MTX with a lock. * @param {String} name * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async createRevoke(name, options) { @@ -3568,6 +3653,7 @@ class Wallet extends EventEmitter { * MTX without a lock. * @param {String} name * @param {Object} options + * @returns {Promise} */ async _sendRevoke(name, options) { @@ -3581,6 +3667,7 @@ class Wallet extends EventEmitter { * MTX with a lock. * @param {String} name * @param {Object} options + * @returns {Promise} */ async sendRevoke(name, options) { @@ -3667,7 +3754,7 @@ class Wallet extends EventEmitter { /** * Make a transaction with normal outputs. * @param {Object[]} outputs - See {@link MTX#addOutput} - * @param {MTX} [mtx=null] - MTX to modify instead of new one. + * @param {MTX?} [mtx] - MTX to modify instead of new one. * @returns {MTX} - MTX with populated outputs. */ @@ -3796,18 +3883,23 @@ class Wallet extends EventEmitter { } case 'OPEN': { assert(action.length === 1, 'Bad arguments for OPEN.'); - await this.makeOpen(...action, acct, mtx); + const name = action[0]; + await this.makeOpen(name, acct, mtx); break; } case 'BID': { assert(action.length === 3, 'Bad arguments for BID.'); const address = account.deriveReceive(receiveIndex++).getAddress(); - await this.makeBid(...action, acct, mtx, address); + const name = action[0]; + const value = action[1]; + const lockup = action[2]; + await this.makeBid(name, value, lockup, acct, mtx, address); break; } case 'REVEAL': { if (action.length === 1) { - await this.makeReveal(...action, acct, mtx); + const name = action[0]; + await this.makeReveal(name, acct, mtx); break; } @@ -3817,7 +3909,8 @@ class Wallet extends EventEmitter { } case 'REDEEM': { if (action.length === 1) { - await this.makeRedeem(...action, acct, mtx); + const name = action[0]; + await this.makeRedeem(name, acct, mtx); break; } @@ -3827,12 +3920,15 @@ class Wallet extends EventEmitter { } case 'UPDATE': { assert(action.length === 2, 'Bad arguments for UPDATE.'); - await this.makeUpdate(...action, acct, mtx); + const name = action[0]; + const resource = action[1]; + await this.makeUpdate(name, resource, acct, mtx); break; } case 'RENEW': { if (action.length === 1) { - await this.makeRenewal(...action, acct, mtx); + const name = action[0]; + await this.makeRenewal(name, acct, mtx); break; } @@ -3842,12 +3938,15 @@ class Wallet extends EventEmitter { } case 'TRANSFER': { assert(action.length === 2, 'Bad arguments for TRANSFER.'); - await this.makeTransfer(...action, acct, mtx); + const name = action[0]; + const address = action[1]; + await this.makeTransfer(name, address, acct, mtx); break; } case 'FINALIZE': { if (action.length === 1) { - await this.makeFinalize(...action, acct, mtx); + const name = action[0]; + await this.makeFinalize(name, acct, mtx); break; } @@ -3857,12 +3956,14 @@ class Wallet extends EventEmitter { } case 'CANCEL': { assert(action.length === 1, 'Bad arguments for CANCEL.'); - await this.makeCancel(...action, acct, mtx); + const name = action[0]; + await this.makeCancel(name, acct, mtx); break; } case 'REVOKE': { assert(action.length === 1, 'Bad arguments for REVOKE.'); - await this.makeRevoke(...action, acct, mtx); + const name = action[0]; + await this.makeRevoke(name, acct, mtx); break; } default: @@ -3939,7 +4040,7 @@ class Wallet extends EventEmitter { * Make a batch transaction with multiple actions. * @param {Array} actions * @param {Object} options - * @returns {MTX} + * @returns {Promise} */ async createBatch(actions, options) { @@ -3955,7 +4056,7 @@ class Wallet extends EventEmitter { * Create and send a batch transaction with multiple actions. * @param {Array} actions * @param {Object} options - * @returns {TX} + * @returns {Promise} */ async _sendBatch(actions, options) { @@ -3968,7 +4069,7 @@ class Wallet extends EventEmitter { * Create and send a batch transaction with multiple actions. * @param {Array} actions * @param {Object} options - * @returns {TX} + * @returns {Promise} */ async sendBatch(actions, options) { @@ -4049,7 +4150,8 @@ class Wallet extends EventEmitter { * coins from being double spent. * @param {Object} options - See {@link Wallet#fund options}. * @param {Object[]} options.outputs - See {@link MTX#addOutput}. - * @returns {Promise} - Returns {@link TX}. + * @param {String} options.passphrase + * @returns {Promise} */ async send(options) { @@ -4066,7 +4168,8 @@ class Wallet extends EventEmitter { * @private * @param {Object} options - See {@link Wallet#fund options}. * @param {Object[]} options.outputs - See {@link MTX#addOutput}. - * @returns {Promise} - Returns {@link TX}. + * @param {String} options.passphrase + * @returns {Promise} */ async _send(options) { @@ -4144,7 +4247,7 @@ class Wallet extends EventEmitter { * @param {Hash} hash * @param {Rate} rate * @param {(String|Buffer)?} passphrase - * @returns {Promise} - Returns {@link TX}. + * @returns {Promise} */ async increaseFee(hash, rate, passphrase) { @@ -4266,8 +4369,7 @@ class Wallet extends EventEmitter { /** * Derive necessary addresses for signing a transaction. * @param {MTX} mtx - * @param {Number?} index - Input index. - * @returns {Promise} - Returns {@link WalletKey}[]. + * @returns {Promise} */ async deriveInputs(mtx) { @@ -4293,7 +4395,7 @@ class Wallet extends EventEmitter { /** * Retrieve a single keyring by address. - * @param {Address|Hash} hash + * @param {Address|Hash} address * @returns {Promise} */ @@ -4330,7 +4432,7 @@ class Wallet extends EventEmitter { /** * Retrieve a single keyring by address * (with the private key reference). - * @param {Address|Hash} hash + * @param {Address|Hash} address * @param {(Buffer|String)?} passphrase * @returns {Promise} */ @@ -4384,7 +4486,7 @@ class Wallet extends EventEmitter { /** * Map output addresses to paths. * @param {TX} tx - * @returns {Promise} - Returns {@link Path}[]. + * @returns {Promise} */ async getOutputPaths(tx) { @@ -4468,8 +4570,7 @@ class Wallet extends EventEmitter { * sign, only creates signature slots). Only builds scripts * for inputs that are redeemable by this wallet. * @param {MTX} mtx - * @returns {Promise} - Returns Number - * (total number of scripts built). + * @returns {Promise} - total number of scripts built. */ async template(mtx) { @@ -4480,8 +4581,8 @@ class Wallet extends EventEmitter { /** * Build input scripts and sign inputs for a transaction. Only attempts * to build/sign inputs that are redeemable by this wallet. - * @param {MTX} tx - * @param {Object|String|Buffer} options - Options or passphrase. + * @param {MTX} mtx + * @param {String|Buffer} passphrase * @returns {Promise} - Returns Number (total number * of inputs scripts built and signed). */ @@ -4500,7 +4601,7 @@ class Wallet extends EventEmitter { /** * Get pending ancestors up to the policy limit * @param {TX} tx - * @returns {Promise} - Returns {BufferSet} with Hash + * @returns {Promise} - Returns {BufferSet} with Hash */ async getPendingAncestors(tx) { @@ -4510,8 +4611,8 @@ class Wallet extends EventEmitter { /** * Get pending ancestors up to the policy limit. * @param {TX} tx - * @param {Object} set - * @returns {Promise} - Returns {BufferSet} with Hash + * @param {BufferSet} set + * @returns {Promise} */ async _getPendingAncestors(tx, set) { @@ -4542,7 +4643,7 @@ class Wallet extends EventEmitter { /** * Test whether the database has a pending transaction. * @param {Hash} hash - * @returns {Promise} - Returns Boolean. + * @returns {Promise} */ hasPending(hash) { @@ -4552,7 +4653,7 @@ class Wallet extends EventEmitter { /** * Get a coin viewpoint. * @param {TX} tx - * @returns {Promise} - Returns {@link CoinView}. + * @returns {Promise} */ getCoinView(tx) { @@ -4562,8 +4663,8 @@ class Wallet extends EventEmitter { /** * Get a wallet coin viewpoint with HD paths. * @param {TX} tx - * @param {CoinView?} view - Coins to be used in wallet coin viewpoint. - * @returns {Promise} - Returns {@link WalletCoinView}. + * @param {CoinView?} [view] - Coins to be used in wallet coin viewpoint. + * @returns {Promise} */ async getWalletCoinView(tx, view) { @@ -4573,11 +4674,11 @@ class Wallet extends EventEmitter { if (!tx.hasCoins(view)) view = await this.txdb.getCoinView(tx); - view = WalletCoinView.fromCoinView(view); + const wview = WalletCoinView.fromCoinView(view); for (const input of tx.inputs) { const prevout = input.prevout; - const coin = view.getCoin(prevout); + const coin = wview.getCoin(prevout); if (!coin) continue; @@ -4608,16 +4709,16 @@ class Wallet extends EventEmitter { path.account ^= HD.common.HARDENED; // Add path to the viewpoint. - view.addPath(prevout, path); + wview.addPath(prevout, path); } - return view; + return wview; } /** * Get a historical coin viewpoint. * @param {TX} tx - * @returns {Promise} - Returns {@link CoinView}. + * @returns {Promise} */ getSpentView(tx) { @@ -4627,7 +4728,7 @@ class Wallet extends EventEmitter { /** * Convert transaction to transaction details. * @param {TXRecord} wtx - * @returns {Promise} - Returns {@link Details}. + * @returns {Promise
} */ toDetails(wtx) { @@ -4637,7 +4738,7 @@ class Wallet extends EventEmitter { /** * Get transaction details. * @param {Hash} hash - * @returns {Promise} - Returns {@link Details}. + * @returns {Promise
} */ getDetails(hash) { @@ -4648,7 +4749,7 @@ class Wallet extends EventEmitter { * Get a coin from the wallet. * @param {Hash} hash * @param {Number} index - * @returns {Promise} - Returns {@link Coin}. + * @returns {Promise} */ getCoin(hash, index) { @@ -4659,7 +4760,7 @@ class Wallet extends EventEmitter { * Get an unspent coin from the wallet. * @param {Hash} hash * @param {Number} index - * @returns {Promise} - Returns {@link Coin}. + * @returns {Promise} */ async getUnspentCoin(hash, index) { @@ -4685,7 +4786,7 @@ class Wallet extends EventEmitter { /** * Get a transaction from the wallet. * @param {Hash} hash - * @returns {Promise} - Returns {@link TX}. + * @returns {Promise} */ getTX(hash) { @@ -4694,7 +4795,7 @@ class Wallet extends EventEmitter { /** * List blocks for the wallet. - * @returns {Promise} - Returns {@link BlockRecord}. + * @returns {Promise} */ getBlocks() { @@ -4723,7 +4824,7 @@ class Wallet extends EventEmitter { /** * Get a name if present. * @param {Buffer} nameHash - * @returns {NameState} + * @returns {Promise} */ async getNameState(nameHash) { @@ -4733,7 +4834,7 @@ class Wallet extends EventEmitter { /** * Get a name if present. * @param {String|Buffer} name - * @returns {NameState} + * @returns {Promise} */ async getNameStateByName(name) { @@ -4743,7 +4844,7 @@ class Wallet extends EventEmitter { /** * Get a blind value if present. * @param {Buffer} blind - Blind hash. - * @returns {BlindValue} + * @returns {Promise} */ async getBlind(blind) { @@ -4763,7 +4864,7 @@ class Wallet extends EventEmitter { /** * Get all bids for name. - * @param {Buffer} nameHash + * @param {Buffer} [nameHash] * @returns {Promise} */ @@ -4773,8 +4874,8 @@ class Wallet extends EventEmitter { /** * Get all bids for name. - * @param {String|Buffer} name - * @returns {BlindBid[]} + * @param {String|Buffer} [name] + * @returns {Promise} */ async getBidsByName(name) { @@ -4796,7 +4897,7 @@ class Wallet extends EventEmitter { * Get reveal. * @param {Buffer} nameHash * @param {Outpoint} outpoint - * @returns {BidReveal?} + * @returns {Promise} */ async getReveal(nameHash, outpoint) { @@ -4806,7 +4907,7 @@ class Wallet extends EventEmitter { /** * Get all reveals by name. * @param {Buffer} nameHash - * @returns {BidReveal[]} + * @returns {Promise} */ async getReveals(nameHash) { @@ -4815,8 +4916,8 @@ class Wallet extends EventEmitter { /** * Get all reveals by name. - * @param {String} name - * @returns {BidReveal[]} + * @param {String|Buffer} name + * @returns {Promise} */ async getRevealsByName(name) { @@ -4827,7 +4928,7 @@ class Wallet extends EventEmitter { * Get reveal for bid. * @param {Buffer} nameHash * @param {Outpoint} outpoint - bid outpoint - * @returns {Promise} + * @returns {Promise} */ async getRevealByBid(nameHash, outpoint) { @@ -4898,7 +4999,7 @@ class Wallet extends EventEmitter { /** * Remove a wallet transaction. * @param {Hash} hash - * @returns {Promise} + * @returns {Promise} */ async remove(hash) { @@ -4931,7 +5032,7 @@ class Wallet extends EventEmitter { * Zap stale TXs from wallet. * @param {(Number|String)?} acct * @param {Number} age - Age threshold (unix time, default=72 hours). - * @returns {Promise} + * @returns {Promise} */ async zap(acct, age) { @@ -4948,7 +5049,7 @@ class Wallet extends EventEmitter { * @private * @param {(Number|String)?} acct * @param {Number} age - * @returns {Promise} + * @returns {Promise} */ async _zap(acct, age) { @@ -4959,7 +5060,7 @@ class Wallet extends EventEmitter { /** * Abandon transaction. * @param {Hash} hash - * @returns {Promise} + * @returns {Promise
} - removed tx details. */ async abandon(hash) { @@ -4975,7 +5076,7 @@ class Wallet extends EventEmitter { * Abandon transaction without a lock. * @private * @param {Hash} hash - * @returns {Promise} + * @returns {Promise
} - removed tx details. */ _abandon(hash) { @@ -4994,6 +5095,7 @@ class Wallet extends EventEmitter { /** * Unlock a single coin. * @param {Coin|Outpoint} coin + * @returns {Boolean} */ unlockCoin(coin) { @@ -5011,6 +5113,7 @@ class Wallet extends EventEmitter { /** * Test locked status of a single coin. * @param {Coin|Outpoint} coin + * @returns {Boolean} */ isLocked(coin) { @@ -5028,8 +5131,8 @@ class Wallet extends EventEmitter { /** * Get all available coins. - * @param {(String|Number)?} account - * @returns {Promise} - Returns {@link Coin}[]. + * @param {(String|Number)?} [acct] + * @returns {Promise} */ async getCoins(acct) { @@ -5039,8 +5142,8 @@ class Wallet extends EventEmitter { /** * Get all available credits. - * @param {(String|Number)?} account - * @returns {Promise} - Returns {@link Credit}[]. + * @param {(String|Number)?} [acct] + * @returns {Promise} */ async getCredits(acct) { @@ -5050,8 +5153,8 @@ class Wallet extends EventEmitter { /** * Get "smart" coins. - * @param {(String|Number)?} account - * @returns {Promise} - Returns {@link Coin}[]. + * @param {(String|Number)?} acct + * @returns {Promise} */ async getSmartCoins(acct) { @@ -5089,8 +5192,8 @@ class Wallet extends EventEmitter { /** * Get all pending/unconfirmed transactions. - * @param {(String|Number)?} acct - * @returns {Promise} - Returns {@link TX}[]. + * @param {(String|Number)?} [acct] + * @returns {Promise} */ async getPending(acct) { @@ -5100,8 +5203,8 @@ class Wallet extends EventEmitter { /** * Get wallet balance. - * @param {(String|Number)?} acct - * @returns {Promise} - Returns {@link Balance}. + * @param {(String|Number)?} [acct] + * @returns {Promise} */ async getBalance(acct) { @@ -5110,7 +5213,7 @@ class Wallet extends EventEmitter { } /** - * @param {(String|Number)} [acct] + * @param {(String|Number)?} acct * @param {Object} options * @param {Number} options.limit * @param {Boolean} options.reverse @@ -5123,9 +5226,9 @@ class Wallet extends EventEmitter { } /** - * @param {(String|Number)} [acct] + * @param {(String|Number)?} acct * @param {Object} options - * @param {String} options.hash + * @param {Buffer} options.hash * @param {Number} options.limit * @param {Boolean} options.reverse * @returns {Promise} @@ -5137,9 +5240,9 @@ class Wallet extends EventEmitter { } /** - * @param {(String|Number)} [acct] + * @param {(String|Number)?} acct * @param {Object} options - * @param {String} options.hash + * @param {Buffer} options.hash * @param {Number} options.limit * @param {Boolean} options.reverse * @returns {Promise} @@ -5151,7 +5254,7 @@ class Wallet extends EventEmitter { } /** - * @param {(String|Number)} [acct] + * @param {(String|Number)?} acct * @param {Object} options * @param {Number} options.time - Time in seconds. * @param {Number} options.limit @@ -5165,7 +5268,7 @@ class Wallet extends EventEmitter { } /** - * @param {(String|Number)} [acct] + * @param {(String|Number)?} acct * @param {Object} options * @param {Number} options.limit * @param {Boolean} options.reverse @@ -5178,7 +5281,7 @@ class Wallet extends EventEmitter { } /** - * @param {(String|Number)} [acct] + * @param {(String|Number)?} acct * @param {Object} options * @param {Buffer} options.hash * @param {Number} options.limit @@ -5192,7 +5295,7 @@ class Wallet extends EventEmitter { } /** - * @param {(String|Number)} [acct] + * @param {(String|Number)?} acct * @param {Object} options * @param {Buffer} options.hash * @param {Number} options.limit @@ -5206,7 +5309,7 @@ class Wallet extends EventEmitter { } /** - * @param {(String|Number)} [acct] + * @param {(String|Number)?} acct * @param {Object} options * @param {Number} options.time - Time in seconds. * @param {Number} options.limit @@ -5222,39 +5325,45 @@ class Wallet extends EventEmitter { /** * Get account key. * @param {Number} [acct=0] - * @returns {HDPublicKey} + * @returns {Promise} */ async accountKey(acct = 0) { const account = await this.getAccount(acct); + if (!account) throw new Error('Account not found.'); + return account.accountKey; } /** * Get current receive depth. * @param {Number} [acct=0] - * @returns {Number} + * @returns {Promise} */ async receiveDepth(acct = 0) { const account = await this.getAccount(acct); + if (!account) throw new Error('Account not found.'); + return account.receiveDepth; } /** * Get current change depth. * @param {Number} [acct=0] - * @returns {Number} + * @returns {Promise} */ async changeDepth(acct = 0) { const account = await this.getAccount(acct); + if (!account) throw new Error('Account not found.'); + return account.changeDepth; } @@ -5266,8 +5375,10 @@ class Wallet extends EventEmitter { async receiveAddress(acct = 0) { const account = await this.getAccount(acct); + if (!account) throw new Error('Account not found.'); + return account.receiveAddress(); } @@ -5279,34 +5390,40 @@ class Wallet extends EventEmitter { async changeAddress(acct = 0) { const account = await this.getAccount(acct); + if (!account) throw new Error('Account not found.'); + return account.changeAddress(); } /** * Get current receive key. * @param {Number} [acct=0] - * @returns {WalletKey} + * @returns {Promise} */ async receiveKey(acct = 0) { const account = await this.getAccount(acct); + if (!account) throw new Error('Account not found.'); + return account.receiveKey(); } /** * Get current change key. * @param {Number} [acct=0] - * @returns {WalletKey} + * @returns {Promise} */ async changeKey(acct = 0) { const account = await this.getAccount(acct); + if (!account) throw new Error('Account not found.'); + return account.changeKey(); } @@ -5339,8 +5456,9 @@ class Wallet extends EventEmitter { /** * Convert the wallet to an object suitable for * serialization. - * @param {Boolean?} unsafe - Whether to include + * @param {Boolean?} [unsafe] - Whether to include * the master key in the JSON. + * @param {Balance?} [balance] * @returns {Object} */ @@ -5354,20 +5472,18 @@ class Wallet extends EventEmitter { token: this.token.toString('hex'), tokenDepth: this.tokenDepth, master: this.master.getJSON(this.network, unsafe), - balance: balance ? balance.toJSON(true) : null + balance: balance ? balance.getJSON(true) : null }; } /** * Convert the wallet to an object suitable for * serialization. - * @param {Boolean?} unsafe - Whether to include - * the master key in the JSON. * @returns {Object} */ toJSON() { - return this.getJSON(); + return this.getJSON(false); } /** @@ -5407,8 +5523,8 @@ class Wallet extends EventEmitter { /** * Inject properties from serialized data. - * @private * @param {Buffer} data + * @returns {this} */ decode(data) { @@ -5427,6 +5543,7 @@ class Wallet extends EventEmitter { /** * Instantiate a wallet from serialized data. + * @param {WalletDB} wdb * @param {Buffer} data * @returns {Wallet} */ diff --git a/lib/wallet/walletcoinview.js b/lib/wallet/walletcoinview.js index 711b97caf..ffce981b9 100644 --- a/lib/wallet/walletcoinview.js +++ b/lib/wallet/walletcoinview.js @@ -11,14 +11,18 @@ const {BufferMap} = require('buffer-map'); const Paths = require('./paths'); const CoinView = require('../coins/coinview'); +/** @typedef {import('../types').Hash} Hash */ +/** @typedef {import('../primitives/outpoint')} Outpoint */ +/** @typedef {import('../primitives/input')} Input */ +/** @typedef {import('../primitives/coin')} Coin */ +/** @typedef {import('../coins/coins')} Coins */ +/** @typedef {import('./path')} Path */ + /** * Wallet Coin View * Represents a wallet, coin viewpoint: a snapshot of {@link Coins} objects * and the HD paths for their associated keys. * @alias module:wallet.WalletCoinView - * @property {Object} map - * @property {Object} paths - * @property {UndoCoins} undo */ class WalletCoinView extends CoinView { @@ -59,7 +63,7 @@ class WalletCoinView extends CoinView { /** * Add paths to the collection. * @param {Hash} hash - * @param {Paths} path + * @param {Paths} paths * @returns {Paths|null} */ @@ -91,7 +95,7 @@ class WalletCoinView extends CoinView { /** * Ensure existence of paths object in the collection. * @param {Hash} hash - * @returns {Coins} + * @returns {Paths} */ ensurePaths(hash) { @@ -105,7 +109,7 @@ class WalletCoinView extends CoinView { /** * Remove paths from the collection. - * @param {Paths} paths + * @param {Hash} hash * @returns {Paths|null} */ diff --git a/lib/wallet/walletdb.js b/lib/wallet/walletdb.js index 60705f159..eb0dc6e8a 100644 --- a/lib/wallet/walletdb.js +++ b/lib/wallet/walletdb.js @@ -35,9 +35,15 @@ const {states} = require('../covenants/namestate'); const util = require('../utils/util'); const {scanActions} = require('../blockchain/common'); +/** @typedef {ReturnType} Batch */ +/** @typedef {import('../types').Hash} Hash */ /** @typedef {import('../primitives/tx')} TX */ +/** @typedef {import('../primitives/claim')} Claim */ /** @typedef {import('../blockchain/common').ScanAction} ScanAction */ -/** @typedef {import('../types').Hash} Hash */ +/** @typedef {import('../blockchain/chainentry')} ChainEntry */ +/** @typedef {import('./records').BlockMeta} BlockMeta */ +/** @typedef {import('./txdb').BlockExtraInfo} BlockExtraInfo */ +/** @typedef {import('./walletkey')} WalletKey */ const { ChainState, @@ -46,9 +52,6 @@ const { MapRecord } = records; -/** @typedef {import('./records').BlockMeta} BlockMeta */ -/** @typedef {import('./txdb').BlockExtraInfo} BlockExtraInfo */ - /** * @typedef {Object} AddBlockResult * @property {Number} txs - Number of transactions added on this add. @@ -57,7 +60,7 @@ const { /** * @typedef {Object} AddTXResult - * @property {Number} wids - Wallet IDs affected. + * @property {Set} wids - Wallet IDs affected. * @property {Boolean} filterUpdated - Whether the bloom filter was updated. /** @@ -83,6 +86,7 @@ class WalletDB extends EventEmitter { this.workers = this.options.workers; this.client = this.options.client || new NullClient(this); this.feeRate = this.options.feeRate; + /** @type {bdb.DB} */ this.db = bdb.create(this.options); this.name = 'wallet'; this.version = 4; @@ -348,7 +352,7 @@ class WalletDB extends EventEmitter { return b.write(); } - const magic = raw.readUInt32LE(0, true); + const magic = raw.readUInt32LE(0); if (magic !== this.network.magic) throw new Error('Network mismatch for WalletDB.'); @@ -590,7 +594,6 @@ class WalletDB extends EventEmitter { /** * Rescan blockchain from a given height. * Needs this.rescanning = true to be set from the caller. - * @private * @param {Number} [height=this.state.startHeight] * @returns {Promise} */ @@ -716,7 +719,7 @@ class WalletDB extends EventEmitter { ); // remove all txdb data *except* blinds ('v') - const key = 'v'.charCodeAt(); + const key = 'v'.charCodeAt(0); const prefix = layout.t.encode(wallet.wid); await removeRange({ gte: Buffer.concat([prefix, Buffer.alloc(1)]), @@ -839,7 +842,7 @@ class WalletDB extends EventEmitter { /** * Get name state. * @param {Buffer} nameHash - * @returns {Object} + * @returns {Promise} */ async getNameStatus(nameHash) { @@ -850,7 +853,7 @@ class WalletDB extends EventEmitter { * Get UTXO from node. * @param {Hash} hash * @param {Number} index - * @returns {Object} + * @returns {Promise} */ async getCoin(hash, index) { @@ -860,7 +863,7 @@ class WalletDB extends EventEmitter { /** * Test whether name is available for CLAIM. * @param {Buffer} nameHash - * @returns {Boolean} + * @returns {Promise} */ async isAvailable(nameHash) { @@ -966,13 +969,13 @@ class WalletDB extends EventEmitter { if (!raw) return 0; - return raw.readUInt32LE(0, true); + return raw.readUInt32LE(0); } /** * Test the bloom filter against a tx or address hash. * @private - * @param {Hash} hash + * @param {Hash} data * @returns {Boolean} */ @@ -1025,7 +1028,7 @@ class WalletDB extends EventEmitter { /** * Register an object with the walletdb. - * @param {Object} object + * @param {Wallet} wallet */ register(wallet) { @@ -1035,8 +1038,7 @@ class WalletDB extends EventEmitter { /** * Unregister a object with the walletdb. - * @param {Object} object - * @returns {Boolean} + * @param {Wallet} wallet */ unregister(wallet) { @@ -1074,7 +1076,7 @@ class WalletDB extends EventEmitter { assert(data.length === 4); - return data.readUInt32LE(0, true); + return data.readUInt32LE(0); } /** @@ -1148,6 +1150,7 @@ class WalletDB extends EventEmitter { /** * Save a wallet to the database. + * @param {Batch} b * @param {Wallet} wallet */ @@ -1219,6 +1222,7 @@ class WalletDB extends EventEmitter { /** * Rename an account. + * @param {Batch} b * @param {Account} account * @param {String} name */ @@ -1242,7 +1246,7 @@ class WalletDB extends EventEmitter { /** * Remove a wallet. * @param {Number|String} id - * @returns {Promise} + * @returns {Promise} */ async remove(id) { @@ -1269,7 +1273,7 @@ class WalletDB extends EventEmitter { * Remove a wallet (without a lock). * @private * @param {Number} wid - * @returns {Promise} + * @returns {Promise} */ async _remove(wid) { @@ -1387,7 +1391,7 @@ class WalletDB extends EventEmitter { * Get a wallet with token auth first. * @param {Number|String} id * @param {Buffer} token - * @returns {Promise} - Returns {@link Wallet}. + * @returns {Promise} */ async auth(id, token) { @@ -1453,7 +1457,7 @@ class WalletDB extends EventEmitter { /** * Test for the existence of a wallet. * @param {Number|String} id - * @returns {Promise} + * @returns {Promise} */ async has(id) { @@ -1464,7 +1468,7 @@ class WalletDB extends EventEmitter { /** * Attempt to create wallet, return wallet if already exists. * @param {Object} options - See {@link Wallet}. - * @returns {Promise} + * @returns {Promise} */ async ensure(options) { @@ -1480,10 +1484,9 @@ class WalletDB extends EventEmitter { /** * Get an account from the database by wid. - * @private * @param {Number} wid * @param {Number} index - Account index. - * @returns {Promise} - Returns {@link Wallet}. + * @returns {Promise} */ async getAccount(wid, index) { @@ -1506,7 +1509,7 @@ class WalletDB extends EventEmitter { /** * List account names and indexes from the db. * @param {Number} wid - * @returns {Promise} - Returns Array. + * @returns {Promise} - Returns Array. */ async getAccounts(wid) { @@ -1521,7 +1524,7 @@ class WalletDB extends EventEmitter { * Lookup the corresponding account name's index. * @param {Number} wid * @param {String} name - Account name/index. - * @returns {Promise} - Returns Number. + * @returns {Promise} */ async getAccountIndex(wid, name) { @@ -1530,14 +1533,14 @@ class WalletDB extends EventEmitter { if (!index) return -1; - return index.readUInt32LE(0, true); + return index.readUInt32LE(0); } /** * Lookup the corresponding account index's name. * @param {Number} wid * @param {Number} index - * @returns {Promise} - Returns Number. + * @returns {Promise} */ async getAccountName(wid, index) { @@ -1551,8 +1554,8 @@ class WalletDB extends EventEmitter { /** * Save an account to the database. + * @param {Batch} b * @param {Account} account - * @returns {Promise} */ saveAccount(b, account) { @@ -1573,8 +1576,8 @@ class WalletDB extends EventEmitter { /** * Test for the existence of an account. * @param {Number} wid - * @param {String|Number} acct - * @returns {Promise} - Returns Boolean. + * @param {Number} index + * @returns {Promise} */ async hasAccount(wid, index) { @@ -1583,7 +1586,8 @@ class WalletDB extends EventEmitter { /** * Save an address to the path map. - * @param {Wallet} wallet + * @param {Batch} b + * @param {Number} wid * @param {WalletKey} ring * @returns {Promise} */ @@ -1600,7 +1604,8 @@ class WalletDB extends EventEmitter { * - `P[wid][address-hash] -> path data` * - `r[wid][account-index][address-hash] -> dummy` * - * @param {Wallet} wallet + * @param {Batch} b + * @param {Number} wid * @param {Path} path * @returns {Promise} */ @@ -1620,7 +1625,7 @@ class WalletDB extends EventEmitter { * Retrieve path by hash. * @param {Number} wid * @param {Hash} hash - * @returns {Promise} + * @returns {Promise} */ async getPath(wid, hash) { @@ -1639,7 +1644,7 @@ class WalletDB extends EventEmitter { * Retrieve path by hash. * @param {Number} wid * @param {Hash} hash - * @returns {Promise} + * @returns {Promise} */ async readPath(wid, hash) { @@ -1658,7 +1663,7 @@ class WalletDB extends EventEmitter { * Test whether a wallet contains a path. * @param {Number} wid * @param {Hash} hash - * @returns {Promise} + * @returns {Promise} */ async hasPath(wid, hash) { @@ -1667,7 +1672,7 @@ class WalletDB extends EventEmitter { /** * Get all address hashes. - * @returns {Promise} + * @returns {Promise} */ async getHashes() { @@ -1680,7 +1685,7 @@ class WalletDB extends EventEmitter { /** * Get all outpoints. - * @returns {Promise} + * @returns {Promise} */ async getOutpoints() { @@ -1697,7 +1702,7 @@ class WalletDB extends EventEmitter { /** * Get all address hashes. * @param {Number} wid - * @returns {Promise} + * @returns {Promise} */ async getWalletHashes(wid) { @@ -1712,7 +1717,7 @@ class WalletDB extends EventEmitter { * Get all account address hashes. * @param {Number} wid * @param {Number} account - * @returns {Promise} + * @returns {Promise} */ async getAccountHashes(wid, account) { @@ -1726,7 +1731,7 @@ class WalletDB extends EventEmitter { /** * Get all paths for a wallet. * @param {Number} wid - * @returns {Promise} + * @returns {Promise} */ async getWalletPaths(wid) { @@ -1766,6 +1771,7 @@ class WalletDB extends EventEmitter { /** * Encrypt all imported keys for a wallet. + * @param {Batch} b * @param {Number} wid * @param {Buffer} key * @returns {Promise} @@ -1798,6 +1804,7 @@ class WalletDB extends EventEmitter { /** * Decrypt all imported keys for a wallet. + * @param {Batch} b * @param {Number} wid * @param {Buffer} key * @returns {Promise} @@ -1893,11 +1900,12 @@ class WalletDB extends EventEmitter { /** * Get all wallet ids by output addresses and outpoints. - * @param {Hash[]} hashes - * @returns {Promise} + * @param {TX} tx + * @returns {Promise>} */ async getWalletsByTX(tx) { + /** @type {Set} */ const wids = new Set(); if (!tx.isCoinbase()) { @@ -1958,7 +1966,7 @@ class WalletDB extends EventEmitter { /** * Get the best block hash. - * @returns {Promise} + * @returns {Promise} */ async getState() { @@ -2038,7 +2046,7 @@ class WalletDB extends EventEmitter { /** * Get a wallet map. * @param {Buffer} key - * @returns {Promise} + * @returns {Promise} */ async getMap(key) { @@ -2068,9 +2076,10 @@ class WalletDB extends EventEmitter { /** * Add wid to a wallet map. - * @param {Wallet} wallet + * @param {Batch} b * @param {Buffer} key * @param {Number} wid + * @returns {Promise} */ async addMap(b, key, wid) { @@ -2095,9 +2104,10 @@ class WalletDB extends EventEmitter { /** * Remove wid from a wallet map. - * @param {Wallet} wallet + * @param {Batch} b * @param {Buffer} key * @param {Number} wid + * @returns {Promise} */ async removeMap(b, key, wid) { @@ -2119,8 +2129,8 @@ class WalletDB extends EventEmitter { /** * Get a wallet map. - * @param {Buffer} key - * @returns {Promise} + * @param {Hash} hash + * @returns {Promise} */ async getPathMap(hash) { @@ -2129,9 +2139,10 @@ class WalletDB extends EventEmitter { /** * Add wid to a wallet map. - * @param {Wallet} wallet - * @param {Buffer} key + * @param {Batch} b + * @param {Hash} hash * @param {Number} wid + * @returns {Promise} */ async addPathMap(b, hash, wid) { @@ -2141,9 +2152,10 @@ class WalletDB extends EventEmitter { /** * Remove wid from a wallet map. - * @param {Wallet} wallet - * @param {Buffer} key + * @param {Batch} b + * @param {Hash} hash * @param {Number} wid + * @returns {Promise} */ async removePathMap(b, hash, wid) { @@ -2152,8 +2164,8 @@ class WalletDB extends EventEmitter { /** * Get a wallet map. - * @param {Buffer} key - * @returns {Promise} + * @param {Number} height + * @returns {Promise} */ async getBlockMap(height) { @@ -2162,9 +2174,10 @@ class WalletDB extends EventEmitter { /** * Add wid to a wallet map. - * @param {Wallet} wallet - * @param {Buffer} key + * @param {Batch} b + * @param {Number} height * @param {Number} wid + * @returns {Promise} */ async addBlockMap(b, height, wid) { @@ -2173,9 +2186,10 @@ class WalletDB extends EventEmitter { /** * Remove wid from a wallet map. - * @param {Wallet} wallet - * @param {Buffer} key + * @param {Batch} b + * @param {Number} height * @param {Number} wid + * @returns {Promise} */ async removeBlockMap(b, height, wid) { @@ -2184,8 +2198,8 @@ class WalletDB extends EventEmitter { /** * Get a wallet map. - * @param {Buffer} key - * @returns {Promise} + * @param {Hash} hash + * @returns {Promise} */ async getTXMap(hash) { @@ -2194,9 +2208,10 @@ class WalletDB extends EventEmitter { /** * Add wid to a wallet map. - * @param {Wallet} wallet - * @param {Buffer} key + * @param {Batch} b + * @param {Hash} hash * @param {Number} wid + * @returns {Promise} */ async addTXMap(b, hash, wid) { @@ -2205,9 +2220,10 @@ class WalletDB extends EventEmitter { /** * Remove wid from a wallet map. - * @param {Wallet} wallet - * @param {Buffer} key + * @param {Batch} b + * @param {Hash} hash * @param {Number} wid + * @returns {Promise} */ async removeTXMap(b, hash, wid) { @@ -2216,8 +2232,9 @@ class WalletDB extends EventEmitter { /** * Get a wallet map. - * @param {Buffer} key - * @returns {Promise} + * @param {Hash} hash + * @param {Number} index + * @returns {Promise} */ async getOutpointMap(hash, index) { @@ -2226,9 +2243,11 @@ class WalletDB extends EventEmitter { /** * Add wid to a wallet map. - * @param {Wallet} wallet - * @param {Buffer} key + * @param {Batch} b + * @param {Hash} hash + * @param {Number} index * @param {Number} wid + * @returns {Promise} */ async addOutpointMap(b, hash, index, wid) { @@ -2238,9 +2257,11 @@ class WalletDB extends EventEmitter { /** * Remove wid from a wallet map. - * @param {Wallet} wallet - * @param {Buffer} key + * @param {Batch} b + * @param {Hash} hash + * @param {Number} index * @param {Number} wid + * @returns {Promise} */ async removeOutpointMap(b, hash, index, wid) { @@ -2249,8 +2270,8 @@ class WalletDB extends EventEmitter { /** * Get a wallet map. - * @param {Buffer} key - * @returns {Promise} + * @param {Hash} nameHash + * @returns {Promise} */ async getNameMap(nameHash) { @@ -2270,9 +2291,10 @@ class WalletDB extends EventEmitter { /** * Add wid to a wallet map. - * @param {Wallet} wallet - * @param {Buffer} key + * @param {Batch} b + * @param {Hash} nameHash * @param {Number} wid + * @returns {Promise} */ async addNameMap(b, nameHash, wid) { @@ -2282,9 +2304,10 @@ class WalletDB extends EventEmitter { /** * Remove wid from a wallet map. - * @param {Wallet} wallet - * @param {Buffer} key + * @param {Batch} b + * @param {Hash} nameHash * @param {Number} wid + * @returns {Promise} */ async removeNameMap(b, nameHash, wid) { @@ -2308,7 +2331,6 @@ class WalletDB extends EventEmitter { /** * Get wallet tip. - * @param {Hash} hash * @returns {Promise} */ @@ -2323,7 +2345,7 @@ class WalletDB extends EventEmitter { /** * Get renewal block hash. - * @returns {Buffer} + * @returns {Promise} */ async getRenewalBlock() { @@ -3013,12 +3035,22 @@ class WalletOptions { * Helpers */ +/** + * @param {Number} num + * @returns {Buffer} + */ + function fromU32(num) { const data = Buffer.allocUnsafe(4); - data.writeUInt32LE(num, 0, true); + data.writeUInt32LE(num, 0); return data; } +/** + * @param {String} str + * @returns {Buffer} + */ + function fromString(str) { const buf = Buffer.alloc(1 + str.length); buf[0] = str.length; diff --git a/lib/wallet/walletkey.js b/lib/wallet/walletkey.js index a8c1e988d..4fa5d29b1 100644 --- a/lib/wallet/walletkey.js +++ b/lib/wallet/walletkey.js @@ -9,6 +9,11 @@ const KeyRing = require('../primitives/keyring'); const Path = require('./path'); +/** @typedef {import('../hd/private')} HDPrivateKey */ +/** @typedef {import('../hd/public')} HDPublicKey */ +/** @typedef {import('../protocol/network')} Network */ +/** @typedef {import('./account')} Account */ + /** * Wallet Key * Represents a key ring which amounts to an address. @@ -36,6 +41,7 @@ class WalletKey extends KeyRing { /** * Convert an WalletKey to a more json-friendly object. + * @param {Network} [network] * @returns {Object} */ @@ -53,12 +59,11 @@ class WalletKey extends KeyRing { /** * Inject properties from hd key. - * @private * @param {Account} account * @param {HDPrivateKey|HDPublicKey} key * @param {Number} branch * @param {Number} index - * @returns {WalletKey} + * @returns {this} */ fromHD(account, key, branch, index) { @@ -89,7 +94,6 @@ class WalletKey extends KeyRing { /** * Inject properties from imported data. - * @private * @param {Account} account * @param {Buffer} data * @returns {WalletKey} diff --git a/package-lock.json b/package-lock.json index fbc1919d9..07124c7f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,8 @@ "hsw-rpc": "bin/hsw-rpc" }, "devDependencies": { - "bmocha": "^2.2.0" + "bmocha": "^2.2.0", + "bslintrc": "^0.0.3" }, "engines": { "node": ">=14.0.0" @@ -311,6 +312,16 @@ "node": ">=8.0.0" } }, + "node_modules/bslintrc": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/bslintrc/-/bslintrc-0.0.3.tgz", + "integrity": "sha512-h95ityvrnwr5fMgX7OjyOqYXIRjWXKcZB/+RhkaKuoGlgNUOAkYnPaF5DYJ+BO6WfWkKsLeZfFWq0gU8OfWhpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/bsock": { "version": "0.1.11", "resolved": "https://registry.npmjs.org/bsock/-/bsock-0.1.11.tgz", diff --git a/package.json b/package.json index ed1fc55f6..9855c1ecc 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "node": ">=14.0.0" }, "dependencies": { + "@handshake-org/bfilter": "~2.3.0", "bcfg": "~0.2.2", "bcrypto": "~5.4.0", "bcurl": "~0.2.1", @@ -27,7 +28,6 @@ "bdns": "~0.1.5", "bevent": "~0.1.6", "bfile": "~0.2.3", - "@handshake-org/bfilter": "~2.3.0", "bheep": "~0.1.6", "binet": "~0.3.9", "blgr": "~0.2.1", @@ -49,7 +49,8 @@ "urkel": "~1.0.3" }, "devDependencies": { - "bmocha": "^2.2.0" + "bmocha": "^2.2.0", + "bslintrc": "^0.0.3" }, "main": "./lib/hsd.js", "bin": {