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();
+
+
+ //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 = CliLib;
+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() {