From 3bf02173c519b2425a905c66e3df942b34d5812e Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 26 Mar 2014 17:55:02 -0300 Subject: [PATCH] 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(); + + }); });