|
@ -53,7 +53,8 @@ CopayServer._emit = function (event) { |
|
|
* @param {string} [opts.network = 'livenet'] - The Bitcoin network for this wallet. |
|
|
* @param {string} [opts.network = 'livenet'] - The Bitcoin network for this wallet. |
|
|
*/ |
|
|
*/ |
|
|
CopayServer.prototype.createWallet = function(opts, cb) { |
|
|
CopayServer.prototype.createWallet = function(opts, cb) { |
|
|
var self = this, pubKey; |
|
|
var self = this, |
|
|
|
|
|
pubKey; |
|
|
|
|
|
|
|
|
Utils.checkRequired(opts, ['id', 'name', 'm', 'n', 'pubKey']); |
|
|
Utils.checkRequired(opts, ['id', 'name', 'm', 'n', 'pubKey']); |
|
|
if (!Wallet.verifyCopayerLimits(opts.m, opts.n)) return cb('Incorrect m or n value'); |
|
|
if (!Wallet.verifyCopayerLimits(opts.m, opts.n)) return cb('Incorrect m or n value'); |
|
@ -125,7 +126,9 @@ CopayServer.prototype._verifySignature = function(text, signature, pubKey) { |
|
|
Utils.checkRequired(opts, ['walletId', 'id', 'name', 'xPubKey', 'xPubKeySignature']); |
|
|
Utils.checkRequired(opts, ['walletId', 'id', 'name', 'xPubKey', 'xPubKeySignature']); |
|
|
|
|
|
|
|
|
Utils.runLocked(opts.walletId, cb, function(cb) { |
|
|
Utils.runLocked(opts.walletId, cb, function(cb) { |
|
|
self.getWallet({ id: opts.walletId }, function (err, wallet) { |
|
|
self.getWallet({ |
|
|
|
|
|
id: opts.walletId |
|
|
|
|
|
}, function(err, wallet) { |
|
|
if (err) return cb(err); |
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
|
if (!self._verifySignature(opts.xPubKey, opts.xPubKeySignature, wallet.pubKey)) { |
|
|
if (!self._verifySignature(opts.xPubKey, opts.xPubKeySignature, wallet.pubKey)) { |
|
@ -171,7 +174,9 @@ CopayServer.prototype._verifySignature = function(text, signature, pubKey) { |
|
|
Utils.checkRequired(opts, ['walletId', 'isChange']); |
|
|
Utils.checkRequired(opts, ['walletId', 'isChange']); |
|
|
|
|
|
|
|
|
Utils.runLocked(opts.walletId, cb, function(cb) { |
|
|
Utils.runLocked(opts.walletId, cb, function(cb) { |
|
|
self.getWallet({ id: opts.walletId }, function (err, wallet) { |
|
|
self.getWallet({ |
|
|
|
|
|
id: opts.walletId |
|
|
|
|
|
}, function(err, wallet) { |
|
|
if (err) return cb(err); |
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
|
var copayer = wallet.copayers[0]; // TODO: Assign copayer from authentication.
|
|
|
var copayer = wallet.copayers[0]; // TODO: Assign copayer from authentication.
|
|
@ -207,7 +212,9 @@ CopayServer.prototype.verifyMessageSignature = function (opts, cb) { |
|
|
|
|
|
|
|
|
Utils.checkRequired(opts, ['walletId', 'copayerId', 'message', 'signature']); |
|
|
Utils.checkRequired(opts, ['walletId', 'copayerId', 'message', 'signature']); |
|
|
|
|
|
|
|
|
self.getWallet({ id: opts.walletId }, function (err, wallet) { |
|
|
self.getWallet({ |
|
|
|
|
|
id: opts.walletId |
|
|
|
|
|
}, function(err, wallet) { |
|
|
if (err) return cb(err); |
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
|
var copayer = wallet.getCopayer(opts.copayerId); |
|
|
var copayer = wallet.getCopayer(opts.copayerId); |
|
@ -253,13 +260,17 @@ CopayServer.prototype._getUtxos = function (opts, cb) { |
|
|
bc.getUnspentUtxos(addresses, function(err, utxos) { |
|
|
bc.getUnspentUtxos(addresses, function(err, utxos) { |
|
|
if (err) return cb(err); |
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
|
self.getPendingTxs({ walletId: opts.walletId }, function (err, txps) { |
|
|
self.getPendingTxs({ |
|
|
|
|
|
walletId: opts.walletId |
|
|
|
|
|
}, function(err, txps) { |
|
|
if (err) return cb(err); |
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
|
var inputs = _.chain(txps) |
|
|
var inputs = _.chain(txps) |
|
|
.pluck('inputs') |
|
|
.pluck('inputs') |
|
|
.flatten() |
|
|
.flatten() |
|
|
.map(function (utxo) { return utxo.txid + '|' + utxo.vout }); |
|
|
.map(function(utxo) { |
|
|
|
|
|
return utxo.txid + '|' + utxo.vout |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
var dictionary = _.groupBy(utxos, function(utxo) { |
|
|
var dictionary = _.groupBy(utxos, function(utxo) { |
|
|
return utxo.txid + '|' + utxo.vout; |
|
|
return utxo.txid + '|' + utxo.vout; |
|
@ -288,12 +299,20 @@ CopayServer.prototype._getUtxos = function (opts, cb) { |
|
|
|
|
|
|
|
|
Utils.checkRequired(opts, 'walletId'); |
|
|
Utils.checkRequired(opts, 'walletId'); |
|
|
|
|
|
|
|
|
self._getUtxos({ walletId: opts.walletId }, function (err, utxos) { |
|
|
self._getUtxos({ |
|
|
|
|
|
walletId: opts.walletId |
|
|
|
|
|
}, function(err, utxos) { |
|
|
if (err) return cb(err); |
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
|
var balance = {}; |
|
|
var balance = {}; |
|
|
balance.totalAmount = _.reduce(utxos, function(sum, utxo) { return sum + utxo.amount; }, 0); |
|
|
balance.totalAmount = _.reduce(utxos, function(sum, utxo) { |
|
|
balance.lockedAmount = _.reduce(_.without(utxos, { locked: true }), function(sum, utxo) { return sum + utxo.amount; }, 0); |
|
|
return sum + utxo.amount; |
|
|
|
|
|
}, 0); |
|
|
|
|
|
balance.lockedAmount = _.reduce(_.without(utxos, { |
|
|
|
|
|
locked: true |
|
|
|
|
|
}), function(sum, utxo) { |
|
|
|
|
|
return sum + utxo.amount; |
|
|
|
|
|
}, 0); |
|
|
|
|
|
|
|
|
return cb(null, balance); |
|
|
return cb(null, balance); |
|
|
}); |
|
|
}); |
|
@ -341,13 +360,19 @@ CopayServer.prototype.createTx = function (opts, cb) { |
|
|
|
|
|
|
|
|
Utils.checkRequired(opts, ['walletId', 'copayerId', 'toAddress', 'amount', 'message']); |
|
|
Utils.checkRequired(opts, ['walletId', 'copayerId', 'toAddress', 'amount', 'message']); |
|
|
|
|
|
|
|
|
self.getWallet({ id: opts.walletId }, function (err, wallet) { |
|
|
self.getWallet({ |
|
|
|
|
|
id: opts.walletId |
|
|
|
|
|
}, function(err, wallet) { |
|
|
if (err) return cb(err); |
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
|
self._getUtxos({ walletId: wallet.id }, function (err, utxos) { |
|
|
self._getUtxos({ |
|
|
|
|
|
walletId: wallet.id |
|
|
|
|
|
}, function(err, utxos) { |
|
|
if (err) return cb(err); |
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
|
utxos = _.without(utxos, { locked: true }); |
|
|
utxos = _.without(utxos, { |
|
|
|
|
|
locked: true |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
var txp = new TxProposal({ |
|
|
var txp = new TxProposal({ |
|
|
creatorId: opts.copayerId, |
|
|
creatorId: opts.copayerId, |
|
@ -393,7 +418,9 @@ CopayServer.prototype.signTx = function (opts, cb) { |
|
|
self.fetchTx(opts.walletId, opts.txProposalId, function(err, txp) { |
|
|
self.fetchTx(opts.walletId, opts.txProposalId, function(err, txp) { |
|
|
if (err) return cb(err); |
|
|
if (err) return cb(err); |
|
|
if (!txp) return cb('Transaction proposal not found'); |
|
|
if (!txp) return cb('Transaction proposal not found'); |
|
|
var action = _.find(txp.actions, { copayerId: opts.copayerId }); |
|
|
var action = _.find(txp.actions, { |
|
|
|
|
|
copayerId: opts.copayerId |
|
|
|
|
|
}); |
|
|
if (action) return cb('Copayer already voted on this transaction proposal'); |
|
|
if (action) return cb('Copayer already voted on this transaction proposal'); |
|
|
if (txp.status != 'pending') return cb('The transaction proposal is not pending'); |
|
|
if (txp.status != 'pending') return cb('The transaction proposal is not pending'); |
|
|
|
|
|
|
|
@ -433,7 +460,9 @@ CopayServer.prototype.rejectTx = function (opts, cb) { |
|
|
self.fetchTx(opts.walletId, opts.txProposalId, function(err, txp) { |
|
|
self.fetchTx(opts.walletId, opts.txProposalId, function(err, txp) { |
|
|
if (err) return cb(err); |
|
|
if (err) return cb(err); |
|
|
if (!txp) return cb('Transaction proposal not found'); |
|
|
if (!txp) return cb('Transaction proposal not found'); |
|
|
var action = _.find(txp.actions, { copayerId: opts.copayerId }); |
|
|
var action = _.find(txp.actions, { |
|
|
|
|
|
copayerId: opts.copayerId |
|
|
|
|
|
}); |
|
|
if (action) return cb('Copayer already voted on this transaction proposal'); |
|
|
if (action) return cb('Copayer already voted on this transaction proposal'); |
|
|
if (txp.status != 'pending') return cb('The transaction proposal is not pending'); |
|
|
if (txp.status != 'pending') return cb('The transaction proposal is not pending'); |
|
|
|
|
|
|
|
@ -461,7 +490,9 @@ CopayServer.prototype.getPendingTxs = function (opts, cb) { |
|
|
self.storage.fetchTxs(opts.walletId, function(err, txps) { |
|
|
self.storage.fetchTxs(opts.walletId, function(err, txps) { |
|
|
if (err) return cb(err); |
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
|
var pending = _.filter(txps, { status: 'pending' }); |
|
|
var pending = _.filter(txps, { |
|
|
|
|
|
status: 'pending' |
|
|
|
|
|
}); |
|
|
return cb(null, pending); |
|
|
return cb(null, pending); |
|
|
}); |
|
|
}); |
|
|
}; |
|
|
}; |
|
|