Subtract fee from amount
Fixes #2724 and #1570. Adds the automatically-subtract-the-fee-from-the-amount-and-send-whats-left feature to the GUI and RPC (sendtoaddress,sendmany).
This commit is contained in:
committed by
Wladimir J. van der Laan
parent
90a43c1e93
commit
292623adf5
@@ -317,7 +317,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void SendMoney(const CTxDestination &address, CAmount nValue, CWalletTx& wtxNew)
|
||||
static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
|
||||
{
|
||||
CAmount curBalance = pwalletMain->GetBalance();
|
||||
|
||||
@@ -335,11 +335,14 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, CWalletTx&
|
||||
CReserveKey reservekey(pwalletMain);
|
||||
CAmount nFeeRequired;
|
||||
std::string strError;
|
||||
if (!pwalletMain->CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError)) {
|
||||
if (nValue + nFeeRequired > curBalance)
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired)));
|
||||
else
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strError);
|
||||
vector<CRecipient> vecSend;
|
||||
int nChangePosRet = -1;
|
||||
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
|
||||
vecSend.push_back(recipient);
|
||||
if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
|
||||
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
|
||||
strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, strError);
|
||||
}
|
||||
if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
|
||||
@@ -347,9 +350,9 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, CWalletTx&
|
||||
|
||||
Value sendtoaddress(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() < 2 || params.size() > 4)
|
||||
if (fHelp || params.size() < 2 || params.size() > 5)
|
||||
throw runtime_error(
|
||||
"sendtoaddress \"bitcoinaddress\" amount ( \"comment\" \"comment-to\" )\n"
|
||||
"sendtoaddress \"bitcoinaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
|
||||
"\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
|
||||
+ HelpRequiringPassphrase() +
|
||||
"\nArguments:\n"
|
||||
@@ -360,11 +363,14 @@ Value sendtoaddress(const Array& params, bool fHelp)
|
||||
"4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
|
||||
" to which you're sending the transaction. This is not part of the \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"
|
||||
" The recipient will receive less bitcoins than you enter in the amount field.\n"
|
||||
"\nResult:\n"
|
||||
"\"transactionid\" (string) The transaction id.\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
|
||||
+ HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
|
||||
+ HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
|
||||
+ HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
|
||||
);
|
||||
|
||||
@@ -384,9 +390,13 @@ Value sendtoaddress(const Array& params, bool fHelp)
|
||||
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
|
||||
wtx.mapValue["to"] = params[3].get_str();
|
||||
|
||||
bool fSubtractFeeFromAmount = false;
|
||||
if (params.size() > 4)
|
||||
fSubtractFeeFromAmount = params[4].get_bool();
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
|
||||
SendMoney(address.Get(), nAmount, wtx);
|
||||
SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
|
||||
|
||||
return wtx.GetHash().GetHex();
|
||||
}
|
||||
@@ -840,7 +850,7 @@ Value sendfrom(const Array& params, bool fHelp)
|
||||
if (nAmount > nBalance)
|
||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
|
||||
|
||||
SendMoney(address.Get(), nAmount, wtx);
|
||||
SendMoney(address.Get(), nAmount, false, wtx);
|
||||
|
||||
return wtx.GetHash().GetHex();
|
||||
}
|
||||
@@ -848,9 +858,9 @@ Value sendfrom(const Array& params, bool fHelp)
|
||||
|
||||
Value sendmany(const Array& params, bool fHelp)
|
||||
{
|
||||
if (fHelp || params.size() < 2 || params.size() > 4)
|
||||
if (fHelp || params.size() < 2 || params.size() > 5)
|
||||
throw runtime_error(
|
||||
"sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" )\n"
|
||||
"sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" {\"address\":true,...} )\n"
|
||||
"\nSend multiple times. Amounts are double-precision floating point numbers."
|
||||
+ HelpRequiringPassphrase() + "\n"
|
||||
"\nArguments:\n"
|
||||
@@ -862,6 +872,14 @@ Value sendmany(const Array& params, bool fHelp)
|
||||
" }\n"
|
||||
"3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
|
||||
"4. \"comment\" (string, optional) A comment\n"
|
||||
"5. subtractfeefromamount (string, optional) A json object with addresses and booleans.\n"
|
||||
" The fee will be equally deducted from the amount of each selected address.\n"
|
||||
" Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
|
||||
" Default for each address is false. If no addresses are specified here, the sender pays the fee.\n"
|
||||
" {\n"
|
||||
" \"address\":true (boolean) Subtract fee from this address\n"
|
||||
" ,...\n"
|
||||
" }\n"
|
||||
"\nResult:\n"
|
||||
"\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
|
||||
" the number of addresses.\n"
|
||||
@@ -870,6 +888,8 @@ Value sendmany(const Array& params, bool fHelp)
|
||||
+ HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
|
||||
"\nSend two amounts to two different addresses setting the confirmation and comment:\n"
|
||||
+ HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
|
||||
"\nSend two amounts to two different addresses, subtract fee from amount:\n"
|
||||
+ HelpExampleCli("sendmany", "\"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":true,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":true}\"") +
|
||||
"\nAs a json rpc call\n"
|
||||
+ HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
|
||||
);
|
||||
@@ -887,8 +907,12 @@ Value sendmany(const Array& params, bool fHelp)
|
||||
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
|
||||
wtx.mapValue["comment"] = params[3].get_str();
|
||||
|
||||
Object subtractFeeFromAmount;
|
||||
if (params.size() > 4)
|
||||
subtractFeeFromAmount = params[4].get_obj();
|
||||
|
||||
set<CBitcoinAddress> setAddress;
|
||||
vector<pair<CScript, CAmount> > vecSend;
|
||||
vector<CRecipient> vecSend;
|
||||
|
||||
CAmount totalAmount = 0;
|
||||
BOOST_FOREACH(const Pair& s, sendTo)
|
||||
@@ -905,7 +929,13 @@ Value sendmany(const Array& params, bool fHelp)
|
||||
CAmount nAmount = AmountFromValue(s.value_);
|
||||
totalAmount += nAmount;
|
||||
|
||||
vecSend.push_back(make_pair(scriptPubKey, nAmount));
|
||||
bool fSubtractFeeFromAmount = false;
|
||||
BOOST_FOREACH(const Pair& s2, subtractFeeFromAmount)
|
||||
if (s2.name_ == s.name_ && s2.value_.get_bool() == true)
|
||||
fSubtractFeeFromAmount = true;
|
||||
|
||||
CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
|
||||
vecSend.push_back(recipient);
|
||||
}
|
||||
|
||||
EnsureWalletIsUnlocked();
|
||||
@@ -918,8 +948,9 @@ Value sendmany(const Array& params, bool fHelp)
|
||||
// Send
|
||||
CReserveKey keyChange(pwalletMain);
|
||||
CAmount nFeeRequired = 0;
|
||||
int nChangePosRet = -1;
|
||||
string strFailReason;
|
||||
bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason);
|
||||
bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
|
||||
if (!fCreated)
|
||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
|
||||
if (!pwalletMain->CommitTransaction(wtx, keyChange))
|
||||
|
||||
Reference in New Issue
Block a user