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