1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2020 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <amount.h>
7 #include <core_io.h>
8 #include <interfaces/chain.h>
9 #include <key_io.h>
10 #include <node/context.h>
11 #include <outputtype.h>
12 #include <policy/feerate.h>
13 #include <policy/fees.h>
14 #include <policy/rbf.h>
15 #include <rpc/rawtransaction_util.h>
16 #include <rpc/server.h>
17 #include <rpc/util.h>
18 #include <script/descriptor.h>
19 #include <script/sign.h>
20 #include <util/bip32.h>
21 #include <util/fees.h>
22 #include <util/message.h> // For MessageSign()
23 #include <util/moneystr.h>
24 #include <util/string.h>
25 #include <util/system.h>
26 #include <util/url.h>
27 #include <util/vector.h>
28 #include <wallet/coincontrol.h>
29 #include <wallet/feebumper.h>
30 #include <wallet/rpcwallet.h>
31 #include <wallet/wallet.h>
32 #include <wallet/walletdb.h>
33 #include <wallet/walletutil.h>
34 #include <qtum/qtumdelegation.h>
35 #include <util/signstr.h>
36 #include <interfaces/wallet.h>
37 #include <rpc/contract_util.h>
38 #include <util/tokenstr.h>
39 
40 #include <stdint.h>
41 
42 #include <univalue.h>
43 
44 
45 static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
46 static const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
47 
GetAvoidReuseFlag(const CWallet * const pwallet,const UniValue & param)48 static inline bool GetAvoidReuseFlag(const CWallet* const pwallet, const UniValue& param) {
49     bool can_avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
50     bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
51 
52     if (avoid_reuse && !can_avoid_reuse) {
53         throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
54     }
55 
56     return avoid_reuse;
57 }
58 
59 
60 /** Used by RPC commands that have an include_watchonly parameter.
61  *  We default to true for watchonly wallets if include_watchonly isn't
62  *  explicitly set.
63  */
ParseIncludeWatchonly(const UniValue & include_watchonly,const CWallet & pwallet)64 static bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& pwallet)
65 {
66     if (include_watchonly.isNull()) {
67         // if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
68         return pwallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
69     }
70 
71     // otherwise return whatever include_watchonly was set to
72     return include_watchonly.get_bool();
73 }
74 
75 
76 /** Checks if a CKey is in the given CWallet compressed or otherwise*/
HaveKey(const SigningProvider & wallet,const CKey & key)77 bool HaveKey(const SigningProvider& wallet, const CKey& key)
78 {
79     CKey key2;
80     key2.Set(key.begin(), key.end(), !key.IsCompressed());
81     return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID());
82 }
83 
GetWalletNameFromJSONRPCRequest(const JSONRPCRequest & request,std::string & wallet_name)84 bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
85 {
86     if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
87         // wallet endpoint was used
88         wallet_name = urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
89         return true;
90     }
91     return false;
92 }
93 
GetWalletForJSONRPCRequest(const JSONRPCRequest & request)94 std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
95 {
96     std::string wallet_name;
97     if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
98         std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name);
99         if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
100         return pwallet;
101     }
102 
103     std::vector<std::shared_ptr<CWallet>> wallets = GetWallets();
104     return wallets.size() == 1 || (request.fHelp && wallets.size() > 0) ? wallets[0] : nullptr;
105 }
106 
GetSenderDest(CWallet * const pwallet,const CTransactionRef & tx,CTxDestination & txSenderDest)107 bool GetSenderDest(CWallet * const pwallet, const CTransactionRef& tx, CTxDestination& txSenderDest)
108 {
109     // Initialize variables
110     CScript senderPubKey;
111 
112     // Get sender destination
113     if(tx->HasOpSender())
114     {
115         // Get destination from the outputs
116         for(CTxOut out : tx->vout)
117         {
118             if(out.scriptPubKey.HasOpSender())
119             {
120                 ExtractSenderData(out.scriptPubKey, &senderPubKey, 0);
121                 break;
122             }
123         }
124     }
125     else
126     {
127         // Get destination from the inputs
128         senderPubKey = pwallet->mapWallet.at(tx->vin[0].prevout.hash).tx->vout[tx->vin[0].prevout.n].scriptPubKey;
129     }
130 
131     // Extract destination from script
132     return ExtractDestination(senderPubKey, txSenderDest);
133 }
134 
EnsureWalletIsAvailable(const CWallet * pwallet,bool avoidException)135 bool EnsureWalletIsAvailable(const CWallet* pwallet, bool avoidException)
136 {
137     if (pwallet) return true;
138     if (avoidException) return false;
139     if (!HasWallets()) {
140         throw JSONRPCError(
141             RPC_METHOD_NOT_FOUND, "Method not found (wallet method is disabled because no wallet is loaded)");
142     }
143     throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,
144         "Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
145 }
146 
EnsureWalletIsUnlocked(const CWallet * pwallet)147 void EnsureWalletIsUnlocked(const CWallet* pwallet)
148 {
149     if (pwallet->IsLocked()) {
150         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
151     }
152     if (pwallet->m_wallet_unlock_staking_only) {
153         throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Wallet is unlocked for staking only.");
154     }
155 }
156 
157 // also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank
EnsureLegacyScriptPubKeyMan(CWallet & wallet,bool also_create)158 LegacyScriptPubKeyMan& EnsureLegacyScriptPubKeyMan(CWallet& wallet, bool also_create)
159 {
160     LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
161     if (!spk_man && also_create) {
162         spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
163     }
164     if (!spk_man) {
165         throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
166     }
167     return *spk_man;
168 }
169 
WalletTxToJSON(interfaces::Chain & chain,interfaces::Chain::Lock & locked_chain,const CWalletTx & wtx,UniValue & entry)170 static void WalletTxToJSON(interfaces::Chain& chain, interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx, UniValue& entry)
171 {
172     int confirms = wtx.GetDepthInMainChain();
173     entry.pushKV("confirmations", confirms);
174     if (wtx.IsCoinBase() || wtx.IsCoinStake())
175         entry.pushKV("generated", true);
176     if (confirms > 0)
177     {
178         entry.pushKV("blockhash", wtx.m_confirm.hashBlock.GetHex());
179         entry.pushKV("blockheight", wtx.m_confirm.block_height);
180         entry.pushKV("blockindex", wtx.m_confirm.nIndex);
181         int64_t block_time;
182         bool found_block = chain.findBlock(wtx.m_confirm.hashBlock, nullptr /* block */, &block_time);
183         CHECK_NONFATAL(found_block);
184         entry.pushKV("blocktime", block_time);
185     } else {
186         entry.pushKV("trusted", wtx.IsTrusted(locked_chain));
187     }
188     uint256 hash = wtx.GetHash();
189     entry.pushKV("txid", hash.GetHex());
190     UniValue conflicts(UniValue::VARR);
191     for (const uint256& conflict : wtx.GetConflicts())
192         conflicts.push_back(conflict.GetHex());
193     entry.pushKV("walletconflicts", conflicts);
194     entry.pushKV("time", wtx.GetTxTime());
195     entry.pushKV("timereceived", (int64_t)wtx.nTimeReceived);
196 
197     // Add opt-in RBF status
198     std::string rbfStatus = "no";
199     if (confirms <= 0) {
200         RBFTransactionState rbfState = chain.isRBFOptIn(*wtx.tx);
201         if (rbfState == RBFTransactionState::UNKNOWN)
202             rbfStatus = "unknown";
203         else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125)
204             rbfStatus = "yes";
205     }
206     entry.pushKV("bip125-replaceable", rbfStatus);
207 
208     for (const std::pair<const std::string, std::string>& item : wtx.mapValue)
209         entry.pushKV(item.first, item.second);
210 }
211 
LabelFromValue(const UniValue & value)212 static std::string LabelFromValue(const UniValue& value)
213 {
214     std::string label = value.get_str();
215     if (label == "*")
216         throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
217     return label;
218 }
219 
SetDefaultPayForContractAddress(CWallet * const pwallet,interfaces::Chain::Lock & locked_chain,CCoinControl & coinControl)220 bool SetDefaultPayForContractAddress(CWallet* const pwallet, interfaces::Chain::Lock& locked_chain, CCoinControl & coinControl)
221 {
222     // Set default coin to pay for the contract
223     // Select any valid unspent output that can be used to pay for the contract
224     std::vector<COutput> vecOutputs;
225     coinControl.fAllowOtherInputs=true;
226 
227     assert(pwallet != NULL);
228     pwallet->AvailableCoins(locked_chain, vecOutputs, false, NULL, true);
229 
230     for (const COutput& out : vecOutputs) {
231         CTxDestination destAdress;
232         const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
233         bool fValidAddress = ExtractDestination(scriptPubKey, destAdress)
234                 && IsValidContractSenderAddress(destAdress);
235 
236         if (!fValidAddress)
237             continue;
238 
239         coinControl.Select(COutPoint(out.tx->GetHash(),out.i));
240         break;
241     }
242 
243     return coinControl.HasSelected();
244 }
245 
SetDefaultSignSenderAddress(CWallet * const pwallet,interfaces::Chain::Lock & locked_chain,CTxDestination & destAdress)246 bool SetDefaultSignSenderAddress(CWallet* const pwallet, interfaces::Chain::Lock& locked_chain, CTxDestination& destAdress)
247 {
248     // Set default sender address if none provided
249     // Select any valid unspent output that can be used for contract sender address
250     std::vector<COutput> vecOutputs;
251 
252     assert(pwallet != NULL);
253     pwallet->AvailableCoins(locked_chain, vecOutputs, false, NULL, true);
254 
255     for (const COutput& out : vecOutputs) {
256         const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
257         bool fValidAddress = ExtractDestination(scriptPubKey, destAdress)
258                 && IsValidContractSenderAddress(destAdress);
259 
260         if (!fValidAddress)
261             continue;
262         break;
263     }
264 
265     return !boost::get<CNoDestination>(&destAdress);
266 }
267 
getnewaddress(const JSONRPCRequest & request)268 static UniValue getnewaddress(const JSONRPCRequest& request)
269 {
270     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
271     CWallet* const pwallet = wallet.get();
272 
273     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
274         return NullUniValue;
275     }
276 
277             RPCHelpMan{"getnewaddress",
278                 "\nReturns a new Qtum address for receiving payments.\n"
279                 "If 'label' is specified, it is added to the address book \n"
280                 "so payments received with the address will be associated with 'label'.\n",
281                 {
282                     {"label", RPCArg::Type::STR, /* default */ "\"\"", "The label name for the address to be linked to. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."},
283                     {"address_type", RPCArg::Type::STR, /* default */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
284                 },
285                 RPCResult{
286                     RPCResult::Type::STR, "address", "The new qtum address"
287                 },
288                 RPCExamples{
289                     HelpExampleCli("getnewaddress", "")
290             + HelpExampleRpc("getnewaddress", "")
291                 },
292             }.Check(request);
293 
294     LOCK(pwallet->cs_wallet);
295 
296     if (!pwallet->CanGetAddresses()) {
297         throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
298     }
299 
300     // Parse the label first so we don't generate a key if there's an error
301     std::string label;
302     if (!request.params[0].isNull())
303         label = LabelFromValue(request.params[0]);
304 
305     OutputType output_type = pwallet->m_default_address_type;
306     if (!request.params[1].isNull()) {
307         if (!ParseOutputType(request.params[1].get_str(), output_type)) {
308             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[1].get_str()));
309         }
310     }
311 
312     CTxDestination dest;
313     std::string error;
314     if (!pwallet->GetNewDestination(output_type, label, dest, error)) {
315         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error);
316     }
317 
318     return EncodeDestination(dest);
319 }
320 
getrawchangeaddress(const JSONRPCRequest & request)321 static UniValue getrawchangeaddress(const JSONRPCRequest& request)
322 {
323     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
324     CWallet* const pwallet = wallet.get();
325 
326     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
327         return NullUniValue;
328     }
329 
330             RPCHelpMan{"getrawchangeaddress",
331                 "\nReturns a new Qtum address, for receiving change.\n"
332                 "This is for use with raw transactions, NOT normal use.\n",
333                 {
334                     {"address_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
335                 },
336                 RPCResult{
337                     RPCResult::Type::STR, "address", "The address"
338                 },
339                 RPCExamples{
340                     HelpExampleCli("getrawchangeaddress", "")
341             + HelpExampleRpc("getrawchangeaddress", "")
342                 },
343             }.Check(request);
344 
345     LOCK(pwallet->cs_wallet);
346 
347     if (!pwallet->CanGetAddresses(true)) {
348         throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
349     }
350 
351     OutputType output_type = pwallet->m_default_change_type != OutputType::CHANGE_AUTO ? pwallet->m_default_change_type : pwallet->m_default_address_type;
352     if (!request.params[0].isNull()) {
353         if (!ParseOutputType(request.params[0].get_str(), output_type)) {
354             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
355         }
356     }
357 
358     CTxDestination dest;
359     std::string error;
360     if (!pwallet->GetNewChangeDestination(output_type, dest, error)) {
361         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error);
362     }
363     return EncodeDestination(dest);
364 }
365 
366 
setlabel(const JSONRPCRequest & request)367 static UniValue setlabel(const JSONRPCRequest& request)
368 {
369     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
370     CWallet* const pwallet = wallet.get();
371 
372     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
373         return NullUniValue;
374     }
375 
376             RPCHelpMan{"setlabel",
377                 "\nSets the label associated with the given address.\n",
378                 {
379                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The qtum address to be associated with a label."},
380                     {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label to assign to the address."},
381                 },
382                 RPCResult{RPCResult::Type::NONE, "", ""},
383                 RPCExamples{
384                     HelpExampleCli("setlabel", "\"" + EXAMPLE_ADDRESS[0] + "\" \"tabby\"")
385             + HelpExampleRpc("setlabel", "\"" + EXAMPLE_ADDRESS[0] + "\", \"tabby\"")
386                 },
387             }.Check(request);
388 
389     LOCK(pwallet->cs_wallet);
390 
391     CTxDestination dest = DecodeDestination(request.params[0].get_str());
392     if (!IsValidDestination(dest)) {
393         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Qtum address");
394     }
395 
396     std::string label = LabelFromValue(request.params[1]);
397 
398     if (pwallet->IsMine(dest)) {
399         pwallet->SetAddressBook(dest, label, "receive");
400     } else {
401         pwallet->SetAddressBook(dest, label, "send");
402     }
403 
404     return NullUniValue;
405 }
406 
407 
SendMoney(interfaces::Chain::Lock & locked_chain,CWallet * const pwallet,const CTxDestination & address,CAmount nValue,bool fSubtractFeeFromAmount,const CCoinControl & coin_control,mapValue_t mapValue,bool hasSender)408 static CTransactionRef SendMoney(interfaces::Chain::Lock& locked_chain, CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue, bool hasSender)
409 {
410     CAmount curBalance = pwallet->GetBalance(0, coin_control.m_avoid_address_reuse).m_mine_trusted;
411 
412     // Check amount
413     if (nValue <= 0)
414         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
415 
416     if (nValue > curBalance)
417         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
418 
419     if (pwallet->m_wallet_unlock_staking_only)
420     {
421         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet unlocked for staking only, unable to create transaction.");
422     }
423 
424     // Parse Bitcoin address
425     CScript scriptPubKey = GetScriptForDestination(address);
426 
427     // Create and send the transaction
428     CAmount nFeeRequired = 0;
429     std::string strError;
430     std::vector<CRecipient> vecSend;
431     int nChangePosRet = -1;
432     CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
433     vecSend.push_back(recipient);
434     CTransactionRef tx;
435     if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strError, coin_control, true, 0, hasSender)) {
436         if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
437             strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
438         throw JSONRPCError(RPC_WALLET_ERROR, strError);
439     }
440     pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */);
441     return tx;
442 }
443 
SplitRemainder(std::vector<CRecipient> & vecSend,CAmount & remainder,CAmount maxValue)444 void SplitRemainder(std::vector<CRecipient>& vecSend, CAmount& remainder, CAmount maxValue)
445 {
446     if(remainder > 0)
447     {
448         for(int i = vecSend.size() - 1; i >= 0 ; i--)
449         {
450             CAmount diffAmount = maxValue - vecSend[i].nAmount;
451             if(diffAmount > 0)
452             {
453                 if((remainder - diffAmount) > 0)
454                 {
455                     vecSend[i].nAmount = vecSend[i].nAmount + diffAmount;
456                     remainder -= diffAmount;
457                 }
458                 else
459                 {
460                     vecSend[i].nAmount = vecSend[i].nAmount + remainder;
461                     remainder = 0;
462                 }
463             }
464 
465             if(remainder <= 0)
466                 break;
467         }
468     }
469 }
470 
SplitUTXOs(interfaces::Chain::Lock & locked_chain,CWallet * const pwallet,const CTxDestination & address,CAmount nValue,CAmount maxValue,const CCoinControl & coin_control,CAmount nTotal,int maxOutputs,CAmount & nSplited)471 static CTransactionRef SplitUTXOs(interfaces::Chain::Lock& locked_chain, CWallet * const pwallet, const CTxDestination &address, CAmount nValue, CAmount maxValue, const CCoinControl& coin_control, CAmount nTotal, int maxOutputs, CAmount& nSplited)
472 {
473     // Check amount
474     if (nValue <= 0)
475         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
476 
477     if (nValue > nTotal)
478         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
479 
480     // Parse Qtum address
481     CScript scriptPubKey = GetScriptForDestination(address);
482 
483     // Split into utxos with nValue
484     CAmount nFeeRequired = 0;
485     std::string strError;
486     std::vector<CRecipient> vecSend;
487     int nChangePosRet = -1;
488     int numOfRecipients = static_cast<int>(nTotal / nValue);
489 
490     // Compute the number of recipients
491     CAmount remainder = nTotal % nValue;
492     if(remainder == 0 && numOfRecipients > 0)
493     {
494         numOfRecipients -= 1;
495         remainder = nValue;
496     }
497     if(numOfRecipients > maxOutputs)
498     {
499         numOfRecipients = maxOutputs;
500         remainder = 0;
501     }
502 
503     // Split coins between recipients
504     CAmount nTxAmount = 0;
505     nSplited = 0;
506     CRecipient recipient = {scriptPubKey, nValue, false};
507     for(int i = 0; i < numOfRecipients; i++) {
508         vecSend.push_back(recipient);
509     }
510     SplitRemainder(vecSend, remainder, maxValue);
511 
512     // Get the total amount of the outputs
513     for(CRecipient rec : vecSend)
514     {
515         nTxAmount += rec.nAmount;
516     }
517 
518     // Create the transaction
519     CTransactionRef tx;
520     if((nTxAmount + pwallet->m_default_max_tx_fee) <= nTotal)
521     {
522         if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strError, coin_control, true, 0, true)) {
523             throw JSONRPCError(RPC_WALLET_ERROR, strError);
524         }
525         nSplited = nFeeRequired;
526     }
527     else if (vecSend.size() > 0)
528     {
529         // Pay the fee for the tx with the last recipient
530         CRecipient lastRecipient = vecSend[vecSend.size() - 1];
531         lastRecipient.fSubtractFeeFromAmount = true;
532         vecSend[vecSend.size() - 1] = lastRecipient;
533         if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strError, coin_control, true, 0, true)) {
534             throw JSONRPCError(RPC_WALLET_ERROR, strError);
535         }
536 
537         // Combine the last 2 outputs when the last output have value less than nValue due to paying the fee
538         if(vecSend.size() >= 2)
539         {
540             if((lastRecipient.nAmount - nFeeRequired) < nValue)
541             {
542                 bool payFeeRemainder = (nTotal - nTxAmount) > nFeeRequired * 1.1;
543                 if(payFeeRemainder)
544                 {
545                     // Pay the fee with the remainder
546                     lastRecipient.fSubtractFeeFromAmount = false;
547                     vecSend.pop_back();
548                     vecSend.push_back(lastRecipient);
549                 }
550                 else
551                 {
552                     // Combine the last 2 outputs
553                     CAmount nValueLast2 = lastRecipient.nAmount + vecSend[vecSend.size() - 2].nAmount;
554                     lastRecipient.nAmount = lastRecipient.nAmount + nFeeRequired;
555                     lastRecipient.fSubtractFeeFromAmount = true;
556                     nValueLast2 -= lastRecipient.nAmount;
557                     vecSend.pop_back();
558                     vecSend.pop_back();
559                     vecSend.push_back(lastRecipient);
560 
561                     // Split the rest with the others
562                     SplitRemainder(vecSend, nValueLast2, maxValue);
563                 }
564 
565                 if((!pwallet->CreateTransaction(locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strError, coin_control, true, 0, true))) {
566                     throw JSONRPCError(RPC_WALLET_ERROR, strError);
567                 }
568                 if(payFeeRemainder)
569                 {
570                     nSplited = nFeeRequired;
571                 }
572             }
573         }
574     }
575 
576     // Compute the splited amount
577     for(CRecipient rec : vecSend)
578     {
579         nSplited += rec.nAmount;
580     }
581 
582     // Send the transaction
583     pwallet->CommitTransaction(tx, {} /* mapValue */, {} /* orderForm */);
584 
585     return tx;
586 }
587 
sendtoaddress(const JSONRPCRequest & request)588 static UniValue sendtoaddress(const JSONRPCRequest& request)
589 {
590     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
591     CWallet* const pwallet = wallet.get();
592 
593     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
594         return NullUniValue;
595     }
596 
597             RPCHelpMan{"sendtoaddress",
598                 "\nSend an amount to a given address." +
599         HELP_REQUIRING_PASSPHRASE,
600                 {
601                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The qtum address to send to."},
602                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"},
603                     {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment used to store what the transaction is for.\n"
604             "                             This is not part of the transaction, just kept in your wallet."},
605                     {"comment_to", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment to store the name of the person or organization\n"
606             "                             to which you're sending the transaction. This is not part of the \n"
607             "                             transaction, just kept in your wallet."},
608                     {"subtractfeefromamount", RPCArg::Type::BOOL, /* default */ "false", "The fee will be deducted from the amount being sent.\n"
609             "                             The recipient will receive less qtums than you enter in the amount field."},
610                     {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
611                     {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
612                     {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
613             "       \"UNSET\"\n"
614             "       \"ECONOMICAL\"\n"
615             "       \"CONSERVATIVE\""},
616                     {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
617             "                             dirty if they have previously been used in a transaction."},
618                     {"senderaddress", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "The qtum address that will be used to send money from."},
619                     {"changeToSender", RPCArg::Type::BOOL, /* default */ "false", "Return the change to the sender."},
620                 },
621                 RPCResult{
622                     RPCResult::Type::STR_HEX, "txid", "The transaction id."
623                 },
624                 RPCExamples{
625                     HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1")
626             + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"donation\" \"seans outpost\"")
627             + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"\" \"\" true")
628             + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 0.1, \"donation\", \"seans outpost\", false, null, null, \"\", false, \"" + EXAMPLE_ADDRESS[1] + "\", true")
629             + HelpExampleRpc("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 0.1, \"donation\", \"seans outpost\"")
630             + HelpExampleRpc("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 0.1, \"donation\", \"seans outpost\", false, null, null, \"\", false, \"" + EXAMPLE_ADDRESS[1] + "\", true")
631                 },
632             }.Check(request);
633 
634     // Make sure the results are valid at least up to the most recent block
635     // the user could have gotten from another RPC command prior to now
636     pwallet->BlockUntilSyncedToCurrentChain();
637 
638     auto locked_chain = pwallet->chain().lock();
639     LOCK(pwallet->cs_wallet);
640 
641     CTxDestination dest = DecodeDestination(request.params[0].get_str());
642     if (!IsValidDestination(dest)) {
643         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Qtum address");
644     }
645 
646     // Amount
647     CAmount nAmount = AmountFromValue(request.params[1]);
648     if (nAmount <= 0)
649         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
650 
651     // Wallet comments
652     mapValue_t mapValue;
653     if (!request.params[2].isNull() && !request.params[2].get_str().empty())
654         mapValue["comment"] = request.params[2].get_str();
655     if (!request.params[3].isNull() && !request.params[3].get_str().empty())
656         mapValue["to"] = request.params[3].get_str();
657 
658     bool fSubtractFeeFromAmount = false;
659     if (!request.params[4].isNull()) {
660         fSubtractFeeFromAmount = request.params[4].get_bool();
661     }
662 
663     CCoinControl coin_control;
664     if (!request.params[5].isNull()) {
665         coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
666     }
667 
668     if (!request.params[6].isNull()) {
669         coin_control.m_confirm_target = ParseConfirmTarget(request.params[6], pwallet->chain().estimateMaxBlocks());
670     }
671 
672     if (request.params.size() > 7 && !request.params[7].isNull()) {
673         std::string estimate_mode = request.params[7].get_str();
674         if (!estimate_mode.empty() && !FeeModeFromString(estimate_mode, coin_control.m_fee_mode)) {
675             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
676         }
677     }
678 
679     coin_control.m_avoid_address_reuse = GetAvoidReuseFlag(pwallet, request.params[8]);
680     // We also enable partial spend avoidance if reuse avoidance is set.
681     coin_control.m_avoid_partial_spends |= coin_control.m_avoid_address_reuse;
682 
683     bool fHasSender=false;
684     CTxDestination senderAddress;
685     if (request.params.size() > 9 && !request.params[9].isNull()){
686     senderAddress = DecodeDestination(request.params[9].get_str());
687         if (!IsValidDestination(senderAddress))
688             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Qtum address to send from");
689         else
690             fHasSender=true;
691     }
692 
693     bool fChangeToSender=false;
694     if (request.params.size() > 10 && !request.params[10].isNull()){
695         fChangeToSender=request.params[10].get_bool();
696     }
697 
698     if(fHasSender){
699     //find a UTXO with sender address
700 
701      UniValue results(UniValue::VARR);
702      std::vector<COutput> vecOutputs;
703 
704      coin_control.fAllowOtherInputs=true;
705 
706      assert(pwallet != NULL);
707      pwallet->AvailableCoins(*locked_chain, vecOutputs, false, NULL, true);
708 
709      for(const COutput& out : vecOutputs) {
710          CTxDestination destAdress;
711          const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
712          bool fValidAddress = ExtractDestination(scriptPubKey, destAdress);
713 
714          if (!fValidAddress || senderAddress != destAdress)
715              continue;
716 
717          coin_control.Select(COutPoint(out.tx->GetHash(),out.i));
718 
719          break;
720 
721      }
722 
723         if(!coin_control.HasSelected()){
724             throw JSONRPCError(RPC_TYPE_ERROR, "Sender address does not have any unspent outputs");
725         }
726         if(fChangeToSender){
727             coin_control.destChange=senderAddress;
728         }
729     }
730 
731     EnsureWalletIsUnlocked(pwallet);
732 
733     CTransactionRef tx = SendMoney(*locked_chain, pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue), fHasSender);
734     return tx->GetHash().GetHex();
735 }
736 
splitutxosforaddress(const JSONRPCRequest & request)737 static UniValue splitutxosforaddress(const JSONRPCRequest& request)
738 {
739     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
740     CWallet* const pwallet = wallet.get();
741 
742     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
743         return NullUniValue;
744     }
745 
746             RPCHelpMan{"splitutxosforaddress",
747                 "\nSplit an address coins into utxo between min and max value." +
748                     HELP_REQUIRING_PASSPHRASE,
749                 {
750                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The qtum address to split utxos."},
751                     {"minValue", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "Select utxo which value is smaller than value (minimum 0.1 COIN)"},
752                     {"maxValue", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "Select utxo which value is greater than value (minimum 0.1 COIN)"},
753                     {"maxOutputs", RPCArg::Type::NUM, /* default */ "100", "Maximum outputs to create"},
754                 },
755                 RPCResult{
756                     RPCResult::Type::OBJ, "", "",
757                     {
758                         {RPCResult::Type::STR_HEX, "txid", "The hex-encoded transaction id"},
759                         {RPCResult::Type::STR_AMOUNT, "selected", "Selected amount of coins"},
760                         {RPCResult::Type::STR_AMOUNT, "splited", "Splited amount of coins"},
761                     }
762                 },
763                 RPCExamples{
764                     HelpExampleCli("splitutxosforaddress", "\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 100 200")
765             + HelpExampleCli("splitutxosforaddress", "\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 100 200 100")
766             + HelpExampleRpc("splitutxosforaddress", "\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 100 200")
767             + HelpExampleRpc("splitutxosforaddress", "\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 100 200 100")
768                 },
769             }.Check(request);
770 
771     // Make sure the results are valid at least up to the most recent block
772     // the user could have gotten from another RPC command prior to now
773     pwallet->BlockUntilSyncedToCurrentChain();
774 
775     auto locked_chain = pwallet->chain().lock();
776     LOCK(pwallet->cs_wallet);
777 
778     // Address
779     CTxDestination address = DecodeDestination(request.params[0].get_str());
780 
781     if (!IsValidDestination(address)) {
782         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Qtum address");
783     }
784     CScript scriptPubKey = GetScriptForDestination(address);
785     if (!pwallet->IsMine(scriptPubKey)) {
786         throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
787     }
788 
789     // minimum value
790     CAmount minValue = AmountFromValue(request.params[1]);
791 
792     // maximum value
793     CAmount maxValue = AmountFromValue(request.params[2]);
794 
795     if (minValue < COIN/10 || maxValue <= 0 || minValue > maxValue) {
796         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid values for minimum and maximum");
797     }
798 
799     // Maximum outputs
800     int maxOutputs = request.params.size() > 3 ? request.params[3].get_int() : 100;
801     if (maxOutputs < 1) {
802         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid value for maximum outputs");
803     }
804 
805     // Amount
806     CAmount nSplitAmount = minValue;
807     CAmount nRequiredAmount = nSplitAmount * maxOutputs;
808 
809     CCoinControl coin_control;
810     coin_control.destChange = address;
811 
812     // Find UTXOs for a address with value smaller than minValue and greater then maxValue
813     std::vector<COutput> vecOutputs;
814     coin_control.fAllowOtherInputs=true;
815 
816     assert(pwallet != NULL);
817     pwallet->AvailableCoins(*locked_chain, vecOutputs, false, NULL, true);
818 
819     CAmount total = 0;
820     CAmount nSelectedAmount = 0;
821     for(const COutput& out : vecOutputs) {
822         CTxDestination destAdress;
823         const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
824         bool fValidAddress = ExtractDestination(scriptPubKey, destAdress);
825 
826         CAmount val = out.tx->tx.get()->vout[out.i].nValue;
827         if (!fValidAddress || address != destAdress || (val >= minValue && val <= maxValue ) )
828             continue;
829 
830         if(nSelectedAmount <= nRequiredAmount)
831         {
832             coin_control.Select(COutPoint(out.tx->GetHash(),out.i));
833             nSelectedAmount += val;
834         }
835         total += val;
836     }
837 
838     CAmount splited = 0;
839     UniValue obj(UniValue::VOBJ);
840     if(coin_control.HasSelected() && nSplitAmount < nSelectedAmount){
841         EnsureWalletIsUnlocked(pwallet);
842         CTransactionRef tx = SplitUTXOs(*locked_chain, pwallet, address, nSplitAmount, maxValue, coin_control, nSelectedAmount, maxOutputs, splited);
843         obj.pushKV("txid",          tx->GetHash().GetHex());
844     }
845 
846     obj.pushKV("selected",      FormatMoney(total));
847     obj.pushKV("splited",       FormatMoney(splited));
848     return obj;
849 }
850 
createcontract(const JSONRPCRequest & request)851 static UniValue createcontract(const JSONRPCRequest& request){
852 
853     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
854     CWallet* const pwallet = wallet.get();
855 
856     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
857         return NullUniValue;
858     }
859 
860     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
861     auto locked_chain = pwallet->chain().lock();
862     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
863     QtumDGP qtumDGP(globalState.get(), fGettingValuesDGP);
864     uint64_t blockGasLimit = qtumDGP.getBlockGasLimit(::ChainActive().Height());
865     uint64_t minGasPrice = CAmount(qtumDGP.getMinGasPrice(::ChainActive().Height()));
866     CAmount nGasPrice = (minGasPrice>DEFAULT_GAS_PRICE)?minGasPrice:DEFAULT_GAS_PRICE;
867 
868                 RPCHelpMan{"createcontract",
869                 "\nCreate a contract with bytcode." +
870                 HELP_REQUIRING_PASSPHRASE,
871                 {
872                     {"bytecode", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "contract bytcode."},
873                     {"gasLimit", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "gasLimit, default: "+i64tostr(DEFAULT_GAS_LIMIT_OP_CREATE)+", max: "+i64tostr(blockGasLimit)},
874                     {"gasPrice", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "gasPrice QTUM price per gas unit, default: "+FormatMoney(nGasPrice)+", min:"+FormatMoney(minGasPrice)},
875                     {"senderaddress", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The qtum address that will be used to create the contract."},
876                     {"broadcast", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Whether to broadcast the transaction or not."},
877                     {"changeToSender", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Return the change to the sender."},
878                 },
879                 RPCResult{
880                     RPCResult::Type::ARR, "", "",
881                     {
882                         {RPCResult::Type::OBJ, "", "",
883                         {
884                             {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
885                             {RPCResult::Type::STR, "sender", CURRENCY_UNIT + " address of the sender"},
886                             {RPCResult::Type::STR_HEX, "hash160", "Ripemd-160 hash of the sender"},
887                             {RPCResult::Type::STR, "address", "Expected contract address"},
888                         }},
889                     }
890                 },
891                 RPCExamples{
892                 HelpExampleCli("createcontract", "\"60606040525b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c010000000000000000000000009081020402179055506103786001600050819055505b600c80605b6000396000f360606040526008565b600256\"")
893                 + HelpExampleCli("createcontract", "\"60606040525b33600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff02191690836c010000000000000000000000009081020402179055506103786001600050819055505b600c80605b6000396000f360606040526008565b600256\" 6000000 "+FormatMoney(minGasPrice)+" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" true")
894                 },
895             }.Check(request);
896 
897 
898     std::string bytecode=request.params[0].get_str();
899 
900     if(bytecode.size() % 2 != 0 || !CheckHex(bytecode))
901         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid data (data not hex)");
902 
903     uint64_t nGasLimit=DEFAULT_GAS_LIMIT_OP_CREATE;
904     if (request.params.size() > 1){
905         nGasLimit = request.params[1].get_int64();
906         if (nGasLimit > blockGasLimit)
907             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasLimit (Maximum is: "+i64tostr(blockGasLimit)+")");
908         if (nGasLimit < MINIMUM_GAS_LIMIT)
909             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasLimit (Minimum is: "+i64tostr(MINIMUM_GAS_LIMIT)+")");
910         if (nGasLimit <= 0)
911             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasLimit");
912     }
913 
914     if (request.params.size() > 2){
915         nGasPrice = AmountFromValue(request.params[2]);
916         if (nGasPrice <= 0)
917             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasPrice");
918         CAmount maxRpcGasPrice = gArgs.GetArg("-rpcmaxgasprice", MAX_RPC_GAS_PRICE);
919         if (nGasPrice > (int64_t)maxRpcGasPrice)
920             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasPrice, Maximum allowed in RPC calls is: "+FormatMoney(maxRpcGasPrice)+" (use -rpcmaxgasprice to change it)");
921         if (nGasPrice < (int64_t)minGasPrice)
922             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasPrice (Minimum is: "+FormatMoney(minGasPrice)+")");
923     }
924 
925     bool fHasSender=false;
926     CTxDestination senderAddress;
927     if (request.params.size() > 3){
928         senderAddress = DecodeDestination(request.params[3].get_str());
929         if (!IsValidDestination(senderAddress))
930             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Qtum address to send from");
931         if (!IsValidContractSenderAddress(senderAddress))
932             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid contract sender address. Only P2PK and P2PKH allowed");
933         else
934             fHasSender=true;
935     }
936 
937     bool fBroadcast=true;
938     if (request.params.size() > 4){
939         fBroadcast=request.params[4].get_bool();
940     }
941 
942     bool fChangeToSender=true;
943     if (request.params.size() > 5){
944         fChangeToSender=request.params[5].get_bool();
945     }
946 
947     CCoinControl coinControl;
948 
949     CTxDestination signSenderAddress = CNoDestination();
950     if(fHasSender){
951         // Find a UTXO with sender address
952         std::vector<COutput> vecOutputs;
953 
954         coinControl.fAllowOtherInputs=true;
955 
956         assert(pwallet != NULL);
957         pwallet->AvailableCoins(*locked_chain, vecOutputs, false, NULL, true);
958 
959         for (const COutput& out : vecOutputs) {
960             CTxDestination destAdress;
961             const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
962             bool fValidAddress = ExtractDestination(scriptPubKey, destAdress);
963 
964             if (!fValidAddress || senderAddress != destAdress)
965                 continue;
966 
967             coinControl.Select(COutPoint(out.tx->GetHash(),out.i));
968 
969             break;
970 
971         }
972 
973         if(coinControl.HasSelected())
974         {
975             // Change to the sender
976             if(fChangeToSender){
977                 coinControl.destChange=senderAddress;
978             }
979         }
980         else
981         {
982             // Create op sender transaction when op sender is activated
983             if(!(::ChainActive().Height() >= Params().GetConsensus().QIP5Height))
984                 throw JSONRPCError(RPC_TYPE_ERROR, "Sender address does not have any unspent outputs");
985         }
986 
987         if(::ChainActive().Height() >= Params().GetConsensus().QIP5Height)
988         {
989             // Set the sender address
990             signSenderAddress = senderAddress;
991         }
992     }
993     else
994     {
995         if(::ChainActive().Height() >= Params().GetConsensus().QIP5Height)
996         {
997             // If no sender address provided set to the default sender address
998             SetDefaultSignSenderAddress(pwallet, *locked_chain, signSenderAddress);
999         }
1000     }
1001     EnsureWalletIsUnlocked(pwallet);
1002 
1003     CAmount nGasFee=nGasPrice*nGasLimit;
1004 
1005     CAmount curBalance = pwallet->GetBalance().m_mine_trusted;
1006 
1007     // Check amount
1008     if (nGasFee <= 0)
1009         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
1010 
1011     if (nGasFee > curBalance)
1012         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
1013 
1014     // Select default coin that will pay for the contract if none selected
1015     if(!coinControl.HasSelected() && !SetDefaultPayForContractAddress(pwallet, *locked_chain, coinControl))
1016         throw JSONRPCError(RPC_TYPE_ERROR, "Does not have any P2PK or P2PKH unspent outputs to pay for the contract.");
1017 
1018     // Build OP_EXEC script
1019     CScript scriptPubKey = CScript() << CScriptNum(VersionVM::GetEVMDefault().toRaw()) << CScriptNum(nGasLimit) << CScriptNum(nGasPrice) << ParseHex(bytecode) <<OP_CREATE;
1020     if(::ChainActive().Height() >= Params().GetConsensus().QIP5Height)
1021     {
1022         if(IsValidDestination(signSenderAddress))
1023         {
1024             CKeyID key_id = GetKeyForDestination(spk_man, signSenderAddress);
1025             CKey key;
1026             if (!spk_man.GetKey(key_id, key)) {
1027                 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
1028             }
1029             std::vector<unsigned char> scriptSig;
1030             scriptPubKey = (CScript() << CScriptNum(addresstype::PUBKEYHASH) << ToByteVector(key_id) << ToByteVector(scriptSig) << OP_SENDER) + scriptPubKey;
1031         }
1032         else
1033         {
1034             // OP_SENDER will always be used when QIP5Height is active
1035             throw JSONRPCError(RPC_TYPE_ERROR, "Sender address fail to set for OP_SENDER.");
1036         }
1037     }
1038 
1039     // Create and send the transaction
1040     CAmount nFeeRequired;
1041     std::string strError;
1042     std::vector<CRecipient> vecSend;
1043     int nChangePosRet = -1;
1044     CRecipient recipient = {scriptPubKey, 0, false};
1045     vecSend.push_back(recipient);
1046 
1047     CTransactionRef tx;
1048     if (!pwallet->CreateTransaction(*locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strError, coinControl, true, nGasFee, true, signSenderAddress)) {
1049         if (nFeeRequired > pwallet->GetBalance().m_mine_trusted)
1050             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));
1051         throw JSONRPCError(RPC_WALLET_ERROR, strError);
1052     }
1053 
1054     CTxDestination txSenderDest;
1055     GetSenderDest(pwallet, tx, txSenderDest);
1056 
1057     if (fHasSender && !(senderAddress == txSenderDest)){
1058            throw JSONRPCError(RPC_TYPE_ERROR, "Sender could not be set, transaction was not committed!");
1059     }
1060 
1061     UniValue result(UniValue::VOBJ);
1062     if(fBroadcast){
1063     pwallet->CommitTransaction(tx, {}, {});
1064 
1065     std::string txId=tx->GetHash().GetHex();
1066     result.pushKV("txid", txId);
1067 
1068     CTxDestination txSenderAdress(txSenderDest);
1069     CKeyID keyid = GetKeyForDestination(spk_man, txSenderAdress);
1070 
1071     result.pushKV("sender", EncodeDestination(txSenderAdress));
1072     result.pushKV("hash160", HexStr(valtype(keyid.begin(),keyid.end())));
1073 
1074     std::vector<unsigned char> SHA256TxVout(32);
1075     std::vector<unsigned char> contractAddress(20);
1076     std::vector<unsigned char> txIdAndVout(tx->GetHash().begin(), tx->GetHash().end());
1077     uint32_t voutNumber=0;
1078     for (const CTxOut& txout : tx->vout) {
1079         if(txout.scriptPubKey.HasOpCreate()){
1080             std::vector<unsigned char> voutNumberChrs;
1081             if (voutNumberChrs.size() < sizeof(voutNumber))voutNumberChrs.resize(sizeof(voutNumber));
1082             std::memcpy(voutNumberChrs.data(), &voutNumber, sizeof(voutNumber));
1083             txIdAndVout.insert(txIdAndVout.end(),voutNumberChrs.begin(),voutNumberChrs.end());
1084             break;
1085         }
1086         voutNumber++;
1087     }
1088     CSHA256().Write(txIdAndVout.data(), txIdAndVout.size()).Finalize(SHA256TxVout.data());
1089     CRIPEMD160().Write(SHA256TxVout.data(), SHA256TxVout.size()).Finalize(contractAddress.data());
1090     result.pushKV("address", HexStr(contractAddress));
1091     }else{
1092     std::string strHex = EncodeHexTx(*tx, RPCSerializationFlags());
1093     result.pushKV("raw transaction", strHex);
1094     }
1095     return result;
1096 }
1097 
SendToContract(interfaces::Chain::Lock & locked_chain,CWallet * const pwallet,LegacyScriptPubKeyMan & spk_man,const UniValue & params)1098 UniValue SendToContract(interfaces::Chain::Lock& locked_chain, CWallet* const pwallet, LegacyScriptPubKeyMan& spk_man, const UniValue& params)
1099 {
1100     QtumDGP qtumDGP(globalState.get(), fGettingValuesDGP);
1101     uint64_t blockGasLimit = qtumDGP.getBlockGasLimit(::ChainActive().Height());
1102     uint64_t minGasPrice = CAmount(qtumDGP.getMinGasPrice(::ChainActive().Height()));
1103     CAmount nGasPrice = (minGasPrice>DEFAULT_GAS_PRICE)?minGasPrice:DEFAULT_GAS_PRICE;
1104 
1105     std::string contractaddress = params[0].get_str();
1106     if(contractaddress.size() != 40 || !CheckHex(contractaddress))
1107         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Incorrect contract address");
1108 
1109     dev::Address addrAccount(contractaddress);
1110     if(!globalState->addressInUse(addrAccount))
1111         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "contract address does not exist");
1112 
1113     std::string datahex = params[1].get_str();
1114     if(datahex.size() % 2 != 0 || !CheckHex(datahex))
1115         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid data (data not hex)");
1116 
1117     CAmount nAmount = 0;
1118     if (params.size() > 2){
1119         nAmount = AmountFromValue(params[2]);
1120         if (nAmount < 0)
1121             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1122     }
1123 
1124     uint64_t nGasLimit=DEFAULT_GAS_LIMIT_OP_SEND;
1125     if (params.size() > 3){
1126         nGasLimit = params[3].get_int64();
1127         if (nGasLimit > blockGasLimit)
1128             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasLimit (Maximum is: "+i64tostr(blockGasLimit)+")");
1129         if (nGasLimit < MINIMUM_GAS_LIMIT)
1130             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasLimit (Minimum is: "+i64tostr(MINIMUM_GAS_LIMIT)+")");
1131         if (nGasLimit <= 0)
1132             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasLimit");
1133     }
1134 
1135     if (params.size() > 4){
1136         nGasPrice = AmountFromValue(params[4]);
1137         if (nGasPrice <= 0)
1138             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasPrice");
1139         CAmount maxRpcGasPrice = gArgs.GetArg("-rpcmaxgasprice", MAX_RPC_GAS_PRICE);
1140         if (nGasPrice > (int64_t)maxRpcGasPrice)
1141             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasPrice, Maximum allowed in RPC calls is: "+FormatMoney(maxRpcGasPrice)+" (use -rpcmaxgasprice to change it)");
1142         if (nGasPrice < (int64_t)minGasPrice)
1143             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for gasPrice (Minimum is: "+FormatMoney(minGasPrice)+")");
1144     }
1145 
1146     bool fHasSender=false;
1147     CTxDestination senderAddress;
1148     if (params.size() > 5){
1149         senderAddress = DecodeDestination(params[5].get_str());
1150         if (!IsValidDestination(senderAddress))
1151             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Qtum address to send from");
1152         if (!IsValidContractSenderAddress(senderAddress))
1153             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid contract sender address. Only P2PK and P2PKH allowed");
1154         else
1155             fHasSender=true;
1156     }
1157 
1158     bool fBroadcast=true;
1159     if (params.size() > 6){
1160         fBroadcast=params[6].get_bool();
1161     }
1162 
1163     bool fChangeToSender=true;
1164     if (params.size() > 7){
1165         fChangeToSender=params[7].get_bool();
1166     }
1167 
1168     CCoinControl coinControl;
1169 
1170     CTxDestination signSenderAddress = CNoDestination();
1171     if(fHasSender){
1172         // Find a UTXO with sender address
1173         std::vector<COutput> vecOutputs;
1174 
1175         coinControl.fAllowOtherInputs=true;
1176 
1177         assert(pwallet != NULL);
1178         pwallet->AvailableCoins(locked_chain, vecOutputs, false, NULL, true);
1179 
1180         for (const COutput& out : vecOutputs) {
1181 
1182             CTxDestination destAdress;
1183             const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
1184             bool fValidAddress = ExtractDestination(scriptPubKey, destAdress);
1185 
1186             if (!fValidAddress || senderAddress != destAdress)
1187                 continue;
1188 
1189             coinControl.Select(COutPoint(out.tx->GetHash(),out.i));
1190 
1191             break;
1192 
1193         }
1194 
1195         if(coinControl.HasSelected())
1196         {
1197             // Change to the sender
1198             if(fChangeToSender){
1199                 coinControl.destChange=senderAddress;
1200             }
1201         }
1202         else
1203         {
1204             // Create op sender transaction when op sender is activated
1205             if(!(::ChainActive().Height() >= Params().GetConsensus().QIP5Height))
1206                 throw JSONRPCError(RPC_TYPE_ERROR, "Sender address does not have any unspent outputs");
1207         }
1208 
1209         if(::ChainActive().Height() >= Params().GetConsensus().QIP5Height)
1210         {
1211             // Set the sender address
1212             signSenderAddress = senderAddress;
1213         }
1214     }
1215     else
1216     {
1217         if(::ChainActive().Height() >= Params().GetConsensus().QIP5Height)
1218         {
1219             // If no sender address provided set to the default sender address
1220             SetDefaultSignSenderAddress(pwallet, locked_chain, signSenderAddress);
1221         }
1222     }
1223 
1224     EnsureWalletIsUnlocked(pwallet);
1225 
1226     CAmount nGasFee=nGasPrice*nGasLimit;
1227 
1228     CAmount curBalance = pwallet->GetBalance().m_mine_trusted;
1229 
1230     // Check amount
1231     if (nGasFee <= 0)
1232         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount for gas fee");
1233 
1234     if (nAmount+nGasFee > curBalance)
1235         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
1236 
1237     // Select default coin that will pay for the contract if none selected
1238     if(!coinControl.HasSelected() && !SetDefaultPayForContractAddress(pwallet, locked_chain, coinControl))
1239         throw JSONRPCError(RPC_TYPE_ERROR, "Does not have any P2PK or P2PKH unspent outputs to pay for the contract.");
1240 
1241     // Build OP_EXEC_ASSIGN script
1242     CScript scriptPubKey = CScript() << CScriptNum(VersionVM::GetEVMDefault().toRaw()) << CScriptNum(nGasLimit) << CScriptNum(nGasPrice) << ParseHex(datahex) << ParseHex(contractaddress) << OP_CALL;
1243     if(::ChainActive().Height() >= Params().GetConsensus().QIP5Height)
1244     {
1245         if(IsValidDestination(signSenderAddress))
1246         {
1247             CKeyID key_id = GetKeyForDestination(spk_man, signSenderAddress);
1248             CKey key;
1249             if (!spk_man.GetKey(key_id, key)) {
1250                 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
1251             }
1252             std::vector<unsigned char> scriptSig;
1253             scriptPubKey = (CScript() << CScriptNum(addresstype::PUBKEYHASH) << ToByteVector(key_id) << ToByteVector(scriptSig) << OP_SENDER) + scriptPubKey;
1254         }
1255         else
1256         {
1257             // OP_SENDER will always be used when QIP5Height is active
1258             throw JSONRPCError(RPC_TYPE_ERROR, "Sender address fail to set for OP_SENDER.");
1259         }
1260     }
1261 
1262     // Create and send the transaction
1263     CAmount nFeeRequired;
1264     std::string strError;
1265     std::vector<CRecipient> vecSend;
1266     int nChangePosRet = -1;
1267     CRecipient recipient = {scriptPubKey, nAmount, false};
1268     vecSend.push_back(recipient);
1269 
1270     CTransactionRef tx;
1271     if (!pwallet->CreateTransaction(locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strError, coinControl, true, nGasFee, true, signSenderAddress)) {
1272         if (nFeeRequired > pwallet->GetBalance().m_mine_trusted)
1273             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));
1274         throw JSONRPCError(RPC_WALLET_ERROR, strError);
1275     }
1276 
1277     CTxDestination txSenderDest;
1278     GetSenderDest(pwallet, tx, txSenderDest);
1279 
1280     if (fHasSender && !(senderAddress == txSenderDest)){
1281         throw JSONRPCError(RPC_TYPE_ERROR, "Sender could not be set, transaction was not committed!");
1282     }
1283 
1284     UniValue result(UniValue::VOBJ);
1285 
1286     if(fBroadcast){
1287         pwallet->CommitTransaction(tx, {}, {});
1288 
1289         std::string txId=tx->GetHash().GetHex();
1290         result.pushKV("txid", txId);
1291 
1292         CTxDestination txSenderAdress(txSenderDest);
1293         CKeyID keyid = GetKeyForDestination(spk_man, txSenderAdress);
1294 
1295         result.pushKV("sender", EncodeDestination(txSenderAdress));
1296         result.pushKV("hash160", HexStr(valtype(keyid.begin(),keyid.end())));
1297     }else{
1298         std::string strHex = EncodeHexTx(*tx, RPCSerializationFlags());
1299         result.pushKV("raw transaction", strHex);
1300     }
1301 
1302     return result;
1303 }
1304 
1305 /**
1306  * @brief The SendToken class Write token data
1307  */
1308 class SendToken : public CallToken
1309 {
1310 public:
SendToken(interfaces::Chain::Lock & _locked_chain,CWallet * const _pwallet,LegacyScriptPubKeyMan & _spk_man)1311     SendToken(interfaces::Chain::Lock& _locked_chain,
1312               CWallet* const _pwallet,
1313               LegacyScriptPubKeyMan& _spk_man):
1314         locked_chain(_locked_chain),
1315         pwallet(_pwallet),
1316         spk_man(_spk_man)
1317     {}
1318 
execValid(const int & func,const bool & sendTo)1319     bool execValid(const int& func, const bool& sendTo)
1320     {
1321         return sendTo ? func != -1 : CallToken::execValid(func, sendTo);
1322     }
1323 
exec(const bool & sendTo,const std::map<std::string,std::string> & lstParams,std::string & result,std::string & message)1324     bool exec(const bool& sendTo, const std::map<std::string, std::string>& lstParams, std::string& result, std::string& message)
1325     {
1326         if(!sendTo)
1327             return CallToken::exec(sendTo, lstParams, result, message);
1328 
1329         UniValue params(UniValue::VARR);
1330 
1331         // Set address
1332         auto it = lstParams.find(paramAddress());
1333         if(it != lstParams.end())
1334             params.push_back(it->second);
1335         else
1336             return false;
1337 
1338         // Set data
1339         it = lstParams.find(paramDatahex());
1340         if(it != lstParams.end())
1341             params.push_back(it->second);
1342         else
1343             return false;
1344 
1345         // Set amount
1346         it = lstParams.find(paramAmount());
1347         if(it != lstParams.end())
1348         {
1349             if(params.size() == 2)
1350                 params.push_back(it->second);
1351             else
1352                 return false;
1353         }
1354 
1355         // Set gas limit
1356         it = lstParams.find(paramGasLimit());
1357         if(it != lstParams.end())
1358         {
1359             if(params.size() == 3) {
1360                 UniValue param(UniValue::VNUM);
1361                 param.setInt(atoi64(it->second));
1362                 params.push_back(param);
1363             }
1364             else
1365                 return false;
1366         }
1367 
1368         // Set gas price
1369         it = lstParams.find(paramGasPrice());
1370         if(it != lstParams.end())
1371         {
1372             if(params.size() == 4)
1373                 params.push_back(it->second);
1374             else
1375                 return false;
1376         }
1377 
1378         // Set sender
1379         it = lstParams.find(paramSender());
1380         if(it != lstParams.end())
1381         {
1382             if(params.size() == 5)
1383                 params.push_back(it->second);
1384             else
1385                 return false;
1386         }
1387 
1388         // Set broadcast
1389         it = lstParams.find(paramBroadcast());
1390         if(it != lstParams.end())
1391         {
1392             if(params.size() == 6) {
1393                 bool val = it->second == "true" ? true : false;
1394                 UniValue param(UniValue::VBOOL);
1395                 param.setBool(val);
1396                 params.push_back(param);
1397             }
1398             else
1399                 return false;
1400         }
1401 
1402         // Set change to sender
1403         it = lstParams.find(paramChangeToSender());
1404         if(it != lstParams.end())
1405         {
1406             if(params.size() == 7) {
1407                 bool val = it->second == "true" ? true : false;
1408                 UniValue param(UniValue::VBOOL);
1409                 param.setBool(val);
1410                 params.push_back(param);
1411             }
1412             else
1413                 return false;
1414         }
1415 
1416         // Get execution result
1417         UniValue response = SendToContract(locked_chain, pwallet, spk_man, params);
1418         if(!response.isObject() || !response.exists("txid"))
1419             return false;
1420         result = response["txid"].get_str();
1421 
1422         return true;
1423     }
1424 private:
1425     interfaces::Chain::Lock& locked_chain;
1426     CWallet* const pwallet;
1427     LegacyScriptPubKeyMan& spk_man;
1428 };
1429 
sendtocontract(const JSONRPCRequest & request)1430 static UniValue sendtocontract(const JSONRPCRequest& request){
1431 
1432     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1433     CWallet* const pwallet = wallet.get();
1434 
1435     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1436         return NullUniValue;
1437     }
1438 
1439     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
1440     auto locked_chain = pwallet->chain().lock();
1441     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
1442     QtumDGP qtumDGP(globalState.get(), fGettingValuesDGP);
1443     uint64_t blockGasLimit = qtumDGP.getBlockGasLimit(::ChainActive().Height());
1444     uint64_t minGasPrice = CAmount(qtumDGP.getMinGasPrice(::ChainActive().Height()));
1445     CAmount nGasPrice = (minGasPrice>DEFAULT_GAS_PRICE)?minGasPrice:DEFAULT_GAS_PRICE;
1446 
1447                 RPCHelpMan{"sendtocontract",
1448                     "\nSend funds and data to a contract." +
1449                     HELP_REQUIRING_PASSPHRASE,
1450                     {
1451                         {"contractaddress", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The contract address that will receive the funds and data."},
1452                         {"datahex", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "data to send."},
1453                         {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The amount in " + CURRENCY_UNIT + " to send. eg 0.1, default: 0"},
1454                         {"gasLimit", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "gasLimit, default: "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+", max: "+i64tostr(blockGasLimit)},
1455                         {"gasPrice", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "gasPrice Qtum price per gas unit, default: "+FormatMoney(nGasPrice)+", min:"+FormatMoney(minGasPrice)},
1456                         {"senderaddress", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The qtum address that will be used as sender."},
1457                         {"broadcast", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Whether to broadcast the transaction or not."},
1458                         {"changeToSender", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Return the change to the sender."},
1459                     },
1460                     RPCResult{
1461                         RPCResult::Type::ARR, "", "",
1462                         {
1463                             {RPCResult::Type::OBJ, "", "",
1464                             {
1465                                 {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
1466                                 {RPCResult::Type::STR, "sender", CURRENCY_UNIT + " address of the sender"},
1467                                 {RPCResult::Type::STR_HEX, "hash160", "Ripemd-160 hash of the sender"},
1468                             }},
1469                         }
1470                     },
1471                     RPCExamples{
1472                     HelpExampleCli("sendtocontract", "\"c6ca2697719d00446d4ea51f6fac8fd1e9310214\" \"54f6127f\"")
1473                     + HelpExampleCli("sendtocontract", "\"c6ca2697719d00446d4ea51f6fac8fd1e9310214\" \"54f6127f\" 12.0015 6000000 "+FormatMoney(minGasPrice)+" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"")
1474                     },
1475                 }.Check(request);
1476 
1477     return SendToContract(*locked_chain, pwallet, spk_man, request.params);
1478 }
1479 
removedelegationforaddress(const JSONRPCRequest & request)1480 static UniValue removedelegationforaddress(const JSONRPCRequest& request){
1481 
1482     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1483     CWallet* const pwallet = wallet.get();
1484 
1485     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1486         return NullUniValue;
1487     }
1488 
1489     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
1490     auto locked_chain = pwallet->chain().lock();
1491     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
1492     QtumDGP qtumDGP(globalState.get(), fGettingValuesDGP);
1493     uint64_t blockGasLimit = qtumDGP.getBlockGasLimit(::ChainActive().Height());
1494     uint64_t minGasPrice = CAmount(qtumDGP.getMinGasPrice(::ChainActive().Height()));
1495     CAmount nGasPrice = (minGasPrice>DEFAULT_GAS_PRICE)?minGasPrice:DEFAULT_GAS_PRICE;
1496 
1497                 RPCHelpMan{"removedelegationforaddress",
1498                     "\nRemove delegation for address." +
1499                     HELP_REQUIRING_PASSPHRASE,
1500                     {
1501                         {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The qtum address to remove delegation, the address will be used as sender too."},
1502                         {"gasLimit", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "gasLimit, default: "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+", max: "+i64tostr(blockGasLimit)},
1503                         {"gasPrice", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "gasPrice Qtum price per gas unit, default: "+FormatMoney(nGasPrice)+", min:"+FormatMoney(minGasPrice)},
1504                     },
1505                     RPCResult{
1506                         RPCResult::Type::ARR, "", "",
1507                         {
1508                             {RPCResult::Type::OBJ, "", "",
1509                             {
1510                                 {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
1511                                 {RPCResult::Type::STR, "sender", CURRENCY_UNIT + " address of the sender"},
1512                                 {RPCResult::Type::STR_HEX, "hash160", "Ripemd-160 hash of the sender"},
1513                             }},
1514                         }
1515                     },
1516                     RPCExamples{
1517                     HelpExampleCli("removedelegationforaddress", " \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 6000000 "+FormatMoney(minGasPrice))
1518                     },
1519                 }.Check(request);
1520 
1521     // Get send to contract parameters for removing delegation for address
1522     UniValue params(UniValue::VARR);
1523     UniValue contractaddress = HexStr(Params().GetConsensus().delegationsAddress);
1524     UniValue datahex = QtumDelegation::BytecodeRemove();
1525     UniValue amount = 0;
1526     UniValue gasLimit = request.params.size() > 1 ? request.params[1] : DEFAULT_GAS_LIMIT_OP_SEND;
1527     UniValue gasPrice = request.params.size() > 2 ? request.params[2] : FormatMoney(nGasPrice);
1528     UniValue senderaddress = request.params[0];
1529 
1530     // Add the send to contract parameters to the list
1531     params.push_back(contractaddress);
1532     params.push_back(datahex);
1533     params.push_back(amount);
1534     params.push_back(gasLimit);
1535     params.push_back(gasPrice);
1536     params.push_back(senderaddress);
1537 
1538     // Send to contract
1539     return SendToContract(*locked_chain, pwallet, spk_man, params);
1540 }
1541 
setdelegateforaddress(const JSONRPCRequest & request)1542 static UniValue setdelegateforaddress(const JSONRPCRequest& request){
1543 
1544     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1545     CWallet* const pwallet = wallet.get();
1546 
1547     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1548         return NullUniValue;
1549     }
1550 
1551     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
1552     auto locked_chain = pwallet->chain().lock();
1553     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
1554     QtumDGP qtumDGP(globalState.get(), fGettingValuesDGP);
1555     uint64_t blockGasLimit = qtumDGP.getBlockGasLimit(::ChainActive().Height());
1556     uint64_t minGasPrice = CAmount(qtumDGP.getMinGasPrice(::ChainActive().Height()));
1557     CAmount nGasPrice = (minGasPrice>DEFAULT_GAS_PRICE)?minGasPrice:DEFAULT_GAS_PRICE;
1558 
1559                 RPCHelpMan{"setdelegateforaddress",
1560                     "\nSet delegate for address." +
1561                     HELP_REQUIRING_PASSPHRASE,
1562                     {
1563                         {"staker", RPCArg::Type::STR, RPCArg::Optional::NO, "The qtum address for the staker."},
1564                         {"fee", RPCArg::Type::NUM, RPCArg::Optional::NO, "Percentage of the reward that will be paid to the staker."},
1565                         {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The qtum address that contain the coins that will be delegated to the staker, the address will be used as sender too."},
1566                         {"gasLimit", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "gasLimit, default: "+i64tostr(DEFAULT_GAS_LIMIT_OP_CREATE)+", max: "+i64tostr(blockGasLimit)},
1567                         {"gasPrice", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "gasPrice Qtum price per gas unit, default: "+FormatMoney(nGasPrice)+", min:"+FormatMoney(minGasPrice)},
1568                     },
1569                     RPCResult{
1570                         RPCResult::Type::ARR, "", "",
1571                         {
1572                             {RPCResult::Type::OBJ, "", "",
1573                             {
1574                                 {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
1575                                 {RPCResult::Type::STR, "sender", CURRENCY_UNIT + " address of the sender"},
1576                                 {RPCResult::Type::STR_HEX, "hash160", "Ripemd-160 hash of the sender"},
1577                             }},
1578                         }
1579                     },
1580                     RPCExamples{
1581                     HelpExampleCli("setdelegateforaddress", " \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 10 \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" 6000000 "+FormatMoney(minGasPrice))
1582                     },
1583                 }.Check(request);
1584 
1585     // Get send to contract parameters for add delegation for address
1586     UniValue params(UniValue::VARR);
1587     UniValue contractaddress = HexStr(Params().GetConsensus().delegationsAddress);
1588     UniValue amount = 0;
1589     UniValue gasLimit = request.params.size() > 3 ? request.params[3] : DEFAULT_GAS_LIMIT_OP_CREATE;
1590     UniValue gasPrice = request.params.size() > 4 ? request.params[4] : FormatMoney(nGasPrice);
1591     UniValue senderaddress = request.params[2];
1592 
1593     // Parse the staker address
1594     CTxDestination destStaker = DecodeDestination(request.params[0].get_str());
1595     const PKHash *pkhStaker = boost::get<PKHash>(&destStaker);
1596     if (!pkhStaker) {
1597         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid contract address for staker. Only P2PK and P2PKH allowed");
1598     }
1599 
1600     // Parse the staker fee
1601     int fee = request.params[1].get_int();
1602     if(fee < 0 || fee > 100)
1603         throw JSONRPCError(RPC_PARSE_ERROR, "The staker fee need to be between 0 and 100");
1604 
1605     // Parse the sender address
1606     CTxDestination destSender = DecodeDestination(senderaddress.get_str());
1607     const PKHash *pkhSender = boost::get<PKHash>(&destSender);
1608     if (!pkhSender) {
1609         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid contract sender address. Only P2PK and P2PKH allowed");
1610     }
1611 
1612     // Get the private key for the sender address
1613     CKey key;
1614     CKeyID keyID(*pkhSender);
1615     if (!spk_man.GetKey(keyID, key)) {
1616         throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available for the sender address");
1617     }
1618 
1619     // Sign the  staker address
1620     std::vector<unsigned char> PoD;
1621     std::string hexStaker =  pkhStaker->GetReverseHex();
1622     if(!SignStr::SignMessage(key, hexStaker, PoD))
1623         throw JSONRPCError(RPC_WALLET_ERROR, "Fail to sign the staker address");
1624 
1625     // Serialize the data
1626     std::string datahex;
1627     std::string errorMessage;
1628     if(!QtumDelegation::BytecodeAdd(hexStaker, fee, PoD, datahex, errorMessage))
1629         throw JSONRPCError(RPC_TYPE_ERROR, errorMessage);
1630 
1631     // Add the send to contract parameters to the list
1632     params.push_back(contractaddress);
1633     params.push_back(datahex);
1634     params.push_back(amount);
1635     params.push_back(gasLimit);
1636     params.push_back(gasPrice);
1637     params.push_back(senderaddress);
1638 
1639     // Send to contract
1640     return SendToContract(*locked_chain, pwallet, spk_man, params);
1641 }
1642 
GetJsonSuperStakerConfig(const CSuperStakerInfo & superStaker)1643 UniValue GetJsonSuperStakerConfig(const CSuperStakerInfo& superStaker)
1644 {
1645     // Fill the json object with information
1646     UniValue result(UniValue::VOBJ);
1647     result.pushKV("address", EncodeDestination(PKHash(superStaker.stakerAddress)));
1648     result.pushKV("customconfig", superStaker.fCustomConfig);
1649     if(superStaker.fCustomConfig)
1650     {
1651         result.pushKV("stakingminfee", (int64_t)superStaker.nMinFee);
1652         result.pushKV("stakingminutxovalue", FormatMoney(superStaker.nMinDelegateUtxo));
1653         UniValue addressList(UniValue::VARR);
1654         for(uint160 address : superStaker.delegateAddressList)
1655         {
1656             addressList.push_back(EncodeDestination(PKHash(address)));
1657         }
1658         if(interfaces::AllowList == superStaker.nDelegateAddressType)
1659         {
1660             result.pushKV("allow", addressList);
1661         }
1662         if(interfaces::ExcludeList == superStaker.nDelegateAddressType)
1663         {
1664             result.pushKV("exclude", addressList);
1665         }
1666     }
1667 
1668     return result;
1669 }
1670 
setsuperstakervaluesforaddress(const JSONRPCRequest & request)1671 static UniValue setsuperstakervaluesforaddress(const JSONRPCRequest& request){
1672 
1673     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1674     CWallet* const pwallet = wallet.get();
1675 
1676     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1677         return NullUniValue;
1678     }
1679 
1680     auto locked_chain = pwallet->chain().lock();
1681     LOCK(pwallet->cs_wallet);
1682                 RPCHelpMan{"setsuperstakervaluesforaddress",
1683                     "\nList super staker configuration values for address." +
1684                     HELP_REQUIRING_PASSPHRASE,
1685                     {
1686                         {"", RPCArg::Type::OBJ, RPCArg::Optional::NO, "",
1687                             {
1688                                 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The address of the staker"},
1689                                 {"stakingminutxovalue", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The output number"},
1690                                 {"stakingminfee", RPCArg::Type::NUM, RPCArg::Optional::NO, "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"},
1691                                 {"allow", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "A json array with allow delegate addresses.",
1692                                     {
1693                                         {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The delegate address"},
1694                                     },
1695                                 },
1696                                 {"exclude", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "A json array with exclude delegate addresses.",
1697                                     {
1698                                         {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The delegate address"},
1699                                     },
1700                                 },
1701                             },
1702                          },
1703                     },
1704                     RPCResult{
1705                     RPCResult::Type::ARR, "", "",
1706                     {
1707                             {RPCResult::Type::OBJ, "", "",
1708                                     {
1709                                             {RPCResult::Type::STR, "address", "Address of the staker."},
1710                                             {RPCResult::Type::BOOL, "customconfig", "Custom configuration exist."},
1711                                             {RPCResult::Type::NUM, "stakingminfee", "Minimum fee for delegate."},
1712                                             {RPCResult::Type::NUM, "stakingminutxovalue", "Minimum UTXO value for delegate."},
1713                                             {RPCResult::Type::ARR, "allow", "List of allowed delegate addresses.",
1714                                                     {
1715                                                             {RPCResult::Type::STR, "address", "The delegate address"},
1716                                                     },
1717                                             },
1718                                             {RPCResult::Type::ARR, "exclude", "List of excluded delegate addresses.",
1719                                                     {
1720                                                             {RPCResult::Type::STR, "address", "The delegate address"},
1721                                                     },
1722                                             },
1723                                     }},
1724                     }
1725                 },
1726                     RPCExamples{
1727                         HelpExampleCli("setsuperstakervaluesforaddress", "\"{\\\"address\\\":\\\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\",\\\"stakingminutxovalue\\\": \\\"100\\\",\\\"stakingminfee\\\": 10}\"")
1728                         + HelpExampleCli("setsuperstakervaluesforaddress", "\"{\\\"address\\\":\\\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\",\\\"stakingminutxovalue\\\": \\\"100\\\",\\\"stakingminfee\\\": 10,\\\"allow\\\":[\\\"QD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\"]}\"")
1729                         + HelpExampleCli("setsuperstakervaluesforaddress", "\"{\\\"address\\\":\\\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\",\\\"stakingminutxovalue\\\": \\\"100\\\",\\\"stakingminfee\\\": 10,\\\"exclude\\\":[\\\"QD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\"]}\"")
1730                         + HelpExampleRpc("setsuperstakervaluesforaddress", "\"{\\\"address\\\":\\\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\",\\\"stakingminutxovalue\\\": \\\"100\\\",\\\"stakingminfee\\\": 10}\"")
1731                         + HelpExampleRpc("setsuperstakervaluesforaddress", "\"{\\\"address\\\":\\\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\",\\\"stakingminutxovalue\\\": \\\"100\\\",\\\"stakingminfee\\\": 10,\\\"allow\\\":[\\\"QD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\"]}\"")
1732                         + HelpExampleRpc("setsuperstakervaluesforaddress", "\"{\\\"address\\\":\\\"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\\\",\\\"stakingminutxovalue\\\": \\\"100\\\",\\\"stakingminfee\\\": 10,\\\"exclude\\\":[\\\"QD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\"]}\"")
1733                     },
1734                 }.Check(request);
1735 
1736     // Get params for the super staker
1737     UniValue params(UniValue::VOBJ);
1738     params = request.params[0].get_obj();
1739 
1740     // Parse the super staker address
1741     if(!params.exists("address"))
1742         throw JSONRPCError(RPC_TYPE_ERROR, "The super staker address doesn't exist");
1743     CTxDestination destStaker = DecodeDestination(params["address"].get_str());
1744     const PKHash *pkhStaker = boost::get<PKHash>(&destStaker);
1745     if (!pkhStaker) {
1746         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address for staker. Only P2PK and P2PKH allowed");
1747     }
1748 
1749     // Parse the staking min utxo value
1750     if(!params.exists("stakingminutxovalue"))
1751         throw JSONRPCError(RPC_TYPE_ERROR, "The staking min utxo value doesn't exist");
1752     CAmount nMinUtxoValue = AmountFromValue(params["stakingminutxovalue"]);
1753     if (nMinUtxoValue < 0)
1754         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for staking min utxo value");
1755 
1756     // Parse the staking min fee
1757     if(!params.exists("stakingminfee"))
1758         throw JSONRPCError(RPC_TYPE_ERROR, "The staking min fee doesn't exist");
1759     CAmount nMinFee = params["stakingminfee"].get_int();
1760     if (nMinFee < 0 || nMinFee > 100)
1761         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value for staking min fee");
1762 
1763     // Parse the delegation address lists
1764     if(params.exists("allow") && params.exists("exclude"))
1765         throw JSONRPCError(RPC_TYPE_ERROR, "The delegation address lists can be empty, or have either allow list or exclude list");
1766 
1767     // Parse the delegation address lists
1768     int nDelegateAddressType = interfaces::AcceptAll;
1769     std::vector<UniValue> addressList;
1770     if(params.exists("allow"))
1771     {
1772         addressList = params["allow"].get_array().getValues();
1773         nDelegateAddressType = interfaces::AllowList;
1774     }
1775     else if(params.exists("exclude"))
1776     {
1777         addressList = params["exclude"].get_array().getValues();
1778         nDelegateAddressType = interfaces::ExcludeList;
1779     }
1780     std::vector<uint160> delegateAddressList;
1781     for(UniValue address : addressList)
1782     {
1783         CTxDestination destAddress = DecodeDestination(address.get_str());
1784         const PKHash *pkhAddress = boost::get<PKHash>(&destAddress);
1785         if (!pkhAddress) {
1786             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address for delegate in allow list or exclude list. Only P2PK and P2PKH allowed");
1787         }
1788         delegateAddressList.push_back(uint160(*pkhAddress));
1789     }
1790 
1791     // Search for super staker
1792     CSuperStakerInfo superStaker;
1793     bool found = false;
1794     for(auto item : pwallet->mapSuperStaker)
1795     {
1796         if(PKHash(item.second.stakerAddress) == *pkhStaker)
1797         {
1798             superStaker = item.second;
1799             found = true;
1800             break;
1801         }
1802     }
1803 
1804     if(found)
1805     {
1806         // Set custom configuration
1807         superStaker.fCustomConfig = true;
1808         superStaker.nMinFee = nMinFee;
1809         superStaker.nMinDelegateUtxo = nMinUtxoValue;
1810         superStaker.nDelegateAddressType = nDelegateAddressType;
1811         superStaker.delegateAddressList = delegateAddressList;
1812 
1813         // Update super staker data
1814         if(!pwallet->AddSuperStakerEntry(superStaker))
1815             throw JSONRPCError(RPC_TYPE_ERROR, "Failed to update the super staker");
1816     }
1817     else
1818     {
1819         throw JSONRPCError(RPC_TYPE_ERROR, "Failed to find the super staker");
1820     }
1821 
1822     return GetJsonSuperStakerConfig(superStaker);
1823 }
1824 
listsuperstakercustomvalues(const JSONRPCRequest & request)1825 static UniValue listsuperstakercustomvalues(const JSONRPCRequest& request){
1826 
1827     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1828     CWallet* const pwallet = wallet.get();
1829 
1830     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1831         return NullUniValue;
1832     }
1833 
1834     auto locked_chain = pwallet->chain().lock();
1835     LOCK(pwallet->cs_wallet);
1836                 RPCHelpMan{"listsuperstakercustomvalues",
1837                     "\nList custom super staker configurations values." +
1838                     HELP_REQUIRING_PASSPHRASE,
1839                     {},
1840                     RPCResult{
1841                     RPCResult::Type::ARR, "", "",
1842                     {
1843                             {RPCResult::Type::OBJ, "", "",
1844                                     {
1845                                             {RPCResult::Type::STR, "address", "Address of the staker."},
1846                                             {RPCResult::Type::BOOL, "customconfig", "Custom configuration exist."},
1847                                             {RPCResult::Type::NUM, "stakingminfee", "Minimum fee for delegate."},
1848                                             {RPCResult::Type::NUM, "stakingminutxovalue", "Minimum UTXO value for delegate."},
1849                                             {RPCResult::Type::ARR, "allow", "List of allowed delegate addresses.",
1850                                                     {
1851                                                             {RPCResult::Type::STR, "address", "The delegate address"},
1852                                                     },
1853                                             },
1854                                             {RPCResult::Type::ARR, "exclude", "List of excluded delegate addresses.",
1855                                                     {
1856                                                             {RPCResult::Type::STR, "address", "The delegate address"},
1857                                                     },
1858                                             },
1859                                     }},
1860                     }
1861                 },
1862                     RPCExamples{
1863                     HelpExampleCli("listsuperstakercustomvalues", "")
1864                     + HelpExampleRpc("listsuperstakercustomvalues", "")
1865                     },
1866                 }.Check(request);
1867 
1868     // Search for super stakers
1869     UniValue result(UniValue::VARR);
1870     for(auto item : pwallet->mapSuperStaker)
1871     {
1872         CSuperStakerInfo superStaker = item.second;
1873         if(superStaker.fCustomConfig)
1874         {
1875             result.push_back(GetJsonSuperStakerConfig(superStaker));
1876         }
1877     }
1878 
1879     return result;
1880 }
1881 
listsuperstakervaluesforaddress(const JSONRPCRequest & request)1882 static UniValue listsuperstakervaluesforaddress(const JSONRPCRequest& request){
1883 
1884     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1885     CWallet* const pwallet = wallet.get();
1886 
1887     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1888         return NullUniValue;
1889     }
1890 
1891     auto locked_chain = pwallet->chain().lock();
1892     LOCK(pwallet->cs_wallet);
1893                 RPCHelpMan{"listsuperstakervaluesforaddress",
1894                     "\nList super staker configuration values for address." +
1895                     HELP_REQUIRING_PASSPHRASE,
1896                     {
1897                         {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The super staker Qtum address."},
1898                     },
1899                     RPCResult{
1900                     RPCResult::Type::ARR, "", "",
1901                     {
1902                             {RPCResult::Type::OBJ, "", "",
1903                                     {
1904                                             {RPCResult::Type::STR, "address", "Address of the staker."},
1905                                             {RPCResult::Type::BOOL, "customconfig", "Custom configuration exist."},
1906                                             {RPCResult::Type::NUM, "stakingminfee", "Minimum fee for delegate."},
1907                                             {RPCResult::Type::NUM, "stakingminutxovalue", "Minimum UTXO value for delegate."},
1908                                             {RPCResult::Type::ARR, "allow", "List of allowed delegate addresses.",
1909                                                     {
1910                                                             {RPCResult::Type::STR, "address", "The delegate address"},
1911                                                     },
1912                                             },
1913                                             {RPCResult::Type::ARR, "exclude", "List of excluded delegate addresses.",
1914                                                     {
1915                                                             {RPCResult::Type::STR, "address", "The delegate address"},
1916                                                     },
1917                                             },
1918                                     }},
1919                     }
1920                 },
1921                     RPCExamples{
1922                     HelpExampleCli("listsuperstakervaluesforaddress", "QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd")
1923                     + HelpExampleRpc("listsuperstakervaluesforaddress", "QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd")
1924                     },
1925                 }.Check(request);
1926 
1927     // Parse the super staker address
1928     CTxDestination destStaker = DecodeDestination(request.params[0].get_str());
1929     const PKHash *pkhStaker = boost::get<PKHash>(&destStaker);
1930     if (!pkhStaker) {
1931         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address for staker. Only P2PK and P2PKH allowed");
1932     }
1933 
1934     // Search for super staker
1935     CSuperStakerInfo superStaker;
1936     bool found = false;
1937     for(auto item : pwallet->mapSuperStaker)
1938     {
1939         if(PKHash(item.second.stakerAddress) == *pkhStaker)
1940         {
1941             superStaker = item.second;
1942             found = true;
1943             break;
1944         }
1945     }
1946 
1947     if(!found)
1948     {
1949         throw JSONRPCError(RPC_TYPE_ERROR, "Failed to find the super staker");
1950     }
1951 
1952     return GetJsonSuperStakerConfig(superStaker);
1953 }
1954 
removesuperstakervaluesforaddress(const JSONRPCRequest & request)1955 static UniValue removesuperstakervaluesforaddress(const JSONRPCRequest& request){
1956 
1957     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1958     CWallet* const pwallet = wallet.get();
1959 
1960     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1961         return NullUniValue;
1962     }
1963 
1964     auto locked_chain = pwallet->chain().lock();
1965     LOCK(pwallet->cs_wallet);
1966                 RPCHelpMan{"removesuperstakervaluesforaddress",
1967                     "\nRemove super staker configuration values for address." +
1968                     HELP_REQUIRING_PASSPHRASE,
1969                     {
1970                         {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The super staker Qtum address."},
1971                     },
1972                     RPCResults{},
1973                     RPCExamples{
1974                     HelpExampleCli("removesuperstakervaluesforaddress", "QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd")
1975                     + HelpExampleRpc("removesuperstakervaluesforaddress", "QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd")
1976                     },
1977                 }.Check(request);
1978 
1979     // Parse the super staker address
1980     CTxDestination destStaker = DecodeDestination(request.params[0].get_str());
1981     const PKHash *pkhStaker = boost::get<PKHash>(&destStaker);
1982     if (!pkhStaker) {
1983         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address for staker. Only P2PK and P2PKH allowed");
1984     }
1985 
1986     // Search for super staker
1987     CSuperStakerInfo superStaker;
1988     bool found = false;
1989     for(auto item : pwallet->mapSuperStaker)
1990     {
1991         if(PKHash(item.second.stakerAddress) == *pkhStaker &&
1992                 item.second.fCustomConfig)
1993         {
1994             superStaker = item.second;
1995             found = true;
1996             break;
1997         }
1998     }
1999 
2000     if(found)
2001     {
2002         // Remove custom configuration
2003         superStaker.fCustomConfig = false;
2004         superStaker.nMinFee = 0;
2005         superStaker.nMinDelegateUtxo = 0;
2006         superStaker.nDelegateAddressType = 0;
2007         superStaker.delegateAddressList.clear();
2008 
2009         // Update super staker data
2010         if(!pwallet->AddSuperStakerEntry(superStaker))
2011             throw JSONRPCError(RPC_TYPE_ERROR, "Failed to update the super staker");
2012     }
2013     else
2014     {
2015         throw JSONRPCError(RPC_TYPE_ERROR, "Failed to find the super staker");
2016     }
2017 
2018     return NullUniValue;
2019 }
2020 
listaddressgroupings(const JSONRPCRequest & request)2021 static UniValue listaddressgroupings(const JSONRPCRequest& request)
2022 {
2023     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2024     const CWallet* const pwallet = wallet.get();
2025 
2026     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2027         return NullUniValue;
2028     }
2029 
2030             RPCHelpMan{"listaddressgroupings",
2031                 "\nLists groups of addresses which have had their common ownership\n"
2032                 "made public by common use as inputs or as the resulting change\n"
2033                 "in past transactions\n",
2034                 {},
2035                 RPCResult{
2036                     RPCResult::Type::ARR, "", "",
2037                     {
2038                         {RPCResult::Type::ARR, "", "",
2039                         {
2040                             {RPCResult::Type::ARR, "", "",
2041                             {
2042                                 {RPCResult::Type::STR, "address", "The qtum address"},
2043                                 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
2044                                 {RPCResult::Type::STR, "label", /* optional */ true, "The label"},
2045                             }},
2046                         }},
2047                     }
2048                 },
2049                 RPCExamples{
2050                     HelpExampleCli("listaddressgroupings", "")
2051             + HelpExampleRpc("listaddressgroupings", "")
2052                 },
2053             }.Check(request);
2054 
2055     // Make sure the results are valid at least up to the most recent block
2056     // the user could have gotten from another RPC command prior to now
2057     pwallet->BlockUntilSyncedToCurrentChain();
2058 
2059     auto locked_chain = pwallet->chain().lock();
2060     LOCK(pwallet->cs_wallet);
2061 
2062     UniValue jsonGroupings(UniValue::VARR);
2063     std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances(*locked_chain);
2064     for (const std::set<CTxDestination>& grouping : pwallet->GetAddressGroupings()) {
2065         UniValue jsonGrouping(UniValue::VARR);
2066         for (const CTxDestination& address : grouping)
2067         {
2068             UniValue addressInfo(UniValue::VARR);
2069             addressInfo.push_back(EncodeDestination(address));
2070             addressInfo.push_back(ValueFromAmount(balances[address]));
2071             {
2072                 const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
2073                 if (address_book_entry) {
2074                     addressInfo.push_back(address_book_entry->GetLabel());
2075                 }
2076             }
2077             jsonGrouping.push_back(addressInfo);
2078         }
2079         jsonGroupings.push_back(jsonGrouping);
2080     }
2081     return jsonGroupings;
2082 }
2083 
signmessage(const JSONRPCRequest & request)2084 static UniValue signmessage(const JSONRPCRequest& request)
2085 {
2086     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2087     const CWallet* const pwallet = wallet.get();
2088 
2089     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2090         return NullUniValue;
2091     }
2092 
2093             RPCHelpMan{"signmessage",
2094                 "\nSign a message with the private key of an address" +
2095         HELP_REQUIRING_PASSPHRASE,
2096                 {
2097                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The qtum address to use for the private key."},
2098                     {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
2099                 },
2100                 RPCResult{
2101                     RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
2102                 },
2103                 RPCExamples{
2104             "\nUnlock the wallet for 30 seconds\n"
2105             + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
2106             "\nCreate the signature\n"
2107             + HelpExampleCli("signmessage", "\"QD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
2108             "\nVerify the signature\n"
2109             + HelpExampleCli("verifymessage", "\"QD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
2110             "\nAs a JSON-RPC call\n"
2111             + HelpExampleRpc("signmessage", "\"QD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")
2112                 },
2113             }.Check(request);
2114 
2115     auto locked_chain = pwallet->chain().lock();
2116     LOCK(pwallet->cs_wallet);
2117 
2118     EnsureWalletIsUnlocked(pwallet);
2119 
2120     std::string strAddress = request.params[0].get_str();
2121     std::string strMessage = request.params[1].get_str();
2122 
2123     CTxDestination dest = DecodeDestination(strAddress);
2124     if (!IsValidDestination(dest)) {
2125         throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
2126     }
2127 
2128     const PKHash *pkhash = boost::get<PKHash>(&dest);
2129     if (!pkhash) {
2130         throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
2131     }
2132 
2133     std::string signature;
2134     SigningResult err = pwallet->SignMessage(strMessage, *pkhash, signature);
2135     if (err == SigningResult::SIGNING_FAILED) {
2136         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, SigningResultString(err));
2137     } else if (err != SigningResult::OK){
2138         throw JSONRPCError(RPC_WALLET_ERROR, SigningResultString(err));
2139     }
2140 
2141     return signature;
2142 }
2143 
getreceivedbyaddress(const JSONRPCRequest & request)2144 static UniValue getreceivedbyaddress(const JSONRPCRequest& request)
2145 {
2146     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2147     const CWallet* const pwallet = wallet.get();
2148 
2149     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2150         return NullUniValue;
2151     }
2152 
2153             RPCHelpMan{"getreceivedbyaddress",
2154                 "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n",
2155                 {
2156                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The qtum address for transactions."},
2157                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only include transactions confirmed at least this many times."},
2158                 },
2159                 RPCResult{
2160                     RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received at this address."
2161                 },
2162                 RPCExamples{
2163             "\nThe amount from transactions with at least 1 confirmation\n"
2164             + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"") +
2165             "\nThe amount including unconfirmed transactions, zero confirmations\n"
2166             + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0") +
2167             "\nThe amount with at least 6 confirmations, very safe\n"
2168             + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 6") +
2169             "\nAs a JSON-RPC call\n"
2170             + HelpExampleRpc("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 6")
2171                 },
2172             }.Check(request);
2173 
2174     // Make sure the results are valid at least up to the most recent block
2175     // the user could have gotten from another RPC command prior to now
2176     pwallet->BlockUntilSyncedToCurrentChain();
2177 
2178     auto locked_chain = pwallet->chain().lock();
2179     LOCK(pwallet->cs_wallet);
2180 
2181     // Bitcoin address
2182     CTxDestination dest = DecodeDestination(request.params[0].get_str());
2183     if (!IsValidDestination(dest)) {
2184         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Qtum address");
2185     }
2186     CScript scriptPubKey = GetScriptForDestination(dest);
2187     if (!pwallet->IsMine(scriptPubKey)) {
2188         throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
2189     }
2190 
2191     // Minimum confirmations
2192     int nMinDepth = 1;
2193     if (!request.params[1].isNull())
2194         nMinDepth = request.params[1].get_int();
2195 
2196     // Tally
2197     CAmount nAmount = 0;
2198     for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
2199         const CWalletTx& wtx = pairWtx.second;
2200         if (wtx.IsCoinBase() || wtx.IsCoinStake() || !locked_chain->checkFinalTx(*wtx.tx)) {
2201             continue;
2202         }
2203 
2204         for (const CTxOut& txout : wtx.tx->vout)
2205             if (txout.scriptPubKey == scriptPubKey)
2206                 if (wtx.GetDepthInMainChain() >= nMinDepth)
2207                     nAmount += txout.nValue;
2208     }
2209 
2210     return  ValueFromAmount(nAmount);
2211 }
2212 
2213 
getreceivedbylabel(const JSONRPCRequest & request)2214 static UniValue getreceivedbylabel(const JSONRPCRequest& request)
2215 {
2216     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2217     const CWallet* const pwallet = wallet.get();
2218 
2219     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2220         return NullUniValue;
2221     }
2222 
2223             RPCHelpMan{"getreceivedbylabel",
2224                 "\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n",
2225                 {
2226                     {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The selected label, may be the default label using \"\"."},
2227                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only include transactions confirmed at least this many times."},
2228                 },
2229                 RPCResult{
2230                     RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this label."
2231                 },
2232                 RPCExamples{
2233             "\nAmount received by the default label with at least 1 confirmation\n"
2234             + HelpExampleCli("getreceivedbylabel", "\"\"") +
2235             "\nAmount received at the tabby label including unconfirmed amounts with zero confirmations\n"
2236             + HelpExampleCli("getreceivedbylabel", "\"tabby\" 0") +
2237             "\nThe amount with at least 6 confirmations\n"
2238             + HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") +
2239             "\nAs a JSON-RPC call\n"
2240             + HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6")
2241                 },
2242             }.Check(request);
2243 
2244     // Make sure the results are valid at least up to the most recent block
2245     // the user could have gotten from another RPC command prior to now
2246     pwallet->BlockUntilSyncedToCurrentChain();
2247 
2248     auto locked_chain = pwallet->chain().lock();
2249     LOCK(pwallet->cs_wallet);
2250 
2251     // Minimum confirmations
2252     int nMinDepth = 1;
2253     if (!request.params[1].isNull())
2254         nMinDepth = request.params[1].get_int();
2255 
2256     // Get the set of pub keys assigned to label
2257     std::string label = LabelFromValue(request.params[0]);
2258     std::set<CTxDestination> setAddress = pwallet->GetLabelAddresses(label);
2259 
2260     // Tally
2261     CAmount nAmount = 0;
2262     for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
2263         const CWalletTx& wtx = pairWtx.second;
2264         if (wtx.IsCoinBase() || wtx.IsCoinStake() || !locked_chain->checkFinalTx(*wtx.tx)) {
2265             continue;
2266         }
2267 
2268         for (const CTxOut& txout : wtx.tx->vout)
2269         {
2270             CTxDestination address;
2271             if (ExtractDestination(txout.scriptPubKey, address) && pwallet->IsMine(address) && setAddress.count(address)) {
2272                 if (wtx.GetDepthInMainChain() >= nMinDepth)
2273                     nAmount += txout.nValue;
2274             }
2275         }
2276     }
2277 
2278     return ValueFromAmount(nAmount);
2279 }
2280 
2281 
getbalance(const JSONRPCRequest & request)2282 static UniValue getbalance(const JSONRPCRequest& request)
2283 {
2284     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2285     const CWallet* const pwallet = wallet.get();
2286 
2287     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2288         return NullUniValue;
2289     }
2290 
2291             RPCHelpMan{"getbalance",
2292                 "\nReturns the total available balance.\n"
2293                 "The available balance is what the wallet considers currently spendable, and is\n"
2294                 "thus affected by options which limit spendability such as -spendzeroconfchange.\n",
2295                 {
2296                     {"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Remains for backward compatibility. Must be excluded or set to \"*\"."},
2297                     {"minconf", RPCArg::Type::NUM, /* default */ "0", "Only include transactions confirmed at least this many times."},
2298                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also include balance in watch-only addresses (see 'importaddress')"},
2299                     {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."},
2300                 },
2301                 RPCResult{
2302                     RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this wallet."
2303                 },
2304                 RPCExamples{
2305             "\nThe total amount in the wallet with 1 or more confirmations\n"
2306             + HelpExampleCli("getbalance", "") +
2307             "\nThe total amount in the wallet at least 6 blocks confirmed\n"
2308             + HelpExampleCli("getbalance", "\"*\" 6") +
2309             "\nAs a JSON-RPC call\n"
2310             + HelpExampleRpc("getbalance", "\"*\", 6")
2311                 },
2312             }.Check(request);
2313 
2314     // Make sure the results are valid at least up to the most recent block
2315     // the user could have gotten from another RPC command prior to now
2316     pwallet->BlockUntilSyncedToCurrentChain();
2317 
2318     auto locked_chain = pwallet->chain().lock();
2319     LOCK(pwallet->cs_wallet);
2320 
2321     const UniValue& dummy_value = request.params[0];
2322     if (!dummy_value.isNull() && dummy_value.get_str() != "*") {
2323         throw JSONRPCError(RPC_METHOD_DEPRECATED, "dummy first argument must be excluded or set to \"*\".");
2324     }
2325 
2326     int min_depth = 0;
2327     if (!request.params[1].isNull()) {
2328         min_depth = request.params[1].get_int();
2329     }
2330 
2331     bool include_watchonly = ParseIncludeWatchonly(request.params[2], *pwallet);
2332 
2333     bool avoid_reuse = GetAvoidReuseFlag(pwallet, request.params[3]);
2334 
2335     const auto bal = pwallet->GetBalance(min_depth, avoid_reuse);
2336 
2337     return ValueFromAmount(bal.m_mine_trusted + (include_watchonly ? bal.m_watchonly_trusted : 0));
2338 }
2339 
getunconfirmedbalance(const JSONRPCRequest & request)2340 static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
2341 {
2342     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2343     const CWallet* const pwallet = wallet.get();
2344 
2345     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2346         return NullUniValue;
2347     }
2348 
2349             RPCHelpMan{"getunconfirmedbalance",
2350                 "DEPRECATED\nIdentical to getbalances().mine.untrusted_pending\n",
2351                 {},
2352                 RPCResult{RPCResult::Type::NUM, "", "The balance"},
2353                 RPCExamples{""},
2354             }.Check(request);
2355 
2356     // Make sure the results are valid at least up to the most recent block
2357     // the user could have gotten from another RPC command prior to now
2358     pwallet->BlockUntilSyncedToCurrentChain();
2359 
2360     auto locked_chain = pwallet->chain().lock();
2361     LOCK(pwallet->cs_wallet);
2362 
2363     return ValueFromAmount(pwallet->GetBalance().m_mine_untrusted_pending);
2364 }
2365 
2366 
sendmany(const JSONRPCRequest & request)2367 static UniValue sendmany(const JSONRPCRequest& request)
2368 {
2369     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2370     CWallet* const pwallet = wallet.get();
2371 
2372     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2373         return NullUniValue;
2374     }
2375 
2376     RPCHelpMan{"sendmany",
2377                 "\nSend multiple times. Amounts are double-precision floating point numbers." +
2378         HELP_REQUIRING_PASSPHRASE,
2379                 {
2380                     {"dummy", RPCArg::Type::STR, RPCArg::Optional::NO, "Must be set to \"\" for backwards compatibility.", "\"\""},
2381                     {"amounts", RPCArg::Type::OBJ, RPCArg::Optional::NO, "The addresses and amounts",
2382                         {
2383                             {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The qtum address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"},
2384                         },
2385                     },
2386                     {"minconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "Ignored dummy value"},
2387                     {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment"},
2388                     {"subtractfeefrom", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The addresses.\n"
2389             "                           The fee will be equally deducted from the amount of each selected address.\n"
2390             "                           Those recipients will receive less qtums than you enter in their corresponding amount field.\n"
2391             "                           If no addresses are specified here, the sender pays the fee.",
2392                         {
2393                             {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Subtract fee from this address"},
2394                         },
2395                     },
2396                     {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
2397                     {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
2398                     {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
2399             "       \"UNSET\"\n"
2400             "       \"ECONOMICAL\"\n"
2401             "       \"CONSERVATIVE\""},
2402                 },
2403                  RPCResult{
2404                      RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of\n"
2405             "the number of addresses."
2406                  },
2407                 RPCExamples{
2408             "\nSend two amounts to two different addresses:\n"
2409             + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\"") +
2410             "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
2411             + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\" 6 \"testing\"") +
2412             "\nSend two amounts to two different addresses, subtract fee from amount:\n"
2413             + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\" 1 \"\" \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"") +
2414             "\nAs a JSON-RPC call\n"
2415             + HelpExampleRpc("sendmany", "\"\", {\"" + EXAMPLE_ADDRESS[0] + "\":0.01,\"" + EXAMPLE_ADDRESS[1] + "\":0.02}, 6, \"testing\"")
2416                 },
2417     }.Check(request);
2418 
2419     // Make sure the results are valid at least up to the most recent block
2420     // the user could have gotten from another RPC command prior to now
2421     pwallet->BlockUntilSyncedToCurrentChain();
2422 
2423     auto locked_chain = pwallet->chain().lock();
2424     LOCK(pwallet->cs_wallet);
2425 
2426     if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
2427         throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"\"");
2428     }
2429     UniValue sendTo = request.params[1].get_obj();
2430 
2431     mapValue_t mapValue;
2432     if (!request.params[3].isNull() && !request.params[3].get_str().empty())
2433         mapValue["comment"] = request.params[3].get_str();
2434 
2435     UniValue subtractFeeFromAmount(UniValue::VARR);
2436     if (!request.params[4].isNull())
2437         subtractFeeFromAmount = request.params[4].get_array();
2438 
2439     CCoinControl coin_control;
2440     if (!request.params[5].isNull()) {
2441         coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
2442     }
2443 
2444     if (!request.params[6].isNull()) {
2445         coin_control.m_confirm_target = ParseConfirmTarget(request.params[6], pwallet->chain().estimateMaxBlocks());
2446     }
2447 
2448     if (!request.params[7].isNull()) {
2449         if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
2450             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
2451         }
2452     }
2453 
2454     std::set<CTxDestination> destinations;
2455     std::vector<CRecipient> vecSend;
2456 
2457     std::vector<std::string> keys = sendTo.getKeys();
2458     for (const std::string& name_ : keys) {
2459         CTxDestination dest = DecodeDestination(name_);
2460         if (!IsValidDestination(dest)) {
2461             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Qtum address: ") + name_);
2462         }
2463 
2464         if (destinations.count(dest)) {
2465             throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
2466         }
2467         destinations.insert(dest);
2468 
2469         CScript scriptPubKey = GetScriptForDestination(dest);
2470         CAmount nAmount = AmountFromValue(sendTo[name_]);
2471         if (nAmount <= 0)
2472             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
2473 
2474         bool fSubtractFeeFromAmount = false;
2475         for (unsigned int idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
2476             const UniValue& addr = subtractFeeFromAmount[idx];
2477             if (addr.get_str() == name_)
2478                 fSubtractFeeFromAmount = true;
2479         }
2480 
2481         CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
2482         vecSend.push_back(recipient);
2483     }
2484 
2485     EnsureWalletIsUnlocked(pwallet);
2486 
2487     // Shuffle recipient list
2488     std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext());
2489 
2490     // Send
2491     CAmount nFeeRequired = 0;
2492     int nChangePosRet = -1;
2493     std::string strFailReason;
2494     CTransactionRef tx;
2495     bool fCreated = pwallet->CreateTransaction(*locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strFailReason, coin_control);
2496     if (!fCreated)
2497         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
2498     pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */);
2499     return tx->GetHash().GetHex();
2500 }
2501 
sendmanywithdupes(const JSONRPCRequest & request)2502 static UniValue sendmanywithdupes(const JSONRPCRequest& request)
2503 {
2504     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2505     CWallet* const pwallet = wallet.get();
2506 
2507     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2508         return NullUniValue;
2509     }
2510 
2511     RPCHelpMan{"sendmanywithdupes",
2512                 "\nSend multiple times. Amounts are double-precision floating point numbers. Supports duplicate addresses" +
2513                     HELP_REQUIRING_PASSPHRASE,
2514                 {
2515                     {"dummy", RPCArg::Type::STR, RPCArg::Optional::NO, "Must be set to \"\" for backwards compatibility.", "\"\""},
2516                     {"amounts", RPCArg::Type::OBJ, RPCArg::Optional::NO, "A json object with addresses and amounts",
2517                         {
2518                             {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The qtum address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"},
2519                         },
2520                     },
2521                     {"minconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "Ignored dummy value"},
2522                     {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment"},
2523                     {"subtractfeefrom", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array with addresses.\n"
2524             "                           The fee will be equally deducted from the amount of each selected address.\n"
2525             "                           Those recipients will receive less qtums than you enter in their corresponding amount field.\n"
2526             "                           If no addresses are specified here, the sender pays the fee.",
2527                         {
2528                             {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Subtract fee from this address"},
2529                         },
2530                     },
2531                     {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
2532                     {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
2533                     {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
2534             "       \"UNSET\"\n"
2535             "       \"ECONOMICAL\"\n"
2536             "       \"CONSERVATIVE\""},
2537                 },
2538                  RPCResult{
2539                      RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of\n"
2540             "the number of addresses."
2541                  },
2542                 RPCExamples{
2543             "\nSend two amounts to two different addresses:\n"
2544             + HelpExampleCli("sendmanywithdupes", "\"\" \"{\\\"QD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"Q353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
2545             "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
2546             + HelpExampleCli("sendmanywithdupes", "\"\" \"{\\\"QD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"Q353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
2547             "\nSend two amounts to two different addresses, subtract fee from amount:\n"
2548             + HelpExampleCli("sendmanywithdupes", "\"\" \"{\\\"QD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"Q353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"QD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\",\\\"Q353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
2549             "\nAs a JSON-RPC call\n"
2550             + HelpExampleRpc("sendmanywithdupes", "\"\", {\"QD1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"Q353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\"")
2551                 },
2552     }.Check(request);
2553 
2554     // Make sure the results are valid at least up to the most recent block
2555     // the user could have gotten from another RPC command prior to now
2556     pwallet->BlockUntilSyncedToCurrentChain();
2557 
2558     auto locked_chain = pwallet->chain().lock();
2559     LOCK(pwallet->cs_wallet);
2560 
2561     if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
2562         throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"\"");
2563     }
2564     UniValue sendTo = request.params[1].get_obj();
2565 
2566     mapValue_t mapValue;
2567     if (!request.params[3].isNull() && !request.params[3].get_str().empty())
2568         mapValue["comment"] = request.params[3].get_str();
2569 
2570     UniValue subtractFeeFromAmount(UniValue::VARR);
2571     if (!request.params[4].isNull())
2572         subtractFeeFromAmount = request.params[4].get_array();
2573 
2574     CCoinControl coin_control;
2575     if (!request.params[5].isNull()) {
2576         coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
2577     }
2578 
2579     if (!request.params[6].isNull()) {
2580         coin_control.m_confirm_target = ParseConfirmTarget(request.params[6], pwallet->chain().estimateMaxBlocks());
2581     }
2582 
2583     if (!request.params[7].isNull()) {
2584         if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
2585             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
2586         }
2587     }
2588 
2589     std::set<CTxDestination> destinations;
2590     std::vector<CRecipient> vecSend;
2591 
2592     std::vector<std::string> keys = sendTo.getKeys();
2593     int i=0;
2594     for (const std::string& name_ : keys) {
2595         CTxDestination dest = DecodeDestination(name_);
2596         if (!IsValidDestination(dest)) {
2597             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Qtum address: ") + name_);
2598         }
2599 
2600         destinations.insert(dest);
2601 
2602         CScript scriptPubKey = GetScriptForDestination(dest);
2603         CAmount nAmount = AmountFromValue(sendTo[i]);
2604         if (nAmount <= 0)
2605             throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
2606 
2607         bool fSubtractFeeFromAmount = false;
2608         for (unsigned int idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
2609             const UniValue& addr = subtractFeeFromAmount[idx];
2610             if (addr.get_str() == name_)
2611                 fSubtractFeeFromAmount = true;
2612         }
2613 
2614         CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
2615         vecSend.push_back(recipient);
2616         i++;
2617     }
2618 
2619     EnsureWalletIsUnlocked(pwallet);
2620 
2621     // Shuffle recipient list
2622     std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext());
2623 
2624     // Send
2625     CAmount nFeeRequired = 0;
2626     int nChangePosRet = -1;
2627     std::string strFailReason;
2628     CTransactionRef tx;
2629     bool fCreated = pwallet->CreateTransaction(*locked_chain, vecSend, tx, nFeeRequired, nChangePosRet, strFailReason, coin_control);
2630     if (!fCreated)
2631         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
2632     pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */);
2633 
2634     return tx->GetHash().GetHex();
2635 }
2636 
addmultisigaddress(const JSONRPCRequest & request)2637 static UniValue addmultisigaddress(const JSONRPCRequest& request)
2638 {
2639     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2640     CWallet* const pwallet = wallet.get();
2641 
2642     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2643         return NullUniValue;
2644     }
2645 
2646             RPCHelpMan{"addmultisigaddress",
2647                 "\nAdd an nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n"
2648                 "Each key is a Qtum address or hex-encoded public key.\n"
2649                 "This functionality is only intended for use with non-watchonly addresses.\n"
2650                 "See `importaddress` for watchonly p2sh address support.\n"
2651                 "If 'label' is specified, assign address to that label.\n",
2652                 {
2653                     {"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, "The number of required signatures out of the n keys or addresses."},
2654                     {"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "A json array of qtum addresses or hex-encoded public keys",
2655                         {
2656                             {"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "qtum address or hex-encoded public key"},
2657                         },
2658                         },
2659                     {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A label to assign the addresses to."},
2660                     {"address_type", RPCArg::Type::STR, /* default */ "set by -addresstype", "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
2661                 },
2662                 RPCResult{
2663                     RPCResult::Type::OBJ, "", "",
2664                     {
2665                         {RPCResult::Type::STR, "address", "The value of the new multisig address"},
2666                         {RPCResult::Type::STR_HEX, "redeemScript", "The string value of the hex-encoded redemption script"},
2667                         {RPCResult::Type::STR, "descriptor", "The descriptor for this multisig"},
2668                     }
2669                 },
2670                 RPCExamples{
2671             "\nAdd a multisig address from 2 addresses\n"
2672             + HelpExampleCli("addmultisigaddress", "2 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"") +
2673             "\nAs a JSON-RPC call\n"
2674             + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"")
2675                 },
2676             }.Check(request);
2677 
2678     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
2679 
2680     auto locked_chain = pwallet->chain().lock();
2681     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
2682 
2683     std::string label;
2684     if (!request.params[2].isNull())
2685         label = LabelFromValue(request.params[2]);
2686 
2687     int required = request.params[0].get_int();
2688 
2689     // Get the public keys
2690     const UniValue& keys_or_addrs = request.params[1].get_array();
2691     std::vector<CPubKey> pubkeys;
2692     for (unsigned int i = 0; i < keys_or_addrs.size(); ++i) {
2693         if (IsHex(keys_or_addrs[i].get_str()) && (keys_or_addrs[i].get_str().length() == 66 || keys_or_addrs[i].get_str().length() == 130)) {
2694             pubkeys.push_back(HexToPubKey(keys_or_addrs[i].get_str()));
2695         } else {
2696             pubkeys.push_back(AddrToPubKey(spk_man, keys_or_addrs[i].get_str()));
2697         }
2698     }
2699 
2700     OutputType output_type = pwallet->m_default_address_type;
2701     if (!request.params[3].isNull()) {
2702         if (!ParseOutputType(request.params[3].get_str(), output_type)) {
2703             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str()));
2704         }
2705     }
2706 
2707     // Construct using pay-to-script-hash:
2708     CScript inner;
2709     CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, spk_man, inner);
2710     pwallet->SetAddressBook(dest, label, "send");
2711 
2712     // Make the descriptor
2713     std::unique_ptr<Descriptor> descriptor = InferDescriptor(GetScriptForDestination(dest), spk_man);
2714 
2715     UniValue result(UniValue::VOBJ);
2716     result.pushKV("address", EncodeDestination(dest));
2717     result.pushKV("redeemScript", HexStr(inner.begin(), inner.end()));
2718     result.pushKV("descriptor", descriptor->ToString());
2719     return result;
2720 }
2721 
2722 struct tallyitem
2723 {
2724     CAmount nAmount{0};
2725     int nConf{std::numeric_limits<int>::max()};
2726     std::vector<uint256> txids;
2727     bool fIsWatchonly{false};
tallyitemtallyitem2728     tallyitem()
2729     {
2730     }
2731 };
2732 
ListReceived(interfaces::Chain::Lock & locked_chain,const CWallet * const pwallet,const UniValue & params,bool by_label)2733 static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, const CWallet* const pwallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
2734 {
2735     // Minimum confirmations
2736     int nMinDepth = 1;
2737     if (!params[0].isNull())
2738         nMinDepth = params[0].get_int();
2739 
2740     // Whether to include empty labels
2741     bool fIncludeEmpty = false;
2742     if (!params[1].isNull())
2743         fIncludeEmpty = params[1].get_bool();
2744 
2745     isminefilter filter = ISMINE_SPENDABLE;
2746 
2747     if (ParseIncludeWatchonly(params[2], *pwallet)) {
2748         filter |= ISMINE_WATCH_ONLY;
2749     }
2750 
2751     bool has_filtered_address = false;
2752     CTxDestination filtered_address = CNoDestination();
2753     if (!by_label && params.size() > 3) {
2754         if (!IsValidDestinationString(params[3].get_str())) {
2755             throw JSONRPCError(RPC_WALLET_ERROR, "address_filter parameter was invalid");
2756         }
2757         filtered_address = DecodeDestination(params[3].get_str());
2758         has_filtered_address = true;
2759     }
2760 
2761     // Tally
2762     std::map<CTxDestination, tallyitem> mapTally;
2763     for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
2764         const CWalletTx& wtx = pairWtx.second;
2765 
2766         if (wtx.IsCoinBase() || wtx.IsCoinStake() || !locked_chain.checkFinalTx(*wtx.tx)) {
2767             continue;
2768         }
2769 
2770         int nDepth = wtx.GetDepthInMainChain();
2771         if (nDepth < nMinDepth)
2772             continue;
2773 
2774         for (const CTxOut& txout : wtx.tx->vout)
2775         {
2776             CTxDestination address;
2777             if (!ExtractDestination(txout.scriptPubKey, address))
2778                 continue;
2779 
2780             if (has_filtered_address && !(filtered_address == address)) {
2781                 continue;
2782             }
2783 
2784             isminefilter mine = pwallet->IsMine(address);
2785             if(!(mine & filter))
2786                 continue;
2787 
2788             tallyitem& item = mapTally[address];
2789             item.nAmount += txout.nValue;
2790             item.nConf = std::min(item.nConf, nDepth);
2791             item.txids.push_back(wtx.GetHash());
2792             if (mine & ISMINE_WATCH_ONLY)
2793                 item.fIsWatchonly = true;
2794         }
2795     }
2796 
2797     // Reply
2798     UniValue ret(UniValue::VARR);
2799     std::map<std::string, tallyitem> label_tally;
2800 
2801     // Create m_address_book iterator
2802     // If we aren't filtering, go from begin() to end()
2803     auto start = pwallet->m_address_book.begin();
2804     auto end = pwallet->m_address_book.end();
2805     // If we are filtering, find() the applicable entry
2806     if (has_filtered_address) {
2807         start = pwallet->m_address_book.find(filtered_address);
2808         if (start != end) {
2809             end = std::next(start);
2810         }
2811     }
2812 
2813     for (auto item_it = start; item_it != end; ++item_it)
2814     {
2815         if (item_it->second.IsChange()) continue;
2816         const CTxDestination& address = item_it->first;
2817         const std::string& label = item_it->second.GetLabel();
2818         auto it = mapTally.find(address);
2819         if (it == mapTally.end() && !fIncludeEmpty)
2820             continue;
2821 
2822         CAmount nAmount = 0;
2823         int nConf = std::numeric_limits<int>::max();
2824         bool fIsWatchonly = false;
2825         if (it != mapTally.end())
2826         {
2827             nAmount = (*it).second.nAmount;
2828             nConf = (*it).second.nConf;
2829             fIsWatchonly = (*it).second.fIsWatchonly;
2830         }
2831 
2832         if (by_label)
2833         {
2834             tallyitem& _item = label_tally[label];
2835             _item.nAmount += nAmount;
2836             _item.nConf = std::min(_item.nConf, nConf);
2837             _item.fIsWatchonly = fIsWatchonly;
2838         }
2839         else
2840         {
2841             UniValue obj(UniValue::VOBJ);
2842             if(fIsWatchonly)
2843                 obj.pushKV("involvesWatchonly", true);
2844             obj.pushKV("address",       EncodeDestination(address));
2845             obj.pushKV("amount",        ValueFromAmount(nAmount));
2846             obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
2847             obj.pushKV("label", label);
2848             UniValue transactions(UniValue::VARR);
2849             if (it != mapTally.end())
2850             {
2851                 for (const uint256& _item : (*it).second.txids)
2852                 {
2853                     transactions.push_back(_item.GetHex());
2854                 }
2855             }
2856             obj.pushKV("txids", transactions);
2857             ret.push_back(obj);
2858         }
2859     }
2860 
2861     if (by_label)
2862     {
2863         for (const auto& entry : label_tally)
2864         {
2865             CAmount nAmount = entry.second.nAmount;
2866             int nConf = entry.second.nConf;
2867             UniValue obj(UniValue::VOBJ);
2868             if (entry.second.fIsWatchonly)
2869                 obj.pushKV("involvesWatchonly", true);
2870             obj.pushKV("amount",        ValueFromAmount(nAmount));
2871             obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
2872             obj.pushKV("label",         entry.first);
2873             ret.push_back(obj);
2874         }
2875     }
2876 
2877     return ret;
2878 }
2879 
listreceivedbyaddress(const JSONRPCRequest & request)2880 static UniValue listreceivedbyaddress(const JSONRPCRequest& request)
2881 {
2882     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2883     const CWallet* const pwallet = wallet.get();
2884 
2885     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2886         return NullUniValue;
2887     }
2888 
2889             RPCHelpMan{"listreceivedbyaddress",
2890                 "\nList balances by receiving address.\n",
2891                 {
2892                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."},
2893                     {"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include addresses that haven't received any payments."},
2894                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses (see 'importaddress')"},
2895                     {"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If present, only return information on this address."},
2896                 },
2897                 RPCResult{
2898                     RPCResult::Type::ARR, "", "",
2899                     {
2900                         {RPCResult::Type::OBJ, "", "",
2901                         {
2902                             {RPCResult::Type::BOOL, "involvesWatchonly", "Only returns true if imported addresses were involved in transaction"},
2903                             {RPCResult::Type::STR, "address", "The receiving address"},
2904                             {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received by the address"},
2905                             {RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
2906                             {RPCResult::Type::STR, "label", "The label of the receiving address. The default label is \"\""},
2907                             {RPCResult::Type::ARR, "txids", "",
2908                             {
2909                                 {RPCResult::Type::STR_HEX, "txid", "The ids of transactions received with the address"},
2910                             }},
2911                         }},
2912                     }
2913                 },
2914                 RPCExamples{
2915                     HelpExampleCli("listreceivedbyaddress", "")
2916             + HelpExampleCli("listreceivedbyaddress", "6 true")
2917             + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
2918             + HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"" + EXAMPLE_ADDRESS[0] + "\"")
2919                 },
2920             }.Check(request);
2921 
2922     // Make sure the results are valid at least up to the most recent block
2923     // the user could have gotten from another RPC command prior to now
2924     pwallet->BlockUntilSyncedToCurrentChain();
2925 
2926     auto locked_chain = pwallet->chain().lock();
2927     LOCK(pwallet->cs_wallet);
2928 
2929     return ListReceived(*locked_chain, pwallet, request.params, false);
2930 }
2931 
listreceivedbylabel(const JSONRPCRequest & request)2932 static UniValue listreceivedbylabel(const JSONRPCRequest& request)
2933 {
2934     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2935     const CWallet* const pwallet = wallet.get();
2936 
2937     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2938         return NullUniValue;
2939     }
2940 
2941             RPCHelpMan{"listreceivedbylabel",
2942                 "\nList received transactions by label.\n",
2943                 {
2944                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum number of confirmations before payments are included."},
2945                     {"include_empty", RPCArg::Type::BOOL, /* default */ "false", "Whether to include labels that haven't received any payments."},
2946                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Whether to include watch-only addresses (see 'importaddress')"},
2947                 },
2948                 RPCResult{
2949                     RPCResult::Type::ARR, "", "",
2950                     {
2951                         {RPCResult::Type::OBJ, "", "",
2952                         {
2953                             {RPCResult::Type::BOOL, "involvesWatchonly", "Only returns true if imported addresses were involved in transaction"},
2954                             {RPCResult::Type::STR_AMOUNT, "amount", "The total amount received by addresses with this label"},
2955                             {RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
2956                             {RPCResult::Type::STR, "label", "The label of the receiving address. The default label is \"\""},
2957                         }},
2958                     }
2959                 },
2960                 RPCExamples{
2961                     HelpExampleCli("listreceivedbylabel", "")
2962             + HelpExampleCli("listreceivedbylabel", "6 true")
2963             + HelpExampleRpc("listreceivedbylabel", "6, true, true")
2964                 },
2965             }.Check(request);
2966 
2967     // Make sure the results are valid at least up to the most recent block
2968     // the user could have gotten from another RPC command prior to now
2969     pwallet->BlockUntilSyncedToCurrentChain();
2970 
2971     auto locked_chain = pwallet->chain().lock();
2972     LOCK(pwallet->cs_wallet);
2973 
2974     return ListReceived(*locked_chain, pwallet, request.params, true);
2975 }
2976 
MaybePushAddress(UniValue & entry,const CTxDestination & dest)2977 static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
2978 {
2979     if (IsValidDestination(dest)) {
2980         entry.pushKV("address", EncodeDestination(dest));
2981     }
2982 }
2983 
2984 /**
2985  * List transactions based on the given criteria.
2986  *
2987  * @param  pwallet        The wallet.
2988  * @param  wtx            The wallet transaction.
2989  * @param  nMinDepth      The minimum confirmation depth.
2990  * @param  fLong          Whether to include the JSON version of the transaction.
2991  * @param  ret            The UniValue into which the result is stored.
2992  * @param  filter_ismine  The "is mine" filter flags.
2993  * @param  filter_label   Optional label string to filter incoming transactions.
2994  */
ListTransactions(interfaces::Chain::Lock & locked_chain,const CWallet * const pwallet,const CWalletTx & wtx,int nMinDepth,bool fLong,UniValue & ret,const isminefilter & filter_ismine,const std::string * filter_label)2995 static void ListTransactions(interfaces::Chain::Lock& locked_chain, const CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
2996 {
2997     CAmount nFee;
2998     std::list<COutputEntry> listReceived;
2999     std::list<COutputEntry> listSent;
3000 
3001     wtx.GetAmounts(listReceived, listSent, nFee, filter_ismine);
3002 
3003     // Check if the coinstake transactions is mined by the wallet
3004     if(wtx.IsCoinStake() && listSent.size() > 0 && listReceived.size() > 0)
3005     {
3006         // Condense all of the coinstake inputs and outputs into one output and compute its value
3007         CAmount amount = wtx.GetCredit(filter_ismine) - wtx.GetDebit(filter_ismine);
3008         COutputEntry output = *listReceived.begin();
3009         output.amount = amount;
3010         listReceived.clear();
3011         listSent.clear();
3012         listReceived.push_back(output);
3013     }
3014 
3015     bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
3016 
3017     // Sent
3018     if (!filter_label)
3019     {
3020         for (const COutputEntry& s : listSent)
3021         {
3022             UniValue entry(UniValue::VOBJ);
3023             if (involvesWatchonly || (pwallet->IsMine(s.destination) & ISMINE_WATCH_ONLY)) {
3024                 entry.pushKV("involvesWatchonly", true);
3025             }
3026             MaybePushAddress(entry, s.destination);
3027             entry.pushKV("category", "send");
3028             entry.pushKV("amount", ValueFromAmount(-s.amount));
3029             const auto* address_book_entry = pwallet->FindAddressBookEntry(s.destination);
3030             if (address_book_entry) {
3031                 entry.pushKV("label", address_book_entry->GetLabel());
3032             }
3033             entry.pushKV("vout", s.vout);
3034             entry.pushKV("fee", ValueFromAmount(-nFee));
3035             if (fLong)
3036                 WalletTxToJSON(pwallet->chain(), locked_chain, wtx, entry);
3037             entry.pushKV("abandoned", wtx.isAbandoned());
3038             ret.push_back(entry);
3039         }
3040     }
3041 
3042     // Received
3043     if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) {
3044         for (const COutputEntry& r : listReceived)
3045         {
3046             std::string label;
3047             const auto* address_book_entry = pwallet->FindAddressBookEntry(r.destination);
3048             if (address_book_entry) {
3049                 label = address_book_entry->GetLabel();
3050             }
3051             if (filter_label && label != *filter_label) {
3052                 continue;
3053             }
3054             UniValue entry(UniValue::VOBJ);
3055             if (involvesWatchonly || (pwallet->IsMine(r.destination) & ISMINE_WATCH_ONLY)) {
3056                 entry.pushKV("involvesWatchonly", true);
3057             }
3058             MaybePushAddress(entry, r.destination);
3059             if (wtx.IsCoinBase() || wtx.IsCoinStake())
3060             {
3061                 if (wtx.GetDepthInMainChain() < 1)
3062                     entry.pushKV("category", "orphan");
3063                 else if (wtx.IsImmature())
3064                     entry.pushKV("category", "immature");
3065                 else
3066                     entry.pushKV("category", "generate");
3067             }
3068             else
3069             {
3070                 entry.pushKV("category", "receive");
3071             }
3072             entry.pushKV("amount", ValueFromAmount(r.amount));
3073             if (address_book_entry) {
3074                 entry.pushKV("label", label);
3075             }
3076             entry.pushKV("vout", r.vout);
3077             if (fLong)
3078                 WalletTxToJSON(pwallet->chain(), locked_chain, wtx, entry);
3079             ret.push_back(entry);
3080         }
3081     }
3082 }
3083 
TransactionDescriptionString()3084 static const std::vector<RPCResult> TransactionDescriptionString()
3085 {
3086     return{{RPCResult::Type::NUM, "confirmations", "The number of confirmations for the transaction. Negative confirmations means the\n"
3087                "transaction conflicted that many blocks ago."},
3088            {RPCResult::Type::BOOL, "generated", "Only present if transaction only input is a coinbase one."},
3089            {RPCResult::Type::BOOL, "trusted", "Only present if we consider transaction to be trusted and so safe to spend from."},
3090            {RPCResult::Type::STR_HEX, "blockhash", "The block hash containing the transaction."},
3091            {RPCResult::Type::NUM, "blockheight", "The block height containing the transaction."},
3092            {RPCResult::Type::NUM, "blockindex", "The index of the transaction in the block that includes it."},
3093            {RPCResult::Type::NUM_TIME, "blocktime", "The block time expressed in " + UNIX_EPOCH_TIME + "."},
3094            {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
3095            {RPCResult::Type::ARR, "walletconflicts", "Conflicting transaction ids.",
3096            {
3097                {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
3098            }},
3099            {RPCResult::Type::NUM_TIME, "time", "The transaction time expressed in " + UNIX_EPOCH_TIME + "."},
3100            {RPCResult::Type::NUM_TIME, "timereceived", "The time received expressed in " + UNIX_EPOCH_TIME + "."},
3101            {RPCResult::Type::STR, "comment", "If a comment is associated with the transaction, only present if not empty."},
3102            {RPCResult::Type::STR, "bip125-replaceable", "(\"yes|no|unknown\") Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
3103                "may be unknown for unconfirmed transactions not in the mempool"}};
3104 }
3105 
listtransactions(const JSONRPCRequest & request)3106 UniValue listtransactions(const JSONRPCRequest& request)
3107 {
3108     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3109     const CWallet* const pwallet = wallet.get();
3110 
3111     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3112         return NullUniValue;
3113     }
3114 
3115             RPCHelpMan{"listtransactions",
3116                 "\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
3117                 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n",
3118                 {
3119                     {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, should be a valid label name to return only incoming transactions\n"
3120             "              with the specified label, or \"*\" to disable filtering and return all transactions."},
3121                     {"count", RPCArg::Type::NUM, /* default */ "10", "The number of transactions to return"},
3122                     {"skip", RPCArg::Type::NUM, /* default */ "0", "The number of transactions to skip"},
3123                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Include transactions to watch-only addresses (see 'importaddress')"},
3124                 },
3125                 RPCResult{
3126                     RPCResult::Type::ARR, "", "",
3127                     {
3128                         {RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
3129                         {
3130                             {RPCResult::Type::BOOL, "involvesWatchonly", "Only returns true if imported addresses were involved in transaction."},
3131                             {RPCResult::Type::STR, "address", "The qtum address of the transaction."},
3132                             {RPCResult::Type::STR, "category", "The transaction category.\n"
3133                                 "\"send\"                  Transactions sent.\n"
3134                                 "\"receive\"               Non-coinbase and non-coinstake transactions received.\n"
3135                                 "\"generate\"              Coinbase or coinstake transactions received with more than 500 confirmations.\n"
3136                                 "\"immature\"              Coinbase or coinstake transactions received with 500 or fewer confirmations.\n"
3137                                 "\"orphan\"                Orphaned coinbase or coinstake transactions received."},
3138                             {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
3139                                 "for all other categories"},
3140                             {RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"},
3141                             {RPCResult::Type::NUM, "vout", "the vout value"},
3142                             {RPCResult::Type::STR_AMOUNT, "fee", "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
3143                                  "'send' category of transactions."},
3144                         },
3145                         TransactionDescriptionString()),
3146                         {
3147                             {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
3148                                  "'send' category of transactions."},
3149                         })},
3150                     }
3151                 },
3152                 RPCExamples{
3153             "\nList the most recent 10 transactions in the systems\n"
3154             + HelpExampleCli("listtransactions", "") +
3155             "\nList transactions 100 to 120\n"
3156             + HelpExampleCli("listtransactions", "\"*\" 20 100") +
3157             "\nAs a JSON-RPC call\n"
3158             + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
3159                 },
3160             }.Check(request);
3161 
3162     // Make sure the results are valid at least up to the most recent block
3163     // the user could have gotten from another RPC command prior to now
3164     pwallet->BlockUntilSyncedToCurrentChain();
3165 
3166     const std::string* filter_label = nullptr;
3167     if (!request.params[0].isNull() && request.params[0].get_str() != "*") {
3168         filter_label = &request.params[0].get_str();
3169         if (filter_label->empty()) {
3170             throw JSONRPCError(RPC_INVALID_PARAMETER, "Label argument must be a valid label name or \"*\".");
3171         }
3172     }
3173     int nCount = 10;
3174     if (!request.params[1].isNull())
3175         nCount = request.params[1].get_int();
3176     int nFrom = 0;
3177     if (!request.params[2].isNull())
3178         nFrom = request.params[2].get_int();
3179     isminefilter filter = ISMINE_SPENDABLE;
3180 
3181     if (ParseIncludeWatchonly(request.params[3], *pwallet)) {
3182         filter |= ISMINE_WATCH_ONLY;
3183     }
3184 
3185     if (nCount < 0)
3186         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
3187     if (nFrom < 0)
3188         throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
3189 
3190     UniValue ret(UniValue::VARR);
3191 
3192     {
3193         auto locked_chain = pwallet->chain().lock();
3194         LOCK(pwallet->cs_wallet);
3195 
3196         const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;
3197 
3198         // iterate backwards until we have nCount items to return:
3199         for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
3200         {
3201             CWalletTx *const pwtx = (*it).second;
3202             ListTransactions(*locked_chain, pwallet, *pwtx, 0, true, ret, filter, filter_label);
3203             if ((int)ret.size() >= (nCount+nFrom)) break;
3204         }
3205     }
3206 
3207     // ret is newest to oldest
3208 
3209     if (nFrom > (int)ret.size())
3210         nFrom = ret.size();
3211     if ((nFrom + nCount) > (int)ret.size())
3212         nCount = ret.size() - nFrom;
3213 
3214     const std::vector<UniValue>& txs = ret.getValues();
3215     UniValue result{UniValue::VARR};
3216     result.push_backV({ txs.rend() - nFrom - nCount, txs.rend() - nFrom }); // Return oldest to newest
3217     return result;
3218 }
3219 
listsinceblock(const JSONRPCRequest & request)3220 static UniValue listsinceblock(const JSONRPCRequest& request)
3221 {
3222     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3223     const CWallet* const pwallet = wallet.get();
3224 
3225     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3226         return NullUniValue;
3227     }
3228 
3229             RPCHelpMan{"listsinceblock",
3230                 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted.\n"
3231                 "If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"
3232                 "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n",
3233                 {
3234                     {"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, the block hash to list transactions since, otherwise list all transactions."},
3235                     {"target_confirmations", RPCArg::Type::NUM, /* default */ "1", "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
3236                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Include transactions to watch-only addresses (see 'importaddress')"},
3237                     {"include_removed", RPCArg::Type::BOOL, /* default */ "true", "Show transactions that were removed due to a reorg in the \"removed\" array\n"
3238             "                                                           (not guaranteed to work on pruned nodes)"},
3239                 },
3240                 RPCResult{
3241                     RPCResult::Type::OBJ, "", "",
3242                     {
3243                         {RPCResult::Type::ARR, "transactions", "",
3244                         {
3245                             {RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
3246                             {
3247                                 {RPCResult::Type::BOOL, "involvesWatchonly", "Only returns true if imported addresses were involved in transaction."},
3248                                 {RPCResult::Type::STR, "address", "The qtum address of the transaction."},
3249                                 {RPCResult::Type::STR, "category", "The transaction category.\n"
3250                                     "\"send\"                  Transactions sent.\n"
3251                                     "\"receive\"               Non-coinbase transactions received.\n"
3252                                     "\"generate\"              Coinbase transactions received with more than 100 confirmations.\n"
3253                                     "\"immature\"              Coinbase transactions received with 100 or fewer confirmations.\n"
3254                                     "\"orphan\"                Orphaned coinbase transactions received."},
3255                                 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
3256                                     "for all other categories"},
3257                                 {RPCResult::Type::NUM, "vout", "the vout value"},
3258                                 {RPCResult::Type::STR_AMOUNT, "fee", "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
3259                                      "'send' category of transactions."},
3260                             },
3261                             TransactionDescriptionString()),
3262                             {
3263                                 {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
3264                                      "'send' category of transactions."},
3265                                 {RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"},
3266                                 {RPCResult::Type::STR, "to", "If a comment to is associated with the transaction."},
3267                             })},
3268                         }},
3269                         {RPCResult::Type::ARR, "removed", "<structure is the same as \"transactions\" above, only present if include_removed=true>\n"
3270                             "Note: transactions that were re-added in the active chain will appear as-is in this array, and may thus have a positive confirmation count."
3271                         , {{RPCResult::Type::ELISION, "", ""},}},
3272                         {RPCResult::Type::STR_HEX, "lastblock", "The hash of the block (target_confirmations-1) from the best block on the main chain. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones"},
3273                     }
3274                 },
3275                 RPCExamples{
3276                     HelpExampleCli("listsinceblock", "")
3277             + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
3278             + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
3279                 },
3280             }.Check(request);
3281 
3282     // Make sure the results are valid at least up to the most recent block
3283     // the user could have gotten from another RPC command prior to now
3284     pwallet->BlockUntilSyncedToCurrentChain();
3285 
3286     auto locked_chain = pwallet->chain().lock();
3287     LOCK(pwallet->cs_wallet);
3288 
3289     // The way the 'height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0.
3290     Optional<int> height = MakeOptional(false, int()); // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
3291     Optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
3292     int target_confirms = 1;
3293     isminefilter filter = ISMINE_SPENDABLE;
3294 
3295     uint256 blockId;
3296     if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
3297         blockId = ParseHashV(request.params[0], "blockhash");
3298         height = locked_chain->findFork(blockId, &altheight);
3299         if (!height) {
3300             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
3301         }
3302     }
3303 
3304     if (!request.params[1].isNull()) {
3305         target_confirms = request.params[1].get_int();
3306 
3307         if (target_confirms < 1) {
3308             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
3309         }
3310     }
3311 
3312     if (ParseIncludeWatchonly(request.params[2], *pwallet)) {
3313         filter |= ISMINE_WATCH_ONLY;
3314     }
3315 
3316     bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
3317 
3318     const Optional<int> tip_height = locked_chain->getHeight();
3319     int depth = tip_height && height ? (1 + *tip_height - *height) : -1;
3320 
3321     UniValue transactions(UniValue::VARR);
3322 
3323     for (const std::pair<const uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
3324         CWalletTx tx = pairWtx.second;
3325 
3326         if (depth == -1 || abs(tx.GetDepthInMainChain()) < depth) {
3327             ListTransactions(*locked_chain, pwallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
3328         }
3329     }
3330 
3331     // when a reorg'd block is requested, we also list any relevant transactions
3332     // in the blocks of the chain that was detached
3333     UniValue removed(UniValue::VARR);
3334     while (include_removed && altheight && *altheight > *height) {
3335         CBlock block;
3336         if (!pwallet->chain().findBlock(blockId, &block) || block.IsNull()) {
3337             throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
3338         }
3339         for (const CTransactionRef& tx : block.vtx) {
3340             auto it = pwallet->mapWallet.find(tx->GetHash());
3341             if (it != pwallet->mapWallet.end()) {
3342                 // We want all transactions regardless of confirmation count to appear here,
3343                 // even negative confirmation ones, hence the big negative.
3344                 ListTransactions(*locked_chain, pwallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
3345             }
3346         }
3347         blockId = block.hashPrevBlock;
3348         --*altheight;
3349     }
3350 
3351     int last_height = tip_height ? *tip_height + 1 - target_confirms : -1;
3352     uint256 lastblock = last_height >= 0 ? locked_chain->getBlockHash(last_height) : uint256();
3353 
3354     UniValue ret(UniValue::VOBJ);
3355     ret.pushKV("transactions", transactions);
3356     if (include_removed) ret.pushKV("removed", removed);
3357     ret.pushKV("lastblock", lastblock.GetHex());
3358 
3359     return ret;
3360 }
3361 
gettransaction(const JSONRPCRequest & request_)3362 static UniValue gettransaction(const JSONRPCRequest& request_)
3363 {
3364     // long-poll
3365     JSONRPCRequest& request = (JSONRPCRequest&) request_;
3366 
3367     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3368     const CWallet* const pwallet = wallet.get();
3369 
3370     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3371         return NullUniValue;
3372     }
3373 
3374             RPCHelpMan{"gettransaction",
3375                 "\nGet detailed information about in-wallet transaction <txid>\n",
3376                 {
3377                     {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
3378                     {"include_watchonly", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false",
3379                             "Whether to include watch-only addresses in balance calculation and details[]"},
3380                     {"verbose", RPCArg::Type::BOOL, /* default */ "false",
3381                             "Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)"},
3382                     {"waitconf", RPCArg::Type::NUM, /* default */ "0", "Wait for enough confirmations before returning."},
3383                 },
3384                 RPCResult{
3385                     RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
3386                     {
3387                         {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
3388                         {RPCResult::Type::STR_AMOUNT, "fee", "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
3389                                      "'send' category of transactions."},
3390                     },
3391                     TransactionDescriptionString()),
3392                     {
3393                         {RPCResult::Type::ARR, "details", "",
3394                         {
3395                             {RPCResult::Type::OBJ, "", "",
3396                             {
3397                                 {RPCResult::Type::BOOL, "involvesWatchonly", "Only returns true if imported addresses were involved in transaction."},
3398                                 {RPCResult::Type::STR, "address", "The qtum address involved in the transaction."},
3399                                 {RPCResult::Type::STR, "category", "The transaction category.\n"
3400                                     "\"send\"                  Transactions sent.\n"
3401                                     "\"receive\"               Non-coinbase and non-coinstake transactions received.\n"
3402                                     "\"generate\"              Coinbase or coinstake transactions received with more than 500 confirmations.\n"
3403                                     "\"immature\"              Coinbase or coinstake transactions received with 500 or fewer confirmations.\n"
3404                                     "\"orphan\"                Orphaned coinbase or coinstake transactions received."},
3405                                 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
3406                                 {RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"},
3407                                 {RPCResult::Type::NUM, "vout", "the vout value"},
3408                                 {RPCResult::Type::STR_AMOUNT, "fee", "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
3409                                     "'send' category of transactions."},
3410                                 {RPCResult::Type::BOOL, "abandoned", "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
3411                                      "'send' category of transactions."},
3412                             }},
3413                         }},
3414                         {RPCResult::Type::STR_HEX, "hex", "Raw data for transaction"},
3415                         {RPCResult::Type::OBJ, "decoded", "Optional, the decoded transaction (only present when `verbose` is passed)",
3416                         {
3417                             {RPCResult::Type::ELISION, "", "Equivalent to the RPC decoderawtransaction method, or the RPC getrawtransaction method when `verbose` is passed."},
3418                         }},
3419                     })
3420                 },
3421                 RPCExamples{
3422                     HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
3423             + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
3424             + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" false true")
3425             + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
3426                 },
3427             }.Check(request);
3428 
3429     // Make sure the results are valid at least up to the most recent block
3430     // the user could have gotten from another RPC command prior to now
3431     pwallet->BlockUntilSyncedToCurrentChain();
3432 
3433 
3434     uint256 hash(ParseHashV(request.params[0], "txid"));
3435 
3436     isminefilter filter = ISMINE_SPENDABLE;
3437 
3438     if (ParseIncludeWatchonly(request.params[1], *pwallet)) {
3439         filter |= ISMINE_WATCH_ONLY;
3440     }
3441 
3442     bool verbose = request.params[2].isNull() ? false : request.params[2].get_bool();
3443 
3444     auto it = pwallet->mapWallet.find(hash);
3445     if (it == pwallet->mapWallet.end()) {
3446         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
3447     }
3448 
3449     int waitconf = 0;
3450     if(request.params.size() > 3) {
3451         waitconf = request.params[3].get_int();
3452     }
3453 
3454     bool shouldWaitConf = request.params.size() > 3 && waitconf > 0;
3455 
3456     {
3457         auto locked_chain = pwallet->chain().lock();
3458         LOCK(pwallet->cs_wallet);
3459         if (!pwallet->mapWallet.count(hash))
3460             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
3461     }
3462 
3463     const CWalletTx* _wtx = nullptr;
3464 
3465     // avoid long-poll if API caller does not specify waitconf
3466     if (!shouldWaitConf) {
3467         {
3468             auto locked_chain = pwallet->chain().lock();
3469             LOCK(pwallet->cs_wallet);
3470             _wtx = &pwallet->mapWallet.at(hash);
3471         }
3472 
3473     } else {
3474         if(!request.req)
3475             throw JSONRPCError(RPC_INTERNAL_ERROR, "No HTTP connection. Waitconf is available from qtum-cli, not qtum-qt");
3476 
3477         request.PollStart();
3478         while (true) {
3479             {
3480                 auto locked_chain = pwallet->chain().lock();
3481                 LOCK(pwallet->cs_wallet);
3482                 _wtx = &pwallet->mapWallet.at(hash);
3483 
3484                 if (_wtx->GetDepthInMainChain() >= waitconf) {
3485                     break;
3486                 }
3487             }
3488 
3489             request.PollPing();
3490 
3491             std::unique_lock<std::mutex> lock(cs_blockchange);
3492             cond_blockchange.wait_for(lock, std::chrono::milliseconds(300));
3493 
3494             if (!request.PollAlive() || !IsRPCRunning()) {
3495                 return NullUniValue;
3496             }
3497         }
3498     }
3499 
3500     auto locked_chain = pwallet->chain().lock();
3501     LOCK(pwallet->cs_wallet);
3502     const CWalletTx& wtx = *_wtx;
3503 
3504     UniValue entry(UniValue::VOBJ);
3505     CAmount nCredit = wtx.GetCredit(filter);
3506     CAmount nDebit = wtx.GetDebit(filter);
3507     CAmount nNet = nCredit - nDebit;
3508     CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);
3509 
3510     if(wtx.IsCoinStake())
3511     {
3512         CAmount amount = nNet;
3513         entry.pushKV("amount", ValueFromAmount(amount));
3514     }
3515     else
3516     {
3517         entry.pushKV("amount", ValueFromAmount(nNet - nFee));
3518         if (wtx.IsFromMe(filter))
3519             entry.pushKV("fee", ValueFromAmount(nFee));
3520     }
3521 
3522     WalletTxToJSON(pwallet->chain(), *locked_chain, wtx, entry);
3523 
3524     UniValue details(UniValue::VARR);
3525     ListTransactions(*locked_chain, pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */);
3526     entry.pushKV("details", details);
3527 
3528     std::string strHex = EncodeHexTx(*wtx.tx, pwallet->chain().rpcSerializationFlags());
3529     entry.pushKV("hex", strHex);
3530 
3531     if (verbose) {
3532         UniValue decoded(UniValue::VOBJ);
3533         TxToUniv(*wtx.tx, uint256(), decoded, false);
3534         entry.pushKV("decoded", decoded);
3535     }
3536 
3537     return entry;
3538 }
3539 
abandontransaction(const JSONRPCRequest & request)3540 static UniValue abandontransaction(const JSONRPCRequest& request)
3541 {
3542     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3543     CWallet* const pwallet = wallet.get();
3544 
3545     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3546         return NullUniValue;
3547     }
3548 
3549             RPCHelpMan{"abandontransaction",
3550                 "\nMark in-wallet transaction <txid> as abandoned\n"
3551                 "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
3552                 "for their inputs to be respent.  It can be used to replace \"stuck\" or evicted transactions.\n"
3553                 "It only works on transactions which are not included in a block and are not currently in the mempool.\n"
3554                 "It has no effect on transactions which are already abandoned.\n",
3555                 {
3556                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
3557                 },
3558                 RPCResult{RPCResult::Type::NONE, "", ""},
3559                 RPCExamples{
3560                     HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
3561             + HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
3562                 },
3563             }.Check(request);
3564 
3565     // Make sure the results are valid at least up to the most recent block
3566     // the user could have gotten from another RPC command prior to now
3567     pwallet->BlockUntilSyncedToCurrentChain();
3568 
3569     auto locked_chain = pwallet->chain().lock();
3570     LOCK(pwallet->cs_wallet);
3571 
3572     uint256 hash(ParseHashV(request.params[0], "txid"));
3573 
3574     if (!pwallet->mapWallet.count(hash)) {
3575         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
3576     }
3577     if (!pwallet->AbandonTransaction(hash)) {
3578         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
3579     }
3580 
3581     return NullUniValue;
3582 }
3583 
3584 
backupwallet(const JSONRPCRequest & request)3585 static UniValue backupwallet(const JSONRPCRequest& request)
3586 {
3587     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3588     const CWallet* const pwallet = wallet.get();
3589 
3590     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3591         return NullUniValue;
3592     }
3593 
3594             RPCHelpMan{"backupwallet",
3595                 "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n",
3596                 {
3597                     {"destination", RPCArg::Type::STR, RPCArg::Optional::NO, "The destination directory or file"},
3598                 },
3599                 RPCResult{RPCResult::Type::NONE, "", ""},
3600                 RPCExamples{
3601                     HelpExampleCli("backupwallet", "\"backup.dat\"")
3602             + HelpExampleRpc("backupwallet", "\"backup.dat\"")
3603                 },
3604             }.Check(request);
3605 
3606     // Make sure the results are valid at least up to the most recent block
3607     // the user could have gotten from another RPC command prior to now
3608     pwallet->BlockUntilSyncedToCurrentChain();
3609 
3610     auto locked_chain = pwallet->chain().lock();
3611     LOCK(pwallet->cs_wallet);
3612 
3613     std::string strDest = request.params[0].get_str();
3614     if (!pwallet->BackupWallet(strDest)) {
3615         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
3616     }
3617 
3618     return NullUniValue;
3619 }
3620 
3621 
keypoolrefill(const JSONRPCRequest & request)3622 static UniValue keypoolrefill(const JSONRPCRequest& request)
3623 {
3624     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3625     CWallet* const pwallet = wallet.get();
3626 
3627     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3628         return NullUniValue;
3629     }
3630 
3631             RPCHelpMan{"keypoolrefill",
3632                 "\nFills the keypool."+
3633         HELP_REQUIRING_PASSPHRASE,
3634                 {
3635                     {"newsize", RPCArg::Type::NUM, /* default */ "100", "The new keypool size"},
3636                 },
3637                 RPCResult{RPCResult::Type::NONE, "", ""},
3638                 RPCExamples{
3639                     HelpExampleCli("keypoolrefill", "")
3640             + HelpExampleRpc("keypoolrefill", "")
3641                 },
3642             }.Check(request);
3643 
3644     if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
3645         throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
3646     }
3647 
3648     auto locked_chain = pwallet->chain().lock();
3649     LOCK(pwallet->cs_wallet);
3650 
3651     // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
3652     unsigned int kpSize = 0;
3653     if (!request.params[0].isNull()) {
3654         if (request.params[0].get_int() < 0)
3655             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
3656         kpSize = (unsigned int)request.params[0].get_int();
3657     }
3658 
3659     EnsureWalletIsUnlocked(pwallet);
3660     pwallet->TopUpKeyPool(kpSize);
3661 
3662     if (pwallet->GetKeyPoolSize() < kpSize) {
3663         throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
3664     }
3665 
3666     return NullUniValue;
3667 }
3668 
3669 
walletpassphrase(const JSONRPCRequest & request)3670 static UniValue walletpassphrase(const JSONRPCRequest& request)
3671 {
3672     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3673     CWallet* const pwallet = wallet.get();
3674 
3675     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3676         return NullUniValue;
3677     }
3678 
3679             RPCHelpMan{"walletpassphrase",
3680                 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
3681                 "This is needed prior to performing transactions related to private keys such as sending QTUM and staking\n"
3682             "\nNote:\n"
3683             "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
3684             "time that overrides the old one.\n",
3685                 {
3686                     {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet passphrase"},
3687                     {"timeout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The time to keep the decryption key in seconds; capped at 100000000 (~3 years)."},
3688                     {"staking only", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Unlock wallet for staking only"},
3689                 },
3690                 RPCResult{RPCResult::Type::NONE, "", ""},
3691                 RPCExamples{
3692             "\nUnlock the wallet for 60 seconds\n"
3693             + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
3694             "\nLock the wallet again (before 60 seconds)\n"
3695             + HelpExampleCli("walletlock", "") +
3696             "\nUnlock the wallet for staking only, for a long time\n"
3697             + HelpExampleCli("walletpassphrase","\"my pass phrase\" 99999999 true") +
3698             "\nAs a JSON-RPC call\n"
3699             + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
3700                 },
3701             }.Check(request);
3702 
3703     int64_t nSleepTime;
3704     int64_t relock_time;
3705     // Prevent concurrent calls to walletpassphrase with the same wallet.
3706     LOCK(pwallet->m_unlock_mutex);
3707     {
3708         auto locked_chain = pwallet->chain().lock();
3709         LOCK(pwallet->cs_wallet);
3710 
3711         if (request.fHelp)
3712             return true;
3713 
3714         if (!pwallet->IsCrypted()) {
3715             throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
3716         }
3717 
3718         // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
3719         SecureString strWalletPass;
3720         strWalletPass.reserve(100);
3721         // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
3722         // Alternately, find a way to make request.params[0] mlock()'d to begin with.
3723         strWalletPass = request.params[0].get_str().c_str();
3724 
3725         // Get the timeout
3726         nSleepTime = request.params[1].get_int64();
3727         // Timeout cannot be negative, otherwise it will relock immediately
3728         if (nSleepTime < 0) {
3729             throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
3730         }
3731         // Clamp timeout
3732         constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug?
3733         if (nSleepTime > MAX_SLEEP_TIME) {
3734             nSleepTime = MAX_SLEEP_TIME;
3735         }
3736 
3737         if (strWalletPass.empty()) {
3738             throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
3739         }
3740 
3741         // Used to restore m_wallet_unlock_staking_only value in case of unlock failure
3742         bool tmpStakingOnly = pwallet->m_wallet_unlock_staking_only;
3743 
3744         // ppcoin: if user OS account compromised prevent trivial sendmoney commands
3745         if (request.params.size() > 2)
3746             pwallet->m_wallet_unlock_staking_only = request.params[2].get_bool();
3747         else
3748             pwallet->m_wallet_unlock_staking_only = false;
3749 
3750         if (!pwallet->Unlock(strWalletPass)) {
3751             pwallet->m_wallet_unlock_staking_only = tmpStakingOnly;
3752             throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
3753         }
3754 
3755         pwallet->TopUpKeyPool();
3756 
3757         pwallet->nRelockTime = GetTime() + nSleepTime;
3758         relock_time = pwallet->nRelockTime;
3759     }
3760 
3761     // rpcRunLater must be called without cs_wallet held otherwise a deadlock
3762     // can occur. The deadlock would happen when RPCRunLater removes the
3763     // previous timer (and waits for the callback to finish if already running)
3764     // and the callback locks cs_wallet.
3765     AssertLockNotHeld(wallet->cs_wallet);
3766     // Keep a weak pointer to the wallet so that it is possible to unload the
3767     // wallet before the following callback is called. If a valid shared pointer
3768     // is acquired in the callback then the wallet is still loaded.
3769     std::weak_ptr<CWallet> weak_wallet = wallet;
3770     pwallet->chain().rpcRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet, relock_time] {
3771         if (auto shared_wallet = weak_wallet.lock()) {
3772             LOCK(shared_wallet->cs_wallet);
3773             // Skip if this is not the most recent rpcRunLater callback.
3774             if (shared_wallet->nRelockTime != relock_time) return;
3775             shared_wallet->Lock();
3776             shared_wallet->nRelockTime = 0;
3777         }
3778     }, nSleepTime);
3779 
3780     return NullUniValue;
3781 }
3782 
3783 
walletpassphrasechange(const JSONRPCRequest & request)3784 static UniValue walletpassphrasechange(const JSONRPCRequest& request)
3785 {
3786     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3787     CWallet* const pwallet = wallet.get();
3788 
3789     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3790         return NullUniValue;
3791     }
3792 
3793             RPCHelpMan{"walletpassphrasechange",
3794                 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n",
3795                 {
3796                     {"oldpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The current passphrase"},
3797                     {"newpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The new passphrase"},
3798                 },
3799                 RPCResult{RPCResult::Type::NONE, "", ""},
3800                 RPCExamples{
3801                     HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
3802             + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
3803                 },
3804             }.Check(request);
3805 
3806     auto locked_chain = pwallet->chain().lock();
3807     LOCK(pwallet->cs_wallet);
3808 
3809     if (request.fHelp)
3810         return true;
3811     if (!pwallet->IsCrypted()) {
3812         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
3813     }
3814 
3815     // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
3816     // Alternately, find a way to make request.params[0] mlock()'d to begin with.
3817     SecureString strOldWalletPass;
3818     strOldWalletPass.reserve(100);
3819     strOldWalletPass = request.params[0].get_str().c_str();
3820 
3821     SecureString strNewWalletPass;
3822     strNewWalletPass.reserve(100);
3823     strNewWalletPass = request.params[1].get_str().c_str();
3824 
3825     if (strOldWalletPass.empty() || strNewWalletPass.empty()) {
3826         throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
3827     }
3828 
3829     if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) {
3830         throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
3831     }
3832 
3833     return NullUniValue;
3834 }
3835 
3836 
walletlock(const JSONRPCRequest & request)3837 static UniValue walletlock(const JSONRPCRequest& request)
3838 {
3839     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3840     CWallet* const pwallet = wallet.get();
3841 
3842     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3843         return NullUniValue;
3844     }
3845 
3846             RPCHelpMan{"walletlock",
3847                 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
3848                 "After calling this method, you will need to call walletpassphrase again\n"
3849                 "before being able to call any methods which require the wallet to be unlocked.\n",
3850                 {},
3851                 RPCResult{RPCResult::Type::NONE, "", ""},
3852                 RPCExamples{
3853             "\nSet the passphrase for 2 minutes to perform a transaction\n"
3854             + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
3855             "\nPerform a send (requires passphrase set)\n"
3856             + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 1.0") +
3857             "\nClear the passphrase since we are done before 2 minutes is up\n"
3858             + HelpExampleCli("walletlock", "") +
3859             "\nAs a JSON-RPC call\n"
3860             + HelpExampleRpc("walletlock", "")
3861                 },
3862             }.Check(request);
3863 
3864     auto locked_chain = pwallet->chain().lock();
3865     LOCK(pwallet->cs_wallet);
3866 
3867     if (request.fHelp)
3868         return true;
3869     if (!pwallet->IsCrypted()) {
3870         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
3871     }
3872 
3873     pwallet->Lock();
3874     pwallet->nRelockTime = 0;
3875 
3876     return NullUniValue;
3877 }
3878 
3879 
encryptwallet(const JSONRPCRequest & request)3880 static UniValue encryptwallet(const JSONRPCRequest& request)
3881 {
3882     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3883     CWallet* const pwallet = wallet.get();
3884 
3885     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3886         return NullUniValue;
3887     }
3888 
3889             RPCHelpMan{"encryptwallet",
3890                 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
3891                 "After this, any calls that interact with private keys such as sending or signing \n"
3892                 "will require the passphrase to be set prior the making these calls.\n"
3893                 "Use the walletpassphrase call for this, and then walletlock call.\n"
3894                 "If the wallet is already encrypted, use the walletpassphrasechange call.\n",
3895                 {
3896                     {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long."},
3897                 },
3898                 RPCResult{RPCResult::Type::STR, "", "A string with further instructions"},
3899                 RPCExamples{
3900             "\nEncrypt your wallet\n"
3901             + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
3902             "\nNow set the passphrase to use the wallet, such as for signing or sending qtum\n"
3903             + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
3904             "\nNow we can do something like sign\n"
3905             + HelpExampleCli("signmessage", "\"address\" \"test message\"") +
3906             "\nNow lock the wallet again by removing the passphrase\n"
3907             + HelpExampleCli("walletlock", "") +
3908             "\nAs a JSON-RPC call\n"
3909             + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
3910                 },
3911             }.Check(request);
3912 
3913     auto locked_chain = pwallet->chain().lock();
3914     LOCK(pwallet->cs_wallet);
3915 
3916     if (request.fHelp)
3917         return true;
3918 
3919     if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
3920         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet does not contain private keys, nothing to encrypt.");
3921     }
3922 
3923     if (pwallet->IsCrypted()) {
3924         throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
3925     }
3926 
3927     // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
3928     // Alternately, find a way to make request.params[0] mlock()'d to begin with.
3929     SecureString strWalletPass;
3930     strWalletPass.reserve(100);
3931     strWalletPass = request.params[0].get_str().c_str();
3932 
3933     if (strWalletPass.empty()) {
3934         throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
3935     }
3936 
3937     if (!pwallet->EncryptWallet(strWalletPass)) {
3938         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
3939     }
3940 
3941     return "wallet encrypted; The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup.";
3942 }
3943 
reservebalance(const JSONRPCRequest & request)3944 static UniValue reservebalance(const JSONRPCRequest& request)
3945 {
3946     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3947     CWallet* const pwallet = wallet.get();
3948 
3949     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3950         return NullUniValue;
3951     }
3952 
3953             RPCHelpMan{"reservebalance",
3954             "\nSet reserve amount not participating in network protection."
3955             "\nIf no parameters provided current setting is printed.\n",
3956             {
3957                 {"reserve", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED,"is true or false to turn balance reserve on or off."},
3958                 {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "is a real and rounded to cent."},
3959             },
3960              RPCResults{},
3961              RPCExamples{
3962             "\nSet reserve balance to 100\n"
3963             + HelpExampleCli("reservebalance", "true 100") +
3964             "\nSet reserve balance to 0\n"
3965             + HelpExampleCli("reservebalance", "false") +
3966             "\nGet reserve balance\n"
3967             + HelpExampleCli("reservebalance", "")			},
3968             }.Check(request);
3969 
3970 
3971     if (request.params.size() > 0)
3972     {
3973         bool fReserve = request.params[0].get_bool();
3974         if (fReserve)
3975         {
3976             if (request.params.size() == 1)
3977                 throw std::runtime_error("must provide amount to reserve balance.\n");
3978             int64_t nAmount = AmountFromValue(request.params[1]);
3979             nAmount = (nAmount / CENT) * CENT;  // round to cent
3980             if (nAmount < 0)
3981                 throw std::runtime_error("amount cannot be negative.\n");
3982             pwallet->m_reserve_balance = nAmount;
3983         }
3984         else
3985         {
3986             if (request.params.size() > 1)
3987                 throw std::runtime_error("cannot specify amount to turn off reserve.\n");
3988             pwallet->m_reserve_balance = 0;
3989         }
3990     }
3991 
3992     UniValue result(UniValue::VOBJ);
3993     result.pushKV("reserve", (pwallet->m_reserve_balance > 0));
3994     result.pushKV("amount", ValueFromAmount(pwallet->m_reserve_balance));
3995     return result;
3996 }
3997 
lockunspent(const JSONRPCRequest & request)3998 static UniValue lockunspent(const JSONRPCRequest& request)
3999 {
4000     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4001     CWallet* const pwallet = wallet.get();
4002 
4003     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4004         return NullUniValue;
4005     }
4006 
4007             RPCHelpMan{"lockunspent",
4008                 "\nUpdates list of temporarily unspendable outputs.\n"
4009                 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
4010                 "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n"
4011                 "A locked transaction output will not be chosen by automatic coin selection, when spending qtums.\n"
4012                 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
4013                 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
4014                 "Also see the listunspent call\n",
4015                 {
4016                     {"unlock", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Whether to unlock (true) or lock (false) the specified transactions"},
4017                     {"transactions", RPCArg::Type::ARR, /* default */ "empty array", "The transaction outputs and within each, the txid (string) vout (numeric).",
4018                         {
4019                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
4020                                 {
4021                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
4022                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
4023                                 },
4024                             },
4025                         },
4026                     },
4027                 },
4028                 RPCResult{
4029                     RPCResult::Type::BOOL, "", "Whether the command was successful or not"
4030                 },
4031                 RPCExamples{
4032             "\nList the unspent transactions\n"
4033             + HelpExampleCli("listunspent", "") +
4034             "\nLock an unspent transaction\n"
4035             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
4036             "\nList the locked transactions\n"
4037             + HelpExampleCli("listlockunspent", "") +
4038             "\nUnlock the transaction again\n"
4039             + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
4040             "\nAs a JSON-RPC call\n"
4041             + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
4042                 },
4043             }.Check(request);
4044 
4045     // Make sure the results are valid at least up to the most recent block
4046     // the user could have gotten from another RPC command prior to now
4047     pwallet->BlockUntilSyncedToCurrentChain();
4048 
4049     auto locked_chain = pwallet->chain().lock();
4050     LOCK(pwallet->cs_wallet);
4051 
4052     RPCTypeCheckArgument(request.params[0], UniValue::VBOOL);
4053 
4054     bool fUnlock = request.params[0].get_bool();
4055 
4056     if (request.params[1].isNull()) {
4057         if (fUnlock)
4058             pwallet->UnlockAllCoins();
4059         return true;
4060     }
4061 
4062     RPCTypeCheckArgument(request.params[1], UniValue::VARR);
4063 
4064     const UniValue& output_params = request.params[1];
4065 
4066     // Create and validate the COutPoints first.
4067 
4068     std::vector<COutPoint> outputs;
4069     outputs.reserve(output_params.size());
4070 
4071     for (unsigned int idx = 0; idx < output_params.size(); idx++) {
4072         const UniValue& o = output_params[idx].get_obj();
4073 
4074         RPCTypeCheckObj(o,
4075             {
4076                 {"txid", UniValueType(UniValue::VSTR)},
4077                 {"vout", UniValueType(UniValue::VNUM)},
4078             });
4079 
4080         const uint256 txid(ParseHashO(o, "txid"));
4081         const int nOutput = find_value(o, "vout").get_int();
4082         if (nOutput < 0) {
4083             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
4084         }
4085 
4086         const COutPoint outpt(txid, nOutput);
4087 
4088         const auto it = pwallet->mapWallet.find(outpt.hash);
4089         if (it == pwallet->mapWallet.end()) {
4090             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, unknown transaction");
4091         }
4092 
4093         const CWalletTx& trans = it->second;
4094 
4095         if (outpt.n >= trans.tx->vout.size()) {
4096             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds");
4097         }
4098 
4099         if (pwallet->IsSpent(outpt.hash, outpt.n)) {
4100             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output");
4101         }
4102 
4103         const bool is_locked = pwallet->IsLockedCoin(outpt.hash, outpt.n);
4104 
4105         if (fUnlock && !is_locked) {
4106             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected locked output");
4107         }
4108 
4109         if (!fUnlock && is_locked) {
4110             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output already locked");
4111         }
4112 
4113         outputs.push_back(outpt);
4114     }
4115 
4116     // Atomically set (un)locked status for the outputs.
4117     for (const COutPoint& outpt : outputs) {
4118         if (fUnlock) pwallet->UnlockCoin(outpt);
4119         else pwallet->LockCoin(outpt);
4120     }
4121 
4122     return true;
4123 }
4124 
listlockunspent(const JSONRPCRequest & request)4125 static UniValue listlockunspent(const JSONRPCRequest& request)
4126 {
4127     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4128     const CWallet* const pwallet = wallet.get();
4129 
4130     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4131         return NullUniValue;
4132     }
4133 
4134             RPCHelpMan{"listlockunspent",
4135                 "\nReturns list of temporarily unspendable outputs.\n"
4136                 "See the lockunspent call to lock and unlock transactions for spending.\n",
4137                 {},
4138                 RPCResult{
4139                     RPCResult::Type::ARR, "", "",
4140                     {
4141                         {RPCResult::Type::OBJ, "", "",
4142                         {
4143                             {RPCResult::Type::STR_HEX, "txid", "The transaction id locked"},
4144                             {RPCResult::Type::NUM, "vout", "The vout value"},
4145                         }},
4146                     }
4147                 },
4148                 RPCExamples{
4149             "\nList the unspent transactions\n"
4150             + HelpExampleCli("listunspent", "") +
4151             "\nLock an unspent transaction\n"
4152             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
4153             "\nList the locked transactions\n"
4154             + HelpExampleCli("listlockunspent", "") +
4155             "\nUnlock the transaction again\n"
4156             + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
4157             "\nAs a JSON-RPC call\n"
4158             + HelpExampleRpc("listlockunspent", "")
4159                 },
4160             }.Check(request);
4161 
4162     auto locked_chain = pwallet->chain().lock();
4163     LOCK(pwallet->cs_wallet);
4164 
4165     std::vector<COutPoint> vOutpts;
4166     pwallet->ListLockedCoins(vOutpts);
4167 
4168     UniValue ret(UniValue::VARR);
4169 
4170     for (const COutPoint& outpt : vOutpts) {
4171         UniValue o(UniValue::VOBJ);
4172 
4173         o.pushKV("txid", outpt.hash.GetHex());
4174         o.pushKV("vout", (int)outpt.n);
4175         ret.push_back(o);
4176     }
4177 
4178     return ret;
4179 }
4180 
settxfee(const JSONRPCRequest & request)4181 static UniValue settxfee(const JSONRPCRequest& request)
4182 {
4183     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4184     CWallet* const pwallet = wallet.get();
4185 
4186     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4187         return NullUniValue;
4188     }
4189 
4190             RPCHelpMan{"settxfee",
4191                 "\nSet the transaction fee per kB for this wallet. Overrides the global -paytxfee command line parameter.\n",
4192                 {
4193                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee in " + CURRENCY_UNIT + "/kB"},
4194                 },
4195                 RPCResult{
4196                     RPCResult::Type::BOOL, "", "Returns true if successful"
4197                 },
4198                 RPCExamples{
4199                     HelpExampleCli("settxfee", "0.00001")
4200             + HelpExampleRpc("settxfee", "0.00001")
4201                 },
4202             }.Check(request);
4203 
4204     auto locked_chain = pwallet->chain().lock();
4205     LOCK(pwallet->cs_wallet);
4206 
4207     CAmount nAmount = AmountFromValue(request.params[0]);
4208     CFeeRate tx_fee_rate(nAmount, 1000);
4209     if (tx_fee_rate == CFeeRate(0)) {
4210         // automatic selection
4211     } else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
4212         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString()));
4213     } else if (tx_fee_rate < pwallet->m_min_fee) {
4214         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than wallet min fee (%s)", pwallet->m_min_fee.ToString()));
4215     }
4216 
4217     pwallet->m_pay_tx_fee = tx_fee_rate;
4218     return true;
4219 }
4220 
getbalances(const JSONRPCRequest & request)4221 static UniValue getbalances(const JSONRPCRequest& request)
4222 {
4223     std::shared_ptr<CWallet> const rpc_wallet = GetWalletForJSONRPCRequest(request);
4224     if (!EnsureWalletIsAvailable(rpc_wallet.get(), request.fHelp)) {
4225         return NullUniValue;
4226     }
4227     CWallet& wallet = *rpc_wallet;
4228 
4229     RPCHelpMan{
4230         "getbalances",
4231         "Returns an object with all balances in " + CURRENCY_UNIT + ".\n",
4232         {},
4233         RPCResult{
4234             RPCResult::Type::OBJ, "", "",
4235             {
4236                 {RPCResult::Type::OBJ, "mine", "balances from outputs that the wallet can sign",
4237                 {
4238                     {RPCResult::Type::STR_AMOUNT, "trusted", "trusted balance (outputs created by the wallet or confirmed outputs)"},
4239                     {RPCResult::Type::STR_AMOUNT, "untrusted_pending", "untrusted pending balance (outputs created by others that are in the mempool)"},
4240                     {RPCResult::Type::STR_AMOUNT, "immature", "balance from immature coinbase outputs"},
4241                     {RPCResult::Type::STR_AMOUNT, "used", "(only present if avoid_reuse is set) balance from coins sent to addresses that were previously spent from (potentially privacy violating)"},
4242                 }},
4243                 {RPCResult::Type::OBJ, "watchonly", "watchonly balances (not present if wallet does not watch anything)",
4244                 {
4245                     {RPCResult::Type::STR_AMOUNT, "trusted", "trusted balance (outputs created by the wallet or confirmed outputs)"},
4246                     {RPCResult::Type::STR_AMOUNT, "untrusted_pending", "untrusted pending balance (outputs created by others that are in the mempool)"},
4247                     {RPCResult::Type::STR_AMOUNT, "immature", "balance from immature coinbase outputs"},
4248                 }},
4249             }
4250             },
4251         RPCExamples{
4252             HelpExampleCli("getbalances", "") +
4253             HelpExampleRpc("getbalances", "")},
4254     }.Check(request);
4255 
4256     // Make sure the results are valid at least up to the most recent block
4257     // the user could have gotten from another RPC command prior to now
4258     wallet.BlockUntilSyncedToCurrentChain();
4259 
4260     auto locked_chain = wallet.chain().lock();
4261     LOCK(wallet.cs_wallet);
4262 
4263     const auto bal = wallet.GetBalance();
4264     UniValue balances{UniValue::VOBJ};
4265     {
4266         UniValue balances_mine{UniValue::VOBJ};
4267         balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
4268         balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending));
4269         balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
4270         if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
4271             // If the AVOID_REUSE flag is set, bal has been set to just the un-reused address balance. Get
4272             // the total balance, and then subtract bal to get the reused address balance.
4273             const auto full_bal = wallet.GetBalance(0, false);
4274             balances_mine.pushKV("used", ValueFromAmount(full_bal.m_mine_trusted + full_bal.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending));
4275         }
4276         balances.pushKV("mine", balances_mine);
4277     }
4278     auto spk_man = wallet.GetLegacyScriptPubKeyMan();
4279     if (spk_man && spk_man->HaveWatchOnly()) {
4280         UniValue balances_watchonly{UniValue::VOBJ};
4281         balances_watchonly.pushKV("trusted", ValueFromAmount(bal.m_watchonly_trusted));
4282         balances_watchonly.pushKV("untrusted_pending", ValueFromAmount(bal.m_watchonly_untrusted_pending));
4283         balances_watchonly.pushKV("immature", ValueFromAmount(bal.m_watchonly_immature));
4284         balances.pushKV("watchonly", balances_watchonly);
4285     }
4286     return balances;
4287 }
4288 
getwalletinfo(const JSONRPCRequest & request)4289 static UniValue getwalletinfo(const JSONRPCRequest& request)
4290 {
4291     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4292     const CWallet* const pwallet = wallet.get();
4293 
4294     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4295         return NullUniValue;
4296     }
4297 
4298     RPCHelpMan{"getwalletinfo",
4299                 "Returns an object containing various wallet state info.\n",
4300                 {},
4301                 RPCResult{
4302                     RPCResult::Type::OBJ, "", "",
4303                     {
4304                         {
4305                         {RPCResult::Type::STR, "walletname", "the wallet name"},
4306                         {RPCResult::Type::NUM, "walletversion", "the wallet version"},
4307                         {RPCResult::Type::STR_AMOUNT, "balance", "DEPRECATED. Identical to getbalances().mine.trusted"},
4308                         {RPCResult::Type::STR_AMOUNT, "stake", "DEPRECATED. Identical to getbalances().mine.stake"},
4309                         {RPCResult::Type::STR_AMOUNT, "unconfirmed_balance", "DEPRECATED. Identical to getbalances().mine.untrusted_pending"},
4310                         {RPCResult::Type::STR_AMOUNT, "immature_balance", "DEPRECATED. Identical to getbalances().mine.immature"},
4311                         {RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
4312                         {RPCResult::Type::NUM_TIME, "keypoololdest", "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool"},
4313                         {RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
4314                         {RPCResult::Type::NUM, "keypoolsize_hd_internal", "how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)"},
4315                         {RPCResult::Type::NUM_TIME, "unlocked_until", "the " + UNIX_EPOCH_TIME + " until which the wallet is unlocked for transfers, or 0 if the wallet is locked"},
4316                         {RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB"},
4317                         {RPCResult::Type::STR_HEX, "hdseedid", /* optional */ true, "the Hash160 of the HD seed (only present when HD is enabled)"},
4318                         {RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},
4319                         {RPCResult::Type::BOOL, "avoid_reuse", "whether this wallet tracks clean/dirty coins in terms of reuse"},
4320                         {RPCResult::Type::OBJ, "scanning", "current scanning details, or false if no scan is in progress",
4321                         {
4322                             {RPCResult::Type::NUM, "duration", "elapsed seconds since scan start"},
4323                             {RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"},
4324                         }},
4325                     }},
4326                 },
4327                 RPCExamples{
4328                     HelpExampleCli("getwalletinfo", "")
4329             + HelpExampleRpc("getwalletinfo", "")
4330                 },
4331     }.Check(request);
4332 
4333     // Make sure the results are valid at least up to the most recent block
4334     // the user could have gotten from another RPC command prior to now
4335     pwallet->BlockUntilSyncedToCurrentChain();
4336 
4337     auto locked_chain = pwallet->chain().lock();
4338     LOCK(pwallet->cs_wallet);
4339 
4340     UniValue obj(UniValue::VOBJ);
4341 
4342     size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
4343     const auto bal = pwallet->GetBalance();
4344     obj.pushKV("walletname", pwallet->GetName());
4345     obj.pushKV("walletversion", pwallet->GetVersion());
4346     obj.pushKV("balance", ValueFromAmount(bal.m_mine_trusted));
4347     obj.pushKV("stake", ValueFromAmount(bal.m_mine_stake));
4348     obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending));
4349     obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature));
4350     obj.pushKV("txcount",       (int)pwallet->mapWallet.size());
4351     obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime());
4352     obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
4353 
4354     LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
4355     if (spk_man) {
4356         CKeyID seed_id = spk_man->GetHDChain().seed_id;
4357         if (!seed_id.IsNull()) {
4358             obj.pushKV("hdseedid", seed_id.GetHex());
4359         }
4360     }
4361 
4362     if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
4363         obj.pushKV("keypoolsize_hd_internal",   (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
4364     }
4365     if (pwallet->IsCrypted()) {
4366         obj.pushKV("unlocked_until", pwallet->nRelockTime);
4367     }
4368     obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK()));
4369     obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
4370     obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
4371     if (pwallet->IsScanning()) {
4372         UniValue scanning(UniValue::VOBJ);
4373         scanning.pushKV("duration", pwallet->ScanningDuration() / 1000);
4374         scanning.pushKV("progress", pwallet->ScanningProgress());
4375         obj.pushKV("scanning", scanning);
4376     } else {
4377         obj.pushKV("scanning", false);
4378     }
4379     return obj;
4380 }
4381 
listwalletdir(const JSONRPCRequest & request)4382 static UniValue listwalletdir(const JSONRPCRequest& request)
4383 {
4384             RPCHelpMan{"listwalletdir",
4385                 "Returns a list of wallets in the wallet directory.\n",
4386                 {},
4387                 RPCResult{
4388                     RPCResult::Type::OBJ, "", "",
4389                     {
4390                         {RPCResult::Type::ARR, "wallets", "",
4391                         {
4392                             {RPCResult::Type::OBJ, "", "",
4393                             {
4394                                 {RPCResult::Type::STR, "name", "The wallet name"},
4395                             }},
4396                         }},
4397                     }
4398                 },
4399                 RPCExamples{
4400                     HelpExampleCli("listwalletdir", "")
4401             + HelpExampleRpc("listwalletdir", "")
4402                 },
4403             }.Check(request);
4404 
4405     UniValue wallets(UniValue::VARR);
4406     for (const auto& path : ListWalletDir()) {
4407         UniValue wallet(UniValue::VOBJ);
4408         wallet.pushKV("name", path.string());
4409         wallets.push_back(wallet);
4410     }
4411 
4412     UniValue result(UniValue::VOBJ);
4413     result.pushKV("wallets", wallets);
4414     return result;
4415 }
4416 
listwallets(const JSONRPCRequest & request)4417 static UniValue listwallets(const JSONRPCRequest& request)
4418 {
4419             RPCHelpMan{"listwallets",
4420                 "Returns a list of currently loaded wallets.\n"
4421                 "For full information on the wallet, use \"getwalletinfo\"\n",
4422                 {},
4423                 RPCResult{
4424                     RPCResult::Type::ARR, "", "",
4425                     {
4426                         {RPCResult::Type::STR, "walletname", "the wallet name"},
4427                     }
4428                 },
4429                 RPCExamples{
4430                     HelpExampleCli("listwallets", "")
4431             + HelpExampleRpc("listwallets", "")
4432                 },
4433             }.Check(request);
4434 
4435     UniValue obj(UniValue::VARR);
4436 
4437     for (const std::shared_ptr<CWallet>& wallet : GetWallets()) {
4438         if (!EnsureWalletIsAvailable(wallet.get(), request.fHelp)) {
4439             return NullUniValue;
4440         }
4441 
4442         LOCK(wallet->cs_wallet);
4443 
4444         obj.push_back(wallet->GetName());
4445     }
4446 
4447     return obj;
4448 }
4449 
loadwallet(const JSONRPCRequest & request)4450 static UniValue loadwallet(const JSONRPCRequest& request)
4451 {
4452             RPCHelpMan{"loadwallet",
4453                 "\nLoads a wallet from a wallet file or directory."
4454                 "\nNote that all wallet command-line options used when starting qtumd will be"
4455                 "\napplied to the new wallet (eg -zapwallettxes, upgradewallet, rescan, etc).\n",
4456                 {
4457                     {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."},
4458                 },
4459                 RPCResult{
4460                     RPCResult::Type::OBJ, "", "",
4461                     {
4462                         {RPCResult::Type::STR, "name", "The wallet name if loaded successfully."},
4463                         {RPCResult::Type::STR, "warning", "Warning message if wallet was not loaded cleanly."},
4464                     }
4465                 },
4466                 RPCExamples{
4467                     HelpExampleCli("loadwallet", "\"test.dat\"")
4468             + HelpExampleRpc("loadwallet", "\"test.dat\"")
4469                 },
4470             }.Check(request);
4471 
4472     WalletLocation location(request.params[0].get_str());
4473 
4474     if (!location.Exists()) {
4475         throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet " + location.GetName() + " not found.");
4476     } else if (fs::is_directory(location.GetPath())) {
4477         // The given filename is a directory. Check that there's a wallet.dat file.
4478         fs::path wallet_dat_file = location.GetPath() / "wallet.dat";
4479         if (fs::symlink_status(wallet_dat_file).type() == fs::file_not_found) {
4480             throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Directory " + location.GetName() + " does not contain a wallet.dat file.");
4481         }
4482     }
4483 
4484     std::string error;
4485     std::vector<std::string> warning;
4486     std::shared_ptr<CWallet> const wallet = LoadWallet(*g_rpc_chain, location, error, warning);
4487     if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error);
4488 
4489     UniValue obj(UniValue::VOBJ);
4490     obj.pushKV("name", wallet->GetName());
4491     obj.pushKV("warning", Join(warning, "\n"));
4492 
4493     return obj;
4494 }
4495 
setwalletflag(const JSONRPCRequest & request)4496 static UniValue setwalletflag(const JSONRPCRequest& request)
4497 {
4498     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4499     CWallet* const pwallet = wallet.get();
4500 
4501     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4502         return NullUniValue;
4503     }
4504 
4505             std::string flags = "";
4506             for (auto& it : WALLET_FLAG_MAP)
4507                 if (it.second & MUTABLE_WALLET_FLAGS)
4508                     flags += (flags == "" ? "" : ", ") + it.first;
4509             RPCHelpMan{"setwalletflag",
4510                 "\nChange the state of the given wallet flag for a wallet.\n",
4511                 {
4512                     {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
4513                     {"value", RPCArg::Type::BOOL, /* default */ "true", "The new state."},
4514                 },
4515                 RPCResult{
4516                     RPCResult::Type::OBJ, "", "",
4517                     {
4518                         {RPCResult::Type::STR, "flag_name", "The name of the flag that was modified"},
4519                         {RPCResult::Type::BOOL, "flag_state", "The new state of the flag"},
4520                         {RPCResult::Type::STR, "warnings", "Any warnings associated with the change"},
4521                     }
4522                 },
4523                 RPCExamples{
4524                     HelpExampleCli("setwalletflag", "avoid_reuse")
4525                   + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
4526                 },
4527             }.Check(request);
4528 
4529     std::string flag_str = request.params[0].get_str();
4530     bool value = request.params[1].isNull() || request.params[1].get_bool();
4531 
4532     if (!WALLET_FLAG_MAP.count(flag_str)) {
4533         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
4534     }
4535 
4536     auto flag = WALLET_FLAG_MAP.at(flag_str);
4537 
4538     if (!(flag & MUTABLE_WALLET_FLAGS)) {
4539         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
4540     }
4541 
4542     UniValue res(UniValue::VOBJ);
4543 
4544     if (pwallet->IsWalletFlagSet(flag) == value) {
4545         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is already set to %s: %s", value ? "true" : "false", flag_str));
4546     }
4547 
4548     res.pushKV("flag_name", flag_str);
4549     res.pushKV("flag_state", value);
4550 
4551     if (value) {
4552         pwallet->SetWalletFlag(flag);
4553     } else {
4554         pwallet->UnsetWalletFlag(flag);
4555     }
4556 
4557     if (flag && value && WALLET_FLAG_CAVEATS.count(flag)) {
4558         res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
4559     }
4560 
4561     return res;
4562 }
4563 
createwallet(const JSONRPCRequest & request)4564 static UniValue createwallet(const JSONRPCRequest& request)
4565 {
4566     RPCHelpMan{
4567         "createwallet",
4568         "\nCreates and loads a new wallet.\n",
4569         {
4570             {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."},
4571             {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
4572             {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
4573             {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
4574             {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "false", "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
4575         },
4576         RPCResult{
4577             RPCResult::Type::OBJ, "", "",
4578             {
4579                 {RPCResult::Type::STR, "name", "The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path."},
4580                 {RPCResult::Type::STR, "warning", "Warning message if wallet was not loaded cleanly."},
4581             }
4582         },
4583         RPCExamples{
4584             HelpExampleCli("createwallet", "\"testwallet\"")
4585             + HelpExampleRpc("createwallet", "\"testwallet\"")
4586         },
4587     }.Check(request);
4588 
4589     uint64_t flags = 0;
4590     if (!request.params[1].isNull() && request.params[1].get_bool()) {
4591         flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS;
4592     }
4593 
4594     if (!request.params[2].isNull() && request.params[2].get_bool()) {
4595         flags |= WALLET_FLAG_BLANK_WALLET;
4596     }
4597     SecureString passphrase;
4598     passphrase.reserve(100);
4599     std::vector<std::string> warnings;
4600     if (!request.params[3].isNull()) {
4601         passphrase = request.params[3].get_str().c_str();
4602         if (passphrase.empty()) {
4603             // Empty string means unencrypted
4604             warnings.emplace_back("Empty string given as passphrase, wallet will not be encrypted.");
4605         }
4606     }
4607 
4608     if (!request.params[4].isNull() && request.params[4].get_bool()) {
4609         flags |= WALLET_FLAG_AVOID_REUSE;
4610     }
4611 
4612     std::string error;
4613     std::shared_ptr<CWallet> wallet;
4614     WalletCreationStatus status = CreateWallet(*g_rpc_chain, passphrase, flags, request.params[0].get_str(), error, warnings, wallet);
4615     switch (status) {
4616         case WalletCreationStatus::CREATION_FAILED:
4617             throw JSONRPCError(RPC_WALLET_ERROR, error);
4618         case WalletCreationStatus::ENCRYPTION_FAILED:
4619             throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error);
4620         case WalletCreationStatus::SUCCESS:
4621             break;
4622         // no default case, so the compiler can warn about missing cases
4623     }
4624 
4625     UniValue obj(UniValue::VOBJ);
4626     obj.pushKV("name", wallet->GetName());
4627     obj.pushKV("warning", Join(warnings, "\n"));
4628 
4629     return obj;
4630 }
4631 
unloadwallet(const JSONRPCRequest & request)4632 static UniValue unloadwallet(const JSONRPCRequest& request)
4633 {
4634             RPCHelpMan{"unloadwallet",
4635                 "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n"
4636                 "Specifying the wallet name on a wallet endpoint is invalid.",
4637                 {
4638                     {"wallet_name", RPCArg::Type::STR, /* default */ "the wallet name from the RPC request", "The name of the wallet to unload."},
4639                 },
4640                 RPCResult{RPCResult::Type::NONE, "", ""},
4641                 RPCExamples{
4642                     HelpExampleCli("unloadwallet", "wallet_name")
4643             + HelpExampleRpc("unloadwallet", "wallet_name")
4644                 },
4645             }.Check(request);
4646 
4647     std::string wallet_name;
4648     if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
4649         if (!request.params[0].isNull()) {
4650             throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot unload the requested wallet");
4651         }
4652     } else {
4653         wallet_name = request.params[0].get_str();
4654     }
4655 
4656     std::shared_ptr<CWallet> wallet = GetWallet(wallet_name);
4657     if (!wallet) {
4658         throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
4659     }
4660 
4661     // Release the "main" shared pointer and prevent further notifications.
4662     // Note that any attempt to load the same wallet would fail until the wallet
4663     // is destroyed (see CheckUniqueFileid).
4664     if (!RemoveWallet(wallet)) {
4665         throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
4666     }
4667 
4668     UnloadWallet(std::move(wallet));
4669 
4670     return NullUniValue;
4671 }
4672 
listunspent(const JSONRPCRequest & request)4673 static UniValue listunspent(const JSONRPCRequest& request)
4674 {
4675     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4676     const CWallet* const pwallet = wallet.get();
4677 
4678     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4679         return NullUniValue;
4680     }
4681 
4682     RPCHelpMan{
4683                 "listunspent",
4684                 "\nReturns array of unspent transaction outputs\n"
4685                 "with between minconf and maxconf (inclusive) confirmations.\n"
4686                 "Optionally filter to only include txouts paid to specified addresses.\n",
4687                 {
4688                     {"minconf", RPCArg::Type::NUM, /* default */ "1", "The minimum confirmations to filter"},
4689                     {"maxconf", RPCArg::Type::NUM, /* default */ "9999999", "The maximum confirmations to filter"},
4690                     {"addresses", RPCArg::Type::ARR, /* default */ "empty array", "A json array of qtum addresses to filter",
4691                         {
4692                             {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "qtum address"},
4693                         },
4694                     },
4695                     {"include_unsafe", RPCArg::Type::BOOL, /* default */ "true", "Include outputs that are not safe to spend\n"
4696             "                  See description of \"safe\" attribute below."},
4697                     {"query_options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "JSON with query options",
4698                         {
4699                             {"minimumAmount", RPCArg::Type::AMOUNT, /* default */ "0", "Minimum value of each UTXO in " + CURRENCY_UNIT + ""},
4700                             {"maximumAmount", RPCArg::Type::AMOUNT, /* default */ "unlimited", "Maximum value of each UTXO in " + CURRENCY_UNIT + ""},
4701                             {"maximumCount", RPCArg::Type::NUM, /* default */ "unlimited", "Maximum number of UTXOs"},
4702                             {"minimumSumAmount", RPCArg::Type::AMOUNT, /* default */ "unlimited", "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""},
4703                         },
4704                         "query_options"},
4705                 },
4706                 RPCResult{
4707                     RPCResult::Type::ARR, "", "",
4708                     {
4709                         {RPCResult::Type::OBJ, "", "",
4710                         {
4711                             {RPCResult::Type::STR_HEX, "txid", "the transaction id"},
4712                             {RPCResult::Type::NUM, "vout", "the vout value"},
4713                             {RPCResult::Type::STR, "address", "the qtum address"},
4714                             {RPCResult::Type::STR, "label", "The associated label, or \"\" for the default label"},
4715                             {RPCResult::Type::STR, "scriptPubKey", "the script key"},
4716                             {RPCResult::Type::STR_AMOUNT, "amount", "the transaction output amount in " + CURRENCY_UNIT},
4717                             {RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
4718                             {RPCResult::Type::STR_HEX, "redeemScript", "The redeemScript if scriptPubKey is P2SH"},
4719                             {RPCResult::Type::STR, "witnessScript", "witnessScript if the scriptPubKey is P2WSH or P2SH-P2WSH"},
4720                             {RPCResult::Type::BOOL, "spendable", "Whether we have the private keys to spend this output"},
4721                             {RPCResult::Type::BOOL, "solvable", "Whether we know how to spend this output, ignoring the lack of keys"},
4722                             {RPCResult::Type::BOOL, "reused", "(only present if avoid_reuse is set) Whether this output is reused/dirty (sent to an address that was previously spent from)"},
4723                             {RPCResult::Type::STR, "desc", "(only when solvable) A descriptor for spending this output"},
4724                             {RPCResult::Type::BOOL, "safe", "Whether this output is considered safe to spend. Unconfirmed transactions\n"
4725                                                             "from outside keys and unconfirmed replacement transactions are considered unsafe\n"
4726                                                             "and are not eligible for spending by fundrawtransaction and sendtoaddress."},
4727                         }},
4728                     }
4729                 },
4730                 RPCExamples{
4731                     HelpExampleCli("listunspent", "")
4732             + HelpExampleCli("listunspent", "6 9999999 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"")
4733             + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"")
4734             + HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'")
4735             + HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
4736                 },
4737             }.Check(request);
4738 
4739     int nMinDepth = 1;
4740     if (!request.params[0].isNull()) {
4741         RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
4742         nMinDepth = request.params[0].get_int();
4743     }
4744 
4745     int nMaxDepth = 9999999;
4746     if (!request.params[1].isNull()) {
4747         RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
4748         nMaxDepth = request.params[1].get_int();
4749     }
4750 
4751     std::set<CTxDestination> destinations;
4752     if (!request.params[2].isNull()) {
4753         RPCTypeCheckArgument(request.params[2], UniValue::VARR);
4754         UniValue inputs = request.params[2].get_array();
4755         for (unsigned int idx = 0; idx < inputs.size(); idx++) {
4756             const UniValue& input = inputs[idx];
4757             CTxDestination dest = DecodeDestination(input.get_str());
4758             if (!IsValidDestination(dest)) {
4759                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Qtum address: ") + input.get_str());
4760             }
4761             if (!destinations.insert(dest).second) {
4762                 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
4763             }
4764         }
4765     }
4766 
4767     bool include_unsafe = true;
4768     if (!request.params[3].isNull()) {
4769         RPCTypeCheckArgument(request.params[3], UniValue::VBOOL);
4770         include_unsafe = request.params[3].get_bool();
4771     }
4772 
4773     CAmount nMinimumAmount = 0;
4774     CAmount nMaximumAmount = MAX_MONEY;
4775     CAmount nMinimumSumAmount = MAX_MONEY;
4776     uint64_t nMaximumCount = 0;
4777 
4778     if (!request.params[4].isNull()) {
4779         const UniValue& options = request.params[4].get_obj();
4780 
4781         if (options.exists("minimumAmount"))
4782             nMinimumAmount = AmountFromValue(options["minimumAmount"]);
4783 
4784         if (options.exists("maximumAmount"))
4785             nMaximumAmount = AmountFromValue(options["maximumAmount"]);
4786 
4787         if (options.exists("minimumSumAmount"))
4788             nMinimumSumAmount = AmountFromValue(options["minimumSumAmount"]);
4789 
4790         if (options.exists("maximumCount"))
4791             nMaximumCount = options["maximumCount"].get_int64();
4792     }
4793 
4794     // Make sure the results are valid at least up to the most recent block
4795     // the user could have gotten from another RPC command prior to now
4796     pwallet->BlockUntilSyncedToCurrentChain();
4797 
4798     UniValue results(UniValue::VARR);
4799     std::vector<COutput> vecOutputs;
4800     {
4801         CCoinControl cctl;
4802         cctl.m_avoid_address_reuse = false;
4803         cctl.m_min_depth = nMinDepth;
4804         cctl.m_max_depth = nMaxDepth;
4805         auto locked_chain = pwallet->chain().lock();
4806         LOCK(pwallet->cs_wallet);
4807         pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount);
4808     }
4809 
4810     LOCK(pwallet->cs_wallet);
4811 
4812     const bool avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
4813 
4814     for (const COutput& out : vecOutputs) {
4815         CTxDestination address;
4816         const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
4817         bool fValidAddress = ExtractDestination(scriptPubKey, address);
4818         bool reused = avoid_reuse && pwallet->IsSpentKey(out.tx->GetHash(), out.i);
4819 
4820         if (destinations.size() && (!fValidAddress || !destinations.count(address)))
4821             continue;
4822 
4823         UniValue entry(UniValue::VOBJ);
4824         entry.pushKV("txid", out.tx->GetHash().GetHex());
4825         entry.pushKV("vout", out.i);
4826 
4827         if (fValidAddress) {
4828             entry.pushKV("address", EncodeDestination(address));
4829 
4830             const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
4831             if (address_book_entry) {
4832                 entry.pushKV("label", address_book_entry->GetLabel());
4833             }
4834 
4835             std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
4836             if (provider) {
4837                 if (scriptPubKey.IsPayToScriptHash()) {
4838                     const CScriptID& hash = CScriptID(boost::get<ScriptHash>(address));
4839                     CScript redeemScript;
4840                     if (provider->GetCScript(hash, redeemScript)) {
4841                         entry.pushKV("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()));
4842                         // Now check if the redeemScript is actually a P2WSH script
4843                         CTxDestination witness_destination;
4844                         if (redeemScript.IsPayToWitnessScriptHash()) {
4845                             bool extracted = ExtractDestination(redeemScript, witness_destination);
4846                             CHECK_NONFATAL(extracted);
4847                             // Also return the witness script
4848                             const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(witness_destination);
4849                             CScriptID id;
4850                             CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
4851                             CScript witnessScript;
4852                             if (provider->GetCScript(id, witnessScript)) {
4853                                 entry.pushKV("witnessScript", HexStr(witnessScript.begin(), witnessScript.end()));
4854                             }
4855                         }
4856                     }
4857                 } else if (scriptPubKey.IsPayToWitnessScriptHash()) {
4858                     const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(address);
4859                     CScriptID id;
4860                     CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
4861                     CScript witnessScript;
4862                     if (provider->GetCScript(id, witnessScript)) {
4863                         entry.pushKV("witnessScript", HexStr(witnessScript.begin(), witnessScript.end()));
4864                     }
4865                 }
4866             }
4867         }
4868 
4869         entry.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
4870         entry.pushKV("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue));
4871         entry.pushKV("confirmations", out.nDepth);
4872         entry.pushKV("spendable", out.fSpendable);
4873         entry.pushKV("solvable", out.fSolvable);
4874         if (out.fSolvable) {
4875             std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
4876             if (provider) {
4877                 auto descriptor = InferDescriptor(scriptPubKey, *provider);
4878                 entry.pushKV("desc", descriptor->ToString());
4879             }
4880         }
4881         if (avoid_reuse) entry.pushKV("reused", reused);
4882         entry.pushKV("safe", out.fSafe);
4883         results.push_back(entry);
4884     }
4885 
4886     return results;
4887 }
4888 
FundTransaction(CWallet * const pwallet,CMutableTransaction & tx,CAmount & fee_out,int & change_position,UniValue options)4889 void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, UniValue options)
4890 {
4891     // Make sure the results are valid at least up to the most recent block
4892     // the user could have gotten from another RPC command prior to now
4893     pwallet->BlockUntilSyncedToCurrentChain();
4894 
4895     CCoinControl coinControl;
4896     change_position = -1;
4897     bool lockUnspents = false;
4898     UniValue subtractFeeFromOutputs;
4899     std::set<int> setSubtractFeeFromOutputs;
4900 
4901     if (!options.isNull()) {
4902       if (options.type() == UniValue::VBOOL) {
4903         // backward compatibility bool only fallback
4904         coinControl.fAllowWatchOnly = options.get_bool();
4905       }
4906       else {
4907         RPCTypeCheckArgument(options, UniValue::VOBJ);
4908         RPCTypeCheckObj(options,
4909             {
4910                 {"changeAddress", UniValueType(UniValue::VSTR)},
4911                 {"changePosition", UniValueType(UniValue::VNUM)},
4912                 {"change_type", UniValueType(UniValue::VSTR)},
4913                 {"includeWatching", UniValueType(UniValue::VBOOL)},
4914                 {"lockUnspents", UniValueType(UniValue::VBOOL)},
4915                 {"feeRate", UniValueType()}, // will be checked below
4916                 {"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
4917                 {"replaceable", UniValueType(UniValue::VBOOL)},
4918                 {"conf_target", UniValueType(UniValue::VNUM)},
4919                 {"estimate_mode", UniValueType(UniValue::VSTR)},
4920             },
4921             true, true);
4922 
4923         if (options.exists("changeAddress")) {
4924             CTxDestination dest = DecodeDestination(options["changeAddress"].get_str());
4925 
4926             if (!IsValidDestination(dest)) {
4927                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid qtum address");
4928             }
4929 
4930             coinControl.destChange = dest;
4931         }
4932 
4933         if (options.exists("changePosition"))
4934             change_position = options["changePosition"].get_int();
4935 
4936         if (options.exists("change_type")) {
4937             if (options.exists("changeAddress")) {
4938                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both changeAddress and address_type options");
4939             }
4940             coinControl.m_change_type = pwallet->m_default_change_type;
4941             if (!ParseOutputType(options["change_type"].get_str(), *coinControl.m_change_type)) {
4942                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));
4943             }
4944         }
4945 
4946         coinControl.fAllowWatchOnly = ParseIncludeWatchonly(options["includeWatching"], *pwallet);
4947 
4948         if (options.exists("lockUnspents"))
4949             lockUnspents = options["lockUnspents"].get_bool();
4950 
4951         if (options.exists("feeRate"))
4952         {
4953             coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
4954             coinControl.fOverrideFeeRate = true;
4955         }
4956 
4957         if (options.exists("subtractFeeFromOutputs"))
4958             subtractFeeFromOutputs = options["subtractFeeFromOutputs"].get_array();
4959 
4960         if (options.exists("replaceable")) {
4961             coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
4962         }
4963         if (options.exists("conf_target")) {
4964             if (options.exists("feeRate")) {
4965                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate");
4966             }
4967             coinControl.m_confirm_target = ParseConfirmTarget(options["conf_target"], pwallet->chain().estimateMaxBlocks());
4968         }
4969         if (options.exists("estimate_mode")) {
4970             if (options.exists("feeRate")) {
4971                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
4972             }
4973             if (!FeeModeFromString(options["estimate_mode"].get_str(), coinControl.m_fee_mode)) {
4974                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
4975             }
4976         }
4977       }
4978     } else {
4979         // if options is null and not a bool
4980         coinControl.fAllowWatchOnly = ParseIncludeWatchonly(NullUniValue, *pwallet);
4981     }
4982 
4983     if (tx.vout.size() == 0)
4984         throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");
4985 
4986     if (change_position != -1 && (change_position < 0 || (unsigned int)change_position > tx.vout.size()))
4987         throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");
4988 
4989     for (unsigned int idx = 0; idx < subtractFeeFromOutputs.size(); idx++) {
4990         int pos = subtractFeeFromOutputs[idx].get_int();
4991         if (setSubtractFeeFromOutputs.count(pos))
4992             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, duplicated position: %d", pos));
4993         if (pos < 0)
4994             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, negative position: %d", pos));
4995         if (pos >= int(tx.vout.size()))
4996             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, position too large: %d", pos));
4997         setSubtractFeeFromOutputs.insert(pos);
4998     }
4999 
5000     std::string strFailReason;
5001 
5002     if (!pwallet->FundTransaction(tx, fee_out, change_position, strFailReason, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
5003         throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
5004     }
5005 }
5006 
fundrawtransaction(const JSONRPCRequest & request)5007 static UniValue fundrawtransaction(const JSONRPCRequest& request)
5008 {
5009     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
5010     CWallet* const pwallet = wallet.get();
5011 
5012     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
5013         return NullUniValue;
5014     }
5015 
5016     RPCHelpMan{"fundrawtransaction",
5017                 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
5018                 "This will not modify existing inputs, and will add at most one change output to the outputs.\n"
5019                 "No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
5020                 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
5021                 "The inputs added will not be signed, use signrawtransactionwithkey\n"
5022                 " or signrawtransactionwithwallet for that.\n"
5023                 "Note that all existing inputs must have their previous output transaction be in the wallet.\n"
5024                 "Note that all inputs selected must be of standard form and P2SH scripts must be\n"
5025                 "in the wallet using importaddress or addmultisigaddress (to calculate fees).\n"
5026                 "You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n"
5027                 "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n",
5028                 {
5029                     {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
5030                     {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
5031                         {
5032                             {"changeAddress", RPCArg::Type::STR, /* default */ "pool address", "The qtum address to receive the change"},
5033                             {"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
5034                             {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
5035                             {"includeWatching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only.\n"
5036                                                           "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
5037                                                           "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
5038                             {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
5039                             {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"},
5040                             {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "The integers.\n"
5041                             "                              The fee will be equally deducted from the amount of each specified output.\n"
5042                             "                              Those recipients will receive less qtums than you enter in their corresponding amount field.\n"
5043                             "                              If no outputs are specified here, the sender pays the fee.",
5044                                 {
5045                                     {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
5046                                 },
5047                             },
5048                             {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
5049                             "                              Allows this transaction to be replaced by a transaction with higher fees"},
5050                             {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
5051                             {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
5052                             "         \"UNSET\"\n"
5053                             "         \"ECONOMICAL\"\n"
5054                             "         \"CONSERVATIVE\""},
5055                         },
5056                         "options"},
5057                     {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
5058                         "If iswitness is not present, heuristic tests will be used in decoding.\n"
5059                         "If true, only witness deserialization will be tried.\n"
5060                         "If false, only non-witness deserialization will be tried.\n"
5061                         "This boolean should reflect whether the transaction has inputs\n"
5062                         "(e.g. fully valid, or on-chain transactions), if known by the caller."
5063                     },
5064                 },
5065                 RPCResult{
5066                     RPCResult::Type::OBJ, "", "",
5067                     {
5068                         {RPCResult::Type::STR_HEX, "hex", "The resulting raw transaction (hex-encoded string)"},
5069                         {RPCResult::Type::STR_AMOUNT, "fee", "Fee in " + CURRENCY_UNIT + " the resulting transaction pays"},
5070                         {RPCResult::Type::NUM, "changepos", "The position of the added change output, or -1"},
5071                     }
5072                                 },
5073                                 RPCExamples{
5074                             "\nCreate a transaction with no inputs\n"
5075                             + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
5076                             "\nAdd sufficient unsigned inputs to meet the output value\n"
5077                             + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
5078                             "\nSign the transaction\n"
5079                             + HelpExampleCli("signrawtransactionwithwallet", "\"fundedtransactionhex\"") +
5080                             "\nSend the transaction\n"
5081                             + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
5082                                 },
5083     }.Check(request);
5084 
5085     RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
5086 
5087     // parse hex string from parameter
5088     CMutableTransaction tx;
5089     bool try_witness = request.params[2].isNull() ? true : request.params[2].get_bool();
5090     bool try_no_witness = request.params[2].isNull() ? true : !request.params[2].get_bool();
5091     if (!DecodeHexTx(tx, request.params[0].get_str(), try_no_witness, try_witness)) {
5092         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
5093     }
5094 
5095     CAmount fee;
5096     int change_position;
5097     FundTransaction(pwallet, tx, fee, change_position, request.params[1]);
5098 
5099     UniValue result(UniValue::VOBJ);
5100     result.pushKV("hex", EncodeHexTx(CTransaction(tx)));
5101     result.pushKV("fee", ValueFromAmount(fee));
5102     result.pushKV("changepos", change_position);
5103 
5104     return result;
5105 }
5106 
signrawtransactionwithwallet(const JSONRPCRequest & request)5107 UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
5108 {
5109     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
5110     const CWallet* const pwallet = wallet.get();
5111 
5112     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
5113         return NullUniValue;
5114     }
5115 
5116             RPCHelpMan{"signrawtransactionwithwallet",
5117                 "\nSign inputs for raw transaction (serialized, hex-encoded).\n"
5118                 "The second optional argument (may be null) is an array of previous transaction outputs that\n"
5119                 "this transaction depends on but may not yet be in the block chain." +
5120         HELP_REQUIRING_PASSPHRASE,
5121                 {
5122                     {"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"},
5123                     {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The previous dependent transaction outputs",
5124                         {
5125                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
5126                                 {
5127                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
5128                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
5129                                     {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"},
5130                                     {"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"},
5131                                     {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"},
5132                                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "(required for Segwit inputs) the amount spent"},
5133                                 },
5134                             },
5135                         },
5136                     },
5137                     {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type. Must be one of\n"
5138             "       \"ALL\"\n"
5139             "       \"NONE\"\n"
5140             "       \"SINGLE\"\n"
5141             "       \"ALL|ANYONECANPAY\"\n"
5142             "       \"NONE|ANYONECANPAY\"\n"
5143             "       \"SINGLE|ANYONECANPAY\""},
5144                 },
5145                 RPCResult{
5146                     RPCResult::Type::OBJ, "", "",
5147                     {
5148                         {RPCResult::Type::STR_HEX, "hex", "The hex-encoded raw transaction with signature(s)"},
5149                         {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
5150                         {RPCResult::Type::ARR, "errors", "Script verification errors (if there are any)",
5151                         {
5152                             {RPCResult::Type::OBJ, "", "",
5153                             {
5154                                 {RPCResult::Type::STR_HEX, "txid", "The hash of the referenced, previous transaction"},
5155                                 {RPCResult::Type::NUM, "vout", "The index of the output to spent and used as input"},
5156                                 {RPCResult::Type::STR_HEX, "scriptSig", "The hex-encoded signature script"},
5157                                 {RPCResult::Type::NUM, "sequence", "Script sequence number"},
5158                                 {RPCResult::Type::STR, "error", "Verification or signing error related to the input"},
5159                             }},
5160                         }},
5161                     }
5162                 },
5163                 RPCExamples{
5164                     HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"")
5165             + HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"")
5166                 },
5167             }.Check(request);
5168 
5169     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true);
5170 
5171     CMutableTransaction mtx;
5172     if (!DecodeHexTx(mtx, request.params[0].get_str(), true)) {
5173         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
5174     }
5175 
5176     // Sign the transaction
5177     auto locked_chain = pwallet->chain().lock();
5178     LOCK(pwallet->cs_wallet);
5179     EnsureWalletIsUnlocked(pwallet);
5180 
5181     // Fetch previous transactions (inputs):
5182     std::map<COutPoint, Coin> coins;
5183     for (const CTxIn& txin : mtx.vin) {
5184         coins[txin.prevout]; // Create empty map entry keyed by prevout.
5185     }
5186     pwallet->chain().findCoins(coins);
5187 
5188     // Parse the prevtxs array
5189     ParsePrevouts(request.params[1], nullptr, coins);
5190 
5191     int nHashType = ParseSighashString(request.params[2]);
5192 
5193     // Script verification errors
5194     std::map<int, std::string> input_errors;
5195 
5196     CheckSenderSignatures(mtx);
5197     bool complete = pwallet->SignTransaction(mtx, coins, nHashType, input_errors);
5198     UniValue result(UniValue::VOBJ);
5199     SignTransactionResultToJSON(mtx, complete, coins, input_errors, result);
5200     return result;
5201 }
5202 
signrawsendertransactionwithwallet(const JSONRPCRequest & request)5203 UniValue signrawsendertransactionwithwallet(const JSONRPCRequest& request)
5204 {
5205     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
5206     CWallet* const pwallet = wallet.get();
5207 
5208     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
5209         return NullUniValue;
5210     }
5211 
5212     if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
5213         throw std::runtime_error(
5214             RPCHelpMan{"signrawsendertransactionwithwallet",
5215                 "\nSign OP_SENDER outputs for raw transaction (serialized, hex-encoded).\n" +
5216                     HELP_REQUIRING_PASSPHRASE,
5217                 {
5218                     {"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"},
5219                     {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type. Must be one of\n"
5220             "       \"ALL\"\n"
5221             "       \"NONE\"\n"
5222             "       \"SINGLE\"\n"
5223             "       \"ALL|ANYONECANPAY\"\n"
5224             "       \"NONE|ANYONECANPAY\"\n"
5225             "       \"SINGLE|ANYONECANPAY\""},
5226                 },
5227                 RPCResult{
5228                     RPCResult::Type::OBJ, "", "",
5229                     {
5230                         {RPCResult::Type::STR_HEX, "hex", "The hex-encoded raw transaction with signature(s)"},
5231                         {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
5232                         {RPCResult::Type::ARR, "errors", "Script verification errors (if there are any)",
5233                         {
5234                             {RPCResult::Type::OBJ, "", "",
5235                             {
5236                                 {RPCResult::Type::STR_AMOUNT, "amount", "The amount of the output"},
5237                                 {RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded public key script of the output"},
5238                                 {RPCResult::Type::STR, "error", "Verification or signing error related to the output"},
5239                             }},
5240                         }},
5241                     }
5242                 },
5243                 RPCExamples{
5244                     HelpExampleCli("signrawsendertransactionwithwallet", "\"myhex\"")
5245             + HelpExampleRpc("signrawsendertransactionwithwallet", "\"myhex\"")
5246                 },
5247             }.ToString());
5248 
5249     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR}, true);
5250 
5251     CMutableTransaction mtx;
5252     if (!DecodeHexTx(mtx, request.params[0].get_str(), true)) {
5253         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
5254     }
5255 
5256     // Sign the transaction
5257     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
5258     auto locked_chain = pwallet->chain().lock();
5259     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
5260     EnsureWalletIsUnlocked(pwallet);
5261 
5262     return SignTransactionSender(mtx, &spk_man, request.params[1]);
5263 }
5264 
bumpfee(const JSONRPCRequest & request)5265 static UniValue bumpfee(const JSONRPCRequest& request)
5266 {
5267     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
5268     CWallet* const pwallet = wallet.get();
5269 
5270 
5271     if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
5272         return NullUniValue;
5273 
5274             RPCHelpMan{"bumpfee",
5275                 "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
5276                 "An opt-in RBF transaction with the given txid must be in the wallet.\n"
5277                 "The command will pay the additional fee by reducing change outputs or adding inputs when necessary. It may add a new change output if one does not already exist.\n"
5278                 "All inputs in the original transaction will be included in the replacement transaction.\n"
5279                 "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
5280                 "By default, the new fee will be calculated automatically using estimatesmartfee.\n"
5281                 "The user can specify a confirmation target for estimatesmartfee.\n"
5282                 "Alternatively, the user can specify a fee_rate (" + CURRENCY_UNIT + " per kB) for the new transaction.\n"
5283                 "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n"
5284                 "returned by getnetworkinfo) to enter the node's mempool.\n",
5285                 {
5286                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"},
5287                     {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
5288                         {
5289                             {"confTarget", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
5290                             {"fee_rate", RPCArg::Type::NUM, /* default */ "fall back to 'confTarget'", "fee rate (NOT total fee) to pay, in " + CURRENCY_UNIT + " per kB\n"
5291             "                         Specify a fee rate instead of relying on the built-in fee estimator.\n"
5292                                      "Must be at least 0.0001 " + CURRENCY_UNIT + " per kB higher than the current transaction fee rate.\n"},
5293                             {"replaceable", RPCArg::Type::BOOL, /* default */ "true", "Whether the new transaction should still be\n"
5294             "                         marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n"
5295             "                         be left unchanged from the original. If false, any input sequence numbers in the\n"
5296             "                         original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
5297             "                         so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
5298             "                         still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
5299             "                         are replaceable)."},
5300                             {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
5301             "         \"UNSET\"\n"
5302             "         \"ECONOMICAL\"\n"
5303             "         \"CONSERVATIVE\""},
5304                         },
5305                         "options"},
5306                 },
5307                 RPCResult{
5308                     RPCResult::Type::OBJ, "", "", {
5309                         {RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction. Only returned when wallet private keys are disabled."},
5310                         {RPCResult::Type::STR_HEX, "txid", "The id of the new transaction. Only returned when wallet private keys are enabled."},
5311                         {RPCResult::Type::STR_AMOUNT, "origfee", "The fee of the replaced transaction."},
5312                         {RPCResult::Type::STR_AMOUNT, "fee", "The fee of the new transaction."},
5313                         {RPCResult::Type::ARR, "errors", "Errors encountered during processing (may be empty).",
5314                         {
5315                             {RPCResult::Type::STR, "", ""},
5316                         }},
5317                     }
5318                 },
5319                 RPCExamples{
5320             "\nBump the fee, get the new transaction\'s txid\n" +
5321                     HelpExampleCli("bumpfee", "<txid>")
5322                 },
5323             }.Check(request);
5324 
5325     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
5326     uint256 hash(ParseHashV(request.params[0], "txid"));
5327 
5328     CCoinControl coin_control;
5329     coin_control.fAllowWatchOnly = pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
5330     // optional parameters
5331     coin_control.m_signal_bip125_rbf = true;
5332 
5333     if (!request.params[1].isNull()) {
5334         UniValue options = request.params[1];
5335         RPCTypeCheckObj(options,
5336             {
5337                 {"confTarget", UniValueType(UniValue::VNUM)},
5338                 {"fee_rate", UniValueType(UniValue::VNUM)},
5339                 {"replaceable", UniValueType(UniValue::VBOOL)},
5340                 {"estimate_mode", UniValueType(UniValue::VSTR)},
5341             },
5342             true, true);
5343         if (options.exists("confTarget") && options.exists("fee_rate")) {
5344             throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget can't be set with fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
5345         } else if (options.exists("confTarget")) { // TODO: alias this to conf_target
5346             coin_control.m_confirm_target = ParseConfirmTarget(options["confTarget"], pwallet->chain().estimateMaxBlocks());
5347         } else if (options.exists("fee_rate")) {
5348             CFeeRate fee_rate(AmountFromValue(options["fee_rate"]));
5349             if (fee_rate <= CFeeRate(0)) {
5350                 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid fee_rate %s (must be greater than 0)", fee_rate.ToString()));
5351             }
5352             coin_control.m_feerate = fee_rate;
5353         }
5354 
5355         if (options.exists("replaceable")) {
5356             coin_control.m_signal_bip125_rbf = options["replaceable"].get_bool();
5357         }
5358         if (options.exists("estimate_mode")) {
5359             if (!FeeModeFromString(options["estimate_mode"].get_str(), coin_control.m_fee_mode)) {
5360                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
5361             }
5362         }
5363     }
5364 
5365     // Make sure the results are valid at least up to the most recent block
5366     // the user could have gotten from another RPC command prior to now
5367     pwallet->BlockUntilSyncedToCurrentChain();
5368 
5369     auto locked_chain = pwallet->chain().lock();
5370     LOCK(pwallet->cs_wallet);
5371     EnsureWalletIsUnlocked(pwallet);
5372 
5373 
5374     std::vector<std::string> errors;
5375     CAmount old_fee;
5376     CAmount new_fee;
5377     CMutableTransaction mtx;
5378     feebumper::Result res;
5379     // Targeting feerate bump.
5380     res = feebumper::CreateRateBumpTransaction(*pwallet, hash, coin_control, errors, old_fee, new_fee, mtx);
5381     if (res != feebumper::Result::OK) {
5382         switch(res) {
5383             case feebumper::Result::INVALID_ADDRESS_OR_KEY:
5384                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errors[0]);
5385                 break;
5386             case feebumper::Result::INVALID_REQUEST:
5387                 throw JSONRPCError(RPC_INVALID_REQUEST, errors[0]);
5388                 break;
5389             case feebumper::Result::INVALID_PARAMETER:
5390                 throw JSONRPCError(RPC_INVALID_PARAMETER, errors[0]);
5391                 break;
5392             case feebumper::Result::WALLET_ERROR:
5393                 throw JSONRPCError(RPC_WALLET_ERROR, errors[0]);
5394                 break;
5395             default:
5396                 throw JSONRPCError(RPC_MISC_ERROR, errors[0]);
5397                 break;
5398         }
5399     }
5400 
5401     UniValue result(UniValue::VOBJ);
5402 
5403     // If wallet private keys are enabled, return the new transaction id,
5404     // otherwise return the base64-encoded unsigned PSBT of the new transaction.
5405     if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
5406         if (!feebumper::SignTransaction(*pwallet, mtx)) {
5407             throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
5408         }
5409 
5410         uint256 txid;
5411         if (feebumper::CommitTransaction(*pwallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
5412             throw JSONRPCError(RPC_WALLET_ERROR, errors[0]);
5413         }
5414 
5415         result.pushKV("txid", txid.GetHex());
5416     } else {
5417         PartiallySignedTransaction psbtx(mtx);
5418         bool complete = false;
5419         const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_ALL, false /* sign */, true /* bip32derivs */);
5420         CHECK_NONFATAL(err == TransactionError::OK);
5421         CHECK_NONFATAL(!complete);
5422         CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
5423         ssTx << psbtx;
5424         result.pushKV("psbt", EncodeBase64(ssTx.str()));
5425     }
5426 
5427     result.pushKV("origfee", ValueFromAmount(old_fee));
5428     result.pushKV("fee", ValueFromAmount(new_fee));
5429     UniValue result_errors(UniValue::VARR);
5430     for (const std::string& error : errors) {
5431         result_errors.push_back(error);
5432     }
5433     result.pushKV("errors", result_errors);
5434 
5435     return result;
5436 }
5437 
rescanblockchain(const JSONRPCRequest & request)5438 UniValue rescanblockchain(const JSONRPCRequest& request)
5439 {
5440     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
5441     CWallet* const pwallet = wallet.get();
5442 
5443     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
5444         return NullUniValue;
5445     }
5446 
5447             RPCHelpMan{"rescanblockchain",
5448                 "\nRescan the local blockchain for wallet related transactions.\n"
5449                 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
5450                 {
5451                     {"start_height", RPCArg::Type::NUM, /* default */ "0", "block height where the rescan should start"},
5452                     {"stop_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "the last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call."},
5453                 },
5454                 RPCResult{
5455                     RPCResult::Type::OBJ, "", "",
5456                     {
5457                         {RPCResult::Type::NUM, "start_height", "The block height where the rescan started (the requested height or 0)"},
5458                         {RPCResult::Type::NUM, "stop_height", "The height of the last rescanned block. May be null in rare cases if there was a reorg and the call didn't scan any blocks because they were already scanned in the background."},
5459                     }
5460                 },
5461                 RPCExamples{
5462                     HelpExampleCli("rescanblockchain", "100000 120000")
5463             + HelpExampleRpc("rescanblockchain", "100000, 120000")
5464                 },
5465             }.Check(request);
5466 
5467     WalletRescanReserver reserver(pwallet);
5468     if (!reserver.reserve()) {
5469         throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
5470     }
5471 
5472     int start_height = 0;
5473     uint256 start_block, stop_block;
5474     {
5475         auto locked_chain = pwallet->chain().lock();
5476         Optional<int> tip_height = locked_chain->getHeight();
5477 
5478         if (!request.params[0].isNull()) {
5479             start_height = request.params[0].get_int();
5480             if (start_height < 0 || !tip_height || start_height > *tip_height) {
5481                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
5482             }
5483         }
5484 
5485         Optional<int> stop_height;
5486         if (!request.params[1].isNull()) {
5487             stop_height = request.params[1].get_int();
5488             if (*stop_height < 0 || !tip_height || *stop_height > *tip_height) {
5489                 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
5490             }
5491             else if (*stop_height < start_height) {
5492                 throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater than start_height");
5493             }
5494         }
5495 
5496         // We can't rescan beyond non-pruned blocks, stop and throw an error
5497         if (locked_chain->findPruned(start_height, stop_height)) {
5498             throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
5499         }
5500 
5501         if (tip_height) {
5502             start_block = locked_chain->getBlockHash(start_height);
5503             // If called with a stop_height, set the stop_height here to
5504             // trigger a rescan to that height.
5505             // If called without a stop height, leave stop_height as null here
5506             // so rescan continues to the tip (even if the tip advances during
5507             // rescan).
5508             if (stop_height) {
5509                 stop_block = locked_chain->getBlockHash(*stop_height);
5510             }
5511         }
5512     }
5513 
5514     CWallet::ScanResult result =
5515         pwallet->ScanForWalletTransactions(start_block, stop_block, reserver, true /* fUpdate */);
5516     switch (result.status) {
5517     case CWallet::ScanResult::SUCCESS:
5518         break;
5519     case CWallet::ScanResult::FAILURE:
5520         throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
5521     case CWallet::ScanResult::USER_ABORT:
5522         throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
5523         // no default case, so the compiler can warn about missing cases
5524     }
5525     UniValue response(UniValue::VOBJ);
5526     response.pushKV("start_height", start_height);
5527     response.pushKV("stop_height", result.last_scanned_height ? *result.last_scanned_height : UniValue());
5528     return response;
5529 }
5530 
5531 class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue>
5532 {
5533 public:
5534     const SigningProvider * const provider;
5535 
ProcessSubScript(const CScript & subscript,UniValue & obj) const5536     void ProcessSubScript(const CScript& subscript, UniValue& obj) const
5537     {
5538         // Always present: script type and redeemscript
5539         std::vector<std::vector<unsigned char>> solutions_data;
5540         txnouttype which_type = Solver(subscript, solutions_data);
5541         obj.pushKV("script", GetTxnOutputType(which_type));
5542         obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
5543 
5544         CTxDestination embedded;
5545         if (ExtractDestination(subscript, embedded)) {
5546             // Only when the script corresponds to an address.
5547             UniValue subobj(UniValue::VOBJ);
5548             UniValue detail = DescribeAddress(embedded);
5549             subobj.pushKVs(detail);
5550             UniValue wallet_detail = boost::apply_visitor(*this, embedded);
5551             subobj.pushKVs(wallet_detail);
5552             subobj.pushKV("address", EncodeDestination(embedded));
5553             subobj.pushKV("scriptPubKey", HexStr(subscript.begin(), subscript.end()));
5554             // Always report the pubkey at the top level, so that `getnewaddress()['pubkey']` always works.
5555             if (subobj.exists("pubkey")) obj.pushKV("pubkey", subobj["pubkey"]);
5556             obj.pushKV("embedded", std::move(subobj));
5557         } else if (which_type == TX_MULTISIG) {
5558             // Also report some information on multisig scripts (which do not have a corresponding address).
5559             // TODO: abstract out the common functionality between this logic and ExtractDestinations.
5560             obj.pushKV("sigsrequired", solutions_data[0][0]);
5561             UniValue pubkeys(UniValue::VARR);
5562             for (size_t i = 1; i < solutions_data.size() - 1; ++i) {
5563                 CPubKey key(solutions_data[i].begin(), solutions_data[i].end());
5564                 pubkeys.push_back(HexStr(key.begin(), key.end()));
5565             }
5566             obj.pushKV("pubkeys", std::move(pubkeys));
5567         }
5568     }
5569 
DescribeWalletAddressVisitor(const SigningProvider * _provider)5570     explicit DescribeWalletAddressVisitor(const SigningProvider* _provider) : provider(_provider) {}
5571 
operator ()(const CNoDestination & dest) const5572     UniValue operator()(const CNoDestination& dest) const { return UniValue(UniValue::VOBJ); }
5573 
operator ()(const PKHash & pkhash) const5574     UniValue operator()(const PKHash& pkhash) const
5575     {
5576         CKeyID keyID(pkhash);
5577         UniValue obj(UniValue::VOBJ);
5578         CPubKey vchPubKey;
5579         if (provider && provider->GetPubKey(keyID, vchPubKey)) {
5580             obj.pushKV("pubkey", HexStr(vchPubKey));
5581             obj.pushKV("iscompressed", vchPubKey.IsCompressed());
5582         }
5583         return obj;
5584     }
5585 
operator ()(const ScriptHash & scripthash) const5586     UniValue operator()(const ScriptHash& scripthash) const
5587     {
5588         CScriptID scriptID(scripthash);
5589         UniValue obj(UniValue::VOBJ);
5590         CScript subscript;
5591         if (provider && provider->GetCScript(scriptID, subscript)) {
5592             ProcessSubScript(subscript, obj);
5593         }
5594         return obj;
5595     }
5596 
operator ()(const WitnessV0KeyHash & id) const5597     UniValue operator()(const WitnessV0KeyHash& id) const
5598     {
5599         UniValue obj(UniValue::VOBJ);
5600         CPubKey pubkey;
5601         if (provider && provider->GetPubKey(CKeyID(id), pubkey)) {
5602             obj.pushKV("pubkey", HexStr(pubkey));
5603         }
5604         return obj;
5605     }
5606 
operator ()(const WitnessV0ScriptHash & id) const5607     UniValue operator()(const WitnessV0ScriptHash& id) const
5608     {
5609         UniValue obj(UniValue::VOBJ);
5610         CScript subscript;
5611         CRIPEMD160 hasher;
5612         uint160 hash;
5613         hasher.Write(id.begin(), 32).Finalize(hash.begin());
5614         if (provider && provider->GetCScript(CScriptID(hash), subscript)) {
5615             ProcessSubScript(subscript, obj);
5616         }
5617         return obj;
5618     }
5619 
operator ()(const WitnessUnknown & id) const5620     UniValue operator()(const WitnessUnknown& id) const { return UniValue(UniValue::VOBJ); }
5621 };
5622 
DescribeWalletAddress(const CWallet * const pwallet,const CTxDestination & dest)5623 static UniValue DescribeWalletAddress(const CWallet* const pwallet, const CTxDestination& dest)
5624 {
5625     UniValue ret(UniValue::VOBJ);
5626     UniValue detail = DescribeAddress(dest);
5627     CScript script = GetScriptForDestination(dest);
5628     std::unique_ptr<SigningProvider> provider = nullptr;
5629     if (pwallet) {
5630         provider = pwallet->GetSolvingProvider(script);
5631     }
5632     ret.pushKVs(detail);
5633     ret.pushKVs(boost::apply_visitor(DescribeWalletAddressVisitor(provider.get()), dest));
5634     return ret;
5635 }
5636 
5637 /** Convert CAddressBookData to JSON record.  */
AddressBookDataToJSON(const CAddressBookData & data,const bool verbose)5638 static UniValue AddressBookDataToJSON(const CAddressBookData& data, const bool verbose)
5639 {
5640     UniValue ret(UniValue::VOBJ);
5641     if (verbose) {
5642         ret.pushKV("name", data.GetLabel());
5643     }
5644     ret.pushKV("purpose", data.purpose);
5645     return ret;
5646 }
5647 
getaddressinfo(const JSONRPCRequest & request)5648 UniValue getaddressinfo(const JSONRPCRequest& request)
5649 {
5650     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
5651     const CWallet* const pwallet = wallet.get();
5652 
5653     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
5654         return NullUniValue;
5655     }
5656 
5657             RPCHelpMan{"getaddressinfo",
5658                 "\nReturn information about the given qtum address.\n"
5659                 "Some of the information will only be present if the address is in the active wallet.\n",
5660                 {
5661                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The qtum address for which to get information."},
5662                 },
5663                 RPCResult{
5664                     RPCResult::Type::OBJ, "", "",
5665                     {
5666                         {RPCResult::Type::STR, "address", "The qtum address validated."},
5667                         {RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded scriptPubKey generated by the address."},
5668                         {RPCResult::Type::BOOL, "ismine", "If the address is yours."},
5669                         {RPCResult::Type::BOOL, "iswatchonly", "If the address is watchonly."},
5670                         {RPCResult::Type::BOOL, "solvable", "If we know how to spend coins sent to this address, ignoring the possible lack of private keys."},
5671                         {RPCResult::Type::STR, "desc", /* optional */ true, "A descriptor for spending coins sent to this address (only when solvable)."},
5672                         {RPCResult::Type::BOOL, "isscript", "If the key is a script."},
5673                         {RPCResult::Type::BOOL, "ischange", "If the address was used for change output."},
5674                         {RPCResult::Type::BOOL, "iswitness", "If the address is a witness address."},
5675                         {RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program."},
5676                         {RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program."},
5677                         {RPCResult::Type::STR, "script", /* optional */ true, "The output script type. Only if isscript is true and the redeemscript is known. Possible\n"
5678             "                                                         types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash,\n"
5679                             "witness_v0_scripthash, witness_unknown."},
5680                         {RPCResult::Type::STR_HEX, "hex", /* optional */ true, "The redeemscript for the p2sh address."},
5681                         {RPCResult::Type::ARR, "pubkeys", /* optional */ true, "Array of pubkeys associated with the known redeemscript (only if script is multisig).",
5682                         {
5683                             {RPCResult::Type::STR, "pubkey", ""},
5684                         }},
5685                         {RPCResult::Type::NUM, "sigsrequired", /* optional */ true, "The number of signatures required to spend multisig output (only if script is multisig)."},
5686                         {RPCResult::Type::STR_HEX, "pubkey", /* optional */ true, "The hex value of the raw public key for single-key addresses (possibly embedded in P2SH or P2WSH)."},
5687                         {RPCResult::Type::OBJ, "embedded", /* optional */ true, "Information about the address embedded in P2SH or P2WSH, if relevant and known.",
5688                         {
5689                             {RPCResult::Type::ELISION, "", "Includes all\n"
5690             "                                                         getaddressinfo output fields for the embedded address, excluding metadata (timestamp, hdkeypath,\n"
5691                             "hdseedid) and relation to the wallet (ismine, iswatchonly)."},
5692                         }},
5693                         {RPCResult::Type::BOOL, "iscompressed", /* optional */ true, "If the pubkey is compressed."},
5694                         {RPCResult::Type::STR, "label", "DEPRECATED. The label associated with the address. Defaults to \"\". Replaced by the labels array below."},
5695                         {RPCResult::Type::NUM_TIME, "timestamp", /* optional */ true, "The creation time of the key, if available, expressed in " + UNIX_EPOCH_TIME + "."},
5696                         {RPCResult::Type::STR, "hdkeypath", /* optional */ true, "The HD keypath, if the key is HD and available."},
5697                         {RPCResult::Type::STR_HEX, "hdseedid", /* optional */ true, "The Hash160 of the HD seed."},
5698                         {RPCResult::Type::STR_HEX, "hdmasterfingerprint", /* optional */ true, "The fingerprint of the master key."},
5699                         {RPCResult::Type::ARR, "labels", "Array of labels associated with the address. Currently limited to one label but returned\n"
5700                             "as an array to keep the API stable if multiple labels are enabled in the future.",
5701                         {
5702                             {RPCResult::Type::STR, "label name", "The label name. Defaults to \"\"."},
5703                             {RPCResult::Type::OBJ, "", "label data, DEPRECATED, will be removed in 0.21. To re-enable, launch qtumd with `-deprecatedrpc=labelspurpose`",
5704                             {
5705                                 {RPCResult::Type::STR, "name", "The label name. Defaults to \"\"."},
5706                                 {RPCResult::Type::STR, "purpose", "The purpose of the associated address (send or receive)."},
5707                             }},
5708                         }},
5709                     }
5710                 },
5711                 RPCExamples{
5712                     HelpExampleCli("getaddressinfo", "\"" + EXAMPLE_ADDRESS[0] + "\"") +
5713                     HelpExampleRpc("getaddressinfo", "\"" + EXAMPLE_ADDRESS[0] + "\"")
5714                 },
5715             }.Check(request);
5716 
5717     LOCK(pwallet->cs_wallet);
5718 
5719     UniValue ret(UniValue::VOBJ);
5720     CTxDestination dest = DecodeDestination(request.params[0].get_str());
5721     // Make sure the destination is valid
5722     if (!IsValidDestination(dest)) {
5723         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
5724     }
5725 
5726     std::string currentAddress = EncodeDestination(dest);
5727     ret.pushKV("address", currentAddress);
5728 
5729     CScript scriptPubKey = GetScriptForDestination(dest);
5730     ret.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
5731 
5732     std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
5733 
5734     isminetype mine = pwallet->IsMine(dest);
5735     ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE));
5736 
5737     bool solvable = provider && IsSolvable(*provider, scriptPubKey);
5738     ret.pushKV("solvable", solvable);
5739 
5740     if (solvable) {
5741        ret.pushKV("desc", InferDescriptor(scriptPubKey, *provider)->ToString());
5742     }
5743 
5744     ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
5745 
5746     UniValue detail = DescribeWalletAddress(pwallet, dest);
5747     ret.pushKVs(detail);
5748 
5749     // DEPRECATED: Return label field if existing. Currently only one label can
5750     // be associated with an address, so the label should be equivalent to the
5751     // value of the name key/value pair in the labels array below.
5752     const auto* address_book_entry = pwallet->FindAddressBookEntry(dest);
5753     if (pwallet->chain().rpcEnableDeprecated("label") && address_book_entry) {
5754         ret.pushKV("label", address_book_entry->GetLabel());
5755     }
5756 
5757     ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
5758 
5759     ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan(scriptPubKey);
5760     if (spk_man) {
5761         if (const CKeyMetadata* meta = spk_man->GetMetadata(dest)) {
5762             ret.pushKV("timestamp", meta->nCreateTime);
5763             if (meta->has_key_origin) {
5764                 ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path));
5765                 ret.pushKV("hdseedid", meta->hd_seed_id.GetHex());
5766                 ret.pushKV("hdmasterfingerprint", HexStr(meta->key_origin.fingerprint, meta->key_origin.fingerprint + 4));
5767             }
5768         }
5769     }
5770 
5771     // Return a `labels` array containing the label associated with the address,
5772     // equivalent to the `label` field above. Currently only one label can be
5773     // associated with an address, but we return an array so the API remains
5774     // stable if we allow multiple labels to be associated with an address in
5775     // the future.
5776     UniValue labels(UniValue::VARR);
5777     if (address_book_entry) {
5778         // DEPRECATED: The previous behavior of returning an array containing a
5779         // JSON object of `name` and `purpose` key/value pairs is deprecated.
5780         if (pwallet->chain().rpcEnableDeprecated("labelspurpose")) {
5781             labels.push_back(AddressBookDataToJSON(*address_book_entry, true));
5782         } else {
5783             labels.push_back(address_book_entry->GetLabel());
5784         }
5785     }
5786     ret.pushKV("labels", std::move(labels));
5787 
5788     return ret;
5789 }
5790 
getaddressesbylabel(const JSONRPCRequest & request)5791 static UniValue getaddressesbylabel(const JSONRPCRequest& request)
5792 {
5793     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
5794     const CWallet* const pwallet = wallet.get();
5795 
5796     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
5797         return NullUniValue;
5798     }
5799 
5800             RPCHelpMan{"getaddressesbylabel",
5801                 "\nReturns the list of addresses assigned the specified label.\n",
5802                 {
5803                     {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label."},
5804                 },
5805                 RPCResult{
5806                     RPCResult::Type::OBJ_DYN, "", "json object with addresses as keys",
5807                     {
5808                         {RPCResult::Type::OBJ, "address", "json object with information about address",
5809                         {
5810                             {RPCResult::Type::STR, "purpose", "Purpose of address (\"send\" for sending address, \"receive\" for receiving address)"},
5811                         }},
5812                     }
5813                 },
5814                 RPCExamples{
5815                     HelpExampleCli("getaddressesbylabel", "\"tabby\"")
5816             + HelpExampleRpc("getaddressesbylabel", "\"tabby\"")
5817                 },
5818             }.Check(request);
5819 
5820     LOCK(pwallet->cs_wallet);
5821 
5822     std::string label = LabelFromValue(request.params[0]);
5823 
5824     // Find all addresses that have the given label
5825     UniValue ret(UniValue::VOBJ);
5826     std::set<std::string> addresses;
5827     for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->m_address_book) {
5828         if (item.second.IsChange()) continue;
5829         if (item.second.GetLabel() == label) {
5830             std::string address = EncodeDestination(item.first);
5831             // CWallet::m_address_book is not expected to contain duplicate
5832             // address strings, but build a separate set as a precaution just in
5833             // case it does.
5834             bool unique = addresses.emplace(address).second;
5835             CHECK_NONFATAL(unique);
5836             // UniValue::pushKV checks if the key exists in O(N)
5837             // and since duplicate addresses are unexpected (checked with
5838             // std::set in O(log(N))), UniValue::__pushKV is used instead,
5839             // which currently is O(1).
5840             ret.__pushKV(address, AddressBookDataToJSON(item.second, false));
5841         }
5842     }
5843 
5844     if (ret.empty()) {
5845         throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, std::string("No addresses with label " + label));
5846     }
5847 
5848     return ret;
5849 }
5850 
listlabels(const JSONRPCRequest & request)5851 static UniValue listlabels(const JSONRPCRequest& request)
5852 {
5853     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
5854     const CWallet* const pwallet = wallet.get();
5855 
5856     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
5857         return NullUniValue;
5858     }
5859 
5860             RPCHelpMan{"listlabels",
5861                 "\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n",
5862                 {
5863                     {"purpose", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument."},
5864                 },
5865                 RPCResult{
5866                     RPCResult::Type::ARR, "", "",
5867                     {
5868                         {RPCResult::Type::STR, "label", "Label name"},
5869                     }
5870                 },
5871                 RPCExamples{
5872             "\nList all labels\n"
5873             + HelpExampleCli("listlabels", "") +
5874             "\nList labels that have receiving addresses\n"
5875             + HelpExampleCli("listlabels", "receive") +
5876             "\nList labels that have sending addresses\n"
5877             + HelpExampleCli("listlabels", "send") +
5878             "\nAs a JSON-RPC call\n"
5879             + HelpExampleRpc("listlabels", "receive")
5880                 },
5881             }.Check(request);
5882 
5883     LOCK(pwallet->cs_wallet);
5884 
5885     std::string purpose;
5886     if (!request.params[0].isNull()) {
5887         purpose = request.params[0].get_str();
5888     }
5889 
5890     // Add to a set to sort by label name, then insert into Univalue array
5891     std::set<std::string> label_set;
5892     for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->m_address_book) {
5893         if (entry.second.IsChange()) continue;
5894         if (purpose.empty() || entry.second.purpose == purpose) {
5895             label_set.insert(entry.second.GetLabel());
5896         }
5897     }
5898 
5899     UniValue ret(UniValue::VARR);
5900     for (const std::string& name : label_set) {
5901         ret.push_back(name);
5902     }
5903 
5904     return ret;
5905 }
5906 
sethdseed(const JSONRPCRequest & request)5907 UniValue sethdseed(const JSONRPCRequest& request)
5908 {
5909     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
5910     CWallet* const pwallet = wallet.get();
5911 
5912     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
5913         return NullUniValue;
5914     }
5915 
5916             RPCHelpMan{"sethdseed",
5917                 "\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n"
5918                 "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
5919                 "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." +
5920         HELP_REQUIRING_PASSPHRASE,
5921                 {
5922                     {"newkeypool", RPCArg::Type::BOOL, /* default */ "true", "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
5923             "                             If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
5924             "                             If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
5925             "                             keypool will be used until it has been depleted."},
5926                     {"seed", RPCArg::Type::STR, /* default */ "random seed", "The WIF private key to use as the new HD seed.\n"
5927             "                             The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"},
5928                 },
5929                 RPCResult{RPCResult::Type::NONE, "", ""},
5930                 RPCExamples{
5931                     HelpExampleCli("sethdseed", "")
5932             + HelpExampleCli("sethdseed", "false")
5933             + HelpExampleCli("sethdseed", "true \"wifkey\"")
5934             + HelpExampleRpc("sethdseed", "true, \"wifkey\"")
5935                 },
5936             }.Check(request);
5937 
5938     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
5939 
5940     if (pwallet->chain().isInitialBlockDownload()) {
5941         throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set a new HD seed while still in Initial Block Download");
5942     }
5943 
5944     if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
5945         throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed to a wallet with private keys disabled");
5946     }
5947 
5948     auto locked_chain = pwallet->chain().lock();
5949     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
5950 
5951     // Do not do anything to non-HD wallets
5952     if (!pwallet->CanSupportFeature(FEATURE_HD)) {
5953         throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed on a non-HD wallet. Start with -upgradewallet in order to upgrade a non-HD wallet to HD");
5954     }
5955 
5956     EnsureWalletIsUnlocked(pwallet);
5957 
5958     bool flush_key_pool = true;
5959     if (!request.params[0].isNull()) {
5960         flush_key_pool = request.params[0].get_bool();
5961     }
5962 
5963     CPubKey master_pub_key;
5964     if (request.params[1].isNull()) {
5965         master_pub_key = spk_man.GenerateNewSeed();
5966     } else {
5967         CKey key = DecodeSecret(request.params[1].get_str());
5968         if (!key.IsValid()) {
5969             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
5970         }
5971 
5972         if (HaveKey(spk_man, key)) {
5973             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
5974         }
5975 
5976         master_pub_key = spk_man.DeriveNewSeed(key);
5977     }
5978 
5979     spk_man.SetHDSeed(master_pub_key);
5980     if (flush_key_pool) spk_man.NewKeyPool();
5981 
5982     return NullUniValue;
5983 }
5984 
walletprocesspsbt(const JSONRPCRequest & request)5985 UniValue walletprocesspsbt(const JSONRPCRequest& request)
5986 {
5987     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
5988     const CWallet* const pwallet = wallet.get();
5989 
5990     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
5991         return NullUniValue;
5992     }
5993 
5994             RPCHelpMan{"walletprocesspsbt",
5995                 "\nUpdate a PSBT with input information from our wallet and then sign inputs\n"
5996                 "that we can sign for." +
5997         HELP_REQUIRING_PASSPHRASE,
5998                 {
5999                     {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction base64 string"},
6000                     {"sign", RPCArg::Type::BOOL, /* default */ "true", "Also sign the transaction when updating"},
6001                     {"sighashtype", RPCArg::Type::STR, /* default */ "ALL", "The signature hash type to sign with if not specified by the PSBT. Must be one of\n"
6002             "       \"ALL\"\n"
6003             "       \"NONE\"\n"
6004             "       \"SINGLE\"\n"
6005             "       \"ALL|ANYONECANPAY\"\n"
6006             "       \"NONE|ANYONECANPAY\"\n"
6007             "       \"SINGLE|ANYONECANPAY\""},
6008                     {"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"},
6009                 },
6010                 RPCResult{
6011                     RPCResult::Type::OBJ, "", "",
6012                     {
6013                         {RPCResult::Type::STR, "psbt", "The base64-encoded partially signed transaction"},
6014                         {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
6015                     }
6016                 },
6017                 RPCExamples{
6018                     HelpExampleCli("walletprocesspsbt", "\"psbt\"")
6019                 },
6020             }.Check(request);
6021 
6022     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR});
6023 
6024     // Unserialize the transaction
6025     PartiallySignedTransaction psbtx;
6026     std::string error;
6027     if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
6028         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
6029     }
6030 
6031     // Get the sighash type
6032     int nHashType = ParseSighashString(request.params[2]);
6033 
6034     // Fill transaction with our data and also sign
6035     bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();
6036     bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool();
6037     bool complete = true;
6038     const TransactionError err = pwallet->FillPSBT(psbtx, complete, nHashType, sign, bip32derivs);
6039     if (err != TransactionError::OK) {
6040         throw JSONRPCTransactionError(err);
6041     }
6042 
6043     UniValue result(UniValue::VOBJ);
6044     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
6045     ssTx << psbtx;
6046     result.pushKV("psbt", EncodeBase64(ssTx.str()));
6047     result.pushKV("complete", complete);
6048 
6049     return result;
6050 }
6051 
walletcreatefundedpsbt(const JSONRPCRequest & request)6052 UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
6053 {
6054     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
6055     CWallet* const pwallet = wallet.get();
6056 
6057     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
6058         return NullUniValue;
6059     }
6060 
6061             RPCHelpMan{"walletcreatefundedpsbt",
6062                 "\nCreates and funds a transaction in the Partially Signed Transaction format. Inputs will be added if supplied inputs are not enough\n"
6063                 "Implements the Creator and Updater roles.\n",
6064                 {
6065                     {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The inputs",
6066                         {
6067                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
6068                                 {
6069                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
6070                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
6071                                     {"sequence", RPCArg::Type::NUM, RPCArg::Optional::NO, "The sequence number"},
6072                                 },
6073                             },
6074                         },
6075                         },
6076                     {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n"
6077                             "That is, each address can only appear once and there can only be one 'data' object.\n"
6078                             "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
6079                             "                             accepted as second parameter.",
6080                         {
6081                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
6082                                 {
6083                                     {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the qtum address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
6084                                 },
6085                                 },
6086                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
6087                                 {
6088                                     {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
6089                                 },
6090                             },
6091                         },
6092                     },
6093                     {"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
6094                     {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
6095                         {
6096                             {"changeAddress", RPCArg::Type::STR_HEX, /* default */ "pool address", "The qtum address to receive the change"},
6097                             {"changePosition", RPCArg::Type::NUM, /* default */ "random", "The index of the change output"},
6098                             {"change_type", RPCArg::Type::STR, /* default */ "set by -changetype", "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
6099                             {"includeWatching", RPCArg::Type::BOOL, /* default */ "true for watch-only wallets, otherwise false", "Also select inputs which are watch only"},
6100                             {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false", "Lock selected unspent outputs"},
6101                             {"feeRate", RPCArg::Type::AMOUNT, /* default */ "not set: makes wallet determine the fee", "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"},
6102                             {"subtractFeeFromOutputs", RPCArg::Type::ARR, /* default */ "empty array", "The outputs to subtract the fee from.\n"
6103                             "                              The fee will be equally deducted from the amount of each specified output.\n"
6104                             "                              Those recipients will receive less qtums than you enter in their corresponding amount field.\n"
6105                             "                              If no outputs are specified here, the sender pays the fee.",
6106                                 {
6107                                     {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
6108                                 },
6109                             },
6110                             {"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
6111                             "                              Allows this transaction to be replaced by a transaction with higher fees"},
6112                             {"conf_target", RPCArg::Type::NUM, /* default */ "fall back to wallet's confirmation target (txconfirmtarget)", "Confirmation target (in blocks)"},
6113                             {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
6114                             "         \"UNSET\"\n"
6115                             "         \"ECONOMICAL\"\n"
6116                             "         \"CONSERVATIVE\""},
6117                         },
6118                         "options"},
6119                     {"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"},
6120                 },
6121                 RPCResult{
6122                     RPCResult::Type::OBJ, "", "",
6123                     {
6124                         {RPCResult::Type::STR, "psbt", "The resulting raw transaction (base64-encoded string)"},
6125                         {RPCResult::Type::STR_AMOUNT, "fee", "Fee in " + CURRENCY_UNIT + " the resulting transaction pays"},
6126                         {RPCResult::Type::NUM, "changepos", "The position of the added change output, or -1"},
6127                     }
6128                                 },
6129                                 RPCExamples{
6130                             "\nCreate a transaction with no inputs\n"
6131                             + HelpExampleCli("walletcreatefundedpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
6132                                 },
6133                             }.Check(request);
6134 
6135     RPCTypeCheck(request.params, {
6136         UniValue::VARR,
6137         UniValueType(), // ARR or OBJ, checked later
6138         UniValue::VNUM,
6139         UniValue::VOBJ,
6140         UniValue::VBOOL
6141         }, true
6142     );
6143 
6144     CAmount fee;
6145     int change_position;
6146     bool rbf = pwallet->m_signal_rbf;
6147     const UniValue &replaceable_arg = request.params[3]["replaceable"];
6148     if (!replaceable_arg.isNull()) {
6149         RPCTypeCheckArgument(replaceable_arg, UniValue::VBOOL);
6150         rbf = replaceable_arg.isTrue();
6151     }
6152     CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
6153     FundTransaction(pwallet, rawTx, fee, change_position, request.params[3]);
6154 
6155     // Make a blank psbt
6156     PartiallySignedTransaction psbtx(rawTx);
6157 
6158     // Fill transaction with out data but don't sign
6159     bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool();
6160     bool complete = true;
6161     const TransactionError err = pwallet->FillPSBT(psbtx, complete, 1, false, bip32derivs);
6162     if (err != TransactionError::OK) {
6163         throw JSONRPCTransactionError(err);
6164     }
6165 
6166     // Serialize the PSBT
6167     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
6168     ssTx << psbtx;
6169 
6170     UniValue result(UniValue::VOBJ);
6171     result.pushKV("psbt", EncodeBase64(ssTx.str()));
6172     result.pushKV("fee", ValueFromAmount(fee));
6173     result.pushKV("changepos", change_position);
6174     return result;
6175 }
6176 
qrc20approve(const JSONRPCRequest & request)6177 static UniValue qrc20approve(const JSONRPCRequest& request)
6178 {
6179     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
6180     CWallet* const pwallet = wallet.get();
6181 
6182     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
6183         return NullUniValue;
6184     }
6185 
6186     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
6187     auto locked_chain = pwallet->chain().lock();
6188     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
6189     QtumDGP qtumDGP(globalState.get(), fGettingValuesDGP);
6190     uint64_t blockGasLimit = qtumDGP.getBlockGasLimit(::ChainActive().Height());
6191     uint64_t minGasPrice = CAmount(qtumDGP.getMinGasPrice(::ChainActive().Height()));
6192     CAmount nGasPrice = (minGasPrice>DEFAULT_GAS_PRICE)?minGasPrice:DEFAULT_GAS_PRICE;
6193     uint64_t nGasLimit=DEFAULT_GAS_LIMIT_OP_SEND;
6194     bool fCheckOutputs = true;
6195 
6196             RPCHelpMan{"qrc20approve",
6197                 "\nOwner approves an address to spend some amount of tokens.\n",
6198                 {
6199                     {"contractaddress", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The contract address."},
6200                     {"owneraddress", RPCArg::Type::STR, RPCArg::Optional::NO, "The token owner qtum address."},
6201                     {"spenderaddress", RPCArg::Type::STR, RPCArg::Optional::NO,  "The token spender qtum address."},
6202                     {"amount", RPCArg::Type::STR, RPCArg::Optional::NO,  "The amount of tokens. eg 0.1"},
6203                     {"gasLimit", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The gas limit, default: "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+", max: "+i64tostr(blockGasLimit)},
6204                     {"gasPrice", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The qtum price per gas unit, default: "+FormatMoney(nGasPrice)+", min:"+FormatMoney(minGasPrice)},
6205                     {"checkOutputs", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Check outputs before send, default: true"},
6206                 },
6207                 RPCResult{
6208                     RPCResult::Type::OBJ, "", "",
6209                     {
6210                         {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
6211                     }
6212                 },
6213                 RPCExamples{
6214                     HelpExampleCli("qrc20approve", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
6215             + HelpExampleCli("qrc20approve", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+" "+FormatMoney(minGasPrice)+" true")
6216             + HelpExampleRpc("qrc20approve", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
6217             + HelpExampleRpc("qrc20approve", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+" "+FormatMoney(minGasPrice)+" true")
6218                 },
6219             }.Check(request);
6220 
6221     // Get mandatory parameters
6222     std::string contract = request.params[0].get_str();
6223     std::string owner = request.params[1].get_str();
6224     std::string spender = request.params[2].get_str();
6225     std::string tokenAmount = request.params[3].get_str();
6226 
6227     // Get gas limit
6228     if (request.params.size() > 4){
6229         nGasLimit = request.params[4].get_int64();
6230     }
6231 
6232     // Get gas price
6233     if (request.params.size() > 5){
6234         nGasPrice = AmountFromValue(request.params[5]);
6235     }
6236 
6237     // Get check outputs flag
6238     if (request.params.size() > 6){
6239         fCheckOutputs = request.params[6].get_bool();
6240     }
6241 
6242     // Set token parameters
6243     SendToken token(*locked_chain, pwallet, spk_man);
6244     token.setAddress(contract);
6245     token.setSender(owner);
6246     token.setGasLimit(i64tostr(nGasLimit));
6247     token.setGasPrice(FormatMoney(nGasPrice));
6248 
6249     // Get decimals
6250     uint32_t decimals;
6251     if(!token.decimals(decimals))
6252         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get decimals");
6253 
6254     // Get token amount to approve
6255     dev::s256 nTokenAmount;
6256     if(!ParseToken(decimals, tokenAmount, nTokenAmount))
6257         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get token amount");
6258 
6259     // Check approve offline
6260     std::string value = nTokenAmount.str();
6261     bool success = false;
6262     if(fCheckOutputs)
6263     {
6264         token.setCheckGasForCall(true);
6265         if(!token.approve(spender, value, success) || !success)
6266             throw JSONRPCError(RPC_MISC_ERROR, "Fail offline check for approve token amount for spending");
6267     }
6268 
6269     // Approve value to spend
6270     if(!token.approve(spender, value, success, true))
6271         throw JSONRPCError(RPC_MISC_ERROR, "Fail to approve token amount for spending");
6272 
6273     UniValue result(UniValue::VOBJ);
6274     result.pushKV("txid", token.getTxId());
6275     return result;
6276 }
6277 
qrc20transfer(const JSONRPCRequest & request)6278 static UniValue qrc20transfer(const JSONRPCRequest& request)
6279 {
6280     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
6281     CWallet* const pwallet = wallet.get();
6282 
6283     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
6284         return NullUniValue;
6285     }
6286 
6287     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
6288     auto locked_chain = pwallet->chain().lock();
6289     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
6290     QtumDGP qtumDGP(globalState.get(), fGettingValuesDGP);
6291     uint64_t blockGasLimit = qtumDGP.getBlockGasLimit(::ChainActive().Height());
6292     uint64_t minGasPrice = CAmount(qtumDGP.getMinGasPrice(::ChainActive().Height()));
6293     CAmount nGasPrice = (minGasPrice>DEFAULT_GAS_PRICE)?minGasPrice:DEFAULT_GAS_PRICE;
6294     uint64_t nGasLimit=DEFAULT_GAS_LIMIT_OP_SEND;
6295     bool fCheckOutputs = true;
6296 
6297             RPCHelpMan{"qrc20transfer",
6298                 "\nSend token amount to a given address.\n",
6299                 {
6300                     {"contractaddress", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The contract address."},
6301                     {"owneraddress", RPCArg::Type::STR, RPCArg::Optional::NO, "The token owner qtum address."},
6302                     {"addressto", RPCArg::Type::STR, RPCArg::Optional::NO,  "The qtum address to send funds to."},
6303                     {"amount", RPCArg::Type::STR, RPCArg::Optional::NO,  "The amount of tokens to send. eg 0.1"},
6304                     {"gasLimit", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The gas limit, default: "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+", max: "+i64tostr(blockGasLimit)},
6305                     {"gasPrice", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The qtum price per gas unit, default: "+FormatMoney(nGasPrice)+", min:"+FormatMoney(minGasPrice)},
6306                     {"checkOutputs", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Check outputs before send, default: true"},
6307                 },
6308                 RPCResult{
6309                     RPCResult::Type::OBJ, "", "",
6310                     {
6311                         {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
6312                     }
6313                 },
6314                 RPCExamples{
6315                     HelpExampleCli("qrc20transfer", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
6316             + HelpExampleCli("qrc20transfer", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+" "+FormatMoney(minGasPrice)+" true")
6317             + HelpExampleRpc("qrc20transfer", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
6318             + HelpExampleRpc("qrc20transfer", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+" "+FormatMoney(minGasPrice)+" true")
6319                 },
6320             }.Check(request);
6321 
6322     // Get mandatory parameters
6323     std::string contract = request.params[0].get_str();
6324     std::string owner = request.params[1].get_str();
6325     std::string address = request.params[2].get_str();
6326     std::string tokenAmount = request.params[3].get_str();
6327 
6328     // Get gas limit
6329     if (request.params.size() > 4){
6330         nGasLimit = request.params[4].get_int64();
6331     }
6332 
6333     // Get gas price
6334     if (request.params.size() > 5){
6335         nGasPrice = AmountFromValue(request.params[5]);
6336     }
6337 
6338     // Get check outputs flag
6339     if (request.params.size() > 6){
6340         fCheckOutputs = request.params[6].get_bool();
6341     }
6342 
6343     // Set token parameters
6344     SendToken token(*locked_chain, pwallet, spk_man);
6345     token.setAddress(contract);
6346     token.setSender(owner);
6347     token.setGasLimit(i64tostr(nGasLimit));
6348     token.setGasPrice(FormatMoney(nGasPrice));
6349 
6350     // Get decimals
6351     uint32_t decimals;
6352     if(!token.decimals(decimals))
6353         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get decimals");
6354 
6355     // Get token amount
6356     dev::s256 nTokenAmount;
6357     if(!ParseToken(decimals, tokenAmount, nTokenAmount))
6358         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get token amount");
6359 
6360     // Get token owner balance
6361     std::string strBalance;
6362     if(!token.balanceOf(strBalance))
6363         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get balance");
6364 
6365     // Check if balance is enough to cover it
6366     dev::s256 balance(strBalance);
6367     if(balance < nTokenAmount)
6368         throw JSONRPCError(RPC_MISC_ERROR, "Not enough token balance");
6369 
6370     // Check transfer offline
6371     std::string value = nTokenAmount.str();
6372     bool success = false;
6373     if(fCheckOutputs)
6374     {
6375         token.setCheckGasForCall(true);
6376         if(!token.transfer(address, value, success) || !success)
6377             throw JSONRPCError(RPC_MISC_ERROR, "Fail offline check for transfer token");
6378     }
6379 
6380     // Send token
6381     if(!token.transfer(address, value, success, true))
6382         throw JSONRPCError(RPC_MISC_ERROR, "Fail to transfer token");
6383 
6384     UniValue result(UniValue::VOBJ);
6385     result.pushKV("txid", token.getTxId());
6386     return result;
6387 }
6388 
qrc20transferfrom(const JSONRPCRequest & request)6389 static UniValue qrc20transferfrom(const JSONRPCRequest& request)
6390 {
6391     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
6392     CWallet* const pwallet = wallet.get();
6393 
6394     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
6395         return NullUniValue;
6396     }
6397 
6398     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
6399     auto locked_chain = pwallet->chain().lock();
6400     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
6401     QtumDGP qtumDGP(globalState.get(), fGettingValuesDGP);
6402     uint64_t blockGasLimit = qtumDGP.getBlockGasLimit(::ChainActive().Height());
6403     uint64_t minGasPrice = CAmount(qtumDGP.getMinGasPrice(::ChainActive().Height()));
6404     CAmount nGasPrice = (minGasPrice>DEFAULT_GAS_PRICE)?minGasPrice:DEFAULT_GAS_PRICE;
6405     uint64_t nGasLimit=DEFAULT_GAS_LIMIT_OP_SEND;
6406     bool fCheckOutputs = true;
6407 
6408             RPCHelpMan{"qrc20transferfrom",
6409                 "\nSend token amount from selected address to a given address.\n",
6410                 {
6411                     {"contractaddress", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The contract address."},
6412                     {"owneraddress", RPCArg::Type::STR, RPCArg::Optional::NO, "The token owner qtum address."},
6413                     {"spenderaddress", RPCArg::Type::STR, RPCArg::Optional::NO,  "The token spender qtum address."},
6414                     {"receiveraddress", RPCArg::Type::STR, RPCArg::Optional::NO,  "The token receiver qtum address."},
6415                     {"amount", RPCArg::Type::STR, RPCArg::Optional::NO,  "The amount of token to send. eg 0.1"},
6416                     {"gasLimit", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The gas limit, default: "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+", max: "+i64tostr(blockGasLimit)},
6417                     {"gasPrice", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The qtum price per gas unit, default: "+FormatMoney(nGasPrice)+", min:"+FormatMoney(minGasPrice)},
6418                     {"checkOutputs", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Check outputs before send, default: true"},
6419                  },
6420                 RPCResult{
6421                     RPCResult::Type::OBJ, "", "",
6422                     {
6423                         {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
6424                     }
6425                 },
6426                 RPCExamples{
6427                     HelpExampleCli("qrc20transferfrom", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QhZThdumK8EFRX8MziWzvjCdiQWRt7Mxdz\" 0.1")
6428             + HelpExampleCli("qrc20transferfrom", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QhZThdumK8EFRX8MziWzvjCdiQWRt7Mxdz\" 0.1 "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+" "+FormatMoney(minGasPrice)+" true")
6429             + HelpExampleRpc("qrc20transferfrom", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QhZThdumK8EFRX8MziWzvjCdiQWRt7Mxdz\" 0.1")
6430             + HelpExampleRpc("qrc20transferfrom", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QhZThdumK8EFRX8MziWzvjCdiQWRt7Mxdz\" 0.1 "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+" "+FormatMoney(minGasPrice)+" true")
6431                 },
6432             }.Check(request);
6433 
6434     // Get mandatory parameters
6435     std::string contract = request.params[0].get_str();
6436     std::string owner = request.params[1].get_str();
6437     std::string spender = request.params[2].get_str();
6438     std::string receiver = request.params[3].get_str();
6439     std::string tokenAmount = request.params[4].get_str();
6440 
6441     // Get gas limit
6442     if (request.params.size() > 5){
6443         nGasLimit = request.params[5].get_int64();
6444     }
6445 
6446     // Get gas price
6447     if (request.params.size() > 6){
6448         nGasPrice = AmountFromValue(request.params[6]);
6449     }
6450 
6451     // Get check outputs flag
6452     if (request.params.size() > 7){
6453         fCheckOutputs = request.params[7].get_bool();
6454     }
6455 
6456     // Set token parameters
6457     SendToken token(*locked_chain, pwallet, spk_man);
6458     token.setAddress(contract);
6459     token.setSender(spender);
6460     token.setGasLimit(i64tostr(nGasLimit));
6461     token.setGasPrice(FormatMoney(nGasPrice));
6462 
6463     // Get decimals
6464     uint32_t decimals;
6465     if(!token.decimals(decimals))
6466         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get decimals");
6467 
6468     // Get token amount to spend
6469     dev::s256 nTokenAmount;
6470     if(!ParseToken(decimals, tokenAmount, nTokenAmount))
6471         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get token amount");
6472 
6473     // Get token spender allowance
6474     std::string strAllowance;
6475     if(!token.allowance(owner, spender, strAllowance))
6476         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get allowance");
6477 
6478     // Check if allowance is enough to cover it
6479     dev::s256 allowance(strAllowance);
6480     if(allowance < nTokenAmount)
6481         throw JSONRPCError(RPC_MISC_ERROR, "Not enough token allowance");
6482 
6483     // Check transfer from offline
6484     std::string value = nTokenAmount.str();
6485     bool success = false;
6486     if(fCheckOutputs)
6487     {
6488         token.setCheckGasForCall(true);
6489         if(!token.transferFrom(owner, receiver, value, success) || !success)
6490             throw JSONRPCError(RPC_MISC_ERROR, "Fail offline check for spend token amount from address");
6491     }
6492 
6493     // Transfer allowed token amount
6494     if(!token.transferFrom(owner, receiver, value, success, true))
6495         throw JSONRPCError(RPC_MISC_ERROR, "Fail to spend token amount from address");
6496 
6497     UniValue result(UniValue::VOBJ);
6498     result.pushKV("txid", token.getTxId());
6499     return result;
6500 }
6501 
qrc20burn(const JSONRPCRequest & request)6502 static UniValue qrc20burn(const JSONRPCRequest& request)
6503 {
6504     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
6505     CWallet* const pwallet = wallet.get();
6506 
6507     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
6508         return NullUniValue;
6509     }
6510 
6511     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
6512     auto locked_chain = pwallet->chain().lock();
6513     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
6514     QtumDGP qtumDGP(globalState.get(), fGettingValuesDGP);
6515     uint64_t blockGasLimit = qtumDGP.getBlockGasLimit(::ChainActive().Height());
6516     uint64_t minGasPrice = CAmount(qtumDGP.getMinGasPrice(::ChainActive().Height()));
6517     CAmount nGasPrice = (minGasPrice>DEFAULT_GAS_PRICE)?minGasPrice:DEFAULT_GAS_PRICE;
6518     uint64_t nGasLimit=DEFAULT_GAS_LIMIT_OP_SEND;
6519     bool fCheckOutputs = true;
6520 
6521             RPCHelpMan{"qrc20burn",
6522                 "\nBurns token amount from owner address.\n",
6523                 {
6524                     {"contractaddress", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The contract address."},
6525                     {"owneraddress", RPCArg::Type::STR, RPCArg::Optional::NO, "The token owner qtum address."},
6526                     {"amount", RPCArg::Type::STR, RPCArg::Optional::NO,  "The amount of tokens to burn. eg 0.1"},
6527                     {"gasLimit", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The gas limit, default: "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+", max: "+i64tostr(blockGasLimit)},
6528                     {"gasPrice", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The qtum price per gas unit, default: "+FormatMoney(nGasPrice)+", min:"+FormatMoney(minGasPrice)},
6529                     {"checkOutputs", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Check outputs before send, default: true"},
6530                 },
6531                 RPCResult{
6532                     RPCResult::Type::OBJ, "", "",
6533                     {
6534                         {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
6535                     }
6536                 },
6537                 RPCExamples{
6538                     HelpExampleCli("qrc20burn", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
6539             + HelpExampleCli("qrc20burn", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+" "+FormatMoney(minGasPrice)+" true")
6540             + HelpExampleRpc("qrc20burn", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
6541             + HelpExampleRpc("qrc20burn", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+" "+FormatMoney(minGasPrice)+" true")
6542                 },
6543             }.Check(request);
6544 
6545     // Get mandatory parameters
6546     std::string contract = request.params[0].get_str();
6547     std::string owner = request.params[1].get_str();
6548     std::string tokenAmount = request.params[2].get_str();
6549 
6550     // Get gas limit
6551     if (request.params.size() > 3){
6552         nGasLimit = request.params[3].get_int64();
6553     }
6554 
6555     // Get gas price
6556     if (request.params.size() > 4){
6557         nGasPrice = AmountFromValue(request.params[4]);
6558     }
6559 
6560     // Get check outputs flag
6561     if (request.params.size() > 5){
6562         fCheckOutputs = request.params[5].get_bool();
6563     }
6564 
6565     // Set token parameters
6566     SendToken token(*locked_chain, pwallet, spk_man);
6567     token.setAddress(contract);
6568     token.setSender(owner);
6569     token.setGasLimit(i64tostr(nGasLimit));
6570     token.setGasPrice(FormatMoney(nGasPrice));
6571 
6572     // Get decimals
6573     uint32_t decimals;
6574     if(!token.decimals(decimals))
6575         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get decimals");
6576 
6577     // Get token amount to burn
6578     dev::s256 nTokenAmount;
6579     if(!ParseToken(decimals, tokenAmount, nTokenAmount))
6580         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get token amount");
6581 
6582     // Get token owner balance
6583     std::string strBalance;
6584     if(!token.balanceOf(strBalance))
6585         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get balance");
6586 
6587     // Check if balance is enough to cover it
6588     dev::s256 balance(strBalance);
6589     if(balance < nTokenAmount)
6590         throw JSONRPCError(RPC_MISC_ERROR, "Not enough token balance");
6591 
6592     // Check burn offline
6593     std::string value = nTokenAmount.str();
6594     bool success = false;
6595     if(fCheckOutputs)
6596     {
6597         token.setCheckGasForCall(true);
6598         if(!token.burn(value, success) || !success)
6599             throw JSONRPCError(RPC_MISC_ERROR, "Fail offline check for burn token amount");
6600     }
6601 
6602     // Burn token amount
6603     if(!token.burn(value, success, true))
6604         throw JSONRPCError(RPC_MISC_ERROR, "Fail to burn token amount");
6605 
6606     UniValue result(UniValue::VOBJ);
6607     result.pushKV("txid", token.getTxId());
6608     return result;
6609 }
6610 
qrc20burnfrom(const JSONRPCRequest & request)6611 static UniValue qrc20burnfrom(const JSONRPCRequest& request)
6612 {
6613     std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
6614     CWallet* const pwallet = wallet.get();
6615 
6616     if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
6617         return NullUniValue;
6618     }
6619 
6620     LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
6621     auto locked_chain = pwallet->chain().lock();
6622     LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
6623     QtumDGP qtumDGP(globalState.get(), fGettingValuesDGP);
6624     uint64_t blockGasLimit = qtumDGP.getBlockGasLimit(::ChainActive().Height());
6625     uint64_t minGasPrice = CAmount(qtumDGP.getMinGasPrice(::ChainActive().Height()));
6626     CAmount nGasPrice = (minGasPrice>DEFAULT_GAS_PRICE)?minGasPrice:DEFAULT_GAS_PRICE;
6627     uint64_t nGasLimit=DEFAULT_GAS_LIMIT_OP_SEND;
6628     bool fCheckOutputs = true;
6629 
6630             RPCHelpMan{"qrc20burnfrom",
6631                 "\nBurns token amount from a given address.\n",
6632                 {
6633                     {"contractaddress", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The contract address."},
6634                     {"owneraddress", RPCArg::Type::STR, RPCArg::Optional::NO, "The token owner qtum address."},
6635                     {"spenderaddress", RPCArg::Type::STR, RPCArg::Optional::NO,  "The token spender qtum address."},
6636                     {"amount", RPCArg::Type::STR, RPCArg::Optional::NO,  "The amount of token to burn. eg 0.1"},
6637                     {"gasLimit", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The gas limit, default: "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+", max: "+i64tostr(blockGasLimit)},
6638                     {"gasPrice", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The qtum price per gas unit, default: "+FormatMoney(nGasPrice)+", min:"+FormatMoney(minGasPrice)},
6639                     {"checkOutputs", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Check outputs before send, default: true"},
6640                  },
6641                 RPCResult{
6642                     RPCResult::Type::OBJ, "", "",
6643                     {
6644                         {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
6645                     }
6646                 },
6647                 RPCExamples{
6648                     HelpExampleCli("qrc20burnfrom", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
6649             + HelpExampleCli("qrc20burnfrom", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+" "+FormatMoney(minGasPrice)+" true")
6650             + HelpExampleRpc("qrc20burnfrom", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
6651             + HelpExampleRpc("qrc20burnfrom", "\"eb23c0b3e6042821da281a2e2364feb22dd543e3\" \"QX1GkJdye9WoUnrE2v6ZQhQ72EUVDtGXQX\" \"QM72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 "+i64tostr(DEFAULT_GAS_LIMIT_OP_SEND)+" "+FormatMoney(minGasPrice)+" true")
6652                 },
6653             }.Check(request);
6654 
6655     // Get mandatory parameters
6656     std::string contract = request.params[0].get_str();
6657     std::string owner = request.params[1].get_str();
6658     std::string spender = request.params[2].get_str();
6659     std::string tokenAmount = request.params[3].get_str();
6660 
6661     // Get gas limit
6662     if (request.params.size() > 4){
6663         nGasLimit = request.params[4].get_int64();
6664     }
6665 
6666     // Get gas price
6667     if (request.params.size() > 5){
6668         nGasPrice = AmountFromValue(request.params[5]);
6669     }
6670 
6671     // Get check outputs flag
6672     if (request.params.size() > 6){
6673         fCheckOutputs = request.params[6].get_bool();
6674     }
6675 
6676     // Set token parameters
6677     SendToken token(*locked_chain, pwallet, spk_man);
6678     token.setAddress(contract);
6679     token.setSender(spender);
6680     token.setGasLimit(i64tostr(nGasLimit));
6681     token.setGasPrice(FormatMoney(nGasPrice));
6682 
6683     // Get decimals
6684     uint32_t decimals;
6685     if(!token.decimals(decimals))
6686         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get decimals");
6687 
6688     // Get token amount to burn
6689     dev::s256 nTokenAmount;
6690     if(!ParseToken(decimals, tokenAmount, nTokenAmount))
6691         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get token amount");
6692 
6693     // Get token spender allowance
6694     std::string strAllowance;
6695     if(!token.allowance(owner, spender, strAllowance))
6696         throw JSONRPCError(RPC_MISC_ERROR, "Fail to get allowance");
6697 
6698     // Check if allowance is enough to cover it
6699     dev::s256 allowance(strAllowance);
6700     if(allowance < nTokenAmount)
6701         throw JSONRPCError(RPC_MISC_ERROR, "Not enough token allowance");
6702 
6703     // Check burn from offline
6704     std::string value = nTokenAmount.str();
6705     bool success = false;
6706     if(fCheckOutputs)
6707     {
6708         token.setCheckGasForCall(true);
6709         if(!token.burnFrom(owner, value, success, false) || !success)
6710             throw JSONRPCError(RPC_MISC_ERROR, "Fail offline check for burn token amount from address");
6711     }
6712 
6713     // Burn token amount
6714     if(!token.burnFrom(owner, value, success, true))
6715         throw JSONRPCError(RPC_MISC_ERROR, "Fail to burn token amount from address");
6716 
6717     UniValue result(UniValue::VOBJ);
6718     result.pushKV("txid", token.getTxId());
6719     return result;
6720 }
6721 
6722 UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
6723 UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
6724 UniValue importprivkey(const JSONRPCRequest& request);
6725 UniValue importaddress(const JSONRPCRequest& request);
6726 UniValue importpubkey(const JSONRPCRequest& request);
6727 UniValue dumpwallet(const JSONRPCRequest& request);
6728 UniValue importwallet(const JSONRPCRequest& request);
6729 UniValue importprunedfunds(const JSONRPCRequest& request);
6730 UniValue removeprunedfunds(const JSONRPCRequest& request);
6731 UniValue importmulti(const JSONRPCRequest& request);
6732 
RegisterWalletRPCCommands(interfaces::Chain & chain,std::vector<std::unique_ptr<interfaces::Handler>> & handlers)6733 void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique_ptr<interfaces::Handler>>& handlers)
6734 {
6735 // clang-format off
6736 static const CRPCCommand commands[] =
6737 { //  category              name                                actor (function)                argNames
6738     //  --------------------- ------------------------          -----------------------         ----------
6739     { "rawtransactions",    "fundrawtransaction",               &fundrawtransaction,            {"hexstring","options","iswitness"} },
6740     { "wallet",             "abandontransaction",               &abandontransaction,            {"txid"} },
6741     { "wallet",             "abortrescan",                      &abortrescan,                   {} },
6742     { "wallet",             "addmultisigaddress",               &addmultisigaddress,            {"nrequired","keys","label","address_type"} },
6743     { "wallet",             "backupwallet",                     &backupwallet,                  {"destination"} },
6744     { "wallet",             "bumpfee",                          &bumpfee,                       {"txid", "options"} },
6745     { "wallet",             "createwallet",                     &createwallet,                  {"wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse"} },
6746     { "wallet",             "dumpprivkey",                      &dumpprivkey,                   {"address"}  },
6747     { "wallet",             "dumpwallet",                       &dumpwallet,                    {"filename"} },
6748     { "wallet",             "encryptwallet",                    &encryptwallet,                 {"passphrase"} },
6749     { "wallet",             "getaddressesbylabel",              &getaddressesbylabel,           {"label"} },
6750     { "wallet",             "getaddressinfo",                   &getaddressinfo,                {"address"} },
6751     { "wallet",             "getbalance",                       &getbalance,                    {"dummy","minconf","include_watchonly","avoid_reuse"} },
6752     { "wallet",             "getnewaddress",                    &getnewaddress,                 {"label","address_type"} },
6753     { "wallet",             "getrawchangeaddress",              &getrawchangeaddress,           {"address_type"} },
6754     { "wallet",             "getreceivedbyaddress",             &getreceivedbyaddress,          {"address","minconf"} },
6755     { "wallet",             "getreceivedbylabel",               &getreceivedbylabel,            {"label","minconf"} },
6756     { "wallet",             "gettransaction",                   &gettransaction,                {"txid","include_watchonly","verbose", "waitconf"} },
6757     { "wallet",             "getunconfirmedbalance",            &getunconfirmedbalance,         {} },
6758     { "wallet",             "getbalances",                      &getbalances,                   {} },
6759     { "wallet",             "getwalletinfo",                    &getwalletinfo,                 {} },
6760     { "wallet",             "importaddress",                    &importaddress,                 {"address","label","rescan","p2sh"} },
6761     { "wallet",             "importmulti",                      &importmulti,                   {"requests","options"} },
6762     { "wallet",             "importprivkey",                    &importprivkey,                 {"privkey","label","rescan"} },
6763     { "wallet",             "importprunedfunds",                &importprunedfunds,             {"rawtransaction","txoutproof"} },
6764     { "wallet",             "importpubkey",                     &importpubkey,                  {"pubkey","label","rescan"} },
6765     { "wallet",             "importwallet",                     &importwallet,                  {"filename"} },
6766     { "wallet",             "keypoolrefill",                    &keypoolrefill,                 {"newsize"} },
6767     { "wallet",             "listaddressgroupings",             &listaddressgroupings,          {} },
6768     { "wallet",             "listlabels",                       &listlabels,                    {"purpose"} },
6769     { "wallet",             "listlockunspent",                  &listlockunspent,               {} },
6770     { "wallet",             "listreceivedbyaddress",            &listreceivedbyaddress,         {"minconf","include_empty","include_watchonly","address_filter"} },
6771     { "wallet",             "listreceivedbylabel",              &listreceivedbylabel,           {"minconf","include_empty","include_watchonly"} },
6772     { "wallet",             "listsinceblock",                   &listsinceblock,                {"blockhash","target_confirmations","include_watchonly","include_removed"} },
6773     { "wallet",             "listtransactions",                 &listtransactions,              {"label|dummy","count","skip","include_watchonly"} },
6774     { "wallet",             "listunspent",                      &listunspent,                   {"minconf","maxconf","addresses","include_unsafe","query_options"} },
6775     { "wallet",             "listwalletdir",                    &listwalletdir,                 {} },
6776     { "wallet",             "listwallets",                      &listwallets,                   {} },
6777     { "wallet",             "loadwallet",                       &loadwallet,                    {"filename"} },
6778     { "wallet",             "lockunspent",                      &lockunspent,                   {"unlock","transactions"} },
6779     { "wallet",             "removeprunedfunds",                &removeprunedfunds,             {"txid"} },
6780     { "wallet",             "rescanblockchain",                 &rescanblockchain,              {"start_height", "stop_height"} },
6781     { "wallet",             "sendmany",                         &sendmany,                      {"dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
6782     { "wallet",             "sendmanywithdupes",                &sendmanywithdupes,             {"fromaccount","amounts","minconf","comment","subtractfeefrom"} },
6783     { "wallet",             "sendtoaddress",                    &sendtoaddress,                 {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode","avoid_reuse","senderAddress","changeToSender"} },
6784     { "wallet",             "splitutxosforaddress",             &splitutxosforaddress,          {"address","minValue","maxValue","maxOutputs"} },
6785     { "wallet",             "sethdseed",                        &sethdseed,                     {"newkeypool","seed"} },
6786     { "wallet",             "setlabel",                         &setlabel,                      {"address","label"} },
6787     { "wallet",             "settxfee",                         &settxfee,                      {"amount"} },
6788     { "wallet",             "setwalletflag",                    &setwalletflag,                 {"flag","value"} },
6789     { "wallet",             "signmessage",                      &signmessage,                   {"address","message"} },
6790     { "wallet",             "signrawtransactionwithwallet",     &signrawtransactionwithwallet,  {"hexstring","prevtxs","sighashtype"} },
6791     { "wallet",             "signrawsendertransactionwithwallet", &signrawsendertransactionwithwallet,  {"hexstring","sighashtype"} },
6792     { "wallet",             "unloadwallet",                     &unloadwallet,                  {"wallet_name"} },
6793     { "wallet",             "walletcreatefundedpsbt",           &walletcreatefundedpsbt,        {"inputs","outputs","locktime","options","bip32derivs"} },
6794     { "wallet",             "walletlock",                       &walletlock,                    {} },
6795     { "wallet",             "walletpassphrase",                 &walletpassphrase,              {"passphrase","timeout","stakingonly"} },
6796     { "wallet",             "walletpassphrasechange",           &walletpassphrasechange,        {"oldpassphrase","newpassphrase"} },
6797     { "wallet",             "walletprocesspsbt",                &walletprocesspsbt,             {"psbt","sign","sighashtype","bip32derivs"} },
6798     { "wallet",             "reservebalance",                   &reservebalance,                {"reserve", "amount"} },
6799     { "wallet",             "createcontract",                   &createcontract,                {"bytecode", "gasLimit", "gasPrice", "senderAddress", "broadcast", "changeToSender"} },
6800     { "wallet",             "sendtocontract",                   &sendtocontract,                {"contractaddress", "bytecode", "amount", "gasLimit", "gasPrice", "senderAddress", "broadcast", "changeToSender"} },
6801     { "wallet",             "removedelegationforaddress",       &removedelegationforaddress,    {"address", "gasLimit", "gasPrice"} },
6802     { "wallet",             "setdelegateforaddress",            &setdelegateforaddress,         {"staker", "fee", "address", "gasLimit", "gasPrice"} },
6803     { "wallet",             "setsuperstakervaluesforaddress",          &setsuperstakervaluesforaddress,       {"params"} },
6804     { "wallet",             "listsuperstakercustomvalues",             &listsuperstakercustomvalues,          {} },
6805     { "wallet",             "listsuperstakervaluesforaddress",         &listsuperstakervaluesforaddress,      {"address"} },
6806     { "wallet",             "removesuperstakervaluesforaddress",       &removesuperstakervaluesforaddress,    {"address"} },
6807     { "wallet",             "qrc20approve",                    &qrc20approve,                   {"contractaddress", "owneraddress", "spenderaddress", "amount", "gasLimit", "gasPrice", "checkOutputs"} },
6808     { "wallet",             "qrc20transfer",                   &qrc20transfer,                  {"contractaddress", "owneraddress", "addressto", "amount", "gasLimit", "gasPrice", "checkOutputs"} },
6809     { "wallet",             "qrc20transferfrom",               &qrc20transferfrom,              {"contractaddress", "owneraddress", "spenderaddress", "receiveraddress", "amount", "gasLimit", "gasPrice", "checkOutputs"} },
6810     { "wallet",             "qrc20burn",                       &qrc20burn,                      {"contractaddress", "owneraddress", "amount", "gasLimit", "gasPrice", "checkOutputs"} },
6811     { "wallet",             "qrc20burnfrom",                   &qrc20burnfrom,                  {"contractaddress", "owneraddress", "spenderaddress", "amount", "gasLimit", "gasPrice", "checkOutputs"} },
6812 };
6813 // clang-format on
6814 
6815     for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
6816         handlers.emplace_back(chain.handleRpc(commands[vcidx]));
6817 }
6818 
6819 interfaces::Chain* g_rpc_chain = nullptr;
6820