diff --git a/2fa b/2fa new file mode 100644 index 000000000..fc4ff15d6 --- /dev/null +++ b/2fa @@ -0,0 +1,18 @@ + + +- 2-2 + 1 desktop + 1 mobile + + - each device creates its own key + - both devices are expected to be logged using the same profile (email / password) + - if using local storage -> all is OK. + - keys will be safe an will never leave the device + + - if using insight + both 'copayers' need to have a new and different password for accessing the wallet. + + + + + - diff --git a/TODO b/TODO new file mode 100644 index 000000000..53967d2d9 --- /dev/null +++ b/TODO @@ -0,0 +1,12 @@ + + - homeWallet address...e sta ok? +- receive controller .. owned +-- +// pkr.cache = opts.cache; + +(en send.js) +// $rootScope.pendingTxCount = res.pendingForUs; + +-- probar payment intent + +// TODO refrescar en 'add' diff --git a/commm b/commm new file mode 100644 index 000000000..24f026c7b --- /dev/null +++ b/commm @@ -0,0 +1 @@ +7b6bcfbbbb6bf82f8843305f563d2a2491f310fe diff --git a/js/controllers/create.js b/js/controllers/create.js index 65ccb27b9..49f6daa01 100644 --- a/js/controllers/create.js +++ b/js/controllers/create.js @@ -62,7 +62,8 @@ angular.module('copayApp.controllers').controller('CreateController', $scope.error = 'Could not create wallet: ' + err; } } - $rootScope.$digest() + + $rootScope.$digest(); }); }; }); diff --git a/js/controllers/createWallet.js b/js/controllers/createWallet.js deleted file mode 100644 index 5a7e034db..000000000 --- a/js/controllers/createWallet.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; -angular.module('copayApp.controllers').controller('CreateWalletController', function($scope, $rootScope) { - - $rootScope.title = 'Create Wallet'; -}); diff --git a/js/controllers/home.js b/js/controllers/home.js index 591419594..ae8113843 100644 --- a/js/controllers/home.js +++ b/js/controllers/home.js @@ -25,7 +25,7 @@ angular.module('copayApp.controllers').controller('HomeController', function($sc $scope.$on("$destroy", function(){ var iden = $rootScope.iden; if (iden) { - iden.removeListener('newWallets', $scope.done ); + iden.removeListener('newWallet', $scope.done ); iden.removeListener('noWallets', $scope.done ); } }); diff --git a/js/controllers/homeWallet.js b/js/controllers/homeWallet.js index 146fc2fae..788e937b8 100644 --- a/js/controllers/homeWallet.js +++ b/js/controllers/homeWallet.js @@ -1,13 +1,16 @@ 'use strict'; -angular.module('copayApp.controllers').controller('HomeWalletController', - function($scope, $rootScope) { +angular.module('copayApp.controllers').controller('HomeWalletController', function($scope, $rootScope) { + $scope.init = function() { + $rootScope.title = 'Home'; $scope.addr = _.last($rootScope.wallet.getReceiveAddresses()); // This is necesarry, since wallet can change in homeWallet, without running init() again. $rootScope.$watch('wallet', function() { - $scope.addr = _.last($rootScope.wallet.getReceiveAddresses()); + if ($rootScope.wallet && $rootScope.wallet.isComplete()) { + $scope.addr = _.last($rootScope.wallet.getReceiveAddresses()); + } }); - } -); + }; +}); diff --git a/js/controllers/import.js b/js/controllers/import.js index 6ee3bf798..c8481f078 100644 --- a/js/controllers/import.js +++ b/js/controllers/import.js @@ -81,6 +81,8 @@ angular.module('copayApp.controllers').controller('ImportController', if (err) { $scope.loading = false; $scope.error = 'Could not read wallet. Please check your password'; + $rootScope.$digest(); + return; } copay.Compatibility.deleteOldWallet(backupOldWallet); }); diff --git a/js/controllers/join.js b/js/controllers/join.js index ce0935530..1b7478712 100644 --- a/js/controllers/join.js +++ b/js/controllers/join.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.controllers').controller('JoinController', - function($scope, $rootScope, $timeout, isMobile, notification) { + function($scope, $rootScope, $timeout, isMobile, notification, identityService) { $rootScope.fromSetup = false; $scope.loading = false; $scope.isMobile = isMobile.any(); diff --git a/js/controllers/profile.js b/js/controllers/profile.js index b13a2565d..ee9bfc576 100644 --- a/js/controllers/profile.js +++ b/js/controllers/profile.js @@ -1,5 +1,5 @@ 'use strict'; -angular.module('copayApp.controllers').controller('ProfileController', function($scope, $rootScope, $location, $modal, $filter, backupService, identityService) { +angular.module('copayApp.controllers').controller('ProfileController', function($scope, $rootScope, $location, $modal, $filter, $timeout, backupService, identityService) { $scope.username = $rootScope.iden.getName(); $scope.isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0; @@ -26,11 +26,13 @@ angular.module('copayApp.controllers').controller('ProfileController', function( }); }; + $scope.init = function() { if ($rootScope.quotaPerItem) { $scope.perItem = $filter('noFractionNumber')($rootScope.quotaPerItem / 1000, 1); $scope.nrWallets = parseInt($rootScope.quotaItems) - 1; } + // no need to add event handlers here. Wallet deletion is handle by callback. }; $scope.setWallets = function() { @@ -46,8 +48,10 @@ angular.module('copayApp.controllers').controller('ProfileController', function( w.usage = $filter('noFractionNumber')(bits / max * 100, 0); } }); - $scope.wallets = wallets; + $timeout(function(){ + $scope.$digest(); + }) }; $scope.downloadWalletBackup = function(w) { diff --git a/js/controllers/sidebar.js b/js/controllers/sidebar.js index 5da6e83ab..a6f7533ae 100644 --- a/js/controllers/sidebar.js +++ b/js/controllers/sidebar.js @@ -63,7 +63,19 @@ angular.module('copayApp.controllers').controller('SidebarController', function( $scope.walletSelection = false; $scope.setWallets(); }); - iden.on('deleteWallet', function() { + iden.on('walletDeleted', function(wid) { + if (wid == $rootScope.wallet.id) { + copay.logger.debug('Deleted focused wallet:', wid); + + // new focus + var newWid = $rootScope.iden.getLastFocusedWalletId(); + if (newWid && $rootScope.iden.getWalletById(newWid)) { + identityService.setFocusedWallet(newWid); + } else { + copay.logger.debug('No wallets'); + identityService.noFocusedWallet(newWid); + } + } $scope.walletSelection = false; $scope.setWallets(); }); diff --git a/js/models/Identity.js b/js/models/Identity.js index d404fc9f3..338d7152e 100644 --- a/js/models/Identity.js +++ b/js/models/Identity.js @@ -151,6 +151,7 @@ Identity.prototype.readAndBindWallet = function(walletId, cb) { var self = this; self.retrieveWalletFromStorage(walletId, {}, function(error, wallet) { if (!error) { + self.wallets[wallet.getId()] = wallet; self.bindWallet(wallet); } return cb(error); @@ -386,6 +387,8 @@ Identity.prototype.importWalletFromObj = function(obj, opts, cb) { log.debug('Updating Indexes for wallet:' + w.getName()); w.updateIndexes(function(err) { log.debug('Adding wallet to profile:' + w.getName()); + self.wallets[w.getId()] = w; + self.updateFocusedTimestamp(w.getId()); self.bindWallet(w); self.storeWallet(w, cb); }); @@ -471,8 +474,9 @@ Identity.importFromFullJson = function(str, password, opts, cb) { * @emits newWallet (walletId) */ Identity.prototype.bindWallet = function(w) { + preconditions.checkArgument(w && this.wallets[w.getId()]); + var self = this; - self.wallets[w.getId()] = w; log.debug('Binding wallet:' + w.getName()); w.on('txProposalsUpdated', function() { @@ -569,11 +573,10 @@ Identity.prototype.createWallet = function(opts, cb) { opts.version = opts.version || this.version; var self = this; - - var w = new walletClass(opts); - self.bindWallet(w); + self.wallets[w.getId()] = w; self.updateFocusedTimestamp(w.getId()); + self.bindWallet(w); self.storeWallet(w, function(err) { if (err) return cb(err); @@ -641,7 +644,7 @@ Identity.prototype.deleteWallet = function(walletId, cb) { this.storage.removeItem(Wallet.getStorageKey(walletId), function(err) { if (err) return cb(err); - self.emitAndKeepAlive('deletedWallet', walletId); + self.emitAndKeepAlive('walletDeleted', walletId); self.store(null, cb); return cb(); }); @@ -664,15 +667,16 @@ Identity.prototype.decodeSecret = function(secret) { * @return {string} walletId */ Identity.prototype.getLastFocusedWalletId = function() { - var max = _.max(this.focusedTimestamp); - var aId = _.findKey(this.wallets) || this.walletIds[0]; + if (this.walletIds.length == 0) return undefined; + + var max = _.max(this.focusedTimestamps); if (!max) - return aId; + return this.walletIds[0]; return _.findKey(this.focusedTimestamps, function(ts) { return ts == max; - }) || aId; + }) || this.walletIds[0]; }; Identity.prototype.updateFocusedTimestamp = function(wid) { diff --git a/js/models/Wallet.js b/js/models/Wallet.js index 29afa6e05..1414ddf8f 100644 --- a/js/models/Wallet.js +++ b/js/models/Wallet.js @@ -125,7 +125,7 @@ Wallet.TX_SIGNED_AND_BROADCASTED = 'txSignedAndBroadcasted'; Wallet.prototype.emitAndKeepAlive = function(args) { var args = Array.prototype.slice.call(arguments); - log.debug('Wallet:'+ this.getName() + ' Emitting:', args); + log.debug('Wallet:' + this.getName() + ' Emitting:', args); this.keepAlive(); this.emit.apply(this, arguments); }; @@ -331,14 +331,16 @@ Wallet.prototype._onPublicKeyRing = function(senderId, data) { return; } if (hasChanged) { + if (wasIncomplete) { this.sendPublicKeyRing(); } if (this.publicKeyRing.isComplete()) { this._lockIncomming(); + this.emitAndKeepAlive('ready'); + } else { + this.emitAndKeepAlive('publicKeyRingUpdated'); } - - this.emitAndKeepAlive('publicKeyRingUpdated'); } }; @@ -891,7 +893,7 @@ Wallet.prototype._setupBlockchainHandlers = function() { self.blockchain.on('tx', function(tx) { log.debug('Wallet:' + self.id + ' blockchain tx event'); var addresses = self.getAddresses(); - if (_.indexOf(addresses,tx.address)>=0) { + if (_.indexOf(addresses, tx.address) >= 0) { self.emitAndKeepAlive('tx', tx.address, self.addressIsChange(tx.address)); } }); @@ -932,7 +934,7 @@ Wallet.prototype.netStart = function() { self._setupBlockchainHandlers(); - self.netStarted= true; + self.netStarted = true; if (!this.isShared()) { self.emitAndKeepAlive('ready'); @@ -956,7 +958,7 @@ Wallet.prototype.netStart = function() { } log.debug('Wallet:' + self.id + ' Starting network.'); this.network.start(startOpts, function() { - self.emitAndKeepAlive('ready'); + self.emitAndKeepAlive(self.isComplete() ? 'ready' : 'waitingCopayers'); }); }; @@ -1399,7 +1401,8 @@ Wallet.prototype.getPendingTxProposalsCount = function() { var txps = this.txProposals.txps; var maxRejectCount = this.maxRejectCount(); var myId = this.getMyCopayerId(); - var pending =0, pendingForUs = 0; + var pending = 0, + pendingForUs = 0; _.each(txps, function(inTxp, ntxid) { if (!inTxp.isPending(maxRejectCount)) @@ -1407,7 +1410,7 @@ Wallet.prototype.getPendingTxProposalsCount = function() { pending++; - if (!inTxp.signedBy[myId] && !inTxp.rejectedBy[myId] ) + if (!inTxp.signedBy[myId] && !inTxp.rejectedBy[myId]) pendingForUs++ }); @@ -1845,9 +1848,8 @@ Wallet.prototype._getPayProRefundOutputs = function(txp) { var opts = JSON.parse(txp.builder.vanilla.opts); if (!opts.remainderOut) { log.warn('no remainder set. Not setting refund in PayPro'); - return; + return; } -console.log('[Wallet.js.1842:builder:]',txp.builder.vanilla.opts); //TODO var addrStr = opts.remainderOut.address; var addr = new bitcore.Address(addrStr); var script = bitcore.Script.createP2SH(addr.payload()).getBuffer(); @@ -2032,7 +2034,7 @@ Wallet.prototype.addressIsOwn = function(addrStr) { /** * @desc Returns true if a given address is a change address (remainder) * @param addrStr - * @return {boolean} + * @return {boolean} */ Wallet.prototype.addressIsChange = function(addrStr) { return this.publicKeyRing.addressIsChange(addrStr); @@ -2129,7 +2131,7 @@ Wallet.prototype.getUnspent = function(cb) { var addresses = this.getAddresses(); - log.debug('Wallet ' + this.getName() + ': Getting unspents from ' + addresses.length + ' addresses'); + log.debug('Wallet ' + this.getName() + ': Getting unspents from ' + addresses.length + ' addresses'); this.blockchain.getUnspent(addresses, function(err, unspentList) { if (err) { diff --git a/js/services/identityService.js b/js/services/identityService.js index 53cf4331f..182e7162e 100644 --- a/js/services/identityService.js +++ b/js/services/identityService.js @@ -126,6 +126,13 @@ angular.module('copayApp.services') $location.path('/send'); }; + root.noFocusedWallet = function() { + $rootScope.wallet = null; + $timeout(function() { + $rootScope.$digest(); + }) + }; + root.setFocusedWallet = function(w, dontUpdateIt) { if (!_.isObject(w)) w = $rootScope.iden.getWalletById(w); @@ -157,6 +164,11 @@ angular.module('copayApp.services') notification.error('Error', $filter('translate')('Received corrupt message from ') + peerId); } }); + + w.on('publicKeyRingUpdated', function() { + $rootScope.$digest(); + }); + w.on('ready', function() { var isFocused = root.isFocused(wid); copay.logger.debug('Wallet:' + w.getName() + ' is ready. Focused:', isFocused); @@ -280,13 +292,8 @@ angular.module('copayApp.services') $rootScope.$digest() }); - iden.on('deletedWallet', function(wid) { - notification.info('Wallet deleted', $filter('translate')('This wallet was deleted')); - if ($rootScope.wallet.id === wid) { - $rootScope.wallet = null; - var lastFocused = iden.getLastFocusedWalletId(); - root.setFocusedWallet(lastFocused); - } + iden.on('walletDeleted', function(wid) { + // do nothing. this is handled 'on sync' on controller. }); iden.on('closed', function() { @@ -307,7 +314,7 @@ angular.module('copayApp.services') }; root.importWallet = function(encryptedObj, pass, opts, cb) { - copay.Compatibility.importEncryptedWallet($rootScope.iden, encryptedObj, pass, opts); + copay.Compatibility.importEncryptedWallet($rootScope.iden, encryptedObj, pass, opts, cb); }; root.joinWallet = function(opts, cb) { diff --git a/meeting b/meeting new file mode 100644 index 000000000..2e4d4e7e1 --- /dev/null +++ b/meeting @@ -0,0 +1,37 @@ + +- We have an historical opportunity + +- To create the software EVERYONE in the WORLD will use for their finance +- To enhance everyone's life by creating an awesome software +- To colaborate with Bitcoin adoption, by creating a simple and intuite wallet +- + + + + + +- be obsessive about the UX +- fucking use Copay +- subscribe and read bitcore dev + + + +- Company funds + - Startups + - Middle size companies + +- Friends funds +- Own funds + - 1-1 for every day usage + - easy and FAST mobile access + - QR reading + - PayPro + + - 2-4 for long term holding + - swipe without need of insight or copay.io + - paper walleting + - + +NOT: + + diff --git a/test-users b/test-users new file mode 100644 index 000000000..d6f982bd1 --- /dev/null +++ b/test-users @@ -0,0 +1,19 @@ + +wallet addr: 2N7YdozHPSyDomeov9sU6kL3RdGkZPUaV2v + + +ematiu+1@gmail.com password: 123 +extPubKey: tprv8ZgxMBicQKsPdWNCTqR5zbCTTCLgc4saAQE32LqLWMHmSzFncTdZegFS7CyA8FKQX9kX7FPAJ1scvtkgumYRJ4iAc4pNekm3LzPtikR3C2L + +ematiu+2@gmail.com password:2 + extPubKey: tprv8ZgxMBicQKsPem5BuuDT6xY9etUC2RohpUoyzoa1MEkkZyAHhszaHPZTmgDheN31hSP1r6bRwpj2JC66r1CPpftwaRrhz9Wz3e9yRVScw9Y + + +ematiu+3@gmail.com password:3 + extPubKey: tprv8ZgxMBicQKsPeQixUQZw1zm2LY6uJqT6oJMStMQHsHkMQDFXwxdomkkFCvMWZbQri3B8mzapiMvREXP85HFKmoUND48yfLEq7AuNCaj41Dw + + +util/swipeWallet.js n2kMqQ8Si9GndzQ6FrJxcwHMKacK2rCEpK 2 tprv8ZgxMBicQKsPdWNCTqR5zbCTTCLgc4saAQE32LqLWMHmSzFncTdZegFS7CyA8FKQX9kX7FPAJ1scvtkgumYRJ4iAc4pNekm3LzPtikR3C2L tprv8ZgxMBicQKsPem5BuuDT6xY9etUC2RohpUoyzoa1MEkkZyAHhszaHPZTmgDheN31hSP1r6bRwpj2JC66r1CPpftwaRrhz9Wz3e9yRVScw9Y tprv8ZgxMBicQKsPeQixUQZw1zm2LY6uJqT6oJMStMQHsHkMQDFXwxdomkkFCvMWZbQri3B8mzapiMvREXP85HFKmoUND48yfLEq7AuNCaj41Dw + +my addr: n2kMqQ8Si9GndzQ6FrJxcwHMKacK2rCEpK + diff --git a/test/util.http.js b/test/util.http.js index 4990d41e7..18d7801dc 100644 --- a/test/util.http.js +++ b/test/util.http.js @@ -16,7 +16,7 @@ describe('http utils', function() { send: function() { var self = this; setTimeout(function() { - self.response = 'test'; + self.response = [1,2,3,4]; self.error ? self.onerror() : self.onload(); }, 10); }, diff --git a/test/util.log.js b/test/util.log.js index 13694c105..899860624 100644 --- a/test/util.log.js +++ b/test/util.log.js @@ -21,7 +21,7 @@ describe('log utils', function() { log.warn('hola'); var arg = console.warn.getCall(0).args[0]; - arg.should.contain('util.log.js'); + //arg.should.contain('util.log.js'); /* Firefox does not include the stack track */ arg.should.contain('hola'); console.warn.restore(); }); diff --git a/util/build.js b/util/build.js index 5bbd0264e..1d55781ef 100644 --- a/util/build.js +++ b/util/build.js @@ -116,7 +116,6 @@ var createBundle = function(opts) { // The following 2 lines fix karma tests b.require('sjcl'); - if (opts.debug) { //include dev dependencies b.require('sinon'); diff --git a/views/homeWallet.html b/views/homeWallet.html index 5563d1fd5..798473247 100644 --- a/views/homeWallet.html +++ b/views/homeWallet.html @@ -1,4 +1,4 @@ -