From bd8271d0ec79ea059da5485656cb2667bac7537e Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 26 Mar 2014 15:26:31 -0300 Subject: [PATCH 1/8] wallet model and test WIP --- js/models/wallet.js | 95 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 7 +++- test/mocha.opts | 1 + test/test.wallet.js | 84 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 js/models/wallet.js create mode 100644 test/mocha.opts create mode 100644 test/test.wallet.js diff --git a/js/models/wallet.js b/js/models/wallet.js new file mode 100644 index 000000000..02714fb1c --- /dev/null +++ b/js/models/wallet.js @@ -0,0 +1,95 @@ +'use strict'; +var imports = require('soop').imports(); +var bitcore = require('bitcore'); +var BIP32 = bitcore.BIP32; + +var Storage = imports.Storage || require('./Storage'); + +/* + * This follow Electrum convetion, as described on + * https://bitcointalk.org/index.php?topic=274182.0 + */ + +var PUBLIC_BRANCH = 'm/0/'; +var CHANGE_BRANCH = 'm/1/'; + +function Wallet(opts) { + opts = opts || {}; + + this.network = opts.network === 'livenet' ? + bitcore.networks.livenet : bitcore.networks.testnet; + + this.neededCosigners = opts.neededCosigners || 3; + this.totalCosigners = opts.totalCosigners || 5; + + this.dirty = 1; + this.cosignersBIP = []; + this.bip32 = new BIP32(opts.bytes || this.network.name); +} + + + +Wallet.read = function (BIP38password) { +}; + +Wallet.prototype.registeredCosigners = function () { + + // 1 is self. + return 1 + this.cosignersBIP.length; +}; + +Wallet.prototype.getExtendedPrivKey = function (BIP38password) { + if (!this.bip32) + throw new Error('no priv key defined on the wallet'); + + return this.bip32.extended_private_key_string(); +}; + + +Wallet.prototype.getExtendedPubKey = function () { + return this.bip32.extended_public_key_string(); +}; + + +// should receive an array also? +Wallet.prototype.addCosignerExtendedPubKey = function (newEpk) { + + if (this.haveAllNeededPubKeys()) + throw new Error('already have all needed key:' + this.totalCosigners); + + if (this.getExtendedPubKey() === newEpk) + throw new Error('already have that key (self kehy)'); + + + this.cosignersBIP.forEach(function(b){ + if (b.getExtendedPubKey() === newEpk) + throw new Error('already have that key'); + }); + + this.cosignersBIP.push(new Wallet({bytes:newEpk, network: this.network.name } )); +}; + + +Wallet.prototype.haveAllNeededPubKeys = function () { + return this.registeredCosigners() === this.totalCosigners; +}; + + +Wallet.prototype.getChangeAddress = function (index) { + + //index can be 0, 1, 2, etc. + if (! this.haveAllNeededPubKeys() ) + throw new Error('cosigners pub key missing'); +}; + + +Wallet.prototype.store = function () { +}; + + +// Input: Bitcore's Transaction, sign with ownPK +// return partially signed or fully signed tx +Wallet.prototype.signTx = function (tx, BIP38password) { +}; + +module.exports = require('soop')(Wallet); diff --git a/package.json b/package.json index bac19d810..7d2565c1e 100644 --- a/package.json +++ b/package.json @@ -18,11 +18,16 @@ "url": "https://github.com/bitpay/cosign/issues" }, "homepage": "https://github.com/bitpay/cosign", + "dependencies": { + "bitcore": "0.1.8", + "soop": "0.1.5" + }, "devDependencies": { "grunt-cli": "~0.1.13", "karma": "~0.12.1", "karma-chrome-launcher": "~0.1.2", "mocha": "~1.18.2", - "karma-mocha": "~0.1.3" + "karma-mocha": "~0.1.3", + "chai": "~1.9.0" } } diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 000000000..ec648f252 --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1 @@ +-R spec diff --git a/test/test.wallet.js b/test/test.wallet.js new file mode 100644 index 000000000..5834860e4 --- /dev/null +++ b/test/test.wallet.js @@ -0,0 +1,84 @@ +'use strict'; + +var chai = chai || require('chai'); +var should = chai.should(); +var bitcore = bitcore || require('../node_modules/bitcore'); + +var cosign = cosign || {}; + +var fakeStorage = {}; // TODO + +var Wallet = cosign.Wallet || require('soop').load('../js/models/Wallet', {Storage: fakeStorage}); + + +var config = { + network:'livenet', +}; + +describe('Wallet model', function() { + + it('should create an instance (livenet)', function () { + var w = new Wallet({ + network: config.network + }); + should.exist(w); + w.network.name.should.equal('livenet'); + }); + it('should create an instance (testnet)', function () { + var w2 = new Wallet(); + should.exist(w2); + w2.network.name.should.equal('testnet'); + }); + + it('should throw master priv key', function () { + var w2 = new Wallet(config); + should.exist(w2); + + w2.getExtendedPrivKey.bind().should.throw(); + }); + + + it('should create an master priv key', function () { + var w2 = new Wallet(config); + should.exist(w2); + should.exist(w2.getExtendedPrivKey()); + }); + + + it('should create an master pub key', function () { + var w2 = new Wallet(config); + should.exist(w2); + should.exist(w2.getExtendedPubKey()); + }); + + it('should fail to generate shared pub keys', function () { + var w2 = new Wallet(config); + should.exist(w2); + w2.getChangeAddress.bind(0).should.throw(); + + w2.registeredCosigners().should.equal(1); + w2.haveAllNeededPubKeys().should.equal(false); + }); + + it('should add and check when adding shared pub keys', function () { + var w = new Wallet(config); + should.exist(w); + + var cosigners = []; + for(var i=0; i<4; i++) { + var c = new Wallet(config); + w.haveAllNeededPubKeys().should.equal(false); + + w.addCosignerExtendedPubKey(c.getExtendedPubKey()); + cosigners.push(c); + } + w.haveAllNeededPubKeys().should.equal(true); + w.addCosignerExtendedPubKey.bind(w.getExtendedPubKey()).should.throw(); + w.addCosignerExtendedPubKey.bind(cosigners[0].getExtendedPubKey()).should.throw(); + w.addCosignerExtendedPubKey.bind((new Wallet(config)).getExtendedPubKey()).should.throw(); + }); + + +}); + + From 3bf02173c519b2425a905c66e3df942b34d5812e Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 26 Mar 2014 17:55:02 -0300 Subject: [PATCH 2/8] wallet model basic functions (WIP) --- js/models/wallet.js | 95 +++++++++++++++++++++++++++++++++++++++------ test/FakeStorage.js | 14 +++++++ test/test.wallet.js | 54 +++++++++++++++++++------- 3 files changed, 138 insertions(+), 25 deletions(-) create mode 100644 test/FakeStorage.js diff --git a/js/models/wallet.js b/js/models/wallet.js index 02714fb1c..924f10127 100644 --- a/js/models/wallet.js +++ b/js/models/wallet.js @@ -2,8 +2,12 @@ var imports = require('soop').imports(); var bitcore = require('bitcore'); var BIP32 = bitcore.BIP32; +var coinUtil= bitcore.util; var Storage = imports.Storage || require('./Storage'); +var log = imports.log || console.log; + +var storage = Storage.default(); /* * This follow Electrum convetion, as described on @@ -13,6 +17,7 @@ var Storage = imports.Storage || require('./Storage'); var PUBLIC_BRANCH = 'm/0/'; var CHANGE_BRANCH = 'm/1/'; + function Wallet(opts) { opts = opts || {}; @@ -22,23 +27,94 @@ function Wallet(opts) { this.neededCosigners = opts.neededCosigners || 3; this.totalCosigners = opts.totalCosigners || 5; + this.id = opts.id || Wallet.getRandomId(); + this.dirty = 1; - this.cosignersBIP = []; + this.cosignersWallets = []; this.bip32 = new BIP32(opts.bytes || this.network.name); } +Wallet.getRandomId = function () { + return coinUtil.generateNonce().toString('hex'); +}; -Wallet.read = function (BIP38password) { +Wallet.decrypt = function (passphrase, encPayload) { + log('[wallet.js.35] TODO READ: passphrase IGNORED'); + return encPayload; +}; + +Wallet.encrypt = function (passphrase, payload) { + log('[wallet.js.92] TODO: passphrase IGNORED'); + return payload; +}; + +Wallet.read = function (id, passphrase) { + var encPayload = storage.read(id); + if (!encPayload) + throw new Error('Could not find wallet data'); + var data; + try { + data = JSON.parse( Wallet.decrypt( passphrase, encPayload )); + } catch (e) { + throw new Error('error in storage: '+ e.toString()); + return; + }; + + if (data.id !== id) + throw new Error('Wrong id in data'); + + var config = { network: data.network === 'livenet' ? + bitcore.networks.livenet : bitcore.networks.testnet + }; + + var w = new Wallet(config); + + w.neededCosigners = data.neededCosigners; + w.totalCosigners = data.totalCosigners; + w.cosignersWallets = data.cosignersExtPubKeys.map( function (pk) { + return new Wallet({bytes:pk, network: w.network.name}); + }); + + w.dirty = 0; + + return w; +}; + +Wallet.prototype.serialize = function () { + return JSON.stringify({ + id: this.id, + network: this.network.name, + neededCosigners: this.neededCosigners, + totalCosigners: this.totalCosigners, + cosignersExtPubKeys: this.cosignersWallets.map( function (b) { + return b.getExtendedPubKey(); + }), + priv: this.getExtendedPrivKey(), + }); +}; + +Wallet.prototype.store = function (passphrase) { + + if (!this.id) + throw new Error('wallet has no id'); + + storage.save(this.id, Wallet.encrypt(passphrase,this.serialize())); + this.dirty = 0; + + return true; }; Wallet.prototype.registeredCosigners = function () { + if (! this.cosignersWallets) return 1; + // 1 is self. - return 1 + this.cosignersBIP.length; + return 1 + this.cosignersWallets.length; }; -Wallet.prototype.getExtendedPrivKey = function (BIP38password) { +Wallet.prototype.getExtendedPrivKey = function () { + if (!this.bip32) throw new Error('no priv key defined on the wallet'); @@ -61,12 +137,13 @@ Wallet.prototype.addCosignerExtendedPubKey = function (newEpk) { throw new Error('already have that key (self kehy)'); - this.cosignersBIP.forEach(function(b){ + this.cosignersWallets.forEach(function(b){ if (b.getExtendedPubKey() === newEpk) throw new Error('already have that key'); }); - this.cosignersBIP.push(new Wallet({bytes:newEpk, network: this.network.name } )); + this.cosignersWallets.push(new Wallet({bytes:newEpk, network: this.network.name } )); + this.dirty = 1; }; @@ -83,13 +160,9 @@ Wallet.prototype.getChangeAddress = function (index) { }; -Wallet.prototype.store = function () { -}; - - // Input: Bitcore's Transaction, sign with ownPK // return partially signed or fully signed tx -Wallet.prototype.signTx = function (tx, BIP38password) { +Wallet.prototype.signTx = function (tx) { }; module.exports = require('soop')(Wallet); diff --git a/test/FakeStorage.js b/test/FakeStorage.js new file mode 100644 index 000000000..164b526ba --- /dev/null +++ b/test/FakeStorage.js @@ -0,0 +1,14 @@ + +var FakeStorage = function(){ + this.storage = {}; +}; + +FakeStorage.prototype.read = function (id) { + return this.storage[id]; +}; + +FakeStorage.prototype.save = function(id, payload) { + this.storage[id] = payload; +} + +module.exports = require('soop')(FakeStorage); diff --git a/test/test.wallet.js b/test/test.wallet.js index 5834860e4..451b8c900 100644 --- a/test/test.wallet.js +++ b/test/test.wallet.js @@ -6,8 +6,7 @@ var bitcore = bitcore || require('../node_modules/bitcore'); var cosign = cosign || {}; -var fakeStorage = {}; // TODO - +var fakeStorage = require('./FakeStorage'); var Wallet = cosign.Wallet || require('soop').load('../js/models/Wallet', {Storage: fakeStorage}); @@ -15,6 +14,22 @@ var config = { network:'livenet', }; +var createW = function () { + var w = new Wallet(config); + should.exist(w); + + var cosigners = []; + for(var i=0; i<4; i++) { + var c = new Wallet(config); + w.haveAllNeededPubKeys().should.equal(false); + + w.addCosignerExtendedPubKey(c.getExtendedPubKey()); + cosigners.push(c); + } + + return {w:w, cosigners: cosigners}; +}; + describe('Wallet model', function() { it('should create an instance (livenet)', function () { @@ -51,33 +66,44 @@ describe('Wallet model', function() { should.exist(w2.getExtendedPubKey()); }); - it('should fail to generate shared pub keys', function () { + it('should fail to generate shared pub keys wo extended key', function () { var w2 = new Wallet(config); should.exist(w2); - w2.getChangeAddress.bind(0).should.throw(); w2.registeredCosigners().should.equal(1); w2.haveAllNeededPubKeys().should.equal(false); + + w2.getChangeAddress.bind(0).should.throw(); }); it('should add and check when adding shared pub keys', function () { - var w = new Wallet(config); - should.exist(w); + var k = createW(); + var w = k.w; + var cosigners = k.cosigners; - var cosigners = []; - for(var i=0; i<4; i++) { - var c = new Wallet(config); - w.haveAllNeededPubKeys().should.equal(false); - - w.addCosignerExtendedPubKey(c.getExtendedPubKey()); - cosigners.push(c); - } w.haveAllNeededPubKeys().should.equal(true); w.addCosignerExtendedPubKey.bind(w.getExtendedPubKey()).should.throw(); w.addCosignerExtendedPubKey.bind(cosigners[0].getExtendedPubKey()).should.throw(); w.addCosignerExtendedPubKey.bind((new Wallet(config)).getExtendedPubKey()).should.throw(); }); + it('show be able to store and retrieve', function () { + var k = createW(); + var w = k.w; + var cosigners = k.cosigners; + + w.store().should.equal(true); + var ID = w.id; + delete w['id']; + w.store.bind().should.throw(); + + var w2 = Wallet.read(ID); + w2.haveAllNeededPubKeys().should.equal(true); + w2.addCosignerExtendedPubKey.bind(w.getExtendedPubKey()).should.throw(); + w2.addCosignerExtendedPubKey.bind(cosigners[0].getExtendedPubKey()).should.throw(); + w2.addCosignerExtendedPubKey.bind((new Wallet(config)).getExtendedPubKey()).should.throw(); + + }); }); From b57c1544bbdc683debe36a3895ee04f87743bc76 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 26 Mar 2014 22:00:42 -0300 Subject: [PATCH 3/8] get Script Address for Wallet --- js/models/wallet.js | 67 +++++++++++++++++++++++++++++++++++++-------- test/test.wallet.js | 27 ++++++++++++++---- 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/js/models/wallet.js b/js/models/wallet.js index 924f10127..b88832dac 100644 --- a/js/models/wallet.js +++ b/js/models/wallet.js @@ -2,6 +2,8 @@ var imports = require('soop').imports(); var bitcore = require('bitcore'); var BIP32 = bitcore.BIP32; +var Address = bitcore.Address; +var Script = bitcore.Script; var coinUtil= bitcore.util; var Storage = imports.Storage || require('./Storage'); @@ -24,7 +26,7 @@ function Wallet(opts) { this.network = opts.network === 'livenet' ? bitcore.networks.livenet : bitcore.networks.testnet; - this.neededCosigners = opts.neededCosigners || 3; + this.requiredCosigners = opts.neededCosigners || 3; this.totalCosigners = opts.totalCosigners || 5; this.id = opts.id || Wallet.getRandomId(); @@ -32,6 +34,9 @@ function Wallet(opts) { this.dirty = 1; this.cosignersWallets = []; this.bip32 = new BIP32(opts.bytes || this.network.name); + + this.changeAddress + } @@ -70,7 +75,7 @@ Wallet.read = function (id, passphrase) { var w = new Wallet(config); - w.neededCosigners = data.neededCosigners; + w.requiredCosigners = data.neededCosigners; w.totalCosigners = data.totalCosigners; w.cosignersWallets = data.cosignersExtPubKeys.map( function (pk) { return new Wallet({bytes:pk, network: w.network.name}); @@ -85,7 +90,7 @@ Wallet.prototype.serialize = function () { return JSON.stringify({ id: this.id, network: this.network.name, - neededCosigners: this.neededCosigners, + requiredCosigners: this.neededCosigners, totalCosigners: this.totalCosigners, cosignersExtPubKeys: this.cosignersWallets.map( function (b) { return b.getExtendedPubKey(); @@ -127,11 +132,22 @@ Wallet.prototype.getExtendedPubKey = function () { }; +Wallet.prototype.haveAllRequiredPubKeys = function () { + return this.registeredCosigners() === this.totalCosigners; +}; + +Wallet.prototype._checkKeys = function() { + + if (!this.haveAllRequiredPubKeys()) + throw new Error('dont have required keys yet'); +}; + + // should receive an array also? Wallet.prototype.addCosignerExtendedPubKey = function (newEpk) { - if (this.haveAllNeededPubKeys()) - throw new Error('already have all needed key:' + this.totalCosigners); + if (this.haveAllRequiredPubKeys()) + throw new Error('already have all required key:' + this.totalCosigners); if (this.getExtendedPubKey() === newEpk) throw new Error('already have that key (self kehy)'); @@ -147,18 +163,47 @@ Wallet.prototype.addCosignerExtendedPubKey = function (newEpk) { }; -Wallet.prototype.haveAllNeededPubKeys = function () { - return this.registeredCosigners() === this.totalCosigners; +Wallet.prototype.getPubKey = function (index,isChange) { + + var path = (isChange ? CHANGE_BRANCH : PUBLIC_BRANCH) + index; + var bip32 = this.bip32.derive(path); + var pub = bip32.eckey.public; + return pub; }; -Wallet.prototype.getChangeAddress = function (index) { +Wallet.prototype.getAddress = function (index, isChange) { + this._checkKeys(); - //index can be 0, 1, 2, etc. - if (! this.haveAllNeededPubKeys() ) - throw new Error('cosigners pub key missing'); + var pubkey = []; + var l = this.cosignersWallets.length; + for(var i=0; i Date: Wed, 26 Mar 2014 23:55:46 -0300 Subject: [PATCH 4/8] add pubkey sorting --- js/models/wallet.js | 67 ++++++++++++++++++++++++++++++++++++--------- test/test.wallet.js | 22 +++++++-------- 2 files changed, 65 insertions(+), 24 deletions(-) diff --git a/js/models/wallet.js b/js/models/wallet.js index b88832dac..857d06a0b 100644 --- a/js/models/wallet.js +++ b/js/models/wallet.js @@ -14,6 +14,10 @@ var storage = Storage.default(); /* * This follow Electrum convetion, as described on * https://bitcointalk.org/index.php?topic=274182.0 + * + * We should probably adapt the next standard once its ready as discussed at: + * http://sourceforge.net/p/bitcoin/mailman/message/32148600/ + * */ var PUBLIC_BRANCH = 'm/0/'; @@ -26,7 +30,7 @@ function Wallet(opts) { this.network = opts.network === 'livenet' ? bitcore.networks.livenet : bitcore.networks.testnet; - this.requiredCosigners = opts.neededCosigners || 3; + this.requiredCosigners = opts.requiredCosigners || 3; this.totalCosigners = opts.totalCosigners || 5; this.id = opts.id || Wallet.getRandomId(); @@ -35,7 +39,8 @@ function Wallet(opts) { this.cosignersWallets = []; this.bip32 = new BIP32(opts.bytes || this.network.name); - this.changeAddress + this.changeAddressIndex=0; + this.addressIndex=0; } @@ -93,9 +98,9 @@ Wallet.prototype.serialize = function () { requiredCosigners: this.neededCosigners, totalCosigners: this.totalCosigners, cosignersExtPubKeys: this.cosignersWallets.map( function (b) { - return b.getExtendedPubKey(); + return b.getMasterExtendedPubKey(); }), - priv: this.getExtendedPrivKey(), + priv: this.getMasterExtendedPrivKey(), }); }; @@ -118,7 +123,7 @@ Wallet.prototype.registeredCosigners = function () { return 1 + this.cosignersWallets.length; }; -Wallet.prototype.getExtendedPrivKey = function () { +Wallet.prototype.getMasterExtendedPrivKey = function () { if (!this.bip32) throw new Error('no priv key defined on the wallet'); @@ -127,7 +132,7 @@ Wallet.prototype.getExtendedPrivKey = function () { }; -Wallet.prototype.getExtendedPubKey = function () { +Wallet.prototype.getMasterExtendedPubKey = function () { return this.bip32.extended_public_key_string(); }; @@ -149,12 +154,12 @@ Wallet.prototype.addCosignerExtendedPubKey = function (newEpk) { if (this.haveAllRequiredPubKeys()) throw new Error('already have all required key:' + this.totalCosigners); - if (this.getExtendedPubKey() === newEpk) - throw new Error('already have that key (self kehy)'); + if (this.getMasterExtendedPubKey() === newEpk) + throw new Error('already have that key (self key)'); this.cosignersWallets.forEach(function(b){ - if (b.getExtendedPubKey() === newEpk) + if (b.getMasterExtendedPubKey() === newEpk) throw new Error('already have that key'); }); @@ -172,17 +177,53 @@ Wallet.prototype.getPubKey = function (index,isChange) { }; -Wallet.prototype.getAddress = function (index, isChange) { + + +Wallet.prototype.getCosignersPubKeys = function (index, isChange) { this._checkKeys(); - var pubkey = []; + var pubKeys = []; var l = this.cosignersWallets.length; for(var i=0; i buf1.length ? buf1.length : buf2.length; + for (var i = 0; i <= len; i++) { + if (buf1[i] === undefined) + return -1; //shorter strings come first + if (buf2[i] === undefined) + return 1; + if (buf1[i] < buf2[i]) + return -1; + if (buf1[i] > buf2[i]) + return 1; + else + continue; + } + return 0; + }); +}; + + + +Wallet.prototype.getAddress = function (index, isChange) { + + var pubKeys = this.getCosignersSortedPubKeys(index, isChange); + var version = this.network.addressScript; - var script = Script.createMultisig(this.requiredCosigners, pubkey); + var script = Script.createMultisig(this.requiredCosigners, pubKeys); var buf = script.buffer; var hash = coinUtil.sha256ripe160(buf); var addr = new Address(version, hash); diff --git a/test/test.wallet.js b/test/test.wallet.js index eb6115d83..8c0ff36c1 100644 --- a/test/test.wallet.js +++ b/test/test.wallet.js @@ -24,7 +24,7 @@ var createW = function () { var c = new Wallet(config); w.haveAllRequiredPubKeys().should.equal(false); - w.addCosignerExtendedPubKey(c.getExtendedPubKey()); + w.addCosignerExtendedPubKey(c.getMasterExtendedPubKey()); cosigners.push(c); } @@ -50,21 +50,21 @@ describe('Wallet model', function() { var w2 = new Wallet(config); should.exist(w2); - w2.getExtendedPrivKey.bind().should.throw(); + w2.getMasterExtendedPrivKey.bind().should.throw(); }); it('should create an master priv key', function () { var w2 = new Wallet(config); should.exist(w2); - should.exist(w2.getExtendedPrivKey()); + should.exist(w2.getMasterExtendedPrivKey()); }); it('should create an master pub key', function () { var w2 = new Wallet(config); should.exist(w2); - should.exist(w2.getExtendedPubKey()); + should.exist(w2.getMasterExtendedPubKey()); }); it('should fail to generate shared pub keys wo extended key', function () { @@ -83,9 +83,9 @@ describe('Wallet model', function() { var cosigners = k.cosigners; w.haveAllRequiredPubKeys().should.equal(true); - w.addCosignerExtendedPubKey.bind(w.getExtendedPubKey()).should.throw(); - w.addCosignerExtendedPubKey.bind(cosigners[0].getExtendedPubKey()).should.throw(); - w.addCosignerExtendedPubKey.bind((new Wallet(config)).getExtendedPubKey()).should.throw(); + w.addCosignerExtendedPubKey.bind(w.getMasterExtendedPubKey()).should.throw(); + w.addCosignerExtendedPubKey.bind(cosigners[0].getMasterExtendedPubKey()).should.throw(); + w.addCosignerExtendedPubKey.bind((new Wallet(config)).getMasterExtendedPubKey()).should.throw(); }); it('show be able to store and retrieve', function () { @@ -100,14 +100,14 @@ describe('Wallet model', function() { var w2 = Wallet.read(ID); w2.haveAllRequiredPubKeys().should.equal(true); - w2.addCosignerExtendedPubKey.bind(w.getExtendedPubKey()).should.throw(); - w2.addCosignerExtendedPubKey.bind(cosigners[0].getExtendedPubKey()).should.throw(); - w2.addCosignerExtendedPubKey.bind((new Wallet(config)).getExtendedPubKey()).should.throw(); + w2.addCosignerExtendedPubKey.bind(w.getMasterExtendedPubKey()).should.throw(); + w2.addCosignerExtendedPubKey.bind(cosigners[0].getMasterExtendedPubKey()).should.throw(); + w2.addCosignerExtendedPubKey.bind((new Wallet(config)).getMasterExtendedPubKey()).should.throw(); }); - it('should create some p2sh address', function () { + it('should create some p2sh addresses', function () { var k = createW(); var w = k.w; From cf1732fc44ce31dd974f3c13d300c5a8f8117ac5 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 27 Mar 2014 01:18:29 -0300 Subject: [PATCH 5/8] add getAddresses to return all wallet\'s addresses --- js/models/wallet.js | 46 +++++++++++++++++++++++++++++++++++---------- test/test.wallet.js | 22 +++++++++++++++++++++- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/js/models/wallet.js b/js/models/wallet.js index 857d06a0b..3fb113c37 100644 --- a/js/models/wallet.js +++ b/js/models/wallet.js @@ -1,15 +1,16 @@ 'use strict'; -var imports = require('soop').imports(); -var bitcore = require('bitcore'); -var BIP32 = bitcore.BIP32; -var Address = bitcore.Address; -var Script = bitcore.Script; -var coinUtil= bitcore.util; +var imports = require('soop').imports(); +var bitcore = require('bitcore'); +var BIP32 = bitcore.BIP32; +var Address = bitcore.Address; +var Script = bitcore.Script; +var coinUtil = bitcore.util; +var Transaction = bitcore.Transaction; -var Storage = imports.Storage || require('./Storage'); -var log = imports.log || console.log; +var Storage = imports.Storage || require('./Storage'); +var log = imports.log || console.log; -var storage = Storage.default(); +var storage = Storage.default(); /* * This follow Electrum convetion, as described on @@ -220,6 +221,12 @@ Wallet.prototype.getCosignersSortedPubKeys = function(index, isChange) { Wallet.prototype.getAddress = function (index, isChange) { + if ( (isChange && index > this.changeAddressIndex) + || (!isChange && index > this.addressIndex)) { + log('Out of bounds at getAddress: Index %d isChange: %d', index, isChange); + throw new Error('index out of bound'); + } + var pubKeys = this.getCosignersSortedPubKeys(index, isChange); var version = this.network.addressScript; @@ -244,7 +251,26 @@ Wallet.prototype.createAddress = function(isChange) { return ret; }; - + +Wallet.prototype.getAddresses = function() { + var ret = []; + + for (var i=0; i Date: Thu, 27 Mar 2014 12:14:49 -0300 Subject: [PATCH 6/8] createTX to wallet --- js/models/wallet.js | 7 +++-- test/test.wallet.js | 69 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/js/models/wallet.js b/js/models/wallet.js index 3fb113c37..5d0ad3642 100644 --- a/js/models/wallet.js +++ b/js/models/wallet.js @@ -6,6 +6,7 @@ var Address = bitcore.Address; var Script = bitcore.Script; var coinUtil = bitcore.util; var Transaction = bitcore.Transaction; +var buffertools = bitcore.buffertools; var Storage = imports.Storage || require('./Storage'); var log = imports.log || console.log; @@ -47,7 +48,7 @@ function Wallet(opts) { Wallet.getRandomId = function () { - return coinUtil.generateNonce().toString('hex'); + return buffertools.toHex(coinUtil.generateNonce()); }; Wallet.decrypt = function (passphrase, encPayload) { @@ -265,9 +266,9 @@ Wallet.prototype.getAddresses = function() { return ret; }; -Wallet.prototype.createTx = function(utxos,outs) { +Wallet.prototype.createTx = function(utxos,outs, changeAddress) { var opts = { - remainderAddress: this.createAddress(1), + remainderAddress: changeAddress || this.createAddress(1), }; return Transaction.create(utxos, outs, opts); }; diff --git a/test/test.wallet.js b/test/test.wallet.js index 6b28b9433..22a2d04f2 100644 --- a/test/test.wallet.js +++ b/test/test.wallet.js @@ -1,33 +1,40 @@ 'use strict'; -var chai = chai || require('chai'); -var should = chai.should(); -var bitcore = bitcore || require('../node_modules/bitcore'); +var chai = chai || require('chai'); +var should = chai.should(); +var bitcore = bitcore || require('../node_modules/bitcore'); +var Address = bitcore.Address; +var buffertools = bitcore.buffertools; +var cosign = cosign || {}; +var fakeStorage = require('./FakeStorage'); +var Wallet = cosign.Wallet || require('soop').load('../js/models/Wallet', {Storage: fakeStorage}); -var cosign = cosign || {}; +var aMasterPrivKey = 'tprv8ZgxMBicQKsPdSVTiWXEqCCzqRaRr9EAQdn5UVMpT9UHX67Dh1FmzEMbavPumpAicsUm2XvC6NTdcWB89yN5DUWx5HQ7z3KByUg7Ht74VRZ'; -var Address = bitcore.Address; -var fakeStorage = require('./FakeStorage'); -var Wallet = cosign.Wallet || require('soop').load('../js/models/Wallet', {Storage: fakeStorage}); - var config = { network:'livenet', }; -var createW = function () { +var createW = function (network, bytes) { + + var config = { + network: network || 'livenet', + }; + if (bytes) config.bytes = bytes; + var w = new Wallet(config); should.exist(w); var cosigners = []; for(var i=0; i<4; i++) { + delete config['bytes']; var c = new Wallet(config); w.haveAllRequiredPubKeys().should.equal(false); w.addCosignerExtendedPubKey(c.getMasterExtendedPubKey()); cosigners.push(c); } - return {w:w, cosigners: cosigners}; }; @@ -142,6 +149,48 @@ describe('Wallet model', function() { } }); + + it('should create a TX', function () { + var k = createW('testnet', aMasterPrivKey); + var w = k.w; + var as=[], j=0; + for(var isChange=0; isChange<2; isChange++) + for(var i=0; i<6; i++) + as[j++] = w.createAddress(isChange); + + var utxos = [ + { + address: as[0], + txid: "2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1", + scriptPubKey: "76a9146ce4e1163eb18939b1440c42844d5f0261c0338288ac", + vout: 1, + amount: 1, + confirmations: 3 + }, + { + address: as[1], + txid: "2ac165fa7a3a2b535d106a0041c7568d03b531e58aeccdd3199d7289ab12cfc1", + scriptPubKey: "76a9146ce4e1163eb18939b1440c42844d5f0261c0338288ac", + vout: 1, + amount: 1.01, + confirmations: 7 + }, + ]; + + + var outs=[{ + address: 'mfwSGKeLEGdd1YwsZ1TkoEeKNk8TTWqXLC', + amount: 1.5, + }]; + var ret = w.createTx(utxos, outs, '2Mu1GwdF9X1LLxXNxtfNChi5ngBMJxi2csv'); + var tx=ret.tx; + should.exist(tx); + tx.ins.length.should.equal(2); + tx.outs.length.should.equal(2); + buffertools.toHex(tx.serialize()).should.equal('0100000002c1cf12ab89729d19d3cdec8ae531b5038d56c741006a105d532b3a7afa65c12a0100000000ffffffffc1cf12ab89729d19d3cdec8ae531b5038d56c741006a105d532b3a7afa65c12a0100000000ffffffff0280d1f008000000001976a91404a154d56e5455dc87f15e293b8872f31d03a12c88acb00b0a030000000017a914134ce4e4ea92b6cb0008803cafe25f197ff1dcb98700000000'); + + }); + }); From d33cf4a751e8f63d31cfa36f7244b9cbf882a88b Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Fri, 4 Apr 2014 15:57:28 -0300 Subject: [PATCH 7/8] change Wallet to PublicKeyRing --- js/models/{wallet.js => PublicKeyRing.js} | 142 +++++----------- test/test.publickeyring.js | 140 ++++++++++++++++ test/test.wallet.js | 196 ---------------------- 3 files changed, 184 insertions(+), 294 deletions(-) rename js/models/{wallet.js => PublicKeyRing.js} (50%) create mode 100644 test/test.publickeyring.js delete mode 100644 test/test.wallet.js diff --git a/js/models/wallet.js b/js/models/PublicKeyRing.js similarity index 50% rename from js/models/wallet.js rename to js/models/PublicKeyRing.js index 5d0ad3642..fd29e26c8 100644 --- a/js/models/wallet.js +++ b/js/models/PublicKeyRing.js @@ -26,48 +26,47 @@ var PUBLIC_BRANCH = 'm/0/'; var CHANGE_BRANCH = 'm/1/'; -function Wallet(opts) { +function PublicKeyRing(opts) { opts = opts || {}; this.network = opts.network === 'livenet' ? bitcore.networks.livenet : bitcore.networks.testnet; - this.requiredCosigners = opts.requiredCosigners || 3; - this.totalCosigners = opts.totalCosigners || 5; + this.requiredCopayers = opts.requiredCopayers || 3; + this.totalCopayers = opts.totalCopayers || 5; - this.id = opts.id || Wallet.getRandomId(); + this.id = opts.id || PublicKeyRing.getRandomId(); this.dirty = 1; - this.cosignersWallets = []; + this.copayersWallets = []; this.bip32 = new BIP32(opts.bytes || this.network.name); this.changeAddressIndex=0; this.addressIndex=0; - } -Wallet.getRandomId = function () { +PublicKeyRing.getRandomId = function () { return buffertools.toHex(coinUtil.generateNonce()); }; -Wallet.decrypt = function (passphrase, encPayload) { +PublicKeyRing.decrypt = function (passphrase, encPayload) { log('[wallet.js.35] TODO READ: passphrase IGNORED'); return encPayload; }; -Wallet.encrypt = function (passphrase, payload) { +PublicKeyRing.encrypt = function (passphrase, payload) { log('[wallet.js.92] TODO: passphrase IGNORED'); return payload; }; -Wallet.read = function (id, passphrase) { +PublicKeyRing.read = function (id, passphrase) { var encPayload = storage.read(id); if (!encPayload) throw new Error('Could not find wallet data'); var data; try { - data = JSON.parse( Wallet.decrypt( passphrase, encPayload )); + data = JSON.parse( PublicKeyRing.decrypt( passphrase, encPayload )); } catch (e) { throw new Error('error in storage: '+ e.toString()); return; @@ -80,12 +79,12 @@ Wallet.read = function (id, passphrase) { bitcore.networks.livenet : bitcore.networks.testnet }; - var w = new Wallet(config); + var w = new PublicKeyRing(config); - w.requiredCosigners = data.neededCosigners; - w.totalCosigners = data.totalCosigners; - w.cosignersWallets = data.cosignersExtPubKeys.map( function (pk) { - return new Wallet({bytes:pk, network: w.network.name}); + w.requiredCopayers = data.neededCopayers; + w.totalCopayers = data.totalCopayers; + w.copayersWallets = data.copayersExtPubKeys.map( function (pk) { + return new PublicKeyRing({bytes:pk, network: w.network.name}); }); w.dirty = 0; @@ -93,57 +92,47 @@ Wallet.read = function (id, passphrase) { return w; }; -Wallet.prototype.serialize = function () { +PublicKeyRing.prototype.serialize = function () { return JSON.stringify({ id: this.id, network: this.network.name, - requiredCosigners: this.neededCosigners, - totalCosigners: this.totalCosigners, - cosignersExtPubKeys: this.cosignersWallets.map( function (b) { + requiredCopayers: this.neededCopayers, + totalCopayers: this.totalCopayers, + copayersExtPubKeys: this.copayersWallets.map( function (b) { return b.getMasterExtendedPubKey(); }), - priv: this.getMasterExtendedPrivKey(), }); }; -Wallet.prototype.store = function (passphrase) { +PublicKeyRing.prototype.store = function (passphrase) { if (!this.id) throw new Error('wallet has no id'); - storage.save(this.id, Wallet.encrypt(passphrase,this.serialize())); + storage.save(this.id, PublicKeyRing.encrypt(passphrase,this.serialize())); this.dirty = 0; return true; }; -Wallet.prototype.registeredCosigners = function () { - if (! this.cosignersWallets) return 1; +PublicKeyRing.prototype.registeredCopayers = function () { + if (! this.copayersWallets) return 1; // 1 is self. - return 1 + this.cosignersWallets.length; + return 1 + this.copayersWallets.length; }; -Wallet.prototype.getMasterExtendedPrivKey = function () { - - if (!this.bip32) - throw new Error('no priv key defined on the wallet'); - - return this.bip32.extended_private_key_string(); +PublicKeyRing.prototype.getMasterExtendedPubKey = function () { + return this.bip32.extendedPublicKeyString(); }; -Wallet.prototype.getMasterExtendedPubKey = function () { - return this.bip32.extended_public_key_string(); +PublicKeyRing.prototype.haveAllRequiredPubKeys = function () { + return this.registeredCopayers() === this.totalCopayers; }; - -Wallet.prototype.haveAllRequiredPubKeys = function () { - return this.registeredCosigners() === this.totalCosigners; -}; - -Wallet.prototype._checkKeys = function() { +PublicKeyRing.prototype._checkKeys = function() { if (!this.haveAllRequiredPubKeys()) throw new Error('dont have required keys yet'); @@ -151,26 +140,26 @@ Wallet.prototype._checkKeys = function() { // should receive an array also? -Wallet.prototype.addCosignerExtendedPubKey = function (newEpk) { +PublicKeyRing.prototype.addCopayerExtendedPubKey = function (newEpk) { if (this.haveAllRequiredPubKeys()) - throw new Error('already have all required key:' + this.totalCosigners); + throw new Error('already have all required key:' + this.totalCopayers); if (this.getMasterExtendedPubKey() === newEpk) throw new Error('already have that key (self key)'); - this.cosignersWallets.forEach(function(b){ + this.copayersWallets.forEach(function(b){ if (b.getMasterExtendedPubKey() === newEpk) throw new Error('already have that key'); }); - this.cosignersWallets.push(new Wallet({bytes:newEpk, network: this.network.name } )); + this.copayersWallets.push(new PublicKeyRing({bytes:newEpk, network: this.network.name } )); this.dirty = 1; }; -Wallet.prototype.getPubKey = function (index,isChange) { +PublicKeyRing.prototype.getPubKey = function (index,isChange) { var path = (isChange ? CHANGE_BRANCH : PUBLIC_BRANCH) + index; var bip32 = this.bip32.derive(path); @@ -178,49 +167,19 @@ Wallet.prototype.getPubKey = function (index,isChange) { return pub; }; - - - -Wallet.prototype.getCosignersPubKeys = function (index, isChange) { +PublicKeyRing.prototype.getCopayersPubKeys = function (index, isChange) { this._checkKeys(); var pubKeys = []; - var l = this.cosignersWallets.length; + var l = this.copayersWallets.length; for(var i=0; i buf1.length ? buf1.length : buf2.length; - for (var i = 0; i <= len; i++) { - if (buf1[i] === undefined) - return -1; //shorter strings come first - if (buf2[i] === undefined) - return 1; - if (buf1[i] < buf2[i]) - return -1; - if (buf1[i] > buf2[i]) - return 1; - else - continue; - } - return 0; - }); -}; - - - -Wallet.prototype.getAddress = function (index, isChange) { +PublicKeyRing.prototype.getAddress = function (index, isChange) { if ( (isChange && index > this.changeAddressIndex) || (!isChange && index > this.addressIndex)) { @@ -228,10 +187,9 @@ Wallet.prototype.getAddress = function (index, isChange) { throw new Error('index out of bound'); } - var pubKeys = this.getCosignersSortedPubKeys(index, isChange); - + var pubKeys = this.getCopayersPubKeys(); var version = this.network.addressScript; - var script = Script.createMultisig(this.requiredCosigners, pubKeys); + var script = Script.createMultisig(this.requiredCopayers, pubKeys); var buf = script.buffer; var hash = coinUtil.sha256ripe160(buf); var addr = new Address(version, hash); @@ -239,11 +197,11 @@ Wallet.prototype.getAddress = function (index, isChange) { return addrStr; }; -Wallet.prototype.createAddress = function(isChange) { +//generate a new address, update index. +PublicKeyRing.prototype.generateAddress = function(isChange) { var ret = this.getAddress(isChange ? this.changeAddressIndex : this.addressIndex, isChange); - if (isChange) this.addressIndex++; else @@ -253,7 +211,7 @@ Wallet.prototype.createAddress = function(isChange) { }; -Wallet.prototype.getAddresses = function() { +PublicKeyRing.prototype.getAddresses = function() { var ret = []; for (var i=0; i Date: Fri, 4 Apr 2014 17:16:10 -0300 Subject: [PATCH 8/8] public key ring, symmetric for all holders --- js/models/PublicKeyRing.js | 88 ++++++++++++++++++++------------------ test/test.publickeyring.js | 32 +++++--------- 2 files changed, 57 insertions(+), 63 deletions(-) diff --git a/js/models/PublicKeyRing.js b/js/models/PublicKeyRing.js index fd29e26c8..a078c51f3 100644 --- a/js/models/PublicKeyRing.js +++ b/js/models/PublicKeyRing.js @@ -1,4 +1,7 @@ + 'use strict'; + + var imports = require('soop').imports(); var bitcore = require('bitcore'); var BIP32 = bitcore.BIP32; @@ -25,7 +28,6 @@ var storage = Storage.default(); var PUBLIC_BRANCH = 'm/0/'; var CHANGE_BRANCH = 'm/1/'; - function PublicKeyRing(opts) { opts = opts || {}; @@ -38,8 +40,7 @@ function PublicKeyRing(opts) { this.id = opts.id || PublicKeyRing.getRandomId(); this.dirty = 1; - this.copayersWallets = []; - this.bip32 = new BIP32(opts.bytes || this.network.name); + this.copayersBIP32 = []; this.changeAddressIndex=0; this.addressIndex=0; @@ -83,8 +84,10 @@ PublicKeyRing.read = function (id, passphrase) { w.requiredCopayers = data.neededCopayers; w.totalCopayers = data.totalCopayers; - w.copayersWallets = data.copayersExtPubKeys.map( function (pk) { - return new PublicKeyRing({bytes:pk, network: w.network.name}); + +// this.bip32 = ; + w.copayersBIP32 = data.copayersExtPubKeys.map( function (pk) { + return new BIP32(pk); }); w.dirty = 0; @@ -98,12 +101,13 @@ PublicKeyRing.prototype.serialize = function () { network: this.network.name, requiredCopayers: this.neededCopayers, totalCopayers: this.totalCopayers, - copayersExtPubKeys: this.copayersWallets.map( function (b) { - return b.getMasterExtendedPubKey(); + copayersExtPubKeys: this.copayersBIP32.map( function (b) { + return b.extendedPublicKeyString(); }), }); }; + PublicKeyRing.prototype.store = function (passphrase) { if (!this.id) @@ -116,16 +120,9 @@ PublicKeyRing.prototype.store = function (passphrase) { }; PublicKeyRing.prototype.registeredCopayers = function () { - if (! this.copayersWallets) return 1; - - - // 1 is self. - return 1 + this.copayersWallets.length; + return this.copayersBIP32.length; }; -PublicKeyRing.prototype.getMasterExtendedPubKey = function () { - return this.bip32.extendedPublicKeyString(); -}; PublicKeyRing.prototype.haveAllRequiredPubKeys = function () { @@ -139,62 +136,69 @@ PublicKeyRing.prototype._checkKeys = function() { }; -// should receive an array also? -PublicKeyRing.prototype.addCopayerExtendedPubKey = function (newEpk) { +PublicKeyRing.prototype._newExtendedPublicKey = function () { + return new BIP32(this.network.name) + .extendedPublicKeyString(); +}; + +PublicKeyRing.prototype.addCopayer = function (newEpk) { if (this.haveAllRequiredPubKeys()) throw new Error('already have all required key:' + this.totalCopayers); - if (this.getMasterExtendedPubKey() === newEpk) - throw new Error('already have that key (self key)'); + if (!newEpk) { + newEpk = this._newExtendedPublicKey(); + } - - this.copayersWallets.forEach(function(b){ - if (b.getMasterExtendedPubKey() === newEpk) + this.copayersBIP32.forEach(function(b){ + if (b.extendedPublicKeyString() === newEpk) throw new Error('already have that key'); }); - this.copayersWallets.push(new PublicKeyRing({bytes:newEpk, network: this.network.name } )); + this.copayersBIP32.push(new BIP32(newEpk)); this.dirty = 1; + return newEpk; }; -PublicKeyRing.prototype.getPubKey = function (index,isChange) { - - var path = (isChange ? CHANGE_BRANCH : PUBLIC_BRANCH) + index; - var bip32 = this.bip32.derive(path); - var pub = bip32.eckey.public; - return pub; -}; - PublicKeyRing.prototype.getCopayersPubKeys = function (index, isChange) { this._checkKeys(); var pubKeys = []; - var l = this.copayersWallets.length; + var l = this.copayersBIP32.length; for(var i=0; i this.changeAddressIndex) - || (!isChange && index > this.addressIndex)) { +PublicKeyRing.prototype._checkIndexRange = function (index, isChange) { + if ( (isChange && index > this.changeAddressIndex) || + (!isChange && index > this.addressIndex)) { log('Out of bounds at getAddress: Index %d isChange: %d', index, isChange); throw new Error('index out of bound'); } +}; + +PublicKeyRing.prototype.getRedeemScript = function (index, isChange) { + this._checkIndexRange(index, isChange); var pubKeys = this.getCopayersPubKeys(); - var version = this.network.addressScript; var script = Script.createMultisig(this.requiredCopayers, pubKeys); - var buf = script.buffer; - var hash = coinUtil.sha256ripe160(buf); + return script; +}; + +PublicKeyRing.prototype.getAddress = function (index, isChange) { + this._checkIndexRange(index, isChange); + + var script = this.getRedeemScript(index,isChange); + var hash = coinUtil.sha256ripe160(script.getBuffer()); + var version = this.network.addressScript; var addr = new Address(version, hash); - var addrStr = addr.as('base58'); - return addrStr; + return addr.as('base58'); }; //generate a new address, update index. diff --git a/test/test.publickeyring.js b/test/test.publickeyring.js index 1648ef613..38c992905 100644 --- a/test/test.publickeyring.js +++ b/test/test.publickeyring.js @@ -16,24 +16,20 @@ var config = { network:'livenet', }; -var createW = function (network, bytes) { +var createW = function (network) { var config = { network: network || 'livenet', }; - if (bytes) config.bytes = bytes; var w = new PublicKeyRing(config); should.exist(w); var copayers = []; - for(var i=0; i<4; i++) { - delete config['bytes']; - var c = new PublicKeyRing(config); + for(var i=0; i<5; i++) { w.haveAllRequiredPubKeys().should.equal(false); - - w.addCopayerExtendedPubKey(c.getMasterExtendedPubKey()); - copayers.push(c); + var newEpk = w.addCopayer(); + copayers.push(newEpk); } return {w:w, copayers: copayers}; @@ -54,17 +50,11 @@ describe('PublicKeyRing model', function() { w2.network.name.should.equal('testnet'); }); - it('should create an master pub key', function () { - var w2 = new PublicKeyRing(config); - should.exist(w2); - should.exist(w2.getMasterExtendedPubKey()); - }); - it('should fail to generate shared pub keys wo extended key', function () { var w2 = new PublicKeyRing(config); should.exist(w2); - w2.registeredCopayers().should.equal(1); + w2.registeredCopayers().should.equal(0); w2.haveAllRequiredPubKeys().should.equal(false); w2.getAddress.bind(false).should.throw(); @@ -76,9 +66,9 @@ describe('PublicKeyRing model', function() { var copayers = k.copayers; w.haveAllRequiredPubKeys().should.equal(true); - w.addCopayerExtendedPubKey.bind(w.getMasterExtendedPubKey()).should.throw(); - w.addCopayerExtendedPubKey.bind(copayers[0].getMasterExtendedPubKey()).should.throw(); - w.addCopayerExtendedPubKey.bind((new PublicKeyRing(config)).getMasterExtendedPubKey()).should.throw(); + w.addCopayer.bind().should.throw(); + for(var i =0; i<5; i++) + w.addCopayer.bind(copayers[i]).should.throw(); }); it('show be able to store and retrieve', function () { @@ -93,9 +83,9 @@ describe('PublicKeyRing model', function() { var w2 = PublicKeyRing.read(ID); w2.haveAllRequiredPubKeys().should.equal(true); - w2.addCopayerExtendedPubKey.bind(w.getMasterExtendedPubKey()).should.throw(); - w2.addCopayerExtendedPubKey.bind(copayers[0].getMasterExtendedPubKey()).should.throw(); - w2.addCopayerExtendedPubKey.bind((new PublicKeyRing(config)).getMasterExtendedPubKey()).should.throw(); + w2.addCopayer.bind().should.throw(); + for(var i =0; i<5; i++) + w2.addCopayer.bind(copayers[i]).should.throw(); });