@ -114,15 +114,15 @@ const SendFunds_ProcessStep_MessageSuffix =
exports . SendFunds _ProcessStep _MessageSuffix = SendFunds _ProcessStep _MessageSuffix
//
function SendFunds (
isRingCT ,
target _address , // currency-ready wallet address, but not an OA address (resolve before calling)
nettype ,
amount , // number
amount _orZeroWhenSweep , // number - value will be ignoring for sweep
isSweep _orZeroWhenAmount , // send true to sweep - amount_orZeroWhenSweep will be ignored
wallet _ _keyImage _cache ,
wallet _ _public _address ,
wallet _ _private _keys ,
wallet _ _public _keys ,
hostedMoneroAPIClient ,
hostedMoneroAPIClient , // TODO: possibly factor this dependency
monero _openalias _utils ,
payment _id ,
mixin ,
@ -141,6 +141,8 @@ function SendFunds(
// err
// )
) {
var isRingCT = true
var sweeping = isSweep _orZeroWhenAmount === true // rather than, say, undefined
//
// some callback trampoline function declarations…
function _ _trampolineFor _success (
@ -174,6 +176,7 @@ function SendFunds(
}
//
// parse & normalize the target descriptions by mapping them to Monero addresses & amounts
var amount = sweeping ? 0 : amount _orZeroWhenSweep
const targetDescription =
{
address : target _address ,
@ -209,8 +212,8 @@ function SendFunds(
var moneroReady _targetDescription _amount = moneroReady _targetDescription . amount
//
var totalAmountWithoutFee _JSBigInt = ( new JSBigInt ( 0 ) ) . add ( moneroReady _targetDescription _amount )
console . log ( "💬 Total to send, before fee: " + monero_utils . formatMoney ( totalAmountWithoutFee _JSBigInt ) ) ;
if ( totalAmountWithoutFee _JSBigInt . compare ( 0 ) <= 0 ) {
console . log ( "💬 Total to send, before fee: " + sweeping ? "all" : monero_utils . formatMoney ( totalAmountWithoutFee _JSBigInt ) ) ;
if ( ! sweeping && totalAmountWithoutFee _JSBigInt . compare ( 0 ) <= 0 ) {
const errStr = "The amount you've entered is too low"
_ _trampolineFor _err _withStr ( errStr )
return
@ -272,8 +275,7 @@ function SendFunds(
unspentOuts ,
unusedOuts ,
dynamic _feePerKB _JSBigInt
)
{
) {
if ( err ) {
_ _trampolineFor _err _withErr ( err )
return
@ -327,7 +329,14 @@ function SendFunds(
//
var attemptAt _network _minimumFee = passedIn _attemptAt _network _minimumFee // we may change this if isRingCT
// const hostingService_chargeAmount = hostedMoneroAPIClient.HostingServiceChargeFor_transactionWithNetworkFee(attemptAt_network_minimumFee)
var totalAmountIncludingFees = totalAmountWithoutFee _JSBigInt . add ( attemptAt _network _minimumFee ) /*.add(hostingService_chargeAmount) NOTE service fee removed for now */
var totalAmountIncludingFees ;
if ( sweeping ) {
totalAmountIncludingFees = new JSBigInt ( "18450000000000000000" ) ; //~uint64 max
console . log ( "Balance required: all" ) ;
} else {
totalAmountIncludingFees = totalAmountWithoutFee _JSBigInt . add ( attemptAt _network _minimumFee ) /*.add(hostingService_chargeAmount) NOTE service fee removed for now */
console . log ( "Balance required: " + monero _utils . formatMoneySymbol ( totalAmountIncludingFees ) ) ;
}
const usableOutputsAndAmounts = _outputsAndAmountToUseForMixin (
totalAmountIncludingFees ,
unusedOuts ,
@ -337,32 +346,49 @@ function SendFunds(
var usingOuts = usableOutputsAndAmounts . usingOuts
var usingOutsAmount = usableOutputsAndAmounts . usingOutsAmount
var remaining _unusedOuts = usableOutputsAndAmounts . remaining _unusedOuts // this is a copy of the pre-mutation usingOuts
if ( isRingCT ) {
if ( usingOuts . length > 1 ) {
var newNeededFee = calculate _fee (
feePerKB _JSBigInt ,
monero _utils . estimateRctSize ( usingOuts . length , mixin , 2 ) ,
fee _multiplier _for _priority ( simple _priority )
)
if ( /*usingOuts.length > 1 &&*/ isRingCT ) {
var newNeededFee = calculate _fee (
feePerKB _JSBigInt ,
monero _utils . estimateRctSize ( usingOuts . length , mixin , 2 ) ,
fee _multiplier _for _priority ( simple _priority )
)
// if newNeededFee < neededFee, use neededFee instead (should only happen on the 2nd or later times through (due to estimated fee being too low))
if ( newNeededFee . compare ( attemptAt _network _minimumFee ) < 0 ) {
newNeededFee = attemptAt _network _minimumFee ;
}
if ( sweeping ) {
/ *
// When/if sending to multiple destinations supported, uncomment and port this:
if ( dsts . length !== 1 ) {
deferred . reject ( "Sweeping to multiple accounts is not allowed" ) ;
return ;
}
* /
totalAmountWithoutFee _JSBigInt = usingOutsAmount . subtract ( newNeededFee ) ;
if ( totalAmountWithoutFee _JSBigInt . compare ( 0 ) < 1 ) {
const errStr = ` Your spendable balance is too low. Have ${ monero _utils . formatMoney ( usingOutsAmount ) } ${ monero _config . coinSymbol } spendable, need ${ monero _utils . formatMoney ( newNeededFee ) } ${ monero _config . coinSymbol } . `
_ _trampolineFor _err _withStr ( errStr )
return
}
totalAmountIncludingFees = totalAmountWithoutFee _JSBigInt . add ( newNeededFee )
} else {
totalAmountIncludingFees = totalAmountWithoutFee _JSBigInt . add ( newNeededFee ) ;
// add outputs 1 at a time till we either have them all or can meet the fee
while ( usingOutsAmount . compare ( totalAmountIncludingFees ) < 0 && remaining _unusedOuts . length > 0 ) {
const out = _popAndReturnRandomElementFromList ( remaining _unusedOuts )
usingOuts . push ( out )
usingOutsAmount = usingOutsAmount . add ( out . amount )
console . log ( "Using output: " + monero _utils . formatMoney ( out . amount ) + " - " + JSON . stringify ( out ) )
//
console . log ( "Using output: " + monero _utils . formatMoney ( out . amount ) + " - " + JSON . stringify ( out ) ) ;
// and recalculate invalidated values
newNeededFee = calculate _fee (
feePerKB _JSBigInt ,
monero _utils . estimateRctSize ( usingOuts . length , mixin , 2 ) ,
fee _multiplier _for _priority ( simple _priority )
)
totalAmountIncludingFees = totalAmountWithoutFee _JSBigInt . add ( newNeededFee )
totalAmountIncludingFees = totalAmountWithoutFee _JSBigInt . add ( newNeededFee ) ;
}
console . log ( "New fee: " + monero _utils . formatMoneySymbol ( newNeededFee ) + " for " + usingOuts . length + " inputs" )
attemptAt _network _minimumFee = newNeededFee
}
console . log ( "New fee: " + monero _utils . formatMoneySymbol ( newNeededFee ) + " for " + usingOuts . length + " inputs" )
attemptAt _network _minimumFee = newNeededFee
}
console . log ( "~ Balance required: " + monero _utils . formatMoneySymbol ( totalAmountIncludingFees ) )
// Now we can validate available balance with usingOutsAmount (TODO? maybe this check can be done before selecting outputs?)
@ -387,6 +413,9 @@ function SendFunds(
// })
// III. some amount of the total outputs will likely need to be returned to the user as "change":
if ( usingOutsAmount _comparedTo _totalAmount > 0 ) {
if ( sweeping ) {
throw "Unexpected usingOutsAmount_comparedTo_totalAmount > 0 && sweeping"
}
var changeAmount = usingOutsAmount . subtract ( totalAmountIncludingFees )
console . log ( "changeAmount" , changeAmount )
if ( isRingCT ) { // for RCT we don't presently care about dustiness so add entire change amount
@ -413,7 +442,8 @@ function SendFunds(
} )
}
}
} else if ( usingOutsAmount _comparedTo _totalAmount == 0 ) {
} else if ( usingOutsAmount _comparedTo _totalAmount == 0 ) {
// this should always fire when sweeping
if ( isRingCT ) { // then create random destination to keep 2 outputs always in case of 0 change
var fakeAddress = monero _utils . create _address ( monero _utils . random _scalar ( ) , nettype ) . public _addr
console . log ( "Sending 0 XMR to a fake address to keep tx uniform (no change exists): " + fakeAddress )
@ -549,7 +579,9 @@ function SendFunds(
const tx _fee = final _networkFee /*.add(hostingService_chargeAmount) NOTE: Service charge removed to reduce bloat for now */
_ _trampolineFor _success (
moneroReady _targetDescription _address ,
amount ,
sweeping
? parseFloat ( monero _utils . formatMoneyFull ( totalAmountWithoutFee _JSBigInt ) )
: amount ,
final _ _payment _id ,
tx _hash ,
tx _fee