commit
0784ec9d7a
|
@ -151,7 +151,7 @@ TxProposal.prototype._addSignaturesToBitcoreTx = function(t, signatures, xpub) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (signatures.length != this.inputs.length)
|
if (signatures.length != this.inputs.length)
|
||||||
return false;
|
throw new Error('Number of signatures does not match number of inputs');
|
||||||
|
|
||||||
var oks = 0,
|
var oks = 0,
|
||||||
i = 0,
|
i = 0,
|
||||||
|
@ -176,16 +176,16 @@ TxProposal.prototype._addSignaturesToBitcoreTx = function(t, signatures, xpub) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (oks != t.inputs.length)
|
if (oks != t.inputs.length)
|
||||||
throw new Error('wrong signatures');
|
throw new Error('Wrong signatures');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TxProposal.prototype.sign = function(copayerId, signatures, xpub) {
|
TxProposal.prototype.sign = function(copayerId, signatures, xpub) {
|
||||||
|
try {
|
||||||
// Tests signatures are OK
|
// Tests signatures are OK
|
||||||
var t = this._getBitcoreTx();
|
var t = this._getBitcoreTx();
|
||||||
try {
|
|
||||||
this._addSignaturesToBitcoreTx(t, signatures, xpub);
|
this._addSignaturesToBitcoreTx(t, signatures, xpub);
|
||||||
|
|
||||||
this.addAction(copayerId, 'accept', null, signatures, xpub);
|
this.addAction(copayerId, 'accept', null, signatures, xpub);
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -25,7 +25,6 @@ var Address = require('./model/address');
|
||||||
var TxProposal = require('./model/txproposal');
|
var TxProposal = require('./model/txproposal');
|
||||||
var Notification = require('./model/Notification');
|
var Notification = require('./model/Notification');
|
||||||
|
|
||||||
|
|
||||||
var initialized = false;
|
var initialized = false;
|
||||||
var storage;
|
var storage;
|
||||||
|
|
||||||
|
@ -425,13 +424,22 @@ CopayServer.prototype._selectUtxos = function(txp, utxos) {
|
||||||
selected.push(inputs[i]);
|
selected.push(inputs[i]);
|
||||||
total += this._inputSatoshis(inputs[i]);
|
total += this._inputSatoshis(inputs[i]);
|
||||||
|
|
||||||
if (total >= txp.amount) {
|
if (total >= txp.amount + Bitcore.Transaction.FEE_PER_KB) {
|
||||||
|
try {
|
||||||
break;
|
// Check if there are enough fees
|
||||||
|
txp.inputs = selected;
|
||||||
|
var raw = txp.getRawTx();
|
||||||
|
return;
|
||||||
|
} catch (ex) {
|
||||||
|
if (ex.name != 'bitcore.ErrorTransactionFeeError') {
|
||||||
|
throw ex.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
};
|
};
|
||||||
return total >= txp.amount ? selected : null;
|
txp.inputs = null;
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -469,6 +477,9 @@ CopayServer.prototype.createTx = function(opts, cb) {
|
||||||
if (toAddress.network != wallet.getNetworkName())
|
if (toAddress.network != wallet.getNetworkName())
|
||||||
return cb(new ClientError('INVALIDADDRESS', 'Incorrect address network'));
|
return cb(new ClientError('INVALIDADDRESS', 'Incorrect address network'));
|
||||||
|
|
||||||
|
if (opts.amount < Bitcore.Transaction.DUST_AMOUNT)
|
||||||
|
return cb(new ClientError('DUSTAMOUNT', 'Amount below dust threshold'));
|
||||||
|
|
||||||
self._getUtxos(function(err, utxos) {
|
self._getUtxos(function(err, utxos) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
@ -488,11 +499,15 @@ CopayServer.prototype.createTx = function(opts, cb) {
|
||||||
requiredRejections: Math.min(wallet.m, wallet.n - wallet.m + 1),
|
requiredRejections: Math.min(wallet.m, wallet.n - wallet.m + 1),
|
||||||
});
|
});
|
||||||
|
|
||||||
txp.inputs = self._selectUtxos(txp, utxos);
|
try {
|
||||||
if (!txp.inputs) {
|
self._selectUtxos(txp, utxos);
|
||||||
return cb(new ClientError('INSUFFICIENTFUNDS', 'Insufficient funds'));
|
} catch (ex) {
|
||||||
|
return cb(new ClientError(ex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!txp.inputs)
|
||||||
|
return cb(new ClientError('INSUFFICIENTFUNDS', 'Insufficient funds'));
|
||||||
|
|
||||||
txp.inputPaths = _.pluck(txp.inputs, 'path');
|
txp.inputPaths = _.pluck(txp.inputs, 'path');
|
||||||
|
|
||||||
self.storage.storeAddressAndWallet(wallet, changeAddress, function(err) {
|
self.storage.storeAddressAndWallet(wallet, changeAddress, function(err) {
|
||||||
|
@ -584,7 +599,12 @@ CopayServer.prototype.removePendingTx = function(opts, cb) {
|
||||||
|
|
||||||
|
|
||||||
CopayServer.prototype._broadcastTx = function(txp, cb) {
|
CopayServer.prototype._broadcastTx = function(txp, cb) {
|
||||||
var raw = txp.getRawTx();
|
var raw;
|
||||||
|
try {
|
||||||
|
raw = txp.getRawTx();
|
||||||
|
} catch (ex) {
|
||||||
|
return cb(ex);
|
||||||
|
}
|
||||||
var bc = this._getBlockExplorer('insight', txp.getNetworkName());
|
var bc = this._getBlockExplorer('insight', txp.getNetworkName());
|
||||||
bc.broadcast(raw, function(err, txid) {
|
bc.broadcast(raw, function(err, txid) {
|
||||||
return cb(err, txid);
|
return cb(err, txid);
|
||||||
|
@ -650,7 +670,6 @@ CopayServer.prototype.signTx = function(opts, cb) {
|
||||||
txid: txid
|
txid: txid
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('[server.js.653:txp:]',txp); //TODO
|
|
||||||
return cb(null, txp);
|
return cb(null, txp);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "^0.9.0",
|
"async": "^0.9.0",
|
||||||
"bitcore": "^0.10.3",
|
"bitcore": "git+https://github.com/eordano/bitcore.git#7e88167891811163071ae35dc3dbb705ab6ccff8",
|
||||||
"bitcore-explorers": "^0.9.1",
|
"bitcore-explorers": "^0.9.1",
|
||||||
"body-parser": "^1.11.0",
|
"body-parser": "^1.11.0",
|
||||||
"commander": "^2.6.0",
|
"commander": "^2.6.0",
|
||||||
|
|
|
@ -728,7 +728,7 @@ describe('Copay server', function() {
|
||||||
|
|
||||||
server.createTx(txOpts, function(err, tx) {
|
server.createTx(txOpts, function(err, tx) {
|
||||||
should.not.exist(tx);
|
should.not.exist(tx);
|
||||||
err.should.exist;
|
should.exist(err);
|
||||||
err.code.should.equal('INVALIDADDRESS');
|
err.code.should.equal('INVALIDADDRESS');
|
||||||
err.message.should.equal('Incorrect address network');
|
err.message.should.equal('Incorrect address network');
|
||||||
done();
|
done();
|
||||||
|
@ -741,6 +741,7 @@ describe('Copay server', function() {
|
||||||
helpers.stubBlockExplorer(server, utxos);
|
helpers.stubBlockExplorer(server, utxos);
|
||||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 120, null, TestData.copayers[0].privKey);
|
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 120, null, TestData.copayers[0].privKey);
|
||||||
server.createTx(txOpts, function(err, tx) {
|
server.createTx(txOpts, function(err, tx) {
|
||||||
|
should.exist(err);
|
||||||
err.code.should.equal('INSUFFICIENTFUNDS');
|
err.code.should.equal('INSUFFICIENTFUNDS');
|
||||||
err.message.should.equal('Insufficient funds');
|
err.message.should.equal('Insufficient funds');
|
||||||
server.getPendingTxs({}, function(err, txs) {
|
server.getPendingTxs({}, function(err, txs) {
|
||||||
|
@ -757,9 +758,31 @@ describe('Copay server', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should fail to create tx when insufficient funds for fee', function(done) {});
|
it('should fail to create tx when insufficient funds for fee', function(done) {
|
||||||
|
helpers.createUtxos(server, wallet, [100], function(utxos) {
|
||||||
|
helpers.stubBlockExplorer(server, utxos);
|
||||||
|
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 100, null, TestData.copayers[0].privKey);
|
||||||
|
server.createTx(txOpts, function(err, tx) {
|
||||||
|
should.exist(err);
|
||||||
|
err.code.should.equal('INSUFFICIENTFUNDS');
|
||||||
|
err.message.should.equal('Insufficient funds');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it.skip('should fail to create tx for dust amount', function(done) {});
|
it('should fail to create tx for dust amount', function(done) {
|
||||||
|
helpers.createUtxos(server, wallet, [1], function(utxos) {
|
||||||
|
helpers.stubBlockExplorer(server, utxos);
|
||||||
|
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.00000001, null, TestData.copayers[0].privKey);
|
||||||
|
server.createTx(txOpts, function(err, tx) {
|
||||||
|
should.exist(err);
|
||||||
|
err.code.should.equal('DUSTAMOUNT');
|
||||||
|
err.message.should.equal('Amount below dust threshold');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should create tx when there is a pending tx and enough UTXOs', function(done) {
|
it('should create tx when there is a pending tx and enough UTXOs', function(done) {
|
||||||
helpers.createUtxos(server, wallet, [10.1, 10.2, 10.3], function(utxos) {
|
helpers.createUtxos(server, wallet, [10.1, 10.2, 10.3], function(utxos) {
|
||||||
|
@ -911,7 +934,7 @@ describe('Copay server', function() {
|
||||||
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, TestData.copayers[0].privKey);
|
var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, TestData.copayers[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;
|
should.exist(tx);
|
||||||
txid = tx.id;
|
txid = tx.id;
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -986,12 +1009,30 @@ describe('Copay server', function() {
|
||||||
var tx = txs[0];
|
var tx = txs[0];
|
||||||
tx.id.should.equal(txid);
|
tx.id.should.equal(txid);
|
||||||
|
|
||||||
var signatures = ['11', '22', '33', '44'];
|
var signatures = ['11', '22', '33', '44', '55'];
|
||||||
server.signTx({
|
server.signTx({
|
||||||
txProposalId: txid,
|
txProposalId: txid,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
err.message.should.contain('signatures');
|
should.exist(err);
|
||||||
|
err.message.should.contain('Bad signatures');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fail on wrong number of invalid signatures', function(done) {
|
||||||
|
server.getPendingTxs({}, function(err, txs) {
|
||||||
|
var tx = txs[0];
|
||||||
|
tx.id.should.equal(txid);
|
||||||
|
|
||||||
|
var signatures = _.take(helpers.clientSign(tx, TestData.copayers[0].xPrivKey), 2);
|
||||||
|
server.signTx({
|
||||||
|
txProposalId: txid,
|
||||||
|
signatures: signatures,
|
||||||
|
}, function(err) {
|
||||||
|
should.exist(err);
|
||||||
|
err.message.should.contain('Bad signatures');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue