mirror of https://github.com/BTCPrivate/copay.git
fix conflicts
This commit is contained in:
commit
b95af5e53a
22
API.js
22
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']
|
||||
]);
|
||||
|
||||
|
|
|
@ -18,11 +18,10 @@ var main = function() {
|
|||
var api = new API(commander);
|
||||
|
||||
var args = commander.args;
|
||||
|
||||
try {
|
||||
var command = args[0];
|
||||
var commandArgs = args.slice(1);
|
||||
|
||||
try {
|
||||
if (command[0] == '_' || typeof api[command] != 'function')
|
||||
throw new Error('invalid command');
|
||||
|
||||
|
|
3
copay.js
3
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');
|
||||
|
|
11
css/main.css
11
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%;}
|
68
index.html
68
index.html
|
@ -96,12 +96,53 @@
|
|||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="setup.html">
|
||||
<div ng-controller="SetupController">
|
||||
<div class="panel callout radius" ng-show="loading">
|
||||
Connecting to wallet...
|
||||
</div>
|
||||
<div ng-show="!loading">
|
||||
<h2>Create new multisig wallet</h2>
|
||||
<div class="row">
|
||||
<div class="large-6 columns">
|
||||
<h3>Select total number of copayers</h3>
|
||||
<select ng-model="totalCopayers"
|
||||
ng-options="totalCopayers as totalCopayers for totalCopayers in TCValues">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="large-6 columns">
|
||||
<h3>Select required number of copayers</h3>
|
||||
<select ng-model="requiredCopayers"
|
||||
ng-options="requiredCopayers as requiredCopayers for requiredCopayers in RCValues">
|
||||
</select>
|
||||
</div>
|
||||
<div class="large-3 columns">
|
||||
<button class="button primary expand round" type="button"
|
||||
ng-click="create(totalCopayers, requiredCopayers)">
|
||||
Create {{requiredCopayers}}-of-{{totalCopayers}} wallet
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="peer.html">
|
||||
<div class="row" ng-controller="PeerController" ng-init="init()">
|
||||
<div class="large-6 columns">
|
||||
<h1>I am <p class="text-muted">{{$root.wallet.network.peerId}}</p></h1>
|
||||
|
||||
<ul class="no-bullet">
|
||||
<div class="large-6 columns p70r line-dashed-v">
|
||||
<h3>I am </h3>
|
||||
<div class="row">
|
||||
<div class="large-10 columns p0r">
|
||||
<p class="panel share-wallet">{{$root.wallet.network.peerId}}</p>
|
||||
</div>
|
||||
<div class="large-2 columns">
|
||||
<p class="panel panel-sign"> <i class="fi-page-copy size-22"></i> </p>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="no-bullet" style="font-size: 0.7rem;">
|
||||
<li> [DEBUG] Pubkeys that you have: {{$root.wallet.publicKeyRing.registeredCopayers()}}
|
||||
<li> [DEBUG] WalletId: {{$root.wallet.id}}
|
||||
<li class="panel" style="word-wrap: break-word;" ng-repeat="pub in $root.wallet.publicKeyRing.copayersBIP32">
|
||||
|
@ -109,16 +150,19 @@
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="large-6 columns">
|
||||
<div class="large-6 columns p70l">
|
||||
<h3 class="panel-title">Copayers ({{$root.wallet.network.connectedPeers.length}}/{{$root.wallet.publicKeyRing.requiredCopayers}})</h3>
|
||||
<ul class="no-bullet">
|
||||
<li class="panel" ng-repeat="copayer in $root.connectedPeers">
|
||||
<li class="panel" ng-repeat="copayer in $root.wallet.network.connectedPeers">
|
||||
<span ng-if="copayer == $root.peerId"> You ({{$root.peerId}})<i class="fi-check size-24"></i></span>
|
||||
<span ng-if="copayer != $root.peerId">{{copayer}}</span>
|
||||
<span>
|
||||
<i class="fi-check size-16 panel-sign right p5h br100"></i>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="text-center">
|
||||
<button href="#/home" class="button secondary round large expand">Go to home</button>
|
||||
<button href="#/home" class="button secondary round right">Go to home</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -162,11 +206,14 @@
|
|||
<p class="large-5 columns"> Address 1</p>
|
||||
<i class="large-2 columns fi-arrow-right size-16 text-center"></i>
|
||||
<p class="large-5 columns"> Address 2</p>
|
||||
<div class="large-12 columns m0">
|
||||
|
||||
<div class="large-12 columns m0" ng-show="txp.signedByUs"> YOU SIGNED! </div>
|
||||
|
||||
<div class="large-12 columns m0" ng-show="!txp.signedByUs">
|
||||
<div class="line"></div>
|
||||
<button class="primary round large-4 columns"><i class="large-2 columns fi-x size-16 text-center"></i> Ignore</button>
|
||||
<small class="large-4 columns text-center">Faltan 3 cosigners</small>
|
||||
<button class="secondary round large-4 columns"><i class="large-2 columns fi-check size-16 text-center"></i> Sign</button>
|
||||
<button class="secondary round large-4 columns" ng-click="sign(txp.ntxid)"><i class="large-2 columns fi-check size-16 text-center"></i> Sign</button>
|
||||
</div>
|
||||
</div> <!-- end of row -->
|
||||
</div> <!-- end of pending -->
|
||||
|
@ -287,7 +334,7 @@
|
|||
<script src="js/routes.js"></script>
|
||||
<script src="js/directives.js"></script>
|
||||
<script src="js/filters.js"></script>
|
||||
<script src="js/services/network.js"></script>
|
||||
<script src="js/services/walletFactory.js"></script>
|
||||
|
||||
<script src="js/controllers/header.js"></script>
|
||||
<script src="js/controllers/home.js"></script>
|
||||
|
@ -295,6 +342,7 @@
|
|||
<script src="js/controllers/send.js"></script>
|
||||
<script src="js/controllers/backup.js"></script>
|
||||
<script src="js/controllers/signin.js"></script>
|
||||
<script src="js/controllers/setup.js"></script>
|
||||
<script src="js/controllers/peer.js"></script>
|
||||
|
||||
<script src="js/init.js"></script>
|
||||
|
|
|
@ -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', []);
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
};
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
});
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
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.parent=EventEmitter;
|
||||
Wallet.prototype.log = function(){
|
||||
// if (!this.verbose) return;
|
||||
console.log(arguments);
|
||||
};
|
||||
|
||||
Wallet.getRandomId = function() {
|
||||
var r = buffertools.toHex(coinUtil.generateNonce());
|
||||
return r;
|
||||
};
|
||||
|
||||
Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) {
|
||||
this.log('RECV PUBLICKEYRING:',data);
|
||||
|
||||
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<l; i++) {
|
||||
var txp = this.txProposals.txps[i];
|
||||
var id2 = txp.builder.build().getNormalizedHash().toString('hex');
|
||||
if (id === id2 ) {
|
||||
ret = txp;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
Wallet.prototype.sign = function(ntxid) {
|
||||
var txp = this._findTxByNtxid(ntxid);
|
||||
if (!txp) return;
|
||||
|
||||
var pkr = this.publicKeyRing;
|
||||
var keys = this.privateKey.getAll(pkr.addressIndex, pkr.changeAddressIndex);
|
||||
var ret = txp.builder.sign(keys);
|
||||
|
||||
if (ret.signaturesAdded) {
|
||||
txp.signedBy[this.privateKey.id] = Date.now();
|
||||
console.log('[Wallet.js.230:ret:]',ret); //TODO
|
||||
if (ret.isFullySigned) {
|
||||
console.log('[Wallet.js.231] BROADCASTING TX!!!'); //TODO
|
||||
var tx = txp.builder.build();
|
||||
var txHex = tx.serialize().toString('hex');
|
||||
this.blockchain.sendRawTransaction(txHex, function(txid) {
|
||||
console.log('[Wallet.js.235:txid:]',txid); //TODO
|
||||
if (txid) {
|
||||
this.store();
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.sendTxProposals();
|
||||
this.store();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
Wallet.prototype.addSeenToTxProposals = function() {
|
||||
var ret=false;
|
||||
var self=this;
|
||||
|
||||
this.txProposals.txps.forEach(function(txp) {
|
||||
if (!txp.seenBy[this.privateKey.id]) {
|
||||
txp.seenBy[this.privateKey.id] = Date.now();
|
||||
if (!txp.seenBy[self.privateKey.id]) {
|
||||
txp.seenBy[self.privateKey.id] = Date.now();
|
||||
ret = true;
|
||||
}
|
||||
});
|
||||
|
@ -181,7 +282,33 @@ Wallet.prototype.listUnspent = function(cb) {
|
|||
this.blockchain.listUnspent(this.getAddressesStr(), cb);
|
||||
};
|
||||
|
||||
Wallet.prototype.createTx = function(toAddress, amountSatStr, utxos, opts) {
|
||||
|
||||
Wallet.prototype.createTx = function(toAddress, amountSatStr, opts, cb) {
|
||||
var self = this;
|
||||
if (typeof opts === 'function') {
|
||||
cb = opts;
|
||||
opts = {};
|
||||
}
|
||||
opts = opts || {};
|
||||
|
||||
if (typeof opts.spendUnconfirmed === 'undefined') {
|
||||
opts.spendUnconfirmed = this.spendUnconfirmed;
|
||||
}
|
||||
|
||||
if (!opts.remainderOut) {
|
||||
opts.remainderOut={ address: this.publicKeyRing.generateAddress(true).toString()};
|
||||
}
|
||||
|
||||
self.listUnspent(function(utxos) {
|
||||
// TODO check enough funds, etc.
|
||||
self.createTxSync(toAddress, amountSatStr, utxos, opts);
|
||||
self.store();
|
||||
self.sendTxProposals();
|
||||
return cb();
|
||||
});
|
||||
};
|
||||
|
||||
Wallet.prototype.createTxSync = function(toAddress, amountSatStr, utxos, opts) {
|
||||
var pkr = this.publicKeyRing;
|
||||
var priv = this.privateKey;
|
||||
opts = opts || {};
|
||||
|
@ -216,7 +343,12 @@ Wallet.prototype.createTx = function(toAddress, amountSatStr, utxos, opts) {
|
|||
});
|
||||
};
|
||||
|
||||
Wallet.prototype.sign = function(txp) {
|
||||
Wallet.prototype.connectTo = function(peerId) {
|
||||
throw new Error('Wallet.connectTo.. not yet implemented!');
|
||||
};
|
||||
|
||||
Wallet.prototype.disconnect = function() {
|
||||
this.network.disconnect();
|
||||
};
|
||||
|
||||
// // HERE? not sure
|
||||
|
@ -224,57 +356,6 @@ Wallet.prototype.sign = function(txp) {
|
|||
// this.storage.remove('peerData');
|
||||
// };
|
||||
//
|
||||
|
||||
Wallet.getRandomId = function() {
|
||||
var r = buffertools.toHex(coinUtil.generateNonce());
|
||||
return r;
|
||||
};
|
||||
|
||||
/*
|
||||
* WalletFactory
|
||||
*
|
||||
*/
|
||||
|
||||
var WalletFactory = function() {
|
||||
this.storage = Storage.default();
|
||||
};
|
||||
|
||||
WalletFactory.prototype.create = function(config, opts) {
|
||||
var w = new Wallet(config);
|
||||
w.create(opts);
|
||||
w.store();
|
||||
return w;
|
||||
};
|
||||
|
||||
WalletFactory.prototype.get = function(config, walletId) {
|
||||
return Wallet.read(config, walletId);
|
||||
};
|
||||
|
||||
WalletFactory.prototype.remove = function(walletId) {
|
||||
// TODO remove wallet contents, not only the id (Wallet.remove?)
|
||||
this._delWalletId(walletId);
|
||||
};
|
||||
|
||||
WalletFactory.prototype.addWalletId = function(walletId) {
|
||||
var ids = this.getWalletIds();
|
||||
if (ids.indexOf(walletId) !== -1) return;
|
||||
ids.push(walletId);
|
||||
this.storage.setGlobal('walletIds', 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.getWalletIds = function() {
|
||||
var ids = this.storage.getGlobal('walletIds');
|
||||
return ids || [];
|
||||
};
|
||||
|
||||
Wallet.factory = new WalletFactory();
|
||||
;
|
||||
|
||||
module.exports = require('soop')(Wallet);
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
'use strict';
|
||||
|
||||
var imports = require('soop').imports();
|
||||
var Storage = imports.Storage;
|
||||
var Network = imports.Network;
|
||||
var Blockchain = imports.Blockchain;
|
||||
|
||||
var TxProposals = require('./TxProposals');
|
||||
var PublicKeyRing = require('./PublicKeyRing');
|
||||
var PrivateKey = require('./PrivateKey');
|
||||
var Wallet = require('./Wallet');
|
||||
|
||||
/*
|
||||
* WalletFactory
|
||||
*
|
||||
*
|
||||
* var wallet = WF.read(config,walletId); -> 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);
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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() {
|
||||
};
|
||||
|
|
|
@ -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);
|
|
@ -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();
|
||||
|
|
|
@ -12,6 +12,9 @@ angular
|
|||
.when('/signin', {
|
||||
templateUrl: 'signin.html'
|
||||
})
|
||||
.when('/setup', {
|
||||
templateUrl: 'setup.html'
|
||||
})
|
||||
.when('/home', {
|
||||
templateUrl: 'home.html'
|
||||
})
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
var wf;
|
||||
angular.module('copay.walletFactory').factory('walletFactory', function($rootScope) {
|
||||
wf = wf || new copay.WalletFactory(config);
|
||||
return wf;
|
||||
});
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -35,6 +35,7 @@
|
|||
"uglifyify": "~1.2.3",
|
||||
"soop": "~0.1.5",
|
||||
"bitcore": "git://github.com/maraoz/bitcore.git#5e636f6b9c7f8e629b1a502025556e886c3b75e1",
|
||||
"chai": "~1.9.1"
|
||||
"chai": "~1.9.1",
|
||||
"sinon": "~1.9.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,4 +23,8 @@ FakeStorage.prototype.clear = function() {
|
|||
delete this['storage'];
|
||||
}
|
||||
|
||||
FakeStorage.prototype.getWalletIds = function() {
|
||||
return [];
|
||||
};
|
||||
|
||||
module.exports = require('soop')(FakeStorage);
|
||||
|
|
|
@ -4,11 +4,13 @@ var chai = chai || require('chai');
|
|||
var should = chai.should();
|
||||
var copay = copay || require('../copay');
|
||||
var API = API || copay.API;
|
||||
var Storage = Storage || require('../test/mocks/FakeStorage');
|
||||
|
||||
describe('API', function() {
|
||||
|
||||
it('should have a command called "echo"', function() {
|
||||
var api = new API();
|
||||
|
||||
var api = new API({Storage: Storage});
|
||||
should.exist(api.echo);
|
||||
});
|
||||
|
||||
|
@ -22,7 +24,7 @@ describe('API', function() {
|
|||
})
|
||||
|
||||
it('should throw an error for all commands when called with wrong number of arguments', function() {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
for (var i in API.prototype) {
|
||||
var f = API.prototype[i];
|
||||
if (i[0] != '_' && typeof f == 'function') {
|
||||
|
@ -49,7 +51,7 @@ describe('API', function() {
|
|||
|
||||
describe('#echo', function() {
|
||||
it('should echo a string', function(done) {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
var str = 'mystr';
|
||||
api.echo(str, function(err, result) {
|
||||
result.should.equal(str);
|
||||
|
@ -60,7 +62,7 @@ describe('API', function() {
|
|||
|
||||
describe('#echoNumber', function() {
|
||||
it('should echo a number', function(done) {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
var num = 500;
|
||||
api.echoNumber(num, function(err, result) {
|
||||
result.should.equal(num);
|
||||
|
@ -72,7 +74,7 @@ describe('API', function() {
|
|||
|
||||
describe('#echoObject', function() {
|
||||
it('should echo an object', function(done) {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
var obj = {test:'test'};
|
||||
api.echoObject(obj, function(err, result) {
|
||||
result.test.should.equal(obj.test);
|
||||
|
@ -84,7 +86,7 @@ describe('API', function() {
|
|||
|
||||
describe('#getArgTypes', function() {
|
||||
it('should get the argTypes of echo', function(done) {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
api.getArgTypes('echo', function(err, result) {
|
||||
result[0][1].should.equal('string');
|
||||
done();
|
||||
|
@ -94,7 +96,7 @@ describe('API', function() {
|
|||
|
||||
describe('#getCommands', function() {
|
||||
it('should get all the commands', function(done) {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
var n = 0;
|
||||
|
||||
for (var i in api)
|
||||
|
@ -108,11 +110,11 @@ describe('API', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('#getPublicKeyRingId', function() {
|
||||
it('should get a public key ring ID', function(done) {
|
||||
var api = new API();
|
||||
api.getPublicKeyRingId(function(err, result) {
|
||||
result.length.should.be.greaterThan(5);
|
||||
describe('#getWalletIds', function() {
|
||||
it('should get the wallet ids', function(done) {
|
||||
var api = new API({Storage: Storage});
|
||||
api.getWalletIds(function(err, result) {
|
||||
result.length.should.be.greaterThan(-1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -120,7 +122,7 @@ describe('API', function() {
|
|||
|
||||
describe('#help', function() {
|
||||
it('should call _cmd_getCommands', function(done) {
|
||||
var api = new API();
|
||||
var api = new API({Storage: Storage});
|
||||
api._cmd_getCommands = function(callback) {
|
||||
(typeof arguments[0]).should.equal('function');
|
||||
callback(null, ['item']);
|
||||
|
|
|
@ -3,12 +3,10 @@
|
|||
var chai = chai || require('chai');
|
||||
var should = chai.should();
|
||||
var copay = copay || require('../copay');
|
||||
var Wallet = require('soop').load('../js/models/core/Wallet', {
|
||||
Storage: require('./mocks/FakeStorage'),
|
||||
Network: copay.WebRTC,
|
||||
Blockchain: copay.Insight
|
||||
});
|
||||
|
||||
var Wallet = require('../js/models/core/Wallet');
|
||||
var Storage= require('./mocks/FakeStorage');
|
||||
var Network= copay.WebRTC;
|
||||
var Blockchain= copay.Insight;
|
||||
|
||||
var addCopayers = function (w) {
|
||||
for(var i=0; i<4; i++) {
|
||||
|
@ -17,73 +15,65 @@ var addCopayers = function (w) {
|
|||
};
|
||||
|
||||
describe('Wallet model', function() {
|
||||
|
||||
var config = {
|
||||
wallet: {
|
||||
requiredCopayers: 3,
|
||||
totalCopayers: 5,
|
||||
},
|
||||
spendUnconfirmed: 1,
|
||||
blockchain: {
|
||||
host: 'test.insight.is',
|
||||
port: 80
|
||||
},
|
||||
networkName: 'testnet',
|
||||
};
|
||||
var opts = {};
|
||||
|
||||
it('should fail to create an instance', function () {
|
||||
(function(){new Wallet(config)}).should.throw();
|
||||
});
|
||||
|
||||
var createW = function () {
|
||||
var c = JSON.parse(JSON.stringify(config));
|
||||
|
||||
c.privateKey = new copay.PrivateKey({ networkName: c.networkName });
|
||||
|
||||
c.publicKeyRing = new copay.PublicKeyRing({
|
||||
networkName: c.networkName,
|
||||
requiredCopayers: c.requiredCopayers,
|
||||
totalCopayers: c.totalCopayers,
|
||||
});
|
||||
c.publicKeyRing.addCopayer(c.privateKey.getBIP32().extendedPublicKeyString());
|
||||
|
||||
c.txProposals = new copay.TxProposals({
|
||||
networkName: c.networkName,
|
||||
});
|
||||
c.storage = new Storage(config.storage);
|
||||
c.network = new Network(config.network);
|
||||
c.blockchain = new Blockchain(config.blockchain);
|
||||
|
||||
c.networkName = config.networkName;
|
||||
c.verbose = config.verbose;
|
||||
|
||||
return new Wallet(c);
|
||||
}
|
||||
|
||||
it('should create an instance', function () {
|
||||
var opts = {};
|
||||
var w = new Wallet(config);
|
||||
var w = createW();
|
||||
should.exist(w);
|
||||
});
|
||||
|
||||
|
||||
it('should fail to load', function () {
|
||||
var opts = {};
|
||||
var w = new Wallet(config);
|
||||
w.load(123);
|
||||
should.not.exist(w.id);
|
||||
});
|
||||
|
||||
|
||||
it('should create', function () {
|
||||
var opts = {};
|
||||
var w = new Wallet(config);
|
||||
w.create();
|
||||
w.publicKeyRing.walletId.should.equal(w.id);
|
||||
w.txProposals.walletId.should.equal(w.id);
|
||||
w.requiredCopayers.should.equal(3);
|
||||
should.exist(w.id);
|
||||
should.exist(w.publicKeyRing);
|
||||
should.exist(w.privateKey);
|
||||
should.exist(w.txProposals);
|
||||
});
|
||||
|
||||
it('should list unspent', function (done) {
|
||||
it('should provide some basic features', function () {
|
||||
var opts = {};
|
||||
var w = new Wallet(config);
|
||||
w.create();
|
||||
var w = createW();
|
||||
addCopayers(w);
|
||||
w.publicKeyRing.generateAddress(false);
|
||||
|
||||
should.exist(w.id);
|
||||
w.publicKeyRing.isComplete().should.equal(true);
|
||||
|
||||
w.listUnspent(function(utxos) {
|
||||
utxos.length.should.equal(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('factory', function() {
|
||||
it('should create the factory', function() {
|
||||
should.exist(Wallet.factory);
|
||||
});
|
||||
it('should be able to create wallets', function() {
|
||||
var w = Wallet.factory.create(config, opts);
|
||||
should.exist(w);
|
||||
});
|
||||
it.skip('should be able to get wallets', function() {
|
||||
var w = Wallet.factory.create(config, opts);
|
||||
var v = Wallet.factory.get(config, w.id);
|
||||
should.exist(w);
|
||||
});
|
||||
});
|
||||
|
||||
var unspentTest = [
|
||||
|
@ -97,9 +87,8 @@ describe('Wallet model', function() {
|
|||
}
|
||||
];
|
||||
|
||||
var createWallet = function (bip32s) {
|
||||
var w = new Wallet(config);
|
||||
w.create();
|
||||
var createW2 = function (bip32s) {
|
||||
var w = createW();
|
||||
should.exist(w);
|
||||
|
||||
var pkr = w.publicKeyRing;
|
||||
|
@ -125,12 +114,12 @@ describe('Wallet model', function() {
|
|||
|
||||
it('#create, 1 sign', function () {
|
||||
|
||||
var w = createWallet();
|
||||
var w = createW2();
|
||||
|
||||
unspentTest[0].address = w.publicKeyRing.getAddress(1, true).toString();
|
||||
unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(1, true);
|
||||
|
||||
w.createTx(
|
||||
w.createTxSync(
|
||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||
'123456789',
|
||||
unspentTest
|
||||
|
@ -148,14 +137,14 @@ describe('Wallet model', function() {
|
|||
|
||||
it('#create. Signing with derivate keys', function () {
|
||||
|
||||
var w = createWallet();
|
||||
var w = createW2();
|
||||
|
||||
var ts = Date.now();
|
||||
for (var isChange=0; isChange<2; isChange++) {
|
||||
for (var index=0; index<3; index++) {
|
||||
unspentTest[0].address = w.publicKeyRing.getAddress(index, isChange).toString();
|
||||
unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(index, isChange);
|
||||
w.createTx(
|
||||
w.createTxSync(
|
||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||
'123456789',
|
||||
unspentTest
|
||||
|
@ -172,25 +161,4 @@ describe('Wallet model', function() {
|
|||
}
|
||||
});
|
||||
|
||||
// TODO: when sign is implemented
|
||||
it.skip('#create, signing with wrong key', function () {
|
||||
var w1 = createWallet();
|
||||
|
||||
unspentTest[0].address = w.publicKeyRing.getAddress(1, true).toString();
|
||||
unspentTest[0].scriptPubKey = w.publicKeyRing.getScriptPubKeyHex(1, true);
|
||||
|
||||
var priv = new PrivateKey(config);
|
||||
w.create(
|
||||
'15q6HKjWHAksHcH91JW23BJEuzZgFwydBt',
|
||||
'123456789',
|
||||
unspentTest
|
||||
);
|
||||
var tx = w.txps[0].builder.build();
|
||||
should.exist(tx);
|
||||
tx.isComplete().should.equal(false);
|
||||
Object.keys(w.txps[0].signedBy).length.should.equal(0);
|
||||
Object.keys(w.txps[0].seenBy).length.should.equal(1);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
|
|
@ -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('./mocks/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);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,144 @@
|
|||
'use strict';
|
||||
|
||||
var chai = chai || require('chai');
|
||||
var should = chai.should();
|
||||
var Storage = Storage || require('../js/models/storage/File.js');
|
||||
var sinon = sinon || require('sinon');
|
||||
|
||||
describe('Storage/File', function() {
|
||||
it('should exist', function() {
|
||||
should.exist(Storage);
|
||||
});
|
||||
|
||||
describe('#load', function(done) {
|
||||
it('should call fs.readFile', function(done) {
|
||||
var fs = {}
|
||||
fs.readFile = function(filename, callback) {
|
||||
filename.should.equal('myfilename');
|
||||
callback();
|
||||
};
|
||||
var Storage = require('soop').load('../js/models/storage/File.js', {fs: fs});
|
||||
var storage = new Storage({password: 'password'});
|
||||
storage.load('myfilename', function(err) {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#save', function(done) {
|
||||
it('should call fs.writeFile', function(done) {
|
||||
var fs = {}
|
||||
fs.writeFile = function(filename, data, callback) {
|
||||
filename.should.equal('myfilename');
|
||||
callback();
|
||||
};
|
||||
var Storage = require('soop').load('../js/models/storage/File.js', {fs: fs});
|
||||
var storage = new Storage({password: 'password'});
|
||||
storage.save('myfilename', function(err) {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#_read', function() {
|
||||
it('should return the value of a key', function() {
|
||||
var storage = new Storage();
|
||||
storage.data = {'walletId':{'test':'data'}};
|
||||
storage._read('walletId::test').should.equal('data');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#_write', function() {
|
||||
it('should save the value of a key and then run save', function(done) {
|
||||
var storage = new Storage();
|
||||
storage.save = function(walletId, callback) {
|
||||
storage.data[walletId]['key'].should.equal('value');
|
||||
callback();
|
||||
};
|
||||
storage._write('walletId::key', 'value', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getGlobal', function() {
|
||||
it('should call storage._read', function() {
|
||||
var storage = new Storage();
|
||||
storage.data = {'walletId':{'test':'test'}};
|
||||
storage._read = sinon.spy();
|
||||
storage.getGlobal('walletId::test');
|
||||
storage._read.calledOnce.should.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setGlobal', function() {
|
||||
it('should store a global key', function(done) {
|
||||
var storage = new Storage();
|
||||
storage.save = function(walletId, callback) {
|
||||
storage.data[walletId]['key'].should.equal('value');
|
||||
callback();
|
||||
};
|
||||
storage.setGlobal('walletId::key', 'value', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#removeGlobal', function() {
|
||||
it('should remove a global key', function(done) {
|
||||
var storage = new Storage();
|
||||
storage.data = {'walletId':{'key':'value'}};
|
||||
storage.save = function(walletId, callback) {
|
||||
should.not.exist(storage.data[walletId]['key']);
|
||||
callback();
|
||||
};
|
||||
storage.removeGlobal('walletId::key', function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#_key', function() {
|
||||
it('should merge the wallet id and item key', function() {
|
||||
var storage = new Storage();
|
||||
storage._key('wallet', 'key').should.equal('wallet::key');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#get', function() {
|
||||
it('should call getGlobal with the correct key', function() {
|
||||
var storage = new Storage();
|
||||
storage.getGlobal = sinon.spy();
|
||||
storage.get('wallet', 'key');
|
||||
storage.getGlobal.calledOnce.should.equal(true);
|
||||
storage.getGlobal.calledWith('wallet::key').should.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#set', function() {
|
||||
it('should call setGlobal with the correct key', function() {
|
||||
var storage = new Storage();
|
||||
storage.setGlobal = sinon.spy();
|
||||
storage.set('wallet', 'key');
|
||||
storage.setGlobal.calledOnce.should.equal(true);
|
||||
storage.setGlobal.calledWith('wallet::key').should.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#remove', function() {
|
||||
it('should call removeGlobal with the correct key', function() {
|
||||
var storage = new Storage();
|
||||
storage.removeGlobal = sinon.spy();
|
||||
storage.remove('wallet', 'key');
|
||||
storage.removeGlobal.calledOnce.should.equal(true);
|
||||
storage.removeGlobal.calledWith('wallet::key').should.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#clearAll', function() {
|
||||
it('should set data to {}', function() {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
|
@ -42,7 +42,15 @@ var createBundle = function(opts) {
|
|||
b.require('./copay', {
|
||||
expose: 'copay'
|
||||
});
|
||||
b.require('./js/models/core/WalletFactory');
|
||||
b.require('./js/models/core/Wallet');
|
||||
b.require('./js/models/core/Wallet', {
|
||||
expose: '../js/models/core/Wallet'
|
||||
});
|
||||
b.require('./test/mocks/FakeStorage', {
|
||||
expose: './mocks/FakeStorage'
|
||||
});
|
||||
|
||||
|
||||
if (!opts.dontminify) {
|
||||
b.transform({
|
||||
|
|
Loading…
Reference in New Issue