Merge branch 'master' of github.com:bitpay/copay into feature/copay-shell

This commit is contained in:
Gordon Hall 2014-06-03 14:22:31 -04:00
commit 4dbad23eac
16 changed files with 287 additions and 166 deletions

View File

@ -103,6 +103,7 @@ var defaultConfig = {
totalCopayers: 3,
spendUnconfirmed: 1,
verbose: 1,
reconnectDelay: 5000,
},
// blockchain service API config

View File

@ -30,6 +30,11 @@ html, body {height: 100%;}
box-shadow: inset 0px 0px 3px 0px rgba(0,0,0,0.10);
}
.text-gray.active {
color: #111 !important;
font-weight: 700;
}
#footer {
position: fixed;
margin-top: -96px; /* negative value of footer height */
@ -59,7 +64,6 @@ html, body {height: 100%;}
.logo {
display: block;
width: 130px;
height: 51px;
margin: 0 auto;
}
@ -169,7 +173,7 @@ h3 {
border-right: 2px dashed #E3E3E3;
}
@media (max-width: 1025px) {
@media (max-width: 640px) {
.line-dashed-v {
border: none;
}
@ -347,11 +351,7 @@ hr { margin: 2.25rem 0;}
}
.box-setup {
padding: 20px 30px;
border: 1px solid #eee;
background: #fff;
overflow: hidden;
margin-bottom: 10px;
margin-bottom: 25px;
}
.box-setup-copayers {
@ -483,19 +483,6 @@ a.loading {
vertical-align:middle
}
fieldset {
border: 1px solid #eee;
padding: 1.11111rem;
margin: 1rem 0;
}
fieldset legend {
font-weight: bold;
padding: 0 0.16667rem;
margin: 0;
margin-left: -0.16667rem;
}
/* notifications */
.dr-notification-container {
@ -640,6 +627,7 @@ ul.pagination li.current a:hover, ul.pagination li.current a:focus {
background-size: 90px 44px !important;
float: left;
margin-top: 0.7rem;
width: 130px;
}
.header-content .small-9 {

View File

@ -321,3 +321,7 @@ input.ng-invalid-wallet-secret {
color: #3FBC9C;
}
.box-setup fieldset {
background: #fff;
}

View File

@ -139,13 +139,13 @@
<div id="footer" data-ng-controller="FooterController" ng-class="{'footer-home': !$root.wallet}">
<link rel="stylesheet" ng-href="{{theme}}">
<div class="row" ng-show="!$root.wallet">
<div ng-show="!$root.wallet">
<div class="large-12 columns text-right">
Copay
<small>v{{version}}</small>
</div>
</div>
<div class="row p10t" ng-show="$root.wallet">
<div class="p10t" ng-show="$root.wallet">
<div class="large-3 medium-3 hide-for-small columns">
<div>
<strong>{{$root.wallet.getName()}}</strong>
@ -203,13 +203,10 @@
</div>
<div ng-show="!wallets.length">
<h3>Create a new wallet</h3>
<form name="createForm" ng-submit="create(createForm)" novalidate>
<p class="text-gray">
Copay is a free, open-source, multisignature bitcoin wallet. A single-owner bitcoin wallet's security depends on carefully securing the private keys. With copay you can have multiple people controlling the funds, using bitcoin's multisignature functionality, requiring no trust in any third party.
</p>
<button type="submit" class="button secondary radius"
ng-disabled="createForm.$invalid || loading" loading="Creating">Create</button>
</form>
<a href="#setup" class="button secondary radius">Create</a>
</div>
</div>
</div>
@ -257,19 +254,21 @@
<label for="backupText" ng-click="pastetext=!pastetext" class="m10b">&middot; Paste backup plain text code <i class="fi-clipboard"></i></label>
<textarea class="form-control" name="backupText" ng-model="backupText" rows="5" ng-show="pastetext"></textarea>
</fieldset>
</div>
<div class="large-8 medium-8 columns">
<div class="large-6 large-centered medium-6 medium-centered columns">
<label for="password">Password <small>Required</small></label>
<input type="password" class="form-control" placeholder="Your wallet password" name="password" ng-model="password" required>
</div>
</div>
<div class="row line-dashed">
<div class="large-6 medium-6 small-5 columns text-left">
<a class="button secondary radius" href="#signin">Go back</a>
</div>
<div class="row">
<div class="large-12 columns line-dashed">
<div class="large-6 medium-6 small-5 columns text-right">
<button type="submit" class="button primary radius right" ng-disabled="importForm.$invalid" loading="Importing">
Import backup
</button>
<a class="button secondary radius" href="#signin">Go back</a>
</div>
</div>
</form>
@ -285,46 +284,64 @@
</div>
<div ng-show="!loading">
<form name="setupForm" ng-submit="create(setupForm)" novalidate>
<div class="small-12 medium-8 medium-centered large-8 large-centered columns box-setup">
<h3>Create new wallet</h3>
<div class="large-6 columns line-dashed-v">
<h6>Select total number of copayers</h6>
<div class="row">
<div class="small-12 medium-8 medium-centered large-8 large-centered columns">
<label>Wallet name <small>Optional</small>
<input type="text" placeholder="Family vacation funds" class="form-control" ng-model="walletName">
</label>
</div>
<div class="small-12 medium-8 medium-centered large-8 large-centered columns">
<div class="row">
<div class="small-12 medium-6 large-6 columns">
<label>Your name <small>Optional</small>
<input type="text" placeholder="Name" class="form-control" ng-model="myNickname">
</label>
</div>
<div class="small-12 medium-6 large-6 columns">
<label>Your Wallet Password <small class="has-tip" tooltip="doesn't need to be shared">Required</small>
<input type="password" placeholder="Choose your password" class="form-control"
ng-model="$parent.walletPassword" check-strength="passwordStrength" tooltip="Password strength: {{passwordStrength}}" tooltip-trigger="focus" required>
</label>
</div>
</div>
</div>
<div class="small-12 medium-8 medium-centered large-8 large-centered columns box-setup">
<fieldset>
<div class="row">
<div class="large-6 medium-6 columns line-dashed-v">
<label>Select total number of copayers
<select ng-model="totalCopayers" ng-options="totalCopayers as totalCopayers for totalCopayers in TCValues">
</select>
</label>
</div>
<div class="large-6 columns">
<h6>Select required signatures</h6>
<div class="large-6 medium-6 columns">
<label>Select required signatures
<select ng-model="requiredCopayers" ng-options="requiredCopayers as requiredCopayers for requiredCopayers in RCValues">
</select>
</label>
</div>
</div>
<div class="row">
<div class="small-12 medium-6 medium-centered large-6 large-centered columns m30v">
</fieldset>
</div>
<div class="small-12 medium-6 medium-centered large-6 large-centered columns m10b">
<div class="box-setup-copayers">
<div class="box-setup-copayers-fix">
<img class="box-setup-copay" ng-repeat="i in getNumber(totalCopayers) track by $index" src="./img/satoshi.gif" alt="Copayer {{$index+1}}-{{totalCopayers}}" ng-class="{'box-setup-copay-required': ($index+1) <= requiredCopayers}">
</div>
</div>
</div>
<div class="small-12 medium-6 medium-centered large-6 large-centered columns m30v">
<h6>Your Wallet Password<small>(doesn't need to be shared) Required</small></h6>
<input type="password" placeholder="Choose your password" class="form-control"
ng-model="$parent.walletPassword" check-strength="passwordStrength" tooltip="Password strength: {{passwordStrength}}" tooltip-trigger="focus" required>
</div>
<div class="small-12 medium-6 medium-centered large-6 large-centered columns m30v">
<h6>Wallet name <small>Optional</small></h6>
<input type="text" placeholder="Family vacation funds" class="form-control" ng-model="walletName">
<div class="row line-dashed">
<div class="large-6 medium-6 small-5 columns text-left">
<a class="button secondary radius" href="#signin">Go back</a>
</div>
<div class="small-12 medium-6 medium-centered large-6 large-centered columns m30v">
<h6>Your name <small>Optional</small></h6>
<input type="text" placeholder="Name" class="form-control" ng-model="myNickname">
</div>
</div>
<div class="large-12 columns line-dashed">
<button type="submit" class="button primary radius right" ng-disabled="setupForm.$invalid || loading">
<div class="large-6 medium-6 small-7 columns text-right">
<button type="submit" class="button primary radius" ng-disabled="setupForm.$invalid || loading">
Create {{requiredCopayers}}-of-{{totalCopayers}} wallet
</button>
<a class="button secondary radius" href="#signin">Go back</a>
</div>
</div>
</form>
</div>
@ -402,11 +419,11 @@
<div class="transactions" data-ng-controller="TransactionsController">
<div class="row" ng-show='$root.wallet.publicKeyRing.isComplete()'>
<div class="large-12 columns">
<h4> Transaction proposals <span ng-if="onlyPending">[Pending]</span> <small>({{txs.length}})</small></h4>
<h4> Transaction proposals <small>({{txs.length}})</small></h4>
<ul class="button-group radius">
<li> <button class="secondary" ng-click="show(true)" ng-disabled="loading || onlyPending" loading="Updating"> Pending </button>
<li> <button class="secondary" ng-click="show()" ng-disabled="loading || !onlyPending" loading="Updating"> All </button>
<ul class="inline-list">
<li> <a class="text-gray size-12" ng-click="show(true)" ng-disabled="loading || onlyPending" loading="Updating" ng-class="{'active' : onlyPending}"> [ Pending ] </a> </li>
<li> <a class="text-gray size-12" ng-click="show()" ng-disabled="loading || !onlyPending" loading="Updating" ng-class="{'active' : !onlyPending}"> [ All ] </a> </li>
</ul>
<div class="panel radius pending" ng-repeat="tx in txs | paged">
<div class="txheader row m10">
@ -501,8 +518,8 @@
</div>
<div class="large-12 columns">
<h4>Last transactions</h4>
<a ng-click="toogleLast()" ng-disabled="loading" loading="Updating" ng-hide="lastShowed && !loading">Show</a>
<a ng-click="toogleLast()" ng-disabled="loading" loading="Updating" ng-show="lastShowed && !loading">Hide</a>
<a class="size-12" ng-click="toogleLast()" ng-disabled="loading" loading="Updating" ng-hide="lastShowed && !loading">Show</a>
<a class="size-12" ng-click="toogleLast()" ng-disabled="loading" loading="Updating" ng-show="lastShowed && !loading">Hide</a>
<div class="btransactions" ng-if="lastShowed">
<div ng-if="!blockchain_txs[0].txid && !loading">
No transactions yet.

View File

@ -21,8 +21,6 @@ angular.module('copay.header').controller('HeaderController',
'link': '#/backup'
}];
var beep = new Audio('sound/transaction.mp3');
$http.get('https://api.github.com/repos/bitpay/copay/tags').success(function(data){
var toInt = function (s) { return parseInt(s); };
var latestVersion = data[0].name.replace('v', '').split('.').map(toInt);
@ -54,6 +52,7 @@ angular.module('copay.header').controller('HeaderController',
}
}
if (currentAddr) {
var beep = new Audio('sound/transaction.mp3');
$notification.funds('Received fund', currentAddr, receivedFund);
beep.play();
}

View File

@ -43,6 +43,7 @@ angular.module('copay.import').controller('ImportController',
if (!backupFile && !backupText) {
$scope.loading = false;
$rootScope.$flashMessage = { message: 'Please, select your backup file or paste the text', type: 'error'};
$scope.loading = false;
return;
}

View File

@ -12,10 +12,6 @@ angular.module('copay.signin').controller('SigninController',
$scope.selectedWalletId = $scope.wallets.length ? $scope.wallets[0].id : null;
$scope.openPassword = '';
$scope.create = function(form) {
$location.path('setup');
};
$scope.open = function(form) {
if (form && form.$invalid) {
$rootScope.$flashMessage = { message: 'Please, enter required fields', type: 'error'};

View File

@ -19,7 +19,8 @@ function Wallet(opts) {
//required params
['storage', 'network', 'blockchain',
'requiredCopayers', 'totalCopayers', 'spendUnconfirmed',
'publicKeyRing', 'txProposals', 'privateKey', 'version'
'publicKeyRing', 'txProposals', 'privateKey', 'version',
'reconnectDelay'
].forEach(function(k) {
if (typeof opts[k] === 'undefined')
throw new Error('missing required option for Wallet: ' + k);
@ -164,6 +165,7 @@ Wallet.prototype._optsToObj = function() {
spendUnconfirmed: this.spendUnconfirmed,
requiredCopayers: this.requiredCopayers,
totalCopayers: this.totalCopayers,
reconnectDelay: this.reconnectDelay,
name: this.name,
netKey: this.netKey,
version: this.version,
@ -247,7 +249,7 @@ Wallet.prototype.netStart = function() {
console.log('[EMIT publicKeyRingUpdated:]'); //TODO
self.emit('publicKeyRingUpdated', true);
console.log('[CONNECT:]'); //TODO
self.connectToAll();
self.scheduleConnect();
console.log('[EMIT TxProposal]'); //TODO
self.emit('txProposalsUpdated');
self.store();
@ -255,6 +257,14 @@ Wallet.prototype.netStart = function() {
});
};
Wallet.prototype.scheduleConnect = function() {
var self = this;
if (self.network.isOnline()) {
self.connectToAll();
setTimeout(self.scheduleConnect.bind(self), self.reconnectDelay);
}
}
Wallet.prototype.getOnlinePeerIDs = function() {
return this.network.getOnlinePeerIDs();
};

View File

@ -115,6 +115,7 @@ WalletFactory.prototype.create = function(opts) {
opts.verbose = this.verbose;
opts.spendUnconfirmed = opts.spendUnconfirmed || this.walletDefaults.spendUnconfirmed;
opts.reconnectDelay = opts.reconnectDelay || this.walletDefaults.reconnectDelay;
opts.requiredCopayers = requiredCopayers;
opts.totalCopayers = totalCopayers;
opts.version = opts.version || this.version;
@ -146,7 +147,6 @@ WalletFactory.prototype.open = function(walletId, opts) {
this.storage._setPassphrase(opts.passphrase);
var w = this.read(walletId);
if (w) {
this._checkVersion(w.version);
w.store();

View File

@ -313,8 +313,8 @@ Network.prototype.setCopayerId = function(copayerId) {
};
Network.prototype.peerFromCopayer = function(hex) {
// TODO cache this.
Network.prototype.peerFromCopayer = function(hex) {
var SIN = bitcore.SIN;
return new SIN(new Buffer(hex,'hex')).toString();
};
@ -409,6 +409,10 @@ Network.prototype.send = function(copayerIds, payload, cb) {
};
Network.prototype.isOnline = function() {
return !!this.peer;
};
Network.prototype.connectTo = function(copayerId) {
var self = this;

View File

@ -15,16 +15,29 @@ module.exports = function(config) {
// list of files / patterns to load in the browser
files: [
//3rd Party Code
'lib/angular/angular.min.js',
'lib/angular-route/angular-route.js',
'lib/angular-mocks/angular-mocks.js',
'lib/bitcore.js',
'lib/socket.io.js',
//Configs
'config.js',
//App-specific Code
'js/*.js',
'js/**/*.js',
'lib/angular/angular.min.js',
'lib/angular-mocks/angular-mocks.js',
'lib/moment/moment.js',
'lib/angular-moment/angular-moment.js',
'lib/qrcode-generator/js/qrcode.js',
'lib/angular-qrcode/qrcode.js',
'lib/angular-route/angular-route.min.js',
'lib/angular-foundation/mm-foundation.min.js',
'lib/angular-foundation/mm-foundation-tpls.min.js',
'lib/peer.js',
'lib/bitcore/browser/bundle.js',
'lib/crypto-js/rollups/sha256.js',
'lib/crypto-js/rollups/pbkdf2.js',
'lib/crypto-js/rollups/aes.js',
'lib/file-saver/FileSaver.js',
'lib/socket.io.js',
'lib/sjcl.js',
'lib/ios-imagefile-megapixel/megapix-image.js',
'lib/qrcode-decoder-js/lib/qrcode-decoder.min.js',
'js/copayBundle.js',
//Test-Specific Code
'lib/chai/chai.js',
@ -34,18 +47,22 @@ module.exports = function(config) {
//Mocha stuff
'test/mocha.conf.js',
//Configs
'config.js',
//test files
'test/unit/**/*.js'
'test/unit/**/*.js',
//App-specific Code
'js/app.js',
'js/routes.js',
'js/directives.js',
'js/filters.js',
'js/services/*.js',
'js/controllers/*.js',
'js/init.js'
],
// list of files to exclude
exclude: [
'js/models/**/*.js',
],
exclude: [],
// preprocess matching files before serving them to the browser

View File

@ -7,8 +7,14 @@ function Network(opts) {
Network.parent=EventEmitter;
Network.prototype.start = function(openCallback, opts) {
Network.prototype.start = function(opts, cb) {
// start! :D
this.peer = {
options: {
token: "asd"
}
};
if (cb) cb();
};
Network.prototype.send = function(peerIds, data, cb) {
@ -24,4 +30,16 @@ Network.prototype.disconnect = function(cb) {
// disconect :c
};
Network.prototype.lockIncommingConnections = function() {
};
Network.prototype.getPeer = function() {
};
Network.prototype.connectToCopayers = function(cps) {
};
Network.prototype.isOnline = function() {
return true;
};
module.exports = require('soop')(Network);

View File

@ -2,6 +2,7 @@
var chai = chai || require('chai');
var should = chai.should();
var sinon = require('sinon');
var copay = copay || require('../copay');
var Wallet = require('../js/models/core/Wallet');
var Storage = require('./mocks/FakeStorage');
@ -20,6 +21,7 @@ describe('Wallet model', function() {
requiredCopayers: 3,
totalCopayers: 5,
spendUnconfirmed: 1,
reconnectDelay: 100,
blockchain: {
host: 'test.insight.is',
port: 80
@ -28,14 +30,19 @@ describe('Wallet model', function() {
};
it('should fail to create an instance', function() {
(function(){new Wallet(config)}).should.throw();
(function() {
new Wallet(config)
}).should.
throw ();
});
var createW = function(netKey) {
var c = JSON.parse(JSON.stringify(config));
if (netKey) c.netKey = netKey;
c.privateKey = new copay.PrivateKey({ networkName: c.networkName });
c.privateKey = new copay.PrivateKey({
networkName: c.networkName
});
c.publicKeyRing = new copay.PublicKeyRing({
networkName: c.networkName,
@ -82,16 +89,14 @@ describe('Wallet model', function() {
w.publicKeyRing.isComplete().should.equal(true);
});
var unspentTest = [
{
var unspentTest = [{
"address": "dummy",
"scriptPubKey": "dummy",
"txid": "2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1",
"vout": 1,
"amount": 10,
"confirmations": 7
}
];
}];
var createW2 = function(privateKeys) {
var netKey = 'T0FbU2JLby0=';
@ -147,7 +152,9 @@ describe('Wallet model', function() {
for (var i = 0; i < l.length; i++)
w.addressIsOwn(l[i]).should.equal(true);
w.addressIsOwn(l[0], {excludeMain:true}).should.equal(false);
w.addressIsOwn(l[0], {
excludeMain: true
}).should.equal(false);
w.addressIsOwn('mmHqhvTVbxgJTnePa7cfweSRjBCy9bQQXJ').should.equal(false);
w.addressIsOwn('mgtUfP9sTJ6vPLoBxZLPEccGpcjNVryaCX').should.equal(false);
@ -211,8 +218,26 @@ describe('Wallet model', function() {
});
it('decodeSecret check', function() {
(function(){Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoKM');}).should.not.throw();
(function(){Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoK');}).should.throw();
(function(){Wallet.decodeSecret('12345');}).should.throw();
(function() {
Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoKM');
}).should.not.
throw ();
(function() {
Wallet.decodeSecret('4fp61K187CsYmjoRQC5iAdC5eGmbCRsAAXfwEwetSQgHvZs27eWKaLaNHRoK');
}).should.
throw ();
(function() {
Wallet.decodeSecret('12345');
}).should.
throw ();
});
it('call reconnect after interval', function(done) {
var w = createW2();
var spy = sinon.spy(w, 'scheduleConnect');
w.netStart();
setTimeout(function() {
sinon.assert.callCount(spy, 10);
done();
}, 1000);
});
});

View File

@ -26,6 +26,7 @@ describe('WalletFactory model', function() {
requiredCopayers: 3,
totalCopayers: 5,
spendUnconfirmed: 1,
reconnectDelay: 100,
},
blockchain: {
host: 'test.insight.is',
@ -60,7 +61,7 @@ describe('WalletFactory model', function() {
});
it('#fromObj #toObj round trip', function() {
var o = '{"opts":{"id":"dbfe10c3fae71cea","spendUnconfirmed":1,"requiredCopayers":3,"totalCopayers":5,"netKey":"LppzFYqlgT0=","version":"0.0.5"},"publicKeyRing":{"walletId":"dbfe10c3fae71cea","networkName":"testnet","requiredCopayers":3,"totalCopayers":5,"changeAddressIndex":3,"addressIndex":3,"copayersExtPubKeys":["tpubD6NzVbkrYhZ4YGK8ZhZ8WVeBXNAAoTYjjpw9twCPiNGrGQYFktP3iVQkKmZNiFnUcAFMJRxJVJF6Nq9MDv2kiRceExJaHFbxUCGUiRhmy97","tpubD6NzVbkrYhZ4YKGDJkzWdQsQV3AcFemaQKiwNhV4RL8FHnBFvinidGdQtP8RKj3h34E65RkdtxjrggZYqsEwJ8RhhN2zz9VrjLnrnwbXYNc","tpubD6NzVbkrYhZ4YkDiewjb32Pp3Sz9WK2jpp37KnL7RCrHAyPpnLfgdfRnTdpn6DTWmPS7niywfgWiT42aJb1J6CjWVNmkgsMCxuw7j9DaGKB","tpubD6NzVbkrYhZ4XEtUAz4UUTWbprewbLTaMhR8NUvSJUEAh4Sidxr6rRPFdqqVRR73btKf13wUjds2i8vVCNo8sbKrAnyoTr3o5Y6QSbboQjk","tpubD6NzVbkrYhZ4Yj9AAt6xUVuGPVd8jXCrEE6V2wp7U3PFh8jYYvVad31b4VUXEYXzSnkco4fktu8r4icBsB2t3pCR3WnhVLedY2hxGcPFLKD"],"nicknameFor":{},"publicKeysCache":{"m/0/1/0":["0314368b8efa07e8c7dad30498d0a7e3aa575db1fef833347c6d381c1a33a17b17","02cfd95f89ab46bd3bd86954dd9f83dbab0cd2e4466dee587e8e4d8d733fc0d748","02568969eb6212fe946450be6c5b3353fc754a40b2cdc4aed501a8976fec371da8","0360f870a088ae0ef1c37035a9b6a462ca8dcdd5da275f4e2dcd19f44b81d3e7e4","0300ad8f1bded838b02e127bb25961fbcee718db2df81f680f889692acdcbdd73d"],"m/0/1/1":["024f97a9adb2fa9306c4e3d9244f5e5355c7e2c6b3dd4122ba804e17dc9729df5d","0214834a5adcbc4ad0f3bbbc1c280b8ac480387fcc9a1fd988c1526ed496d923c4","024e72338bd5e976375d076bd71a9649e9141b4cbfc9e16cb7109b354b3e913a05","0322045ea35c3118aa7ab9f2c9f182b0120956b0aa65cc72b9d093f145327a4b17","030dc2450c72df366c1960739c577a2efd4451070bd78effcb6f71d1bcd7dfc7a8"],"m/0/1/2":["0247de59deb66783b8f9b0c326234a9569d00866c2a73f599e77a4d0cab5cbce8f","0376e49f0ac3647404034aae0dc8dd927c34a634ef24ea36f56a272f75fce9539b","032fbaa2593bd1eea4a46e7ac15f15802cdd1eb65a7d5bc4364ddd9d52f0838234","03a81f2a7e1f7191aa0b0c6e0a4ccefc71edd3564e86014972fe338045f68d5a5a","02eb8a012ea9a709392502cacda6ef5115d6d2319ab470d546d9068ab941621a99"],"m/0/0/0":["036dcbd378b4352120d6b720b6294dd2d0dd02801fcf010bb69dadbec1f3999279","022089eedb85dc45d1efa418e1ea226588deedebc1d85acca15ff72783e33636c0","0388aa5fd432b74c56427396f350d236c3ca8f7b2f62da513ce4c2e6ff04a67e9c","02fc4caa7449db7483d2e1fccdacac6fa2f736278c758af9966402589b5632f13e","02e4a15b885d8b2d586f82fa85d16179644e60a154674bde0ec3004810b1bdab99"],"m/0/0/1":["039afa26b2f341c76c7b3c3d0672438f35ac6ebb67b1ddfefac9cd79b7b24418c1","021acaaf500d431ebc396f50630767b01c91ce98ae48e968775ceaad932b7e3b8e","022a947259c4a9f76d5e95c0849df31d01233df41d0d75d631b89317a48d8cddce","03d38d9f94217da780303d9a8987c86d737ef39683febc0cd6632cddbfa62186fd","0394d2581b307fe2af19721888d922aab58ab198ef88cedf9506177e30d807811e"],"m/0/0/2":["037825ffce15d34f9bd6c02bcda7701826706471a4d6ab5004eb965f98811c2098","023768dd6d3c71b7df5733ccda5b2d8b454d5b4c4179d91a6fda74db8b869a2406","021a79e91f003f308764d43039e9b5d56bc8f33ca2f4d30ec6cc5a37c0d09dc273","02437f1e388b273936319f79a5d22958ef5ebff9c8cd7b6f6f72518445b1e30867","0373b0881cb4fd02baa62589023fdfe9739c6148cf104d907549f2528eb80146f5"]}},"txProposals":{"txps":[],"walletId":"dbfe10c3fae71cea","networkName":"testnet"},"privateKey":{"extendedPrivateKeyString":"tprv8ZgxMBicQKsPeoHLg3tY75z4xLeEe8MqAXLNcRA6J6UTRvHV8VZTXznt9eoTmSk1fwSrwZtMhY3XkNsceJ14h6sCXHSWinRqMSSbY8tfhHi","networkName":"testnet","privateKeyCache":{}}}';
var o = '{"opts":{"id":"dbfe10c3fae71cea","spendUnconfirmed":1,"requiredCopayers":3,"totalCopayers":5,"reconnectDelay":100,"netKey":"LppzFYqlgT0=","version":"0.0.5"},"publicKeyRing":{"walletId":"dbfe10c3fae71cea","networkName":"testnet","requiredCopayers":3,"totalCopayers":5,"changeAddressIndex":3,"addressIndex":3,"copayersExtPubKeys":["tpubD6NzVbkrYhZ4YGK8ZhZ8WVeBXNAAoTYjjpw9twCPiNGrGQYFktP3iVQkKmZNiFnUcAFMJRxJVJF6Nq9MDv2kiRceExJaHFbxUCGUiRhmy97","tpubD6NzVbkrYhZ4YKGDJkzWdQsQV3AcFemaQKiwNhV4RL8FHnBFvinidGdQtP8RKj3h34E65RkdtxjrggZYqsEwJ8RhhN2zz9VrjLnrnwbXYNc","tpubD6NzVbkrYhZ4YkDiewjb32Pp3Sz9WK2jpp37KnL7RCrHAyPpnLfgdfRnTdpn6DTWmPS7niywfgWiT42aJb1J6CjWVNmkgsMCxuw7j9DaGKB","tpubD6NzVbkrYhZ4XEtUAz4UUTWbprewbLTaMhR8NUvSJUEAh4Sidxr6rRPFdqqVRR73btKf13wUjds2i8vVCNo8sbKrAnyoTr3o5Y6QSbboQjk","tpubD6NzVbkrYhZ4Yj9AAt6xUVuGPVd8jXCrEE6V2wp7U3PFh8jYYvVad31b4VUXEYXzSnkco4fktu8r4icBsB2t3pCR3WnhVLedY2hxGcPFLKD"],"nicknameFor":{},"publicKeysCache":{"m/0/1/0":["0314368b8efa07e8c7dad30498d0a7e3aa575db1fef833347c6d381c1a33a17b17","02cfd95f89ab46bd3bd86954dd9f83dbab0cd2e4466dee587e8e4d8d733fc0d748","02568969eb6212fe946450be6c5b3353fc754a40b2cdc4aed501a8976fec371da8","0360f870a088ae0ef1c37035a9b6a462ca8dcdd5da275f4e2dcd19f44b81d3e7e4","0300ad8f1bded838b02e127bb25961fbcee718db2df81f680f889692acdcbdd73d"],"m/0/1/1":["024f97a9adb2fa9306c4e3d9244f5e5355c7e2c6b3dd4122ba804e17dc9729df5d","0214834a5adcbc4ad0f3bbbc1c280b8ac480387fcc9a1fd988c1526ed496d923c4","024e72338bd5e976375d076bd71a9649e9141b4cbfc9e16cb7109b354b3e913a05","0322045ea35c3118aa7ab9f2c9f182b0120956b0aa65cc72b9d093f145327a4b17","030dc2450c72df366c1960739c577a2efd4451070bd78effcb6f71d1bcd7dfc7a8"],"m/0/1/2":["0247de59deb66783b8f9b0c326234a9569d00866c2a73f599e77a4d0cab5cbce8f","0376e49f0ac3647404034aae0dc8dd927c34a634ef24ea36f56a272f75fce9539b","032fbaa2593bd1eea4a46e7ac15f15802cdd1eb65a7d5bc4364ddd9d52f0838234","03a81f2a7e1f7191aa0b0c6e0a4ccefc71edd3564e86014972fe338045f68d5a5a","02eb8a012ea9a709392502cacda6ef5115d6d2319ab470d546d9068ab941621a99"],"m/0/0/0":["036dcbd378b4352120d6b720b6294dd2d0dd02801fcf010bb69dadbec1f3999279","022089eedb85dc45d1efa418e1ea226588deedebc1d85acca15ff72783e33636c0","0388aa5fd432b74c56427396f350d236c3ca8f7b2f62da513ce4c2e6ff04a67e9c","02fc4caa7449db7483d2e1fccdacac6fa2f736278c758af9966402589b5632f13e","02e4a15b885d8b2d586f82fa85d16179644e60a154674bde0ec3004810b1bdab99"],"m/0/0/1":["039afa26b2f341c76c7b3c3d0672438f35ac6ebb67b1ddfefac9cd79b7b24418c1","021acaaf500d431ebc396f50630767b01c91ce98ae48e968775ceaad932b7e3b8e","022a947259c4a9f76d5e95c0849df31d01233df41d0d75d631b89317a48d8cddce","03d38d9f94217da780303d9a8987c86d737ef39683febc0cd6632cddbfa62186fd","0394d2581b307fe2af19721888d922aab58ab198ef88cedf9506177e30d807811e"],"m/0/0/2":["037825ffce15d34f9bd6c02bcda7701826706471a4d6ab5004eb965f98811c2098","023768dd6d3c71b7df5733ccda5b2d8b454d5b4c4179d91a6fda74db8b869a2406","021a79e91f003f308764d43039e9b5d56bc8f33ca2f4d30ec6cc5a37c0d09dc273","02437f1e388b273936319f79a5d22958ef5ebff9c8cd7b6f6f72518445b1e30867","0373b0881cb4fd02baa62589023fdfe9739c6148cf104d907549f2528eb80146f5"]}},"txProposals":{"txps":[],"walletId":"dbfe10c3fae71cea","networkName":"testnet"},"privateKey":{"extendedPrivateKeyString":"tprv8ZgxMBicQKsPeoHLg3tY75z4xLeEe8MqAXLNcRA6J6UTRvHV8VZTXznt9eoTmSk1fwSrwZtMhY3XkNsceJ14h6sCXHSWinRqMSSbY8tfhHi","networkName":"testnet","privateKeyCache":{}}}';
var wf = new WalletFactory(config, '0.0.5');
var w = wf.fromObj(JSON.parse(o));
@ -75,9 +76,43 @@ describe('WalletFactory model', function() {
it('BIP32 length problem', function() {
var sconfig = {"networkName":"testnet","network":{"key":"g23ihfh82h35rf","host":"162.242.219.26","port":10009,"path":"/","maxPeers":15,"debug":3},"limits":{"totalCopayers":10,"mPlusN":15},"wallet":{"requiredCopayers":2,"totalCopayers":3,"spendUnconfirmed":1,"verbose":0},"blockchain":{"host":"test.insight.is","port":3001},"socket":{"host":"test.insight.is","port":3001},"verbose":0,"themes":["default"]};
var sconfig = {
"networkName": "testnet",
"network": {
"key": "g23ihfh82h35rf",
"host": "162.242.219.26",
"port": 10009,
"path": "/",
"maxPeers": 15,
"debug": 3
},
"limits": {
"totalCopayers": 10,
"mPlusN": 15
},
"wallet": {
"requiredCopayers": 2,
"totalCopayers": 3,
"reconnectDelay":100,
"spendUnconfirmed": 1,
"verbose": 0
},
"blockchain": {
"host": "test.insight.is",
"port": 3001
},
"socket": {
"host": "test.insight.is",
"port": 3001
},
"verbose": 0,
"themes": ["default"]
};
var wf = new WalletFactory(sconfig, '0.0.1');
var opts = {'requiredCopayers': 2, 'totalCopayers':3};
var opts = {
'requiredCopayers': 2,
'totalCopayers': 3
};
var w = wf.create(opts);
});

View File

@ -33,4 +33,9 @@ describe("Unit: Testing Controllers", function() {
expect(copayApp.TransactionsController).not.to.equal(null);
});
beforeEach(angular.mock.module('copay.walletFactory'));
it('should display a link to create a new wallet if no wallets in localStorage', inject(function(walletFactory) {
expect(walletFactory.storage.getWalletIds()).to.be.empty;
}));
});

View File

@ -17,10 +17,11 @@ describe("Unit: Testing Services", function() {
}));
beforeEach(angular.mock.module('copay.controllerUtils'));
// TODO
/*beforeEach(angular.mock.module('copay.controllerUtils'));
it('should contain a controllerUtils service', inject(function(controllerUtils) {
expect(controllerUtils).not.to.equal(null);
}));
*/
});