diff --git a/bin/bcoin-cli b/bin/bcoin-cli index 9b8b6877..f0f168d4 100755 --- a/bin/bcoin-cli +++ b/bin/bcoin-cli @@ -41,18 +41,12 @@ function createWallet(callback) { if (argv.lookahead) options.lookahead = argv.lookahead >>> 0; - if (argv.derivation) - options.derivation = argv.derivation; - if (argv.m) options.m = argv.m >>> 0; if (argv.n) options.n = argv.n >>> 0; - if (argv.copay != null) - options.copayBIP45 = !!argv.copay; - if (argv.witness != null) options.witness = !!argv.witness; @@ -63,7 +57,6 @@ function createWallet(callback) { if (err) return callback(err); utils.print(wallet); - wallet.destroy(); callback(); }); } @@ -75,7 +68,7 @@ function addKey(callback) { keys = keys.split(','); else keys = argv.args; - client.addKey(id, keys, function(err, wallet) { + client.addKey(id, argv.account, keys, function(err, wallet) { if (err) return callback(err); utils.print('added'); @@ -90,7 +83,7 @@ function removeKey(callback) { keys = keys.split(','); else keys = argv.args; - client.removeKey(id, keys, function(err) { + client.removeKey(id, argv.account, keys, function(err) { if (err) return callback(err); utils.print('removed'); @@ -101,7 +94,7 @@ function removeKey(callback) { function getWallet(callback) { var id = getID(); var passphrase = argv.args[0]; - client.getWallet(id, passphrase, function(err, wallet) { + client.getWallet(id, argv.account, passphrase, function(err, wallet) { if (err) return callback(err); utils.print(wallet); @@ -185,7 +178,7 @@ function getCoin(callback) { function getWalletHistory(callback) { var id = getID(); - client.getWalletHistory(id, function(err, txs) { + client.getWalletHistory(id, argv.account, function(err, txs) { if (err) return callback(err); utils.print(txs); @@ -195,7 +188,7 @@ function getWalletHistory(callback) { function listenWallet(callback) { var id = getID(); - client.listenWallet(id); + client.join(id); client.on('tx', function(tx, map) { utils.print('TX:'); utils.print(tx); @@ -220,7 +213,7 @@ function listenWallet(callback) { function getBalance(callback) { var id = getID(); - client.getWalletBalance(id, function(err, balance) { + client.getWalletBalance(id, argv.account, function(err, balance) { if (err) return callback(err); utils.print('Confirmed: %s', utils.btc(balance.confirmed)); @@ -241,15 +234,16 @@ function getMempool(callback) { function send(callback) { var id = getID(); - var options = {}; + var options = { account: argv.account, passphrase: argv.passphrase }; + var output = {}; if (argv.script) { - options.script = new bcoin.script(new Buffer(argv.script, 'hex')); - options.value = utils.satoshi(argv.value || argv.args[0]); + output.script = new bcoin.script(new Buffer(argv.script, 'hex')); + output.value = utils.satoshi(argv.value || argv.args[0]); } else { - options.address = argv.address || argv.args[0]; - options.value = utils.satoshi(argv.value || argv.args[1]); + output.address = argv.address || argv.args[0]; + output.value = utils.satoshi(argv.value || argv.args[1]); } - client.walletSend(id, options, function(err, tx) { + client.walletSend(id, options, [output], function(err, tx) { if (err) return callback(err); utils.print(tx); @@ -259,9 +253,8 @@ function send(callback) { function zap(callback) { var id = getID(); - var now = (argv.now >>> 0) || utils.now(); var age = (argv.age >>> 0) || 72 * 60 * 60; - client.walletZap(id, now, age, function(err) { + client.walletZap(id, argv.account, age, function(err) { if (err) return callback(err); utils.print('zapped'); @@ -309,7 +302,7 @@ function main(callback) { utils.print(' $ balance [id]: Get wallet balance.'); utils.print(' $ history [id]: View wallet TX history.'); utils.print(' $ send [id] [address] [value] --script [code]: Send transaction.'); - utils.print(' $ zap [id] --now [now] --age [age]: Zap pending wallet TXs.'); + utils.print(' $ zap [id] --age [age]: Zap pending wallet TXs.'); utils.print(' $ mempool: Get mempool snapshot.'); utils.print(' $ tx [hash/address]: View transactions.'); utils.print(' $ coin [hash+index/address]: View coins.'); @@ -374,7 +367,7 @@ function parseArg(argv) { client.getInfo(function(err, info) { if (err) { console.error(err.stack + ''); - return process.exit(1); + //return process.exit(1); } if (!argv.args[0]) diff --git a/lib/bcoin/http/base.js b/lib/bcoin/http/base.js index 3dcd691a..b4185744 100644 --- a/lib/bcoin/http/base.js +++ b/lib/bcoin/http/base.js @@ -99,7 +99,7 @@ HTTPBase.prototype._initRouter = function _initRouter() { function done(err) { if (err) { - send(res, 400, { error: err.stack + '' }); + send(res, 400, { error: err.message + '' }); try { req.destroy(); req.socket.destroy(); @@ -372,7 +372,7 @@ function compilePath(path) { return { regex: path, map: map }; var regex = path - .replace(/([^\/]+)\?/g, '(?:$1)?') + .replace(/(\/[^\/]+)\?/g, '(?:$1)?') .replace(/\.(?!\+)/g, '\\.') .replace(/\*/g, '.*?') .replace(/%/g, '\\') diff --git a/lib/bcoin/http/client.js b/lib/bcoin/http/client.js index 50acd85e..845af42c 100644 --- a/lib/bcoin/http/client.js +++ b/lib/bcoin/http/client.js @@ -136,7 +136,7 @@ HTTPClient.prototype.open = function open(callback) { * @param {WalletID} id */ -HTTPClient.prototype.listenWallet = function listenWallet(id) { +HTTPClient.prototype.join = function join(id) { if (!this.socket) return; @@ -148,7 +148,7 @@ HTTPClient.prototype.listenWallet = function listenWallet(id) { * @param {WalletID} id */ -HTTPClient.prototype.unlistenWallet = function unlistenWallet(id) { +HTTPClient.prototype.leave = function leave(id) { if (!this.socket) return; @@ -159,16 +159,16 @@ HTTPClient.prototype.unlistenWallet = function unlistenWallet(id) { * Listen for events on all wallets. */ -HTTPClient.prototype.listenAll = function listenAll() { - this.listenWallet('!all'); +HTTPClient.prototype.all = function all() { + this.join('!all'); }; /** * Unlisten for events on all wallets. */ -HTTPClient.prototype.unlistenAll = function unlistenAll() { - this.unlistenWallet('!all'); +HTTPClient.prototype.none = function none() { + this.leave('!all'); }; /** @@ -233,8 +233,11 @@ HTTPClient.prototype._request = function _request(method, endpoint, json, callba if (!body) return callback(new Error('No body.')); - if (res.statusCode !== 200) + if (res.statusCode !== 200) { + if (body.error) + return callback(new Error(body.error)); return callback(new Error('Status code: ' + res.statusCode)); + } try { return callback(null, body); @@ -299,7 +302,7 @@ HTTPClient.prototype._del = function _del(endpoint, json, callback) { * @param {Function} callback - Returns [Error, Object]. */ -HTTPClient.prototype._createWallet = function createWallet(options, callback) { +HTTPClient.prototype.createWallet = function createWallet(options, callback) { return this._post('/wallet', options, callback); }; @@ -310,71 +313,27 @@ HTTPClient.prototype._createWallet = function createWallet(options, callback) { * @param {Function} callback - Returns [Error, Object]. */ -HTTPClient.prototype._getWallet = function getWallet(id, callback) { +HTTPClient.prototype.getWallet = function getWallet(id, callback) { return this._get('/wallet/' + id, callback); }; -/** - * Get wallet and setup http provider (note that the - * passphrase is _not_ sent over the wire). - * @param {WalletID} id - * @param {String?} passphrase - * @param {Function} callback - Returns [Error, {@link Wallet}]. - */ - -HTTPClient.prototype.getWallet = function getWallet(id, passphrase, callback) { - var self = this; - - return this._getWallet(id, function(err, json) { - if (err) - return callback(err); - - try { - json = bcoin.wallet.parseJSON(json, passphrase); - } catch (e) { - return callback(e); - } - - json.provider = new bcoin.http.provider(self.options); - - return callback(null, new bcoin.wallet(json)); - }); -}; - -/** - * Get wallet and setup http provider (note that the - * passphrase is _not_ sent over the wire). - * @param {WalletID} id - * @param {String?} passphrase - * @param {Function} callback - Returns [Error, {@link Wallet}]. - */ - -HTTPClient.prototype.createWallet = function createWallet(options, callback) { - var self = this; - return this._createWallet(options, function(err, json) { - if (err) - return callback(err); - - try { - json = bcoin.wallet.parseJSON(json, options.passphrase); - } catch (e) { - return callback(e); - } - - json.provider = new bcoin.http.provider(self.options); - - return callback(null, new bcoin.wallet(json)); - }); -}; - /** * Get wallet transaction history. * @param {WalletID} id * @param {Function} callback - Returns [Error, {@link TX}[]]. */ -HTTPClient.prototype.getWalletHistory = function getWalletHistory(id, callback) { - return this._get('/wallet/' + id + '/tx/history', function(err, body) { +HTTPClient.prototype.getWalletHistory = function getWalletHistory(id, account, callback) { + var options; + + if (typeof account === 'function') { + callback = account; + account = null; + } + + options = { account: account }; + + return this._get('/wallet/' + id + '/tx/history', options, function(err, body) { if (err) return callback(err); @@ -399,8 +358,17 @@ HTTPClient.prototype.getWalletHistory = function getWalletHistory(id, callback) * @param {Function} callback - Returns [Error, {@link Coin}[]]. */ -HTTPClient.prototype.getWalletCoins = function getWalletCoins(id, callback) { - return this._get('/wallet/' + id + '/coin', function(err, body) { +HTTPClient.prototype.getWalletCoins = function getWalletCoins(id, account, callback) { + var options; + + if (typeof account === 'function') { + callback = account; + account = null; + } + + options = { account: account }; + + return this._get('/wallet/' + id + '/coin', options, function(err, body) { if (err) return callback(err); @@ -425,8 +393,17 @@ HTTPClient.prototype.getWalletCoins = function getWalletCoins(id, callback) { * @param {Function} callback - Returns [Error, {@link TX}[]]. */ -HTTPClient.prototype.getWalletUnconfirmed = function getUnconfirmed(id, callback) { - return this._get('/wallet/' + id + '/tx/unconfirmed', function(err, body) { +HTTPClient.prototype.getWalletUnconfirmed = function getUnconfirmed(id, account, callback) { + var options; + + if (typeof account === 'function') { + callback = account; + account = null; + } + + options = { account: account }; + + return this._get('/wallet/' + id + '/tx/unconfirmed', options, function(err, body) { if (err) return callback(err); @@ -451,8 +428,17 @@ HTTPClient.prototype.getWalletUnconfirmed = function getUnconfirmed(id, callback * @param {Function} callback - Returns [Error, {@link Balance}]. */ -HTTPClient.prototype.getWalletBalance = function getBalance(id, callback) { - return this._get('/wallet/' + id + '/balance', function(err, body) { +HTTPClient.prototype.getWalletBalance = function getBalance(id, account, callback) { + var options; + + if (typeof account === 'function') { + callback = account; + account = null; + } + + options = { account: account }; + + return this._get('/wallet/' + id + '/balance', options, function(err, body) { if (err) return callback(err); @@ -474,8 +460,16 @@ HTTPClient.prototype.getWalletBalance = function getBalance(id, callback) { * @param {Function} callback - Returns [Error, {@link TX}[]]. */ -HTTPClient.prototype.getWalletLast = function getWalletLast(id, limit, callback) { - var options = { limit: limit }; +HTTPClient.prototype.getWalletLast = function getWalletLast(id, account, limit, callback) { + var options; + + if (typeof account === 'function') { + callback = account; + account = null; + } + + options = { account: account, limit: limit }; + return this._get('/wallet/' + id + '/tx/last', options, function(err, body) { if (err) return callback(err); @@ -506,7 +500,16 @@ HTTPClient.prototype.getWalletLast = function getWalletLast(id, limit, callback) * @param {Function} callback - Returns [Error, {@link TX}[]]. */ -HTTPClient.prototype.getWalletRange = function getWalletRange(id, options, callback) { +HTTPClient.prototype.getWalletRange = function getWalletRange(id, account, options, callback) { + if (typeof options === 'function') { + callback = options; + options = account; + account = null; + } + + if (!options.account) + options.account = account; + return this._get('/wallet/' + id + '/tx/range', options, function(err, body) { if (err) return callback(err); @@ -534,10 +537,20 @@ HTTPClient.prototype.getWalletRange = function getWalletRange(id, options, callb * @param {Function} callback - Returns [Error, {@link TX}[]]. */ -HTTPClient.prototype.getWalletTX = function getTX(id, hash, callback) { +HTTPClient.prototype.getWalletTX = function getTX(id, account, hash, callback) { + var options; + + if (typeof hash === 'function') { + callback = hash; + hash = account; + account = null; + } + + options = { account: account }; + hash = utils.revHex(hash); - return this._get('/wallet/' + id + '/tx/' + hash, function(err, body) { + return this._get('/wallet/' + id + '/tx/' + hash, options, function(err, body) { if (err) return callback(err); @@ -563,13 +576,22 @@ HTTPClient.prototype.getWalletTX = function getTX(id, hash, callback) { * @param {Function} callback - Returns [Error, {@link Coin}[]]. */ -HTTPClient.prototype.getWalletCoin = function getCoin(id, hash, index, callback) { - var path; +HTTPClient.prototype.getWalletCoin = function getCoin(id, account, hash, index, callback) { + var options, path; + + if (typeof hash === 'function') { + callback = index; + index = hash; + hash = account; + account = null; + } + + options = { account: account }; hash = utils.revHex(hash); path = '/wallet/' + id + '/coin/' + hash + '/' + index; - return this._get(path, function(err, body) { + return this._get(path, options, function(err, body) { if (err) return callback(err); @@ -586,28 +608,6 @@ HTTPClient.prototype.getWalletCoin = function getCoin(id, hash, index, callback) }); }; -/** - * Sync wallet receive and change depth with the server. - * @param {WalletID} id - * @param {Object} options - * @param {Number} options.receiveDepth - * @param {Number} options.changeDepth - * @param {Function} callback - */ - -HTTPClient.prototype.syncWallet = function syncWallet(id, options, callback) { - var body = { - receiveDepth: options.receiveDepth, - changeDepth: options.changeDepth - }; - - return this._put('/wallet/' + id, body, function(err) { - if (err) - return callback(err); - return callback(); - }); -}; - /** * Get coins that pertain to an address from the mempool or chain database. * Takes into account spent coins in the mempool. @@ -774,15 +774,114 @@ HTTPClient.prototype.broadcast = function broadcast(tx, callback) { * @param {Function} callback - Returns [Error, {@link TX}]. */ -HTTPClient.prototype.walletSend = function walletSend(id, options, callback) { - var body = { - address: options.address, - value: utils.btc(options.value) +HTTPClient.prototype.walletSend = function walletSend(id, options, outputs, callback) { + if (typeof outputs === 'function') { + callback = outputs; + outputs = null; + } + + options = utils.merge({}, options); + options.outputs = outputs || options.outputs || []; + + if (!Array.isArray(options.outputs)) + options.outputs = [options.outputs]; + + options.outputs = options.outputs.map(function(output) { + return { + value: utils.btc(output.value), + address: output.address && output.address.toBase58 + ? output.address.toBase58() + : output.address, + script: output.script ? output.script.toRaw('hex') : null + } + }); + + callback = utils.ensure(callback); + + return this._post('/wallet/' + id + '/send', options, function(err, body) { + if (err) + return callback(err); + + try { + body = bcoin.tx.fromJSON(body); + } catch (e) { + return callback(e); + } + + return callback(null, body); + }); +}; + +/** + * Create a transaction, fill. + * @param {WalletID} id + * @param {Object} options + * @param {Base58Address} options.address + * @param {Amount} options.value + * @param {Function} callback - Returns [Error, {@link TX}]. + */ + +HTTPClient.prototype.walletCreate = function walletCreate(id, options, outputs, callback) { + if (typeof outputs === 'function') { + callback = outputs; + outputs = null; + } + + options = utils.merge({}, options); + options.outputs = outputs || options.outputs || []; + + if (!Array.isArray(options.outputs)) + options.outputs = [options.outputs]; + + options.outputs = options.outputs.map(function(output) { + return { + value: utils.btc(output.value), + address: output.address && output.address.toBase58 + ? output.address.toBase58() + : output.address, + script: output.script ? output.script.toRaw('hex') : null + } + }); + + callback = utils.ensure(callback); + + return this._post('/wallet/' + id + '/create', options, function(err, body) { + if (err) + return callback(err); + + try { + body = bcoin.tx.fromJSON(body); + } catch (e) { + return callback(e); + } + + return callback(null, body); + }); +}; + +/** + * Sign a transaction. + * @param {WalletID} id + * @param {Object} options + * @param {Function} callback - Returns [Error, {@link TX}]. + */ + +HTTPClient.prototype.walletSign = function walletCreate(id, account, options, callback) { + var body; + + if (typeof options === 'function') { + callback = options; + options = account; + account = null; + } + + body = { + account: account || options.account }; callback = utils.ensure(callback); - return this._post('/wallet/' + id + '/send', body, function(err, body) { + return this._post('/wallet/' + id + '/sign', body, function(err, body) { if (err) return callback(err); @@ -803,15 +902,21 @@ HTTPClient.prototype.walletSend = function walletSend(id, options, callback) { * @param {Function} callback */ -HTTPClient.prototype.zapWallet = function zapWallet(id, now, age, callback) { - var body = { - now: now, +HTTPClient.prototype.walletZap = function walletZap(id, account, age, callback) { + var body; + + if (typeof age === 'function') { + callback = age; + age = account; + account = null; + } + + body = { + account: account, age: age }; - assert(utils.isNumber(now)); assert(utils.isNumber(age)); - assert(now >= age); callback = utils.ensure(callback); @@ -830,14 +935,24 @@ HTTPClient.prototype.zapWallet = function zapWallet(id, now, age, callback) { * @param {Function} callback */ -HTTPClient.prototype.addKey = function addKey(id, keys, callback) { +HTTPClient.prototype.addKey = function addKey(id, account, keys, callback) { + var options; + + if (typeof keys === 'function') { + callback = keys; + keys = account; + account = null; + } + if (!Array.isArray(keys)) keys = [keys]; keys = keys.map(function(key) { - return key || key.xpubkey; + return key.xpubkey || key; }); + options = { account: account, keys: keys }; + callback = utils.ensure(callback); return this._put('/wallet/' + id + '/key', keys, function(err) { @@ -856,13 +971,23 @@ HTTPClient.prototype.addKey = function addKey(id, keys, callback) { */ HTTPClient.prototype.removeKey = function removeKey(id, keys, callback) { + var options; + + if (typeof keys === 'function') { + callback = keys; + keys = account; + account = null; + } + if (!Array.isArray(keys)) keys = [keys]; keys = keys.map(function(key) { - return key || key.xpubkey; + return key.xpubkey || key; }); + options = { account: account, keys: keys }; + callback = utils.ensure(callback); return this._del('/wallet/' + id + '/key', keys, function(err) { diff --git a/lib/bcoin/http/server.js b/lib/bcoin/http/server.js index d7250d29..31c59fee 100644 --- a/lib/bcoin/http/server.js +++ b/lib/bcoin/http/server.js @@ -75,9 +75,12 @@ HTTPServer.prototype._init = function _init() { }); this.use(function(req, res, next, send) { - var params = utils.merge({}, req.query, req.body, req.params); + var params = utils.merge({}, req.params, req.query, req.body); var options = {}; + bcoin.debug('Params:'); + bcoin.debug(params); + if (params.id) { assert(params.id !== '!all'); options.id = params.id; @@ -147,6 +150,9 @@ HTTPServer.prototype._init = function _init() { } } + if (params.account) + options.account = params.account; + if (params.now) options.now = params.now >>> 0; @@ -313,24 +319,57 @@ HTTPServer.prototype._init = function _init() { }); }); - // Get wallet - this.get('/wallet/:id', function(req, res, next, send) { - self.walletdb.getJSON(req.options.id, function(err, json) { + // Mempool snapshot + this.get('/mempool', function(req, res, next, send) { + self.node.mempool.getHistory(function(err, txs) { if (err) return next(err); - if (!json) + if (!txs.length) return send(404); - send(200, json); + utils.forEach(txs, function(tx, next) { + self.node.fillHistory(tx, next); + }, function(err) { + if (err) + return next(err); + + send(200, txs.map(function(tx) { + return tx.toJSON(); + })); + }); + }); + }); + + // Broadcast TX + this.post('/broadcast', function(req, res, next, send) { + self.node.sendTX(req.options.tx, function(err) { + if (err) + return next(err); + + send(200, { + success: true + }); + }); + }); + + // Get wallet + this.get('/wallet/:id', function(req, res, next, send) { + self.walletdb.getInfo(req.options.id, function(err, wallet) { + if (err) + return next(err); + + if (!wallet) + return send(404); + + send(200, wallet.toJSON()); }); }); // Create/get wallet - this.post(['/wallet', '/wallet/:id'], function(req, res, next, send) { + this.post('/wallet/:id?', function(req, res, next, send) { + var json; self.walletdb.ensure(req.options, function(err, wallet) { - var json; - if (err) return next(err); @@ -344,29 +383,38 @@ HTTPServer.prototype._init = function _init() { }); }); - // Send TX - this.post('/wallet/:id/send', function(req, res, next, send) { + // Create/get account + this.post('/wallet/:id/:account', function(req, res, next, send) { var id = req.options.id; - var passphrase = req.options.passphrase; + var account = req.options.account; + var options = req.options; + self.walletdb.makeAccount(id, account, options, function(err, account) { + if (err) + return next(err); + + if (!account) + return send(404); + + send(200, account.toJSON()); + }); + }); + + // Send TX + this.post('/wallet/:id/:account?/send', function(req, res, next, send) { + var id = req.options.id; + var options = req.options; var outputs = req.options.outputs; if (!Array.isArray(outputs)) return send(400); - self.walletdb.get(id, passphrase, function(err, wallet) { + self.walletdb.createTX(id, options, outputs, function(err, tx) { if (err) return next(err); - if (!wallet) - return send(404); - - wallet.createTX(outputs, function(err, tx) { - if (err) { - wallet.destroy(); + self.walletdb.sign(id, tx, options, function(err) { + if (err) return next(err); - } - - wallet.destroy(); self.node.sendTX(tx, function(err) { if (err) @@ -378,29 +426,43 @@ HTTPServer.prototype._init = function _init() { }); }); - // Zap Wallet TXs - this.post('/wallet/:id/zap', function(req, res, next, send) { + // Create TX + this.post('/wallet/:id/:account?/create', function(req, res, next, send) { var id = req.options.id; - var now = req.options.now; - var age = req.options.age; + var options = req.options; + var outputs = req.options.outputs; - self.walletdb.zapWallet(id, now, age, function(err) { + if (!Array.isArray(outputs)) + return send(400); + + self.walletdb.createTX(id, options, outputs, function(err, tx) { if (err) return next(err); - send(200, { - success: true - }); + send(200, tx.toJSON()); }); }); - // Update wallet / sync address depth - this.put('/wallet/:id', function(req, res, next, send) { + // Sign TX + this.post('/wallet/:id/:account?/sign', function(req, res, next, send) { var id = req.options.id; - var receive = req.options.receiveDepth; - var change = req.options.changeDepth; + var options = req.options; - self.walletdb.setDepth(id, receive, change, function(err) { + self.walletdb.sign(id, tx, options, function(err) { + if (err) + return next(err); + + send(200, tx.toJSON()); + }); + }); + + // Zap Wallet TXs + this.post('/wallet/:id/:account?/zap', function(req, res, next, send) { + var id = req.options.id; + var account = req.options.account; + var age = req.options.age; + + self.walletdb.zap(id, account, age, function(err) { if (err) return next(err); @@ -411,8 +473,11 @@ HTTPServer.prototype._init = function _init() { }); // Add key - this.put('/wallet/:id/key', function(req, res, next, send) { - self.walletdb.addKey(req.options.id, req.options.keys, function(err) { + this.put('/wallet/:id/:account?/key', function(req, res, next, send) { + var id = req.options.id; + var account = req.options.account; + var keys = req.options.keys; + self.walletdb.addKey(id, account, keys, function(err) { if (err) return next(err); @@ -421,8 +486,11 @@ HTTPServer.prototype._init = function _init() { }); // Remove key - this.del('/wallet/:id/key', function(req, res, next, send) { - self.walletdb.removeKey(req.options.id, req.options.keys, function(err) { + this.del('/wallet/:id/:account?/key', function(req, res, next, send) { + var id = req.options.id; + var account = req.options.account; + var keys = req.options.keys; + self.walletdb.removeKey(id, account, keys, function(err) { if (err) return next(err); @@ -431,8 +499,10 @@ HTTPServer.prototype._init = function _init() { }); // Wallet Balance - this.get('/wallet/:id/balance', function(req, res, next, send) { - self.walletdb.getBalance(req.options.id, function(err, balance) { + this.get('/wallet/:id/:account?/balance', function(req, res, next, send) { + var id = req.options.id; + var account = req.options.account; + self.walletdb.getBalance(id, account, function(err, balance) { if (err) return next(err); @@ -448,8 +518,10 @@ HTTPServer.prototype._init = function _init() { }); // Wallet UTXOs - this.get('/wallet/:id/coin', function(req, res, next, send) { - self.walletdb.getCoins(req.options.id, function(err, coins) { + this.get('/wallet/:id/:account?/coin', function(req, res, next, send) { + var id = req.options.id; + var account = req.options.account; + self.walletdb.getCoins(id, account, function(err, coins) { if (err) return next(err); @@ -462,10 +534,10 @@ HTTPServer.prototype._init = function _init() { }); }); - // Wallet TX - this.get('/wallet/:id/coin/:hash/:index', function(req, res, next, send) { - var hash = req.options.hash; - var index = req.options.index; + // Wallet Coin + this.get('/wallet/:id/:account?/coin/:hash/:index', function(req, res, next, send) { + var id = req.options.id; + var account = req.options.account; self.walletdb.getCoin(hash, index, function(err, coin) { if (err) return next(err); @@ -478,8 +550,10 @@ HTTPServer.prototype._init = function _init() { }); // Wallet TXs - this.get('/wallet/:id/tx/history', function(req, res, next, send) { - self.walletdb.getHistory(req.options.id, function(err, txs) { + this.get('/wallet/:id/:account?/tx/history', function(req, res, next, send) { + var id = req.options.id; + var account = req.options.account; + self.walletdb.getHistory(id, account, function(err, txs) { if (err) return next(err); @@ -500,54 +574,60 @@ HTTPServer.prototype._init = function _init() { }); // Wallet Pending TXs - this.get('/wallet/:id/tx/unconfirmed', function(req, res, next, send) { - self.walletdb.getUnconfirmed(req.options.id, function(err, txs) { - if (err) - return next(err); - - if (!txs.length) - return send(404); - - utils.forEach(txs, function(tx, next) { - self.walletdb.fillHistory(tx, next); - }, function(err) { - if (err) - return next(err); - - send(200, txs.map(function(tx) { - return tx.toJSON(); - })); - }); - }); - }); - - // Wallet TXs within time range - this.get('/wallet/:id/tx/range', function(req, res, next, send) { - self.walletdb.getRange(req.options.id, req.options, function(err, txs) { - if (err) - return next(err); - - if (!txs.length) - return send(404); - - utils.forEach(txs, function(tx, next) { - self.walletdb.fillHistory(tx, next); - }, function(err) { - if (err) - return next(err); - - send(200, txs.map(function(tx) { - return tx.toJSON(); - })); - }); - }); - }); - - // Wallet TXs within time range - this.get('/wallet/:id/tx/last', function(req, res, next, send) { + this.get('/wallet/:id/:account?/tx/unconfirmed', function(req, res, next, send) { var id = req.options.id; + var account = req.options.account; + self.walletdb.getUnconfirmed(id, account, function(err, txs) { + if (err) + return next(err); + + if (!txs.length) + return send(404); + + utils.forEach(txs, function(tx, next) { + self.walletdb.fillHistory(tx, next); + }, function(err) { + if (err) + return next(err); + + send(200, txs.map(function(tx) { + return tx.toJSON(); + })); + }); + }); + }); + + // Wallet TXs within time range + this.get('/wallet/:id/:account?/tx/range', function(req, res, next, send) { + var id = req.options.id; + var account = req.options.account; + var options = req.options; + self.walletdb.getRange(id, account, options, function(err, txs) { + if (err) + return next(err); + + if (!txs.length) + return send(404); + + utils.forEach(txs, function(tx, next) { + self.walletdb.fillHistory(tx, next); + }, function(err) { + if (err) + return next(err); + + send(200, txs.map(function(tx) { + return tx.toJSON(); + })); + }); + }); + }); + + // Wallet TXs within time range + this.get('/wallet/:id/:account?/tx/last', function(req, res, next, send) { + var id = req.options.id; + var account = req.options.account; var limit = req.options.limit; - self.walletdb.getRange(id, limit, function(err, txs) { + self.walletdb.getRange(id, account, limit, function(err, txs) { if (err) return next(err); @@ -568,7 +648,7 @@ HTTPServer.prototype._init = function _init() { }); // Wallet TX - this.get('/wallet/:id/tx/:hash', function(req, res, next, send) { + this.get('/wallet/:id/:account?/tx/:hash', function(req, res, next, send) { self.walletdb.getTX(req.options.hash, function(err, tx) { if (err) return next(err); @@ -584,40 +664,6 @@ HTTPServer.prototype._init = function _init() { }); }); - // Broadcast TX - this.post('/broadcast', function(req, res, next, send) { - self.pool.sendTX(req.options.tx, function(err) { - if (err) - return next(err); - - send(200, { - success: true - }); - }); - }); - - // Mempool snapshot - this.get('/mempool', function(req, res, next, send) { - self.node.mempool.getHistory(function(err, txs) { - if (err) - return next(err); - - if (!txs.length) - return send(404); - - utils.forEach(txs, function(tx, next) { - self.node.fillHistory(tx, next); - }, function(err) { - if (err) - return next(err); - - send(200, txs.map(function(tx) { - return tx.toJSON(); - })); - }); - }); - }); - this.server.on('error', function(err) { self.emit('error', err); }); diff --git a/lib/bcoin/wallet.js b/lib/bcoin/wallet.js index 7bbe073a..e6e4162b 100644 --- a/lib/bcoin/wallet.js +++ b/lib/bcoin/wallet.js @@ -1397,7 +1397,8 @@ Wallet.prototype.toJSON = function toJSON() { id: this.id, initialized: this.initialized, accountDepth: this.accountDepth, - master: this.master.toJSON() + master: this.master.toJSON(), + account: this.account ? this.account.toJSON() : null }; }; @@ -2154,6 +2155,12 @@ Account.prototype.toJSON = function toJSON() { accountIndex: this.accountIndex, receiveDepth: this.receiveDepth, changeDepth: this.changeDepth, + receiveAddress: this.receiveAddress + ? this.receiveAddress.getAddress() + : null, + changeAddress: this.changeAddress + ? this.changeAddress.getAddress() + : null, accountKey: this.accountKey.xpubkey, keys: this.keys.map(function(key) { return key.xpubkey; diff --git a/lib/bcoin/walletdb.js b/lib/bcoin/walletdb.js index 7ade880d..5e64811b 100644 --- a/lib/bcoin/walletdb.js +++ b/lib/bcoin/walletdb.js @@ -928,6 +928,7 @@ WalletDB.prototype.zap = function zap(id, account, age, callback) { * Parse arguments and return an id * consisting of `walletid/accountname`. * @private + * @param {WalletID} id * @param {String|Number} account * @param {Function} errback * @param {Function} callback - Returns [String, Function]. @@ -1088,6 +1089,18 @@ WalletDB.prototype.getInfo = function getInfo(id, callback) { }); }; +WalletDB.prototype.makeAccount = function makeAccount(id, account, options, callback) { + this.fetchWallet(id, callback, function(wallet, callback) { + wallet.hasAccount(account, function(err, exists) { + if (err) + return callback(err); + if (exists) + return wallet.getAccount(account, callback); + return wallet.createAccount(options, callback); + }); + }); +}; + WalletDB.prototype.getRedeem = function getRedeem(id, hash, callback) { this.fetchWallet(id, callback, function(wallet, callback) { wallet.getRedeem(hash, callback);