diff --git a/js/controllers/send.js b/js/controllers/send.js index 6698975ab..6b89a2392 100644 --- a/js/controllers/send.js +++ b/js/controllers/send.js @@ -121,7 +121,15 @@ angular.module('copayApp.controllers').controller('SendController', var w = $rootScope.wallet; - function done(ntxid, merchantData) { + function done(err, ntxid, merchantData) { + if (err) { + var message = 'The transaction' + (w.isShared() ? ' proposal' : '') + ' could not be created'; + notification.error('Error', message); + $scope.loading = false; + $scope.loadTxs(); + return; + } + // If user is granted the privilege of choosing // their own amount, add it to the tx. if (merchantData && +merchantData.total === 0) { diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index f64b1d9ad..60e2a6ca5 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -879,7 +879,6 @@ Wallet.prototype.sendAllTxProposals = function(recipients) { */ Wallet.prototype.sendTxProposal = function(ntxid, recipients) { preconditions.checkArgument(ntxid); - log.debug('### SENDING txProposal ' + ntxid + ' TO:', recipients || 'All', this.txProposals); this.send(recipients, { type: 'txProposal', @@ -2030,24 +2029,6 @@ Wallet.prototype.removeTxWithSpentInputs = function(cb) { Wallet.prototype.createTx = function(toAddress, amountSatStr, comment, opts, cb) { var self = this; - if (_.isFunction(amountSatStr)) { - var cb = amountSatStr; - var merchant = toAddress; - return this.createPaymentTx({ - uri: merchant - }, cb); - } - - if (_.isFunction(comment)) { - var cb = comment; - var merchant = toAddress; - var comment = amountSatStr; - return this.createPaymentTx({ - uri: merchant, - memo: comment - }, cb); - } - if (_.isFunction(opts)) { cb = opts; opts = {}; @@ -2059,14 +2040,18 @@ Wallet.prototype.createTx = function(toAddress, amountSatStr, comment, opts, cb) } this.getUnspent(function(err, safeUnspent) { + if (err) return cb(new Error('Could not get list of UTXOs')); + var ntxid = self.createTxSync(toAddress, amountSatStr, comment, safeUnspent, opts); - if (ntxid) { - self.sendIndexes(); - self.sendTxProposal(ntxid); - self.store(); - self.emit('txProposalsUpdated'); + if (!ntxid) { + return cb(new Error('Error creating TX')); } - return cb(ntxid); + + self.sendIndexes(); + self.sendTxProposal(ntxid); + self.store(); + self.emit('txProposalsUpdated'); + return cb(null, ntxid); }); }; diff --git a/test/mocks/FakeWallet.js b/test/mocks/FakeWallet.js index 77b2d04a5..ee2621a1e 100644 --- a/test/mocks/FakeWallet.js +++ b/test/mocks/FakeWallet.js @@ -46,7 +46,7 @@ var FakeWallet = function() { FakeWallet.prototype.createTx = function(toAddress, amountSatStr, comment, opts, cb) { var callback = cb || opts; - callback({}); + callback(null, {}); } FakeWallet.prototype.sendTx = function(ntxid, cb) { diff --git a/test/test.PayPro.js b/test/test.PayPro.js index 0528864f3..fbbeaf7ef 100644 --- a/test/test.PayPro.js +++ b/test/test.PayPro.js @@ -739,7 +739,7 @@ describe('PayPro (in Wallet) model', function() { uri = address.split(/\s+/)[1]; } - w.createTx(uri, commentText, function(ntxid, merchantData) { + w.createPaymentTx({ uri: uri, memo: commentText }, function(ntxid, merchantData) { if (w.isShared()) { should.exist(ntxid); should.exist(merchantData); @@ -760,7 +760,7 @@ describe('PayPro (in Wallet) model', function() { should.exist(w); var address = 'bitcoin:2NBzZdFBoQymDgfzH2Pmnthser1E71MmU47?amount=0.00003&r=' + server.uri + '/request'; var commentText = 'Hello, server. I\'d like to make a payment.'; - w.createTx(address, commentText, function(ntxid, merchantData) { + w.createPaymentTx({ uri: address, memo: commentText }, function(ntxid, merchantData) { if (w.isShared()) { should.exist(ntxid); should.exist(merchantData); @@ -780,7 +780,7 @@ describe('PayPro (in Wallet) model', function() { should.exist(w); var address = 'bitcoin:2NBzZdFBoQymDgfzH2Pmnthser1E71MmU47?amount=0.00003&r=' + server.uri + '/request'; var commentText = 'Hello, server. I\'d like to make a payment.'; - w.createTx(address, commentText, function(ntxid, merchantData) { + w.createPaymentTx({ uri: address, memo: commentText }, function(ntxid, merchantData) { should.exist(ntxid); should.exist(merchantData); @@ -816,7 +816,7 @@ describe('PayPro (in Wallet) model', function() { should.exist(w); var address = 'bitcoin:2NBzZdFBoQymDgfzH2Pmnthser1E71MmU47?amount=0.00003&r=' + server.uri + '/request'; var commentText = 'Hello, server. I\'d like to make a payment.'; - w.createTx(address, commentText, function(ntxid, merchantData) { + w.createPaymentTx({ uri: address, memo: commentText }, function(ntxid, merchantData) { should.exist(ntxid); should.exist(merchantData); @@ -843,7 +843,7 @@ describe('PayPro (in Wallet) model', function() { should.exist(w); var address = 'bitcoin:2NBzZdFBoQymDgfzH2Pmnthser1E71MmU47?amount=0.00003&r=' + server.uri + '/request'; var commentText = 'Hello, server. I\'d like to make a payment.'; - w.createTx(address, commentText, function(ntxid, merchantData) { + w.createPaymentTx({ uri: address, memo: commentText }, function(ntxid, merchantData) { should.exist(ntxid); should.exist(merchantData); @@ -869,7 +869,7 @@ describe('PayPro (in Wallet) model', function() { should.exist(w); var address = 'bitcoin:2NBzZdFBoQymDgfzH2Pmnthser1E71MmU47?amount=0.00003&r=' + server.uri + '/request'; var commentText = 'Hello, server. I\'d like to make a payment.'; - w.createTx(address, commentText, function(ntxid, merchantData) { + w.createPaymentTx({ uri: address, memo: commentText }, function(ntxid, merchantData) { should.exist(ntxid); should.exist(merchantData); diff --git a/test/test.Wallet.js b/test/test.Wallet.js index 95c461266..7a8dac56f 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -694,7 +694,7 @@ describe('Wallet model', function() { var w = cachedCreateW2(); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx(toAddress, amountSatStr, null, function(ntxid) { + w.createTx(toAddress, amountSatStr, null, function(err, ntxid) { ntxid.length.should.equal(64); done(); }); @@ -708,7 +708,7 @@ describe('Wallet model', function() { var w = createW2([k2]); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx(toAddress, amountSatStr, null, function(ntxid) { + w.createTx(toAddress, amountSatStr, null, function(err, ntxid) { w.on('txProposalsUpdated', function() { w.getTxProposals()[0].signedByUs.should.equal(true); w.getTxProposals()[0].rejectedByUs.should.equal(false); @@ -724,7 +724,7 @@ describe('Wallet model', function() { var w = cachedCreateW2(); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx(toAddress, amountSatStr, null, function(ntxid) { + w.createTx(toAddress, amountSatStr, null, function(err, ntxid) { (function() { w.reject(ntxid); }).should.throw('reject a signed'); @@ -736,7 +736,7 @@ describe('Wallet model', function() { var oldK = w.privateKey; var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx(toAddress, amountSatStr, null, function(ntxid) { + w.createTx(toAddress, amountSatStr, null, function(err, ntxid) { var s = sinon.stub(w, 'getMyCopayerId').returns('213'); Object.keys(w.txProposals.get(ntxid).rejectedBy).length.should.equal(0); w.reject(ntxid); @@ -750,7 +750,7 @@ describe('Wallet model', function() { var w = createW2(null, 1); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx(toAddress, amountSatStr, null, function(ntxid) { + w.createTx(toAddress, amountSatStr, null, function(err, ntxid) { w.sendTx(ntxid, function(txid) { txid.length.should.equal(64); done(); @@ -761,7 +761,7 @@ describe('Wallet model', function() { var w = createW2(null, 1); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx(toAddress, amountSatStr, null, function(ntxid) { + w.createTx(toAddress, amountSatStr, null, function(err, ntxid) { var txp = w.txProposals.get(ntxid); // Assign fake builder txp.builder = new Builder(); @@ -776,7 +776,7 @@ describe('Wallet model', function() { var w = createW2(null, 1); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx(toAddress, amountSatStr, null, function(ntxid) { + w.createTx(toAddress, amountSatStr, null, function(err, ntxid) { sinon.stub(w.blockchain, 'broadcast').yields({statusCode: 303}); var spyCheckSentTx = sinon.spy(w, '_checkSentTx'); w.sendTx(ntxid, function () {}); @@ -788,7 +788,7 @@ describe('Wallet model', function() { var w = cachedCreateW2(); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx(toAddress, amountSatStr, null, function(ntxid) { + w.createTx(toAddress, amountSatStr, null, function(err, ntxid) { w.sendTxProposal.bind(w).should.throw('Illegal Argument.'); (function() { w.sendTxProposal(ntxid); @@ -801,7 +801,7 @@ describe('Wallet model', function() { var w = cachedCreateW2(); var utxo = createUTXO(w); w.blockchain.fixUnspent(utxo); - w.createTx(toAddress, amountSatStr, null, function(ntxid) { + w.createTx(toAddress, amountSatStr, null, function(err, ntxid) { w.sendAllTxProposals.bind(w).should.not.throw(); (function() { w.sendAllTxProposals(); @@ -810,6 +810,19 @@ describe('Wallet model', function() { }); }); + describe('#createTx', function () { + it('should fail if insight server is down', function (done) { + var w = cachedCreateW2(); + var utxo = createUTXO(w); + w.blockchain.fixUnspent(utxo); + sinon.stub(w, 'getUnspent').yields('error', null); + w.createTx(toAddress, amountSatStr, null, function(err, ntxid) { + chai.expect(err.message).to.equal('Could not get list of UTXOs'); + done(); + }); + }); + }); + describe('#createTxSync', function() { it('should fail if amount below min value', function() { var w = cachedCreateW2(); @@ -833,7 +846,7 @@ describe('Wallet model', function() { var utxo = createUTXO(w); chai.expect(w.getTxProposals().length).to.equal(0); w.blockchain.fixUnspent(utxo); - w.createTx(toAddress, amountSatStr, null, function(ntxid) { + w.createTx(toAddress, amountSatStr, null, function(err, ntxid) { w.sendTxProposal(ntxid); chai.expect(w.getTxProposals().length).to.equal(1); @@ -858,7 +871,7 @@ describe('Wallet model', function() { utxo[1].vout = 1; chai.expect(w.getTxProposals().length).to.equal(0); w.blockchain.fixUnspent(utxo); - w.createTx(toAddress, '100000', null, function(ntxid) { + w.createTx(toAddress, '100000', null, function(err, ntxid) { w.sendTxProposal(ntxid); chai.expect(w.getTxProposals().length).to.equal(1); @@ -880,7 +893,7 @@ describe('Wallet model', function() { var utxo = createUTXO(w); chai.expect(w.getTxProposals().length).to.equal(0); w.blockchain.fixUnspent(utxo); - w.createTx(toAddress, amountSatStr, null, function(ntxid) { + w.createTx(toAddress, amountSatStr, null, function(err, ntxid) { w.sendTxProposal(ntxid); chai.expect(w.getTxProposals().length).to.equal(1); diff --git a/test/unit/controllers/controllersSpec.js b/test/unit/controllers/controllersSpec.js index ef6a820e6..1c464b236 100644 --- a/test/unit/controllers/controllersSpec.js +++ b/test/unit/controllers/controllersSpec.js @@ -285,6 +285,18 @@ describe("Unit: Controllers", function() { sinon.assert.callCount(scope.loadTxs, 1); }); + it('should not send txp when there is an error at creation', function() { + sendForm.address.$setViewValue('mkfTyEk7tfgV611Z4ESwDDSZwhsZdbMpVy'); + sendForm.amount.$setViewValue(1000); + scope.wallet.totalCopayers = scope.wallet.requiredCopayers = 1; + sinon.stub(scope.wallet, 'createTx').yields('error'); + var spySendTx = sinon.spy(scope.wallet, 'sendTx'); + scope.loadTxs = sinon.spy(); + + scope.submitForm(sendForm); + sinon.assert.callCount(spySendTx, 0); + sinon.assert.callCount(scope.loadTxs, 1); + }); }); describe("Unit: Version Controller", function() {