commit
7e5a8dc16d
|
@ -29,7 +29,7 @@ Address.fromObj = function (obj) {
|
|||
* @return {Script}
|
||||
*/
|
||||
Address.prototype.getScriptPubKey = function (threshold) {
|
||||
return Bitcore.Script.buildMultisigOut(this.publicKeys, threshold)
|
||||
return Bitcore.Script.buildMultisigOut(this.publicKeys, threshold).toScriptHashOut();
|
||||
};
|
||||
|
||||
module.exports = Address;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var Guid = require('guid');
|
||||
|
||||
var TxProposalAction = require('./txproposalaction');
|
||||
|
||||
|
@ -11,7 +12,7 @@ function TxProposal(opts) {
|
|||
|
||||
this.version = VERSION;
|
||||
this.createdOn = Math.floor(Date.now() / 1000);
|
||||
this.id = opts.id;
|
||||
this.id = Guid.raw();
|
||||
this.creatorId = opts.creatorId;
|
||||
this.toAddress = opts.toAddress;
|
||||
this.amount = opts.amount;
|
||||
|
|
|
@ -113,6 +113,7 @@ Wallet.prototype.createAddress = function(isChange) {
|
|||
return new Address({
|
||||
address: bitcoreAddress.toString(),
|
||||
path: path,
|
||||
publicKeys: _.invoke(publicKeys, 'toString'),
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -299,6 +299,8 @@ CopayServer.prototype._getUtxos = function(opts, cb) {
|
|||
dictionary[input].locked = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return cb(null, utxos);
|
||||
});
|
||||
});
|
||||
|
@ -323,14 +325,15 @@ CopayServer.prototype.getBalance = function(opts, cb) {
|
|||
if (err) return cb(err);
|
||||
|
||||
var balance = {};
|
||||
balance.totalAmount = _.reduce(utxos, function(sum, utxo) {
|
||||
balance.totalAmount = Utils.strip(_.reduce(utxos, function(sum, utxo) {
|
||||
return sum + utxo.amount;
|
||||
}, 0);
|
||||
balance.lockedAmount = _.reduce(_.filter(utxos, {
|
||||
}, 0));
|
||||
|
||||
balance.lockedAmount = Utils.strip(_.reduce(_.filter(utxos, {
|
||||
locked: true
|
||||
}), function(sum, utxo) {
|
||||
return sum + utxo.amount;
|
||||
}, 0);
|
||||
}, 0));
|
||||
|
||||
return cb(null, balance);
|
||||
});
|
||||
|
@ -338,12 +341,15 @@ CopayServer.prototype.getBalance = function(opts, cb) {
|
|||
|
||||
|
||||
CopayServer.prototype._createRawTx = function(txp) {
|
||||
console.log(txp);
|
||||
console.log('[server.js.320:txp:]',txp.inputs, txp.toAddress, txp.amount, txp.changeAddress); //TODO
|
||||
|
||||
|
||||
var rawTx = new Bitcore.Transaction()
|
||||
.from(txp.inputs)
|
||||
.to(txp.toAddress, txp.amount)
|
||||
.change(txp.changeAddress);
|
||||
|
||||
console.log('[server.js.324:rawTx:]',rawTx); //TODO
|
||||
return rawTx;
|
||||
};
|
||||
|
||||
|
@ -361,7 +367,7 @@ CopayServer.prototype._selectUtxos = function(txp, utxos) {
|
|||
}
|
||||
i++;
|
||||
};
|
||||
return selected;
|
||||
return total >= txp.amount ? selected : null;
|
||||
};
|
||||
|
||||
|
||||
|
@ -380,6 +386,11 @@ CopayServer.prototype.createTx = function(opts, cb) {
|
|||
|
||||
Utils.checkRequired(opts, ['walletId', 'copayerId', 'toAddress', 'amount', 'message']);
|
||||
|
||||
|
||||
// TODO?
|
||||
// Check some parameters like:
|
||||
// amount > dust
|
||||
|
||||
self.getWallet({
|
||||
id: opts.walletId
|
||||
}, function(err, wallet) {
|
||||
|
@ -390,7 +401,9 @@ CopayServer.prototype.createTx = function(opts, cb) {
|
|||
}, function(err, utxos) {
|
||||
if (err) return cb(err);
|
||||
|
||||
utxos = _.without(utxos, {
|
||||
var changeAddress = wallet.createAddress(true).address;
|
||||
|
||||
utxos = _.reject(utxos, {
|
||||
locked: true
|
||||
});
|
||||
|
||||
|
@ -398,14 +411,17 @@ CopayServer.prototype.createTx = function(opts, cb) {
|
|||
creatorId: opts.copayerId,
|
||||
toAddress: opts.toAddress,
|
||||
amount: opts.amount,
|
||||
changeAddress: opts.changeAddress,
|
||||
changeAddress: changeAddress,
|
||||
requiredSignatures: wallet.m,
|
||||
maxRejections: wallet.n - wallet.m,
|
||||
});
|
||||
|
||||
txp.inputs = self._selectUtxos(txp, utxos);
|
||||
if (!txp.inputs)
|
||||
return cb('insufficient funds')
|
||||
|
||||
txp.rawTx = self._createRawTx(txp);
|
||||
|
||||
// no need to do this now: // TODO remove this comment
|
||||
//self._createRawTx(txp);
|
||||
self.storage.storeTx(wallet.id, txp, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ Storage.prototype.fetchTxs = function (walletId, cb) {
|
|||
};
|
||||
|
||||
Storage.prototype.storeTx = function (walletId, txp, cb) {
|
||||
this.db.put('wallet-' + walletId + '-txp-' + txp.txProposalId, txp, cb);
|
||||
this.db.put('wallet-' + walletId + '-txp-' + txp.id, txp, cb);
|
||||
};
|
||||
|
||||
Storage.prototype.fetchAddresses = function (walletId, cb) {
|
||||
|
|
10
lib/utils.js
10
lib/utils.js
|
@ -25,4 +25,14 @@ Utils.checkRequired = function (obj, args) {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @desc rounds a JAvascript number
|
||||
* @param number
|
||||
* @return {number}
|
||||
*/
|
||||
Utils.strip = function(number) {
|
||||
return (parseFloat(number.toPrecision(12)));
|
||||
}
|
||||
|
||||
module.exports = Utils;
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
"levelup": "^0.19.0",
|
||||
"lodash": "^2.4.1",
|
||||
"npmlog": "^0.1.1",
|
||||
"preconditions": "^1.0.7"
|
||||
"preconditions": "^1.0.7",
|
||||
"guid":"*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^1.9.1",
|
||||
|
|
|
@ -97,11 +97,7 @@ helpers.createAndJoinWallet = function(id, m, n, cb) {
|
|||
};
|
||||
|
||||
helpers.randomTXID = function() {
|
||||
var ret = '';
|
||||
for (var i = 0; i < 64 / 4; i++)
|
||||
ret += Math.floor(Math.random() * 255 * 255).toString(16);
|
||||
|
||||
return ret;
|
||||
return Bitcore.crypto.Hash.sha256(new Buffer(Math.random() * 100000)).toString('hex');;
|
||||
};
|
||||
|
||||
helpers.createUtxos = function(server, wallet, amounts, cb) {
|
||||
|
@ -113,7 +109,6 @@ helpers.createUtxos = function(server, wallet, amounts, cb) {
|
|||
isChange: false,
|
||||
}, function(err, address) {
|
||||
addresses.push(address);
|
||||
console.log('[integration.js.115:address:]', address); //TODO
|
||||
next(err);
|
||||
});
|
||||
},
|
||||
|
@ -126,7 +121,7 @@ helpers.createUtxos = function(server, wallet, amounts, cb) {
|
|||
txid: helpers.randomTXID(),
|
||||
vout: Math.floor((Math.random() * 10) + 1),
|
||||
amount: amount,
|
||||
scriptPubKey: addresses[i].getScriptPubKey(wallet.m),
|
||||
scriptPubKey: addresses[i].getScriptPubKey(wallet.m).toBuffer().toString('hex'),
|
||||
};
|
||||
}));
|
||||
});
|
||||
|
@ -623,12 +618,12 @@ describe('Copay server', function() {
|
|||
|
||||
it('should create many addresses on simultaneous requests', function(done) {
|
||||
helpers.createAndJoinWallet('123', 2, 2, function(err, wallet) {
|
||||
async.map(_.range(10), function (i, cb) {
|
||||
async.map(_.range(10), function(i, cb) {
|
||||
server.createAddress({
|
||||
walletId: '123',
|
||||
isChange: false,
|
||||
}, cb);
|
||||
}, function (err, addresses) {
|
||||
}, function(err, addresses) {
|
||||
addresses.length.should.equal(10);
|
||||
addresses[0].path.should.equal('m/2147483647/0/0');
|
||||
addresses[9].path.should.equal('m/2147483647/0/9');
|
||||
|
@ -721,30 +716,27 @@ describe('Copay server', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it.skip('should create tx', function(done) {
|
||||
it('should create tx', function(done) {
|
||||
|
||||
helpers.createUtxos(server, wallet, [100, 200], function(utxos) {
|
||||
|
||||
console.log('[integration.js.670:utxos:]', utxos); //TODO
|
||||
var bc = sinon.stub();
|
||||
bc.getUnspentUtxos = sinon.stub().callsArgWith(1, null, utxos);
|
||||
server._getBlockExplorer = sinon.stub().returns(bc);
|
||||
//server._createRawTx = sinon.stub().returns('raw');
|
||||
|
||||
var txOpts = {
|
||||
copayerId: '1',
|
||||
walletId: '123',
|
||||
toAddress: 'dummy',
|
||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||
amount: 80,
|
||||
message: 'some message',
|
||||
otToken: 'dummy',
|
||||
requestSignature: 'dummy',
|
||||
};
|
||||
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
tx.should.exist;
|
||||
console.log(tx);
|
||||
//tx.rawTx.should.equal('raw');
|
||||
tx.isAccepted().should.equal.false;
|
||||
tx.isRejected().should.equal.false;
|
||||
server.getPendingTxs({
|
||||
|
@ -765,10 +757,146 @@ describe('Copay server', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it.skip('should fail to create tx when insufficient funds', function(done) {});
|
||||
it('should fail to create tx when insufficient funds', function(done) {
|
||||
|
||||
it.skip('should create tx when there is a pending tx and enough UTXOs', function(done) {});
|
||||
helpers.createUtxos(server, wallet, [100], function(utxos) {
|
||||
|
||||
it.skip('should fail to create tx when there is a pending tx and not enough UTXOs', function(done) {});
|
||||
var bc = sinon.stub();
|
||||
bc.getUnspentUtxos = sinon.stub().callsArgWith(1, null, utxos);
|
||||
server._getBlockExplorer = sinon.stub().returns(bc);
|
||||
|
||||
var txOpts = {
|
||||
copayerId: '1',
|
||||
walletId: '123',
|
||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||
amount: 120,
|
||||
message: 'some message',
|
||||
otToken: 'dummy',
|
||||
requestSignature: 'dummy',
|
||||
};
|
||||
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
err.should.contain('insufficient');
|
||||
server.getPendingTxs({
|
||||
walletId: '123'
|
||||
}, function(err, txs) {
|
||||
should.not.exist(err);
|
||||
txs.length.should.equal(0);
|
||||
server.getBalance({
|
||||
walletId: '123'
|
||||
}, function(err, balance) {
|
||||
should.not.exist(err);
|
||||
balance.lockedAmount.should.equal(0);
|
||||
balance.totalAmount.should.equal(100);
|
||||
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) {
|
||||
|
||||
var bc = sinon.stub();
|
||||
bc.getUnspentUtxos = sinon.stub().callsArgWith(1, null, utxos);
|
||||
server._getBlockExplorer = sinon.stub().returns(bc);
|
||||
|
||||
var txOpts = {
|
||||
copayerId: '1',
|
||||
walletId: '123',
|
||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||
amount: 12,
|
||||
message: 'some message',
|
||||
otToken: 'dummy',
|
||||
requestSignature: 'dummy',
|
||||
};
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
tx.should.exist;
|
||||
|
||||
var txOpts2 = {
|
||||
copayerId: '1',
|
||||
walletId: '123',
|
||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||
amount: 8,
|
||||
message: 'some message 2',
|
||||
otToken: 'dummy',
|
||||
requestSignature: 'dummy',
|
||||
};
|
||||
server.createTx(txOpts2, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
tx.should.exist;
|
||||
server.getPendingTxs({
|
||||
walletId: '123'
|
||||
}, function(err, txs) {
|
||||
should.not.exist(err);
|
||||
txs.length.should.equal(2);
|
||||
server.getBalance({
|
||||
walletId: '123'
|
||||
}, function(err, balance) {
|
||||
should.not.exist(err);
|
||||
balance.totalAmount.should.equal(30.6);
|
||||
balance.lockedAmount.should.equal(30.6);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail to create tx when there is a pending tx and not enough UTXOs', function(done) {
|
||||
helpers.createUtxos(server, wallet, [10.1, 10.2, 10.3], function(utxos) {
|
||||
|
||||
var bc = sinon.stub();
|
||||
bc.getUnspentUtxos = sinon.stub().callsArgWith(1, null, utxos);
|
||||
server._getBlockExplorer = sinon.stub().returns(bc);
|
||||
|
||||
var txOpts = {
|
||||
copayerId: '1',
|
||||
walletId: '123',
|
||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||
amount: 12,
|
||||
message: 'some message',
|
||||
otToken: 'dummy',
|
||||
requestSignature: 'dummy',
|
||||
};
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
tx.should.exist;
|
||||
|
||||
var txOpts2 = {
|
||||
copayerId: '1',
|
||||
walletId: '123',
|
||||
toAddress: '18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7',
|
||||
amount: 24,
|
||||
message: 'some message 2',
|
||||
otToken: 'dummy',
|
||||
requestSignature: 'dummy',
|
||||
};
|
||||
server.createTx(txOpts2, function(err, tx) {
|
||||
err.should.contain('insufficient');
|
||||
should.not.exist(tx);
|
||||
server.getPendingTxs({
|
||||
walletId: '123'
|
||||
}, function(err, txs) {
|
||||
should.not.exist(err);
|
||||
txs.length.should.equal(1);
|
||||
server.getBalance({
|
||||
walletId: '123'
|
||||
}, function(err, balance) {
|
||||
should.not.exist(err);
|
||||
balance.totalAmount.should.equal(30.6);
|
||||
balance.lockedAmount.should.equal(20.3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue