diff --git a/app.js b/app.js index 99eba80..eb7aab5 100644 --- a/app.js +++ b/app.js @@ -204,6 +204,17 @@ router.post('/v1/txproposals/:id/signatures/', function(req, res) { }); }); +// TODO Check HTTP verb and URL name +router.post('/v1/txproposals/:id/broadcast/', function(req, res) { + getServerWithAuth(req, res, function(server) { + req.body.txProposalId = req.params['id']; + server.broadcastTx(req.body, function(err, txp) { + if (err) return returnError(err, res, req); + res.end(); + }); + }); +}); + router.post('/v1/txproposals/:id/rejections', function(req, res) { getServerWithAuth(req, res, function(server) { req.body.txProposalId = req.params['id']; diff --git a/bit-wallet/bit b/bit-wallet/bit index cffe423..b5b3026 100755 --- a/bit-wallet/bit +++ b/bit-wallet/bit @@ -13,6 +13,7 @@ program .command('send
', 'send bitcoins') .command('sign ', 'sign a transaction proposal') .command('reject [reason]', 'reject a transaction proposal') + .command('broadcast ', 'broadcast a transaction proposal to the Bitcoin network') .command('rm ', 'remove a transaction proposal') .parse(process.argv); diff --git a/bit-wallet/bit-broadcast b/bit-wallet/bit-broadcast new file mode 100644 index 0000000..24597fa --- /dev/null +++ b/bit-wallet/bit-broadcast @@ -0,0 +1,30 @@ +#!/usr/bin/env node + +var _ = require('lodash'); +var program = require('commander'); +var Client = require('../lib/client'); +var utils = require('./cli-utils'); + +program +.version('0.0.1') +.option('-c,--config [file]', 'Wallet config filename') +.option('-v,--verbose', 'be verbose') +.usage('[options] ') +.parse(process.argv); + +var args = program.args; +if (!args[0]) + program.help(); + + var txpid = args[0]; + var client = utils.getClient(program); + + client.getTxProposals({}, function(err, txps) { + utils.die(err); + + var txp = utils.findOneTxProposal(txps, txpid); + client.broadcastTxProposal(txp, function(err, txid) { + utils.die(err); + console.log('TX Broadcasted: ',txid); + }); + }); diff --git a/lib/client/API.js b/lib/client/API.js index a51af67..f582925 100644 --- a/lib/client/API.js +++ b/lib/client/API.js @@ -360,6 +360,16 @@ API.prototype.rejectTxProposal = function(txp, reason, cb) { this._doPostRequest(url, args, data, cb); }; +API.prototype.broadcastTxProposal = function(txp, cb) { + var self = this; + var data = this._loadAndCheck(); + + var url = '/v1/txproposals/' + txp.id + '/broadcast/'; + this._doPostRequest(url, {}, data, cb); +}; + + + API.prototype.removeTxProposal = function(txp, cb) { var self = this; var data = this._loadAndCheck(); diff --git a/lib/server.js b/lib/server.js index 579129a..7923351 100644 --- a/lib/server.js +++ b/lib/server.js @@ -660,6 +660,51 @@ CopayServer.prototype.signTx = function(opts, cb) { }); }; + +/** + * Broadcast a transaction proposal. + * @param {Object} opts + * @param {string} opts.txProposalId - The identifier of the transaction. + */ +CopayServer.prototype.broadcastTx = function(opts, cb) { + var self = this; + + if (!Utils.checkRequired(opts, ['txProposalId'])) + return cb(new ClientError('Required argument missing')); + + self.getWallet({}, function(err, wallet) { + if (err) return cb(err); + + self.getTx({ + id: opts.txProposalId + }, function(err, txp) { + if (err) return cb(err); + + if (txp.status == 'broadcasted') + return cb(new ClientError('TXALREADYBROADCASTED', 'The transaction proposal is already broadcasted')); + + if (txp.status != 'accepted') + return cb(new ClientError('TXNOTACCEPTED', 'The transaction proposal is not accepted')); + + self._broadcastTx(txp, function(err, txid) { + if (err) return cb(err); + + txp.setBroadcasted(txid); + self.storage.storeTx(self.walletId, txp, function(err) { + if (err) return cb(err); + + self._notify('NewOutgoingTx', { + txProposalId: opts.txProposalId, + txid: txid + }); + + return cb(null, txp); + }); + }); + }); + }); +}; + /** * Reject a transaction proposal. * @param {Object} opts