|
|
@ -1174,7 +1174,6 @@ WalletService.prototype.getSendMaxInfo = function(opts, cb) { |
|
|
|
size: 0, |
|
|
|
amount: 0, |
|
|
|
fee: 0, |
|
|
|
nbInputs: 0, |
|
|
|
inputs: [], |
|
|
|
}; |
|
|
|
|
|
|
@ -1210,7 +1209,6 @@ WalletService.prototype.getSendMaxInfo = function(opts, cb) { |
|
|
|
info.size = txp.getEstimatedSize(); |
|
|
|
info.fee = txp.getEstimatedFee(); |
|
|
|
info.amount = _.sum(txp.inputs, 'satoshis') - info.fee; |
|
|
|
info.nbInputs = txp.inputs.length; |
|
|
|
info.inputs = txp.inputs; |
|
|
|
|
|
|
|
return cb(null, info); |
|
|
@ -1803,27 +1801,42 @@ WalletService.prototype._doCreateTx = function(opts, cb) { |
|
|
|
} |
|
|
|
|
|
|
|
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 wallet, txp, changeAddress; |
|
|
|
async.series([ |
|
|
|
|
|
|
|
function(next) { |
|
|
|
self.getWallet({}, function(err, w) { |
|
|
|
if (err) return next(err); |
|
|
|
if (!w.isComplete()) return next(Errors.WALLET_NOT_COMPLETE); |
|
|
|
wallet = w; |
|
|
|
next(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
function(next) { |
|
|
|
self._canCreateTx(function(err, canCreate) { |
|
|
|
if (err) return cb(err); |
|
|
|
if (!canCreate) return cb(Errors.TX_CANNOT_CREATE); |
|
|
|
if (err) return next(err); |
|
|
|
if (!canCreate) return next(Errors.TX_CANNOT_CREATE); |
|
|
|
|
|
|
|
if (opts.validateOutputs !== false) { |
|
|
|
var validationError = self._validateOutputs(opts, wallet); |
|
|
|
if (validationError) { |
|
|
|
return cb(validationError); |
|
|
|
return next(validationError); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
next(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
function(next) { |
|
|
|
if (!opts.sendMax) { |
|
|
|
changeAddress = wallet.createAddress(true); |
|
|
|
} |
|
|
|
var txOpts = { |
|
|
|
walletId: self.walletId, |
|
|
|
creatorId: self.copayerId, |
|
|
|
outputs: opts.outputs, |
|
|
|
message: opts.message, |
|
|
|
changeAddress: wallet.createAddress(true), |
|
|
|
changeAddress: changeAddress, |
|
|
|
feePerKb: opts.feePerKb, |
|
|
|
payProUrl: opts.payProUrl, |
|
|
|
walletM: wallet.m, |
|
|
@ -1836,23 +1849,24 @@ WalletService.prototype._doCreateTx = function(opts, cb) { |
|
|
|
fee: opts.inputs && !_.isNumber(opts.feePerKb) ? opts.fee : null, |
|
|
|
}; |
|
|
|
|
|
|
|
var txp = Model.TxProposal.create(txOpts); |
|
|
|
|
|
|
|
self._selectTxInputs(txp, opts.utxosToExclude, function(err) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
self.storage.storeAddressAndWallet(wallet, txp.changeAddress, function(err) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
self.storage.storeTx(wallet.id, txp, function(err) { |
|
|
|
txp = Model.TxProposal.create(txOpts); |
|
|
|
next(); |
|
|
|
}, |
|
|
|
function(next) { |
|
|
|
self._selectTxInputs(txp, opts.utxosToExclude, next); |
|
|
|
}, |
|
|
|
function(next) { |
|
|
|
if (!changeAddress) return next(); |
|
|
|
self.storage.storeAddressAndWallet(wallet, txp.changeAddress, next); |
|
|
|
}, |
|
|
|
function(next) { |
|
|
|
self.storage.storeTx(wallet.id, txp, next); |
|
|
|
}, |
|
|
|
], function(err) { |
|
|
|
if (err) return cb(err); |
|
|
|
return cb(null, txp); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
@ -1883,6 +1897,11 @@ WalletService.prototype.createTx = function(opts, cb) { |
|
|
|
if (!_.isArray(opts.outputs) || opts.outputs.length > 1) { |
|
|
|
return next(new ClientError('Only one output allowed when sendMax is specified')); |
|
|
|
} |
|
|
|
if (_.isNumber(opts.outputs[0].amount)) |
|
|
|
return next(new ClientError('Amount is not allowed when sendMax is specified')); |
|
|
|
if (_.isNumber(opts.fee)) |
|
|
|
return next(new ClientError('Fee is not allowed when sendMax is specified (use feePerKb instead)')); |
|
|
|
|
|
|
|
self.getSendMaxInfo(opts, function(err, info) { |
|
|
|
if (err) return next(err); |
|
|
|
opts.outputs[0].amount = info.amount; |
|
|
|