diff --git a/API.js b/API.js index dd6d2fe19..76f30a29e 100644 --- a/API.js +++ b/API.js @@ -10,23 +10,13 @@ API.prototype._init = function(opts) { opts = opts || {}; self.opts = opts; - var Wallet = require('soop').load('./js/models/core/Wallet', { + var WalletFactory = require('soop').load('./js/models/core/WalletFactory', { Storage: opts.Storage || require('./test/mocks/FakeStorage'), - Network: opts.Network || require('./js/models/network/WebRTC'), + Network: opts.Network || require('./js/models/network/Base'), Blockchain: opts.Blockchain || require('./js/models/blockchain/Insight') }); - - var config = { - wallet: { - requiredCopayers: opts.requiredCopayers || 3, - totalCopayers: opts.totalCopayers || 5, - } - }; - var walletConfig = opts.walletConfig || config; - var walletOpts = opts.walletOpts || {}; - - self.wallet = self.opts.wallet || Wallet.factory.create(walletConfig, walletOpts); + this.walletFactory = new WalletFactory(opts); }; API._coerceArgTypes = function(args, argTypes) { @@ -179,13 +169,13 @@ API.prototype.getCommands = decorate('getCommands', [ ['callback', 'function'] ]); -API.prototype._cmd_getPublicKeyRingId = function(callback) { +API.prototype._cmd_getWalletIds = function(callback) { var self = this; - return callback(null, self.wallet.publicKeyRing.walletId); + return callback(null, self.walletFactory.getWalletIds()); }; -API.prototype.getPublicKeyRingId = decorate('getPublicKeyRingId', [ +API.prototype.getWalletIds = decorate('getWalletIds', [ ['callback', 'function'] ]); diff --git a/bin/copay b/bin/copay index 2721da0e2..9890f66cd 100755 --- a/bin/copay +++ b/bin/copay @@ -18,11 +18,10 @@ var main = function() { var api = new API(commander); var args = commander.args; + var command = args[0]; + var commandArgs = args.slice(1); try { - var command = args[0]; - var commandArgs = args.slice(1); - if (command[0] == '_' || typeof api[command] != 'function') throw new Error('invalid command'); diff --git a/copay.js b/copay.js index fa34b585b..d68d1cfb1 100644 --- a/copay.js +++ b/copay.js @@ -10,11 +10,12 @@ 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; module.exports.API = require('./API'); diff --git a/css/main.css b/css/main.css index 9db1e305c..c42153d1b 100644 --- a/css/main.css +++ b/css/main.css @@ -135,7 +135,6 @@ h3 { span.panel-res { float: right; - width: 3%; padding: 0.4rem 0.55rem; margin: 0 1rem; border-radius: 1rem; @@ -160,6 +159,11 @@ span.panel-res { margin: 0.5rem 0 1rem; } +.share-wallet.panel { + background-color: #111; + color: #FBE500; +} + button.primary { background-color: #111; } button.secondary { background-color: #FAE448 !important; } @@ -180,3 +184,8 @@ button.secondary:hover { background-color: #FFDF00 !important;} .size-60 { font-size: 60px; } .size-72 { font-size: 72px; } .m10t {margin-top: 10px;} +.p0r {padding-right: 0;} +.p70r {padding-right: 70px;} +.p70l {padding-left: 70px;} +.p5h {padding: 0 5px;} +.br100 {border-radius: 100%;} \ No newline at end of file diff --git a/index.html b/index.html index f1b6c95cb..1b8f93c30 100644 --- a/index.html +++ b/index.html @@ -96,12 +96,53 @@ + + - + @@ -295,6 +342,7 @@ + diff --git a/js/app.js b/js/app.js index 56fc11cde..f1fff46a0 100644 --- a/js/app.js +++ b/js/app.js @@ -9,8 +9,9 @@ angular.module('copay',[ 'copay.transactions', 'copay.send', 'copay.backup', - 'copay.network', + 'copay.walletFactory', 'copay.signin', + 'copay.setup', 'copay.peer' ]); @@ -19,7 +20,8 @@ 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.setup', []); angular.module('copay.peer', []); diff --git a/js/config.js b/js/config.js index 8e0d35ee8..d73f23cdb 100644 --- a/js/config.js +++ b/js/config.js @@ -7,9 +7,15 @@ var config = { maxPeers: 3, debug: 3, }, + limits: { + totalCopayers: 10, + mPlusN: 15 + }, wallet: { requiredCopayers: 2, totalCopayers: 3, + spendUnconfirmed: 1, + verbose: 1, }, blockchain: { host: 'test.insight.is', diff --git a/js/controllers/header.js b/js/controllers/header.js index 9653731f9..91f00d863 100644 --- a/js/controllers/header.js +++ b/js/controllers/header.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copay.header').controller('HeaderController', - function($scope, $rootScope, $location, Network) { + function($scope, $rootScope, $location, walletFactory) { $scope.menu = [{ 'title': 'Home', 'icon': 'fi-home', @@ -35,15 +35,13 @@ angular.module('copay.header').controller('HeaderController', return false; }; - $scope.init = function() { - $rootScope.isLogged = false; - }; - $scope.signout = function() { - Network.disconnect(function() { + var w = $rootScope.wallet; + if (w) { + w.disconnect(); + delete $rootScope['wallet']; $location.path('signin'); - $rootScope.$digest(); - }); + } }; $scope.clearFlashMessage = function() { diff --git a/js/controllers/peer.js b/js/controllers/peer.js index b99729a5a..f6f482315 100644 --- a/js/controllers/peer.js +++ b/js/controllers/peer.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copay.peer').controller('PeerController', - function($scope, $rootScope, $location, $routeParams, Network) { + function($scope, $rootScope, $location, $routeParams) { $scope.init = function() { //Network.connect($rootScope.masterId); diff --git a/js/controllers/send.js b/js/controllers/send.js index 8b2bf9e0a..682d89dc9 100644 --- a/js/controllers/send.js +++ b/js/controllers/send.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copay.send').controller('SendController', - function($scope, $rootScope, $location, Network) { + function($scope, $rootScope, $location) { $scope.title = 'Send'; if (!$rootScope.wallet.id) { @@ -11,27 +11,8 @@ angular.module('copay.send').controller('SendController', $scope.sendTest = function() { 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/setup.js b/js/controllers/setup.js new file mode 100644 index 000000000..a8f25cb3e --- /dev/null +++ b/js/controllers/setup.js @@ -0,0 +1,48 @@ +'use strict'; + +angular.module('copay.setup').controller('SetupController', + function($scope, $rootScope, $location, walletFactory) { + + $scope.loading = false; + + $scope.totalCopayers = config.wallet.totalCopayers; + $scope.TCValues = []; + for (var n = 1; n <= config.limits.totalCopayers; n++) + $scope.TCValues.push(n); + + var updateRCSelect = function(n) { + $scope.requiredCopayers = parseInt(Math.min(n / 2 + 1, config.limits.mPlusN-n)); + $scope.RCValues = []; + for (var m = 1; m <= n; m++) { + if (n + m <= config.limits.mPlusN) { + $scope.RCValues.push(m); + } + } + }; + updateRCSelect($scope.totalCopayers); + + $scope.$watch('totalCopayers', function(tc) { + updateRCSelect(tc); + }) + + $scope.create = function(totalCopayers, requiredCopayers) { + $scope.loading = true; + var opts = { + requiredCopayers: requiredCopayers, + totalCopayers: totalCopayers + }; + var w = walletFactory.create(opts); + w.on('created', 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'); + }); + w.netStart(); + }; + + }); diff --git a/js/controllers/signin.js b/js/controllers/signin.js index 62fca1008..2a5c00890 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,55 +10,68 @@ 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('created', function() { + $location.path('peer'); + $rootScope.wallet = w; + $rootScope.$digest(); + }); + w.on('refresh', function() { + +console.log('[signin.js.23] RECEIVED REFRESH'); //TODO + $rootScope.$digest(); + }); + + w.on('openError', function(){ + $scope.loading = false; + $rootScope.flashMessage = {type:'error', message: 'Wallet not found'}; + $location.path('signin'); + }); }; $scope.create = function() { - $scope.loading = true; - - Network.createWallet(); - Network.init(function() { - $location.path('peer'); - $rootScope.$digest(); - }); + $location.path('setup'); }; $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.connect(cid, - function() { - $location.path('peer'); - $rootScope.$digest(); - }, function() { - $rootScope.flashMessage = { message: 'Connection refussed', type: 'error'}; - $location.path('home'); - $rootScope.$digest(); - }); - }); - } + walletFactory.connectTo(cid, function(w) { +console.log('[signin.js.50]'); //TODO + _setupUxHandlers(w); + w.netStart(); + }); }; + +// +// if (cid) { +// var w = walletFactory.(walletId); + //TODO + // Network.init(null, function() { + // Network.connect(cid, + // function() { + // $location.path('peer'); + // $rootScope.$digest(); + // }, function() { + // $rootScope.flashMessage = { message: 'Connection refussed', type: 'error'}; + // $location.path('home'); + // $rootScope.$digest(); + // }); + // }); +// } + // if (peerData && peerData.peerId && peerData.connectedPeers.length > 0) { // $rootScope.peerId = peerData.peerId; // $scope.join(peerData.connectedPeers); 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..8484da099 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -7,102 +7,147 @@ 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; -Wallet.prototype.log = function(){ - if (!this.verbose) return; + //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]; + }); - console.this.log(arguments); -} + console.log('creating '+opts.requiredCopayers+' of '+opts.totalCopayers+' wallet'); -Wallet.prototype._startInterface = function(config) { - this.storage = new Storage(config.storage); - this.network = new Network(config.network); - this.blockchain = new Blockchain(config.blockchain); - - this.networkName = config.networkName; - this.requiredCopayers = config.wallet.requiredCopayers; - this.totalCopayers = config.wallet.totalCopayers; -}; - - -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')); + this.verbose = opts.verbose; + this.publicKeyRing.walletId = this.id; + this.txProposals.walletId = this.id; - this.privateKey = new copay.PrivateKey({ - networkName: this.networkName - }); - this.log('\t### PrivateKey Initialized'); - - this.publicKeyRing = new copay.PublicKeyRing({ - walletId: this.id, - requiredCopayers: opts.requiredCopayers || this.requiredCopayers, - totalCopayers: opts.totalCopayers || this.totalCopayers, - networkName: this.networkName, - }); - - 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'); -}; - - -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; +Wallet.parent=EventEmitter; +Wallet.prototype.log = function(){ +// if (!this.verbose) return; + console.log(arguments); +}; +Wallet.getRandomId = function() { + var r = buffertools.toHex(coinUtil.generateNonce()); + return r; +}; - 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 +Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) { + this.log('RECV PUBLICKEYRING:',data); - // JIC: Add our key - try { - this.publicKeyRing.addCopayer( - this.privateKey.getBIP32().extendedPublicKeyString() - ); - } catch (e) { - this.log('NOT NECCESARY AN ERROR:', e); //TODO - }; + 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._handleTxProposals = function(senderId, data, isInbound) { + this.log('RECV TXPROPOSAL:',data); //TODO + + var shouldSend = false; + var recipients; + var inTxp = copay.TxProposals.fromObj(data.txProposals); + var mergeInfo = this.txProposals.merge(inTxp, true); + + 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; + } + + if (shouldSend) + this.sendTxProposals(recipients); + + this.store(); +}; + +Wallet.prototype._handleData = function(senderId, data, isInbound) { + + if (this.id !== data.walletId) + throw new Error('wrong message received: Bad wallet ID'); + +console.log('[Wallet.js.98]' , data.type); //TODO + + 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.sendWalletId(newPeer); + this.sendPublicKeyRing(newPeer); + this.sendTxProposals(newPeer); +}; + +Wallet.prototype.netStart = function() { + var self = this; + var net = this.network; + net.on('networkChange', self._handleNetworkChange.bind(self) ); + net.on('data', self._handleData.bind(self) ); + net.on('open', function() {}); // TODO + net.on('close', function() {}); // TODO + net.start(function(peerId) { + self.emit('created'); + }); +}; Wallet.prototype.store = function() { - Wallet.factory.addWalletId(this.id); +console.log('[Wallet.js.135:store:]'); //TODO + 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()); + +console.log('[Wallet.js.146] EMIT REFRESH'); //TODO + this.emit('refresh'); }; @@ -114,8 +159,20 @@ Wallet.prototype.sendTxProposals = function(recipients) { txProposals: this.txProposals.toObj(), walletId: this.id, }); + this.emit('txProposalsUpdated', this.txProposals); }; + +Wallet.prototype.sendWalletId = function(recipients) { + this.log('### SENDING walletId TO:', recipients||'All', this.walletId); + + this.network.send(recipients, { + type: 'walletId', + walletId: this.id, + }); +}; + + Wallet.prototype.sendPublicKeyRing = function(recipients) { this.log('### SENDING publicKeyRing TO:', recipients||'All', this.publicKeyRing.toObj()); @@ -124,38 +181,82 @@ 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; + opts.verbose = this.verbose; + + 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.verbose = this.verbose; + + opts.spendUnconfirmed = opts.spendUnconfirmed || this.walletDefaults.spendUnconfirmed; + opts.requiredCopayers = requiredCopayers; + opts.totalCopayers = totalCopayers; + var w = new Wallet(opts); + w.store(); + return w; +}; + +WalletFactory.prototype.open = function(walletId) { + var w = this.read(walletId) || this.create({ + id: walletId, + verbose: this.verbose, + }); + return w; +}; + +WalletFactory.prototype.openRemote = function(peedId) { + 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.getWalletIds = function() { + return this.storage.getWalletIds(); +} + +WalletFactory.prototype.remove = function(walletId) { + // TODO remove wallet contents +}; + + +WalletFactory.prototype.connectTo = function(peerId, cb) { + var self=this; + self.network.start(function() { + self.network.connectTo(peerId) + self.network.on('walletId', function(walletId) { +console.log('[WalletFactory.js.187]'); //TODO + return cb(self.open(walletId)); + }); + }); +}; + +module.exports = require('soop')(WalletFactory); diff --git a/js/models/network/WebRTC.js b/js/models/network/WebRTC.js index f3efa6895..80171fba7 100644 --- a/js/models/network/WebRTC.js +++ b/js/models/network/WebRTC.js @@ -67,7 +67,6 @@ Network.prototype._showConnectedPeers = function() { }; Network.prototype._onClose = function(peerId) { - console.log('[Network.js.70] _onClose'); //TODO this.connectedPeers = Network._arrayRemove(peerId, this.connectedPeers); this._notify(); }; @@ -103,6 +102,9 @@ Network.prototype._onData = function(data, isInbound) { case 'disconnect': this._onClose(obj.sender); break; + case 'walletId': + this.emit('walletId', obj.data.walletId); + break; default: this.emit('data', obj.sender, obj.data, isInbound); } @@ -131,8 +133,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 +145,7 @@ Network.prototype._setupConnectionHandlers = function( self._addPeer(dataConn.peer, isInbound); self._notify( isInbound ? dataConn.peer : null); - if (typeof openCallback === 'function') openCallback(); + this.emit('open'); } }); @@ -158,10 +159,10 @@ Network.prototype._setupConnectionHandlers = function( dataConn.on('close', function() { if (self.closing) return; + self.closing=1; console.log('### CLOSE RECV FROM:', dataConn.peer); - self._onClose(dataConn.peer); - if (typeof closeCallback === 'function') closeCallback(); + this.emit('close'); }); }; @@ -174,7 +175,6 @@ Network.prototype._setupPeerHandlers = function(openCallback) { var self=this; var p = this.peer; - p.on('open', function(peerId) { self.peerId = peerId; self.connectedPeers = [peerId]; @@ -208,6 +208,8 @@ Network.prototype._setupPeerHandlers = function(openCallback) { Network.prototype.start = function(openCallback) { // Start PeerJS Peer + if (this.peer) return openCallback(); // This is for connectTo-> peer is started before + this.peer = new Peer(this.peerId, { key: this.apiKey, // TODO: we need our own PeerServer KEY (http://peerjs.com/peerserver) debug: this.debug, @@ -218,8 +220,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 +257,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,11 +269,11 @@ Network.prototype.connectTo = function(peerId, openCallback, closeCallback ) { metadata: { message: 'hi copayer!' } }); - self._setupConnectionHandlers(dataConn, false, openCallback, closeCallback); + self._setupConnectionHandlers(dataConn, false); }; -Network.prototype.disconnect = function(peerId, cb) { +Network.prototype.disconnect = function(cb) { var self = this; self.closing = 1; diff --git a/js/models/storage/Base.js b/js/models/storage/Base.js index 8f61f4dfe..29ca2564c 100644 --- a/js/models/storage/Base.js +++ b/js/models/storage/Base.js @@ -17,6 +17,9 @@ Storage.prototype.set = function(walletId,v) { Storage.prototype.remove = function(walletId, k) { }; +Storage.prototype.getWalletIds = function() { +}; + // remove all values Storage.prototype.clearAll = function() { }; diff --git a/js/models/storage/File.js b/js/models/storage/File.js new file mode 100644 index 000000000..2c07b7010 --- /dev/null +++ b/js/models/storage/File.js @@ -0,0 +1,102 @@ +'use strict'; +var imports = require('soop').imports(); +var fs = imports.fs || require('fs'); + +function Storage(opts) { + opts = opts || {}; + + this.data = {}; +} + +Storage.prototype.load = function(walletId, callback) { + fs.readFile(walletId, function(err, data) { + if (err) return callback(err); + + try { + this.data[walletId] = JSON.parse(data); + } catch (err) { + if (callback) + return callback(err); + } + + if (callback) + return callback(null); + }); +}; + +Storage.prototype.save = function(walletId, callback) { + var data = JSON.stringify(this.data[walletId]); + + //TODO: update to use a queue to ensure that saves are made sequentially + fs.writeFile(walletId, data, function(err) { + if (callback) + return callback(err); + }); +}; + +Storage.prototype._read = function(k) { + var split = k.split('::'); + var walletId = split[0]; + var key = split[1]; + return this.data[walletId][key]; +}; + +Storage.prototype._write = function(k, v, callback) { + var split = k.split('::'); + var walletId = split[0]; + var key = split[1]; + if (!this.data[walletId]) + this.data[walletId] = {}; + this.data[walletId][key] = v; + this.save(walletId, callback); +}; + +// get value by key +Storage.prototype.getGlobal = function(k) { + return this._read(k); +}; + +// set value for key +Storage.prototype.setGlobal = function(k, v, callback) { + this._write(k, v, callback); +}; + +// remove value for key +Storage.prototype.removeGlobal = function(k, callback) { + var split = k.split('::'); + var walletId = split[0]; + var key = split[1]; + delete this.data[walletId][key]; + this.save(walletId, callback); +}; + +Storage.prototype._key = function(walletId, k) { + return walletId + '::' + k; +}; + +// get value by key +Storage.prototype.get = function(walletId, k) { + return this.getGlobal(this._key(walletId, k)); +}; + +// set value for key +Storage.prototype.set = function(walletId, k, v, callback) { + this.setGlobal(this._key(walletId,k), v, callback); +}; + +// remove value for key +Storage.prototype.remove = function(walletId, k, callback) { + this.removeGlobal(this._key(walletId, k), callback); +}; + +Storage.prototype.getWalletIds = function() { + return []; +}; + +// remove all values +Storage.prototype.clearAll = function(callback) { + this.data = {}; + this.save(callback); +}; + +module.exports = require('soop')(Storage); diff --git a/js/models/storage/LocalPlain.js b/js/models/storage/LocalPlain.js index 1bda410f2..d32234899 100644 --- a/js/models/storage/LocalPlain.js +++ b/js/models/storage/LocalPlain.js @@ -52,6 +52,21 @@ Storage.prototype.remove = function(walletId, k) { this.removeGlobal(this._key(walletId,k)); }; +Storage.prototype.getWalletIds = function() { + var walletIds = []; + + for (var i = 0; i < localStorage.length; i++) { + var key = localStorage.key(i); + var split = key.split('::'); + if (split.length == 2) { + var walletId = split[0]; + walletIds.push(walletId); + } + } + + return walletIds; +}; + // remove all values Storage.prototype.clearAll = function() { localStorage.clear(); diff --git a/js/routes.js b/js/routes.js index 3793d88bd..5c655b208 100644 --- a/js/routes.js +++ b/js/routes.js @@ -12,6 +12,9 @@ angular .when('/signin', { templateUrl: 'signin.html' }) + .when('/setup', { + templateUrl: 'setup.html' + }) .when('/home', { templateUrl: 'home.html' }) diff --git a/js/services/network.js b/js/services/network.js deleted file mode 100644 index a4e69dac7..000000000 --- a/js/services/network.js +++ /dev/null @@ -1,204 +0,0 @@ -'use strict'; - -angular.module('copay.network') - .factory('Network', function($rootScope) { - var peer; - - var _refreshUx = function() { - var net = $rootScope.wallet.network; - log('*** UPDATING UX'); //TODO - $rootScope.peedId = net.peerId; - $rootScope.connectedPeers = net.connectedPeers; - $rootScope.$digest(); - }; - - // set new inbound connections - var _setNewPeer = function(newPeer) { - var w = $rootScope.wallet; - log('#### Setting new PEER:', newPeer); - w.sendPublicKeyRing(newPeer); - w.sendTxProposals(newPeer); - }; - - 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); - } - _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(); - }); - }; - - var disconnect = function() { - var w = $rootScope.wallet; - var net = w.network; - - if (net) { - net.disconnect(); - } - closeWallet(); - }; - - var connect = function(peerId, openCallback, failCallback) { - if ($rootScope.wallet.network) { - $rootScope.wallet.network.connectTo(peerId, openCallback, function () { - disconnect(); - failCallback(); - }); - } - else - return failCallback(); - }; - - var sendTxProposals = function(recipients) { - var w = $rootScope.wallet; - w.sendTxProposals(recipients); - }; - - return { - 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/lib/bitcore.js b/lib/bitcore.js new file mode 100644 index 000000000..3ef2263bb --- /dev/null +++ b/lib/bitcore.js @@ -0,0 +1,375 @@ +require= +// modules are defined as an array +// [ module function, map of requireuires ] +// +// map of requireuires is short require name -> numeric require +// +// anything defined in a previous bundle is accessed via the +// orig method which is the requireuire for previous bundles +(function outer (modules, cache, entry) { + // Save the require from previous bundle to this closure if any + var previousRequire = typeof require == "function" && require; + + function newRequire(name, jumped, inSkipCache){ + + var m, skipCache = inSkipCache; + if (typeof name === 'string') { + if (name.charAt(0) === '!' ) { + name = name.substr(1); + skipCache=true; + } + } + if(skipCache || !cache[name]) { + if(!modules[name]) { + // if we cannot find the the module within our internal map or + // cache jump to the current global require ie. the last bundle + // that was added to the page. + var currentRequire = typeof require == "function" && require; + if (!jumped && currentRequire) return currentRequire(name, true); + + // If there are other bundles on this page the require from the + // previous one is saved to 'previousRequire'. Repeat this as + // many times as there are bundles until the module is found or + // we exhaust the require chain. + if (previousRequire) return previousRequire(name, true); + throw new Error('Cannot find module \'' + name + '\''); + } + + m = {exports:{}}; + var nextSkipCache = inSkipCache ? false : skipCache; + if (!skipCache) cache[name] = m; + skipCache = false; + modules[name][0].call(m.exports, function(x){ + var id = modules[name][1][x]; + return newRequire(id ? id : x, false, nextSkipCache); + },m,m.exports,outer,modules,cache,entry); + } + return m ? m.exports:cache[name].exports; + } + for(var i=0;in;n++)t*=256,t+=e[n];return t}function t(e){return i(e,1)}function n(e){return i(e,4)}var r=require("soop").imports(),s=r.base58||require("base58-native").base58,h=r.coinUtil||require("./util/util"),d=r.Key||require("./Key"),c=r.Point||require("./Point"),a=r.bignum||require("bignum"),o=(require("crypto"),require("./networks")),y=new a("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",16),l=(new a("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",16),function(i){if("mainnet"==i||"livenet"==i?this.version=o.livenet.bip32privateVersion:"testnet"==i&&(this.version=o.testnet.bip32privateVersion),"mainnet"==i||"livenet"==i||"testnet"==i)return this.depth=0,this.parentFingerprint=new e([0,0,0,0]),this.childIndex=new e([0,0,0,0]),this.chainCode=d.generateSync().private,this.eckey=d.generateSync(),this.hasPrivateKey=!0,this.pubKeyHash=h.sha256ripe160(this.eckey.public),this.buildExtendedPublicKey(),void this.buildExtendedPrivateKey();if("string"==typeof i){var t=s.decode(i);if(82!=t.length)throw new Error("Not enough data");var n=t.slice(78,82);i=t.slice(0,78);var r=h.sha256(h.sha256(i));if(r[0]!=n[0]||r[1]!=n[1]||r[2]!=n[2]||r[3]!=n[3])throw new Error("Invalid checksum")}void 0!==i&&this.initFromBytes(i)});l.seed=function(i,t){if(t||(t="livenet"),e.isBuffer(i)||(i=new e(i,"hex")),i.length<16)return!1;var n=h.sha512hmac(i,new e("Bitcoin seed")),r=new l;return r.depth=0,r.parentFingerprint=new e([0,0,0,0]),r.childIndex=new e([0,0,0,0]),r.chainCode=n.slice(32,64),r.version=o[t].bip32privateVersion,r.eckey=new d,r.eckey.private=n.slice(0,32),r.eckey.regenerateSync(),r.hasPrivateKey=!0,r.pubKeyHash=h.sha256ripe160(r.eckey.public),r.buildExtendedPublicKey(),r.buildExtendedPrivateKey(),r},l.prototype.initFromBytes=function(e){if(78!=e.length)throw new Error("not enough data");this.version=n(e.slice(0,4)),this.depth=t(e.slice(4,5)),this.parentFingerprint=e.slice(5,9),this.childIndex=n(e.slice(9,13)),this.chainCode=e.slice(13,45);var i=e.slice(45,78),r=this.version==o.livenet.bip32privateVersion||this.version==o.testnet.bip32privateVersion,s=this.version==o.livenet.bip32publicVersion||this.version==o.testnet.bip32publicVersion;if(r&&0==i[0])this.eckey=new d,this.eckey.private=i.slice(1,33),this.eckey.compressed=!0,this.eckey.regenerateSync(),this.pubKeyHash=h.sha256ripe160(this.eckey.public),this.hasPrivateKey=!0;else{if(!s||2!=i[0]&&3!=i[0])throw new Error("Invalid key");this.eckey=new d,this.eckey.public=i,this.pubKeyHash=h.sha256ripe160(this.eckey.public),this.hasPrivateKey=!1}this.buildExtendedPublicKey(),this.buildExtendedPrivateKey()},l.prototype.buildExtendedPublicKey=function(){this.extendedPublicKey=new e([]);var i=null;switch(this.version){case o.livenet.bip32publicVersion:case o.livenet.bip32privateVersion:i=o.livenet.bip32publicVersion;break;case o.testnet.bip32publicVersion:case o.testnet.bip32privateVersion:i=o.testnet.bip32publicVersion;break;default:throw new Error("Unknown version")}this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([i>>24])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([i>>16&255])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([i>>8&255])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([255&i])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([this.depth])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,this.parentFingerprint]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([this.childIndex>>>24])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([this.childIndex>>>16&255])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([this.childIndex>>>8&255])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,new e([255&this.childIndex])]),this.extendedPublicKey=e.concat([this.extendedPublicKey,this.chainCode]),this.extendedPublicKey=e.concat([this.extendedPublicKey,this.eckey.public])},l.prototype.extendedPublicKeyString=function(i){if(void 0===i||"base58"===i){var t=h.sha256(h.sha256(this.extendedPublicKey)),n=t.slice(0,4),r=e.concat([this.extendedPublicKey,n]);return s.encode(r)}if("hex"===i)return this.extendedPublicKey.toString("hex");throw new Error("bad format")},l.prototype.buildExtendedPrivateKey=function(){if(this.hasPrivateKey){this.extendedPrivateKey=new e([]);var i=this.version;this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([i>>24])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([i>>16&255])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([i>>8&255])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([255&i])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([this.depth])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,this.parentFingerprint]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([this.childIndex>>>24])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([this.childIndex>>>16&255])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([this.childIndex>>>8&255])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([255&this.childIndex])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,this.chainCode]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,new e([0])]),this.extendedPrivateKey=e.concat([this.extendedPrivateKey,this.eckey.private])}},l.prototype.extendedPrivateKeyString=function(i){if(void 0===i||"base58"===i){var t=h.sha256(h.sha256(this.extendedPrivateKey)),n=t.slice(0,4),r=e.concat([this.extendedPrivateKey,n]);return s.encode(r)}if("hex"===i)return this.extendedPrivateKey.toString("hex");throw new Error("bad format")},l.prototype.derive=function(e){var i=e.split("/");if("m"==e||"M"==e||"m'"==e||"M'"==e)return this;var t=this;for(var n in i){var r=i[n];if(0!=n){var s=r.length>1&&"'"==r[r.length-1],h=2147483647&parseInt(s?r.slice(0,r.length-1):r);s&&(h+=2147483648),t=t.deriveChild(h)}else if("m"!=r)throw new Error("invalid path")}return t},l.prototype.deriveChild=function(i){var t=[];t.push(i>>24&255),t.push(i>>16&255),t.push(i>>8&255),t.push(255&i),t=new e(t);var n=0!=(2147483648&i),r=this.version==o.livenet.bip32privateVersion||this.version==o.testnet.bip32privateVersion;if(n&&(!this.hasPrivateKey||!r))throw new Error("Cannot do private key derivation without private key");var s=null;if(this.hasPrivateKey){var u=null;u=e.concat(n?[new e([0]),this.eckey.private,t]:[this.eckey.public,t]);var v=h.sha512hmac(u,this.chainCode),p=a.fromBuffer(v.slice(0,32),{size:32}),b=v.slice(32,64),K=a.fromBuffer(this.eckey.private,{size:32}),x=p.add(K).mod(y);s=new l,s.chainCode=b,s.eckey=new d,s.eckey.private=x.toBuffer({size:32}),s.eckey.regenerateSync(),s.hasPrivateKey=!0}else{var u=e.concat([this.eckey.public,t]),v=h.sha512hmac(u,this.chainCode),p=a.fromBuffer(v.slice(0,32),{size:32}),b=v.slice(32,64),P=new d;P.private=p.toBuffer({size:32}),P.regenerateSync();var w=c.fromKey(P),f=new d;f.public=this.eckey.public;var F=c.fromKey(f),k=c.add(w,F).toKey().public;s=new l,s.chainCode=new e(b);var g=new d;g.public=k,s.eckey=g,s.hasPrivateKey=!1}return s.childIndex=i,s.parentFingerprint=this.pubKeyHash.slice(0,4),s.version=this.version,s.depth=this.depth+1,s.eckey.compressed=!0,s.pubKeyHash=h.sha256ripe160(s.eckey.public),s.buildExtendedPublicKey(),s.buildExtendedPrivateKey(),s},module.exports=require("soop")(l)}).call(this,require("buffer").Buffer); +},{"./Key":"Af1Gom","./Point":"8PQ/SZ","./networks":"ULNIu2","./util/util":"ACyo5H","base58-native":"xtP2pj","bignum":"J4nwo8","buffer":75,"crypto":79,"soop":146}],"KqTx5b":[function(require,module,exports){ +(function(t){function e(t){"object"!=typeof t&&(t={}),this.hash=t.hash||null,this.prev_hash=t.prev_hash||i.NULL_HASH,this.merkle_root=t.merkle_root||i.NULL_HASH,this.timestamp=t.timestamp||0,this.bits=t.bits||0,this.nonce=t.nonce||0,this.version=t.version||0,this.height=t.height||0,this.size=t.size||0,this.active=t.active||!1,this.chainWork=t.chainWork||i.EMPTY_BUFFER,this.txs=t.txs||[]}var r=require("soop").imports(),i=r.util||require("./util/util"),o=(r.Debug1||function(){},r.Script||require("./Script")),s=r.Bignum||require("bignum"),h=(r.Binary||require("binary"),r.Step||require("step"),r.buffertools||require("buffertools")),n=r.Transaction||require("./Transaction"),a=n.In,c=n.Out,u=n.COINBASE_OP,l=r.VerificationError||require("./util/error").VerificationError,f={maxTimeOffset:7200,largestHash:s(2).pow(256)};e.prototype.getHeader=function(){var e=new t(80),r=0;return e.writeUInt32LE(this.version,r),r+=4,this.prev_hash.copy(e,r),r+=32,this.merkle_root.copy(e,r),r+=32,e.writeUInt32LE(this.timestamp,r),r+=4,e.writeUInt32LE(this.bits,r),r+=4,e.writeUInt32LE(this.nonce,r),r+=4,e},e.prototype.parse=function(t,e){if(this.version=t.word32le(),this.prev_hash=t.buffer(32),this.merkle_root=t.buffer(32),this.timestamp=t.word32le(),this.bits=t.word32le(),this.nonce=t.word32le(),this.txs=[],this.size=0,!e)for(var r=t.varInt(),i=0;r>i;i++){var o=new n;o.parse(t),this.txs.push(o)}},e.prototype.calcHash=function(){var t=this.getHeader();return i.twoSha256(t)},e.prototype.checkHash=function(){return this.hash&&this.hash.length?0==h.compare(this.calcHash(),this.hash):!1},e.prototype.getHash=function(){return this.hash&&this.hash.length||(this.hash=this.calcHash()),this.hash},e.prototype.checkProofOfWork=function(){var t=i.decodeDiffBits(this.bits),e=h.reverse(this.hash);if(h.compare(e,t)>0)throw new l("Difficulty target not met");return!0},e.prototype.getWork=function(){var t=i.decodeDiffBits(this.bits,!0);return f.largestHash.div(t.add(1))},e.prototype.checkTimestamp=function(){var t=(new Date).getTime()/1e3;if(this.timestamp>t+f.maxTimeOffset)throw new l("Timestamp too far into the future");return!0},e.prototype.checkTransactions=function(t){if(!Array.isArray(t)||t.length<=0)throw new l("No transactions");if(!t[0].isCoinBase())throw new l("First tx must be coinbase");for(var e=1;e1;s=Math.floor((s+1)/2)){for(var h=0;s>h;h+=2){var a=Math.min(h+1,s-1),c=r[o+h],u=r[o+a];r.push(i.twoSha256(t.concat([c,u])))}o+=s}return r},e.prototype.calcMerkleRoot=function(t){var e=this.getMerkleTree(t);return e[e.length-1]},e.prototype.checkMerkleRoot=function(e){if(!this.merkle_root||!this.merkle_root.length)throw new l("No merkle root");if(0!==h.compare(this.calcMerkleRoot(e),new t(this.merkle_root)))throw new l("Merkle root incorrect");return!0},e.prototype.checkBlock=function(t){if(!this.checkHash())throw new l("Block hash invalid");if(this.checkProofOfWork(),this.checkTimestamp(),t&&(this.checkTransactions(t),!this.checkMerkleRoot(t)))throw new l("Merkle hash invalid");return!0},e.getBlockValue=function(t){var e=s(50).mul(i.COIN);return e=e.div(s(2).pow(Math.floor(t/21e4)))},e.prototype.getBlockValue=function(){return e.getBlockValue(this.height)},e.prototype.toString=function(){return""},e.prototype.createCoinbaseTx=function(t){var e=new n;return e.ins.push(new a({s:i.EMPTY_BUFFER,q:4294967295,o:u})),e.outs.push(new c({v:i.bigIntToValue(this.getBlockValue()),s:o.createPubKeyOut(t).getBuffer()})),e},e.prototype.solve=function(t,e){var r=this.getHeader(),o=i.decodeDiffBits(this.bits);t.solve(r,o,e)},e.prototype.getStandardizedObject=function(t){var e={hash:i.formatHashFull(this.getHash()),version:this.version,prev_block:i.formatHashFull(this.prev_hash),mrkl_root:i.formatHashFull(this.merkle_root),time:this.timestamp,bits:this.bits,nonce:this.nonce,height:this.height};if(t){var r=this.getMerkleTree(t).map(function(t){return i.formatHashFull(t)});e.mrkl_root=r[r.length-1],e.n_tx=t.length;var o=80;o+=i.getVarIntSize(t.length),t=t.map(function(t){return t=t.getStandardizedObject(),o+=t.size,t}),e.size=o,e.tx=t,e.mrkl_tree=r}else e.size=this.size;return e},module.exports=require("soop")(e)}).call(this,require("buffer").Buffer); +},{"./Script":"clx6XL","./Transaction":"RNv6Te","./util/error":155,"./util/util":"ACyo5H","bignum":"J4nwo8","binary":62,"buffer":75,"buffertools":"fugeBw","soop":146,"step":147}],"./Block":[function(require,module,exports){ +module.exports=require('KqTx5b'); +},{}],"ZnXdbH":[function(require,module,exports){ +function Bloom(){this.data="",this.hashFuncs=0}function ROTL32(t,n){return t<>32-n}function getBlockU32(t,n){var o=4*t,s=n[o+0]<<0|n[o+1]<<8|n[o+2]<<16|n[o+3]<<24;return s}function toInt(t){return~~t}function min(t,n){return n>t?t:n}var MAX_BLOOM_FILTER_SIZE=36e3,MAX_HASH_FUNCS=50,LN2SQUARED=.48045301391820144,LN2=.6931471805599453,bit_mask=[1,2,4,8,16,32,64,128];Bloom.prototype.hash=function(t,n){for(var o=t*(4294967295/(this.hashFuncs-1)),s=3432918353,a=461845907,h=n.length/4,i=-h;i;i++){var r=getBlockU32(i);r*=s,r=ROTLF32(r,15),r*=a,o^=r,o=ROTFL(o,13),o=5*o+3864292196}var e=n.slice(4*h),r=0;switch(3&n.length){case 3:r^=e[2]<<16;case 2:r^=e[1]<<8;case 1:r^=e[0],r*=s,r=ROTL32(r,15),r*=a,o^=r}return o^=n.length,o^=o>>16,o*=2246822507,o^=o>>13,o*=3266489909,o^=o>>16,o%(8*this.data.length)},Bloom.prototype.insert=function(t){for(var n=0;n>3]|=bit_mask[7&o]}},Bloom.prototype.contains=function(t){for(var n=0;n>3]&bit_mask[7&o]))return!1}return!0},Bloom.prototype.sizeOk=function(){return this.data.length<=MAX_BLOOM_FILTER_SIZE&&this.hashFuncs<=MAX_HASH_FUNCS},Bloom.prototype.init=function(t,n){var o=min(toInt(-1/LN2SQUARED*t*Math.log(n)),8*MAX_BLOOM_FILTER_SIZE)/8;this.data[o]=0,this.hashFuncs=min(toInt(8*this.data.length/t*LN2),MAX_HASH_FUNCS)},module.exports=require("soop")(Bloom); +},{"soop":146}],"./Bloom":[function(require,module,exports){ +module.exports=require('ZnXdbH'); +},{}],"./Buffers.monkey":[function(require,module,exports){ +module.exports=require('jmkPxi'); +},{}],"jmkPxi":[function(require,module,exports){ +(function(f){exports.patch=function(t){t.prototype.skip=function(t){if(0!=t){if(t==this.length)return this.buffers=[],void(this.length=0);var s=this.pos(t);this.buffers=this.buffers.slice(s.buf),this.buffers[0]=new f(this.buffers[0].slice(s.offset)),this.length-=t}}}}).call(this,require("buffer").Buffer); +},{"buffer":75}],"./Connection":[function(require,module,exports){ +module.exports=require('h81grl'); +},{}],"h81grl":[function(require,module,exports){ +(function(e){function t(e,r){t.super(this,arguments),this.socket=e,this.peer=r,this.active=!1,this.recvVer=0,this.sendVer=0,this.bestHeight=0,this.inbound=!!e.server,this.getaddr=!1,this.buffers=new c,(new Date).getTime()>1329696e6&&(this.recvVer=209,this.sendVer=209),this.setupHandlers()}var r=require("soop").imports(),s=r.config||require("./config"),n=r.log||require("./util/log"),i=r.network||require("./networks")[s.network],o=1e7,a=7e4,h=(r.Binary||require("binary"),r.Put||require("bufferput")),c=r.Buffers||require("buffers");require("./Buffers.monkey").patch(c);var d=require("./Block"),f=require("./Transaction"),u=r.util||require("./util/util"),p=r.Parser||require("./util/BinaryParser"),g=r.buffertools||require("buffertools"),l=r.doubleSha256||u.twoSha256,v=u.generateNonce(),b=6e4;t.parent=r.parent||require("events").EventEmitter,t.prototype.setupHandlers=function(){this.socket.addListener("connect",this.handleConnect.bind(this)),this.socket.addListener("error",this.handleError.bind(this)),this.socket.addListener("end",this.handleDisconnect.bind(this)),this.socket.addListener("data",function(e){var t=35;n.debug("["+this.peer+"] Recieved "+e.length+" bytes of data:"),n.debug("... "+g.toHex(e.slice(0,t>e.length?e.length:t))+(e.length>t?"...":""))}.bind(this)),this.socket.addListener("data",this.handleData.bind(this))},t.prototype.handleConnect=function(){this.inbound||this.sendVersion(),this.emit("connect",{conn:this,socket:this.socket,peer:this.peer})},t.prototype.handleError=function(e){110==e.errno||"ETIMEDOUT"==e.errno?n.info("connection timed out for "+this.peer):111==e.errno||"ECONNREFUSED"==e.errno?n.info("connection refused for "+this.peer):n.warn("connection with "+this.peer+" "+e.toString()),this.emit("error",{conn:this,socket:this.socket,peer:this.peer,err:e})},t.prototype.handleDisconnect=function(){this.emit("disconnect",{conn:this,socket:this.socket,peer:this.peer})},t.prototype.handleMessage=function(t){if(t){try{switch(t.command){case"version":if(0===g.compare(v,t.nonce))return void this.socket.end();this.inbound&&this.sendVersion(),t.version>=209&&this.sendMessage("verack",new e([])),this.sendVer=Math.min(t.version,a),t.version<209?this.recvVer=Math.min(t.version,a):this.once("verack",function(){this.recvVer=t.version}.bind(this)),this.bestHeight=t.start_height;break;case"verack":this.recvVer=Math.min(t.version,a),this.active=!0;break;case"ping":"object"==typeof t.nonce&&this.sendPong(t.nonce)}}catch(r){return void n.err('Error while handling "'+t.command+'" message from '+this.peer+":\n"+(r.stack?r.stack:r.toString()))}this.emit(t.command,{conn:this,socket:this.socket,peer:this.peer,message:t})}},t.prototype.sendPong=function(e){this.sendMessage("pong",e)},t.prototype.sendVersion=function(){var t="/BitcoinX:0.1/",r=new h;r.word32le(a),r.word64le(1),r.word64le(Math.round((new Date).getTime()/1e3)),r.pad(26),r.pad(26),r.put(v),r.varint(t.length),r.put(new e(t,"ascii")),r.word32le(0),this.sendMessage("version",r.buffer())},t.prototype.sendGetBlocks=function(t,r,s){r=r||u.NULL_HASH;var n=new h;n.word32le(this.sendVer),n.varint(t.length);for(var i=0;i12)throw"Command name too long";var a;a=this.sendVer>=209?l(r).slice(0,4):new e([]);var c=new h;c.put(s),c.put(o),c.pad(12-o.length),c.word32le(r.length),c.put(a),c.put(r);var d=c.buffer();n.debug("["+this.peer+"] Sending message "+t+" ("+r.length+" bytes)"),this.socket.write(d)}catch(f){n.err("Error while sending message to peer "+this.peer+": "+(f.stack?f.stack:f.toString()))}},t.prototype.handleData=function(e){return this.buffers.push(e),this.buffers.length>o?(n.err("Peer "+this.peer+" exceeded maxreceivebuffer, disconnecting."+(err.stack?err.stack:err.toString())),void this.socket.destroy()):void this.processData()},t.prototype.processData=function(){if(!(this.buffers.length<20)){for(var e=i.magic,t=0;;){if(this.buffers.get(t)===e[0]&&this.buffers.get(t+1)===e[1]&&this.buffers.get(t+2)===e[2]&&this.buffers.get(t+3)===e[3]){0!==t&&(n.debug("["+this.peer+"] Received "+t+" bytes of inter-message garbage: "),n.debug("... "+this.buffers.slice(0,t)),this.buffers.skip(t));break}if(t>this.buffers.length-4)return void this.buffers.skip(t);t++}var r=this.buffers.get(16)+(this.buffers.get(17)<<8)+(this.buffers.get(18)<<16)+(this.buffers.get(19)<<24),s=this.recvVer>=209?24:20,o=s+r;if(!(this.buffers.length=209?this.buffers.slice(20,24):null;if(n.debug("["+this.peer+"] Received message "+a+" ("+r+" bytes)"),null!==c){var d=l(h).slice(0,4);if(0!==g.compare(d,c))return void n.err("["+this.peer+"] Checksum failed",{cmd:a,expected:d.toString("hex"),actual:c.toString("hex")})}var f;try{f=this.parseMessage(a,h)}catch(u){n.err("Error while parsing message "+a+" from "+this.peer+":\n"+(u.stack?u.stack:u.toString()))}f&&this.handleMessage(f),this.buffers.skip(o),this.processData()}}},t.prototype.parseMessage=function(e,t){var r,s=new p(t),i={command:e};switch(e){case"version":i.version=s.word32le(),i.services=s.word64le(),i.timestamp=s.word64le(),i.addr_me=s.buffer(26),i.addr_you=s.buffer(26),i.nonce=s.buffer(8),i.subversion=s.varStr(),i.start_height=s.word32le();break;case"inv":case"getdata":for(i.count=s.varInt(),i.invs=[],r=0;rr;r++)i.starts.push(s.buffer(32));i.stop=s.buffer(32);break;case"addr":var u=s.varInt();for(u>1e3&&(u=1e3),i.addrs=[],r=0;u>r;r++)i.addrs.push({time:s.word32le(),services:s.word64le(),ip:s.buffer(16),port:s.word16be()});break;case"alert":i.payload=s.varStr(),i.signature=s.varStr();break;case"ping":this.recvVer>b&&(i.nonce=s.buffer(8));break;case"getaddr":case"verack":case"reject":break;default:return n.err("Connection.parseMessage(): Command not implemented",{cmd:e}),null}return i},module.exports=require("soop")(t)}).call(this,require("buffer").Buffer); +},{"./Block":"KqTx5b","./Buffers.monkey":"jmkPxi","./Transaction":"RNv6Te","./config":"4itQ50","./networks":"ULNIu2","./util/BinaryParser":"b3ZSD7","./util/log":"AdF7pF","./util/util":"ACyo5H","binary":62,"buffer":75,"bufferput":"aXRuS6","buffers":"OBo3aV","buffertools":"fugeBw","events":84,"soop":146}],"ypnq12":[function(require,module,exports){ +exports.intFromCompact=function(r){var t=(r>>>24&255)>>>0,n=(16777215&r)<<8*(t-3)>>>0;return n}; +},{}],"./Deserialize":[function(require,module,exports){ +module.exports=require('ypnq12'); +},{}],"./Gruntfile":[function(require,module,exports){ +module.exports=require('NbSoFu'); +},{}],"NbSoFu":[function(require,module,exports){ +"use strict";module.exports=function(s){s.loadNpmTasks("grunt-contrib-watch"),s.loadNpmTasks("grunt-mocha-test"),s.loadNpmTasks("grunt-markdown"),s.loadNpmTasks("grunt-shell"),s.initConfig({shell:{browserify:{options:{stdout:!0,stderr:!0},command:"dev"===s.option("target")?"node ./browser/build.js -a -d ":"node ./browser/build.js -a"}},watch:{readme:{files:["README.md"],tasks:["markdown"]},scripts:{files:["**/*.js","**/*.html","!**/node_modules/**","!browser/bundle.js","!browser/testdata.js","!browser/vendor-bundle.js"],tasks:["shell"]}},mochaTest:{options:{reporter:"spec"},src:["test/*.js"]},markdown:{all:{files:[{expand:!0,src:"README.md",dest:".",ext:".html"}]}}}),s.registerTask("default",["shell","watch"])}; +},{}],"./Key":[function(require,module,exports){ +module.exports=require('Af1Gom'); +},{}],"Af1Gom":[function(require,module,exports){ +(function(e,r){if(e.versions){var t=require("bindings")("KeyModule"),s=t.Key;module.exports=s}else{var o=require("./browser/vendor-bundle.js").ECKey,n=require("buffertools"),i=function(){this._pub=null,this.compressed=!0},u=i.bufferToArray=function(e){for(var r=[],t=e.length,s=0;t>s;s++)r.push(e.readUInt8(s));return r};Object.defineProperty(i.prototype,"public",{set:function(e){if(!r.isBuffer(e))throw new Error("Arg should be a buffer");var t=e[0];this.compressed=4!==t,this._pub=e},get:function(){return this._pub}}),i.generateSync=function(){var e=new o;e.setCompressed(!0);var t=e.getPub(),s=new i;return s.private=new r(e.priv.toByteArrayUnsigned()),s.public=new r(t),s},i.prototype.regenerateSync=function(){if(!this.private)throw new Error("Key does not have a private key set");var e=new o(n.toHex(this.private));return e.setCompressed(this.compressed),this.public=new r(e.getPub()),this},i.prototype.signSync=function(e){if(!this.private)throw new Error("Key does not have a private key set");if(!r.isBuffer(e)||32!==e.length)throw new Error("Arg should be a 32 bytes hash buffer");var t=new o(n.toHex(this.private));t.setCompressed(this.compressed);var s=t.sign(u(e));return new r(s)},i.prototype.verifySignature=function(e,r,t){try{var s=this.verifySignatureSync(e,r);t(null,s)}catch(o){t(o)}},i.prototype.verifySignatureSync=function(e,t){var s=this;if(!r.isBuffer(e)||32!==e.length)throw new Error("Arg 1 should be a 32 bytes hash buffer");if(!r.isBuffer(t))throw new Error("Arg 2 should be a buffer");if(!s.public)throw new Error("Key does not have a public key set");var n=new o;n.setPub(u(s.public)),n.setCompressed(s.compressed);var i=u(t),f=n.verify(u(e),i);return f},module.exports=i}}).call(this,require("/Users/ryanxcharles/dev/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"),require("buffer").Buffer); +},{"./browser/vendor-bundle.js":53,"/Users/ryanxcharles/dev/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":91,"bindings":66,"buffer":75,"buffertools":"fugeBw"}],"ahN55r":[function(require,module,exports){ +exports.patch=function(t){t.prototype.round=function(t){if(!t)return Math.round(this);var r=Math.pow(10,t);return Math.round(this*r)/r}}; +},{}],"./Number.monkey":[function(require,module,exports){ +module.exports=require('ahN55r'); +},{}],"./Opcode":[function(require,module,exports){ +module.exports=require('zHwnes'); +},{}],"zHwnes":[function(require,module,exports){ +function Opcode(O){this.code=O}var imports=require("soop").imports();Opcode.prototype.toString=function(){return Opcode.reverseMap[this.code]},Opcode.map={OP_FALSE:0,OP_0:0,OP_PUSHDATA1:76,OP_PUSHDATA2:77,OP_PUSHDATA4:78,OP_1NEGATE:79,OP_RESERVED:80,OP_TRUE:81,OP_1:81,OP_2:82,OP_3:83,OP_4:84,OP_5:85,OP_6:86,OP_7:87,OP_8:88,OP_9:89,OP_10:90,OP_11:91,OP_12:92,OP_13:93,OP_14:94,OP_15:95,OP_16:96,OP_NOP:97,OP_VER:98,OP_IF:99,OP_NOTIF:100,OP_VERIF:101,OP_VERNOTIF:102,OP_ELSE:103,OP_ENDIF:104,OP_VERIFY:105,OP_RETURN:106,OP_TOALTSTACK:107,OP_FROMALTSTACK:108,OP_2DROP:109,OP_2DUP:110,OP_3DUP:111,OP_2OVER:112,OP_2ROT:113,OP_2SWAP:114,OP_IFDUP:115,OP_DEPTH:116,OP_DROP:117,OP_DUP:118,OP_NIP:119,OP_OVER:120,OP_PICK:121,OP_ROLL:122,OP_ROT:123,OP_SWAP:124,OP_TUCK:125,OP_CAT:126,OP_SUBSTR:127,OP_LEFT:128,OP_RIGHT:129,OP_SIZE:130,OP_INVERT:131,OP_AND:132,OP_OR:133,OP_XOR:134,OP_EQUAL:135,OP_EQUALVERIFY:136,OP_RESERVED1:137,OP_RESERVED2:138,OP_1ADD:139,OP_1SUB:140,OP_2MUL:141,OP_2DIV:142,OP_NEGATE:143,OP_ABS:144,OP_NOT:145,OP_0NOTEQUAL:146,OP_ADD:147,OP_SUB:148,OP_MUL:149,OP_DIV:150,OP_MOD:151,OP_LSHIFT:152,OP_RSHIFT:153,OP_BOOLAND:154,OP_BOOLOR:155,OP_NUMEQUAL:156,OP_NUMEQUALVERIFY:157,OP_NUMNOTEQUAL:158,OP_LESSTHAN:159,OP_GREATERTHAN:160,OP_LESSTHANOREQUAL:161,OP_GREATERTHANOREQUAL:162,OP_MIN:163,OP_MAX:164,OP_WITHIN:165,OP_RIPEMD160:166,OP_SHA1:167,OP_SHA256:168,OP_HASH160:169,OP_HASH256:170,OP_CODESEPARATOR:171,OP_CHECKSIG:172,OP_CHECKSIGVERIFY:173,OP_CHECKMULTISIG:174,OP_CHECKMULTISIGVERIFY:175,OP_NOP1:176,OP_NOP2:177,OP_NOP3:178,OP_NOP4:179,OP_NOP5:180,OP_NOP6:181,OP_NOP7:182,OP_NOP8:183,OP_NOP9:184,OP_NOP10:185,OP_PUBKEYHASH:253,OP_PUBKEY:254,OP_INVALIDOPCODE:255},Opcode.reverseMap=[];for(var k in Opcode.map)Opcode.map.hasOwnProperty(k)&&(Opcode.reverseMap[Opcode.map[k]]=k.substr(3));Opcode.asList=function(){var O=[];for(var P in Opcode.map)Opcode.map.hasOwnProperty(P)&&O.push(P);return O},module.exports=require("soop")(Opcode); +},{"soop":146}],"6VMrjH":[function(require,module,exports){ +(function(t){function e(r,o,i){if("string"==typeof r){if(r.indexOf(":")&&!o){var n=r.split(":");r=n[0],o=n[1]}this.host=r,this.port=+o||8333}else if(r instanceof e)this.host=r.host,this.port=r.port;else{if(!t.isBuffer(r))throw new Error("Could not instantiate peer, invalid parameter type: "+typeof r);if(0!=s.compare(e.IPV6_IPV4_PADDING,r.slice(0,12)))throw new Error("IPV6 not supported yet! Cannot instantiate host.");this.host=Array.prototype.slice.apply(r.slice(12)).join("."),this.port=+o||8333}this.services=i?i:null,this.lastSeen=0}var r=require("soop").imports(),o=r.Net||require("net"),i=r.Binary||require("binary"),s=r.buffertools||require("buffertools");e.IPV6_IPV4_PADDING=new t([0,0,0,0,0,0,0,0,0,0,255,255]),e.prototype.createConnection=function(){var t=o.createConnection(this.port,this.host);return t},e.prototype.getHostAsBuffer=function(){return new t(this.host.split("."))},e.prototype.toString=function(){return this.host+":"+this.port},e.prototype.toBuffer=function(){var t=i.put();return t.word32le(this.lastSeen),t.word64le(this.services),t.put(this.getHostAsBuffer()),t.word16be(this.port),t.buffer()},module.exports=require("soop")(e)}).call(this,require("buffer").Buffer); +},{"binary":62,"buffer":75,"buffertools":"fugeBw","net":71,"soop":146}],"./Peer":[function(require,module,exports){ +module.exports=require('6VMrjH'); +},{}],"./PeerManager":[function(require,module,exports){ +module.exports=require('z6R5yC'); +},{}],"z6R5yC":[function(require,module,exports){ +function PeerManager(){this.active=!1,this.timer=null,this.peers=[],this.connections=[],this.isConnected=!1,this.peerDiscovery=!1,this.interval=5e3,this.minConnections=8,this.minKnownPeers=10}var imports=require("soop").imports(),config=imports.config||require("./config"),log=imports.log||require("./util/log"),network=imports.network||require("./networks")[config.network],Connection=imports.Connection||require("soop").load("./Connection",{config:config,network:network})||require("./Connection"),Peer=imports.Peer||require("./Peer");GetAdjustedTime=imports.GetAdjustedTime||function(){return Math.floor((new Date).getTime()/1e3)},PeerManager.parent=imports.parent||require("events").EventEmitter,PeerManager.Connection=Connection,PeerManager.prototype.start=function(){this.active=!0,this.timer||(this.timer=setInterval(this.checkStatus.bind(this),this.interval))},PeerManager.prototype.stop=function(){this.active=!1,this.timer&&(clearInterval(this.timer),this.timer=null);for(var e=0;e=31402||this.peers.length<1e3)&&(e.conn.sendGetAddr(),e.conn.getaddr=!0)},PeerManager.prototype.handleReady=function(e){log.info("connected to "+e.conn.peer.host+":"+e.conn.peer.port),this.emit("connect",{pm:this,conn:e.conn,socket:e.socket,peer:e.peer}),0==this.isConnected&&(this.emit("netConnected",e),this.isConnected=!0)},PeerManager.prototype.handleAddr=function(e){if(this.peerDiscovery){var n=GetAdjustedTime();e.message.addrs.forEach(function(e){try{(e.time<=1e8||e.time>n+600)&&(e.time=n-432e3);var t=new Peer(e.ip,e.port,e.services);t.lastSeen=e.time,this.peers.push(t)}catch(r){log.warn("Invalid addr received: "+r.message)}}.bind(this)),e.message.addrs.length<1e3&&(e.conn.getaddr=!1)}},PeerManager.prototype.handleGetAddr=function(){},PeerManager.prototype.handleError=function(e){log.err("unkown error with peer "+e.peer+" (disconnecting): "+e.err),this.handleDisconnect.apply(this,[].slice.call(arguments))},PeerManager.prototype.handleDisconnect=function(e){log.info("disconnected from peer "+e.peer);var n=this.connections.indexOf(e.conn);-1!=n&&this.connections.splice(n,1),this.connections.length||(this.emit("netDisconnected"),this.isConnected=!1)},PeerManager.prototype.getActiveConnection=function(){var e=this.connections.filter(function(e){return e.active});if(e.length){var n=Math.floor(Math.random()*e.length),t=e[n];return t.socket.writable?t:(e.splice(n,1),this.getActiveConnection())}return null},PeerManager.prototype.getActiveConnections=function(){return this.connections.slice(0)},module.exports=require("soop")(PeerManager); +},{"./Connection":"h81grl","./Peer":"6VMrjH","./config":"4itQ50","./networks":"ULNIu2","./util/log":"AdF7pF","events":84,"soop":146}],"./Point":[function(require,module,exports){ +module.exports=require('8PQ/SZ'); +},{}],"8PQ/SZ":[function(require,module,exports){ +(function(e,r){"use strict";var s=require("soop").imports(),o=s.Key||require("./Key"),n=s.bignum||require("bignum"),t=require("assert");if(!e.versions){var i=require("./browser/vendor-bundle.js").ECKey,u=require("./browser/vendor-bundle.js").ECPointFp,f=require("./browser/vendor-bundle.js").ECFieldElementFp,d=require("./browser/vendor-bundle.js").getSECCurveByName,c=require("./browser/vendor-bundle.js").BigInteger;require("chai").should()}var l=function(e,r){this.x=e,this.y=r};l.add=function(s,i){if(e.versions){var g=s.toKey();g.compressed=!1;var p=i.toKey();p.compressed=!1;var w=o.addUncompressed(g.public,p.public),b=new o;return b.compressed=!1,b.public=w,b.compressed=!0,l.fromKey(b)}var m=d("secp256k1"),v=s.x.toBuffer({size:32}).toString("hex"),a=new c(v,16),y=s.y.toBuffer({size:32}).toString("hex"),B=new c(y,16),h=new f(m.getCurve().getQ(),a),C=new f(m.getCurve().getQ(),B),x=new u(m.getCurve(),h,C),z=i.x.toBuffer({size:32}).toString("hex"),q=new c(z,16),K=i.y.toBuffer({size:32}).toString("hex"),j=new c(K,16),P=new f(m.getCurve().getQ(),q),E=new f(m.getCurve().getQ(),j),S=new u(m.getCurve(),P,E),A=x.add(S),Q=new l,U=new r(A.getX().toBigInteger().toByteArrayUnsigned());Q.x=n.fromBuffer(U,{size:U.length}),t(U.length<=32);var F=new r(A.getY().toBigInteger().toByteArrayUnsigned());return t(F.length<=32),Q.y=n.fromBuffer(F,{size:F.length}),Q},l.fromKey=function(s){if(e.versions){var t=new l,u=new r(s.public),f=new o;return f.compressed=s.compressed,f.public=u,f.compressed=!1,t.x=n.fromBuffer(f.public.slice(1,33),{size:32}),t.y=n.fromBuffer(f.public.slice(33,65),{size:32}),t}var t=new l,u=new r(s.public),f=new i;return f.setCompressed(s.compressed),f.setPub(o.bufferToArray(u)),f.setCompressed(!1),t.x=n.fromBuffer(new r(f.getPub()).slice(1,33),{size:32}),t.y=n.fromBuffer(new r(f.getPub()).slice(33,65),{size:32}),t},l.prototype.toKey=function(){if(e.versions){var s=this.x.toBuffer({size:32}),n=this.y.toBuffer({size:32}),t=new o;t.compressed=!1;var u=new r([4]);return t.public=r.concat([u,s,n]),t.compressed=!0,t}var s=this.x.toBuffer({size:32}),n=this.y.toBuffer({size:32}),t=new i;t.setCompressed(!1);var u=new r([4]),f=r.concat([u,s,n]);t.setPub(o.bufferToArray(f)),t.setCompressed(!0);var d=new o;return d.public=new r(t.getPub()),d},module.exports=require("soop")(l)}).call(this,require("/Users/ryanxcharles/dev/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"),require("buffer").Buffer); +},{"./Key":"Af1Gom","./browser/vendor-bundle.js":53,"/Users/ryanxcharles/dev/bitcore/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":91,"assert":72,"bignum":"J4nwo8","buffer":75,"chai":112,"soop":146}],"./PrivateKey":[function(require,module,exports){ +module.exports=require('+A60Qr'); +},{}],"+A60Qr":[function(require,module,exports){ +(function(t){function e(t,i,r){e.super(this,arguments),void 0!==r&&this.compressed(r)}var i=require("soop").imports(),r=i.parent||require("./util/VersionedData"),n=i.networks||require("./networks");e.parent=r,r.applyEncodingsTo(e),e.prototype.validate=function(){if(this.doAsBinary(function(){if(e.super(this,"validate",arguments),this.data.length<32||this.data.length>33&&!this.compressed()||34==this.data.length&&1!=this.data[33]||this.data.length>34)throw new Error("invalid data length")}),"undefined"==typeof this.network())throw new Error("invalid network")},e.prototype.payload=function(t){if(t)return this.doAsBinary(function(){t.copy(this.data,1)}),t;var e=this.as("binary");return 34==e.length?e.slice(1,33):33==e.length?e.slice(1):void 0},e.prototype.compressed=function(e){if(void 0===e){var i=34,r=this.as("binary");if(r.length==i&&1==r[i-1])return!0;if(r.length==i-1)return!1;throw new Error("invalid private key")}this.doAsBinary(function(){var i=34;if(e){var r=new t(i);this.data.copy(r),this.data=r,this.data[i-1]=1}else this.data=this.data.slice(0,i-1)})},e.prototype.network=function(){var t,e=this.version(),i=n.livenet,r=n.testnet;return e===i.privKeyVersion?t=i:e===r.privKeyVersion&&(t=r),t},module.exports=require("soop")(e)}).call(this,require("buffer").Buffer); +},{"./networks":"ULNIu2","./util/VersionedData":"QLzNQg","buffer":75,"soop":146}],"Svwrvc":[function(require,module,exports){ +(function(t){function e(t){t=t||{},this.host=t.host||"127.0.0.1",this.port=t.port||8332,this.user=t.user||"user",this.pass=t.pass||"pass",this.protocol="http"==t.protocol?n:i,this.batchedCalls=null,this.disableAgent=t.disableAgent||!1}function r(t,e,r){function s(t,e){return function(){var s=arguments.length-1;if(this.batchedCalls)var s=arguments.length;for(var o=0;s>o;o++)e[o]&&(arguments[o]=e[o](arguments[o]));this.batchedCalls?this.batchedCalls.push({jsonrpc:"2.0",method:t,params:c(arguments)}):r.call(this,{method:t,params:c(arguments,0,arguments.length-1)},arguments[arguments.length-1])}}var o={str:function(t){return t.toString()},"int":function(t){return parseFloat(t)},"float":function(t){return parseFloat(t)},bool:function(t){return t===!0||"1"==t||"true"==t||"true"==t.toString().toLowerCase()}};for(var n in e)if(e.hasOwnProperty(n)){for(var i=e[n].split(" "),a=0;a=OP_1&&OP_16>=t}function prefixSize(t){return OP_PUSHDATA1>t?1:255>=t?2:65535>=t?3:5}function encodeLen(t){var r=void 0;return OP_PUSHDATA1>t?(r=new Buffer(1),r.writeUInt8(t,0)):255>=t?(r=new Buffer(2),r.writeUInt8(OP_PUSHDATA1,0),r.writeUInt8(t,1)):65535>=t?(r=new Buffer(3),r.writeUInt8(OP_PUSHDATA2,0),r.writeUInt16LE(t,1)):(r=new Buffer(5),r.writeUInt8(OP_PUSHDATA4,0),r.writeUInt32LE(t,1)),r}var imports=require("soop").imports(),config=imports.config||require("./config"),log=imports.log||require("./util/log"),Opcode=imports.Opcode||require("./Opcode"),buffertools=imports.buffertools||require("buffertools");for(var i in Opcode.map)eval(i+" = "+Opcode.map[i]+";");var util=imports.util||require("./util/util"),Parser=imports.Parser||require("./util/BinaryParser"),Put=imports.Put||require("bufferput"),TX_UNKNOWN=0,TX_PUBKEY=1,TX_PUBKEYHASH=2,TX_MULTISIG=3,TX_SCRIPTHASH=4,TX_TYPES=["unknown","pubkey","pubkeyhash","multisig","scripthash"];Script.TX_UNKNOWN=TX_UNKNOWN,Script.TX_PUBKEY=TX_PUBKEY,Script.TX_PUBKEYHASH=TX_PUBKEYHASH,Script.TX_MULTISIG=TX_MULTISIG,Script.TX_SCRIPTHASH=TX_SCRIPTHASH,Script.prototype.parse=function(){this.chunks=[];for(var t=new Parser(this.buffer);!t.eof();){var r,e,i=t.word8();i>0&&OP_PUSHDATA1>i?this.chunks.push(t.buffer(i)):i===OP_PUSHDATA1?(r=t.word8(),e=t.buffer(r),this.chunks.push(e)):i===OP_PUSHDATA2?(r=t.word16le(),e=t.buffer(r),this.chunks.push(e)):i===OP_PUSHDATA4?(r=t.word32le(),e=t.buffer(r),this.chunks.push(e)):this.chunks.push(i)}},Script.prototype.isPushOnly=function(){for(var t=0;tOP_16)return!1}return!0},Script.prototype.isP2SH=function(){return 3==this.chunks.length&&this.chunks[0]==OP_HASH160&&Buffer.isBuffer(this.chunks[1])&&20==this.chunks[1].length&&this.chunks[2]==OP_EQUAL},Script.prototype.isPubkey=function(){return 2==this.chunks.length&&Buffer.isBuffer(this.chunks[0])&&this.chunks[1]==OP_CHECKSIG},Script.prototype.isPubkeyHash=function(){return 5==this.chunks.length&&this.chunks[0]==OP_DUP&&this.chunks[1]==OP_HASH160&&Buffer.isBuffer(this.chunks[2])&&20==this.chunks[2].length&&this.chunks[3]==OP_EQUALVERIFY&&this.chunks[4]==OP_CHECKSIG},Script.prototype.isMultiSig=function(){return this.chunks.length>3&&isSmallIntOp(this.chunks[0])&&isSmallIntOp(this.chunks[this.chunks.length-2])&&this.chunks[this.chunks.length-1]==OP_CHECKMULTISIG},Script.prototype.finishedMultiSig=function(){for(var t=0,r=0;ri;i++){var u=this.chunks[i];if(i>0&&(e+=" "),e+=Buffer.isBuffer(u)?"0x"+util.formatBuffer(u,t?null:0):Opcode.reverseMap[u],r&&i>r){e+=" ...";break}}return e},Script.prototype.toString=function(t,r){var e="