@ -356,7 +356,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
return ret ;
return ret ;
}
}
static void SendMoney ( CWallet * const pwallet , const CTxDestination & address , CAmount nValue , bool fSubtractFeeFromAmount , CWalletTx & wtxNew )
static void SendMoney ( CWallet * const pwallet , const CTxDestination & address , CAmount nValue , bool fSubtractFeeFromAmount , CWalletTx & wtxNew , CCoinControl * coin_control = nullptr )
{
{
CAmount curBalance = pwallet - > GetBalance ( ) ;
CAmount curBalance = pwallet - > GetBalance ( ) ;
@ -382,7 +382,7 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA
int nChangePosRet = - 1 ;
int nChangePosRet = - 1 ;
CRecipient recipient = { scriptPubKey , nValue , fSubtractFeeFromAmount } ;
CRecipient recipient = { scriptPubKey , nValue , fSubtractFeeFromAmount } ;
vecSend . push_back ( recipient ) ;
vecSend . push_back ( recipient ) ;
if ( ! pwallet - > CreateTransaction ( vecSend , wtxNew , reservekey , nFeeRequired , nChangePosRet , strError ) ) {
if ( ! pwallet - > CreateTransaction ( vecSend , wtxNew , reservekey , nFeeRequired , nChangePosRet , strError , coin_control ) ) {
if ( ! fSubtractFeeFromAmount & & nValue + nFeeRequired > curBalance )
if ( ! fSubtractFeeFromAmount & & nValue + nFeeRequired > curBalance )
strError = strprintf ( " Error: This transaction requires a transaction fee of at least %s " , FormatMoney ( nFeeRequired ) ) ;
strError = strprintf ( " Error: This transaction requires a transaction fee of at least %s " , FormatMoney ( nFeeRequired ) ) ;
throw JSONRPCError ( RPC_WALLET_ERROR , strError ) ;
throw JSONRPCError ( RPC_WALLET_ERROR , strError ) ;
@ -401,9 +401,9 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
return NullUniValue ;
return NullUniValue ;
}
}
if ( request . fHelp | | request . params . size ( ) < 2 | | request . params . size ( ) > 5 )
if ( request . fHelp | | request . params . size ( ) < 2 | | request . params . size ( ) > 8 )
throw std : : runtime_error (
throw std : : runtime_error (
" sendtoaddress \" address \" amount ( \" comment \" \" comment_to \" subtractfeefromamount ) \n "
" sendtoaddress \" address \" amount ( \" comment \" \" comment_to \" subtractfeefromamount replaceable conf_target \" estimate_mode \" ) \n "
" \n Send an amount to a given address. \n "
" \n Send an amount to a given address. \n "
+ HelpRequiringPassphrase ( pwallet ) +
+ HelpRequiringPassphrase ( pwallet ) +
" \n Arguments: \n "
" \n Arguments: \n "
@ -416,6 +416,12 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
" transaction, just kept in your wallet. \n "
" transaction, just kept in your wallet. \n "
" 5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent. \n "
" 5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent. \n "
" The recipient will receive less bitcoins than you enter in the amount field. \n "
" The recipient will receive less bitcoins than you enter in the amount field. \n "
" 6. replaceable (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees via BIP 125 \n "
" 7. conf_target (numeric, optional) Confirmation target (in blocks) \n "
" 8. \" estimate_mode \" (string, optional, default=UNSET) The fee estimate mode, must be one of: \n "
" \" UNSET \" \n "
" \" ECONOMICAL \" \n "
" \" CONSERVATIVE \" \n "
" \n Result: \n "
" \n Result: \n "
" \" txid \" (string) The transaction id. \n "
" \" txid \" (string) The transaction id. \n "
" \n Examples: \n "
" \n Examples: \n "
@ -444,12 +450,29 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
wtx . mapValue [ " to " ] = request . params [ 3 ] . get_str ( ) ;
wtx . mapValue [ " to " ] = request . params [ 3 ] . get_str ( ) ;
bool fSubtractFeeFromAmount = false ;
bool fSubtractFeeFromAmount = false ;
if ( request . params . size ( ) > 4 )
if ( request . params . size ( ) > 4 & & ! request . params [ 4 ] . isNull ( ) ) {
fSubtractFeeFromAmount = request . params [ 4 ] . get_bool ( ) ;
fSubtractFeeFromAmount = request . params [ 4 ] . get_bool ( ) ;
}
CCoinControl coin_control ;
if ( request . params . size ( ) > 5 & & ! request . params [ 5 ] . isNull ( ) ) {
coin_control . signalRbf = request . params [ 5 ] . get_bool ( ) ;
}
if ( request . params . size ( ) > 6 & & ! request . params [ 6 ] . isNull ( ) ) {
coin_control . nConfirmTarget = request . params [ 6 ] . get_int ( ) ;
}
if ( request . params . size ( ) > 7 & & ! request . params [ 7 ] . isNull ( ) ) {
if ( ! FeeModeFromString ( request . params [ 7 ] . get_str ( ) , coin_control . m_fee_mode ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid estimate_mode parameter " ) ;
}
}
EnsureWalletIsUnlocked ( pwallet ) ;
EnsureWalletIsUnlocked ( pwallet ) ;
SendMoney ( pwallet , address . Get ( ) , nAmount , fSubtractFeeFromAmount , wtx ) ;
SendMoney ( pwallet , address . Get ( ) , nAmount , fSubtractFeeFromAmount , wtx , & coin_control ) ;
return wtx . GetHash ( ) . GetHex ( ) ;
return wtx . GetHash ( ) . GetHex ( ) ;
}
}
@ -888,9 +911,9 @@ UniValue sendmany(const JSONRPCRequest& request)
return NullUniValue ;
return NullUniValue ;
}
}
if ( request . fHelp | | request . params . size ( ) < 2 | | request . params . size ( ) > 5 )
if ( request . fHelp | | request . params . size ( ) < 2 | | request . params . size ( ) > 8 )
throw std : : runtime_error (
throw std : : runtime_error (
" sendmany \" fromaccount \" { \" address \" :amount,...} ( minconf \" comment \" [ \" address \" ,...] ) \n "
" sendmany \" fromaccount \" { \" address \" :amount,...} ( minconf \" comment \" [ \" address \" ,...] replaceable conf_target \" estimate_mode \" ) \n "
" \n Send multiple times. Amounts are double-precision floating point numbers. "
" \n Send multiple times. Amounts are double-precision floating point numbers. "
+ HelpRequiringPassphrase ( pwallet ) + " \n "
+ HelpRequiringPassphrase ( pwallet ) + " \n "
" \n Arguments: \n "
" \n Arguments: \n "
@ -910,7 +933,13 @@ UniValue sendmany(const JSONRPCRequest& request)
" \" address \" (string) Subtract fee from this address \n "
" \" address \" (string) Subtract fee from this address \n "
" ,... \n "
" ,... \n "
" ] \n "
" ] \n "
" \n Result: \n "
" 6. replaceable (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees via BIP 125 \n "
" 7. conf_target (numeric, optional) Confirmation target (in blocks) \n "
" 8. \" estimate_mode \" (string, optional, default=UNSET) The fee estimate mode, must be one of: \n "
" \" UNSET \" \n "
" \" ECONOMICAL \" \n "
" \" CONSERVATIVE \" \n "
" \n Result: \n "
" \" txid \" (string) The transaction id for the send. Only 1 transaction is created regardless of \n "
" \" txid \" (string) The transaction id for the send. Only 1 transaction is created regardless of \n "
" the number of addresses. \n "
" the number of addresses. \n "
" \n Examples: \n "
" \n Examples: \n "
@ -942,9 +971,24 @@ UniValue sendmany(const JSONRPCRequest& request)
wtx . mapValue [ " comment " ] = request . params [ 3 ] . get_str ( ) ;
wtx . mapValue [ " comment " ] = request . params [ 3 ] . get_str ( ) ;
UniValue subtractFeeFromAmount ( UniValue : : VARR ) ;
UniValue subtractFeeFromAmount ( UniValue : : VARR ) ;
if ( request . params . size ( ) > 4 )
if ( request . params . size ( ) > 4 & & ! request . params [ 4 ] . isNull ( ) )
subtractFeeFromAmount = request . params [ 4 ] . get_array ( ) ;
subtractFeeFromAmount = request . params [ 4 ] . get_array ( ) ;
CCoinControl coin_control ;
if ( request . params . size ( ) > 5 & & ! request . params [ 5 ] . isNull ( ) ) {
coin_control . signalRbf = request . params [ 5 ] . get_bool ( ) ;
}
if ( request . params . size ( ) > 6 & & ! request . params [ 6 ] . isNull ( ) ) {
coin_control . nConfirmTarget = request . params [ 6 ] . get_int ( ) ;
}
if ( request . params . size ( ) > 7 & & ! request . params [ 7 ] . isNull ( ) ) {
if ( ! FeeModeFromString ( request . params [ 7 ] . get_str ( ) , coin_control . m_fee_mode ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid estimate_mode parameter " ) ;
}
}
std : : set < CBitcoinAddress > setAddress ;
std : : set < CBitcoinAddress > setAddress ;
std : : vector < CRecipient > vecSend ;
std : : vector < CRecipient > vecSend ;
@ -989,7 +1033,7 @@ UniValue sendmany(const JSONRPCRequest& request)
CAmount nFeeRequired = 0 ;
CAmount nFeeRequired = 0 ;
int nChangePosRet = - 1 ;
int nChangePosRet = - 1 ;
std : : string strFailReason ;
std : : string strFailReason ;
bool fCreated = pwallet - > CreateTransaction ( vecSend , wtx , keyChange , nFeeRequired , nChangePosRet , strFailReason ) ;
bool fCreated = pwallet - > CreateTransaction ( vecSend , wtx , keyChange , nFeeRequired , nChangePosRet , strFailReason , & coin_control ) ;
if ( ! fCreated )
if ( ! fCreated )
throw JSONRPCError ( RPC_WALLET_INSUFFICIENT_FUNDS , strFailReason ) ;
throw JSONRPCError ( RPC_WALLET_INSUFFICIENT_FUNDS , strFailReason ) ;
CValidationState state ;
CValidationState state ;
@ -2658,6 +2702,11 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
" [vout_index,...] \n "
" [vout_index,...] \n "
" \" replaceable \" (boolean, optional) Marks this transaction as BIP125 replaceable. \n "
" \" replaceable \" (boolean, optional) Marks this transaction as BIP125 replaceable. \n "
" Allows this transaction to be replaced by a transaction with higher fees \n "
" Allows this transaction to be replaced by a transaction with higher fees \n "
" \" conf_target \" (numeric, optional) Confirmation target (in blocks) \n "
" \" estimate_mode \" (string, optional, default=UNSET) The fee estimate mode, must be one of: \n "
" \" UNSET \" \n "
" \" ECONOMICAL \" \n "
" \" CONSERVATIVE \" \n "
" } \n "
" } \n "
" for backward compatibility: passing in a true instead of an object will result in { \" includeWatching \" :true} \n "
" for backward compatibility: passing in a true instead of an object will result in { \" includeWatching \" :true} \n "
" \n Result: \n "
" \n Result: \n "
@ -2710,6 +2759,8 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
{ " feeRate " , UniValueType ( ) } , // will be checked below
{ " feeRate " , UniValueType ( ) } , // will be checked below
{ " subtractFeeFromOutputs " , UniValueType ( UniValue : : VARR ) } ,
{ " subtractFeeFromOutputs " , UniValueType ( UniValue : : VARR ) } ,
{ " replaceable " , UniValueType ( UniValue : : VBOOL ) } ,
{ " replaceable " , UniValueType ( UniValue : : VBOOL ) } ,
{ " conf_target " , UniValueType ( UniValue : : VNUM ) } ,
{ " estimate_mode " , UniValueType ( UniValue : : VSTR ) } ,
} ,
} ,
true , true ) ;
true , true ) ;
@ -2746,6 +2797,14 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
if ( options . exists ( " replaceable " ) ) {
if ( options . exists ( " replaceable " ) ) {
coinControl . signalRbf = options [ " replaceable " ] . get_bool ( ) ;
coinControl . signalRbf = options [ " replaceable " ] . get_bool ( ) ;
}
}
if ( options . exists ( " conf_target " ) ) {
coinControl . nConfirmTarget = options [ " conf_target " ] . get_int ( ) ;
}
if ( options . exists ( " estimate_mode " ) ) {
if ( ! FeeModeFromString ( options [ " estimate_mode " ] . get_str ( ) , coinControl . m_fee_mode ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid estimate_mode parameter " ) ;
}
}
}
}
}
}
@ -2823,6 +2882,10 @@ UniValue bumpfee(const JSONRPCRequest& request)
" so the new transaction will not be explicitly bip-125 replaceable (though it may \n "
" so the new transaction will not be explicitly bip-125 replaceable (though it may \n "
" still be replaceable in practice, for example if it has unconfirmed ancestors which \n "
" still be replaceable in practice, for example if it has unconfirmed ancestors which \n "
" are replaceable). \n "
" are replaceable). \n "
" \" estimate_mode \" (string, optional, default=UNSET) The fee estimate mode, must be one of: \n "
" \" UNSET \" \n "
" \" ECONOMICAL \" \n "
" \" CONSERVATIVE \" \n "
" } \n "
" } \n "
" \n Result: \n "
" \n Result: \n "
" { \n "
" { \n "
@ -2845,6 +2908,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
int newConfirmTarget = nTxConfirmTarget ;
int newConfirmTarget = nTxConfirmTarget ;
CAmount totalFee = 0 ;
CAmount totalFee = 0 ;
bool replaceable = true ;
bool replaceable = true ;
FeeEstimateMode fee_mode = FeeEstimateMode : : UNSET ;
if ( request . params . size ( ) > 1 ) {
if ( request . params . size ( ) > 1 ) {
UniValue options = request . params [ 1 ] ;
UniValue options = request . params [ 1 ] ;
RPCTypeCheckObj ( options ,
RPCTypeCheckObj ( options ,
@ -2852,6 +2916,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
{ " confTarget " , UniValueType ( UniValue : : VNUM ) } ,
{ " confTarget " , UniValueType ( UniValue : : VNUM ) } ,
{ " totalFee " , UniValueType ( UniValue : : VNUM ) } ,
{ " totalFee " , UniValueType ( UniValue : : VNUM ) } ,
{ " replaceable " , UniValueType ( UniValue : : VBOOL ) } ,
{ " replaceable " , UniValueType ( UniValue : : VBOOL ) } ,
{ " estimate_mode " , UniValueType ( UniValue : : VSTR ) } ,
} ,
} ,
true , true ) ;
true , true ) ;
@ -2876,12 +2941,17 @@ UniValue bumpfee(const JSONRPCRequest& request)
if ( options . exists ( " replaceable " ) ) {
if ( options . exists ( " replaceable " ) ) {
replaceable = options [ " replaceable " ] . get_bool ( ) ;
replaceable = options [ " replaceable " ] . get_bool ( ) ;
}
}
if ( options . exists ( " estimate_mode " ) ) {
if ( ! FeeModeFromString ( options [ " estimate_mode " ] . get_str ( ) , fee_mode ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid estimate_mode parameter " ) ;
}
}
}
}
LOCK2 ( cs_main , pwallet - > cs_wallet ) ;
LOCK2 ( cs_main , pwallet - > cs_wallet ) ;
EnsureWalletIsUnlocked ( pwallet ) ;
EnsureWalletIsUnlocked ( pwallet ) ;
CFeeBumper feeBump ( pwallet , hash , newConfirmTarget , ignoreGlobalPayTxFee , totalFee , replaceable ) ;
CFeeBumper feeBump ( pwallet , hash , newConfirmTarget , ignoreGlobalPayTxFee , totalFee , replaceable , fee_mode ) ;
BumpFeeResult res = feeBump . getResult ( ) ;
BumpFeeResult res = feeBump . getResult ( ) ;
if ( res ! = BumpFeeResult : : OK )
if ( res ! = BumpFeeResult : : OK )
{
{
@ -3023,8 +3093,8 @@ static const CRPCCommand commands[] =
{ " wallet " , " lockunspent " , & lockunspent , true , { " unlock " , " transactions " } } ,
{ " wallet " , " lockunspent " , & lockunspent , true , { " unlock " , " transactions " } } ,
{ " wallet " , " move " , & movecmd , false , { " fromaccount " , " toaccount " , " amount " , " minconf " , " comment " } } ,
{ " wallet " , " move " , & movecmd , false , { " fromaccount " , " toaccount " , " amount " , " minconf " , " comment " } } ,
{ " wallet " , " sendfrom " , & sendfrom , false , { " fromaccount " , " toaddress " , " amount " , " minconf " , " comment " , " comment_to " } } ,
{ " wallet " , " sendfrom " , & sendfrom , false , { " fromaccount " , " toaddress " , " amount " , " minconf " , " comment " , " comment_to " } } ,
{ " wallet " , " sendmany " , & sendmany , false , { " fromaccount " , " amounts " , " minconf " , " comment " , " subtractfeefrom " } } ,
{ " wallet " , " sendmany " , & sendmany , false , { " fromaccount " , " amounts " , " minconf " , " comment " , " subtractfeefrom " , " replaceable " , " conf_target " , " estimate_mode " } } ,
{ " wallet " , " sendtoaddress " , & sendtoaddress , false , { " address " , " amount " , " comment " , " comment_to " , " subtractfeefromamount " } } ,
{ " wallet " , " sendtoaddress " , & sendtoaddress , false , { " address " , " amount " , " comment " , " comment_to " , " subtractfeefromamount " , " replaceable " , " conf_target " , " estimate_mode " } } ,
{ " wallet " , " setaccount " , & setaccount , true , { " address " , " account " } } ,
{ " wallet " , " setaccount " , & setaccount , true , { " address " , " account " } } ,
{ " wallet " , " settxfee " , & settxfee , true , { " amount " } } ,
{ " wallet " , " settxfee " , & settxfee , true , { " amount " } } ,
{ " wallet " , " signmessage " , & signmessage , true , { " address " , " message " } } ,
{ " wallet " , " signmessage " , & signmessage , true , { " address " , " message " } } ,