Skip to content

Commit

Permalink
[MOVE-ONLY] Move fundrawtransaction to rpcwallet
Browse files Browse the repository at this point in the history
  • Loading branch information
random-zebra committed Jun 9, 2021
1 parent 499d62a commit 7e30e3f
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 149 deletions.
149 changes: 0 additions & 149 deletions src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,154 +484,6 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
vErrorsRet.push_back(entry);
}

UniValue fundrawtransaction(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);

if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;

if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
"fundrawtransaction \"hexstring\" ( options )\n"
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
"This will not modify existing inputs, and will add one change output to the outputs.\n"
"Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
"The inputs added will not be signed, use signrawtransaction for that.\n"
"Note that all existing inputs must have their previous output transaction be in the wallet.\n"
"Note that all inputs selected must be of standard form and P2SH scripts must be "
"in the wallet using importaddress or addmultisigaddress (to calculate fees).\n"
"You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n"
"Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n"

"\nArguments:\n"
"1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
"2. options (object, optional)\n"
" {\n"
" \"changeAddress\" (string, optional, default pool address) The PIVX address to receive the change\n"
" \"changePosition\" (numeric, optional, default random) The index of the change output\n"
" \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n"
" \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n"
" \"feeRate\" (numeric, optional, default 0=estimate) Set a specific feerate (PIV per KB)\n"
" \"subtractFeeFromOutputs\" (array, optional) A json array of integers.\n"
" The fee will be equally deducted from the amount of each specified output.\n"
" The outputs are specified by their zero-based index, before any change output is added.\n"
" Those recipients will receive less PIV than you enter in their corresponding amount field.\n"
" If no outputs are specified here, the sender pays the fee.\n"
" [vout_index,...]\n"
" }\n"
"\nResult:\n"
"{\n"
" \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
" \"fee\": n, (numeric) The fee added to the transaction\n"
" \"changepos\": n (numeric) The position of the added change output, or -1\n"
"}\n"
"\"hex\" \n"
"\nExamples:\n"
"\nCreate a transaction with no inputs\n"
+ HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
"\nAdd sufficient unsigned inputs to meet the output value\n"
+ HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
"\nSign the transaction\n"
+ HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
"\nSend the transaction\n"
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
);

// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();

RPCTypeCheck(request.params, {UniValue::VSTR});

CTxDestination changeAddress = CNoDestination();
int changePosition = -1;
bool includeWatching = false;
bool lockUnspents = false;
UniValue subtractFeeFromOutputs;
std::set<int> setSubtractFeeFromOutputs;
CFeeRate feeRate = CFeeRate(0);
bool overrideEstimatedFeerate = false;

if (request.params.size() > 1) {
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
UniValue options = request.params[1];
RPCTypeCheckObj(options,
{
{"changeAddress", UniValueType(UniValue::VSTR)},
{"changePosition", UniValueType(UniValue::VNUM)},
{"includeWatching", UniValueType(UniValue::VBOOL)},
{"lockUnspents", UniValueType(UniValue::VBOOL)},
{"feeRate", UniValueType()}, // will be checked below
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
},
true, true);

if (options.exists("changeAddress")) {
changeAddress = DecodeDestination(options["changeAddress"].get_str());

if (!IsValidDestination(changeAddress))
throw JSONRPCError(RPC_INVALID_PARAMETER, "changeAddress must be a valid PIVX address");
}

if (options.exists("changePosition"))
changePosition = options["changePosition"].get_int();

if (options.exists("includeWatching"))
includeWatching = options["includeWatching"].get_bool();

if (options.exists("lockUnspents"))
lockUnspents = options["lockUnspents"].get_bool();

if (options.exists("feeRate")) {
feeRate = CFeeRate(AmountFromValue(options["feeRate"]));
overrideEstimatedFeerate = true;
}

if (options.exists("subtractFeeFromOutputs")) {
subtractFeeFromOutputs = options["subtractFeeFromOutputs"].get_array();
}
}

// parse hex string from parameter
CMutableTransaction origTx;
if (!DecodeHexTx(origTx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");

if (origTx.vout.size() == 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");

if (changePosition != -1 && (changePosition < 0 || (unsigned int) changePosition > origTx.vout.size()))
throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");

for (unsigned int idx = 0; idx < subtractFeeFromOutputs.size(); idx++) {
int pos = subtractFeeFromOutputs[idx].get_int();
if (setSubtractFeeFromOutputs.count(pos))
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, duplicated position: %d", pos));
if (pos < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, negative position: %d", pos));
if (pos >= int(origTx.vout.size()))
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, position too large: %d", pos));
setSubtractFeeFromOutputs.insert(pos);
}

CMutableTransaction tx(origTx);
CAmount nFeeOut;
std::string strFailReason;
if(!pwallet->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate,
changePosition, strFailReason, includeWatching,
lockUnspents, setSubtractFeeFromOutputs, changeAddress)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
}

UniValue result(UniValue::VOBJ);
result.pushKV("hex", EncodeHexTx(tx));
result.pushKV("changepos", changePosition);
result.pushKV("fee", ValueFromAmount(nFeeOut));

return result;
}

UniValue signrawtransaction(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
Expand Down Expand Up @@ -1027,7 +879,6 @@ static const CRPCCommand commands[] =
{ "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"inputs","outputs","locktime"} },
{ "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} },
{ "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} },
{ "rawtransactions", "fundrawtransaction", &fundrawtransaction, false, {"hexstring","options"} },
{ "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose","blockhash"} },
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} },
{ "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
Expand Down
149 changes: 149 additions & 0 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3800,6 +3800,154 @@ UniValue listunspent(const JSONRPCRequest& request)
return results;
}

UniValue fundrawtransaction(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);

if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;

if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
"fundrawtransaction \"hexstring\" ( options )\n"
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
"This will not modify existing inputs, and will add one change output to the outputs.\n"
"Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
"The inputs added will not be signed, use signrawtransaction for that.\n"
"Note that all existing inputs must have their previous output transaction be in the wallet.\n"
"Note that all inputs selected must be of standard form and P2SH scripts must be "
"in the wallet using importaddress or addmultisigaddress (to calculate fees).\n"
"You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n"
"Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n"

"\nArguments:\n"
"1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
"2. options (object, optional)\n"
" {\n"
" \"changeAddress\" (string, optional, default pool address) The PIVX address to receive the change\n"
" \"changePosition\" (numeric, optional, default random) The index of the change output\n"
" \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n"
" \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n"
" \"feeRate\" (numeric, optional, default 0=estimate) Set a specific feerate (PIV per KB)\n"
" \"subtractFeeFromOutputs\" (array, optional) A json array of integers.\n"
" The fee will be equally deducted from the amount of each specified output.\n"
" The outputs are specified by their zero-based index, before any change output is added.\n"
" Those recipients will receive less PIV than you enter in their corresponding amount field.\n"
" If no outputs are specified here, the sender pays the fee.\n"
" [vout_index,...]\n"
" }\n"
"\nResult:\n"
"{\n"
" \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
" \"fee\": n, (numeric) The fee added to the transaction\n"
" \"changepos\": n (numeric) The position of the added change output, or -1\n"
"}\n"
"\"hex\" \n"
"\nExamples:\n"
"\nCreate a transaction with no inputs\n"
+ HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
"\nAdd sufficient unsigned inputs to meet the output value\n"
+ HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
"\nSign the transaction\n"
+ HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
"\nSend the transaction\n"
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
);

// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();

RPCTypeCheck(request.params, {UniValue::VSTR});

CTxDestination changeAddress = CNoDestination();
int changePosition = -1;
bool includeWatching = false;
bool lockUnspents = false;
UniValue subtractFeeFromOutputs;
std::set<int> setSubtractFeeFromOutputs;
CFeeRate feeRate = CFeeRate(0);
bool overrideEstimatedFeerate = false;

if (request.params.size() > 1) {
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
UniValue options = request.params[1];
RPCTypeCheckObj(options,
{
{"changeAddress", UniValueType(UniValue::VSTR)},
{"changePosition", UniValueType(UniValue::VNUM)},
{"includeWatching", UniValueType(UniValue::VBOOL)},
{"lockUnspents", UniValueType(UniValue::VBOOL)},
{"feeRate", UniValueType()}, // will be checked below
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
},
true, true);

if (options.exists("changeAddress")) {
changeAddress = DecodeDestination(options["changeAddress"].get_str());

if (!IsValidDestination(changeAddress))
throw JSONRPCError(RPC_INVALID_PARAMETER, "changeAddress must be a valid PIVX address");
}

if (options.exists("changePosition"))
changePosition = options["changePosition"].get_int();

if (options.exists("includeWatching"))
includeWatching = options["includeWatching"].get_bool();

if (options.exists("lockUnspents"))
lockUnspents = options["lockUnspents"].get_bool();

if (options.exists("feeRate")) {
feeRate = CFeeRate(AmountFromValue(options["feeRate"]));
overrideEstimatedFeerate = true;
}

if (options.exists("subtractFeeFromOutputs")) {
subtractFeeFromOutputs = options["subtractFeeFromOutputs"].get_array();
}
}

// parse hex string from parameter
CMutableTransaction origTx;
if (!DecodeHexTx(origTx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");

if (origTx.vout.size() == 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");

if (changePosition != -1 && (changePosition < 0 || (unsigned int) changePosition > origTx.vout.size()))
throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");

for (unsigned int idx = 0; idx < subtractFeeFromOutputs.size(); idx++) {
int pos = subtractFeeFromOutputs[idx].get_int();
if (setSubtractFeeFromOutputs.count(pos))
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, duplicated position: %d", pos));
if (pos < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, negative position: %d", pos));
if (pos >= int(origTx.vout.size()))
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, position too large: %d", pos));
setSubtractFeeFromOutputs.insert(pos);
}

CMutableTransaction tx(origTx);
CAmount nFeeOut;
std::string strFailReason;
if(!pwallet->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate,
changePosition, strFailReason, includeWatching,
lockUnspents, setSubtractFeeFromOutputs, changeAddress)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
}

UniValue result(UniValue::VOBJ);
result.pushKV("hex", EncodeHexTx(tx));
result.pushKV("changepos", changePosition);
result.pushKV("fee", ValueFromAmount(nFeeOut));

return result;
}

UniValue lockunspent(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
Expand Down Expand Up @@ -4531,6 +4679,7 @@ static const CRPCCommand commands[] =
{ "wallet", "dumpprivkey", &dumpprivkey, true, {"address"} },
{ "wallet", "dumpwallet", &dumpwallet, true, {"filename"} },
{ "wallet", "encryptwallet", &encryptwallet, true, {"passphrase"} },
{ "wallet", "fundrawtransaction", &fundrawtransaction, false, {"hexstring","options"} },
{ "wallet", "getbalance", &getbalance, false, {"minconf","include_watchonly","include_delegated","include_shield"} },
{ "wallet", "getcoldstakingbalance", &getcoldstakingbalance, false, {} },
{ "wallet", "getdelegatedbalance", &getdelegatedbalance, false, {} },
Expand Down

0 comments on commit 7e30e3f

Please sign in to comment.