diff --git a/lib/server.js b/lib/server.js index 375ad7e..b7eb952 100644 --- a/lib/server.js +++ b/lib/server.js @@ -25,25 +25,56 @@ var Address = require('./model/address'); var TxProposal = require('./model/txproposal'); +var initialized = false; +var storage; + /** * Creates an instance of the Copay server. * @constructor + */ +function CopayServer() { + if (!initialized) throw new Error('Server not initialized'); + this.storage = storage; +}; + + +/** + * Initializes global settings for all instances. * @param {Object} opts * @param {Storage} [opts.storage] - The storage provider. */ -function CopayServer(opts) { +CopayServer.initialize = function (opts) { opts = opts || {}; - this.storage = opts.storage ||  new Storage(); + storage = opts.storage ||  new Storage(); + initialized = true; }; -inherits(CopayServer, events.EventEmitter); +/** + * Gets an instance of the server after authenticating the copayer. + * @param {Object} opts + * @param {string} opts.copayerId - The copayer id making the request. + * @param {string} opts.message - The contents of the request to be signed. + * @param {string} opts.signature - Signature of message to be verified using the copayer's signingPubKey. + */ +CopayServer.getInstanceWithAuth = function (opts, cb) { + + Utils.checkRequired(opts, ['copayerId', 'message', 'signature']); + + var server = new CopayServer(); + server.storage.fetchCopayerLookup(opts.copayerId, function (err, copayer) { + if (err) return cb(err); + if (!copayer) return cb('Copayer not found'); + + var isValid = server._verifySignature(opts.message, opts.signature, copayer.signingPubKey); + if (!isValid) return cb('Invalid signature'); -CopayServer._emit = function(event) { - var args = Array.prototype.slice.call(arguments); - log.debug('Emitting: ', args); - this.emit.apply(this, arguments); + server.copayerId = opts.copayerId; + server.walletId = copayer.walletId; + return cb(null, server); + }); }; + /** * Creates a new wallet. * @param {Object} opts @@ -89,13 +120,12 @@ CopayServer.prototype.createWallet = function(opts, cb) { /** * Retrieves a wallet from storage. * @param {Object} opts - * @param {string} opts.id - The wallet id. * @returns {Object} wallet */ CopayServer.prototype.getWallet = function(opts, cb) { var self = this; - self.storage.fetchWallet(opts.id, function(err, wallet) { + self.storage.fetchWallet(self.walletId, function(err, wallet) { if (err) return cb(err); if (!wallet) return cb(new ClientError('Wallet not found')); return cb(null, wallet); @@ -128,10 +158,9 @@ CopayServer.prototype.joinWallet = function(opts, cb) { Utils.checkRequired(opts, ['walletId', 'id', 'name', 'xPubKey', 'xPubKeySignature']); Utils.runLocked(opts.walletId, cb, function(cb) { - self.getWallet({ - id: opts.walletId - }, function(err, wallet) { + self.storage.fetchWallet(opts.walletId, function(err, wallet) { if (err) return cb(err); + if (!wallet) return cb(new ClientError('Wallet not found')); if (!self._verifySignature(opts.xPubKey, opts.xPubKeySignature, wallet.pubKey)) { return cb(new ClientError()); @@ -160,12 +189,8 @@ CopayServer.prototype.joinWallet = function(opts, cb) { }; /** - * - * TODO: How this is going to be authenticated? - * * Creates a new address. * @param {Object} opts - * @param {string} opts.walletId - The wallet id. * @param {truthy} opts.isChange - Indicates whether this is a regular address or a change address. * @returns {Address} address */ @@ -173,12 +198,10 @@ CopayServer.prototype.createAddress = function(opts, cb) { var self = this; var isChange = opts.isChange || false; - Utils.checkRequired(opts, ['walletId', 'isChange']); + Utils.checkRequired(opts, ['isChange']); - Utils.runLocked(opts.walletId, cb, function(cb) { - self.getWallet({ - id: opts.walletId - }, function(err, wallet) { + Utils.runLocked(self.walletId, cb, function(cb) { + self.getWallet({}, function(err, wallet) { if (err) return cb(err); var address = wallet.createAddress(opts.isChange); @@ -203,13 +226,12 @@ CopayServer.prototype.createAddress = function(opts, cb) { /** * Get all addresses. * @param {Object} opts - * @param {string} opts.walletId - The wallet id. * @returns {Address[]} */ CopayServer.prototype.getAddresses = function(opts, cb) { var self = this; - self.storage.fetchAddresses(opts.walletId, function(err, addresses) { + self.storage.fetchAddresses(self.walletId, function(err, addresses) { if (err) return cb(err); return cb(null, addresses); @@ -219,8 +241,6 @@ CopayServer.prototype.getAddresses = function(opts, cb) { /** * Verifies that a given message was actually sent by an authorized copayer. * @param {Object} opts - * @param {string} opts.walletId - The wallet id. - * @param {string} opts.copayerId - The wallet id. * @param {string} opts.message - The message to verify. * @param {string} opts.signature - The signature of message to verify. * @returns {truthy} The result of the verification. @@ -228,15 +248,12 @@ CopayServer.prototype.getAddresses = function(opts, cb) { CopayServer.prototype.verifyMessageSignature = function(opts, cb) { var self = this; - Utils.checkRequired(opts, ['walletId', 'copayerId', 'message', 'signature']); + Utils.checkRequired(opts, ['message', 'signature']); - self.getWallet({ - id: opts.walletId - }, function(err, wallet) { + self.getWallet({}, function(err, wallet) { if (err) return cb(err); - var copayer = wallet.getCopayer(opts.copayerId); - if (!copayer) return cb(new ClientError('Copayer not found')); + var copayer = wallet.getCopayer(self.copayerId); var isValid = self._verifySignature(opts.message, opts.signature, copayer.signingPubKey); return cb(null, isValid); @@ -267,14 +284,13 @@ CopayServer.prototype._getBlockExplorer = function(provider, network) { /** * _getUtxos * - * @param opts.walletId */ -CopayServer.prototype._getUtxos = function(opts, cb) { +CopayServer.prototype._getUtxos = function(cb) { var self = this; // Get addresses for this wallet - self.storage.fetchAddresses(opts.walletId, function(err, addresses) { + self.storage.fetchAddresses(self.walletId, function(err, addresses) { if (err) return cb(err); if (addresses.length == 0) return cb(new ClientError('The wallet has no addresses')); @@ -286,9 +302,7 @@ CopayServer.prototype._getUtxos = function(opts, cb) { bc.getUnspentUtxos(addressStrs, function(err, utxos) { if (err) return cb(err); - self.getPendingTxs({ - walletId: opts.walletId - }, function(err, txps) { + self.getPendingTxs({}, function(err, txps) { if (err) return cb(err); var inputs = _.chain(txps) @@ -326,17 +340,12 @@ CopayServer.prototype._getUtxos = function(opts, cb) { /** * Creates a new transaction proposal. * @param {Object} opts - * @param {string} opts.walletId - The wallet id. * @returns {Object} balance - Total amount & locked amount. */ CopayServer.prototype.getBalance = function(opts, cb) { var self = this; - Utils.checkRequired(opts, 'walletId'); - - self._getUtxos({ - walletId: opts.walletId - }, function(err, utxos) { + self._getUtxos(function(err, utxos) { if (err) return cb(err); var balance = {}; @@ -355,7 +364,7 @@ CopayServer.prototype.getBalance = function(opts, cb) { }; - +// TODO: should be in Utils CopayServer.prototype._inputSatoshis = function(i) { return i.amount ? Utils.strip(i.amount * 1e8) : i.satoshis; }; @@ -383,8 +392,6 @@ CopayServer.prototype._selectUtxos = function(txp, utxos) { /** * Creates a new transaction proposal. * @param {Object} opts - * @param {string} opts.walletId - The wallet id. - * @param {string} opts.copayerId - The wallet id. * @param {string} opts.toAddress - Destination address. * @param {number} opts.amount - Amount to transfer in satoshi. * @param {string} opts.message - A message to attach to this transaction. @@ -393,21 +400,17 @@ CopayServer.prototype._selectUtxos = function(txp, utxos) { CopayServer.prototype.createTx = function(opts, cb) { var self = this; - Utils.checkRequired(opts, ['walletId', 'copayerId', 'toAddress', 'amount', 'message']); + Utils.checkRequired(opts, ['toAddress', 'amount', 'message']); // TODO? // Check some parameters like: // amount > dust - self.getWallet({ - id: opts.walletId - }, function(err, wallet) { + self.getWallet({}, function(err, wallet) { if (err) return cb(err); - self._getUtxos({ - walletId: wallet.id - }, function(err, utxos) { + self._getUtxos(function(err, utxos) { if (err) return cb(err); var changeAddress = wallet.createAddress(true).address; @@ -417,7 +420,7 @@ CopayServer.prototype.createTx = function(opts, cb) { }); var txp = new TxProposal({ - creatorId: opts.copayerId, + creatorId: self.copayerId, toAddress: opts.toAddress, amount: opts.amount, changeAddress: changeAddress, @@ -446,14 +449,13 @@ CopayServer.prototype.createTx = function(opts, cb) { /** * Retrieves a tx from storage. * @param {Object} opts - * @param {string} opts.walletId - The wallet id. * @param {string} opts.id - The tx id. * @returns {Object} txProposal */ CopayServer.prototype.getTx = function(opts, cb) { var self = this; - self.storage.fetchTx(opts.walletId, opts.id, function(err, txp) { + self.storage.fetchTx(self.walletId, opts.id, function(err, txp) { if (err) return cb(err); if (!txp) return cb(new ClientError('Transaction proposal not found')); return cb(null, txp); @@ -471,23 +473,18 @@ CopayServer.prototype._broadcastTx = function(txp, cb) { /** * Sign a transaction proposal. * @param {Object} opts - * @param {string} opts.walletId - The wallet id. - * @param {string} opts.copayerId - The wallet id. * @param {string} opts.txProposalId - The identifier of the transaction. * @param {string} opts.signatures - The signatures of the inputs of this tx for this copayer (in apperance order) */ CopayServer.prototype.signTx = function(opts, cb) { var self = this; - Utils.checkRequired(opts, ['walletId', 'copayerId', 'txProposalId', 'signatures']); + Utils.checkRequired(opts, ['txProposalId', 'signatures']); - self.getWallet({ - id: opts.walletId - }, function(err, wallet) { + self.getWallet({}, function(err, wallet) { if (err) return cb(err); self.getTx({ - walletId: opts.walletId, id: opts.txProposalId }, function(err, txp) { if (err) return cb(err); @@ -500,22 +497,22 @@ CopayServer.prototype.signTx = function(opts, cb) { if (txp.status != 'pending') return cb(new ClientError('TXNOTPENDING', 'The transaction proposal is not pending')); - var copayer = wallet.getCopayer(opts.copayerId); + var copayer = wallet.getCopayer(self.copayerId); if (!txp.checkSignatures(opts.signatures, copayer.xPubKey)) return cb(new ClientError('BADSIGNATURES', 'Bad signatures')); - txp.sign(opts.copayerId, opts.signatures); + txp.sign(self.copayerId, opts.signatures); - self.storage.storeTx(opts.walletId, txp, function(err) { + self.storage.storeTx(self.walletId, txp, function(err) { if (err) return cb(err); if (txp.status == 'accepted') { self._broadcastTx(txp, function(err, txid) { - if (err) return cb(err, txp); + if (err) return cb(err); txp.setBroadcasted(txid); - self.storage.storeTx(opts.walletId, txp, function(err) { + self.storage.storeTx(self.walletId, txp, function(err) { if (err) return cb(err); return cb(null, txp); @@ -532,31 +529,28 @@ CopayServer.prototype.signTx = function(opts, cb) { /** * Reject a transaction proposal. * @param {Object} opts - * @param {string} opts.walletId - The wallet id. - * @param {string} opts.copayerId - The wallet id. * @param {string} opts.txProposalId - The identifier of the transaction. * @param {string} [opts.reason] - A message to other copayers explaining the rejection. */ CopayServer.prototype.rejectTx = function(opts, cb) { var self = this; - Utils.checkRequired(opts, ['walletId', 'copayerId', 'txProposalId']); + Utils.checkRequired(opts, ['txProposalId']); self.getTx({ - walletId: opts.walletId, id: opts.txProposalId }, function(err, txp) { if (err) return cb(err); if (!txp) return cb(new ClientError('Transaction proposal not found')); var action = _.find(txp.actions, { - copayerId: opts.copayerId + copayerId: self.copayerId }); if (action) return cb(new ClientError('CVOTED', 'Copayer already voted on this transaction proposal')); if (txp.status != 'pending') return cb(new ClientError('TXNOTPENDING', 'The transaction proposal is not pending')); - txp.reject(opts.copayerId); + txp.reject(self.copayerId); - self.storage.storeTx(opts.walletId, txp, function(err) { + self.storage.storeTx(self.walletId, txp, function(err) { if (err) return cb(err); return cb(); @@ -567,15 +561,12 @@ CopayServer.prototype.rejectTx = function(opts, cb) { /** * Retrieves all pending transaction proposals. * @param {Object} opts - * @param {string} opts.walletId - The wallet id. * @returns {TxProposal[]} Transaction proposal. */ CopayServer.prototype.getPendingTxs = function(opts, cb) { var self = this; - Utils.checkRequired(opts, 'walletId'); - - self.storage.fetchTxs(opts.walletId, function(err, txps) { + self.storage.fetchTxs(self.walletId, function(err, txps) { if (err) return cb(err); var pending = _.filter(txps, { diff --git a/test/integration.js b/test/integration.js index 1d88204..fe8f649 100644 --- a/test/integration.js +++ b/test/integration.js @@ -60,7 +60,22 @@ var aTextSignature = '3045022100addd20e5413865d65d561ad2979f2289a40d52594b1f8048 var helpers = {}; +helpers.getAuthServer = function (copayerId, cb) { + var signatureStub = sinon.stub(CopayServer.prototype, '_verifySignature'); + signatureStub.returns(true); + CopayServer.getInstanceWithAuth({ + copayerId: copayerId, + message: 'dummy', + signature: 'dummy', + }, function (err, server) { + signatureStub.restore(); + return cb(server); + }); +}; + helpers.createAndJoinWallet = function(id, m, n, cb) { + var server = new CopayServer(); + var walletOpts = { id: id, name: id + ' wallet', @@ -84,14 +99,13 @@ helpers.createAndJoinWallet = function(id, m, n, cb) { server.joinWallet(copayerOpts, function(err) { return cb(err); }); - }, function(err) { - if (err) return cb(err); - - server.getWallet({ - id: id, - includeCopayers: true - }, function(err, wallet) { - return cb(err, wallet); + }, function (err) { + if (err) return new Error('Could not generate wallet'); + + helpers.getAuthServer('1', function (s) { + s.getWallet({}, function (err, w) { + cb(s, w); + }); }); }); }); @@ -114,10 +128,8 @@ helpers.toSatoshi = function(btc) { helpers.createUtxos = function(server, wallet, amounts, cb) { var addresses = []; - async.each(amounts, function(a, next) { server.createAddress({ - walletId: wallet.id, isChange: false, }, function(err, address) { addresses.push(address); @@ -191,7 +203,6 @@ helpers.clientSign = function(tx, xpriv, n) { }; var db, storage; -var server; describe('Copay server', function() { @@ -202,96 +213,27 @@ describe('Copay server', function() { storage = new Storage({ db: db }); + CopayServer.initialize({ storage: storage }); }); - describe('#getWallet', function() { + describe.skip('#getInstanceWithAuth', function() { beforeEach(function() { - server = new CopayServer({ - storage: storage, - }); }); - it('should get existing wallet', function(done) { - - var w1 = new Wallet({ - id: '123', - name: 'my wallet', - m: 2, - n: 3, - pubKey: aPubKey, - }); - - var w2 = new Wallet({ - id: '234', - name: 'my wallet 2', - m: 3, - n: 4, - pubKey: aPubKey, - }); - - db.batch([{ - type: 'put', - key: 'wallet-123', - value: w1, - }, { - type: 'put', - key: 'wallet-234', - value: w2, - }]); + it('should get server instance for existing copayer', function(done) { + }); - server.getWallet({ - id: '123', - includeCopayers: true - }, function(err, wallet) { - should.not.exist(err); - wallet.id.should.equal('123'); - wallet.name.should.equal('my wallet'); - wallet.status.should.equal('pending'); - wallet.copayers.length.should.equal(0); - done(); - }); + it('should fail when requesting for non-existent copayer', function(done) { }); - it('should fail when requesting non-existent wallet', function(done) { - var w1 = new Wallet({ - id: '123', - name: 'my wallet', - m: 2, - n: 3, - pubKey: aPubKey, - }); - var w2 = new Wallet({ - id: '234', - name: 'my wallet 2', - m: 3, - n: 4, - pubKey: aPubKey, - }); - db.batch([{ - type: 'put', - key: 'wallet-123', - value: w1, - }, { - type: 'put', - key: 'wallet-234', - value: w2, - }]); - - server.getWallet({ - id: '345' - }, function(err, wallet) { - should.exist(err); - err.message.should.equal('Wallet not found'); - done(); - }); + it('should fail when message signature cannot be verified', function(done) { }); }); describe('#createWallet', function() { + var server; beforeEach(function() { - server = new CopayServer({ - storage: storage, - }); + server = new CopayServer(); }); it('should create and store wallet', function(done) { @@ -304,9 +246,7 @@ describe('Copay server', function() { }; server.createWallet(opts, function(err) { should.not.exist(err); - server.getWallet({ - id: '123' - }, function(err, wallet) { + server.storage.fetchWallet('123', function(err, wallet) { should.not.exist(err); wallet.id.should.equal('123'); wallet.name.should.equal('my wallet'); @@ -325,9 +265,7 @@ describe('Copay server', function() { }; server.createWallet(opts, function(err) { should.not.exist(err); - server.getWallet({ - id: '123' - }, function(err, wallet) { + server.storage.fetchWallet('123', function(err, wallet) { should.not.exist(err); wallet.id.should.equal('123'); wallet.name.should.equal('my wallet'); @@ -379,10 +317,9 @@ describe('Copay server', function() { }); describe('#joinWallet', function() { + var server; beforeEach(function() { - server = new CopayServer({ - storage: storage, - }); + server = new CopayServer(); }); it('should join existing wallet', function(done) { @@ -405,16 +342,15 @@ describe('Copay server', function() { }; server.joinWallet(copayerOpts, function(err) { should.not.exist(err); - server.getWallet({ - id: '123', - includeCopayers: true - }, function(err, wallet) { - wallet.id.should.equal('123'); - wallet.copayers.length.should.equal(1); - var copayer = wallet.copayers[0]; - copayer.id.should.equal('999'); - copayer.name.should.equal('me'); - done(); + helpers.getAuthServer('999', function (server) { + server.getWallet({}, function(err, wallet) { + wallet.id.should.equal('123'); + wallet.copayers.length.should.equal(1); + var copayer = wallet.copayers[0]; + copayer.id.should.equal('999'); + copayer.name.should.equal('me'); + done(); + }); }); }); }); @@ -470,15 +406,15 @@ describe('Copay server', function() { }; server.joinWallet(copayer1Opts, function(err) { should.not.exist(err); - server.getWallet({ - id: '123' - }, function(err, wallet) { - wallet.status.should.equal('complete'); - server.joinWallet(copayer2Opts, function(err) { - should.exist(err); - err.code.should.equal('WFULL'); - err.message.should.equal('Wallet full'); - done(); + helpers.getAuthServer('111', function (server) { + server.getWallet({}, function(err, wallet) { + wallet.status.should.equal('complete'); + server.joinWallet(copayer2Opts, function(err) { + should.exist(err); + err.code.should.equal('WFULL'); + err.message.should.equal('Wallet full'); + done(); + }); }); }); }); @@ -590,10 +526,8 @@ describe('Copay server', function() { }); it('should set pkr and status = complete on last copayer joining (2-3)', function(done) { - helpers.createAndJoinWallet('123', 2, 3, function(err, wallet) { - server.getWallet({ - id: '123' - }, function(err, wallet) { + helpers.createAndJoinWallet('123', 2, 3, function(server) { + server.getWallet({}, function(err, wallet) { should.not.exist(err); wallet.status.should.equal('complete'); wallet.publicKeyRing.length.should.equal(3); @@ -606,16 +540,11 @@ describe('Copay server', function() { describe('#verifyMessageSignature', function() { beforeEach(function() { - server = new CopayServer({ - storage: storage, - }); }); it('should successfully verify message signature', function(done) { - helpers.createAndJoinWallet('123', 2, 2, function(err, wallet) { + helpers.createAndJoinWallet('123', 2, 2, function(server) { var opts = { - walletId: '123', - copayerId: '1', message: aText, signature: aTextSignature, }; @@ -627,17 +556,18 @@ describe('Copay server', function() { }); }); - it('should fail to verify message signature when copayer does not exist', function(done) { - helpers.createAndJoinWallet('123', 2, 2, function(err, wallet) { + it('should fail to verify message signature for different copayer', function(done) { + helpers.createAndJoinWallet('123', 2, 2, function() { var opts = { - walletId: '123', - copayerId: '999', - message: 'hello world', - signature: 'dummy', + message: aText, + signature: aTextSignature, }; - server.verifyMessageSignature(opts, function(err, isValid) { - err.message.should.equal('Copayer not found'); - done(); + helpers.getAuthServer('2', function (server) { + server.verifyMessageSignature(opts, function(err, isValid) { + should.not.exist(err); + isValid.should.be.false; + done(); + }); }); }); }); @@ -645,15 +575,11 @@ describe('Copay server', function() { describe('#createAddress', function() { beforeEach(function() { - server = new CopayServer({ - storage: storage, - }); }); it('should create main address', function(done) { - helpers.createAndJoinWallet('123', 2, 2, function(err, wallet) { + helpers.createAndJoinWallet('123', 2, 2, function(server) { server.createAddress({ - walletId: '123', isChange: false, }, function(err, address) { should.not.exist(err); @@ -667,9 +593,8 @@ describe('Copay server', function() { it('should create change address', function(done) { - helpers.createAndJoinWallet('123', 2, 2, function(err, wallet) { + helpers.createAndJoinWallet('123', 2, 2, function(server) { server.createAddress({ - walletId: '123', isChange: true, }, function(err, address) { should.not.exist(err); @@ -682,10 +607,9 @@ describe('Copay server', function() { }); it('should create many addresses on simultaneous requests', function(done) { - helpers.createAndJoinWallet('123', 2, 2, function(err, wallet) { + helpers.createAndJoinWallet('123', 2, 2, function(server) { async.map(_.range(10), function(i, cb) { server.createAddress({ - walletId: '123', isChange: false, }, cb); }, function(err, addresses) { @@ -700,26 +624,22 @@ describe('Copay server', function() { }); it('should not create address if unable to store wallet', function(done) { - helpers.createAndJoinWallet('123', 2, 2, function(err, wallet) { + helpers.createAndJoinWallet('123', 2, 2, function(server) { var storeWalletStub = sinon.stub(server.storage, 'storeWallet'); storeWalletStub.yields('dummy error'); server.createAddress({ - walletId: '123', isChange: true, }, function(err, address) { err.should.exist; should.not.exist(address); - server.getAddresses({ - walletId: '123' - }, function(err, addresses) { + server.getAddresses({}, function(err, addresses) { addresses.length.should.equal(0); server.storage.storeWallet.restore(); server.createAddress({ - walletId: '123', isChange: true, }, function(err, address) { should.not.exist(err); @@ -734,26 +654,22 @@ describe('Copay server', function() { }); it('should not create address if unable to store addresses', function(done) { - helpers.createAndJoinWallet('123', 2, 2, function(err, wallet) { + helpers.createAndJoinWallet('123', 2, 2, function(server) { var storeAddressStub = sinon.stub(server.storage, 'storeAddress'); storeAddressStub.yields('dummy error'); server.createAddress({ - walletId: '123', isChange: true, }, function(err, address) { err.should.exist; should.not.exist(address); - server.getAddresses({ - walletId: '123' - }, function(err, addresses) { + server.getAddresses({}, function(err, addresses) { addresses.length.should.equal(0); server.storage.storeAddress.restore(); server.createAddress({ - walletId: '123', isChange: true, }, function(err, address) { should.not.exist(err); @@ -769,15 +685,12 @@ describe('Copay server', function() { }); describe('#createTx', function() { - var wallet; + var server, wallet; beforeEach(function(done) { - server = new CopayServer({ - storage: storage, - }); - helpers.createAndJoinWallet('123', 2, 2, function(err, w) { + helpers.createAndJoinWallet('123', 2, 2, function(s, w) { + server = s; wallet = w; server.createAddress({ - walletId: '123', isChange: false, }, function(err, address) { done(); @@ -786,14 +699,9 @@ describe('Copay server', function() { }); it('should create tx', function(done) { - helpers.createUtxos(server, wallet, helpers.toSatoshi([100, 200]), function(utxos) { - helpers.stubBlockExplorer(server, utxos); - var txOpts = { - copayerId: '1', - walletId: '123', toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: helpers.toSatoshi(80), message: 'some message', @@ -806,14 +714,10 @@ describe('Copay server', function() { tx.should.exist; tx.isAccepted().should.equal.false; tx.isRejected().should.equal.false; - server.getPendingTxs({ - walletId: '123' - }, function(err, txs) { + server.getPendingTxs({}, function(err, txs) { should.not.exist(err); txs.length.should.equal(1); - server.getBalance({ - walletId: '123' - }, function(err, balance) { + server.getBalance({}, function(err, balance) { should.not.exist(err); balance.totalAmount.should.equal(helpers.toSatoshi(300)); balance.lockedAmount.should.equal(helpers.toSatoshi(100)); @@ -825,13 +729,9 @@ describe('Copay server', function() { }); it('should fail to create tx when insufficient funds', function(done) { - helpers.createUtxos(server, wallet, helpers.toSatoshi([100]), function(utxos) { helpers.stubBlockExplorer(server, utxos); - var txOpts = { - copayerId: '1', - walletId: '123', toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: helpers.toSatoshi(120), message: 'some message', @@ -842,14 +742,10 @@ describe('Copay server', function() { server.createTx(txOpts, function(err, tx) { err.code.should.equal('INSUFFICIENTFUNDS'); err.message.should.equal('Insufficient funds'); - server.getPendingTxs({ - walletId: '123' - }, function(err, txs) { + server.getPendingTxs({}, function(err, txs) { should.not.exist(err); txs.length.should.equal(0); - server.getBalance({ - walletId: '123' - }, function(err, balance) { + server.getBalance({}, function(err, balance) { should.not.exist(err); balance.lockedAmount.should.equal(0); balance.totalAmount.should.equal(10000000000); @@ -861,13 +757,9 @@ describe('Copay server', function() { }); it('should create tx when there is a pending tx and enough UTXOs', function(done) { - helpers.createUtxos(server, wallet, helpers.toSatoshi([10.1, 10.2, 10.3]), function(utxos) { helpers.stubBlockExplorer(server, utxos); - var txOpts = { - copayerId: '1', - walletId: '123', toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: helpers.toSatoshi(12), message: 'some message', @@ -879,8 +771,6 @@ describe('Copay server', function() { tx.should.exist; var txOpts2 = { - copayerId: '1', - walletId: '123', toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: 8, message: 'some message 2', @@ -890,14 +780,10 @@ describe('Copay server', function() { server.createTx(txOpts2, function(err, tx) { should.not.exist(err); tx.should.exist; - server.getPendingTxs({ - walletId: '123' - }, function(err, txs) { + server.getPendingTxs({}, function(err, txs) { should.not.exist(err); txs.length.should.equal(2); - server.getBalance({ - walletId: '123' - }, function(err, balance) { + server.getBalance({}, function(err, balance) { should.not.exist(err); balance.totalAmount.should.equal(3060000000); balance.lockedAmount.should.equal(3060000000); @@ -911,11 +797,8 @@ describe('Copay server', function() { it('should fail to create tx when there is a pending tx and not enough UTXOs', function(done) { helpers.createUtxos(server, wallet, helpers.toSatoshi([10.1, 10.2, 10.3]), function(utxos) { - helpers.stubBlockExplorer(server, utxos); var txOpts = { - copayerId: '1', - walletId: '123', toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: helpers.toSatoshi(12), message: 'some message', @@ -927,8 +810,6 @@ describe('Copay server', function() { tx.should.exist; var txOpts2 = { - copayerId: '1', - walletId: '123', toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: helpers.toSatoshi(24), message: 'some message 2', @@ -939,14 +820,10 @@ describe('Copay server', function() { err.code.should.equal('INSUFFICIENTFUNDS'); err.message.should.equal('Insufficient funds'); should.not.exist(tx); - server.getPendingTxs({ - walletId: '123' - }, function(err, txs) { + server.getPendingTxs({}, function(err, txs) { should.not.exist(err); txs.length.should.equal(1); - server.getBalance({ - walletId: '123' - }, function(err, balance) { + server.getBalance({}, function(err, balance) { should.not.exist(err); balance.totalAmount.should.equal(helpers.toSatoshi(30.6)); balance.lockedAmount.should.equal(helpers.toSatoshi(20.3)); @@ -961,23 +838,18 @@ describe('Copay server', function() { }); describe('#signTx', function() { - var wallet, txid; + var server, wallet, txid; beforeEach(function(done) { - server = new CopayServer({ - storage: storage, - }); - helpers.createAndJoinWallet('123', 2, 2, function(err, w) { + helpers.createAndJoinWallet('123', 2, 2, function(s, w) { + server = s; wallet = w; server.createAddress({ - walletId: '123', isChange: false, }, function(err, address) { helpers.createUtxos(server, wallet, helpers.toSatoshi([1, 2, 3, 4, 5, 6, 7, 8]), function(utxos) { helpers.stubBlockExplorer(server, utxos); var txOpts = { - copayerId: '1', - walletId: '123', toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: helpers.toSatoshi(10), message: 'some message', @@ -995,17 +867,13 @@ describe('Copay server', function() { }); }); - it('should sign a TX with multiple inputs, different paths', function(done) { - server.getPendingTxs({ - walletId: '123' - }, function(err, txs) { + it('should sign a TX with multiple inputs, different paths', function(done) { + server.getPendingTxs({}, function(err, txs) { var tx = txs[0]; tx.id.should.equal(txid); var signatures = helpers.clientSign(tx, someXPrivKey[0], wallet.n); server.signTx({ - walletId: '123', - copayerId: '1', txProposalId: txid, signatures: signatures, }, function(err) { @@ -1015,10 +883,8 @@ describe('Copay server', function() { }); }); - it('should fail if one signature is broken', function(done) { - server.getPendingTxs({ - walletId: '123' - }, function(err, txs) { + it('should fail if one signature is broken', function(done) { + server.getPendingTxs({}, function(err, txs) { var tx = txs[0]; tx.id.should.equal(txid); @@ -1026,8 +892,6 @@ describe('Copay server', function() { signatures[0] = 1; server.signTx({ - walletId: '123', - copayerId: '1', txProposalId: txid, signatures: signatures, }, function(err) { @@ -1036,17 +900,13 @@ describe('Copay server', function() { }); }); }); - it('should fail on invalids signature', function(done) { - server.getPendingTxs({ - walletId: '123' - }, function(err, txs) { + it('should fail on invalids signature', function(done) { + server.getPendingTxs({}, function(err, txs) { var tx = txs[0]; tx.id.should.equal(txid); var signatures = ['11', '22', '33', '44']; server.signTx({ - walletId: '123', - copayerId: '1', txProposalId: txid, signatures: signatures, }, function(err) { @@ -1060,16 +920,13 @@ describe('Copay server', function() { describe('#signTx and broadcast', function() { - var wallet, utxos; + var server, wallet, utxos; beforeEach(function(done) { - server = new CopayServer({ - storage: storage, - }); - helpers.createAndJoinWallet('123', 1, 1, function(err, w) { + helpers.createAndJoinWallet('123', 1, 1, function(s, w) { + server = s; wallet = w; server.createAddress({ - walletId: '123', isChange: false, }, function(err, address) { helpers.createUtxos(server, wallet, helpers.toSatoshi([1, 2, 3, 4, 5, 6, 7, 8]), function(inutxos) { @@ -1083,8 +940,6 @@ describe('Copay server', function() { it('should sign and broadcast a tx', function(done) { helpers.stubBlockExplorer(server, utxos, '1122334455'); var txOpts = { - copayerId: '1', - walletId: '123', toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: helpers.toSatoshi(10), message: 'some message', @@ -1096,15 +951,11 @@ describe('Copay server', function() { txp.should.exist; var txpid = txp.id; - server.getPendingTxs({ - walletId: '123' - }, function(err, txps) { + server.getPendingTxs({}, function(err, txps) { var txp = txps[0]; txp.id.should.equal(txpid); var signatures = helpers.clientSign(txp, someXPrivKey[0], wallet.n); server.signTx({ - walletId: '123', - copayerId: '1', txProposalId: txpid, signatures: signatures, }, function(err, txp) { @@ -1122,8 +973,6 @@ describe('Copay server', function() { helpers.stubBlockExplorer(server, utxos); var txOpts = { - copayerId: '1', - walletId: '123', toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', amount: helpers.toSatoshi(10), message: 'some message', @@ -1135,22 +984,25 @@ describe('Copay server', function() { txp.should.exist; var txpid = txp.id; - server.getPendingTxs({ - walletId: '123' - }, function(err, txps) { + server.getPendingTxs({}, function(err, txps) { var txp = txps[0]; txp.id.should.equal(txpid); var signatures = helpers.clientSign(txp, someXPrivKey[0], wallet.n); server.signTx({ - walletId: '123', - copayerId: '1', txProposalId: txpid, signatures: signatures, }, function(err, txp) { err.should.contain('broadcast'); - txp.status.should.equal('accepted'); - should.not.exist(txp.txid); - done(); + + server.getPendingTxs({}, function(err, txps) { + should.not.exist(err); + txps.length.should.equal(0); + server.getTx({ id: txpid }, function (err, txp) { + txp.status.should.equal('accepted'); + should.not.exist(txp.txid); + done(); + }); + }); }); }); });