diff --git a/app.js b/app.js index 2ece691..7eb3f00 100644 --- a/app.js +++ b/app.js @@ -39,6 +39,9 @@ app.use(bodyParser.json({ limit: POST_LIMIT })); +app.use(require('morgan')('dev')); + + var port = process.env.COPAY_PORT || 3001; var router = express.Router(); @@ -59,7 +62,6 @@ function returnError(err, res, req) { } var m = message || err.toString(); - console.log('[app.js.60]'); //TODO log.error('Error: ' + req.url + ' :' + code + ':' + m); res.status(code || 500).json({ error: m, @@ -144,6 +146,17 @@ router.get('/v1/wallets/', function(req, res) { }); }); + +router.get('/v1/txproposals/', function(req, res) { + getServerWithAuth(req, res, function(server) { + server.getPendingTxs({}, function(err, pendings) { + if (err) return returnError(err, res, req); + res.json(pendings); + }); + }); +}); + + router.post('/v1/txproposals/', function(req, res) { getServerWithAuth(req, res, function(server) { server.createTx(req.body, function(err, txp) { @@ -181,9 +194,9 @@ router.get('/v1/balance/', function(req, res) { }); }); -router.post('/v1/txproposals/:id/signatures', function(req, res) { - req.body.txProposalId = req.params['id']; +router.post('/v1/txproposals/:id/signatures/', function(req, res) { getServerWithAuth(req, res, function(server) { + req.body.txProposalId = req.params['id']; server.signTx(req.body, function(err, txp) { if (err) return returnError(err, res, req); res.end(); @@ -192,8 +205,8 @@ router.post('/v1/txproposals/:id/signatures', function(req, res) { }); router.post('/v1/txproposals/:id/rejections', function(req, res) { - req.body.txProposalId = req.params['id']; getServerWithAuth(req, res, function(server) { + req.body.txProposalId = req.params['id']; server.signTx(req.body, function(err, txp) { if (err) return returnError(err, res, req); res.end(); diff --git a/bit-wallet/bit b/bit-wallet/bit index 297adf8..1beaac6 100755 --- a/bit-wallet/bit +++ b/bit-wallet/bit @@ -1,7 +1,6 @@ #!/usr/bin/env node var program = require('commander'); -var cli = require('../lib/clilib.js'); program .version('0.0.1') @@ -12,6 +11,7 @@ program .command('addresses', 'list addresses') .command('balance', 'wallet balance') .command('send
', 'send bitcoins') + .command('sign ', 'sign a Transaction Proposal') .parse(process.argv); diff --git a/bit-wallet/bit-address b/bit-wallet/bit-address old mode 100644 new mode 100755 index c1f6ddc..217b78e --- a/bit-wallet/bit-address +++ b/bit-wallet/bit-address @@ -1,7 +1,7 @@ #!/usr/bin/env node var program = require('commander'); -var CliLib = require('../lib/clilib.js'); +var ClientLib = require('../lib/clientlib.js'); var common = require('./common'); program @@ -11,7 +11,7 @@ program .parse(process.argv); var args = program.args; -var cli = new CliLib({ +var cli = new ClientLib({ filename: program.config }); diff --git a/bit-wallet/bit-addresses b/bit-wallet/bit-addresses old mode 100644 new mode 100755 index 31f2a93..19614b1 --- a/bit-wallet/bit-addresses +++ b/bit-wallet/bit-addresses @@ -2,8 +2,8 @@ var _ = require('lodash'); var program = require('commander'); -var CliLib = require('../lib/clilib.js'); var common = require('./common'); +var ClientLib = require('../lib/clientlib.js'); program .version('0.0.1') @@ -12,7 +12,7 @@ program .parse(process.argv); var args = program.args; -var cli = new CliLib({ +var cli = new ClientLib({ filename: program.config }); diff --git a/bit-wallet/bit-balance b/bit-wallet/bit-balance old mode 100644 new mode 100755 index 7c95f3e..579bc07 --- a/bit-wallet/bit-balance +++ b/bit-wallet/bit-balance @@ -1,7 +1,7 @@ #!/usr/bin/env node var program = require('commander'); -var CliLib = require('../lib/clilib.js'); +var ClientLib = require('../lib/clientlib.js'); var common = require('./common'); program @@ -11,7 +11,7 @@ program .parse(process.argv); var args = program.args; -var cli = new CliLib({ +var cli = new ClientLib({ filename: program.config }); diff --git a/bit-wallet/bit-create b/bit-wallet/bit-create index 01137a6..710838e 100755 --- a/bit-wallet/bit-create +++ b/bit-wallet/bit-create @@ -1,7 +1,7 @@ #!/usr/bin/env node var program = require('commander'); -var CliLib = require('../lib/clilib.js'); +var ClientLib = require('../lib/clientlib.js'); var common = require('./common'); program @@ -21,7 +21,7 @@ var network = program.network; var mn = common.parseMN(args[1]); -var cli = new CliLib({ +var cli = new ClientLib({ filename: program.config }); cli.createWallet(walletName, copayerName, mn[0], mn[1], network, function(err, secret) { diff --git a/bit-wallet/bit-join b/bit-wallet/bit-join old mode 100644 new mode 100755 index 4a14659..f2a3424 --- a/bit-wallet/bit-join +++ b/bit-wallet/bit-join @@ -1,7 +1,7 @@ #!/usr/bin/env node var program = require('commander'); -var CliLib = require('../lib/clilib.js'); +var ClientLib = require('../lib/clientlib.js'); var common = require('./common'); program @@ -17,7 +17,7 @@ if (!args[0]) var secret = args[0]; var copayerName = args[1] || process.env.USER; -var cli = new CliLib({ +var cli = new ClientLib({ filename: program.config }); diff --git a/bit-wallet/bit-send b/bit-wallet/bit-send old mode 100644 new mode 100755 index 0fc35d3..7603bc5 --- a/bit-wallet/bit-send +++ b/bit-wallet/bit-send @@ -1,7 +1,7 @@ #!/usr/bin/env node var program = require('commander'); -var CliLib = require('../lib/clilib.js'); +var ClientLib = require('../lib/clientlib.js'); var common = require('./common'); program @@ -19,15 +19,15 @@ if (!args[0] || !args[1] || !args[2]) var amount = args[1]; var message = args[2]; - var cli = new CliLib({ -filename: program.config +var cli = new ClientLib({ + filename: program.config }); cli.send({toAddress: address, amount: amount, message:message}, function(err, x) { common.die(err); console.log(' * Tx created: ID %s [%s] RequiredSignatures:', - x.id, x.status, x.requiredSignatures); + x.id, x.status, x.requiredSignatures); if (program.verbose) - console.log('* Raw Server Response:\n', x); //TODO -}); + console.log('* Raw Server Response:\n', x); //TODO + }); diff --git a/bit-wallet/bit-sign b/bit-wallet/bit-sign new file mode 100755 index 0000000..bad5658 --- /dev/null +++ b/bit-wallet/bit-sign @@ -0,0 +1,52 @@ +#!/usr/bin/env node + +var _ = require('lodash'); +var program = require('commander'); +var ClientLib = require('../lib/clientlib.js'); +var common = require('./common'); + +program + .version('0.0.1') + .option('-c,--config [file]', 'Wallet config filename') + .option('-v,--verbose', 'be verbose') + .usage('[options] ') + .parse(process.argv); + +var args = program.args; +if (!args[0]) + program.help(); + +var txpid = args[0]; + +var cli = new ClientLib({ + filename: program.config +}); + +cli.txProposals({}, function(err, x) { + common.die(err); + + if (program.verbose) + console.log('* Raw Server Response:\n', x); //TODO + + var txps = _.filter(x, function(x) { + return _.endsWith(common.shortID(x.id), txpid); + }); + + if (!txps.length) + common.die('Could not find TX Proposal:' + txpid); + + if (txps.length > 1) + common.die('More that one TX Proposals match:' + txpid + ' : ' + _.map(txps, function(x) { + return x.id; + }).join(' '));; + + var txp = txps[0]; + cli.sign(txp, function(err, x) { + common.die(err); + + if (program.verbose) + console.log('* Raw Server Response:\n', x); //TODO + + console.log('Transaction signed.'); + }); +}); diff --git a/bit-wallet/bit-status b/bit-wallet/bit-status old mode 100644 new mode 100755 index 6d98416..8fe542d --- a/bit-wallet/bit-status +++ b/bit-wallet/bit-status @@ -1,7 +1,9 @@ #!/usr/bin/env node +var _ = require('lodash'); var program = require('commander'); -var CliLib = require('../lib/clilib.js'); + +var ClientLib = require('../lib/clientlib.js'); var common = require('./common'); program @@ -11,14 +13,33 @@ program .parse(process.argv); var args = program.args; -var cli = new CliLib({ +var cli = new ClientLib({ filename: program.config }); -cli.status(function(err, x) { +cli.status(function(err, res) { common.die(err); + + var x = res.wallet; console.log('* Wallet %s [%s]: %d-%d %s ', x.name, x.isTestnet ? 'testnet' : 'livenet', x.m, x.n, x.status); - if (program.verbose) - console.log('* Raw Server Response:\n', x); //TODO + var x = res.balance; + console.log('* Balance %d (Locked: %d)', x.totalAmount, x.lockedAmount); + + if (!_.isEmpty(res.pendingTxps)) { + console.log("* TX Proposals:") + _.each(res.pendingTxps, function(x) { + console.log("\t%s [%s by %s] %dSAT => %s", common.shortID(x.id), x.message, x.creatorName, x.amount, x.toAddress); + + if (!_.isEmpty(x.actions)) { + console.log('\t\t * Actions'); + console.log('\t\t', _.map(x.actions, function(a) { + return a.copayerName + ': ' + a.type + '' + }).join('. ')); + } + + if (program.verbose) + console.log('* Raw Server Response:\n', res); //TODO + }); + } }); diff --git a/bit-wallet/common.js b/bit-wallet/common.js index 7a6c256..5fe7337 100644 --- a/bit-wallet/common.js +++ b/bit-wallet/common.js @@ -24,4 +24,8 @@ common.parseMN = function(MN) { }; +common.shortID = function(id) { + return id.substr(id.length - 4); +}; + module.exports = common; diff --git a/lib/clilib.js b/lib/clientlib.js similarity index 74% rename from lib/clilib.js rename to lib/clientlib.js index 9ac09e1..e5ba809 100644 --- a/lib/clilib.js +++ b/lib/clientlib.js @@ -11,7 +11,7 @@ var fs = require('fs') var Bitcore = require('bitcore') var SignUtils = require('./signutils'); -var BASE_URL = 'http://localhost:3001/copay/api/'; +var BASE_URL = 'http://localhost:3001/copay/api'; function _createProposalOpts(opts, signingKey) { var msg = opts.toAddress + '|' + opts.amount + '|' + opts.message; @@ -43,29 +43,28 @@ function _signRequest(url, args, privKey) { return SignUtils.sign(message, privKey); }; -function _createXPrivKey() { - return new Bitcore.HDPrivateKey().toString(); +function _createXPrivKey(network) { + return new Bitcore.HDPrivateKey(network).toString(); }; -function CliLib(opts) { +function ClientLib(opts) { if (!opts.filename) { throw new Error('Please set the config filename'); } this.filename = opts.filename; }; - -CliLib.prototype._save = function(data) { +ClientLib.prototype._save = function(data) { fs.writeFileSync(this.filename, JSON.stringify(data)); }; -CliLib.prototype._load = function() { +ClientLib.prototype._load = function() { try { return JSON.parse(fs.readFileSync(this.filename)); } catch (ex) {} }; -CliLib.prototype._loadAndCheck = function() { +ClientLib.prototype._loadAndCheck = function() { var data = this._load(); if (!data) { log.error('Wallet file not found.'); @@ -85,18 +84,18 @@ CliLib.prototype._loadAndCheck = function() { return data; }; -CliLib.prototype.createWallet = function(walletName, copayerName, m, n, network, cb) { +ClientLib.prototype.createWallet = function(walletName, copayerName, m, n, network, cb) { var self = this; + network = network || 'livenet'; var data = this._load(); if (data) return cb('File ' + this.filename + ' already contains a wallet'); // Generate wallet key pair to verify copayers - var privKey = new Bitcore.PrivateKey(); + var privKey = new Bitcore.PrivateKey(null, network); var pubKey = privKey.toPublicKey(); data = { - xPrivKey: _createXPrivKey(), m: m, n: n, walletPrivKey: privKey.toString(), @@ -107,7 +106,7 @@ CliLib.prototype.createWallet = function(walletName, copayerName, m, n, network, m: m, n: n, pubKey: pubKey.toString(), - network: network || 'livenet', + network: network, }; request({ @@ -123,11 +122,10 @@ CliLib.prototype.createWallet = function(walletName, copayerName, m, n, network, } var walletId = body.walletId; - var secret = walletId + ':' + privKey.toString(); + var secret = walletId + ':' + privKey.toString() + ':' + (network ? 'T' : 'L'); data.secret = secret; self._save(data); - self._joinWallet(data, secret, copayerName, function(err) { if (err) return cb(err); @@ -136,18 +134,21 @@ CliLib.prototype.createWallet = function(walletName, copayerName, m, n, network, }); }; -CliLib.prototype._joinWallet = function(data, secret, copayerName, cb) { +ClientLib.prototype._joinWallet = function(data, secret, copayerName, cb) { var self = this; + data = data || {}; var secretSplit = secret.split(':'); var walletId = secretSplit[0]; + var walletPrivKey = Bitcore.PrivateKey.fromString(secretSplit[1]); + var network = secretSplit[2] == 'T' ? 'testnet' : 'livenet'; + data.xPrivKey = _createXPrivKey(network); var xPubKey = new Bitcore.HDPublicKey(data.xPrivKey); var xPubKeySignature = SignUtils.sign(xPubKey.toString(), walletPrivKey); var signingPrivKey = (new Bitcore.HDPrivateKey(data.xPrivKey)).derive('m/1/0').privateKey; - var args = { walletId: walletId, name: copayerName, @@ -180,20 +181,16 @@ CliLib.prototype._joinWallet = function(data, secret, copayerName, cb) { }); }; -CliLib.prototype.joinWallet = function(secret, copayerName, cb) { +ClientLib.prototype.joinWallet = function(secret, copayerName, cb) { var self = this; var data = this._load(); if (data) return cb('File ' + this.filename + ' already contains a wallet'); - data = { - xPrivKey: _createXPrivKey(), - }; - self._joinWallet(data, secret, copayerName, cb); }; -CliLib.prototype.status = function(cb) { +ClientLib.prototype.status = function(cb) { var self = this; var data = this._loadAndCheck(); @@ -253,7 +250,7 @@ CliLib.prototype.status = function(cb) { * @param inArgs.amount * @param inArgs.message */ -CliLib.prototype.send = function(inArgs, cb) { +ClientLib.prototype.send = function(inArgs, cb) { var self = this; var data = this._loadAndCheck(); @@ -282,16 +279,16 @@ CliLib.prototype.send = function(inArgs, cb) { }; // TODO check change address -CliLib.prototype.sign = function(proposalId, cb) { +ClientLib.prototype.sign = function(proposalId, cb) { }; -CliLib.prototype.reject = function(proposalId, cb) { +ClientLib.prototype.reject = function(proposalId, cb) { }; // Get addresses -CliLib.prototype.addresses = function(cb) { +ClientLib.prototype.addresses = function(cb) { var self = this; var data = this._loadAndCheck(); @@ -320,7 +317,7 @@ CliLib.prototype.addresses = function(cb) { // Creates a new address // TODO: verify derivation!! -CliLib.prototype.address = function(cb) { +ClientLib.prototype.address = function(cb) { var self = this; var data = this._loadAndCheck(); @@ -346,11 +343,11 @@ CliLib.prototype.address = function(cb) { }); }; -CliLib.prototype.history = function(limit, cb) { +ClientLib.prototype.history = function(limit, cb) { }; -CliLib.prototype.balance = function(cb) { +ClientLib.prototype.balance = function(cb) { var self = this; var data = this._loadAndCheck(); @@ -377,7 +374,7 @@ CliLib.prototype.balance = function(cb) { }; -CliLib.prototype.txProposals = function(cb) { +ClientLib.prototype.txProposals = function(opts, cb) { var self = this; var data = this._loadAndCheck(); @@ -403,5 +400,65 @@ CliLib.prototype.txProposals = function(cb) { }); }; +ClientLib.prototype.sign = function(txp, cb) { + var self = this; + var data = this._loadAndCheck(); -module.exports = CliLib; + + //Derive proper key to sign, for each input + var privs = [], + derived = {}; + + var network = new Bitcore.Address(txp.toAddress).network.name; + var xpriv = new Bitcore.HDPrivateKey(data.xPrivKey, network); + + _.each(txp.inputs, function(i) { + if (!derived[i.path]) { + derived[i.path] = xpriv.derive(i.path).privateKey; + } + privs.push(derived[i.path]); + }); + + var t = new Bitcore.Transaction(); + _.each(txp.inputs, function(i) { + t.from(i, i.publicKeys, txp.requiredSignatures); + }); + + t.to(txp.toAddress, txp.amount) + .change(txp.changeAddress) + .sign(privs); + + var signatures = []; + _.each(privs, function(p) { + var s = t.getSignatures(p)[0].signature.toDER().toString('hex'); + signatures.push(s); + }); + + var url = '/v1/txproposals/' + txp.id + '/signatures/'; + var args = { + signatures: signatures + }; + var reqSignature = _signRequest(url, args, data.signingPrivKey); +console.log('[clientlib.js.441:reqSignature:]',url, args, reqSignature); //TODO + + request({ + headers: { + 'x-identity': data.copayerId, + 'x-signature': reqSignature, + }, + method: 'post', + url: _getUrl(url), + body: args, + json: true, + }, function(err, res, body) { + if (err) return cb(err); + if (res.statusCode != 200) { + _parseError(body); + return cb('Request error'); + } + return cb(null, body); + }); +}; + + +module.exports = ClientLib; diff --git a/lib/model/txproposal.js b/lib/model/txproposal.js index 292f7c6..11546fd 100644 --- a/lib/model/txproposal.js +++ b/lib/model/txproposal.js @@ -69,6 +69,19 @@ TxProposal.prototype._updateStatus = function() { }; +TxProposal.prototype._getCurrentSignatures = function() { + var acceptedActions = _.filter(this.actions, function(x) { + return x && x.type == 'accept'; + }); + + return _.map(acceptedActions, function(x) { + return { + signatures: x.signatures, + xpub: x.xpub, + }; + }); +}; + TxProposal.prototype._getBitcoreTx = function() { var self = this; @@ -81,6 +94,13 @@ TxProposal.prototype._getBitcoreTx = function() { .change(this.changeAddress); t._updateChangeOutput(); + + + var sigs = this._getCurrentSignatures(); + _.each(sigs, function(x) { + self._addSignaturesToBitcoreTx(t, x.signatures, x.xpub); + }); + return t; }; @@ -121,22 +141,20 @@ TxProposal.prototype.getActionBy = function(copayerId) { }; }; -TxProposal.prototype.addAction = function(copayerId, type, signatures) { +TxProposal.prototype.addAction = function(copayerId, type, signatures, xpub) { var action = new TxProposalAction({ copayerId: copayerId, type: type, signatures: signatures, + xpub: xpub, }); this.actions[copayerId] = action; this._updateStatus(); }; -// TODO: no sure we should receive xpub or a list of pubkeys (pre derived) -TxProposal.prototype.checkSignatures = function(signatures, xpub) { +TxProposal.prototype._addSignaturesToBitcoreTx = function(t, signatures, xpub) { var self = this; - var t = this._getBitcoreTx(); - if (signatures.length != this.inputs.length) return false; @@ -159,17 +177,25 @@ TxProposal.prototype.checkSignatures = function(signatures, xpub) { t.applySignature(s); oks++; - } catch (e) { - // TODO only for debug now - console.log('DEBUG ONLY:', e.message); //TODO - }; + } catch (e) {}; }); - return oks === t.inputs.length; + + if (oks != t.inputs.length) + throw new Error('wrong signatures'); }; -TxProposal.prototype.sign = function(copayerId, signatures) { - this.addAction(copayerId, 'accept', signatures); +TxProposal.prototype.sign = function(copayerId, signatures, xpub) { + + // Tests signatures are OK + var t = this._getBitcoreTx(); + try { + this._addSignaturesToBitcoreTx(t, signatures, xpub); + this.addAction(copayerId, 'accept', signatures, xpub); + return true; + } catch (e) { + return false; + } }; TxProposal.prototype.reject = function(copayerId) { diff --git a/lib/model/txproposalaction.js b/lib/model/txproposalaction.js index 8e0f3af..13fa98b 100644 --- a/lib/model/txproposalaction.js +++ b/lib/model/txproposalaction.js @@ -7,6 +7,7 @@ function TxProposalAction(opts) { this.copayerId = opts.copayerId; this.type = opts.type || (opts.signatures ? 'accept' : 'reject'); this.signatures = opts.signatures; + this.xpub = opts.xpub; }; TxProposalAction.fromObj = function (obj) { @@ -16,6 +17,7 @@ TxProposalAction.fromObj = function (obj) { x.copayerId = obj.copayerId; x.type = obj.type; x.signatures = obj.signatures; + x.xpub = obj.xpub; return x; }; diff --git a/lib/server.js b/lib/server.js index 4b58469..02558b2 100644 --- a/lib/server.js +++ b/lib/server.js @@ -341,8 +341,11 @@ CopayServer.prototype._getUtxos = function(cb) { var networkName = Bitcore.Address(addressStrs[0]).toObject().network; var bc = self._getBlockExplorer('insight', networkName); - bc.getUnspentUtxos(addressStrs, function(err, utxos) { + bc.getUnspentUtxos(addressStrs, function(err, inutxos) { if (err) return cb(err); + var utxos = _.map(inutxos, function(i) { + return i.toObject(); + }); self.getPendingTxs({}, function(err, txps) { if (err) return cb(err); @@ -581,6 +584,7 @@ CopayServer.prototype.removePendingTx = function(opts, cb) { CopayServer.prototype._broadcastTx = function(txp, cb) { var raw = txp.getRawTx(); +console.log('[server.js.586:raw:]',raw); //TODO var bc = this._getBlockExplorer('insight', txp.getNetworkName()); bc.broadcast(raw, function(err, txid) { return cb(err, txid); @@ -617,11 +621,9 @@ CopayServer.prototype.signTx = function(opts, cb) { var copayer = wallet.getCopayer(self.copayerId); - if (!txp.checkSignatures(opts.signatures, copayer.xPubKey)) + if (!txp.sign(self.copayerId, opts.signatures, copayer.xPubKey)) return cb(new ClientError('BADSIGNATURES', 'Bad signatures')); - txp.sign(self.copayerId, opts.signatures); - self.storage.storeTx(self.walletId, txp, function(err) { if (err) return cb(err); diff --git a/package.json b/package.json index 3adba26..33c4327 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "dependencies": { "async": "^0.9.0", - "bitcore": "0.10.0", + "bitcore": "^0.10.3", "bitcore-explorers": "^0.9.1", "body-parser": "^1.11.0", "commander": "^2.6.0", @@ -26,7 +26,8 @@ "inherits": "^2.0.1", "leveldown": "^0.10.0", "levelup": "^0.19.0", - "lodash": "^2.4.1", + "lodash": "^3.2.0", + "morgan": "*", "npmlog": "^0.1.1", "preconditions": "^1.0.7", "request": "^2.53.0", diff --git a/test/integration.js b/test/integration.js index b4685f4..e80218c 100644 --- a/test/integration.js +++ b/test/integration.js @@ -114,7 +114,14 @@ helpers.createUtxos = function(server, wallet, amounts, cb) { }; -helpers.stubBlockExplorer = function(server, utxos, txid) { +helpers.stubBlockExplorer = function(server, inUtxos, txid) { + + var utxos = _.map(inUtxos, function(x) { + x.toObject = function() { + return this; + }; + return x; + }); var bc = sinon.stub(); bc.getUnspentUtxos = sinon.stub().callsArgWith(1, null, utxos); diff --git a/test/txproposal.js b/test/txproposal.js index a3709bf..c463a8b 100644 --- a/test/txproposal.js +++ b/test/txproposal.js @@ -28,15 +28,25 @@ describe('TXProposal', function() { describe('#sign', function() { it('should sign 2-2', function() { var txp = TXP.fromObj(aTXP()); - txp.sign('1', theSignatures); + txp.sign('1', theSignatures, theXPub); txp.isAccepted().should.equal(false); txp.isRejected().should.equal(false); - txp.sign('2', theSignatures); + txp.sign('2', theSignatures, theXPub); txp.isAccepted().should.equal(true); txp.isRejected().should.equal(false); }); }); + describe('#getRawTx', function() { + it('should generate correct raw transaction for signed 2-2', function() { + var txp = TXP.fromObj(aTXP()); + txp.sign('1', theSignatures, theXPub); + txp.getRawTx().should.equal('0100000001ab069f7073be9b491bb1ad4233a45d2e383082ccc7206df905662d6d8499e66e080000009200483045022100896aeb8db75fec22fddb5facf791927a996eb3aee23ee6deaa15471ea46047de02204c0c33f42a9d3ff93d62738712a8c8a5ecd21b45393fdd144e7b01b5a186f1f9014752210319008ffe1b3e208f5ebed8f46495c056763f87b07930a7027a92ee477fb0cb0f2103b5f035af8be40d0db5abb306b7754949ab39032cf99ad177691753b37d10130152aeffffffff0280f0fa02000000001976a91451224bca38efcaa31d5340917c3f3f713b8b20e488ac70c9fa020000000017a914778192003f0e9e1d865c082179cc3dae5464b03d8700000000'); + }); + }); + + + describe('#reject', function() { it('should reject 2-2', function() { var txp = TXP.fromObj(aTXP()); @@ -59,26 +69,10 @@ describe('TXProposal', function() { }); }); - - describe('#checkSignatures', function() { - it('should check signatures', function() { - var txp = TXP.fromObj(aTXP()); - var xpriv = new Bitcore.HDPrivateKey(theXPriv); - var priv = xpriv.derive(txp.inputPaths[0]).privateKey; - - var t = txp._getBitcoreTx(); - t.sign(priv); - - var s = t.getSignatures(priv)[0].signature.toDER().toString('hex'); - var xpub = new Bitcore.HDPublicKey(xpriv); - - var res = txp.checkSignatures([s], xpub); - res.should.equal(true); - }); - }); }); var theXPriv = 'xprv9s21ZrQH143K2rMHbXTJmWTuFx6ssqn1vyRoZqPkCXYchBSkp5ey8kMJe84sxfXq5uChWH4gk94rWbXZt2opN9kg4ufKGvUM7HQSLjnoh7e'; +var theXPub = 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9'; var theSignatures = ['3045022100896aeb8db75fec22fddb5facf791927a996eb3aee23ee6deaa15471ea46047de02204c0c33f42a9d3ff93d62738712a8c8a5ecd21b45393fdd144e7b01b5a186f1f9']; var aTXP = function() {