Merge pull request #23 from isocolsky/ref/createTx
WIP Added signature to tx proposal creation
This commit is contained in:
commit
ebc7e2e885
|
@ -19,6 +19,7 @@ function TxProposal(opts) {
|
||||||
this.toAddress = opts.toAddress;
|
this.toAddress = opts.toAddress;
|
||||||
this.amount = opts.amount;
|
this.amount = opts.amount;
|
||||||
this.message = opts.message;
|
this.message = opts.message;
|
||||||
|
this.proposalSignature = opts.proposalSignature;
|
||||||
this.changeAddress = opts.changeAddress;
|
this.changeAddress = opts.changeAddress;
|
||||||
this.inputs = opts.inputs;
|
this.inputs = opts.inputs;
|
||||||
this.inputPaths = opts.inputPaths;
|
this.inputPaths = opts.inputPaths;
|
||||||
|
@ -38,6 +39,7 @@ TxProposal.fromObj = function(obj) {
|
||||||
x.toAddress = obj.toAddress;
|
x.toAddress = obj.toAddress;
|
||||||
x.amount = obj.amount;
|
x.amount = obj.amount;
|
||||||
x.message = obj.message;
|
x.message = obj.message;
|
||||||
|
x.proposalSignature = obj.proposalSignature;
|
||||||
x.changeAddress = obj.changeAddress;
|
x.changeAddress = obj.changeAddress;
|
||||||
x.inputs = obj.inputs;
|
x.inputs = obj.inputs;
|
||||||
x.requiredSignatures = obj.requiredSignatures;
|
x.requiredSignatures = obj.requiredSignatures;
|
||||||
|
|
|
@ -82,6 +82,10 @@ Wallet.fromObj = function(obj) {
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Wallet.prototype.isShared = function() {
|
||||||
|
return this.n > 1;
|
||||||
|
};
|
||||||
|
|
||||||
Wallet.prototype.addCopayer = function(copayer) {
|
Wallet.prototype.addCopayer = function(copayer) {
|
||||||
this.copayers.push(copayer);
|
this.copayers.push(copayer);
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ CopayServer.initialize = function(opts) {
|
||||||
*/
|
*/
|
||||||
CopayServer.getInstanceWithAuth = function(opts, cb) {
|
CopayServer.getInstanceWithAuth = function(opts, cb) {
|
||||||
|
|
||||||
Utils.checkRequired(opts, ['copayerId', 'message', 'signature']);
|
if (!Utils.checkRequired(opts, ['copayerId', 'message', 'signature'])) return cb(new ClientError('Required argument missing'));
|
||||||
|
|
||||||
var server = new CopayServer();
|
var server = new CopayServer();
|
||||||
server.storage.fetchCopayerLookup(opts.copayerId, function(err, copayer) {
|
server.storage.fetchCopayerLookup(opts.copayerId, function(err, copayer) {
|
||||||
|
@ -89,7 +89,7 @@ CopayServer.prototype.createWallet = function(opts, cb) {
|
||||||
var self = this,
|
var self = this,
|
||||||
pubKey;
|
pubKey;
|
||||||
|
|
||||||
Utils.checkRequired(opts, ['name', 'm', 'n', 'pubKey']);
|
if (!Utils.checkRequired(opts, ['name', 'm', 'n', 'pubKey'])) return cb(new ClientError('Required argument missing'));
|
||||||
|
|
||||||
if (_.isEmpty(opts.name)) return cb(new ClientError('Invalid wallet name'));
|
if (_.isEmpty(opts.name)) return cb(new ClientError('Invalid wallet name'));
|
||||||
if (!Wallet.verifyCopayerLimits(opts.m, opts.n))
|
if (!Wallet.verifyCopayerLimits(opts.m, opts.n))
|
||||||
|
@ -155,7 +155,7 @@ CopayServer.prototype._verifySignature = function(text, signature, pubKey) {
|
||||||
CopayServer.prototype.joinWallet = function(opts, cb) {
|
CopayServer.prototype.joinWallet = function(opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
Utils.checkRequired(opts, ['walletId', 'name', 'xPubKey', 'xPubKeySignature']);
|
if (!Utils.checkRequired(opts, ['walletId', 'name', 'xPubKey', 'xPubKeySignature'])) return cb(new ClientError('Required argument missing'));
|
||||||
|
|
||||||
if (_.isEmpty(opts.name)) return cb(new ClientError('Invalid copayer name'));
|
if (_.isEmpty(opts.name)) return cb(new ClientError('Invalid copayer name'));
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ CopayServer.prototype.getAddresses = function(opts, cb) {
|
||||||
CopayServer.prototype.verifyMessageSignature = function(opts, cb) {
|
CopayServer.prototype.verifyMessageSignature = function(opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
Utils.checkRequired(opts, ['message', 'signature']);
|
if (!Utils.checkRequired(opts, ['message', 'signature'])) return cb(new ClientError('Required argument missing'));
|
||||||
|
|
||||||
self.getWallet({}, function(err, wallet) {
|
self.getWallet({}, function(err, wallet) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
@ -384,17 +384,23 @@ CopayServer.prototype._selectUtxos = function(txp, utxos) {
|
||||||
* @param {string} opts.toAddress - Destination address.
|
* @param {string} opts.toAddress - Destination address.
|
||||||
* @param {number} opts.amount - Amount to transfer in satoshi.
|
* @param {number} opts.amount - Amount to transfer in satoshi.
|
||||||
* @param {string} opts.message - A message to attach to this transaction.
|
* @param {string} opts.message - A message to attach to this transaction.
|
||||||
|
* @param {string} opts.proposalSignature - S(toAddress + '|' + amount + '|' + message). Used by other copayers to verify the proposal. Optional in 1-of-1 wallets.
|
||||||
* @returns {TxProposal} Transaction proposal.
|
* @returns {TxProposal} Transaction proposal.
|
||||||
*/
|
*/
|
||||||
CopayServer.prototype.createTx = function(opts, cb) {
|
CopayServer.prototype.createTx = function(opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
Utils.checkRequired(opts, ['toAddress', 'amount']);
|
if (!Utils.checkRequired(opts, ['toAddress', 'amount'])) return cb(new ClientError('Required argument missing'));
|
||||||
|
|
||||||
Utils.runLocked(self.walletId, cb, function(cb) {
|
Utils.runLocked(self.walletId, cb, function(cb) {
|
||||||
self.getWallet({}, function(err, wallet) {
|
self.getWallet({}, function(err, wallet) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
if (!wallet.isComplete()) return cb(new ClientError('Wallet is not complete'));
|
if (!wallet.isComplete()) return cb(new ClientError('Wallet is not complete'));
|
||||||
|
if (wallet.isShared() && !Utils.checkRequired(opts, 'proposalSignature')) return cb(new ClientError('Proposal signature is required for shared wallets'));
|
||||||
|
|
||||||
|
var copayer = wallet.getCopayer(self.copayerId);
|
||||||
|
var msg = opts.toAddress + '|' + opts.amount + '|' + opts.message;
|
||||||
|
if (!self._verifySignature(msg, opts.proposalSignature, copayer.signingPubKey)) return cb(new ClientError('Invalid proposal signature'));
|
||||||
|
|
||||||
var toAddress;
|
var toAddress;
|
||||||
try {
|
try {
|
||||||
|
@ -486,7 +492,7 @@ CopayServer.prototype._broadcastTx = function(txp, cb) {
|
||||||
CopayServer.prototype.signTx = function(opts, cb) {
|
CopayServer.prototype.signTx = function(opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
Utils.checkRequired(opts, ['txProposalId', 'signatures']);
|
if (!Utils.checkRequired(opts, ['txProposalId', 'signatures'])) return cb(new ClientError('Required argument missing'));
|
||||||
|
|
||||||
self.getWallet({}, function(err, wallet) {
|
self.getWallet({}, function(err, wallet) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
@ -542,7 +548,7 @@ CopayServer.prototype.signTx = function(opts, cb) {
|
||||||
CopayServer.prototype.rejectTx = function(opts, cb) {
|
CopayServer.prototype.rejectTx = function(opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
Utils.checkRequired(opts, ['txProposalId']);
|
if (!Utils.checkRequired(opts, ['txProposalId'])) return cb(new ClientError('Required argument missing'));
|
||||||
|
|
||||||
self.getTx({
|
self.getTx({
|
||||||
id: opts.txProposalId
|
id: opts.txProposalId
|
||||||
|
|
19
lib/utils.js
19
lib/utils.js
|
@ -4,11 +4,11 @@ var Lock = require('./lock');
|
||||||
|
|
||||||
var Utils = {};
|
var Utils = {};
|
||||||
|
|
||||||
Utils.runLocked = function (token, cb, task) {
|
Utils.runLocked = function(token, cb, task) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
Lock.get(token, function (lock) {
|
Lock.get(token, function(lock) {
|
||||||
var _cb = function () {
|
var _cb = function() {
|
||||||
cb.apply(null, arguments);
|
cb.apply(null, arguments);
|
||||||
lock.free();
|
lock.free();
|
||||||
};
|
};
|
||||||
|
@ -17,16 +17,17 @@ Utils.runLocked = function (token, cb, task) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Utils.checkRequired = function (obj, args) {
|
Utils.checkRequired = function(obj, args) {
|
||||||
args = [].concat(args);
|
args = [].concat(args);
|
||||||
if (!_.isObject(obj)) throw 'Required arguments missing';
|
if (!_.isObject(obj)) return false;
|
||||||
_.each(args, function (arg) {
|
for (var i = 0; i < args.length; i++) {
|
||||||
if (!obj.hasOwnProperty(arg)) throw "Missing required argument '" + arg + "'";
|
if (!obj.hasOwnProperty(args[i])) return false;
|
||||||
});
|
}
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @desc rounds a JAvascript number
|
* @desc rounds a JAvascript number
|
||||||
* @param number
|
* @param number
|
||||||
* @return {number}
|
* @return {number}
|
||||||
|
|
|
@ -18,45 +18,7 @@ var Wallet = require('../lib/model/wallet');
|
||||||
var Address = require('../lib/model/address');
|
var Address = require('../lib/model/address');
|
||||||
var Copayer = require('../lib/model/copayer');
|
var Copayer = require('../lib/model/copayer');
|
||||||
var CopayServer = require('../lib/server');
|
var CopayServer = require('../lib/server');
|
||||||
|
var TestData = require('./testdata');
|
||||||
var keyPair = {
|
|
||||||
priv: '0dea92f1df6675085b5cdd965487bb862f84f2755bcb56fa45dbf5b387a6c4a0',
|
|
||||||
pub: '026092daeed8ecb2212869395770e956ffc9bf453f803e700f64ffa70c97a00d80',
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var aPubKey = '042F65F56A6C06C2B651C473AC221B2460DA57859AFB72564E9781B655EBC0AFAF322B9A732324ECC92A3319DFB1F0D53F0CB7E6620C98BD1EF53106A7CF3F6DB9';
|
|
||||||
var aXPubKey = 'xpub661MyMwAqRbcFHFFvUP6HaKdd2FYzNcZCGagxMzQEf1J3x2DeASBW2JWox7ToGwPM7V2yRzQAxcD6MdPid9C8kwhKkVWBxQ3dMo8zu3pub7';
|
|
||||||
var aXPubKeySignature = '3045022100f988737147894bbfdc196c1289e4d970b391c0d8e9d1fcc0397f16e6a31c9df2022014d9af9aceccb540f4a5a2680e2aebb1f3df55bcf3778599b78314a02064c592'; // with keyPair.priv
|
|
||||||
|
|
||||||
// Copayers
|
|
||||||
|
|
||||||
var someXPrivKey = [
|
|
||||||
'xprv9s21ZrQH143K2rMHbXTJmWTuFx6ssqn1vyRoZqPkCXYchBSkp5ey8kMJe84sxfXq5uChWH4gk94rWbXZt2opN9kg4ufKGvUM7HQSLjnoh7e',
|
|
||||||
];
|
|
||||||
|
|
||||||
var someXPubKeys = [
|
|
||||||
'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9',
|
|
||||||
'xpub661MyMwAqRbcEzHgVwwxoXksq21rRNsJsn7AFy4VD4PzsEmjjWwsyEiTjsdQviXbqZ5yHVWJR8zFUDgUKkq4R97su3UyNo36Z8hSaCPrv6o',
|
|
||||||
'xpub661MyMwAqRbcFXUfkjfSaRwxJbAPpzNUvTiNFjgZwDJ8sZuhyodkP24L4LvsrgThYAAwKkVVSSmL7Ts7o9EHEHPB3EE89roAra7njoSeiMd',
|
|
||||||
'xpub661MyMwAqRbcGpExxHEzAWxBQX3k76NyerSpjqucSXXfTqH6Wq9sUVRwTjpHZHwapDbG16KEB9w9r3LT2jKYqU9xJf1YBAaZFikbUHiV1tg',
|
|
||||||
'xpub661MyMwAqRbcEvKQnt9ELHHcangXssm174sWr5gNTSmQYsAtvQJNUpLETDTm1vDxwtABvB4SRjGkNMm37NnMerKg4e3ygqmWEr75Fka4dK7',
|
|
||||||
'xpub661MyMwAqRbcG67ioS7rz3fFg7EDQNLJ9m1etAPwBecZhL5kKAKe4JU5jCTzRcEWp28XCYA1gKh7jyficSr97gcR2pjDL5jbWua1CwTKWV4',
|
|
||||||
];
|
|
||||||
|
|
||||||
// with keyPair.priv
|
|
||||||
var someXPubKeysSignatures = [
|
|
||||||
'30440220192ae7345d980f45f908bd63ccad60ce04270d07b91f1a9d92424a07a38af85202201591f0f71dd4e79d9206d2306862e6b8375e13a62c193953d768e884b6fb5a46',
|
|
||||||
'30440220134d13139323ba16ff26471c415035679ee18b2281bf85550ccdf6a370899153022066ef56ff97091b9be7dede8e40f50a3a8aad8205f2e3d8e194f39c20f3d15c62',
|
|
||||||
'304402207a4e7067d823a98fa634f9c9d991b8c42cd0f82da24f686992acf96cdeb5e387022021ceba729bf763fc8e4277f6851fc2b856a82a22b35f20d2eeb23d99c5f5a41c',
|
|
||||||
'304402203ae5bf7fa8935b8ab2ac33724dbb191356cecb47c8371d2c9389e918a3600918022073b48705306730c8fe4ab22d5f6ed3ca3def27eb6e8c5cc8f53e23c11fa5e5ef',
|
|
||||||
'3045022100eabd2a605403b377a8db9eec57726da0309a7eb385e7e4e5273b9862046f25ef02204d18755a90580a98f45e162ae5d5dc39aa3aa708a0d79433ed259e70a832b49c',
|
|
||||||
'3045022100c282254773c65025054e18a61ee550cbf78b88fc72ef66770050815b62502d9c02206e0df528203c9201c144f865df71f5d2471668f4ed8387979fcee20f6fa121a9',
|
|
||||||
];
|
|
||||||
|
|
||||||
//Copayer signature
|
|
||||||
var aText = 'hello world';
|
|
||||||
var aTextSignature = '3045022100addd20e5413865d65d561ad2979f2289a40d52594b1f804840babd9a63e4ebbf02204b86285e1fcab02df772e7a1325fc4b511ecad79a8f80a2bd1ad8bfa858ac3d4'; // with someXPrivKey[0].derive('m/1/0')=5c0e043a513032907d181325a8e7990b076c0af15ed13dc5e611cda9bb3ae52a;
|
|
||||||
|
|
||||||
|
|
||||||
var helpers = {};
|
var helpers = {};
|
||||||
|
@ -82,18 +44,17 @@ helpers.createAndJoinWallet = function(m, n, cb) {
|
||||||
name: 'a wallet',
|
name: 'a wallet',
|
||||||
m: m,
|
m: m,
|
||||||
n: n,
|
n: n,
|
||||||
pubKey: keyPair.pub,
|
pubKey: TestData.keyPair.pub,
|
||||||
};
|
};
|
||||||
server.createWallet(walletOpts, function(err, walletId) {
|
server.createWallet(walletOpts, function(err, walletId) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
async.each(_.range(1, n + 1), function(i, cb) {
|
async.each(_.range(n), function(i, cb) {
|
||||||
|
|
||||||
var copayerOpts = {
|
var copayerOpts = {
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
name: 'copayer ' + i,
|
name: 'copayer ' + (i + 1),
|
||||||
xPubKey: someXPubKeys[i - 1],
|
xPubKey: TestData.copayers[i].xPubKey,
|
||||||
xPubKeySignature: someXPubKeysSignatures[i - 1],
|
xPubKeySignature: TestData.copayers[i].xPubKeySignature,
|
||||||
};
|
};
|
||||||
|
|
||||||
server.joinWallet(copayerOpts, function(err, copayerId) {
|
server.joinWallet(copayerOpts, function(err, copayerId) {
|
||||||
|
@ -105,7 +66,7 @@ helpers.createAndJoinWallet = function(m, n, cb) {
|
||||||
|
|
||||||
helpers.getAuthServer(copayerIds[0], function(s) {
|
helpers.getAuthServer(copayerIds[0], function(s) {
|
||||||
s.getWallet({}, function(err, w) {
|
s.getWallet({}, function(err, w) {
|
||||||
cb(s, w);
|
cb(s, w, _.take(TestData.copayers, w.n));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -173,7 +134,7 @@ helpers.clientSign = function(tx, xpriv, n) {
|
||||||
//Derive proper key to sign, for each input
|
//Derive proper key to sign, for each input
|
||||||
var privs = [],
|
var privs = [],
|
||||||
derived = {};
|
derived = {};
|
||||||
var xpriv = new Bitcore.HDPrivateKey(someXPrivKey[0]);
|
var xpriv = new Bitcore.HDPrivateKey(TestData.copayers[0].xPrivKey);
|
||||||
|
|
||||||
_.each(tx.inputs, function(i) {
|
_.each(tx.inputs, function(i) {
|
||||||
if (!derived[i.path]) {
|
if (!derived[i.path]) {
|
||||||
|
@ -201,6 +162,11 @@ helpers.clientSign = function(tx, xpriv, n) {
|
||||||
return signatures;
|
return signatures;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
helpers.addProposalSignature = function(txOpts, privKey) {
|
||||||
|
var msg = txOpts.toAddress + '|' + txOpts.amount + '|' + txOpts.message;
|
||||||
|
txOpts.proposalSignature = SignUtils.sign(msg, privKey);
|
||||||
|
};
|
||||||
|
|
||||||
var db, storage;
|
var db, storage;
|
||||||
|
|
||||||
|
|
||||||
|
@ -238,7 +204,7 @@ describe('Copay server', function() {
|
||||||
name: 'my wallet',
|
name: 'my wallet',
|
||||||
m: 2,
|
m: 2,
|
||||||
n: 3,
|
n: 3,
|
||||||
pubKey: aPubKey,
|
pubKey: TestData.keyPair.pub,
|
||||||
};
|
};
|
||||||
server.createWallet(opts, function(err, walletId) {
|
server.createWallet(opts, function(err, walletId) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
|
@ -256,7 +222,7 @@ describe('Copay server', function() {
|
||||||
name: '',
|
name: '',
|
||||||
m: 2,
|
m: 2,
|
||||||
n: 3,
|
n: 3,
|
||||||
pubKey: aPubKey,
|
pubKey: TestData.keyPair.pub,
|
||||||
};
|
};
|
||||||
server.createWallet(opts, function(err, walletId) {
|
server.createWallet(opts, function(err, walletId) {
|
||||||
should.not.exist(walletId);
|
should.not.exist(walletId);
|
||||||
|
@ -289,7 +255,7 @@ describe('Copay server', function() {
|
||||||
var opts = {
|
var opts = {
|
||||||
id: '123',
|
id: '123',
|
||||||
name: 'my wallet',
|
name: 'my wallet',
|
||||||
pubKey: aPubKey,
|
pubKey: TestData.keyPair.pub,
|
||||||
};
|
};
|
||||||
async.each(invalidPairs, function(pair, cb) {
|
async.each(invalidPairs, function(pair, cb) {
|
||||||
opts.m = pair.m;
|
opts.m = pair.m;
|
||||||
|
@ -313,7 +279,7 @@ describe('Copay server', function() {
|
||||||
name: 'my wallet',
|
name: 'my wallet',
|
||||||
m: 2,
|
m: 2,
|
||||||
n: 3,
|
n: 3,
|
||||||
pubKey: keyPair.pub,
|
pubKey: TestData.keyPair.pub,
|
||||||
};
|
};
|
||||||
server.createWallet(walletOpts, function(err, wId) {
|
server.createWallet(walletOpts, function(err, wId) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
|
@ -327,8 +293,8 @@ describe('Copay server', function() {
|
||||||
var copayerOpts = {
|
var copayerOpts = {
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
name: 'me',
|
name: 'me',
|
||||||
xPubKey: aXPubKey,
|
xPubKey: TestData.copayers[0].xPubKey,
|
||||||
xPubKeySignature: aXPubKeySignature,
|
xPubKeySignature: TestData.copayers[0].xPubKeySignature,
|
||||||
};
|
};
|
||||||
server.joinWallet(copayerOpts, function(err, copayerId) {
|
server.joinWallet(copayerOpts, function(err, copayerId) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
|
@ -349,8 +315,8 @@ describe('Copay server', function() {
|
||||||
var copayerOpts = {
|
var copayerOpts = {
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
name: '',
|
name: '',
|
||||||
xPubKey: someXPubKeys[0],
|
xPubKey: TestData.copayers[0].xPubKey,
|
||||||
xPubKeySignature: someXPubKeysSignatures[0],
|
xPubKeySignature: TestData.copayers[0].xPubKeySignature,
|
||||||
};
|
};
|
||||||
server.joinWallet(copayerOpts, function(err, copayerId) {
|
server.joinWallet(copayerOpts, function(err, copayerId) {
|
||||||
should.not.exist(copayerId);
|
should.not.exist(copayerId);
|
||||||
|
@ -378,8 +344,8 @@ describe('Copay server', function() {
|
||||||
var copayerOpts = {
|
var copayerOpts = {
|
||||||
walletId: wallet.id,
|
walletId: wallet.id,
|
||||||
name: 'me',
|
name: 'me',
|
||||||
xPubKey: someXPubKeys[1],
|
xPubKey: TestData.copayers[1].xPubKey,
|
||||||
xPubKeySignature: someXPubKeysSignatures[1],
|
xPubKeySignature: TestData.copayers[1].xPubKeySignature,
|
||||||
};
|
};
|
||||||
server.joinWallet(copayerOpts, function(err) {
|
server.joinWallet(copayerOpts, function(err) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
|
@ -394,8 +360,8 @@ describe('Copay server', function() {
|
||||||
var copayerOpts = {
|
var copayerOpts = {
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
name: 'me',
|
name: 'me',
|
||||||
xPubKey: someXPubKeys[0],
|
xPubKey: TestData.copayers[0].xPubKey,
|
||||||
xPubKeySignature: someXPubKeysSignatures[0],
|
xPubKeySignature: TestData.copayers[0].xPubKeySignature,
|
||||||
};
|
};
|
||||||
server.joinWallet(copayerOpts, function(err) {
|
server.joinWallet(copayerOpts, function(err) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
|
@ -412,7 +378,7 @@ describe('Copay server', function() {
|
||||||
var copayerOpts = {
|
var copayerOpts = {
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
name: 'me',
|
name: 'me',
|
||||||
xPubKey: someXPubKeys[0],
|
xPubKey: TestData.copayers[0].xPubKey,
|
||||||
xPubKeySignature: 'bad sign',
|
xPubKeySignature: 'bad sign',
|
||||||
};
|
};
|
||||||
server.joinWallet(copayerOpts, function(err) {
|
server.joinWallet(copayerOpts, function(err) {
|
||||||
|
@ -425,22 +391,21 @@ describe('Copay server', function() {
|
||||||
var copayerOpts = {
|
var copayerOpts = {
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
name: 'me',
|
name: 'me',
|
||||||
xPubKey: someXPubKeys[0],
|
xPubKey: TestData.copayers[0].xPubKey[0],
|
||||||
};
|
};
|
||||||
try {
|
server.joinWallet(copayerOpts, function(err) {
|
||||||
server.joinWallet(copayerOpts, function(err) {});
|
err.should.exist;
|
||||||
} catch (e) {
|
err.message.should.contain('argument missing');
|
||||||
e.should.contain('xPubKeySignature');
|
|
||||||
done();
|
done();
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail to join with wrong signature', function(done) {
|
it('should fail to join with wrong signature', function(done) {
|
||||||
var copayerOpts = {
|
var copayerOpts = {
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
name: 'me',
|
name: 'me',
|
||||||
xPubKey: someXPubKeys[0],
|
xPubKey: TestData.copayers[0].xPubKey,
|
||||||
xPubKeySignature: someXPubKeysSignatures[1],
|
xPubKeySignature: TestData.copayers[1].xPubKeySignature,
|
||||||
};
|
};
|
||||||
server.joinWallet(copayerOpts, function(err) {
|
server.joinWallet(copayerOpts, function(err) {
|
||||||
err.message.should.equal('Bad request');
|
err.message.should.equal('Bad request');
|
||||||
|
@ -473,8 +438,8 @@ describe('Copay server', function() {
|
||||||
|
|
||||||
it('should successfully verify message signature', function(done) {
|
it('should successfully verify message signature', function(done) {
|
||||||
var opts = {
|
var opts = {
|
||||||
message: aText,
|
message: TestData.message.text,
|
||||||
signature: aTextSignature,
|
signature: TestData.message.signature,
|
||||||
};
|
};
|
||||||
server.verifyMessageSignature(opts, function(err, isValid) {
|
server.verifyMessageSignature(opts, function(err, isValid) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
|
@ -485,8 +450,8 @@ describe('Copay server', function() {
|
||||||
|
|
||||||
it('should fail to verify message signature for different copayer', function(done) {
|
it('should fail to verify message signature for different copayer', function(done) {
|
||||||
var opts = {
|
var opts = {
|
||||||
message: aText,
|
message: TestData.message.text,
|
||||||
signature: aTextSignature,
|
signature: TestData.message.signature,
|
||||||
};
|
};
|
||||||
helpers.getAuthServer(wallet.copayers[1].id, function(server) {
|
helpers.getAuthServer(wallet.copayers[1].id, function(server) {
|
||||||
server.verifyMessageSignature(opts, function(err, isValid) {
|
server.verifyMessageSignature(opts, function(err, isValid) {
|
||||||
|
@ -512,7 +477,7 @@ describe('Copay server', function() {
|
||||||
server.createAddress({}, function(err, address) {
|
server.createAddress({}, function(err, address) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
address.should.exist;
|
address.should.exist;
|
||||||
address.address.should.equal('36JdLEUDa6UwCfMhhkdZ2VFnDrGUoLedsR');
|
address.address.should.equal('38Jf1QE7ddXscW76ACgJrNkMWBwDAgMm6M');
|
||||||
address.path.should.equal('m/2147483647/0/0');
|
address.path.should.equal('m/2147483647/0/0');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -524,15 +489,15 @@ describe('Copay server', function() {
|
||||||
name: 'my wallet',
|
name: 'my wallet',
|
||||||
m: 2,
|
m: 2,
|
||||||
n: 3,
|
n: 3,
|
||||||
pubKey: keyPair.pub,
|
pubKey: TestData.keyPair.pub,
|
||||||
};
|
};
|
||||||
server.createWallet(walletOpts, function(err, walletId) {
|
server.createWallet(walletOpts, function(err, walletId) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
var copayerOpts = {
|
var copayerOpts = {
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
name: 'me',
|
name: 'me',
|
||||||
xPubKey: aXPubKey,
|
xPubKey: TestData.copayers[0].xPubKey,
|
||||||
xPubKeySignature: aXPubKeySignature,
|
xPubKeySignature: TestData.copayers[0].xPubKeySignature,
|
||||||
};
|
};
|
||||||
server.joinWallet(copayerOpts, function(err, copayerId) {
|
server.joinWallet(copayerOpts, function(err, copayerId) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
|
@ -576,7 +541,7 @@ describe('Copay server', function() {
|
||||||
server.createAddress({}, function(err, address) {
|
server.createAddress({}, function(err, address) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
address.should.exist;
|
address.should.exist;
|
||||||
address.address.should.equal('36JdLEUDa6UwCfMhhkdZ2VFnDrGUoLedsR');
|
address.address.should.equal('38Jf1QE7ddXscW76ACgJrNkMWBwDAgMm6M');
|
||||||
address.path.should.equal('m/2147483647/0/0');
|
address.path.should.equal('m/2147483647/0/0');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -586,11 +551,12 @@ describe('Copay server', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#createTx', function() {
|
describe('#createTx', function() {
|
||||||
var server, wallet;
|
var server, wallet, copayerPriv;
|
||||||
beforeEach(function(done) {
|
beforeEach(function(done) {
|
||||||
helpers.createAndJoinWallet(2, 2, function(s, w) {
|
helpers.createAndJoinWallet(2, 2, function(s, w, c) {
|
||||||
server = s;
|
server = s;
|
||||||
wallet = w;
|
wallet = w;
|
||||||
|
copayerPriv = c;
|
||||||
server.createAddress({}, function(err, address) {
|
server.createAddress({}, function(err, address) {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -605,6 +571,7 @@ describe('Copay server', function() {
|
||||||
amount: helpers.toSatoshi(80),
|
amount: helpers.toSatoshi(80),
|
||||||
message: 'some message',
|
message: 'some message',
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
|
|
||||||
server.createTx(txOpts, function(err, tx) {
|
server.createTx(txOpts, function(err, tx) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
|
@ -632,15 +599,15 @@ describe('Copay server', function() {
|
||||||
name: 'my wallet',
|
name: 'my wallet',
|
||||||
m: 2,
|
m: 2,
|
||||||
n: 3,
|
n: 3,
|
||||||
pubKey: keyPair.pub,
|
pubKey: TestData.keyPair.pub,
|
||||||
};
|
};
|
||||||
server.createWallet(walletOpts, function(err, walletId) {
|
server.createWallet(walletOpts, function(err, walletId) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
var copayerOpts = {
|
var copayerOpts = {
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
name: 'me',
|
name: 'me',
|
||||||
xPubKey: aXPubKey,
|
xPubKey: TestData.copayers[0].xPubKey,
|
||||||
xPubKeySignature: aXPubKeySignature,
|
xPubKeySignature: TestData.copayers[0].xPubKeySignature,
|
||||||
};
|
};
|
||||||
server.joinWallet(copayerOpts, function(err, copayerId) {
|
server.joinWallet(copayerOpts, function(err, copayerId) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
|
@ -649,6 +616,7 @@ describe('Copay server', function() {
|
||||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||||
amount: helpers.toSatoshi(80),
|
amount: helpers.toSatoshi(80),
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
server.createTx(txOpts, function(err, tx) {
|
server.createTx(txOpts, function(err, tx) {
|
||||||
should.not.exist(tx);
|
should.not.exist(tx);
|
||||||
err.should.exist;
|
err.should.exist;
|
||||||
|
@ -667,6 +635,7 @@ describe('Copay server', function() {
|
||||||
toAddress: 'invalid address',
|
toAddress: 'invalid address',
|
||||||
amount: helpers.toSatoshi(80),
|
amount: helpers.toSatoshi(80),
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
|
|
||||||
server.createTx(txOpts, function(err, tx) {
|
server.createTx(txOpts, function(err, tx) {
|
||||||
should.not.exist(tx);
|
should.not.exist(tx);
|
||||||
|
@ -685,6 +654,7 @@ describe('Copay server', function() {
|
||||||
toAddress: 'myE38JHdxmQcTJGP1ZiX4BiGhDxMJDvLJD', // testnet
|
toAddress: 'myE38JHdxmQcTJGP1ZiX4BiGhDxMJDvLJD', // testnet
|
||||||
amount: helpers.toSatoshi(80),
|
amount: helpers.toSatoshi(80),
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
|
|
||||||
server.createTx(txOpts, function(err, tx) {
|
server.createTx(txOpts, function(err, tx) {
|
||||||
should.not.exist(tx);
|
should.not.exist(tx);
|
||||||
|
@ -703,6 +673,7 @@ describe('Copay server', function() {
|
||||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||||
amount: helpers.toSatoshi(120),
|
amount: helpers.toSatoshi(120),
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
|
|
||||||
server.createTx(txOpts, function(err, tx) {
|
server.createTx(txOpts, function(err, tx) {
|
||||||
err.code.should.equal('INSUFFICIENTFUNDS');
|
err.code.should.equal('INSUFFICIENTFUNDS');
|
||||||
|
@ -732,6 +703,7 @@ describe('Copay server', function() {
|
||||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||||
amount: helpers.toSatoshi(12),
|
amount: helpers.toSatoshi(12),
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
server.createTx(txOpts, function(err, tx) {
|
server.createTx(txOpts, function(err, tx) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
tx.should.exist;
|
tx.should.exist;
|
||||||
|
@ -740,6 +712,7 @@ describe('Copay server', function() {
|
||||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||||
amount: 8,
|
amount: 8,
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts2, copayerPriv[0].privKey);
|
||||||
server.createTx(txOpts2, function(err, tx) {
|
server.createTx(txOpts2, function(err, tx) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
tx.should.exist;
|
tx.should.exist;
|
||||||
|
@ -765,6 +738,7 @@ describe('Copay server', function() {
|
||||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||||
amount: helpers.toSatoshi(12),
|
amount: helpers.toSatoshi(12),
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
server.createTx(txOpts, function(err, tx) {
|
server.createTx(txOpts, function(err, tx) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
tx.should.exist;
|
tx.should.exist;
|
||||||
|
@ -773,6 +747,7 @@ describe('Copay server', function() {
|
||||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||||
amount: helpers.toSatoshi(24),
|
amount: helpers.toSatoshi(24),
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts2, copayerPriv[0].privKey);
|
||||||
server.createTx(txOpts2, function(err, tx) {
|
server.createTx(txOpts2, function(err, tx) {
|
||||||
err.code.should.equal('INSUFFICIENTFUNDS');
|
err.code.should.equal('INSUFFICIENTFUNDS');
|
||||||
err.message.should.equal('Insufficient funds');
|
err.message.should.equal('Insufficient funds');
|
||||||
|
@ -807,6 +782,7 @@ describe('Copay server', function() {
|
||||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||||
amount: helpers.toSatoshi(80),
|
amount: helpers.toSatoshi(80),
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
async.map(_.range(N), function(i, cb) {
|
async.map(_.range(N), function(i, cb) {
|
||||||
server.createTx(txOpts, function(err, tx) {
|
server.createTx(txOpts, function(err, tx) {
|
||||||
cb(err, tx);
|
cb(err, tx);
|
||||||
|
@ -830,12 +806,13 @@ describe('Copay server', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#signTx', function() {
|
describe('#signTx', function() {
|
||||||
var server, wallet, txid;
|
var server, wallet, copayerPriv, txid;
|
||||||
|
|
||||||
beforeEach(function(done) {
|
beforeEach(function(done) {
|
||||||
helpers.createAndJoinWallet(2, 2, function(s, w) {
|
helpers.createAndJoinWallet(2, 2, function(s, w, c) {
|
||||||
server = s;
|
server = s;
|
||||||
wallet = w;
|
wallet = w;
|
||||||
|
copayerPriv = c;
|
||||||
server.createAddress({}, function(err, address) {
|
server.createAddress({}, function(err, address) {
|
||||||
helpers.createUtxos(server, wallet, helpers.toSatoshi([1, 2, 3, 4, 5, 6, 7, 8]), function(utxos) {
|
helpers.createUtxos(server, wallet, helpers.toSatoshi([1, 2, 3, 4, 5, 6, 7, 8]), function(utxos) {
|
||||||
helpers.stubBlockExplorer(server, utxos);
|
helpers.stubBlockExplorer(server, utxos);
|
||||||
|
@ -843,6 +820,7 @@ describe('Copay server', function() {
|
||||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||||
amount: helpers.toSatoshi(10),
|
amount: helpers.toSatoshi(10),
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
server.createTx(txOpts, function(err, tx) {
|
server.createTx(txOpts, function(err, tx) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
tx.should.exist;
|
tx.should.exist;
|
||||||
|
@ -859,7 +837,7 @@ describe('Copay server', function() {
|
||||||
var tx = txs[0];
|
var tx = txs[0];
|
||||||
tx.id.should.equal(txid);
|
tx.id.should.equal(txid);
|
||||||
|
|
||||||
var signatures = helpers.clientSign(tx, someXPrivKey[0], wallet.n);
|
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey, wallet.n);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txid,
|
txProposalId: txid,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -875,7 +853,7 @@ describe('Copay server', function() {
|
||||||
var tx = txs[0];
|
var tx = txs[0];
|
||||||
tx.id.should.equal(txid);
|
tx.id.should.equal(txid);
|
||||||
|
|
||||||
var signatures = helpers.clientSign(tx, someXPrivKey[0], wallet.n);
|
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey, wallet.n);
|
||||||
signatures[0] = 1;
|
signatures[0] = 1;
|
||||||
|
|
||||||
server.signTx({
|
server.signTx({
|
||||||
|
@ -906,11 +884,12 @@ describe('Copay server', function() {
|
||||||
|
|
||||||
|
|
||||||
describe('#signTx and broadcast', function() {
|
describe('#signTx and broadcast', function() {
|
||||||
var server, wallet, utxos;
|
var server, wallet, copayerPriv, utxos;
|
||||||
beforeEach(function(done) {
|
beforeEach(function(done) {
|
||||||
helpers.createAndJoinWallet(1, 1, function(s, w) {
|
helpers.createAndJoinWallet(1, 1, function(s, w, c) {
|
||||||
server = s;
|
server = s;
|
||||||
wallet = w;
|
wallet = w;
|
||||||
|
copayerPriv = c;
|
||||||
server.createAddress({}, function(err, address) {
|
server.createAddress({}, function(err, address) {
|
||||||
helpers.createUtxos(server, wallet, helpers.toSatoshi([1, 2, 3, 4, 5, 6, 7, 8]), function(inutxos) {
|
helpers.createUtxos(server, wallet, helpers.toSatoshi([1, 2, 3, 4, 5, 6, 7, 8]), function(inutxos) {
|
||||||
utxos = inutxos;
|
utxos = inutxos;
|
||||||
|
@ -926,6 +905,7 @@ describe('Copay server', function() {
|
||||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||||
amount: helpers.toSatoshi(10),
|
amount: helpers.toSatoshi(10),
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
server.createTx(txOpts, function(err, txp) {
|
server.createTx(txOpts, function(err, txp) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
txp.should.exist;
|
txp.should.exist;
|
||||||
|
@ -934,7 +914,7 @@ describe('Copay server', function() {
|
||||||
server.getPendingTxs({}, function(err, txps) {
|
server.getPendingTxs({}, function(err, txps) {
|
||||||
var txp = txps[0];
|
var txp = txps[0];
|
||||||
txp.id.should.equal(txpid);
|
txp.id.should.equal(txpid);
|
||||||
var signatures = helpers.clientSign(txp, someXPrivKey[0], wallet.n);
|
var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey, wallet.n);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txpid,
|
txProposalId: txpid,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -955,6 +935,7 @@ describe('Copay server', function() {
|
||||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||||
amount: helpers.toSatoshi(10),
|
amount: helpers.toSatoshi(10),
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
server.createTx(txOpts, function(err, txp) {
|
server.createTx(txOpts, function(err, txp) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
txp.should.exist;
|
txp.should.exist;
|
||||||
|
@ -963,7 +944,7 @@ describe('Copay server', function() {
|
||||||
server.getPendingTxs({}, function(err, txps) {
|
server.getPendingTxs({}, function(err, txps) {
|
||||||
var txp = txps[0];
|
var txp = txps[0];
|
||||||
txp.id.should.equal(txpid);
|
txp.id.should.equal(txpid);
|
||||||
var signatures = helpers.clientSign(txp, someXPrivKey[0], wallet.n);
|
var signatures = helpers.clientSign(txp, TestData.copayers[0].xPrivKey, wallet.n);
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txpid,
|
txProposalId: txpid,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
@ -985,11 +966,12 @@ describe('Copay server', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Tx proposal workflow', function() {
|
describe('Tx proposal workflow', function() {
|
||||||
var server, wallet, utxos;
|
var server, wallet, copayerPriv, utxos;
|
||||||
beforeEach(function(done) {
|
beforeEach(function(done) {
|
||||||
helpers.createAndJoinWallet(2, 3, function(s, w) {
|
helpers.createAndJoinWallet(2, 3, function(s, w, c) {
|
||||||
server = s;
|
server = s;
|
||||||
wallet = w;
|
wallet = w;
|
||||||
|
copayerPriv = c;
|
||||||
server.createAddress({}, function(err, address) {
|
server.createAddress({}, function(err, address) {
|
||||||
helpers.createUtxos(server, wallet, helpers.toSatoshi([1, 2, 3, 4, 5, 6, 7, 8]), function(inutxos) {
|
helpers.createUtxos(server, wallet, helpers.toSatoshi([1, 2, 3, 4, 5, 6, 7, 8]), function(inutxos) {
|
||||||
utxos = inutxos;
|
utxos = inutxos;
|
||||||
|
@ -1006,6 +988,7 @@ describe('Copay server', function() {
|
||||||
amount: helpers.toSatoshi(10),
|
amount: helpers.toSatoshi(10),
|
||||||
message: 'some message',
|
message: 'some message',
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
server.createTx(txOpts, function(err, txp) {
|
server.createTx(txOpts, function(err, txp) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
should.exist.txp;
|
should.exist.txp;
|
||||||
|
@ -1031,7 +1014,7 @@ describe('Copay server', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#getTxs', function() {
|
describe('#getTxs', function() {
|
||||||
var server, wallet, clock;
|
var server, wallet, copayerPriv, clock;
|
||||||
|
|
||||||
beforeEach(function(done) {
|
beforeEach(function(done) {
|
||||||
if (server)
|
if (server)
|
||||||
|
@ -1040,9 +1023,10 @@ describe('Copay server', function() {
|
||||||
this.timeout(5000);
|
this.timeout(5000);
|
||||||
console.log('\tCreating TXS...');
|
console.log('\tCreating TXS...');
|
||||||
clock = sinon.useFakeTimers();
|
clock = sinon.useFakeTimers();
|
||||||
helpers.createAndJoinWallet(1, 1, function(s, w) {
|
helpers.createAndJoinWallet(1, 1, function(s, w, c) {
|
||||||
server = s;
|
server = s;
|
||||||
wallet = w;
|
wallet = w;
|
||||||
|
copayerPriv = c;
|
||||||
server.createAddress({}, function(err, address) {
|
server.createAddress({}, function(err, address) {
|
||||||
helpers.createUtxos(server, wallet, helpers.toSatoshi(_.range(10)), function(utxos) {
|
helpers.createUtxos(server, wallet, helpers.toSatoshi(_.range(10)), function(utxos) {
|
||||||
helpers.stubBlockExplorer(server, utxos);
|
helpers.stubBlockExplorer(server, utxos);
|
||||||
|
@ -1050,6 +1034,7 @@ describe('Copay server', function() {
|
||||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||||
amount: helpers.toSatoshi(0.1),
|
amount: helpers.toSatoshi(0.1),
|
||||||
};
|
};
|
||||||
|
helpers.addProposalSignature(txOpts, copayerPriv[0].privKey);
|
||||||
async.eachSeries(_.range(10), function(i, next) {
|
async.eachSeries(_.range(10), function(i, next) {
|
||||||
clock.tick(10000);
|
clock.tick(10000);
|
||||||
server.createTx(txOpts, function(err, tx) {
|
server.createTx(txOpts, function(err, tx) {
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
var keyPair = {
|
||||||
|
priv: '0dea92f1df6675085b5cdd965487bb862f84f2755bcb56fa45dbf5b387a6c4a0',
|
||||||
|
pub: '026092daeed8ecb2212869395770e956ffc9bf453f803e700f64ffa70c97a00d80',
|
||||||
|
};
|
||||||
|
|
||||||
|
var message = {
|
||||||
|
text: 'hello world',
|
||||||
|
signature: '3045022100addd20e5413865d65d561ad2979f2289a40d52594b1f804840babd9a63e4ebbf02204b86285e1fcab02df772e7a1325fc4b511ecad79a8f80a2bd1ad8bfa858ac3d4', // with 5c0e043a513032907d181325a8e7990b076c0af15ed13dc5e611cda9bb3ae52a
|
||||||
|
};
|
||||||
|
|
||||||
|
var copayers = [{
|
||||||
|
xPrivKey: 'xprv9s21ZrQH143K2rMHbXTJmWTuFx6ssqn1vyRoZqPkCXYchBSkp5ey8kMJe84sxfXq5uChWH4gk94rWbXZt2opN9kg4ufKGvUM7HQSLjnoh7e',
|
||||||
|
xPubKey: 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9',
|
||||||
|
xPubKeySignature: '30440220192ae7345d980f45f908bd63ccad60ce04270d07b91f1a9d92424a07a38af85202201591f0f71dd4e79d9206d2306862e6b8375e13a62c193953d768e884b6fb5a46', // signed using keyPair.priv
|
||||||
|
privKey: '5c0e043a513032907d181325a8e7990b076c0af15ed13dc5e611cda9bb3ae52a', // derived with 'm/1/0'
|
||||||
|
pubKey: '03814ac7decf64321a3c6967bfb746112fdb5b583531cd512cc3787eaf578947dc',
|
||||||
|
}, {
|
||||||
|
xPrivKey: 'xprv9s21ZrQH143K2JgXh8Va3Taq22D2gXw2nYULffV5dc9acQvAmB3KhomPKGwV9AbVsBcAXMW2QxCnvmHU1rVtHRfZwTxdEEAN5ZojRYdryQ1',
|
||||||
|
xPubKey: 'xpub661MyMwAqRbcEnkzoA2aQbXZa43X5zet9mPwU3thBwgZVDFKJiMaFc5sAYS97qVtMxpvceittobtoH2JKmpweSN1CLSe91hiE1Wrf5YJhsQ',
|
||||||
|
xPubKeySignature: '3045022100b9079d0d9b70da828b0e9c776fe01c5c13fc254a314c0b09a638c8695ec9360c022079922950779080569163c692ed8ee882f9ef37e7b2dff03de9c6756e7599960e',
|
||||||
|
privKey: '7708f0b7a60da9b88893e41eb2f59acf13ddc38edd794e1af9c2b57d35e99d85',
|
||||||
|
pubKey: '0266efb3b02973233636b153296486cdbc1728e1f42a1062f030af193ab14e1321',
|
||||||
|
}, {
|
||||||
|
xPrivKey: 'xprv9s21ZrQH143K2DoxHNrecLmp121HU4nZRB57jj2cGmSkp9Wrgz2AevFT98AcYocYXEyyWDwC1JUn13beDjQU87FwfCaHiWhgoSx9G31tmDa',
|
||||||
|
xPubKey: 'xpub661MyMwAqRbcEhtRPQPeyUiYZ3qmsXWQnPziY7SDq6yjgwr1EXLRCiZvzQsfnQehH8hBzCxNPYCJXx51QKcbervpkBK931H1A9F39z5E1XD',
|
||||||
|
xPubKeySignature: '3045022100ed04aca131acf6f030018a7e3dd564788bbad5528e9edb7880f032ae6917bf10022022879ca8a60700c9c3bf9d603ae2555d4be1914084c912579b4bc09a432e9c32',
|
||||||
|
privKey: 'a8e36ab9e065a5cc0551938c225d40542b7780a84aff55cb52e4eb4d7f64de11',
|
||||||
|
pubKey: '033e44b94789a591380787effbad0a01f41aedd7ed315c931efc51284e99ae34a9',
|
||||||
|
}, {
|
||||||
|
xPrivKey: 'xprv9s21ZrQH143K3dHn6j7zuLSnnMpBAceHfQFDm6R3wbkD26pTSUuZ7JY4549T8mMhwwUeq6SW6guDwy6cUhqs6PwoF2svKKkLjJdeKi1BzUn',
|
||||||
|
xPubKey: 'xpub661MyMwAqRbcG7NFCkf1GUPXLPefa5N92dApZUpfVwHBtu9bz2Dof6rXvKjioVpLXRBHKeyX2AxLdtaCbUtz2zx3dE9F4mPkDsARrPaGsSL',
|
||||||
|
xPubKeySignature: '3045022100a17dee46810e379aa37104ec1a4e20276aa41eac67b7e555475b15db6f6ee8ca0220472d114368f6d78bd8dba5c5fed77b22437341621d7879331bc48f7ee7701853',
|
||||||
|
privKey: '68cc2c1776f3456fcdef12812e634b6adbd676c5b8168a4b2547cf73c5363cfd',
|
||||||
|
pubKey: '027597e3a18c829dfdd92f875ae87f2aa4654cbb13db28a92a19401cf6f8ac18cb',
|
||||||
|
}, {
|
||||||
|
xPrivKey: 'xprv9s21ZrQH143K3Wac3NKJ8nZsBsn4HboPtCD2LDB8zkXcmo9q97efAi9i6KkcyBoJ4vjD59corGsdJebmNXud4nH3bCBSo64uWfwauo3Kdco',
|
||||||
|
xPubKey: 'xpub661MyMwAqRbcFzf59PrJVvWbjucYh4XFFR8d8bakZ64bebUygexuiWUBwa7EnFosoFstoocLQTrLPeAQThonSrYTDQ18gkS219dLJuwUHDb',
|
||||||
|
xPubKeySignature: '30440220023c1902434aaca0c2ed3c92262d56ee4296cd5c7598b009b8556deab2df89e70220714117970debf5cc1232441aa2d1ce335b5b99958acb2d000c4241e2a2fc567f',
|
||||||
|
privKey: 'fc97d94e97857b2016a1e68ab0313ce2ea5a791638e8eb0bb6d5a5aa72de01df',
|
||||||
|
pubKey: '03a3e04a3fb218b074306ca2a4995ec1ea97ef2b73dd54edfbae9ee56651dd21cc',
|
||||||
|
}, {
|
||||||
|
xPrivKey: 'xprv9s21ZrQH143K2Hxh1Xj59WjAimbDuubNBFknLYPr563BBziVuLhMvw7F3CkYMYj1y6QSbDnKQVHrMGekXi7awjLwKR1XWcMoR3eKEcH65Pa',
|
||||||
|
xPubKey: 'xpub661MyMwAqRbcEn3A7ZG5WefuGoRiKNKDYUgP8voTdRaA4o3eSt1cUjRitVc75a2gsifRDufbicYXeQCchDvkRKSSTWi1uy7PPaNHnerGvTa',
|
||||||
|
xPubKeySignature: '3044022042f063cd154a359f1d49202d79efc0737c47077ee50e36ed3d796327b9b29a9602206a4baf2902b49d1cb265eb31b9ab12d470fd023a11d9d425679a1630ba0b0e29',
|
||||||
|
privKey: '72381546174e6165e39853510bf3353645cb2e19e0499d3bb1d8aef0027352eb',
|
||||||
|
pubKey: '037e4163f69c3e2b05e980e3ac5dac06730894b1ba520a15a9d8221245d4bfe2a4',
|
||||||
|
}, {
|
||||||
|
xPrivKey: 'xprv9s21ZrQH143K2L2wxVQ5nJ8FrTjz2KHB4wy83Xu6y6jdxmzrKNWvh6g7apPJqwj5NjhrmyJ6TYe9Hk4fbYx4tRg7Zk4Y7dAdgej4RVeUBTn',
|
||||||
|
xPubKey: 'xpub661MyMwAqRbcEp7R4Ww69S4zQVaURn12SAtiqvJiXSGcqaKzruqBEtzbS97V145KiYxsW4g9M3pqsibfc5mtbMn4R52v7bnnrHGAoiHb1pz',
|
||||||
|
xPubKeySignature: '304402207b082a63fc39b90a0f18edeb20d191430f11a9e5378681f15a68aac052aa858202201fd127b374e4a301a45f0c73d2a747d156a60075e643308e489a672bd0a7b4fb',
|
||||||
|
privKey: 'daff48eab1268c23e9ecde993b93ace4a375e7c627da0d3662746c7e3fecbdfa',
|
||||||
|
pubKey: '02035c09deeef7436df39a09ef2167129c686c6177185216525b9d778af96bacd7',
|
||||||
|
}, {
|
||||||
|
xPrivKey: 'xprv9s21ZrQH143K3Pqe7LhTkE84VM6GysvSvggfhS3KbHvgBLaaQeR9YNePRo3vpLMVBv5SNhNVAaEDyj6Q8vMRVYM4X9bWYCiPgsJXkH8WzX1',
|
||||||
|
xPubKey: 'xpub661MyMwAqRbcFLRkhYzK8eQdoywNHJVsJCMQNDoMks5bZymuMcyDgYfnVQYq2Q9npnVmdTAthYGc3N3uxm5sEdnTpSqBc4YYTAhNnoSxCm9',
|
||||||
|
xPubKeySignature: '30440220192ae7345d980f45f908bd63ccad60ce04270d07b91f1a9d92424a07a38af85202201591f0f71dd4e79d9206d2306862e6b8375e13a62c193953d768e884b6fb5a46',
|
||||||
|
privKey: '5c0e043a513032907d181325a8e7990b076c0af15ed13dc5e611cda9bb3ae52a',
|
||||||
|
pubKey: '03814ac7decf64321a3c6967bfb746112fdb5b583531cd512cc3787eaf578947dc',
|
||||||
|
}, {
|
||||||
|
xPrivKey: 'xprv9s21ZrQH143K2QSAHGxQhUsJYFDcZ6h2oiTjKFPmbnzeNzXgRW73NwX7ifBgbJ35eHGR7toyj9CCXB6Wzf5iCjj3YDuJuvBoJFJsiQAdTUH',
|
||||||
|
xPubKey: 'xpub661MyMwAqRbcEtWdPJVR4cp36H46xZQtAwPL7doPA8XdFnrpy3RHvjqbZxERYNMd4E2tt84xy4F2PqtKkHFDzZbSAaUabp36oZDwwPEqFjK',
|
||||||
|
xPubKeySignature: '304502210081a88684d4e27cab752d0df6a746aeb4bbcac57e73edd3847ffb43f1cf6740b20220312598f47dc5e775ea2ba97048764675afa4796173115049b4dacc8882b5c7b7',
|
||||||
|
privKey: '01273975489d85ac06f2e47677149420cd4901264cb40e3a756ff901acfc11f6',
|
||||||
|
pubKey: '0210eed257f41c9a991f8bd9523f66c3a83c1aab27cd2ccf233f8f5c3caef77e7a',
|
||||||
|
}, {
|
||||||
|
xPrivKey: 'xprv9s21ZrQH143K2bj7Azs1rCkumDJmbNveDA96wDJThzsDEJjBngkFXEr646AbvrTAfRd2scqq7hN48fGXesobx4sKRkddCrLaCpoWUkMJErj',
|
||||||
|
xPubKey: 'xpub661MyMwAqRbcF5oaH2Q2DLheKF9FzqeVaP4hjbi5GLQC774LLE4W53AZuMztQ6e6SMmEMj8K8zsP3iMMnJgK2PawWZCh7QcdgAg7eJWSJFr',
|
||||||
|
xPubKeySignature: '304402207781231f8bd9a679938057373702afdeec43e84b5b239e2e4dc8e35c63e4ee7102207f7ed929c81dfb59ebd14f56609dcd8255de6337c967704340a2089080fd896f',
|
||||||
|
privKey: 'dda3b5d7c6a9294a71b3ae116e69be756bed55f1caf68205e7889baa5fc76dd6',
|
||||||
|
pubKey: '03182e14c3d256359ba478d3c7842ad882141f0e61ef905dcb6b5c9786f958f325',
|
||||||
|
}, ];
|
||||||
|
|
||||||
|
|
||||||
|
module.exports.keyPair = keyPair;
|
||||||
|
module.exports.message = message;
|
||||||
|
module.exports.copayers = copayers;
|
|
@ -89,6 +89,8 @@ var aTXP = function() {
|
||||||
"creatorId": "1",
|
"creatorId": "1",
|
||||||
"toAddress": "18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7",
|
"toAddress": "18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7",
|
||||||
"amount": 50000000,
|
"amount": 50000000,
|
||||||
|
"message": 'some message',
|
||||||
|
"proposalSignature": '7035022100896aeb8db75fec22fddb5facf791927a996eb3aee23ee6deaa15471ea46047de02204c0c33f42a9d3ff93d62738712a8c8a5ecd21b45393fdd144e7b01b5a186f1f9',
|
||||||
"changeAddress": "3CauZ5JUFfmSAx2yANvCRoNXccZ3YSUjXH",
|
"changeAddress": "3CauZ5JUFfmSAx2yANvCRoNXccZ3YSUjXH",
|
||||||
"inputs": [{
|
"inputs": [{
|
||||||
"txid": "6ee699846d2d6605f96d20c7cc8230382e5da43342adb11b499bbe73709f06ab",
|
"txid": "6ee699846d2d6605f96d20c7cc8230382e5da43342adb11b499bbe73709f06ab",
|
||||||
|
|
Loading…
Reference in New Issue