diff --git a/index.html b/index.html index b30118510..5ad74b5a6 100644 --- a/index.html +++ b/index.html @@ -178,7 +178,7 @@ - diff --git a/js/app.js b/js/app.js index c955f458e..1b6ef9813 100644 --- a/js/app.js +++ b/js/app.js @@ -13,8 +13,7 @@ angular.module('copay',[ 'copay.signin', 'copay.socket', 'copay.controllerUtils', - 'copay.setup', - 'copay.peer' + 'copay.setup' ]); angular.module('copay.header', []); @@ -26,6 +25,5 @@ angular.module('copay.walletFactory', []); angular.module('copay.controllerUtils', []); angular.module('copay.signin', []); angular.module('copay.setup', []); -angular.module('copay.peer', []); angular.module('copay.socket', []); diff --git a/js/controllers/peer.js b/js/controllers/peer.js deleted file mode 100644 index 5ae619020..000000000 --- a/js/controllers/peer.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -angular.module('copay.peer').controller('PeerController', - function($scope, $rootScope, $location, $routeParams) { - }); - diff --git a/js/controllers/send.js b/js/controllers/send.js index 276468464..46000b937 100644 --- a/js/controllers/send.js +++ b/js/controllers/send.js @@ -23,16 +23,15 @@ angular.module('copay.send').controller('SendController', var w = $rootScope.wallet; w.createTx( address, amount,function() { + + // reset fields + $scope.address = null; + $scope.amount = null; + form.address.$pristine = true; + form.amount.$pristine = true; + $rootScope.flashMessage = { message: 'The transaction proposal has been created', type: 'success'}; $rootScope.$digest(); }); - // reset fields - $scope.address = null; - $scope.amount = null; - form.address.$pristine = true; - form.amount.$pristine = true; - - // TODO: check if createTx has an error. - $rootScope.flashMessage = { message: 'Your transaction proposal has been sent successfully', type: 'success'}; }; }); diff --git a/js/controllers/transactions.js b/js/controllers/transactions.js index a2e8a3697..82b1f2a1a 100644 --- a/js/controllers/transactions.js +++ b/js/controllers/transactions.js @@ -5,8 +5,9 @@ angular.module('copay.transactions').controller('TransactionsController', function($scope, $rootScope, $location) { $scope.title = 'Transactions'; var _updateTxs = function() { -console.log('[transactions.js.10:_updateTxs:]'); //TODO var w =$rootScope.wallet; + if (!w) return; + var inT = w.getTxProposals(); var txs = []; @@ -25,11 +26,10 @@ console.log('[transactions.js.10:_updateTxs:]'); //TODO }); // extra fields i.outs = outs; - i.fee = i.feeSat/bitcore.util.COIN; + i.fee = i.builder.feeSat/bitcore.util.COIN; i.missingSignatures = tx.countInputMissingSignatures(0); txs.push(i); }); -console.log('[transactions.js.35:txs:]',txs); //TODO $scope.txs = txs; w.removeListener('txProposalsUpdated',_updateTxs) w.once('txProposalsUpdated',_updateTxs); @@ -38,7 +38,7 @@ console.log('[transactions.js.35:txs:]',txs); //TODO $scope.send = function (ntxid) { var w = $rootScope.wallet; w.sendTx(ntxid, function(txid) { -console.log('[transactions.js.68:txid:] SENTTX CALLBACK',txid); //TODO + console.log('[transactions.js.68:txid:] SENTTX CALLBACK',txid); //TODO $rootScope.flashMessage = txid ? {type:'success', message: 'Transactions SENT! txid:' + txid} : {type:'error', message: 'There was an error sending the Transaction'} @@ -51,17 +51,20 @@ console.log('[transactions.js.68:txid:] SENTTX CALLBACK',txid); //TODO $scope.sign = function (ntxid) { var w = $rootScope.wallet; var ret = w.sign(ntxid); - _updateTxs(); + if (!ret) { + $rootScope.flashMessage = {type:'error', message: 'There was an error signing the Transaction'}; + _updateTxs(); + $rootScope.$digest(); + return; + } var p = w.getTxProposal(ntxid); if (p.txp.builder.isFullySigned()) { $scope.send(ntxid); + _updateTxs(); + $rootScope.$digest(); } else { - $rootScope.flashMessage = ret - ? {type:'success', message: 'Transactions signed'} - : {type:'error', message: 'There was an error signing the Transaction'} - ; _updateTxs(); $rootScope.$digest(); } @@ -79,5 +82,13 @@ console.log('[transactions.js.68:txid:] SENTTX CALLBACK',txid); //TODO } }; + $scope.reject = function (ntxid) { + var w = $rootScope.wallet; + w.reject(ntxid); + $rootScope.flashMessage = {type:'warning', message: 'Transaction rejected by you'}; + _updateTxs(); + $rootScope.$digest(); + }; + _updateTxs(); }); diff --git a/js/models/core/PrivateKey.js b/js/models/core/PrivateKey.js index 2002a14b6..0e2d87631 100644 --- a/js/models/core/PrivateKey.js +++ b/js/models/core/PrivateKey.js @@ -71,7 +71,6 @@ PrivateKey.prototype.get = function(index,isChange) { PrivateKey.prototype.getAll = function(addressIndex, changeAddressIndex) { var ret = []; - for(var i=0;imaxRejectCount) + continue; + for (var j in u){ ret.push(u[j].txid); } diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 823c91098..b90b71040 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -269,56 +269,46 @@ Wallet.prototype.sendPublicKeyRing = function(recipients) { Wallet.prototype.generateAddress = function(isChange) { var addr = this.publicKeyRing.generateAddress(isChange); -console.log('[Wallet.js.281:addr:]',addr, this.publicKeyRing.toObj(), this.getAddresses()); //TODO this.sendPublicKeyRing(); this.store(true); return addr; }; -// TODO : sort by time... / signed. + Wallet.prototype.getTxProposals = function() { var ret = []; for(var k in this.txProposals.txps) { - var txp = this.txProposals.txps[k]; - var i = JSON.parse(JSON.stringify(txp)); - i.builder = txp.builder; - i.ntxid = k; - i.signedByUs = txp.signedBy[this.getMyPeerId()]?true:false; - - i.peerActions = {}; - for(var p in txp.seenBy){ - i.peerActions[p]={seen: txp.seenBy[p]}; - } - for(var p in txp.signedBy){ - i.peerActions[p]= i.peerActions[p] || {}; - i.peerActions[p].sign = txp.signedBy[p]; - } - var c = txp.creator; - i.peerActions[c] = i.peerActions[c] || {}; - i.peerActions[c].create = txp.createdTs; - + var i = this.txProposals.getTxProposal(k); + i.signedByUs = i.signedBy[this.getMyPeerId()]?true:false; + i.rejectedByUs = i.rejectedBy[this.getMyPeerId()]?true:false; + if (this.totalCopayers-i.rejectCount < this.requiredCopayers) + i.finallyRejected=true; ret.push(i); } return ret; }; -Wallet.prototype.getTxProposal = function(ntxid) { + +Wallet.prototype.reject = function(ntxid) { + var myId=this.getMyPeerId(); var txp = this.txProposals.txps[ntxid]; - var i = {txp:txp}; - i.ntxid = ntxid; - i.signedByUs = txp.signedBy[this.getMyPeerId()]?true:false; - return i; + if (!txp || txp.rejectedBy[myId] || txp.signedBy[myId]) return; + + txp.rejectedBy[myId] = Date.now(); + this.sendTxProposals(); + this.store(true); }; + Wallet.prototype.sign = function(ntxid) { var self = this; + var myId=this.getMyPeerId(); var txp = self.txProposals.txps[ntxid]; - if (!txp) return; + if (!txp || txp.rejectedBy[myId] || txp.signedBy[myId]) return; var pkr = self.publicKeyRing; var keys = self.privateKey.getAll(pkr.addressIndex, pkr.changeAddressIndex); -console.log('[Wallet.js.329:keys:]',keys); //TODO var b = txp.builder; var before = b.signaturesAdded; @@ -326,7 +316,7 @@ console.log('[Wallet.js.329:keys:]',keys); //TODO var ret = false; if (b.signaturesAdded > before) { - txp.signedBy[self.getMyPeerId()] = Date.now(); + txp.signedBy[myId] = Date.now(); this.sendTxProposals(); this.store(true); ret = true; @@ -373,7 +363,6 @@ Wallet.prototype.addSeenToTxProposals = function() { return ret; }; - Wallet.prototype.getAddresses = function(onlyMain) { return this.publicKeyRing.getAddresses(onlyMain); }; @@ -440,7 +429,8 @@ Wallet.prototype.getSafeUnspent = function(cb) { this.blockchain.getUnspent(this.getAddressesStr(), function(unspentList) { var ret=[]; - var uu = self.txProposals.getUsedUnspent(); + var maxRejectCount = self.totalCopayers - self.requiredCopayers; + var uu = self.txProposals.getUsedUnspent(maxRejectCount); for(var i in unspentList){ if (uu.indexOf(unspentList[i].txid) === -1) @@ -465,11 +455,11 @@ Wallet.prototype.createTx = function(toAddress, amountSatStr, opts, cb) { } self.getSafeUnspent(function(unspentList) { - // TODO check enough funds, etc. - self.createTxSync(toAddress, amountSatStr, unspentList, opts); - self.sendPublicKeyRing(); // Change Address - self.sendTxProposals(); - self.store(); + if (self.createTxSync(toAddress, amountSatStr, unspentList, opts)) { + self.sendPublicKeyRing(); // Change Address + self.sendTxProposals(); + self.store(); + } return cb(); }); }; @@ -497,25 +487,27 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, utxos, opts) { var signRet; if (priv) { -console.log('[Wallet.js.486] aLL Priv', priv.getAll(pkr.addressIndex, pkr.changeAddressIndex)); //TODO b.sign( priv.getAll(pkr.addressIndex, pkr.changeAddressIndex) ); } -console.log('[Wallet.js.494]', b, b.build().serialize().toString('hex')); //TODO - var me = {}; var myId = this.getMyPeerId(); var now = Date.now(); - if (priv) me[myId] = now; + var me = {}; + if (priv && b.signaturesAdded) me[myId] = now; + + var meSeen = {}; + if (priv) meSeen[myId] = now; var data = { - signedBy: (priv && b.signaturesAdded ? me : {}), - seenBy: (priv ? me : {}), + signedBy: me, + seenBy: meSeen, creator: myId, createdTs: now, builder: b, }; this.txProposals.add(data); + return true; }; Wallet.prototype.connectTo = function(peerId) { diff --git a/js/models/network/WebRTC.js b/js/models/network/WebRTC.js index 382f9e536..1d7dc10a8 100644 --- a/js/models/network/WebRTC.js +++ b/js/models/network/WebRTC.js @@ -261,7 +261,6 @@ console.log('[WebRTC.js.255] WARN: NO CONNECTION TO:', peerId); //TODO Network.prototype.send = function(peerIds, data, cb) { var self=this; -console.log('[WebRTC.js.242] SENDING ', data.type); //TODO if (!peerIds) { peerIds = this.connectedPeers; data.isBroadcast = 1; diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index a803c7436..bce88761d 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -61,7 +61,7 @@ angular.module('copay.controllerUtils').factory('controllerUtils', function ($ro console.log('### SUBSCRIBE TO', addrs[i]); Socket.emit('subscribe', addrs[i]); } - +console.log('[controllerUtils.js.64]'); //TODO addrs.forEach(function(addr) { Socket.on(addr, function(txid) { console.log('Received!', txid); diff --git a/test/test.PrivateKey.js b/test/test.PrivateKey.js index f3cec474f..9eafd5794 100644 --- a/test/test.PrivateKey.js +++ b/test/test.PrivateKey.js @@ -70,7 +70,7 @@ describe('PrivateKey model', function() { it('should calculate .id', function () { var w1 = new PrivateKey(config); should.exist(w1.getId()); - w1.getId().length.should.equal(40); + w1.getId().length.should.equal(32); }); it('fromObj toObj roundtrip', function () { var w1 = new PrivateKey(config); diff --git a/test/test.TxProposals.js b/test/test.TxProposals.js index f49c92319..647b634d4 100644 --- a/test/test.TxProposals.js +++ b/test/test.TxProposals.js @@ -59,9 +59,61 @@ var createPKR = function (bip32s) { return w; }; +var vopts = { + verifyP2SH: true, + dontVerifyStrictEnc: true +}; + describe('TxProposals model', function() { + + it('verify TXs', function (done) { + + var priv = new PrivateKey(config); + var priv2 = new PrivateKey(config); + var priv3 = new PrivateKey(config); + var ts = Date.now(); + var isChange=0; + var index=0; + var pkr = createPKR([priv, priv2, priv3]); + var opts = {remainderOut: { address: pkr.generateAddress(true).toString() }}; + + var w = new TxProposals({ + networkName: config.networkName, + }); + unspentTest[0].address = pkr.getAddress(index, isChange).toString(); + unspentTest[0].scriptPubKey = pkr.getScriptPubKeyHex(index, isChange); + w.add(createTx( + '15q6HKjWHAksHcH91JW23BJEuzZgFwydBt', + '123456789', + unspentTest, + opts, + priv, + pkr + )); + var k = Object.keys(w.txps)[0]; + var b = w.txps[k].builder; + var tx = b.build(); + tx.isComplete().should.equal(false); + b.sign( priv2.getAll(pkr.addressIndex, pkr.changeAddressIndex) ); + b.sign( priv3.getAll(pkr.addressIndex, pkr.changeAddressIndex) ); + tx = b.build(); + tx.isComplete().should.equal(true); + + var s = new Script(new Buffer(unspentTest[0].scriptPubKey,'hex')); + + tx.verifyInput(0,s, { + verifyP2SH: true, + dontVerifyStrictEnc: true + }, function(err, results){ + should.not.exist(err); + results.should.equal(true); + done(); + }); + }); + + it('should create an instance', function () { var w = new TxProposals({ networkName: config.networkName @@ -496,5 +548,6 @@ var _dumpChunks = function (scriptSig, label) { w2.merge(w); Object.keys(w2.txps).length.should.equal(1); }); + + }); -