diff --git a/copay.js b/copay.js index fa34b585b..8d2faed83 100644 --- a/copay.js +++ b/copay.js @@ -10,11 +10,13 @@ var Insight = module.exports.Insight = require('./js/models/blockchain/Insight') var StorageLocalPlain = module.exports.StorageLocalPlain = require('./js/models/storage/LocalPlain'); var StorageLocalEncrypted = module.exports.StorageLocalEncrypted = require('./js/models/storage/LocalEncrypted'); -module.exports.Wallet = require('soop').load('./js/models/core/Wallet',{ +var WalletFactory = require('soop').load('./js/models/core/WalletFactory',{ Network: WebRTC, Blockchain: Insight, Storage: StorageLocalPlain, }); +module.exports.WalletFactory = WalletFactory; +//var walletFactory = new WalletFactory(config); module.exports.API = require('./API'); diff --git a/index.html b/index.html index 8c725b41c..78b5015c4 100644 --- a/index.html +++ b/index.html @@ -156,17 +156,20 @@

Pending Transactions ({{txsoutput.length}})

-
+
{{txp}}

Address 1

Address 2

-
+ +
YOU SIGNED!
+ +
Faltan 3 cosigners - +
diff --git a/js/app.js b/js/app.js index 56fc11cde..21859c3ff 100644 --- a/js/app.js +++ b/js/app.js @@ -9,7 +9,7 @@ angular.module('copay',[ 'copay.transactions', 'copay.send', 'copay.backup', - 'copay.network', + 'copay.walletFactory', 'copay.signin', 'copay.peer' ]); @@ -19,7 +19,7 @@ angular.module('copay.home', []); angular.module('copay.transactions', []); angular.module('copay.send', []); angular.module('copay.backup', []); -angular.module('copay.network', []); +angular.module('copay.walletFactory', []); angular.module('copay.signin', []); angular.module('copay.peer', []); diff --git a/js/config.js b/js/config.js index 8e0d35ee8..cbc46bab8 100644 --- a/js/config.js +++ b/js/config.js @@ -10,6 +10,8 @@ var config = { wallet: { requiredCopayers: 2, totalCopayers: 3, + spendUnconfirmed: 1, + verbose: 1, }, blockchain: { host: 'test.insight.is', diff --git a/js/controllers/send.js b/js/controllers/send.js index 8b2bf9e0a..71687fdeb 100644 --- a/js/controllers/send.js +++ b/js/controllers/send.js @@ -13,25 +13,8 @@ angular.module('copay.send').controller('SendController', var w = $rootScope.wallet; var pkr = w.publicKeyRing; var txp = w.txProposals; - var opts = {remainderOut: { address: pkr.generateAddress(true).toString() }}; - - // From @cmgustavo's wallet - w.listUnspent(function (unspentTest) { -console.log('[send.js.19:unspentTest:]',unspentTest); //TODO - - txp.create( - '15q6HKjWHAksHcH91JW23BJEuzZgFwydBt', - '123456789', - unspentTest, - w.privateKey, - opts - ); -console.log('[send.js.29:txp:] READY:',txp); //TODO - - Network.storeOpenWallet(); - Network.sendTxProposals(); - $rootScope.$digest; - - }); + w.createTx( '15q6HKjWHAksHcH91JW23BJEuzZgFwydBt', '12345',function() { + $rootScope.$digest(); + }); }; }); diff --git a/js/controllers/signin.js b/js/controllers/signin.js index 62fca1008..cc84f6823 100644 --- a/js/controllers/signin.js +++ b/js/controllers/signin.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copay.signin').controller('SigninController', - function($scope, $rootScope, $location, Network) { + function($scope, $rootScope, $location, walletFactory) { // var peerData = Storage.get($rootScope.walletId, 'peerData'); // $rootScope.peerId = peerData ? peerData.peerId : null; @@ -10,42 +10,45 @@ angular.module('copay.signin').controller('SigninController', $scope.selectedWalletId = false; $scope.listWalletIds = function() { - return copay.Wallet.factory.getWalletIds(); + return walletFactory.getWalletIds(); + }; + + var _setupUxHandlers = function(w) { + w.on('open', function(){ + $location.path('peer'); + $rootScope.wallet = w; + $rootScope.$digest(); + }); + w.on('openError', function(){ + $scope.loading = false; + $rootScope.flashMessage = {type:'error', message: 'Wallet not found'}; + $location.path('signin'); + }); }; $scope.create = function() { +console.log('[signin.js.42:create:]'); //TODO $scope.loading = true; - Network.createWallet(); - Network.init(function() { - $location.path('peer'); - $rootScope.$digest(); - }); + var w = walletFactory.create(); + _setupUxHandlers(w); + w.netStart(); }; $scope.open = function(walletId) { $scope.loading = true; - Network.openWallet(walletId); - - if ($rootScope.wallet && $rootScope.wallet.id) { - Network.init(function() { - $location.path('peer'); - $rootScope.$digest(); - }); - } - else { - $scope.loading = false; - $rootScope.flashMessage = {type:'error', message: 'Wallet not found'}; - $location.path('signin'); - } + var w = walletFactory.open(walletId); + _setupUxHandlers(w); + w.netStart(); }; $scope.join = function(cid) { +console.log('[signin.js.42:join:]'); //TODO $scope.loading = true; if (cid) { - Network.init(function() { + Network.init(null, function() { Network.connect(cid, function() { $location.path('peer'); diff --git a/js/controllers/transactions.js b/js/controllers/transactions.js index beaf553cb..b92a6b409 100644 --- a/js/controllers/transactions.js +++ b/js/controllers/transactions.js @@ -24,4 +24,11 @@ angular.module('copay.transactions').controller('TransactionsController', ]; $scope.txsoutput = $rootScope.wallet.getTxProposals(); + + $scope.sign = function (ntxid) { + var w = $rootScope.wallet; + var ret = w.sign(ntxid); +console.log('[transactions.js.28:ret:]',ret); //TODO + $scope.txsoutput = $rootScope.wallet.getTxProposals(); + }; }); diff --git a/js/models/blockchain/Insight.js b/js/models/blockchain/Insight.js index d45be6266..b7f11fad4 100644 --- a/js/models/blockchain/Insight.js +++ b/js/models/blockchain/Insight.js @@ -59,7 +59,7 @@ Insight.prototype.listUnspent = function(addresses, cb) { self._request(options, function(err, res) { if (res && res.length > 0) { all = all.concat(res); - } + } callback(); }); }, function() { diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index 39ba995ff..43f419d85 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -7,99 +7,134 @@ var coinUtil = bitcore.util; var buffertools = bitcore.buffertools; var Builder = bitcore.TransactionBuilder; var http = require('http'); - -var Storage = imports.Storage; -var Network = imports.Network; -var Blockchain = imports.Blockchain; - +var EventEmitter= imports.EventEmitter || require('events').EventEmitter; var copay = copay || require('../../../copay'); -function Wallet(config) { - this._startInterface(config); +function Wallet(opts) { + var self = this; + + //required params + ['storage', 'network', 'blockchain', + 'requiredCopayers', 'totalCopayers', 'spendUnconfirmed', + 'publicKeyRing', 'txProposals', 'privateKey' + ].forEach( function(k){ + if (typeof opts[k] === 'undefined') throw new Error('missing key:' + k); + self[k] = opts[k]; + }); + + this.id = opts.id || Wallet.getRandomId(); + this.publicKeyRing.walletId = this.id; + this.txProposals.walletId = this.id; } +Wallet.parent=EventEmitter; Wallet.prototype.log = function(){ if (!this.verbose) return; + console.log(arguments); +}; - console.this.log(arguments); -} +Wallet.getRandomId = function() { + var r = buffertools.toHex(coinUtil.generateNonce()); + return r; +}; -Wallet.prototype._startInterface = function(config) { - this.storage = new Storage(config.storage); - this.network = new Network(config.network); - this.blockchain = new Blockchain(config.blockchain); +Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) { + this.openWalletId(data.walletId); + this.log('RECV PUBLICKEYRING:',data); - this.networkName = config.networkName; - this.requiredCopayers = config.wallet.requiredCopayers; - this.totalCopayers = config.wallet.totalCopayers; + var shouldSend = false; + var recipients, pkr = this.publicKeyRing; + var inPKR = copay.PublicKeyRing.fromObj(data.publicKeyRing); + if (pkr.merge(inPKR, true) && !data.isBroadcast) { + this.log('### BROADCASTING PKR'); + recipients = null; + shouldSend = true; + } + else if (isInbound && !data.isBroadcast) { + // always replying to connecting peer + this.log('### REPLYING PKR TO:', senderId); + recipients = senderId; + shouldSend = true; + } + + if (shouldSend) { + this.sendPublicKeyRing(recipients); + } + + this.store(); }; -Wallet.prototype.create = function(opts) { - opts = opts || {}; - this.id = opts.id || Wallet.getRandomId(); - this.log('### CREATING NEW WALLET.' + (opts.id ? ' USING ID: ' + opts.id : ' NEW ID')); +Wallet.prototype._handleTxProposals = function(senderId, data, isInbound) { + this.openWalletId(data.walletId); + this.log('RECV TXPROPOSAL:',data); //TODO - this.privateKey = new copay.PrivateKey({ - networkName: this.networkName - }); - this.log('\t### PrivateKey Initialized'); + var shouldSend = false; + var recipients; + var inTxp = copay.TxProposals.fromObj(data.txProposals); + var mergeInfo = this.txProposals.merge(inTxp, true); - this.publicKeyRing = new copay.PublicKeyRing({ - walletId: this.id, - requiredCopayers: opts.requiredCopayers || this.requiredCopayers, - totalCopayers: opts.totalCopayers || this.totalCopayers, - networkName: this.networkName, - }); + var addSeen = this.addSeenToTxProposals(); + if ((mergeInfo.merged && !data.isBroadcast) || addSeen) { + this.log('### BROADCASTING txProposals. ' ); + recipients = null; + shouldSend = true; + } + else if (isInbound && !data.isBroadcast) { + // always replying to connecting peer + this.log('### REPLYING txProposals TO:', senderId); + recipients = senderId; + shouldSend = true; + } - this.publicKeyRing.addCopayer(this.privateKey.getBIP32().extendedPublicKeyString()); - this.log('\t### PublicKeyRing Initialized WalletID: ' + this.publicKeyRing.walletId); - - this.txProposals = new copay.TxProposals({ - walletId: this.id, - networkName: this.networkName, - }); - this.log('\t### TxProposals Initialized'); + if (shouldSend) + this.sendTxProposals(recipients); + + this.store(); }; - -Wallet.prototype._checkLoad = function(walletId) { - var ret = this.storage.get(walletId, 'publicKeyRing') && - this.storage.get(walletId, 'txProposals') && - this.storage.get(walletId, 'privateKey') - ; - return ret; -} - -Wallet.prototype.load = function(walletId) { - if (! this._checkLoad(walletId)) return; - - - this.id = walletId; - this.publicKeyRing = new copay.PublicKeyRing.fromObj( - this.storage.get(this.id, 'publicKeyRing') - ); - this.txProposals = new copay.TxProposals.fromObj( - this.storage.get(this.id, 'txProposals') - ); - this.privateKey = new copay.PrivateKey.fromObj( - this.storage.get(this.id, 'privateKey') - ); //TODO secure - - // JIC: Add our key - try { - this.publicKeyRing.addCopayer( - this.privateKey.getBIP32().extendedPublicKeyString() - ); - } catch (e) { - this.log('NOT NECCESARY AN ERROR:', e); //TODO - }; +Wallet.prototype._handleData = function(senderId, data, isInbound) { + switch(data.type) { + case 'publicKeyRing': + this._handlePublicKeyRing(senderId, data, isInbound); + break; + case 'txProposals': + this._handleTxProposals(senderId, data, isInbound); + break; + case 'abort': + this.emit('abort'); + break; + } }; +Wallet.prototype._handleNetworkChange = function(newPeer) { + if (!newPeer) return; + this.log('#### Setting new PEER:', newPeer); + this.sendPublicKeyRing(newPeer); + this.sendTxProposals(newPeer); +}; + +Wallet.prototype.netStart = function(cb) { + var self = this; + var net = this.network; + net.on('networkChange', function() { self._handleNetworkChange() } ); + net.on('data', function() { self._handleData();}); + net.on('open', function() {}); // TODO + net.on('close', function() {}); // TODO + net.start(function(peerId) { + self.emit('created'); + return cb(); + }); +}; Wallet.prototype.store = function() { - Wallet.factory.addWalletId(this.id); + this.storage.set(this.id,'opts', { + id: this.id, + spendUnconfirmed: this.spendUnconfirmed, + requiredCopayers: this.requiredCopayers, + totalCopayers: this.totalCopayers, + }); this.storage.set(this.id,'publicKeyRing', this.publicKeyRing.toObj()); this.storage.set(this.id,'txProposals', this.txProposals.toObj()); this.storage.set(this.id,'privateKey', this.privateKey.toObj()); @@ -114,6 +149,7 @@ Wallet.prototype.sendTxProposals = function(recipients) { txProposals: this.txProposals.toObj(), walletId: this.id, }); + this.emit('txProposalsUpdated', this.txProposals); }; Wallet.prototype.sendPublicKeyRing = function(recipients) { @@ -124,38 +160,68 @@ Wallet.prototype.sendPublicKeyRing = function(recipients) { publicKeyRing: this.publicKeyRing.toObj(), walletId: this.id, }); + this.emit('publicKeyRingUpdated', this.publicKeyRing); }; Wallet.prototype.generateAddress = function() { var addr = this.publicKeyRing.generateAddress(); this.store(); - - this.network.send(null, { - type: 'publicKeyRing', - publicKeyRing: this.publicKeyRing.toObj(), - walletId: this.id - }); - + this.sendPublicKeyRing(); return addr; }; Wallet.prototype.getTxProposals = function() { var ret = []; - this.txProposals.txps.forEach(function(txp) { + var self= this; + self.txProposals.txps.forEach(function(txp) { var i = {txp:txp}; - i.signedByUs = txp.signedBy[this.privateKey.id]?true:false; + i.ntxid = txp.builder.build().getNormalizedHash(); + i.signedByUs = txp.signedBy[self.privateKey.id]?true:false; ret.push(i); }); + return ret; +}; +// TODO: this can be precalculated. +Wallet.prototype._findTxByNtxid = function(ntxid) { + var ret; + var l = this.txProposals.txps.length; + var id = ntxid.toString('hex'); + for(var i=0; i always go to storage + * var wallet = WF.create(config,walletId); -> create wallets, with the given ID (or random is not given) + * + * var wallet = WF.open(config,walletId); -> try to read walletId, if fails, create a new wallet with that id + */ + +function WalletFactory(config) { + var self = this; + this.storage = new Storage(config.storage); + this.network = new Network(config.network); + this.blockchain = new Blockchain(config.blockchain); + + this.networkName = config.networkName; + this.verbose = config.verbose; + this.walletDefaults = config.wallet; +} + +WalletFactory.prototype.log = function(){ + if (!this.verbose) return; + console.log(arguments); +}; + + +WalletFactory.prototype._checkRead = function(walletId) { + var s = this.storage; + var ret = s.get(walletId, 'publicKeyRing') && + s.get(walletId, 'txProposals') && + s.get(walletId, 'opts') && + s.get(walletId, 'privateKey') + ; + return ret; +}; + +WalletFactory.prototype.read = function(walletId) { + if (! this._checkRead(walletId)) return false; + + var s = this.storage; + var opts = s.get(walletId, 'opts'); + + opts.publicKeyRing = new PublicKeyRing.fromObj(s.get(walletId, 'publicKeyRing')); + opts.txProposals = new TxProposals.fromObj(s.get(walletId, 'txProposals')); + opts.privateKey = new PrivateKey.fromObj(s.get(walletId, 'privateKey')); + + opts.storage = this.storage; + opts.network = this.network; + opts.blockchain = this.blockchain; + + var w = new Wallet(opts); + + // JIC: Add our key + try { + w.publicKeyRing.addCopayer( + w.privateKey.getBIP32().extendedPublicKeyString() + ); + } catch (e) { + this.log('NOT NECCESARY AN ERROR:', e); //TODO + } + this.log('### WALLET OPENED:', w.id); + return w; +}; + +WalletFactory.prototype.create = function(opts) { + var s = WalletFactory.storage; + opts = opts || {}; + this.log('### CREATING NEW WALLET.' + (opts.id ? ' USING ID: ' + opts.id : ' NEW ID')); + + opts.privateKey = opts.privateKey || new PrivateKey({ networkName: this.networkName }); + this.log('\t### PrivateKey Initialized'); + + var requiredCopayers = opts.requiredCopayers || this.walletDefaults.requiredCopayers; + var totalCopayers = opts.totalCopayers || this.walletDefaults.totalCopayers; + + opts.publicKeyRing = opts.publicKeyRing || new PublicKeyRing({ + networkName: this.networkName, + requiredCopayers: requiredCopayers, + totalCopayers: totalCopayers, + }); + opts.publicKeyRing.addCopayer(opts.privateKey.getBIP32().extendedPublicKeyString()); + this.log('\t### PublicKeyRing Initialized'); + + opts.txProposals = opts.txProposals || new TxProposals({ + networkName: this.networkName, + }); + this.log('\t### TxProposals Initialized'); + + opts.storage = this.storage; + opts.network = this.network; + opts.blockchain = this.blockchain; + opts.spendUnconfirmed = opts.spendUnconfirmed || this.walletDefaults.spendUnconfirmed; + opts.requiredCopayers = requiredCopayers; + opts.totalCopayers = totalCopayers; + var w = new Wallet(opts); + w.store(); + this.addWalletId(w.id); + return w; +}; + +WalletFactory.prototype.open = function(walletId) { + if(!WalletFactory.read(walletId)) { + WalletFactory.create({id: walletId}); + } +}; + +WalletFactory.prototype.getWalletIds = function() { + var ids = this.storage.getGlobal('walletIds'); + return ids || []; +} + +WalletFactory.prototype._delWalletId = function(walletId) { + var ids = this.getWalletIds(); + var index = ids.indexOf(walletId); + if (index === -1) return; + ids.splice(index, 1); // removes walletId + this.storage.setGlobal('walletIds', ids); +}; + +WalletFactory.prototype.remove = function(walletId) { + WalletFactory._delWalletId(walletId); + // TODO remove wallet contents, not only the id (Wallet.remove?) +}; + +WalletFactory.prototype.addWalletId = function(walletId) { + var ids = this.getWalletIds(); + if (ids.indexOf(walletId) !== -1) return; + ids.push(walletId); + this.storage.setGlobal('walletIds', ids); +}; + +module.exports = require('soop')(WalletFactory); diff --git a/js/models/network/WebRTC.js b/js/models/network/WebRTC.js index f3efa6895..bb125fce1 100644 --- a/js/models/network/WebRTC.js +++ b/js/models/network/WebRTC.js @@ -131,8 +131,7 @@ Network.prototype._addPeer = function(peerId, isInbound) { } }; -Network.prototype._setupConnectionHandlers = function( - dataConn, isInbound, openCallback, closeCallback) { +Network.prototype._setupConnectionHandlers = function(dataConn, isInbound) { var self=this; @@ -144,7 +143,7 @@ Network.prototype._setupConnectionHandlers = function( self._addPeer(dataConn.peer, isInbound); self._notify( isInbound ? dataConn.peer : null); - if (typeof openCallback === 'function') openCallback(); + this.emit('open'); } }); @@ -161,7 +160,7 @@ Network.prototype._setupConnectionHandlers = function( console.log('### CLOSE RECV FROM:', dataConn.peer); self._onClose(dataConn.peer); - if (typeof closeCallback === 'function') closeCallback(); + this.emit('close'); }); }; @@ -174,7 +173,6 @@ Network.prototype._setupPeerHandlers = function(openCallback) { var self=this; var p = this.peer; - p.on('open', function(peerId) { self.peerId = peerId; self.connectedPeers = [peerId]; @@ -218,8 +216,6 @@ Network.prototype.start = function(openCallback) { Network.prototype._sendToOne = function(peerId, data, cb) { if (peerId !== this.peerId) { -console.log('[WebRTC.js.222:peerId:]',peerId, data); //TODO - var conns = this.peer.connections[peerId]; if (conns) { @@ -257,7 +253,7 @@ Network.prototype.send = function(peerIds, data, cb) { self._sendToOne(peerIds, data, cb); }; -Network.prototype.connectTo = function(peerId, openCallback, closeCallback ) { +Network.prototype.connectTo = function(peerId) { var self = this; console.log('### STARTING TO CONNECT TO:' + peerId ); @@ -269,7 +265,7 @@ Network.prototype.connectTo = function(peerId, openCallback, closeCallback ) { metadata: { message: 'hi copayer!' } }); - self._setupConnectionHandlers(dataConn, false, openCallback, closeCallback); + self._setupConnectionHandlers(dataConn, false); }; diff --git a/js/services/network.js b/js/services/network.js index a4e69dac7..55a6e9c90 100644 --- a/js/services/network.js +++ b/js/services/network.js @@ -12,155 +12,31 @@ angular.module('copay.network') $rootScope.$digest(); }; - // set new inbound connections - var _setNewPeer = function(newPeer) { + var closeWallet = function() { var w = $rootScope.wallet; - log('#### Setting new PEER:', newPeer); - w.sendPublicKeyRing(newPeer); - w.sendTxProposals(newPeer); + if (w && w.id) w.store(); + + log('### CLOSING WALLET'); + delete $rootScope['wallet']; }; - var _handleNetworkChange = function(newPeer) { - var cp = $rootScope.cp; - - if (newPeer) - _setNewPeer(newPeer); - - _refreshUx(); - }; - - // TODO -> probably not in network.js - var storeOpenWallet = function() { - var w = $rootScope.wallet; - w.store(); - log('\t### Wallet %s Stored', w.id); - }; - - // TODO -> probably not in network.js - var createWallet = function(walletId) { - var w = $rootScope.wallet || new copay.Wallet(config); - w.create({id: walletId}); - w.store(); - $rootScope.wallet = w; - log('createWallet ENDED'); //TODO - }; - - var openWallet = function (walletId) { - var w = $rootScope.wallet || new copay.Wallet(config); - w.load(walletId); - if (w && w.publicKeyRing && w.privateKey) { - log('### WALLET OPENED:', w.walletId); - $rootScope.wallet = w; - } - }; - - - var closeWallet = function() { - var w = $rootScope.wallet; - if (w && w.id) - w.store(); - - log('### CLOSING WALLET'); - delete $rootScope['wallet']; - }; - - var _checkWallet = function(walletId) { - log('[network.js.79:_checkWallet:]',walletId); //TODO - - if ($rootScope.wallet && $rootScope.wallet.id === walletId) - return; - - if ($rootScope.wallet && $rootScope.wallet.id && $rootScope.wallet.id !== walletId) { - throw new Error('message to wrong walletID'); - } - - if (!openWallet(walletId)) { - createWallet(walletId); - } - }; - - var _handlePublicKeyRing = function(senderId, data, isInbound) { - _checkWallet(data.walletId); - var shouldSend = false; - - var w = $rootScope.wallet; - var recipients, pkr = w.publicKeyRing; - var inPKR = copay.PublicKeyRing.fromObj(data.publicKeyRing); - if (pkr.merge(inPKR, true) && !data.isBroadcast) { - log('### BROADCASTING PKR'); - recipients = null; - shouldSend = true; - } - else if (isInbound && !data.isBroadcast) { - // always replying to connecting peer - log('### REPLYING PKR TO:', senderId); - recipients = senderId; - shouldSend = true; - } - - if (shouldSend) { - w.sendPublicKeyRing(recipients); - } + // public methods + var init = function(walletId, cb) { + if (!$rootScope.wallet) { + // create an empty Wallet + $rootScope.wallet = new copay.Wallet(config); + } + var w = $rootScope.wallet; +console.log('[network.js.30:walletId:]',walletId); //TODO + if (!walletId) w.openWalletId(); + w.on('created', _refreshUx); + w.on('txProposals', _refreshUx); + w.on('publicKeyRing', _refreshUx); + w.on('abort', function() { + disconnect(); _refreshUx(); - }; - - var _handleTxProposals = function(senderId, data, isInbound) { - _checkWallet(data.walletId); - - var shouldSend = false; - var w = $rootScope.wallet; - log('RECV TXPROPOSAL:',data); //TODO - - var recipients; - var inTxProposals = copay.TxProposals.fromObj(data.txProposals); - var mergeInfo = w.txProposals.merge(inTxProposals, true); - - var addSeen = w.addSeenToTxProposals(); - if ((mergeInfo.merged && !data.isBroadcast) || addSeen) { - log('### BROADCASTING txProposals. ' ); - recipients = null; - shouldSend = true; - } - else if (isInbound && !data.isBroadcast) { - // always replying to connecting peer - log('### REPLYING txProposals TO:', senderId); - recipients = senderId; - shouldSend = true; - } - - if (shouldSend) { - w.sendTxProposals(recipients); - } - }; - - var _handleData = function(senderId, data, isInbound) { - - switch(data.type) { - case 'publicKeyRing': - _handlePublicKeyRing(senderId, data, isInbound); - break; - case 'txProposals': - _handleTxProposals(senderId, data, isInbound); - break; - case 'abort': - disconnect(); - _refreshUx(); - break; - } - }; - - // public methods - var init = function(cb) { - if (!$rootScope.wallet) { - // create an empty Wallet - $rootScope.wallet = new copay.Wallet(config); - } - var net = $rootScope.wallet.network; - net.on('networkChange', _handleNetworkChange); - net.on('data', _handleData); - net.start(function(peerId) { - return cb(); - }); + }); + w.netStart(cb); }; var disconnect = function() { @@ -174,14 +50,9 @@ angular.module('copay.network') }; var connect = function(peerId, openCallback, failCallback) { - if ($rootScope.wallet.network) { - $rootScope.wallet.network.connectTo(peerId, openCallback, function () { - disconnect(); - failCallback(); - }); - } - else - return failCallback(); + $rootScope.wallet.connectTo(peerId); + $rootScope.wallet.on('open', openCallback); + $rootScope.wallet.on('close', failCallback); }; var sendTxProposals = function(recipients) { @@ -193,11 +64,6 @@ angular.module('copay.network') init: init, connect: connect, disconnect: disconnect, - - createWallet: createWallet, - openWallet: openWallet, - storeOpenWallet: storeOpenWallet, - sendTxProposals: sendTxProposals, } }); diff --git a/js/services/walletFactory.js b/js/services/walletFactory.js new file mode 100644 index 000000000..2264f104b --- /dev/null +++ b/js/services/walletFactory.js @@ -0,0 +1,8 @@ +'use strict'; + +var wf; +angular.module('copay.walletFactory').factory('walletFactory', function($rootScope) { + wf = wf || new copay.WalletFactory(config); + return wf; +}); + diff --git a/test/test.walletfactory.js b/test/test.walletfactory.js new file mode 100644 index 000000000..d3b7c7044 --- /dev/null +++ b/test/test.walletfactory.js @@ -0,0 +1,57 @@ +'use strict'; + +var chai = chai || require('chai'); +var should = chai.should(); + +var WebRTC = require('../js/models/network/WebRTC'); +var Insight = require('../js/models/blockchain/Insight'); +var FakeStorage = require('./FakeStorage'); + +var WalletFactory = typeof copay === 'undefined' ? require('soop').load('../js/models/core/WalletFactory',{ + Network: WebRTC, + Blockchain: Insight, + Storage: FakeStorage, +}) : copay.WalletFactory; + + +var addCopayers = function (w) { + for(var i=0; i<4; i++) { + w.publicKeyRing.addCopayer(); + } +}; + +describe('WalletFactory model', function() { + var config = { + wallet: { + requiredCopayers: 3, + totalCopayers: 5, + spendUnconfirmed: 1, + }, + blockchain: { + host: 'test.insight.is', + port: 80 + }, + networkName: 'testnet', + }; + + describe('factory', function() { + it('should create the factory', function() { + var wf = new WalletFactory(config); + should.exist(wf); + }); + it('should be able to create wallets', function() { + var wf = new WalletFactory(config); + var w = wf.create(); + should.exist(w); + }); + it('should be able to get wallets', function() { + var wf = new WalletFactory(config); + var w = wf.create(); + + var w2 = wf.read(w.id); + should.exist(w2); + w2.id.should.equal(w.id); + }); + }); + +});