|
|
@ -34,7 +34,6 @@ var blockchainExplorerOpts; |
|
|
|
var messageBroker; |
|
|
|
var serviceVersion; |
|
|
|
|
|
|
|
var MAX_KEYS = 100; |
|
|
|
|
|
|
|
/** |
|
|
|
* Creates an instance of the Bitcore Wallet Service. |
|
|
@ -53,6 +52,8 @@ function WalletService() { |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
WalletService.MAX_KEYS = 100; |
|
|
|
|
|
|
|
// Time after which a Tx proposal can be erased by any copayer. in seconds
|
|
|
|
WalletService.DELETE_LOCKTIME = 24 * 3600; |
|
|
|
|
|
|
@ -62,9 +63,11 @@ WalletService.BACKOFF_OFFSET = 3; |
|
|
|
// Time a copayer need to wait to create a new TX after her tx previous proposal we rejected. (incremental). in Minutes.
|
|
|
|
WalletService.BACKOFF_TIME = 2; |
|
|
|
|
|
|
|
WalletService.MAX_MAIN_ADDRESS_GAP = 20; |
|
|
|
|
|
|
|
// Fund scanning parameters
|
|
|
|
WalletService.SCAN_CONFIG = { |
|
|
|
maxGap: 20, |
|
|
|
maxGap: WalletService.MAX_MAIN_ADDRESS_GAP, |
|
|
|
}; |
|
|
|
|
|
|
|
WalletService.FEE_LEVELS = [{ |
|
|
@ -518,7 +521,7 @@ WalletService.prototype.addAccess = function(opts, cb) { |
|
|
|
return cb(Errors.NOT_AUTHORIZED); |
|
|
|
} |
|
|
|
|
|
|
|
if (copayer.requestPubKeys.length > MAX_KEYS) |
|
|
|
if (copayer.requestPubKeys.length > WalletService.MAX_KEYS) |
|
|
|
return cb(Errors.TOO_MANY_KEYS); |
|
|
|
|
|
|
|
self._addKeyToCopayer(wallet, copayer, opts, cb); |
|
|
@ -689,29 +692,74 @@ WalletService.prototype.getPreferences = function(opts, cb) { |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
WalletService.prototype._canCreateAddress = function(ignoreMaxGap, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
if (ignoreMaxGap) return cb(null, true); |
|
|
|
|
|
|
|
self.storage.fetchAddresses(self.walletId, function(err, addresses) { |
|
|
|
if (err) return cb(err); |
|
|
|
var latestAddresses = _.takeRight(_.reject(addresses, { |
|
|
|
isChange: true |
|
|
|
}), WalletService.MAX_MAIN_ADDRESS_GAP); |
|
|
|
if (latestAddresses.length < WalletService.MAX_MAIN_ADDRESS_GAP || _.any(latestAddresses, { |
|
|
|
hasActivity: true |
|
|
|
})) return cb(null, true); |
|
|
|
|
|
|
|
var bc = self._getBlockchainExplorer(latestAddresses[0].network); |
|
|
|
var activityFound = false; |
|
|
|
var i = latestAddresses.length; |
|
|
|
async.whilst(function() { |
|
|
|
return i > 0 && !activityFound; |
|
|
|
}, function(next) { |
|
|
|
bc.getAddressActivity(latestAddresses[--i].address, function(err, res) { |
|
|
|
if (err) return next(err); |
|
|
|
activityFound = !!res; |
|
|
|
return next(); |
|
|
|
}); |
|
|
|
}, function(err) { |
|
|
|
if (err) return cb(err); |
|
|
|
if (!activityFound) return cb(null, false); |
|
|
|
|
|
|
|
var address = latestAddresses[i]; |
|
|
|
address.hasActivity = true; |
|
|
|
self.storage.storeAddress(address, function(err) { |
|
|
|
return cb(err, true); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
* Creates a new address. |
|
|
|
* @param {Object} opts |
|
|
|
* @param {Boolean} [opts.ignoreMaxGap=false] - Ignore constraint of maximum number of consecutive addresses without activity |
|
|
|
* @returns {Address} address |
|
|
|
*/ |
|
|
|
WalletService.prototype.createAddress = function(opts, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
opts = opts || {}; |
|
|
|
|
|
|
|
self._runLocked(cb, function(cb) { |
|
|
|
self.getWallet({}, function(err, wallet) { |
|
|
|
if (err) return cb(err); |
|
|
|
if (!wallet.isComplete()) return cb(Errors.WALLET_NOT_COMPLETE); |
|
|
|
|
|
|
|
var address = wallet.createAddress(false); |
|
|
|
|
|
|
|
self.storage.storeAddressAndWallet(wallet, address, function(err) { |
|
|
|
self._canCreateAddress(opts.ignoreMaxGap, function(err, canCreate) { |
|
|
|
if (err) return cb(err); |
|
|
|
if (!canCreate) return cb(Errors.MAIN_ADDRESS_GAP_REACHED); |
|
|
|
|
|
|
|
var address = wallet.createAddress(false); |
|
|
|
|
|
|
|
self._notify('NewAddress', { |
|
|
|
address: address.address, |
|
|
|
}, function() { |
|
|
|
return cb(null, address); |
|
|
|
self.storage.storeAddressAndWallet(wallet, address, function(err) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
self._notify('NewAddress', { |
|
|
|
address: address.address, |
|
|
|
}, function() { |
|
|
|
return cb(null, address); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|