change indentation
This commit is contained in:
parent
5114b0cc25
commit
399c412cde
36
lib/lock.js
36
lib/lock.js
|
@ -3,31 +3,31 @@ var _ = require('lodash');
|
||||||
var locks = {};
|
var locks = {};
|
||||||
|
|
||||||
var Lock = function () {
|
var Lock = function () {
|
||||||
this.taken = false;
|
this.taken = false;
|
||||||
this.queue = [];
|
this.queue = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
Lock.prototype.free = function () {
|
Lock.prototype.free = function () {
|
||||||
if (this.queue.length > 0) {
|
if (this.queue.length > 0) {
|
||||||
var f = this.queue.shift();
|
var f = this.queue.shift();
|
||||||
f(this);
|
f(this);
|
||||||
} else {
|
} else {
|
||||||
this.taken = false;
|
this.taken = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Lock.get = function (key, callback) {
|
Lock.get = function (key, callback) {
|
||||||
if (_.isUndefined(locks[key])) {
|
if (_.isUndefined(locks[key])) {
|
||||||
locks[key] = new Lock();
|
locks[key] = new Lock();
|
||||||
}
|
}
|
||||||
var lock = locks[key];
|
var lock = locks[key];
|
||||||
|
|
||||||
if (lock.taken) {
|
if (lock.taken) {
|
||||||
lock.queue.push(callback);
|
lock.queue.push(callback);
|
||||||
} else {
|
} else {
|
||||||
lock.taken = true;
|
lock.taken = true;
|
||||||
callback(lock);
|
callback(lock);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Lock;
|
module.exports = Lock;
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function Address(opts) {
|
function Address(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
this.createdOn = Math.floor(Date.now() / 1000);
|
this.createdOn = Math.floor(Date.now() / 1000);
|
||||||
this.address = opts.address;
|
this.address = opts.address;
|
||||||
this.path = opts.path;
|
this.path = opts.path;
|
||||||
};
|
};
|
||||||
|
|
||||||
Address.fromObj = function (obj) {
|
Address.fromObj = function (obj) {
|
||||||
var x = new Address();
|
var x = new Address();
|
||||||
|
|
||||||
x.createdOn = obj.createdOn;
|
x.createdOn = obj.createdOn;
|
||||||
x.address = obj.address;
|
x.address = obj.address;
|
||||||
x.path = obj.path;
|
x.path = obj.path;
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Address;
|
module.exports = Address;
|
||||||
|
|
|
@ -8,17 +8,17 @@ var VERSION = '1.0.0';
|
||||||
var MESSAGE_SIGNING_PATH = "m/1/0";
|
var MESSAGE_SIGNING_PATH = "m/1/0";
|
||||||
|
|
||||||
function Copayer(opts) {
|
function Copayer(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
this.version = VERSION;
|
this.version = VERSION;
|
||||||
this.createdOn = Math.floor(Date.now() / 1000);
|
this.createdOn = Math.floor(Date.now() / 1000);
|
||||||
this.id = opts.id;
|
this.id = opts.id;
|
||||||
this.name = opts.name;
|
this.name = opts.name;
|
||||||
this.xPubKey = opts.xPubKey;
|
this.xPubKey = opts.xPubKey;
|
||||||
this.xPubKeySignature = opts.xPubKeySignature; // So third parties can check independently
|
this.xPubKeySignature = opts.xPubKeySignature; // So third parties can check independently
|
||||||
if (opts.xPubKey) {
|
if (opts.xPubKey) {
|
||||||
this.signingPubKey = this.getSigningPubKey();
|
this.signingPubKey = this.getSigningPubKey();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Copayer.prototype.getSigningPubKey = function () {
|
Copayer.prototype.getSigningPubKey = function () {
|
||||||
|
@ -27,17 +27,17 @@ Copayer.prototype.getSigningPubKey = function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
Copayer.fromObj = function (obj) {
|
Copayer.fromObj = function (obj) {
|
||||||
var x = new Copayer();
|
var x = new Copayer();
|
||||||
|
|
||||||
x.version = obj.version;
|
x.version = obj.version;
|
||||||
x.createdOn = obj.createdOn;
|
x.createdOn = obj.createdOn;
|
||||||
x.id = obj.id;
|
x.id = obj.id;
|
||||||
x.name = obj.name;
|
x.name = obj.name;
|
||||||
x.xPubKey = obj.xPubKey;
|
x.xPubKey = obj.xPubKey;
|
||||||
x.xPubKeySignature = obj.xPubKeySignature;
|
x.xPubKeySignature = obj.xPubKeySignature;
|
||||||
x.signingPubKey = obj.signingPubKey;
|
x.signingPubKey = obj.signingPubKey;
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,88 +7,88 @@ var TxProposalAction = require('./txproposalaction');
|
||||||
var VERSION = '1.0.0';
|
var VERSION = '1.0.0';
|
||||||
|
|
||||||
function TxProposal(opts) {
|
function TxProposal(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
this.version = VERSION;
|
this.version = VERSION;
|
||||||
this.createdOn = Math.floor(Date.now() / 1000);
|
this.createdOn = Math.floor(Date.now() / 1000);
|
||||||
this.id = opts.id;
|
this.id = opts.id;
|
||||||
this.creatorId = opts.creatorId;
|
this.creatorId = opts.creatorId;
|
||||||
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.changeAddress = opts.changeAddress;
|
this.changeAddress = opts.changeAddress;
|
||||||
this.inputs = opts.inputs;
|
this.inputs = opts.inputs;
|
||||||
this.requiredSignatures = opts.requiredSignatures;
|
this.requiredSignatures = opts.requiredSignatures;
|
||||||
this.maxRejections = opts.maxRejections;
|
this.maxRejections = opts.maxRejections;
|
||||||
this.status = 'pending';
|
this.status = 'pending';
|
||||||
this.actions = [];
|
this.actions = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
TxProposal.fromObj = function (obj) {
|
TxProposal.fromObj = function (obj) {
|
||||||
var x = new TxProposal();
|
var x = new TxProposal();
|
||||||
|
|
||||||
x.version = obj.version;
|
x.version = obj.version;
|
||||||
x.createdOn = obj.createdOn;
|
x.createdOn = obj.createdOn;
|
||||||
x.id = obj.id;
|
x.id = obj.id;
|
||||||
x.creatorId = obj.creatorId;
|
x.creatorId = obj.creatorId;
|
||||||
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.changeAddress = obj.changeAddress;
|
x.changeAddress = obj.changeAddress;
|
||||||
x.inputs = obj.inputs;
|
x.inputs = obj.inputs;
|
||||||
x.rawTx = obj.rawTx;
|
x.rawTx = obj.rawTx;
|
||||||
x.requiredSignatures = obj.requiredSignatures;
|
x.requiredSignatures = obj.requiredSignatures;
|
||||||
x.maxRejections = obj.maxRejections;
|
x.maxRejections = obj.maxRejections;
|
||||||
x.status = obj.status;
|
x.status = obj.status;
|
||||||
x.txid = obj.txid;
|
x.txid = obj.txid;
|
||||||
x.actions = _.map(obj.actions, function(action) {
|
x.actions = _.map(obj.actions, function(action) {
|
||||||
return new TxProposalAction(action);
|
return new TxProposalAction(action);
|
||||||
});
|
});
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
||||||
TxProposal.prototype._updateStatus = function () {
|
TxProposal.prototype._updateStatus = function () {
|
||||||
if (this.status != 'pending') return;
|
if (this.status != 'pending') return;
|
||||||
|
|
||||||
if (this.isRejected()) {
|
if (this.isRejected()) {
|
||||||
this.status = 'rejected';
|
this.status = 'rejected';
|
||||||
} else if (this.isAccepted()) {
|
} else if (this.isAccepted()) {
|
||||||
this.status = 'accepted';
|
this.status = 'accepted';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TxProposal.prototype.addAction = function (copayerId, type, signature) {
|
TxProposal.prototype.addAction = function (copayerId, type, signature) {
|
||||||
var action = new TxProposalAction({
|
var action = new TxProposalAction({
|
||||||
copayerId: copayerId,
|
copayerId: copayerId,
|
||||||
type: type,
|
type: type,
|
||||||
signature: signature,
|
signature: signature,
|
||||||
});
|
});
|
||||||
this.actions.push(action);
|
this.actions.push(action);
|
||||||
this._updateStatus();
|
this._updateStatus();
|
||||||
};
|
};
|
||||||
|
|
||||||
TxProposal.prototype.sign = function (copayerId, signature) {
|
TxProposal.prototype.sign = function (copayerId, signature) {
|
||||||
this.addAction(copayerId, 'accept', signature);
|
this.addAction(copayerId, 'accept', signature);
|
||||||
};
|
};
|
||||||
|
|
||||||
TxProposal.prototype.reject = function (copayerId) {
|
TxProposal.prototype.reject = function (copayerId) {
|
||||||
this.addAction(copayerId, 'reject');
|
this.addAction(copayerId, 'reject');
|
||||||
};
|
};
|
||||||
|
|
||||||
TxProposal.prototype.isAccepted = function () {
|
TxProposal.prototype.isAccepted = function () {
|
||||||
var votes = _.countBy(this.actions, 'type');
|
var votes = _.countBy(this.actions, 'type');
|
||||||
return votes['accept'] >= this.requiredSignatures;
|
return votes['accept'] >= this.requiredSignatures;
|
||||||
};
|
};
|
||||||
|
|
||||||
TxProposal.prototype.isRejected = function () {
|
TxProposal.prototype.isRejected = function () {
|
||||||
var votes = _.countBy(this.actions, 'type');
|
var votes = _.countBy(this.actions, 'type');
|
||||||
return votes['reject'] > this.maxRejections;
|
return votes['reject'] > this.maxRejections;
|
||||||
};
|
};
|
||||||
|
|
||||||
TxProposal.prototype.setBroadcasted = function (txid) {
|
TxProposal.prototype.setBroadcasted = function (txid) {
|
||||||
this.txid = txid;
|
this.txid = txid;
|
||||||
this.status = 'broadcasted';
|
this.status = 'broadcasted';
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = TxProposal;
|
module.exports = TxProposal;
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function TxProposalAction(opts) {
|
function TxProposalAction(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
this.createdOn = Math.floor(Date.now() / 1000);
|
this.createdOn = Math.floor(Date.now() / 1000);
|
||||||
this.copayerId = opts.copayerId;
|
this.copayerId = opts.copayerId;
|
||||||
this.type = opts.type || (opts.signature ? 'accept' : 'reject');
|
this.type = opts.type || (opts.signature ? 'accept' : 'reject');
|
||||||
this.signature = opts.signature;
|
this.signature = opts.signature;
|
||||||
};
|
};
|
||||||
|
|
||||||
TxProposalAction.fromObj = function (obj) {
|
TxProposalAction.fromObj = function (obj) {
|
||||||
var x = new TxProposalAction();
|
var x = new TxProposalAction();
|
||||||
|
|
||||||
x.createdOn = obj.createdOn;
|
x.createdOn = obj.createdOn;
|
||||||
x.copayerId = obj.copayerId;
|
x.copayerId = obj.copayerId;
|
||||||
x.type = obj.type;
|
x.type = obj.type;
|
||||||
x.signature = obj.signature;
|
x.signature = obj.signature;
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = TxProposalAction;
|
module.exports = TxProposalAction;
|
||||||
|
|
|
@ -6,18 +6,18 @@ var Copayer = require('./copayer');
|
||||||
var VERSION = '1.0.0';
|
var VERSION = '1.0.0';
|
||||||
|
|
||||||
function Wallet(opts) {
|
function Wallet(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
this.version = VERSION;
|
this.version = VERSION;
|
||||||
this.createdOn = Math.floor(Date.now() / 1000);
|
this.createdOn = Math.floor(Date.now() / 1000);
|
||||||
this.id = opts.id;
|
this.id = opts.id;
|
||||||
this.name = opts.name;
|
this.name = opts.name;
|
||||||
this.m = opts.m;
|
this.m = opts.m;
|
||||||
this.n = opts.n;
|
this.n = opts.n;
|
||||||
this.status = 'pending';
|
this.status = 'pending';
|
||||||
this.publicKeyRing = [];
|
this.publicKeyRing = [];
|
||||||
this.addressIndex = 0;
|
this.addressIndex = 0;
|
||||||
this.copayers = [];
|
this.copayers = [];
|
||||||
this.pubKey = opts.pubKey;
|
this.pubKey = opts.pubKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,40 +48,40 @@ Wallet.getMaxRequiredCopayers = function(totalCopayers) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.verifyCopayerLimits = function (m, n) {
|
Wallet.verifyCopayerLimits = function (m, n) {
|
||||||
return (n >= 1 && n <= 12) && (m >= 1 && m <= Wallet.COPAYER_PAIR_LIMITS[n]);
|
return (n >= 1 && n <= 12) && (m >= 1 && m <= Wallet.COPAYER_PAIR_LIMITS[n]);
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.fromObj = function (obj) {
|
Wallet.fromObj = function (obj) {
|
||||||
var x = new Wallet();
|
var x = new Wallet();
|
||||||
|
|
||||||
x.version = obj.version;
|
x.version = obj.version;
|
||||||
x.createdOn = obj.createdOn;
|
x.createdOn = obj.createdOn;
|
||||||
x.id = obj.id;
|
x.id = obj.id;
|
||||||
x.name = obj.name;
|
x.name = obj.name;
|
||||||
x.m = obj.m;
|
x.m = obj.m;
|
||||||
x.n = obj.n;
|
x.n = obj.n;
|
||||||
x.status = obj.status;
|
x.status = obj.status;
|
||||||
x.publicKeyRing = obj.publicKeyRing;
|
x.publicKeyRing = obj.publicKeyRing;
|
||||||
x.addressIndex = obj.addressIndex;
|
x.addressIndex = obj.addressIndex;
|
||||||
x.copayers = _.map(obj.copayers, function (copayer) {
|
x.copayers = _.map(obj.copayers, function (copayer) {
|
||||||
return new Copayer(copayer);
|
return new Copayer(copayer);
|
||||||
});
|
});
|
||||||
x.pubKey = obj.pubKey;
|
x.pubKey = obj.pubKey;
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.addCopayer = function (copayer) {
|
Wallet.prototype.addCopayer = function (copayer) {
|
||||||
this.copayers.push(copayer);
|
this.copayers.push(copayer);
|
||||||
|
|
||||||
if (this.copayers.length < this.n) return;
|
if (this.copayers.length < this.n) return;
|
||||||
|
|
||||||
this.status = 'complete';
|
this.status = 'complete';
|
||||||
this.publicKeyRing = _.pluck(this.copayers, 'xPubKey');
|
this.publicKeyRing = _.pluck(this.copayers, 'xPubKey');
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.getCopayer = function (copayerId) {
|
Wallet.prototype.getCopayer = function (copayerId) {
|
||||||
return _.find(this.copayers, { id: copayerId });
|
return _.find(this.copayers, { id: copayerId });
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Wallet;
|
module.exports = Wallet;
|
||||||
|
|
430
lib/server.js
430
lib/server.js
|
@ -30,8 +30,8 @@ var TxProposal = require('./model/txproposal');
|
||||||
* @param {Storage} [opts.storage] - The storage provider.
|
* @param {Storage} [opts.storage] - The storage provider.
|
||||||
*/
|
*/
|
||||||
function CopayServer(opts) {
|
function CopayServer(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
this.storage = opts.storage || new Storage();
|
this.storage = opts.storage || new Storage();
|
||||||
};
|
};
|
||||||
|
|
||||||
inherits(CopayServer, events.EventEmitter);
|
inherits(CopayServer, events.EventEmitter);
|
||||||
|
@ -53,12 +53,12 @@ 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');
|
||||||
var network = opts.network || 'livenet';
|
var network = opts.network || 'livenet';
|
||||||
if (network != 'livenet' && network != 'testnet') return cb('Invalid network');
|
if (network != 'livenet' && network != 'testnet') return cb('Invalid network');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pubKey = new PublicKey.fromString(opts.pubKey);
|
pubKey = new PublicKey.fromString(opts.pubKey);
|
||||||
|
@ -66,21 +66,21 @@ CopayServer.prototype.createWallet = function (opts, cb) {
|
||||||
return cb(e.toString());
|
return cb(e.toString());
|
||||||
};
|
};
|
||||||
|
|
||||||
self.storage.fetchWallet(opts.id, function (err, wallet) {
|
self.storage.fetchWallet(opts.id, function (err, wallet) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
if (wallet) return cb('Wallet already exists');
|
if (wallet) return cb('Wallet already exists');
|
||||||
|
|
||||||
var wallet = new Wallet({
|
var wallet = new Wallet({
|
||||||
id: opts.id,
|
id: opts.id,
|
||||||
name: opts.name,
|
name: opts.name,
|
||||||
m: opts.m,
|
m: opts.m,
|
||||||
n: opts.n,
|
n: opts.n,
|
||||||
network: network,
|
network: network,
|
||||||
pubKey: pubKey,
|
pubKey: pubKey,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.storage.storeWallet(wallet, cb);
|
self.storage.storeWallet(wallet, cb);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,13 +90,13 @@ CopayServer.prototype.createWallet = function (opts, cb) {
|
||||||
* @returns {Object} wallet
|
* @returns {Object} wallet
|
||||||
*/
|
*/
|
||||||
CopayServer.prototype.getWallet = function (opts, cb) {
|
CopayServer.prototype.getWallet = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self.storage.fetchWallet(opts.id, function (err, wallet) {
|
self.storage.fetchWallet(opts.id, function (err, wallet) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
if (!wallet) return cb('Wallet not found');
|
if (!wallet) return cb('Wallet not found');
|
||||||
return cb(null, wallet);
|
return cb(null, wallet);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -120,40 +120,40 @@ CopayServer.prototype._verifySignature = function (text, signature, pubKey) {
|
||||||
* @param {number} opts.xPubKeySignature - Signature of xPubKey using the wallet pubKey.
|
* @param {number} opts.xPubKeySignature - Signature of xPubKey using the wallet pubKey.
|
||||||
*/
|
*/
|
||||||
CopayServer.prototype.joinWallet = function (opts, cb) {
|
CopayServer.prototype.joinWallet = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
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)) {
|
||||||
return cb('Bad request');
|
return cb('Bad request');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.find(wallet.copayers, { xPubKey: opts.xPubKey })) return cb('Copayer already in wallet');
|
if (_.find(wallet.copayers, { xPubKey: opts.xPubKey })) return cb('Copayer already in wallet');
|
||||||
if (wallet.copayers.length == wallet.n) return cb('Wallet full');
|
if (wallet.copayers.length == wallet.n) return cb('Wallet full');
|
||||||
var copayer = new Copayer({
|
var copayer = new Copayer({
|
||||||
id: opts.id,
|
id: opts.id,
|
||||||
name: opts.name,
|
name: opts.name,
|
||||||
xPubKey: opts.xPubKey,
|
xPubKey: opts.xPubKey,
|
||||||
xPubKeySignature: opts.xPubKeySignature,
|
xPubKeySignature: opts.xPubKeySignature,
|
||||||
});
|
});
|
||||||
|
|
||||||
wallet.addCopayer(copayer);
|
wallet.addCopayer(copayer);
|
||||||
|
|
||||||
self.storage.storeWallet(wallet, function (err) {
|
self.storage.storeWallet(wallet, function (err) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
return cb();
|
return cb();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
CopayServer.prototype._doCreateAddress = function (pkr, index, isChange) {
|
CopayServer.prototype._doCreateAddress = function (pkr, index, isChange) {
|
||||||
throw 'not implemented';
|
throw 'not implemented';
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -167,27 +167,27 @@ CopayServer.prototype._doCreateAddress = function (pkr, index, isChange) {
|
||||||
* @returns {Address} address
|
* @returns {Address} address
|
||||||
*/
|
*/
|
||||||
CopayServer.prototype.createAddress = function (opts, cb) {
|
CopayServer.prototype.createAddress = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
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 index = wallet.addressIndex++;
|
var index = wallet.addressIndex++;
|
||||||
self.storage.storeWallet(wallet, function (err) {
|
self.storage.storeWallet(wallet, function (err) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
var address = self._doCreateAddress(wallet.publicKeyRing, index, opts.isChange);
|
var address = self._doCreateAddress(wallet.publicKeyRing, index, opts.isChange);
|
||||||
self.storage.storeAddress(opts.walletId, address, function (err) {
|
self.storage.storeAddress(opts.walletId, address, function (err) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
return cb(null, address);
|
return cb(null, address);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -200,78 +200,78 @@ CopayServer.prototype._doCreateAddress = function (pkr, index, isChange) {
|
||||||
* @returns {truthy} The result of the verification.
|
* @returns {truthy} The result of the verification.
|
||||||
*/
|
*/
|
||||||
CopayServer.prototype.verifyMessageSignature = function (opts, cb) {
|
CopayServer.prototype.verifyMessageSignature = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
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);
|
||||||
if (!copayer) return cb('Copayer not found');
|
if (!copayer) return cb('Copayer not found');
|
||||||
|
|
||||||
var isValid = self._verifySignature(opts.message, opts.signature, copayer.signingPubKey);
|
var isValid = self._verifySignature(opts.message, opts.signature, copayer.signingPubKey);
|
||||||
return cb(null, isValid);
|
return cb(null, isValid);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
CopayServer.prototype._getBlockExplorer = function (provider, network) {
|
CopayServer.prototype._getBlockExplorer = function (provider, network) {
|
||||||
var url;
|
var url;
|
||||||
|
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
default:
|
default:
|
||||||
case 'insight':
|
case 'insight':
|
||||||
switch (network) {
|
switch (network) {
|
||||||
default:
|
default:
|
||||||
case 'livenet':
|
case 'livenet':
|
||||||
url = 'https://insight.bitpay.com:443';
|
url = 'https://insight.bitpay.com:443';
|
||||||
break;
|
break;
|
||||||
case 'testnet':
|
case 'testnet':
|
||||||
url = 'https://test-insight.bitpay.com:443'
|
url = 'https://test-insight.bitpay.com:443'
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return new Explorers.Insight(url, network);
|
return new Explorers.Insight(url, network);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
CopayServer.prototype._getUtxos = function (opts, cb) {
|
CopayServer.prototype._getUtxos = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// Get addresses for this wallet
|
// Get addresses for this wallet
|
||||||
self.storage.fetchAddresses(opts.walletId, function (err, addresses) {
|
self.storage.fetchAddresses(opts.walletId, function (err, addresses) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
if (addresses.length == 0) return cb('The wallet has no addresses');
|
if (addresses.length == 0) return cb('The wallet has no addresses');
|
||||||
|
|
||||||
var addresses = _.pluck(addresses, 'address');
|
var addresses = _.pluck(addresses, 'address');
|
||||||
|
|
||||||
var bc = self._getBlockExplorer('insight', opts.network);
|
var bc = self._getBlockExplorer('insight', opts.network);
|
||||||
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;
|
||||||
});
|
});
|
||||||
|
|
||||||
_.each(inputs, function (input) {
|
_.each(inputs, function (input) {
|
||||||
if (dictionary[input]) {
|
if (dictionary[input]) {
|
||||||
dictionary[input].locked = true;
|
dictionary[input].locked = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return cb(null, utxos);
|
return cb(null, utxos);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -282,45 +282,45 @@ CopayServer.prototype._getUtxos = function (opts, cb) {
|
||||||
* @returns {Object} balance - Total amount & locked amount.
|
* @returns {Object} balance - Total amount & locked amount.
|
||||||
*/
|
*/
|
||||||
CopayServer.prototype.getBalance = function (opts, cb) {
|
CopayServer.prototype.getBalance = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
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) { return sum + utxo.amount; }, 0);
|
||||||
balance.lockedAmount = _.reduce(_.without(utxos, { locked: true }), function(sum, utxo) { 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);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
CopayServer.prototype._createRawTx = function (txp) {
|
CopayServer.prototype._createRawTx = function (txp) {
|
||||||
var rawTx = new Bitcore.Transaction()
|
var rawTx = new Bitcore.Transaction()
|
||||||
.from(tx.inputs)
|
.from(tx.inputs)
|
||||||
.to(txp.toAddress, txp.amount)
|
.to(txp.toAddress, txp.amount)
|
||||||
.change(txp.changeAddress);
|
.change(txp.changeAddress);
|
||||||
|
|
||||||
return rawTx;
|
return rawTx;
|
||||||
};
|
};
|
||||||
|
|
||||||
CopayServer.prototype._selectUtxos = function (txp, utxos) {
|
CopayServer.prototype._selectUtxos = function (txp, utxos) {
|
||||||
var i = 0;
|
var i = 0;
|
||||||
var total = 0;
|
var total = 0;
|
||||||
var selected = [];
|
var selected = [];
|
||||||
var inputs = _.sortBy(utxos, 'amount');
|
var inputs = _.sortBy(utxos, 'amount');
|
||||||
while (i < inputs.length) {
|
while (i < inputs.length) {
|
||||||
selected.push(inputs[i]);
|
selected.push(inputs[i]);
|
||||||
total += inputs[i].amount;
|
total += inputs[i].amount;
|
||||||
if (total >= txp.amount) {
|
if (total >= txp.amount) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
};
|
};
|
||||||
return selected;
|
return selected;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -335,44 +335,44 @@ CopayServer.prototype._selectUtxos = function (txp, utxos) {
|
||||||
* @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, ['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,
|
||||||
toAddress: opts.toAddress,
|
toAddress: opts.toAddress,
|
||||||
amount: opts.amount,
|
amount: opts.amount,
|
||||||
inputs: self._selectUtxos(opts.amount, utxos),
|
inputs: self._selectUtxos(opts.amount, utxos),
|
||||||
changeAddress: opts.changeAddress,
|
changeAddress: opts.changeAddress,
|
||||||
requiredSignatures: wallet.m,
|
requiredSignatures: wallet.m,
|
||||||
maxRejections: wallet.n - wallet.m,
|
maxRejections: wallet.n - wallet.m,
|
||||||
});
|
});
|
||||||
|
|
||||||
txp.rawTx = self._createRawTx(txp);
|
txp.rawTx = self._createRawTx(txp);
|
||||||
|
|
||||||
self.storage.storeTx(wallet.id, txp, function (err) {
|
self.storage.storeTx(wallet.id, txp, function (err) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
return cb(null, txp);
|
return cb(null, txp);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
CopayServer.prototype._broadcastTx = function (rawTx, cb) {
|
CopayServer.prototype._broadcastTx = function (rawTx, cb) {
|
||||||
// TODO: this should attempt to broadcast _all_ accepted and not-yet broadcasted (status=='accepted') txps?
|
// TODO: this should attempt to broadcast _all_ accepted and not-yet broadcasted (status=='accepted') txps?
|
||||||
cb = cb || function () {};
|
cb = cb || function () {};
|
||||||
|
|
||||||
throw 'not implemented';
|
throw 'not implemented';
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -384,35 +384,35 @@ CopayServer.prototype._broadcastTx = function (rawTx, cb) {
|
||||||
* @param {string} opts.signature - The signature of the tx for this copayer.
|
* @param {string} opts.signature - The signature of the tx for this copayer.
|
||||||
*/
|
*/
|
||||||
CopayServer.prototype.signTx = function (opts, cb) {
|
CopayServer.prototype.signTx = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
Utils.checkRequired(opts, ['walletId', 'copayerId', 'txProposalId', 'signature']);
|
Utils.checkRequired(opts, ['walletId', 'copayerId', 'txProposalId', 'signature']);
|
||||||
|
|
||||||
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');
|
||||||
|
|
||||||
txp.sign(opts.copayerId, opts.signature);
|
txp.sign(opts.copayerId, opts.signature);
|
||||||
|
|
||||||
self.storage.storeTx(opts.walletId, txp, function (err) {
|
self.storage.storeTx(opts.walletId, txp, function (err) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
if (txp.status == 'accepted');
|
if (txp.status == 'accepted');
|
||||||
self._broadcastTx(txp.rawTx, function (err, txid) {
|
self._broadcastTx(txp.rawTx, function (err, txid) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
tx.setBroadcasted(txid);
|
tx.setBroadcasted(txid);
|
||||||
self.storage.storeTx(opts.walletId, txp, function (err) {
|
self.storage.storeTx(opts.walletId, txp, function (err) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
return cb();
|
return cb();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -424,25 +424,25 @@ CopayServer.prototype.signTx = function (opts, cb) {
|
||||||
* @param {string} [opts.reason] - A message to other copayers explaining the rejection.
|
* @param {string} [opts.reason] - A message to other copayers explaining the rejection.
|
||||||
*/
|
*/
|
||||||
CopayServer.prototype.rejectTx = function (opts, cb) {
|
CopayServer.prototype.rejectTx = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
Utils.checkRequired(opts, ['walletId', 'copayerId', 'txProposalId']);
|
Utils.checkRequired(opts, ['walletId', 'copayerId', 'txProposalId']);
|
||||||
|
|
||||||
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');
|
||||||
|
|
||||||
txp.reject(opts.copayerId);
|
txp.reject(opts.copayerId);
|
||||||
|
|
||||||
self.storage.storeTx(opts.walletId, txp, function (err) {
|
self.storage.storeTx(opts.walletId, txp, function (err) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
return cb();
|
return cb();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -452,17 +452,17 @@ CopayServer.prototype.rejectTx = function (opts, cb) {
|
||||||
* @returns {TxProposal[]} Transaction proposal.
|
* @returns {TxProposal[]} Transaction proposal.
|
||||||
*/
|
*/
|
||||||
CopayServer.prototype.getPendingTxs = function (opts, cb) {
|
CopayServer.prototype.getPendingTxs = function (opts, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
Utils.checkRequired(opts, 'walletId');
|
Utils.checkRequired(opts, 'walletId');
|
||||||
|
|
||||||
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);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,73 +13,73 @@ var Address = require('./model/address');
|
||||||
var TxProposal = require('./model/txproposal');
|
var TxProposal = require('./model/txproposal');
|
||||||
|
|
||||||
var Storage = function (opts) {
|
var Storage = function (opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
this.db = opts.db || levelup(opts.dbPath || './db/copay.db', { valueEncoding: 'json' });
|
this.db = opts.db || levelup(opts.dbPath || './db/copay.db', { valueEncoding: 'json' });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Storage.prototype.fetchWallet = function (id, cb) {
|
Storage.prototype.fetchWallet = function (id, cb) {
|
||||||
this.db.get('wallet-' + id, function (err, data) {
|
this.db.get('wallet-' + id, function (err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err.notFound) return cb();
|
if (err.notFound) return cb();
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
return cb(null, Wallet.fromObj(data));
|
return cb(null, Wallet.fromObj(data));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Storage.prototype.storeWallet = function (wallet, cb) {
|
Storage.prototype.storeWallet = function (wallet, cb) {
|
||||||
this.db.put('wallet-' + wallet.id, wallet, cb);
|
this.db.put('wallet-' + wallet.id, wallet, cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
Storage.prototype.fetchTx = function (walletId, txProposalId, cb) {
|
Storage.prototype.fetchTx = function (walletId, txProposalId, cb) {
|
||||||
this.db.get('wallet-' + walletId + '-txp-' + txProposalId, function (err, data) {
|
this.db.get('wallet-' + walletId + '-txp-' + txProposalId, function (err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err.notFound) return cb();
|
if (err.notFound) return cb();
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
return cb(null, TxProposal.fromObj(data));
|
return cb(null, TxProposal.fromObj(data));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Storage.prototype.fetchTxs = function (walletId, cb) {
|
Storage.prototype.fetchTxs = function (walletId, cb) {
|
||||||
var txs = [];
|
var txs = [];
|
||||||
var key = 'wallet-' + walletId + '-txp-';
|
var key = 'wallet-' + walletId + '-txp-';
|
||||||
this.db.createReadStream({ gte: key, lt: key + '~' })
|
this.db.createReadStream({ gte: key, lt: key + '~' })
|
||||||
.on('data', function (data) {
|
.on('data', function (data) {
|
||||||
txs.push(TxProposal.fromObj(data.value));
|
txs.push(TxProposal.fromObj(data.value));
|
||||||
})
|
})
|
||||||
.on('error', function (err) {
|
.on('error', function (err) {
|
||||||
if (err.notFound) return cb();
|
if (err.notFound) return cb();
|
||||||
return cb(err);
|
return cb(err);
|
||||||
})
|
})
|
||||||
.on('end', function () {
|
.on('end', function () {
|
||||||
return cb(null, txs);
|
return cb(null, txs);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Storage.prototype.storeTx = function (walletId, txp, 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.txProposalId, txp, cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
Storage.prototype.fetchAddresses = function (walletId, cb) {
|
Storage.prototype.fetchAddresses = function (walletId, cb) {
|
||||||
var addresses = [];
|
var addresses = [];
|
||||||
var key = 'wallet-' + walletId + '-address-';
|
var key = 'wallet-' + walletId + '-address-';
|
||||||
this.db.createReadStream({ gte: key, lt: key + '~' })
|
this.db.createReadStream({ gte: key, lt: key + '~' })
|
||||||
.on('data', function (data) {
|
.on('data', function (data) {
|
||||||
addresses.push(Address.fromObj(data.value));
|
addresses.push(Address.fromObj(data.value));
|
||||||
})
|
})
|
||||||
.on('error', function (err) {
|
.on('error', function (err) {
|
||||||
if (err.notFound) return cb();
|
if (err.notFound) return cb();
|
||||||
return cb(err);
|
return cb(err);
|
||||||
})
|
})
|
||||||
.on('end', function () {
|
.on('end', function () {
|
||||||
return cb(null, addresses);
|
return cb(null, addresses);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Storage.prototype.storeAddress = function (walletId, address, cb) {
|
Storage.prototype.storeAddress = function (walletId, address, cb) {
|
||||||
this.db.put('wallet-' + walletId + '-address-' + address.address, address, cb);
|
this.db.put('wallet-' + walletId + '-address-' + address.address, address, cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
26
lib/utils.js
26
lib/utils.js
|
@ -5,24 +5,24 @@ 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();
|
||||||
};
|
};
|
||||||
task(_cb);
|
task(_cb);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
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)) throw 'Required arguments missing';
|
||||||
_.each(args, function (arg) {
|
_.each(args, function (arg) {
|
||||||
if (!obj.hasOwnProperty(arg)) throw "Missing required argument '" + arg + "'";
|
if (!obj.hasOwnProperty(arg)) throw "Missing required argument '" + arg + "'";
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Utils;
|
module.exports = Utils;
|
||||||
|
|
Loading…
Reference in New Issue