1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 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.
8 #include "consensus/upgrades.h"
14 #include "rpcserver.h"
17 #include "utilmoneystr.h"
20 #include "primitives/transaction.h"
21 #include "zcbenchmarks.h"
22 #include "script/interpreter.h"
25 #include "asyncrpcoperation.h"
26 #include "asyncrpcqueue.h"
27 #include "wallet/asyncrpcoperation_mergetoaddress.h"
28 #include "wallet/asyncrpcoperation_sendmany.h"
29 #include "wallet/asyncrpcoperation_shieldcoinbase.h"
35 #include <boost/assign/list_of.hpp>
43 using namespace libzcash;
45 extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
47 int64_t nWalletUnlockTime;
48 static CCriticalSection cs_nWalletUnlockTime;
51 UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
53 std::string HelpRequiringPassphrase()
55 return pwalletMain && pwalletMain->IsCrypted()
56 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
60 bool EnsureWalletIsAvailable(bool avoidException)
65 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
72 void EnsureWalletIsUnlocked()
74 if (pwalletMain->IsLocked())
75 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
78 void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
80 int confirms = wtx.GetDepthInMainChain();
81 entry.push_back(Pair("confirmations", confirms));
83 entry.push_back(Pair("generated", true));
86 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
87 entry.push_back(Pair("blockindex", wtx.nIndex));
88 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
89 entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight));
91 uint256 hash = wtx.GetHash();
92 entry.push_back(Pair("txid", hash.GetHex()));
93 UniValue conflicts(UniValue::VARR);
94 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
95 conflicts.push_back(conflict.GetHex());
96 entry.push_back(Pair("walletconflicts", conflicts));
97 entry.push_back(Pair("time", wtx.GetTxTime()));
98 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
99 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
100 entry.push_back(Pair(item.first, item.second));
102 entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
105 string AccountFromValue(const UniValue& value)
107 string strAccount = value.get_str();
108 if (strAccount != "")
109 throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
113 UniValue getnewaddress(const UniValue& params, bool fHelp)
115 if (!EnsureWalletIsAvailable(fHelp))
118 if (fHelp || params.size() > 1)
120 "getnewaddress ( \"account\" )\n"
121 "\nReturns a new Zcash address for receiving payments.\n"
123 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
125 "\"zcashaddress\" (string) The new Zcash address\n"
127 + HelpExampleCli("getnewaddress", "")
128 + HelpExampleRpc("getnewaddress", "")
131 LOCK2(cs_main, pwalletMain->cs_wallet);
133 // Parse the account first so we don't generate a key if there's an error
135 if (params.size() > 0)
136 strAccount = AccountFromValue(params[0]);
138 if (!pwalletMain->IsLocked())
139 pwalletMain->TopUpKeyPool();
141 // Generate a new key that is added to wallet
143 if (!pwalletMain->GetKeyFromPool(newKey))
144 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
145 CKeyID keyID = newKey.GetID();
147 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
149 return CBitcoinAddress(keyID).ToString();
153 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
155 CWalletDB walletdb(pwalletMain->strWalletFile);
158 walletdb.ReadAccount(strAccount, account);
160 bool bKeyUsed = false;
162 // Check if the current key has been used
163 if (account.vchPubKey.IsValid())
165 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
166 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
167 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
170 const CWalletTx& wtx = (*it).second;
171 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
172 if (txout.scriptPubKey == scriptPubKey)
177 // Generate a new key
178 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
180 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
181 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
183 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
184 walletdb.WriteAccount(strAccount, account);
187 return CBitcoinAddress(account.vchPubKey.GetID());
190 UniValue getaccountaddress(const UniValue& params, bool fHelp)
192 if (!EnsureWalletIsAvailable(fHelp))
195 if (fHelp || params.size() != 1)
197 "getaccountaddress \"account\"\n"
198 "\nDEPRECATED. Returns the current Zcash address for receiving payments to this account.\n"
200 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
202 "\"zcashaddress\" (string) The account Zcash address\n"
204 + HelpExampleCli("getaccountaddress", "")
205 + HelpExampleCli("getaccountaddress", "\"\"")
206 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
207 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
210 LOCK2(cs_main, pwalletMain->cs_wallet);
212 // Parse the account first so we don't generate a key if there's an error
213 string strAccount = AccountFromValue(params[0]);
215 UniValue ret(UniValue::VSTR);
217 ret = GetAccountAddress(strAccount).ToString();
222 UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
224 if (!EnsureWalletIsAvailable(fHelp))
227 if (fHelp || params.size() > 1)
229 "getrawchangeaddress\n"
230 "\nReturns a new Zcash address, for receiving change.\n"
231 "This is for use with raw transactions, NOT normal use.\n"
233 "\"address\" (string) The address\n"
235 + HelpExampleCli("getrawchangeaddress", "")
236 + HelpExampleRpc("getrawchangeaddress", "")
239 LOCK2(cs_main, pwalletMain->cs_wallet);
241 if (!pwalletMain->IsLocked())
242 pwalletMain->TopUpKeyPool();
244 CReserveKey reservekey(pwalletMain);
246 if (!reservekey.GetReservedKey(vchPubKey))
247 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
249 reservekey.KeepKey();
251 CKeyID keyID = vchPubKey.GetID();
253 return CBitcoinAddress(keyID).ToString();
257 UniValue setaccount(const UniValue& params, bool fHelp)
259 if (!EnsureWalletIsAvailable(fHelp))
262 if (fHelp || params.size() < 1 || params.size() > 2)
264 "setaccount \"zcashaddress\" \"account\"\n"
265 "\nDEPRECATED. Sets the account associated with the given address.\n"
267 "1. \"zcashaddress\" (string, required) The Zcash address to be associated with an account.\n"
268 "2. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
270 + HelpExampleCli("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"tabby\"")
271 + HelpExampleRpc("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"tabby\"")
274 LOCK2(cs_main, pwalletMain->cs_wallet);
276 CBitcoinAddress address(params[0].get_str());
277 if (!address.IsValid())
278 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
281 if (params.size() > 1)
282 strAccount = AccountFromValue(params[1]);
284 // Only add the account if the address is yours.
285 if (IsMine(*pwalletMain, address.Get()))
287 // Detect when changing the account of an address that is the 'unused current key' of another account:
288 if (pwalletMain->mapAddressBook.count(address.Get()))
290 string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
291 if (address == GetAccountAddress(strOldAccount))
292 GetAccountAddress(strOldAccount, true);
294 pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
297 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
303 UniValue getaccount(const UniValue& params, bool fHelp)
305 if (!EnsureWalletIsAvailable(fHelp))
308 if (fHelp || params.size() != 1)
310 "getaccount \"zcashaddress\"\n"
311 "\nDEPRECATED. Returns the account associated with the given address.\n"
313 "1. \"zcashaddress\" (string, required) The Zcash address for account lookup.\n"
315 "\"accountname\" (string) the account address\n"
317 + HelpExampleCli("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
318 + HelpExampleRpc("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
321 LOCK2(cs_main, pwalletMain->cs_wallet);
323 CBitcoinAddress address(params[0].get_str());
324 if (!address.IsValid())
325 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
328 map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
329 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
330 strAccount = (*mi).second.name;
335 UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
337 if (!EnsureWalletIsAvailable(fHelp))
340 if (fHelp || params.size() != 1)
342 "getaddressesbyaccount \"account\"\n"
343 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
345 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
347 "[ (json array of string)\n"
348 " \"zcashaddress\" (string) a Zcash address associated with the given account\n"
352 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
353 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
356 LOCK2(cs_main, pwalletMain->cs_wallet);
358 string strAccount = AccountFromValue(params[0]);
360 // Find all addresses that have the given account
361 UniValue ret(UniValue::VARR);
362 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
364 const CBitcoinAddress& address = item.first;
365 const string& strName = item.second.name;
366 if (strName == strAccount)
367 ret.push_back(address.ToString());
372 static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
374 CAmount curBalance = pwalletMain->GetBalance();
378 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
380 if (nValue > curBalance)
381 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
383 // Parse Zcash address
384 CScript scriptPubKey = GetScriptForDestination(address);
386 // Create and send the transaction
387 CReserveKey reservekey(pwalletMain);
388 CAmount nFeeRequired;
389 std::string strError;
390 vector<CRecipient> vecSend;
391 int nChangePosRet = -1;
392 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
393 vecSend.push_back(recipient);
394 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
395 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
396 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));
397 throw JSONRPCError(RPC_WALLET_ERROR, strError);
399 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
400 throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
403 UniValue sendtoaddress(const UniValue& params, bool fHelp)
405 if (!EnsureWalletIsAvailable(fHelp))
408 if (fHelp || params.size() < 2 || params.size() > 5)
410 "sendtoaddress \"zcashaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
411 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
412 + HelpRequiringPassphrase() +
414 "1. \"zcashaddress\" (string, required) The Zcash address to send to.\n"
415 "2. \"amount\" (numeric, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n"
416 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
417 " This is not part of the transaction, just kept in your wallet.\n"
418 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
419 " to which you're sending the transaction. This is not part of the \n"
420 " transaction, just kept in your wallet.\n"
421 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
422 " The recipient will receive less Zcash than you enter in the amount field.\n"
424 "\"transactionid\" (string) The transaction id.\n"
426 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
427 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
428 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
429 + HelpExampleRpc("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
432 LOCK2(cs_main, pwalletMain->cs_wallet);
434 CBitcoinAddress address(params[0].get_str());
435 if (!address.IsValid())
436 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
439 CAmount nAmount = AmountFromValue(params[1]);
441 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
445 if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
446 wtx.mapValue["comment"] = params[2].get_str();
447 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
448 wtx.mapValue["to"] = params[3].get_str();
450 bool fSubtractFeeFromAmount = false;
451 if (params.size() > 4)
452 fSubtractFeeFromAmount = params[4].get_bool();
454 EnsureWalletIsUnlocked();
456 SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
458 return wtx.GetHash().GetHex();
461 UniValue listaddressgroupings(const UniValue& params, bool fHelp)
463 if (!EnsureWalletIsAvailable(fHelp))
468 "listaddressgroupings\n"
469 "\nLists groups of addresses which have had their common ownership\n"
470 "made public by common use as inputs or as the resulting change\n"
471 "in past transactions\n"
476 " \"zcashaddress\", (string) The zcash address\n"
477 " amount, (numeric) The amount in " + CURRENCY_UNIT + "\n"
478 " \"account\" (string, optional) The account (DEPRECATED)\n"
485 + HelpExampleCli("listaddressgroupings", "")
486 + HelpExampleRpc("listaddressgroupings", "")
489 LOCK2(cs_main, pwalletMain->cs_wallet);
491 UniValue jsonGroupings(UniValue::VARR);
492 map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
493 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
495 UniValue jsonGrouping(UniValue::VARR);
496 BOOST_FOREACH(CTxDestination address, grouping)
498 UniValue addressInfo(UniValue::VARR);
499 addressInfo.push_back(CBitcoinAddress(address).ToString());
500 addressInfo.push_back(ValueFromAmount(balances[address]));
502 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
503 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
505 jsonGrouping.push_back(addressInfo);
507 jsonGroupings.push_back(jsonGrouping);
509 return jsonGroupings;
512 UniValue signmessage(const UniValue& params, bool fHelp)
514 if (!EnsureWalletIsAvailable(fHelp))
517 if (fHelp || params.size() != 2)
519 "signmessage \"zcashaddress\" \"message\"\n"
520 "\nSign a message with the private key of an address"
521 + HelpRequiringPassphrase() + "\n"
523 "1. \"zcashaddress\" (string, required) The Zcash address to use for the private key.\n"
524 "2. \"message\" (string, required) The message to create a signature of.\n"
526 "\"signature\" (string) The signature of the message encoded in base 64\n"
528 "\nUnlock the wallet for 30 seconds\n"
529 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
530 "\nCreate the signature\n"
531 + HelpExampleCli("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"my message\"") +
532 "\nVerify the signature\n"
533 + HelpExampleCli("verifymessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"signature\" \"my message\"") +
535 + HelpExampleRpc("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"my message\"")
538 LOCK2(cs_main, pwalletMain->cs_wallet);
540 EnsureWalletIsUnlocked();
542 string strAddress = params[0].get_str();
543 string strMessage = params[1].get_str();
545 CBitcoinAddress addr(strAddress);
547 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
550 if (!addr.GetKeyID(keyID))
551 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
554 if (!pwalletMain->GetKey(keyID, key))
555 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
557 CHashWriter ss(SER_GETHASH, 0);
558 ss << strMessageMagic;
561 vector<unsigned char> vchSig;
562 if (!key.SignCompact(ss.GetHash(), vchSig))
563 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
565 return EncodeBase64(&vchSig[0], vchSig.size());
568 UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
570 if (!EnsureWalletIsAvailable(fHelp))
573 if (fHelp || params.size() < 1 || params.size() > 2)
575 "getreceivedbyaddress \"zcashaddress\" ( minconf )\n"
576 "\nReturns the total amount received by the given Zcash address in transactions with at least minconf confirmations.\n"
578 "1. \"zcashaddress\" (string, required) The Zcash address for transactions.\n"
579 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
581 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n"
583 "\nThe amount from transactions with at least 1 confirmation\n"
584 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"") +
585 "\nThe amount including unconfirmed transactions, zero confirmations\n"
586 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 0") +
587 "\nThe amount with at least 6 confirmations, very safe\n"
588 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 6") +
589 "\nAs a json rpc call\n"
590 + HelpExampleRpc("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", 6")
593 LOCK2(cs_main, pwalletMain->cs_wallet);
596 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
597 if (!address.IsValid())
598 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
599 CScript scriptPubKey = GetScriptForDestination(address.Get());
600 if (!IsMine(*pwalletMain,scriptPubKey))
603 // Minimum confirmations
605 if (params.size() > 1)
606 nMinDepth = params[1].get_int();
610 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
612 const CWalletTx& wtx = (*it).second;
613 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
616 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
617 if (txout.scriptPubKey == scriptPubKey)
618 if (wtx.GetDepthInMainChain() >= nMinDepth)
619 nAmount += txout.nValue;
622 return ValueFromAmount(nAmount);
626 UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
628 if (!EnsureWalletIsAvailable(fHelp))
631 if (fHelp || params.size() < 1 || params.size() > 2)
633 "getreceivedbyaccount \"account\" ( minconf )\n"
634 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
636 "1. \"account\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
637 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
639 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
641 "\nAmount received by the default account with at least 1 confirmation\n"
642 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
643 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
644 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
645 "\nThe amount with at least 6 confirmation, very safe\n"
646 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
647 "\nAs a json rpc call\n"
648 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
651 LOCK2(cs_main, pwalletMain->cs_wallet);
653 // Minimum confirmations
655 if (params.size() > 1)
656 nMinDepth = params[1].get_int();
658 // Get the set of pub keys assigned to account
659 string strAccount = AccountFromValue(params[0]);
660 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
664 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
666 const CWalletTx& wtx = (*it).second;
667 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
670 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
672 CTxDestination address;
673 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
674 if (wtx.GetDepthInMainChain() >= nMinDepth)
675 nAmount += txout.nValue;
679 return (double)nAmount / (double)COIN;
683 CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
685 CAmount nBalance = 0;
687 // Tally wallet transactions
688 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
690 const CWalletTx& wtx = (*it).second;
691 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
694 CAmount nReceived, nSent, nFee;
695 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
697 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
698 nBalance += nReceived;
699 nBalance -= nSent + nFee;
702 // Tally internal accounting entries
703 nBalance += walletdb.GetAccountCreditDebit(strAccount);
708 CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
710 CWalletDB walletdb(pwalletMain->strWalletFile);
711 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
715 UniValue getbalance(const UniValue& params, bool fHelp)
717 if (!EnsureWalletIsAvailable(fHelp))
720 if (fHelp || params.size() > 3)
722 "getbalance ( \"account\" minconf includeWatchonly )\n"
723 "\nReturns the server's total available balance.\n"
725 "1. \"account\" (string, optional) DEPRECATED. If provided, it MUST be set to the empty string \"\" or to the string \"*\", either of which will give the total available balance. Passing any other string will result in an error.\n"
726 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
727 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
729 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
731 "\nThe total amount in the wallet\n"
732 + HelpExampleCli("getbalance", "") +
733 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
734 + HelpExampleCli("getbalance", "\"*\" 6") +
735 "\nAs a json rpc call\n"
736 + HelpExampleRpc("getbalance", "\"*\", 6")
739 LOCK2(cs_main, pwalletMain->cs_wallet);
741 if (params.size() == 0)
742 return ValueFromAmount(pwalletMain->GetBalance());
745 if (params.size() > 1)
746 nMinDepth = params[1].get_int();
747 isminefilter filter = ISMINE_SPENDABLE;
748 if(params.size() > 2)
749 if(params[2].get_bool())
750 filter = filter | ISMINE_WATCH_ONLY;
752 if (params[0].get_str() == "*") {
753 // Calculate total balance a different way from GetBalance()
754 // (GetBalance() sums up all unspent TxOuts)
755 // getbalance and "getbalance * 1 true" should return the same number
756 CAmount nBalance = 0;
757 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
759 const CWalletTx& wtx = (*it).second;
760 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
764 string strSentAccount;
765 list<COutputEntry> listReceived;
766 list<COutputEntry> listSent;
767 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
768 if (wtx.GetDepthInMainChain() >= nMinDepth)
770 BOOST_FOREACH(const COutputEntry& r, listReceived)
771 nBalance += r.amount;
773 BOOST_FOREACH(const COutputEntry& s, listSent)
774 nBalance -= s.amount;
777 return ValueFromAmount(nBalance);
780 string strAccount = AccountFromValue(params[0]);
782 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
784 return ValueFromAmount(nBalance);
787 UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp)
789 if (!EnsureWalletIsAvailable(fHelp))
792 if (fHelp || params.size() > 0)
794 "getunconfirmedbalance\n"
795 "Returns the server's total unconfirmed balance\n");
797 LOCK2(cs_main, pwalletMain->cs_wallet);
799 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
803 UniValue movecmd(const UniValue& params, bool fHelp)
805 if (!EnsureWalletIsAvailable(fHelp))
808 if (fHelp || params.size() < 3 || params.size() > 5)
810 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
811 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
813 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
814 "2. \"toaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
815 "3. amount (numeric) Quantity of " + CURRENCY_UNIT + " to move between accounts.\n"
816 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
817 "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
819 "true|false (boolean) true if successful.\n"
821 "\nMove 0.01 " + CURRENCY_UNIT + " from the default account to the account named tabby\n"
822 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
823 "\nMove 0.01 " + CURRENCY_UNIT + " timotei to akiko with a comment and funds have 6 confirmations\n"
824 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
825 "\nAs a json rpc call\n"
826 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
829 LOCK2(cs_main, pwalletMain->cs_wallet);
831 string strFrom = AccountFromValue(params[0]);
832 string strTo = AccountFromValue(params[1]);
833 CAmount nAmount = AmountFromValue(params[2]);
835 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
836 if (params.size() > 3)
837 // unused parameter, used to be nMinDepth, keep type-checking it though
838 (void)params[3].get_int();
840 if (params.size() > 4)
841 strComment = params[4].get_str();
843 CWalletDB walletdb(pwalletMain->strWalletFile);
844 if (!walletdb.TxnBegin())
845 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
847 int64_t nNow = GetAdjustedTime();
850 CAccountingEntry debit;
851 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
852 debit.strAccount = strFrom;
853 debit.nCreditDebit = -nAmount;
855 debit.strOtherAccount = strTo;
856 debit.strComment = strComment;
857 walletdb.WriteAccountingEntry(debit);
860 CAccountingEntry credit;
861 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
862 credit.strAccount = strTo;
863 credit.nCreditDebit = nAmount;
865 credit.strOtherAccount = strFrom;
866 credit.strComment = strComment;
867 walletdb.WriteAccountingEntry(credit);
869 if (!walletdb.TxnCommit())
870 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
876 UniValue sendfrom(const UniValue& params, bool fHelp)
878 if (!EnsureWalletIsAvailable(fHelp))
881 if (fHelp || params.size() < 3 || params.size() > 6)
883 "sendfrom \"fromaccount\" \"tozcashaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
884 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a Zcash address.\n"
885 "The amount is a real and is rounded to the nearest 0.00000001."
886 + HelpRequiringPassphrase() + "\n"
888 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
889 "2. \"tozcashaddress\" (string, required) The Zcash address to send funds to.\n"
890 "3. amount (numeric, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n"
891 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
892 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
893 " This is not part of the transaction, just kept in your wallet.\n"
894 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
895 " to which you're sending the transaction. This is not part of the transaction, \n"
896 " it is just kept in your wallet.\n"
898 "\"transactionid\" (string) The transaction id.\n"
900 "\nSend 0.01 " + CURRENCY_UNIT + " from the default account to the address, must have at least 1 confirmation\n"
901 + HelpExampleCli("sendfrom", "\"\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
902 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
903 + HelpExampleCli("sendfrom", "\"tabby\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
904 "\nAs a json rpc call\n"
905 + HelpExampleRpc("sendfrom", "\"tabby\", \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
908 LOCK2(cs_main, pwalletMain->cs_wallet);
910 string strAccount = AccountFromValue(params[0]);
911 CBitcoinAddress address(params[1].get_str());
912 if (!address.IsValid())
913 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
914 CAmount nAmount = AmountFromValue(params[2]);
916 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
918 if (params.size() > 3)
919 nMinDepth = params[3].get_int();
922 wtx.strFromAccount = strAccount;
923 if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
924 wtx.mapValue["comment"] = params[4].get_str();
925 if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
926 wtx.mapValue["to"] = params[5].get_str();
928 EnsureWalletIsUnlocked();
931 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
932 if (nAmount > nBalance)
933 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
935 SendMoney(address.Get(), nAmount, false, wtx);
937 return wtx.GetHash().GetHex();
941 UniValue sendmany(const UniValue& params, bool fHelp)
943 if (!EnsureWalletIsAvailable(fHelp))
946 if (fHelp || params.size() < 2 || params.size() > 5)
948 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
949 "\nSend multiple times. Amounts are double-precision floating point numbers."
950 + HelpRequiringPassphrase() + "\n"
952 "1. \"fromaccount\" (string, required) MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
953 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
955 " \"address\":amount (numeric) The Zcash address is the key, the numeric amount in " + CURRENCY_UNIT + " is the value\n"
958 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
959 "4. \"comment\" (string, optional) A comment\n"
960 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
961 " The fee will be equally deducted from the amount of each selected address.\n"
962 " Those recipients will receive less Zcash than you enter in their corresponding amount field.\n"
963 " If no addresses are specified here, the sender pays the fee.\n"
965 " \"address\" (string) Subtract fee from this address\n"
969 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
970 " the number of addresses.\n"
972 "\nSend two amounts to two different addresses:\n"
973 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
974 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
975 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
976 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
977 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\",\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
978 "\nAs a json rpc call\n"
979 + HelpExampleRpc("sendmany", "\"\", \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
982 LOCK2(cs_main, pwalletMain->cs_wallet);
984 string strAccount = AccountFromValue(params[0]);
985 UniValue sendTo = params[1].get_obj();
987 if (params.size() > 2)
988 nMinDepth = params[2].get_int();
991 wtx.strFromAccount = strAccount;
992 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
993 wtx.mapValue["comment"] = params[3].get_str();
995 UniValue subtractFeeFromAmount(UniValue::VARR);
996 if (params.size() > 4)
997 subtractFeeFromAmount = params[4].get_array();
999 set<CBitcoinAddress> setAddress;
1000 vector<CRecipient> vecSend;
1002 CAmount totalAmount = 0;
1003 vector<string> keys = sendTo.getKeys();
1004 BOOST_FOREACH(const string& name_, keys)
1006 CBitcoinAddress address(name_);
1007 if (!address.IsValid())
1008 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+name_);
1010 if (setAddress.count(address))
1011 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
1012 setAddress.insert(address);
1014 CScript scriptPubKey = GetScriptForDestination(address.Get());
1015 CAmount nAmount = AmountFromValue(sendTo[name_]);
1017 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1018 totalAmount += nAmount;
1020 bool fSubtractFeeFromAmount = false;
1021 for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
1022 const UniValue& addr = subtractFeeFromAmount[idx];
1023 if (addr.get_str() == name_)
1024 fSubtractFeeFromAmount = true;
1027 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1028 vecSend.push_back(recipient);
1031 EnsureWalletIsUnlocked();
1034 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1035 if (totalAmount > nBalance)
1036 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1039 CReserveKey keyChange(pwalletMain);
1040 CAmount nFeeRequired = 0;
1041 int nChangePosRet = -1;
1042 string strFailReason;
1043 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
1045 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
1046 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1047 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
1049 return wtx.GetHash().GetHex();
1052 // Defined in rpcmisc.cpp
1053 extern CScript _createmultisig_redeemScript(const UniValue& params);
1055 UniValue addmultisigaddress(const UniValue& params, bool fHelp)
1057 if (!EnsureWalletIsAvailable(fHelp))
1058 return NullUniValue;
1060 if (fHelp || params.size() < 2 || params.size() > 3)
1062 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1063 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1064 "Each key is a Zcash address or hex-encoded public key.\n"
1065 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
1068 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1069 "2. \"keysobject\" (string, required) A json array of Zcash addresses or hex-encoded public keys\n"
1071 " \"address\" (string) Zcash address or hex-encoded public key\n"
1074 "3. \"account\" (string, optional) DEPRECATED. If provided, MUST be set to the empty string \"\" to represent the default account. Passing any other string will result in an error.\n"
1077 "\"zcashaddress\" (string) A Zcash address associated with the keys.\n"
1080 "\nAdd a multisig address from 2 addresses\n"
1081 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
1082 "\nAs json rpc call\n"
1083 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
1085 throw runtime_error(msg);
1088 LOCK2(cs_main, pwalletMain->cs_wallet);
1091 if (params.size() > 2)
1092 strAccount = AccountFromValue(params[2]);
1094 // Construct using pay-to-script-hash:
1095 CScript inner = _createmultisig_redeemScript(params);
1096 CScriptID innerID(inner);
1097 pwalletMain->AddCScript(inner);
1099 pwalletMain->SetAddressBook(innerID, strAccount, "send");
1100 return CBitcoinAddress(innerID).ToString();
1108 vector<uint256> txids;
1113 nConf = std::numeric_limits<int>::max();
1114 fIsWatchonly = false;
1118 UniValue ListReceived(const UniValue& params, bool fByAccounts)
1120 // Minimum confirmations
1122 if (params.size() > 0)
1123 nMinDepth = params[0].get_int();
1125 // Whether to include empty accounts
1126 bool fIncludeEmpty = false;
1127 if (params.size() > 1)
1128 fIncludeEmpty = params[1].get_bool();
1130 isminefilter filter = ISMINE_SPENDABLE;
1131 if(params.size() > 2)
1132 if(params[2].get_bool())
1133 filter = filter | ISMINE_WATCH_ONLY;
1136 map<CBitcoinAddress, tallyitem> mapTally;
1137 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1139 const CWalletTx& wtx = (*it).second;
1141 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
1144 int nDepth = wtx.GetDepthInMainChain();
1145 if (nDepth < nMinDepth)
1148 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1150 CTxDestination address;
1151 if (!ExtractDestination(txout.scriptPubKey, address))
1154 isminefilter mine = IsMine(*pwalletMain, address);
1155 if(!(mine & filter))
1158 tallyitem& item = mapTally[address];
1159 item.nAmount += txout.nValue;
1160 item.nConf = min(item.nConf, nDepth);
1161 item.txids.push_back(wtx.GetHash());
1162 if (mine & ISMINE_WATCH_ONLY)
1163 item.fIsWatchonly = true;
1168 UniValue ret(UniValue::VARR);
1169 map<string, tallyitem> mapAccountTally;
1170 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
1172 const CBitcoinAddress& address = item.first;
1173 const string& strAccount = item.second.name;
1174 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1175 if (it == mapTally.end() && !fIncludeEmpty)
1178 CAmount nAmount = 0;
1179 int nConf = std::numeric_limits<int>::max();
1180 bool fIsWatchonly = false;
1181 if (it != mapTally.end())
1183 nAmount = (*it).second.nAmount;
1184 nConf = (*it).second.nConf;
1185 fIsWatchonly = (*it).second.fIsWatchonly;
1190 tallyitem& item = mapAccountTally[strAccount];
1191 item.nAmount += nAmount;
1192 item.nConf = min(item.nConf, nConf);
1193 item.fIsWatchonly = fIsWatchonly;
1197 UniValue obj(UniValue::VOBJ);
1199 obj.push_back(Pair("involvesWatchonly", true));
1200 obj.push_back(Pair("address", address.ToString()));
1201 obj.push_back(Pair("account", strAccount));
1202 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1203 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1204 UniValue transactions(UniValue::VARR);
1205 if (it != mapTally.end())
1207 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1209 transactions.push_back(item.GetHex());
1212 obj.push_back(Pair("txids", transactions));
1219 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1221 CAmount nAmount = (*it).second.nAmount;
1222 int nConf = (*it).second.nConf;
1223 UniValue obj(UniValue::VOBJ);
1224 if((*it).second.fIsWatchonly)
1225 obj.push_back(Pair("involvesWatchonly", true));
1226 obj.push_back(Pair("account", (*it).first));
1227 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1228 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1236 UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
1238 if (!EnsureWalletIsAvailable(fHelp))
1239 return NullUniValue;
1241 if (fHelp || params.size() > 3)
1242 throw runtime_error(
1243 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
1244 "\nList balances by receiving address.\n"
1246 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1247 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
1248 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1253 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1254 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
1255 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
1256 " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n"
1257 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1263 + HelpExampleCli("listreceivedbyaddress", "")
1264 + HelpExampleCli("listreceivedbyaddress", "6 true")
1265 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1268 LOCK2(cs_main, pwalletMain->cs_wallet);
1270 return ListReceived(params, false);
1273 UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
1275 if (!EnsureWalletIsAvailable(fHelp))
1276 return NullUniValue;
1278 if (fHelp || params.size() > 3)
1279 throw runtime_error(
1280 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
1281 "\nDEPRECATED. List balances by account.\n"
1283 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1284 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
1285 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1290 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1291 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1292 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1293 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1299 + HelpExampleCli("listreceivedbyaccount", "")
1300 + HelpExampleCli("listreceivedbyaccount", "6 true")
1301 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
1304 LOCK2(cs_main, pwalletMain->cs_wallet);
1306 return ListReceived(params, true);
1309 static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
1311 CBitcoinAddress addr;
1313 entry.push_back(Pair("address", addr.ToString()));
1316 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
1319 string strSentAccount;
1320 list<COutputEntry> listReceived;
1321 list<COutputEntry> listSent;
1323 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
1325 bool fAllAccounts = (strAccount == string("*"));
1326 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
1329 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1331 BOOST_FOREACH(const COutputEntry& s, listSent)
1333 UniValue entry(UniValue::VOBJ);
1334 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
1335 entry.push_back(Pair("involvesWatchonly", true));
1336 entry.push_back(Pair("account", strSentAccount));
1337 MaybePushAddress(entry, s.destination);
1338 entry.push_back(Pair("category", "send"));
1339 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1340 entry.push_back(Pair("vout", s.vout));
1341 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1343 WalletTxToJSON(wtx, entry);
1344 entry.push_back(Pair("size", static_cast<uint64_t>(static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION))));
1345 ret.push_back(entry);
1350 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1352 BOOST_FOREACH(const COutputEntry& r, listReceived)
1355 if (pwalletMain->mapAddressBook.count(r.destination))
1356 account = pwalletMain->mapAddressBook[r.destination].name;
1357 if (fAllAccounts || (account == strAccount))
1359 UniValue entry(UniValue::VOBJ);
1360 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
1361 entry.push_back(Pair("involvesWatchonly", true));
1362 entry.push_back(Pair("account", account));
1363 MaybePushAddress(entry, r.destination);
1364 if (wtx.IsCoinBase())
1366 if (wtx.GetDepthInMainChain() < 1)
1367 entry.push_back(Pair("category", "orphan"));
1368 else if (wtx.GetBlocksToMaturity() > 0)
1369 entry.push_back(Pair("category", "immature"));
1371 entry.push_back(Pair("category", "generate"));
1375 entry.push_back(Pair("category", "receive"));
1377 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1378 entry.push_back(Pair("vout", r.vout));
1380 WalletTxToJSON(wtx, entry);
1381 entry.push_back(Pair("size", static_cast<uint64_t>(static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION))));
1382 ret.push_back(entry);
1388 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
1390 bool fAllAccounts = (strAccount == string("*"));
1392 if (fAllAccounts || acentry.strAccount == strAccount)
1394 UniValue entry(UniValue::VOBJ);
1395 entry.push_back(Pair("account", acentry.strAccount));
1396 entry.push_back(Pair("category", "move"));
1397 entry.push_back(Pair("time", acentry.nTime));
1398 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1399 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1400 entry.push_back(Pair("comment", acentry.strComment));
1401 ret.push_back(entry);
1405 UniValue listtransactions(const UniValue& params, bool fHelp)
1407 if (!EnsureWalletIsAvailable(fHelp))
1408 return NullUniValue;
1410 if (fHelp || params.size() > 4)
1411 throw runtime_error(
1412 "listtransactions ( \"account\" count from includeWatchonly)\n"
1413 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1415 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
1416 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1417 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
1418 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
1422 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
1423 " It will be \"\" for the default account.\n"
1424 " \"address\":\"zcashaddress\", (string) The Zcash address of the transaction. Not present for \n"
1425 " move transactions (category = move).\n"
1426 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1427 " transaction between accounts, and not associated with an address,\n"
1428 " transaction id or block. 'send' and 'receive' transactions are \n"
1429 " associated with an address, transaction id and block details\n"
1430 " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the\n"
1431 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1432 " and for the 'move' category for inbound funds.\n"
1433 " \"vout\" : n, (numeric) the vout value\n"
1434 " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
1435 " 'send' category of transactions.\n"
1436 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1437 " 'receive' category of transactions.\n"
1438 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1439 " category of transactions.\n"
1440 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1441 " category of transactions.\n"
1442 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1443 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1444 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1445 " for 'send' and 'receive' category of transactions.\n"
1446 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1447 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1448 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1449 " negative amounts).\n"
1450 " \"size\": n, (numeric) Transaction size in bytes\n"
1455 "\nList the most recent 10 transactions in the systems\n"
1456 + HelpExampleCli("listtransactions", "") +
1457 "\nList transactions 100 to 120\n"
1458 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
1459 "\nAs a json rpc call\n"
1460 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
1463 LOCK2(cs_main, pwalletMain->cs_wallet);
1465 string strAccount = "*";
1466 if (params.size() > 0)
1467 strAccount = params[0].get_str();
1469 if (params.size() > 1)
1470 nCount = params[1].get_int();
1472 if (params.size() > 2)
1473 nFrom = params[2].get_int();
1474 isminefilter filter = ISMINE_SPENDABLE;
1475 if(params.size() > 3)
1476 if(params[3].get_bool())
1477 filter = filter | ISMINE_WATCH_ONLY;
1480 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1482 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1484 UniValue ret(UniValue::VARR);
1486 std::list<CAccountingEntry> acentries;
1487 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1489 // iterate backwards until we have nCount items to return:
1490 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1492 CWalletTx *const pwtx = (*it).second.first;
1494 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1495 CAccountingEntry *const pacentry = (*it).second.second;
1497 AcentryToJSON(*pacentry, strAccount, ret);
1499 if ((int)ret.size() >= (nCount+nFrom)) break;
1501 // ret is newest to oldest
1503 if (nFrom > (int)ret.size())
1505 if ((nFrom + nCount) > (int)ret.size())
1506 nCount = ret.size() - nFrom;
1508 vector<UniValue> arrTmp = ret.getValues();
1510 vector<UniValue>::iterator first = arrTmp.begin();
1511 std::advance(first, nFrom);
1512 vector<UniValue>::iterator last = arrTmp.begin();
1513 std::advance(last, nFrom+nCount);
1515 if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
1516 if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
1518 std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
1522 ret.push_backV(arrTmp);
1527 UniValue listaccounts(const UniValue& params, bool fHelp)
1529 if (!EnsureWalletIsAvailable(fHelp))
1530 return NullUniValue;
1532 if (fHelp || params.size() > 2)
1533 throw runtime_error(
1534 "listaccounts ( minconf includeWatchonly)\n"
1535 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
1537 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
1538 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
1540 "{ (json object where keys are account names, and values are numeric balances\n"
1541 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1545 "\nList account balances where there at least 1 confirmation\n"
1546 + HelpExampleCli("listaccounts", "") +
1547 "\nList account balances including zero confirmation transactions\n"
1548 + HelpExampleCli("listaccounts", "0") +
1549 "\nList account balances for 6 or more confirmations\n"
1550 + HelpExampleCli("listaccounts", "6") +
1551 "\nAs json rpc call\n"
1552 + HelpExampleRpc("listaccounts", "6")
1555 LOCK2(cs_main, pwalletMain->cs_wallet);
1558 if (params.size() > 0)
1559 nMinDepth = params[0].get_int();
1560 isminefilter includeWatchonly = ISMINE_SPENDABLE;
1561 if(params.size() > 1)
1562 if(params[1].get_bool())
1563 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
1565 map<string, CAmount> mapAccountBalances;
1566 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
1567 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
1568 mapAccountBalances[entry.second.name] = 0;
1571 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1573 const CWalletTx& wtx = (*it).second;
1575 string strSentAccount;
1576 list<COutputEntry> listReceived;
1577 list<COutputEntry> listSent;
1578 int nDepth = wtx.GetDepthInMainChain();
1579 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
1581 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1582 mapAccountBalances[strSentAccount] -= nFee;
1583 BOOST_FOREACH(const COutputEntry& s, listSent)
1584 mapAccountBalances[strSentAccount] -= s.amount;
1585 if (nDepth >= nMinDepth)
1587 BOOST_FOREACH(const COutputEntry& r, listReceived)
1588 if (pwalletMain->mapAddressBook.count(r.destination))
1589 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
1591 mapAccountBalances[""] += r.amount;
1595 list<CAccountingEntry> acentries;
1596 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1597 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1598 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1600 UniValue ret(UniValue::VOBJ);
1601 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
1602 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1607 UniValue listsinceblock(const UniValue& params, bool fHelp)
1609 if (!EnsureWalletIsAvailable(fHelp))
1610 return NullUniValue;
1613 throw runtime_error(
1614 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
1615 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1617 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1618 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
1619 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
1622 " \"transactions\": [\n"
1623 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
1624 " \"address\":\"zcashaddress\", (string) The Zcash address of the transaction. Not present for move transactions (category = move).\n"
1625 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1626 " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
1627 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1628 " \"vout\" : n, (numeric) the vout value\n"
1629 " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the 'send' category of transactions.\n"
1630 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1631 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1632 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1633 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1634 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1635 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1636 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1637 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1638 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1640 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1643 + HelpExampleCli("listsinceblock", "")
1644 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1645 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1648 LOCK2(cs_main, pwalletMain->cs_wallet);
1650 CBlockIndex *pindex = NULL;
1651 int target_confirms = 1;
1652 isminefilter filter = ISMINE_SPENDABLE;
1654 if (params.size() > 0)
1658 blockId.SetHex(params[0].get_str());
1659 BlockMap::iterator it = mapBlockIndex.find(blockId);
1660 if (it != mapBlockIndex.end())
1661 pindex = it->second;
1664 if (params.size() > 1)
1666 target_confirms = params[1].get_int();
1668 if (target_confirms < 1)
1669 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1672 if(params.size() > 2)
1673 if(params[2].get_bool())
1674 filter = filter | ISMINE_WATCH_ONLY;
1676 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
1678 UniValue transactions(UniValue::VARR);
1680 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1682 CWalletTx tx = (*it).second;
1684 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1685 ListTransactions(tx, "*", 0, true, transactions, filter);
1688 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
1689 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
1691 UniValue ret(UniValue::VOBJ);
1692 ret.push_back(Pair("transactions", transactions));
1693 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1698 UniValue gettransaction(const UniValue& params, bool fHelp)
1700 if (!EnsureWalletIsAvailable(fHelp))
1701 return NullUniValue;
1703 if (fHelp || params.size() < 1 || params.size() > 2)
1704 throw runtime_error(
1705 "gettransaction \"txid\" ( includeWatchonly )\n"
1706 "\nGet detailed information about in-wallet transaction <txid>\n"
1708 "1. \"txid\" (string, required) The transaction id\n"
1709 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
1712 " \"amount\" : x.xxx, (numeric) The transaction amount in " + CURRENCY_UNIT + "\n"
1713 " \"confirmations\" : n, (numeric) The number of confirmations\n"
1714 " \"blockhash\" : \"hash\", (string) The block hash\n"
1715 " \"blockindex\" : xx, (numeric) The block index\n"
1716 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
1717 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
1718 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1719 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1720 " \"details\" : [\n"
1722 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
1723 " \"address\" : \"zcashaddress\", (string) The Zcash address involved in the transaction\n"
1724 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
1725 " \"amount\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
1726 " \"vout\" : n, (numeric) the vout value\n"
1730 " \"vjoinsplit\" : [\n"
1732 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
1733 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
1734 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
1735 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
1736 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
1737 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
1741 " \"hex\" : \"data\" (string) Raw data for transaction\n"
1745 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1746 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
1747 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1750 LOCK2(cs_main, pwalletMain->cs_wallet);
1753 hash.SetHex(params[0].get_str());
1755 isminefilter filter = ISMINE_SPENDABLE;
1756 if(params.size() > 1)
1757 if(params[1].get_bool())
1758 filter = filter | ISMINE_WATCH_ONLY;
1760 UniValue entry(UniValue::VOBJ);
1761 if (!pwalletMain->mapWallet.count(hash))
1762 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1763 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1765 CAmount nCredit = wtx.GetCredit(filter);
1766 CAmount nDebit = wtx.GetDebit(filter);
1767 CAmount nNet = nCredit - nDebit;
1768 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1770 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1771 if (wtx.IsFromMe(filter))
1772 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1774 WalletTxToJSON(wtx, entry);
1776 UniValue details(UniValue::VARR);
1777 ListTransactions(wtx, "*", 0, false, details, filter);
1778 entry.push_back(Pair("details", details));
1780 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
1781 entry.push_back(Pair("hex", strHex));
1787 UniValue backupwallet(const UniValue& params, bool fHelp)
1789 if (!EnsureWalletIsAvailable(fHelp))
1790 return NullUniValue;
1792 if (fHelp || params.size() != 1)
1793 throw runtime_error(
1794 "backupwallet \"destination\"\n"
1795 "\nSafely copies wallet.dat to destination filename\n"
1797 "1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
1799 "\"path\" (string) The full path of the destination file\n"
1801 + HelpExampleCli("backupwallet", "\"backupdata\"")
1802 + HelpExampleRpc("backupwallet", "\"backupdata\"")
1805 LOCK2(cs_main, pwalletMain->cs_wallet);
1807 boost::filesystem::path exportdir;
1809 exportdir = GetExportDir();
1810 } catch (const std::runtime_error& e) {
1811 throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
1813 if (exportdir.empty()) {
1814 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
1816 std::string unclean = params[0].get_str();
1817 std::string clean = SanitizeFilename(unclean);
1818 if (clean.compare(unclean) != 0) {
1819 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
1821 boost::filesystem::path exportfilepath = exportdir / clean;
1823 if (!BackupWallet(*pwalletMain, exportfilepath.string()))
1824 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1826 return exportfilepath.string();
1830 UniValue keypoolrefill(const UniValue& params, bool fHelp)
1832 if (!EnsureWalletIsAvailable(fHelp))
1833 return NullUniValue;
1835 if (fHelp || params.size() > 1)
1836 throw runtime_error(
1837 "keypoolrefill ( newsize )\n"
1838 "\nFills the keypool."
1839 + HelpRequiringPassphrase() + "\n"
1841 "1. newsize (numeric, optional, default=100) The new keypool size\n"
1843 + HelpExampleCli("keypoolrefill", "")
1844 + HelpExampleRpc("keypoolrefill", "")
1847 LOCK2(cs_main, pwalletMain->cs_wallet);
1849 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1850 unsigned int kpSize = 0;
1851 if (params.size() > 0) {
1852 if (params[0].get_int() < 0)
1853 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1854 kpSize = (unsigned int)params[0].get_int();
1857 EnsureWalletIsUnlocked();
1858 pwalletMain->TopUpKeyPool(kpSize);
1860 if (pwalletMain->GetKeyPoolSize() < kpSize)
1861 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1863 return NullUniValue;
1867 static void LockWallet(CWallet* pWallet)
1869 LOCK(cs_nWalletUnlockTime);
1870 nWalletUnlockTime = 0;
1874 UniValue walletpassphrase(const UniValue& params, bool fHelp)
1876 if (!EnsureWalletIsAvailable(fHelp))
1877 return NullUniValue;
1879 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1880 throw runtime_error(
1881 "walletpassphrase \"passphrase\" timeout\n"
1882 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
1883 "This is needed prior to performing transactions related to private keys such as sending Zcash\n"
1885 "1. \"passphrase\" (string, required) The wallet passphrase\n"
1886 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
1888 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
1889 "time that overrides the old one.\n"
1891 "\nunlock the wallet for 60 seconds\n"
1892 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1893 "\nLock the wallet again (before 60 seconds)\n"
1894 + HelpExampleCli("walletlock", "") +
1895 "\nAs json rpc call\n"
1896 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1899 LOCK2(cs_main, pwalletMain->cs_wallet);
1903 if (!pwalletMain->IsCrypted())
1904 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1906 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1907 SecureString strWalletPass;
1908 strWalletPass.reserve(100);
1909 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1910 // Alternately, find a way to make params[0] mlock()'d to begin with.
1911 strWalletPass = params[0].get_str().c_str();
1913 if (strWalletPass.length() > 0)
1915 if (!pwalletMain->Unlock(strWalletPass))
1916 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1919 throw runtime_error(
1920 "walletpassphrase <passphrase> <timeout>\n"
1921 "Stores the wallet decryption key in memory for <timeout> seconds.");
1923 // No need to check return values, because the wallet was unlocked above
1924 pwalletMain->UpdateNullifierNoteMap();
1925 pwalletMain->TopUpKeyPool();
1927 int64_t nSleepTime = params[1].get_int64();
1928 LOCK(cs_nWalletUnlockTime);
1929 nWalletUnlockTime = GetTime() + nSleepTime;
1930 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
1932 return NullUniValue;
1936 UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
1938 if (!EnsureWalletIsAvailable(fHelp))
1939 return NullUniValue;
1941 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1942 throw runtime_error(
1943 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
1944 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
1946 "1. \"oldpassphrase\" (string) The current passphrase\n"
1947 "2. \"newpassphrase\" (string) The new passphrase\n"
1949 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
1950 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
1953 LOCK2(cs_main, pwalletMain->cs_wallet);
1957 if (!pwalletMain->IsCrypted())
1958 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1960 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1961 // Alternately, find a way to make params[0] mlock()'d to begin with.
1962 SecureString strOldWalletPass;
1963 strOldWalletPass.reserve(100);
1964 strOldWalletPass = params[0].get_str().c_str();
1966 SecureString strNewWalletPass;
1967 strNewWalletPass.reserve(100);
1968 strNewWalletPass = params[1].get_str().c_str();
1970 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1971 throw runtime_error(
1972 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1973 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1975 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1976 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1978 return NullUniValue;
1982 UniValue walletlock(const UniValue& params, bool fHelp)
1984 if (!EnsureWalletIsAvailable(fHelp))
1985 return NullUniValue;
1987 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1988 throw runtime_error(
1990 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
1991 "After calling this method, you will need to call walletpassphrase again\n"
1992 "before being able to call any methods which require the wallet to be unlocked.\n"
1994 "\nSet the passphrase for 2 minutes to perform a transaction\n"
1995 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
1996 "\nPerform a send (requires passphrase set)\n"
1997 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
1998 "\nClear the passphrase since we are done before 2 minutes is up\n"
1999 + HelpExampleCli("walletlock", "") +
2000 "\nAs json rpc call\n"
2001 + HelpExampleRpc("walletlock", "")
2004 LOCK2(cs_main, pwalletMain->cs_wallet);
2008 if (!pwalletMain->IsCrypted())
2009 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
2012 LOCK(cs_nWalletUnlockTime);
2013 pwalletMain->Lock();
2014 nWalletUnlockTime = 0;
2017 return NullUniValue;
2021 UniValue encryptwallet(const UniValue& params, bool fHelp)
2023 if (!EnsureWalletIsAvailable(fHelp))
2024 return NullUniValue;
2026 auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-developerencryptwallet", false);
2028 std::string strWalletEncryptionDisabledMsg = "";
2029 if (!fEnableWalletEncryption) {
2030 strWalletEncryptionDisabledMsg = "\nWARNING: Wallet encryption is DISABLED. This call always fails.\n";
2033 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2034 throw runtime_error(
2035 "encryptwallet \"passphrase\"\n"
2036 + strWalletEncryptionDisabledMsg +
2037 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2038 "After this, any calls that interact with private keys such as sending or signing \n"
2039 "will require the passphrase to be set prior the making these calls.\n"
2040 "Use the walletpassphrase call for this, and then walletlock call.\n"
2041 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2042 "Note that this will shutdown the server.\n"
2044 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2046 "\nEncrypt you wallet\n"
2047 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
2048 "\nNow set the passphrase to use the wallet, such as for signing or sending Zcash\n"
2049 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2050 "\nNow we can so something like sign\n"
2051 + HelpExampleCli("signmessage", "\"zcashaddress\" \"test message\"") +
2052 "\nNow lock the wallet again by removing the passphrase\n"
2053 + HelpExampleCli("walletlock", "") +
2054 "\nAs a json rpc call\n"
2055 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2058 LOCK2(cs_main, pwalletMain->cs_wallet);
2062 if (!fEnableWalletEncryption) {
2063 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
2065 if (pwalletMain->IsCrypted())
2066 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
2068 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2069 // Alternately, find a way to make params[0] mlock()'d to begin with.
2070 SecureString strWalletPass;
2071 strWalletPass.reserve(100);
2072 strWalletPass = params[0].get_str().c_str();
2074 if (strWalletPass.length() < 1)
2075 throw runtime_error(
2076 "encryptwallet <passphrase>\n"
2077 "Encrypts the wallet with <passphrase>.");
2079 if (!pwalletMain->EncryptWallet(strWalletPass))
2080 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
2082 // BDB seems to have a bad habit of writing old data into
2083 // slack space in .dat files; that is bad if the old data is
2084 // unencrypted private keys. So:
2086 return "wallet encrypted; Zcash server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
2089 UniValue lockunspent(const UniValue& params, bool fHelp)
2091 if (!EnsureWalletIsAvailable(fHelp))
2092 return NullUniValue;
2094 if (fHelp || params.size() < 1 || params.size() > 2)
2095 throw runtime_error(
2096 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2097 "\nUpdates list of temporarily unspendable outputs.\n"
2098 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
2099 "A locked transaction output will not be chosen by automatic coin selection, when spending Zcash.\n"
2100 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2101 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2102 "Also see the listunspent call\n"
2104 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2105 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2106 " [ (json array of json objects)\n"
2108 " \"txid\":\"id\", (string) The transaction id\n"
2109 " \"vout\": n (numeric) The output number\n"
2115 "true|false (boolean) Whether the command was successful or not\n"
2118 "\nList the unspent transactions\n"
2119 + HelpExampleCli("listunspent", "") +
2120 "\nLock an unspent transaction\n"
2121 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2122 "\nList the locked transactions\n"
2123 + HelpExampleCli("listlockunspent", "") +
2124 "\nUnlock the transaction again\n"
2125 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2126 "\nAs a json rpc call\n"
2127 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2130 LOCK2(cs_main, pwalletMain->cs_wallet);
2132 if (params.size() == 1)
2133 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
2135 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
2137 bool fUnlock = params[0].get_bool();
2139 if (params.size() == 1) {
2141 pwalletMain->UnlockAllCoins();
2145 UniValue outputs = params[1].get_array();
2146 for (size_t idx = 0; idx < outputs.size(); idx++) {
2147 const UniValue& output = outputs[idx];
2148 if (!output.isObject())
2149 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
2150 const UniValue& o = output.get_obj();
2152 RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
2154 string txid = find_value(o, "txid").get_str();
2156 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
2158 int nOutput = find_value(o, "vout").get_int();
2160 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
2162 COutPoint outpt(uint256S(txid), nOutput);
2165 pwalletMain->UnlockCoin(outpt);
2167 pwalletMain->LockCoin(outpt);
2173 UniValue listlockunspent(const UniValue& params, bool fHelp)
2175 if (!EnsureWalletIsAvailable(fHelp))
2176 return NullUniValue;
2178 if (fHelp || params.size() > 0)
2179 throw runtime_error(
2181 "\nReturns list of temporarily unspendable outputs.\n"
2182 "See the lockunspent call to lock and unlock transactions for spending.\n"
2186 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2187 " \"vout\" : n (numeric) The vout value\n"
2192 "\nList the unspent transactions\n"
2193 + HelpExampleCli("listunspent", "") +
2194 "\nLock an unspent transaction\n"
2195 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2196 "\nList the locked transactions\n"
2197 + HelpExampleCli("listlockunspent", "") +
2198 "\nUnlock the transaction again\n"
2199 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2200 "\nAs a json rpc call\n"
2201 + HelpExampleRpc("listlockunspent", "")
2204 LOCK2(cs_main, pwalletMain->cs_wallet);
2206 vector<COutPoint> vOutpts;
2207 pwalletMain->ListLockedCoins(vOutpts);
2209 UniValue ret(UniValue::VARR);
2211 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
2212 UniValue o(UniValue::VOBJ);
2214 o.push_back(Pair("txid", outpt.hash.GetHex()));
2215 o.push_back(Pair("vout", (int)outpt.n));
2222 UniValue settxfee(const UniValue& params, bool fHelp)
2224 if (!EnsureWalletIsAvailable(fHelp))
2225 return NullUniValue;
2227 if (fHelp || params.size() < 1 || params.size() > 1)
2228 throw runtime_error(
2230 "\nSet the transaction fee per kB.\n"
2232 "1. amount (numeric, required) The transaction fee in " + CURRENCY_UNIT + "/kB rounded to the nearest 0.00000001\n"
2234 "true|false (boolean) Returns true if successful\n"
2236 + HelpExampleCli("settxfee", "0.00001")
2237 + HelpExampleRpc("settxfee", "0.00001")
2240 LOCK2(cs_main, pwalletMain->cs_wallet);
2243 CAmount nAmount = AmountFromValue(params[0]);
2245 payTxFee = CFeeRate(nAmount, 1000);
2249 UniValue getwalletinfo(const UniValue& params, bool fHelp)
2251 if (!EnsureWalletIsAvailable(fHelp))
2252 return NullUniValue;
2254 if (fHelp || params.size() != 0)
2255 throw runtime_error(
2257 "Returns an object containing various wallet state info.\n"
2260 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
2261 " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2262 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2263 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n"
2264 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2265 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2266 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2267 " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
2268 " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
2271 + HelpExampleCli("getwalletinfo", "")
2272 + HelpExampleRpc("getwalletinfo", "")
2275 LOCK2(cs_main, pwalletMain->cs_wallet);
2277 UniValue obj(UniValue::VOBJ);
2278 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2279 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
2280 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2281 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
2282 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
2283 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
2284 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2285 if (pwalletMain->IsCrypted())
2286 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
2287 obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
2291 UniValue resendwallettransactions(const UniValue& params, bool fHelp)
2293 if (!EnsureWalletIsAvailable(fHelp))
2294 return NullUniValue;
2296 if (fHelp || params.size() != 0)
2297 throw runtime_error(
2298 "resendwallettransactions\n"
2299 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2300 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2302 "Returns array of transaction ids that were re-broadcast.\n"
2305 LOCK2(cs_main, pwalletMain->cs_wallet);
2307 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
2308 UniValue result(UniValue::VARR);
2309 BOOST_FOREACH(const uint256& txid, txids)
2311 result.push_back(txid.ToString());
2316 UniValue listunspent(const UniValue& params, bool fHelp)
2318 if (!EnsureWalletIsAvailable(fHelp))
2319 return NullUniValue;
2321 if (fHelp || params.size() > 3)
2322 throw runtime_error(
2323 "listunspent ( minconf maxconf [\"address\",...] )\n"
2324 "\nReturns array of unspent transaction outputs\n"
2325 "with between minconf and maxconf (inclusive) confirmations.\n"
2326 "Optionally filter to only include txouts paid to specified addresses.\n"
2327 "Results are an array of Objects, each of which has:\n"
2328 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2330 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2331 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
2332 "3. \"addresses\" (string) A json array of Zcash addresses to filter\n"
2334 " \"address\" (string) Zcash address\n"
2338 "[ (array of json object)\n"
2340 " \"txid\" : \"txid\", (string) the transaction id \n"
2341 " \"vout\" : n, (numeric) the vout value\n"
2342 " \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
2343 " \"address\" : \"address\", (string) the Zcash address\n"
2344 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2345 " \"scriptPubKey\" : \"key\", (string) the script key\n"
2346 " \"amount\" : x.xxx, (numeric) the transaction amount in " + CURRENCY_UNIT + "\n"
2347 " \"confirmations\" : n (numeric) The number of confirmations\n"
2353 + HelpExampleCli("listunspent", "")
2354 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2355 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2358 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
2361 if (params.size() > 0)
2362 nMinDepth = params[0].get_int();
2364 int nMaxDepth = 9999999;
2365 if (params.size() > 1)
2366 nMaxDepth = params[1].get_int();
2368 set<CBitcoinAddress> setAddress;
2369 if (params.size() > 2) {
2370 UniValue inputs = params[2].get_array();
2371 for (size_t idx = 0; idx < inputs.size(); idx++) {
2372 const UniValue& input = inputs[idx];
2373 CBitcoinAddress address(input.get_str());
2374 if (!address.IsValid())
2375 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+input.get_str());
2376 if (setAddress.count(address))
2377 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2378 setAddress.insert(address);
2382 UniValue results(UniValue::VARR);
2383 vector<COutput> vecOutputs;
2384 assert(pwalletMain != NULL);
2385 LOCK2(cs_main, pwalletMain->cs_wallet);
2386 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2387 BOOST_FOREACH(const COutput& out, vecOutputs) {
2388 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
2391 if (setAddress.size()) {
2392 CTxDestination address;
2393 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
2396 if (!setAddress.count(address))
2400 CAmount nValue = out.tx->vout[out.i].nValue;
2401 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
2402 UniValue entry(UniValue::VOBJ);
2403 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
2404 entry.push_back(Pair("vout", out.i));
2405 entry.push_back(Pair("generated", out.tx->IsCoinBase()));
2406 CTxDestination address;
2407 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2408 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2409 if (pwalletMain->mapAddressBook.count(address))
2410 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
2412 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2413 if (pk.IsPayToScriptHash()) {
2414 CTxDestination address;
2415 if (ExtractDestination(pk, address)) {
2416 const CScriptID& hash = boost::get<CScriptID>(address);
2417 CScript redeemScript;
2418 if (pwalletMain->GetCScript(hash, redeemScript))
2419 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
2422 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
2423 entry.push_back(Pair("confirmations",out.nDepth));
2424 entry.push_back(Pair("spendable", out.fSpendable));
2425 results.push_back(entry);
2431 UniValue fundrawtransaction(const UniValue& params, bool fHelp)
2433 if (!EnsureWalletIsAvailable(fHelp))
2434 return NullUniValue;
2436 if (fHelp || params.size() != 1)
2437 throw runtime_error(
2438 "fundrawtransaction \"hexstring\"\n"
2439 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
2440 "This will not modify existing inputs, and will add one change output to the outputs.\n"
2441 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
2442 "The inputs added will not be signed, use signrawtransaction for that.\n"
2444 "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
2447 " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
2448 " \"fee\": n, (numeric) The fee added to the transaction\n"
2449 " \"changepos\": n (numeric) The position of the added change output, or -1\n"
2453 "\nCreate a transaction with no inputs\n"
2454 + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
2455 "\nAdd sufficient unsigned inputs to meet the output value\n"
2456 + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
2457 "\nSign the transaction\n"
2458 + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
2459 "\nSend the transaction\n"
2460 + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
2463 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
2465 // parse hex string from parameter
2466 CTransaction origTx;
2467 if (!DecodeHexTx(origTx, params[0].get_str()))
2468 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2470 CMutableTransaction tx(origTx);
2472 string strFailReason;
2473 int nChangePos = -1;
2474 if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
2475 throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
2477 UniValue result(UniValue::VOBJ);
2478 result.push_back(Pair("hex", EncodeHexTx(tx)));
2479 result.push_back(Pair("changepos", nChangePos));
2480 result.push_back(Pair("fee", ValueFromAmount(nFee)));
2485 UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
2488 throw runtime_error(
2489 "zcsamplejoinsplit\n"
2491 "Perform a joinsplit and return the JSDescription.\n"
2498 uint256 anchor = ZCIncrementalMerkleTree().root();
2499 JSDescription samplejoinsplit(*pzcashParams,
2502 {JSInput(), JSInput()},
2503 {JSOutput(), JSOutput()},
2507 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2508 ss << samplejoinsplit;
2510 return HexStr(ss.begin(), ss.end());
2513 UniValue zc_benchmark(const UniValue& params, bool fHelp)
2515 if (!EnsureWalletIsAvailable(fHelp)) {
2516 return NullUniValue;
2519 if (fHelp || params.size() < 2) {
2520 throw runtime_error(
2521 "zcbenchmark benchmarktype samplecount\n"
2523 "Runs a benchmark of the selected type samplecount times,\n"
2524 "returning the running times of each sample.\n"
2528 " \"runningtime\": runningtime\n"
2531 " \"runningtime\": runningtime\n"
2540 std::string benchmarktype = params[0].get_str();
2541 int samplecount = params[1].get_int();
2543 if (samplecount <= 0) {
2544 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2547 std::vector<double> sample_times;
2549 JSDescription samplejoinsplit;
2551 if (benchmarktype == "verifyjoinsplit") {
2552 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2553 ss >> samplejoinsplit;
2556 for (int i = 0; i < samplecount; i++) {
2557 if (benchmarktype == "sleep") {
2558 sample_times.push_back(benchmark_sleep());
2559 } else if (benchmarktype == "parameterloading") {
2560 sample_times.push_back(benchmark_parameter_loading());
2561 } else if (benchmarktype == "createjoinsplit") {
2562 if (params.size() < 3) {
2563 sample_times.push_back(benchmark_create_joinsplit());
2565 int nThreads = params[2].get_int();
2566 std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
2567 // Divide by nThreads^2 to get average seconds per JoinSplit because
2568 // we are running one JoinSplit per thread.
2569 sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
2571 } else if (benchmarktype == "verifyjoinsplit") {
2572 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2573 #ifdef ENABLE_MINING
2574 } else if (benchmarktype == "solveequihash") {
2575 if (params.size() < 3) {
2576 sample_times.push_back(benchmark_solve_equihash());
2578 int nThreads = params[2].get_int();
2579 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
2580 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
2583 } else if (benchmarktype == "verifyequihash") {
2584 sample_times.push_back(benchmark_verify_equihash());
2585 } else if (benchmarktype == "validatelargetx") {
2586 // Number of inputs in the spending transaction that we will simulate
2588 if (params.size() >= 3) {
2589 nInputs = params[2].get_int();
2591 sample_times.push_back(benchmark_large_tx(nInputs));
2592 } else if (benchmarktype == "trydecryptnotes") {
2593 int nAddrs = params[2].get_int();
2594 sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
2595 } else if (benchmarktype == "incnotewitnesses") {
2596 int nTxs = params[2].get_int();
2597 sample_times.push_back(benchmark_increment_note_witnesses(nTxs));
2598 } else if (benchmarktype == "connectblockslow") {
2599 if (Params().NetworkIDString() != "regtest") {
2600 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2602 sample_times.push_back(benchmark_connectblock_slow());
2603 } else if (benchmarktype == "sendtoaddress") {
2604 if (Params().NetworkIDString() != "regtest") {
2605 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2607 auto amount = AmountFromValue(params[2]);
2608 sample_times.push_back(benchmark_sendtoaddress(amount));
2609 } else if (benchmarktype == "loadwallet") {
2610 if (Params().NetworkIDString() != "regtest") {
2611 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2613 sample_times.push_back(benchmark_loadwallet());
2614 } else if (benchmarktype == "listunspent") {
2615 sample_times.push_back(benchmark_listunspent());
2617 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2621 UniValue results(UniValue::VARR);
2622 for (auto time : sample_times) {
2623 UniValue result(UniValue::VOBJ);
2624 result.push_back(Pair("runningtime", time));
2625 results.push_back(result);
2631 UniValue zc_raw_receive(const UniValue& params, bool fHelp)
2633 if (!EnsureWalletIsAvailable(fHelp)) {
2634 return NullUniValue;
2637 if (fHelp || params.size() != 2) {
2638 throw runtime_error(
2639 "zcrawreceive zcsecretkey encryptednote\n"
2641 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
2642 "are in the blockchain as indicated by the \"exists\" result.\n"
2645 " \"amount\": value,\n"
2646 " \"note\": noteplaintext,\n"
2647 " \"exists\": exists\n"
2652 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
2656 CZCSpendingKey spendingkey(params[0].get_str());
2657 SpendingKey k = spendingkey.Get();
2660 unsigned char nonce;
2661 ZCNoteEncryption::Ciphertext ct;
2665 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
2671 } catch(const std::exception &) {
2672 throw runtime_error(
2673 "encrypted_note could not be decoded"
2678 ZCNoteDecryption decryptor(k.receiving_key());
2680 NotePlaintext npt = NotePlaintext::decrypt(
2687 PaymentAddress payment_addr = k.address();
2688 Note decrypted_note = npt.note(payment_addr);
2690 assert(pwalletMain != NULL);
2691 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2693 uint256 commitment = decrypted_note.cm();
2694 pwalletMain->WitnessNoteCommitment(
2700 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2703 UniValue result(UniValue::VOBJ);
2704 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
2705 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2706 result.push_back(Pair("exists", (bool) witnesses[0]));
2712 UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
2714 if (!EnsureWalletIsAvailable(fHelp)) {
2715 return NullUniValue;
2718 if (fHelp || params.size() != 5) {
2719 throw runtime_error(
2720 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
2721 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
2722 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
2724 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
2725 "Outputs are confidential between sender/receiver. The vpub_old and\n"
2726 "vpub_new values are globally public and move transparent value into\n"
2727 "or out of the confidential value store, respectively.\n"
2729 "Note: The caller is responsible for delivering the output enc1 and\n"
2730 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
2731 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
2732 "payments in-band on the blockchain.)\n"
2735 " \"encryptednote1\": enc1,\n"
2736 " \"encryptednote2\": enc2,\n"
2737 " \"rawtxn\": rawtxout\n"
2745 if (!DecodeHexTx(tx, params[0].get_str()))
2746 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2748 UniValue inputs = params[1].get_obj();
2749 UniValue outputs = params[2].get_obj();
2751 CAmount vpub_old(0);
2752 CAmount vpub_new(0);
2754 if (params[3].get_real() != 0.0)
2755 vpub_old = AmountFromValue(params[3]);
2757 if (params[4].get_real() != 0.0)
2758 vpub_new = AmountFromValue(params[4]);
2760 std::vector<JSInput> vjsin;
2761 std::vector<JSOutput> vjsout;
2762 std::vector<Note> notes;
2763 std::vector<SpendingKey> keys;
2764 std::vector<uint256> commitments;
2766 for (const string& name_ : inputs.getKeys()) {
2767 CZCSpendingKey spendingkey(inputs[name_].get_str());
2768 SpendingKey k = spendingkey.Get();
2775 CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
2779 PaymentAddress addr = k.address();
2780 Note note = npt.note(addr);
2781 notes.push_back(note);
2782 commitments.push_back(note.cm());
2786 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2787 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
2789 assert(witnesses.size() == notes.size());
2790 assert(notes.size() == keys.size());
2793 for (size_t i = 0; i < witnesses.size(); i++) {
2794 if (!witnesses[i]) {
2795 throw runtime_error(
2796 "joinsplit input could not be found in tree"
2800 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
2804 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
2805 vjsin.push_back(JSInput());
2808 for (const string& name_ : outputs.getKeys()) {
2809 CZCPaymentAddress pubaddr(name_);
2810 PaymentAddress addrTo = pubaddr.Get();
2811 CAmount nAmount = AmountFromValue(outputs[name_]);
2813 vjsout.push_back(JSOutput(addrTo, nAmount));
2816 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
2817 vjsout.push_back(JSOutput());
2821 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
2822 throw runtime_error("unsupported joinsplit input/output counts");
2825 uint256 joinSplitPubKey;
2826 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
2827 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
2829 CMutableTransaction mtx(tx);
2831 mtx.joinSplitPubKey = joinSplitPubKey;
2833 JSDescription jsdesc(*pzcashParams,
2836 {vjsin[0], vjsin[1]},
2837 {vjsout[0], vjsout[1]},
2842 auto verifier = libzcash::ProofVerifier::Strict();
2843 assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
2846 mtx.vjoinsplit.push_back(jsdesc);
2848 // Empty output script.
2850 CTransaction signTx(mtx);
2851 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
2852 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
2854 // Add the signature
2855 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
2856 dataToBeSigned.begin(), 32,
2861 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
2862 dataToBeSigned.begin(), 32,
2863 mtx.joinSplitPubKey.begin()
2866 CTransaction rawTx(mtx);
2868 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2871 std::string encryptedNote1;
2872 std::string encryptedNote2;
2874 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2875 ss2 << ((unsigned char) 0x00);
2876 ss2 << jsdesc.ephemeralKey;
2877 ss2 << jsdesc.ciphertexts[0];
2878 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
2880 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
2883 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2884 ss2 << ((unsigned char) 0x01);
2885 ss2 << jsdesc.ephemeralKey;
2886 ss2 << jsdesc.ciphertexts[1];
2887 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
2889 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
2892 UniValue result(UniValue::VOBJ);
2893 result.push_back(Pair("encryptednote1", encryptedNote1));
2894 result.push_back(Pair("encryptednote2", encryptedNote2));
2895 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
2899 UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
2901 if (!EnsureWalletIsAvailable(fHelp)) {
2902 return NullUniValue;
2905 if (fHelp || params.size() != 0) {
2906 throw runtime_error(
2909 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
2912 " \"zcaddress\": zcaddr,\n"
2913 " \"zcsecretkey\": zcsecretkey,\n"
2914 " \"zcviewingkey\": zcviewingkey,\n"
2919 auto k = SpendingKey::random();
2920 auto addr = k.address();
2921 auto viewing_key = k.viewing_key();
2923 CZCPaymentAddress pubaddr(addr);
2924 CZCSpendingKey spendingkey(k);
2925 CZCViewingKey viewingkey(viewing_key);
2927 UniValue result(UniValue::VOBJ);
2928 result.push_back(Pair("zcaddress", pubaddr.ToString()));
2929 result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
2930 result.push_back(Pair("zcviewingkey", viewingkey.ToString()));
2935 UniValue z_getnewaddress(const UniValue& params, bool fHelp)
2937 if (!EnsureWalletIsAvailable(fHelp))
2938 return NullUniValue;
2940 if (fHelp || params.size() > 0)
2941 throw runtime_error(
2943 "\nReturns a new zaddr for receiving payments.\n"
2946 "\"zcashaddress\" (string) The new zaddr\n"
2948 + HelpExampleCli("z_getnewaddress", "")
2949 + HelpExampleRpc("z_getnewaddress", "")
2952 LOCK2(cs_main, pwalletMain->cs_wallet);
2954 EnsureWalletIsUnlocked();
2956 CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
2957 std::string result = pubaddr.ToString();
2962 UniValue z_listaddresses(const UniValue& params, bool fHelp)
2964 if (!EnsureWalletIsAvailable(fHelp))
2965 return NullUniValue;
2967 if (fHelp || params.size() > 1)
2968 throw runtime_error(
2969 "z_listaddresses ( includeWatchonly )\n"
2970 "\nReturns the list of zaddr belonging to the wallet.\n"
2972 "1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
2974 "[ (json array of string)\n"
2975 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
2979 + HelpExampleCli("z_listaddresses", "")
2980 + HelpExampleRpc("z_listaddresses", "")
2983 LOCK2(cs_main, pwalletMain->cs_wallet);
2985 bool fIncludeWatchonly = false;
2986 if (params.size() > 0) {
2987 fIncludeWatchonly = params[0].get_bool();
2990 UniValue ret(UniValue::VARR);
2991 std::set<libzcash::PaymentAddress> addresses;
2992 pwalletMain->GetPaymentAddresses(addresses);
2993 for (auto addr : addresses ) {
2994 if (fIncludeWatchonly || pwalletMain->HaveSpendingKey(addr)) {
2995 ret.push_back(CZCPaymentAddress(addr).ToString());
3001 CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ignoreUnspendable=true) {
3002 set<CBitcoinAddress> setAddress;
3003 vector<COutput> vecOutputs;
3004 CAmount balance = 0;
3006 if (transparentAddress.length() > 0) {
3007 CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
3008 if (!taddr.IsValid()) {
3009 throw std::runtime_error("invalid transparent address");
3011 setAddress.insert(taddr);
3014 LOCK2(cs_main, pwalletMain->cs_wallet);
3016 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
3018 BOOST_FOREACH(const COutput& out, vecOutputs) {
3019 if (out.nDepth < minDepth) {
3023 if (ignoreUnspendable && !out.fSpendable) {
3027 if (setAddress.size()) {
3028 CTxDestination address;
3029 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3033 if (!setAddress.count(address)) {
3038 CAmount nValue = out.tx->vout[out.i].nValue;
3044 CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
3045 CAmount balance = 0;
3046 std::vector<CNotePlaintextEntry> entries;
3047 LOCK2(cs_main, pwalletMain->cs_wallet);
3048 pwalletMain->GetFilteredNotes(entries, address, minDepth, true, ignoreUnspendable);
3049 for (auto & entry : entries) {
3050 balance += CAmount(entry.plaintext.value);
3056 UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
3058 if (!EnsureWalletIsAvailable(fHelp))
3059 return NullUniValue;
3061 if (fHelp || params.size()==0 || params.size() >2)
3062 throw runtime_error(
3063 "z_listreceivedbyaddress \"address\" ( minconf )\n"
3064 "\nReturn a list of amounts received by a zaddr belonging to the node’s wallet.\n"
3066 "1. \"address\" (string) The private address.\n"
3067 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3070 " \"txid\": xxxxx, (string) the transaction id\n"
3071 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
3072 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
3075 + HelpExampleCli("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3076 + HelpExampleRpc("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3079 LOCK2(cs_main, pwalletMain->cs_wallet);
3082 if (params.size() > 1) {
3083 nMinDepth = params[1].get_int();
3085 if (nMinDepth < 0) {
3086 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3089 // Check that the from address is valid.
3090 auto fromaddress = params[0].get_str();
3092 libzcash::PaymentAddress zaddr;
3093 CZCPaymentAddress address(fromaddress);
3095 zaddr = address.Get();
3096 } catch (const std::runtime_error&) {
3097 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
3100 if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
3101 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
3105 UniValue result(UniValue::VARR);
3106 std::vector<CNotePlaintextEntry> entries;
3107 pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false, false);
3108 for (CNotePlaintextEntry & entry : entries) {
3109 UniValue obj(UniValue::VOBJ);
3110 obj.push_back(Pair("txid",entry.jsop.hash.ToString()));
3111 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value))));
3112 std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
3113 obj.push_back(Pair("memo", HexStr(data)));
3114 result.push_back(obj);
3120 UniValue z_getbalance(const UniValue& params, bool fHelp)
3122 if (!EnsureWalletIsAvailable(fHelp))
3123 return NullUniValue;
3125 if (fHelp || params.size()==0 || params.size() >2)
3126 throw runtime_error(
3127 "z_getbalance \"address\" ( minconf )\n"
3128 "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
3129 "\nCAUTION: If address is a watch-only zaddr, the returned balance may be larger than the actual balance,"
3130 "\nbecause spends cannot be detected with incoming viewing keys.\n"
3132 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
3133 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3135 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this address.\n"
3137 "\nThe total amount received by address \"myaddress\"\n"
3138 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
3139 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
3140 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
3141 "\nAs a json rpc call\n"
3142 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
3145 LOCK2(cs_main, pwalletMain->cs_wallet);
3148 if (params.size() > 1) {
3149 nMinDepth = params[1].get_int();
3151 if (nMinDepth < 0) {
3152 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3155 // Check that the from address is valid.
3156 auto fromaddress = params[0].get_str();
3157 bool fromTaddr = false;
3158 CBitcoinAddress taddr(fromaddress);
3159 fromTaddr = taddr.IsValid();
3160 libzcash::PaymentAddress zaddr;
3162 CZCPaymentAddress address(fromaddress);
3164 zaddr = address.Get();
3165 } catch (const std::runtime_error&) {
3166 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3168 if (!(pwalletMain->HaveSpendingKey(zaddr) || pwalletMain->HaveViewingKey(zaddr))) {
3169 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
3173 CAmount nBalance = 0;
3175 nBalance = getBalanceTaddr(fromaddress, nMinDepth, false);
3177 nBalance = getBalanceZaddr(fromaddress, nMinDepth, false);
3180 return ValueFromAmount(nBalance);
3184 UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
3186 if (!EnsureWalletIsAvailable(fHelp))
3187 return NullUniValue;
3189 if (fHelp || params.size() > 2)
3190 throw runtime_error(
3191 "z_gettotalbalance ( minconf includeWatchonly )\n"
3192 "\nReturn the total value of funds stored in the node’s wallet.\n"
3193 "\nCAUTION: If the wallet contains watch-only zaddrs, the returned private balance may be larger than the actual balance,"
3194 "\nbecause spends cannot be detected with incoming viewing keys.\n"
3196 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
3197 "2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n"
3200 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
3201 " \"private\": xxxxx, (numeric) the total balance of private funds\n"
3202 " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
3205 "\nThe total amount in the wallet\n"
3206 + HelpExampleCli("z_gettotalbalance", "") +
3207 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3208 + HelpExampleCli("z_gettotalbalance", "5") +
3209 "\nAs a json rpc call\n"
3210 + HelpExampleRpc("z_gettotalbalance", "5")
3213 LOCK2(cs_main, pwalletMain->cs_wallet);
3216 if (params.size() > 0) {
3217 nMinDepth = params[0].get_int();
3219 if (nMinDepth < 0) {
3220 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3223 bool fIncludeWatchonly = false;
3224 if (params.size() > 1) {
3225 fIncludeWatchonly = params[1].get_bool();
3228 // getbalance and "getbalance * 1 true" should return the same number
3229 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
3230 // pwalletMain->GetBalance() does not accept min depth parameter
3231 // so we use our own method to get balance of utxos.
3232 CAmount nBalance = getBalanceTaddr("", nMinDepth, !fIncludeWatchonly);
3233 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, !fIncludeWatchonly);
3234 CAmount nTotalBalance = nBalance + nPrivateBalance;
3235 UniValue result(UniValue::VOBJ);
3236 result.push_back(Pair("transparent", FormatMoney(nBalance)));
3237 result.push_back(Pair("private", FormatMoney(nPrivateBalance)));
3238 result.push_back(Pair("total", FormatMoney(nTotalBalance)));
3242 UniValue z_getoperationresult(const UniValue& params, bool fHelp)
3244 if (!EnsureWalletIsAvailable(fHelp))
3245 return NullUniValue;
3247 if (fHelp || params.size() > 1)
3248 throw runtime_error(
3249 "z_getoperationresult ([\"operationid\", ... ]) \n"
3250 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3251 + HelpRequiringPassphrase() + "\n"
3253 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3255 "\" [object, ...]\" (array) A list of JSON objects\n"
3257 + HelpExampleCli("z_getoperationresult", "'[\"operationid\", ... ]'")
3258 + HelpExampleRpc("z_getoperationresult", "'[\"operationid\", ... ]'")
3261 // This call will remove finished operations
3262 return z_getoperationstatus_IMPL(params, true);
3265 UniValue z_getoperationstatus(const UniValue& params, bool fHelp)
3267 if (!EnsureWalletIsAvailable(fHelp))
3268 return NullUniValue;
3270 if (fHelp || params.size() > 1)
3271 throw runtime_error(
3272 "z_getoperationstatus ([\"operationid\", ... ]) \n"
3273 "\nGet operation status and any associated result or error data. The operation will remain in memory."
3274 + HelpRequiringPassphrase() + "\n"
3276 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3278 "\" [object, ...]\" (array) A list of JSON objects\n"
3280 + HelpExampleCli("z_getoperationstatus", "'[\"operationid\", ... ]'")
3281 + HelpExampleRpc("z_getoperationstatus", "'[\"operationid\", ... ]'")
3284 // This call is idempotent so we don't want to remove finished operations
3285 return z_getoperationstatus_IMPL(params, false);
3288 UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedOperations=false)
3290 LOCK2(cs_main, pwalletMain->cs_wallet);
3292 std::set<AsyncRPCOperationId> filter;
3293 if (params.size()==1) {
3294 UniValue ids = params[0].get_array();
3295 for (const UniValue & v : ids.getValues()) {
3296 filter.insert(v.get_str());
3299 bool useFilter = (filter.size()>0);
3301 UniValue ret(UniValue::VARR);
3302 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3303 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3305 for (auto id : ids) {
3306 if (useFilter && !filter.count(id))
3309 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3312 // It's possible that the operation was removed from the internal queue and map during this loop
3313 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3316 UniValue obj = operation->getStatus();
3317 std::string s = obj["status"].get_str();
3318 if (fRemoveFinishedOperations) {
3319 // Caller is only interested in retrieving finished results
3320 if ("success"==s || "failed"==s || "cancelled"==s) {
3322 q->popOperationForId(id);
3329 std::vector<UniValue> arrTmp = ret.getValues();
3331 // sort results chronologically by creation_time
3332 std::sort(arrTmp.begin(), arrTmp.end(), [](UniValue a, UniValue b) -> bool {
3333 const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
3334 const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
3340 ret.push_backV(arrTmp);
3346 // Here we define the maximum number of zaddr outputs that can be included in a transaction.
3347 // If input notes are small, we might actually require more than one joinsplit per zaddr output.
3348 // For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
3349 // We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
3350 #define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1)
3352 // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
3353 #define CTXIN_SPEND_DUST_SIZE 148
3354 #define CTXOUT_REGULAR_SIZE 34
3356 UniValue z_sendmany(const UniValue& params, bool fHelp)
3358 if (!EnsureWalletIsAvailable(fHelp))
3359 return NullUniValue;
3361 if (fHelp || params.size() < 2 || params.size() > 4)
3362 throw runtime_error(
3363 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
3364 "\nSend multiple times. Amounts are double-precision floating point numbers."
3365 "\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
3366 "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
3367 + strprintf("\nCurrently, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS)
3368 + HelpRequiringPassphrase() + "\n"
3370 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
3371 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
3373 " \"address\":address (string, required) The address is a taddr or zaddr\n"
3374 " \"amount\":amount (numeric, required) The numeric amount in " + CURRENCY_UNIT + " is the value\n"
3375 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3377 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
3378 "4. fee (numeric, optional, default="
3379 + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3381 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3383 + HelpExampleCli("z_sendmany", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" '[{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]'")
3384 + HelpExampleRpc("z_sendmany", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", [{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]")
3387 LOCK2(cs_main, pwalletMain->cs_wallet);
3389 // Check that the from address is valid.
3390 auto fromaddress = params[0].get_str();
3391 bool fromTaddr = false;
3392 CBitcoinAddress taddr(fromaddress);
3393 fromTaddr = taddr.IsValid();
3394 libzcash::PaymentAddress zaddr;
3396 CZCPaymentAddress address(fromaddress);
3398 zaddr = address.Get();
3399 } catch (const std::runtime_error&) {
3401 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3405 // Check that we have the spending key
3407 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3408 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3412 UniValue outputs = params[1].get_array();
3414 if (outputs.size()==0)
3415 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3417 // Keep track of addresses to spot duplicates
3418 set<std::string> setAddress;
3421 std::vector<SendManyRecipient> taddrRecipients;
3422 std::vector<SendManyRecipient> zaddrRecipients;
3423 CAmount nTotalOut = 0;
3425 for (const UniValue& o : outputs.getValues()) {
3427 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
3429 // sanity check, report error if unknown key-value pairs
3430 for (const string& name_ : o.getKeys()) {
3431 std::string s = name_;
3432 if (s != "address" && s != "amount" && s!="memo")
3433 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3436 string address = find_value(o, "address").get_str();
3437 bool isZaddr = false;
3438 CBitcoinAddress taddr(address);
3439 if (!taddr.IsValid()) {
3441 CZCPaymentAddress zaddr(address);
3444 } catch (const std::runtime_error&) {
3445 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3449 if (setAddress.count(address))
3450 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3451 setAddress.insert(address);
3453 UniValue memoValue = find_value(o, "memo");
3455 if (!memoValue.isNull()) {
3456 memo = memoValue.get_str();
3458 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo cannot be used with a taddr. It can only be used with a zaddr.");
3459 } else if (!IsHex(memo)) {
3460 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3462 if (memo.length() > ZC_MEMO_SIZE*2) {
3463 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3467 UniValue av = find_value(o, "amount");
3468 CAmount nAmount = AmountFromValue( av );
3470 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3473 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3475 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3478 nTotalOut += nAmount;
3481 // Check the number of zaddr outputs does not exceed the limit.
3482 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS) {
3483 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
3486 // As a sanity check, estimate and verify that the size of the transaction will be valid.
3487 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
3489 CMutableTransaction mtx;
3491 for (int i = 0; i < zaddrRecipients.size(); i++) {
3492 mtx.vjoinsplit.push_back(JSDescription());
3494 CTransaction tx(mtx);
3495 txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
3497 txsize += CTXIN_SPEND_DUST_SIZE;
3498 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
3500 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
3501 if (txsize > MAX_TX_SIZE) {
3502 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", MAX_TX_SIZE ));
3505 // Minimum confirmations
3507 if (params.size() > 2) {
3508 nMinDepth = params[2].get_int();
3510 if (nMinDepth < 0) {
3511 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3514 // Fee in Zatoshis, not currency format)
3515 CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
3516 if (params.size() > 3) {
3517 if (params[3].get_real() == 0.0) {
3520 nFee = AmountFromValue( params[3] );
3523 // Check that the user specified fee is sane.
3524 if (nFee > nTotalOut) {
3525 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s", FormatMoney(nFee), FormatMoney(nTotalOut)));
3529 // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
3530 UniValue o(UniValue::VOBJ);
3531 o.push_back(Pair("fromaddress", params[0]));
3532 o.push_back(Pair("amounts", params[1]));
3533 o.push_back(Pair("minconf", nMinDepth));
3534 o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
3535 UniValue contextInfo = o;
3537 // Contextual transaction we will build on
3538 int nextBlockHeight = chainActive.Height() + 1;
3539 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
3540 bool isShielded = !fromTaddr || zaddrRecipients.size() > 0;
3541 if (contextualTx.nVersion == 1 && isShielded) {
3542 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
3544 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
3545 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
3548 // Create operation and add to global queue
3549 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3550 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(contextualTx, fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
3551 q->addOperation(operation);
3552 AsyncRPCOperationId operationId = operation->getId();
3558 When estimating the number of coinbase utxos we can shield in a single transaction:
3559 1. Joinsplit description is 1802 bytes.
3560 2. Transaction overhead ~ 100 bytes
3561 3. Spending a typical P2PKH is >=148 bytes, as defined in CTXIN_SPEND_DUST_SIZE.
3562 4. Spending a multi-sig P2SH address can vary greatly:
3563 https://github.com/bitcoin/bitcoin/blob/c3ad56f4e0b587d8d763af03d743fdfc2d180c9b/src/main.cpp#L517
3564 In real-world coinbase utxos, we consider a 3-of-3 multisig, where the size is roughly:
3565 (3*(33+1))+3 = 105 byte redeem script
3566 105 + 1 + 3*(73+1) = 328 bytes of scriptSig, rounded up to 400 based on testnet experiments.
3568 #define CTXIN_SPEND_P2SH_SIZE 400
3570 #define SHIELD_COINBASE_DEFAULT_LIMIT 50
3572 UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
3574 if (!EnsureWalletIsAvailable(fHelp))
3575 return NullUniValue;
3577 if (fHelp || params.size() < 2 || params.size() > 4)
3578 throw runtime_error(
3579 "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee ) ( limit )\n"
3580 "\nShield transparent coinbase funds by sending to a shielded zaddr. This is an asynchronous operation and utxos"
3581 "\nselected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent`"
3582 "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding can be limited"
3583 "\nby the caller. If the limit parameter is set to zero, the -mempooltxinputlimit option will determine the number"
3584 "\nof uxtos. Any limit is constrained by the consensus rule defining a maximum transaction size of "
3585 + strprintf("%d bytes.", MAX_TX_SIZE)
3586 + HelpRequiringPassphrase() + "\n"
3588 "1. \"fromaddress\" (string, required) The address is a taddr or \"*\" for all taddrs belonging to the wallet.\n"
3589 "2. \"toaddress\" (string, required) The address is a zaddr.\n"
3590 "3. fee (numeric, optional, default="
3591 + strprintf("%s", FormatMoney(SHIELD_COINBASE_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3592 "4. limit (numeric, optional, default="
3593 + strprintf("%d", SHIELD_COINBASE_DEFAULT_LIMIT) + ") Limit on the maximum number of utxos to shield. Set to 0 to use node option -mempooltxinputlimit.\n"
3596 " \"remainingUTXOs\": xxx (numeric) Number of coinbase utxos still available for shielding.\n"
3597 " \"remainingValue\": xxx (numeric) Value of coinbase utxos still available for shielding.\n"
3598 " \"shieldingUTXOs\": xxx (numeric) Number of coinbase utxos being shielded.\n"
3599 " \"shieldingValue\": xxx (numeric) Value of coinbase utxos being shielded.\n"
3600 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3603 + HelpExampleCli("z_shieldcoinbase", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3604 + HelpExampleRpc("z_shieldcoinbase", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3607 LOCK2(cs_main, pwalletMain->cs_wallet);
3609 // Validate the from address
3610 auto fromaddress = params[0].get_str();
3611 bool isFromWildcard = fromaddress == "*";
3612 CBitcoinAddress taddr;
3613 if (!isFromWildcard) {
3614 taddr = CBitcoinAddress(fromaddress);
3615 if (!taddr.IsValid()) {
3616 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
3620 // Validate the destination address
3621 auto destaddress = params[1].get_str();
3623 CZCPaymentAddress pa(destaddress);
3624 libzcash::PaymentAddress zaddr = pa.Get();
3625 } catch (const std::runtime_error&) {
3626 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
3629 // Convert fee from currency format to zatoshis
3630 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
3631 if (params.size() > 2) {
3632 if (params[2].get_real() == 0.0) {
3635 nFee = AmountFromValue( params[2] );
3639 int nLimit = SHIELD_COINBASE_DEFAULT_LIMIT;
3640 if (params.size() > 3) {
3641 nLimit = params[3].get_int();
3643 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of utxos cannot be negative");
3647 // Prepare to get coinbase utxos
3648 std::vector<ShieldCoinbaseUTXO> inputs;
3649 CAmount shieldedValue = 0;
3650 CAmount remainingValue = 0;
3651 size_t estimatedTxSize = 2000; // 1802 joinsplit description + tx overhead + wiggle room
3652 size_t utxoCounter = 0;
3653 bool maxedOutFlag = false;
3654 size_t mempoolLimit = (nLimit != 0) ? nLimit : (size_t)GetArg("-mempooltxinputlimit", 0);
3656 // Set of addresses to filter utxos by
3657 set<CBitcoinAddress> setAddress = {};
3658 if (!isFromWildcard) {
3659 setAddress.insert(taddr);
3662 // Get available utxos
3663 vector<COutput> vecOutputs;
3664 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true);
3666 // Find unspent coinbase utxos and update estimated size
3667 BOOST_FOREACH(const COutput& out, vecOutputs) {
3668 if (!out.fSpendable) {
3672 CTxDestination address;
3673 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3676 // If taddr is not wildcard "*", filter utxos
3677 if (setAddress.size()>0 && !setAddress.count(address)) {
3681 if (!out.tx->IsCoinBase()) {
3686 CAmount nValue = out.tx->vout[out.i].nValue;
3688 if (!maxedOutFlag) {
3689 CBitcoinAddress ba(address);
3690 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
3691 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
3692 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
3694 maxedOutFlag = true;
3696 estimatedTxSize += increase;
3697 ShieldCoinbaseUTXO utxo = {out.tx->GetHash(), out.i, nValue};
3698 inputs.push_back(utxo);
3699 shieldedValue += nValue;
3704 remainingValue += nValue;
3708 size_t numUtxos = inputs.size();
3710 if (numUtxos == 0) {
3711 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any coinbase funds to shield.");
3714 if (shieldedValue < nFee) {
3715 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
3716 strprintf("Insufficient coinbase funds, have %s, which is less than miners fee %s",
3717 FormatMoney(shieldedValue), FormatMoney(nFee)));
3720 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
3721 CAmount netAmount = shieldedValue - nFee;
3722 if (nFee > netAmount) {
3723 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
3726 // Keep record of parameters in context object
3727 UniValue contextInfo(UniValue::VOBJ);
3728 contextInfo.push_back(Pair("fromaddress", params[0]));
3729 contextInfo.push_back(Pair("toaddress", params[1]));
3730 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
3732 // Contextual transaction we will build on
3733 int nextBlockHeight = chainActive.Height() + 1;
3734 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
3735 Params().GetConsensus(), nextBlockHeight);
3736 if (contextualTx.nVersion == 1) {
3737 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
3739 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
3740 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
3743 // Create operation and add to global queue
3744 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3745 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(contextualTx, inputs, destaddress, nFee, contextInfo) );
3746 q->addOperation(operation);
3747 AsyncRPCOperationId operationId = operation->getId();
3749 // Return continuation information
3750 UniValue o(UniValue::VOBJ);
3751 o.push_back(Pair("remainingUTXOs", static_cast<uint64_t>(utxoCounter - numUtxos)));
3752 o.push_back(Pair("remainingValue", ValueFromAmount(remainingValue)));
3753 o.push_back(Pair("shieldingUTXOs", static_cast<uint64_t>(numUtxos)));
3754 o.push_back(Pair("shieldingValue", ValueFromAmount(shieldedValue)));
3755 o.push_back(Pair("opid", operationId));
3760 #define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50
3761 #define MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT 10
3763 #define JOINSPLIT_SIZE JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)
3765 UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
3767 if (!EnsureWalletIsAvailable(fHelp))
3768 return NullUniValue;
3770 auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-zmergetoaddress", false);
3771 std::string strDisabledMsg = "";
3772 if (!fEnableMergeToAddress) {
3773 strDisabledMsg = "\nWARNING: z_mergetoaddress is DISABLED but can be enabled as an experimental feature.\n";
3776 if (fHelp || params.size() < 2 || params.size() > 6)
3777 throw runtime_error(
3778 "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n"
3780 "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`"
3781 "\nto combine those into a single note."
3782 "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they"
3783 "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs."
3784 "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit"
3785 "\nparameter is set to zero, the -mempooltxinputlimit option will determine the number of UTXOs. Any limit is"
3786 "\nconstrained by the consensus rule defining a maximum transaction size of "
3787 + strprintf("%d bytes.", MAX_TX_SIZE)
3788 + HelpRequiringPassphrase() + "\n"
3790 "1. fromaddresses (string, required) A JSON array with addresses.\n"
3791 " The following special strings are accepted inside the array:\n"
3792 " - \"*\": Merge both UTXOs and notes from all addresses belonging to the wallet.\n"
3793 " - \"ANY_TADDR\": Merge UTXOs from all t-addrs belonging to the wallet.\n"
3794 " - \"ANY_ZADDR\": Merge notes from all z-addrs belonging to the wallet.\n"
3795 " If a special string is given, any given addresses of that type will be ignored.\n"
3797 " \"address\" (string) Can be a t-addr or a z-addr\n"
3800 "2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n"
3801 "3. fee (numeric, optional, default="
3802 + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3803 "4. transparent_limit (numeric, optional, default="
3804 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit.\n"
3805 "4. shielded_limit (numeric, optional, default="
3806 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n"
3807 "5. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n"
3810 " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n"
3811 " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n"
3812 " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n"
3813 " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n"
3814 " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n"
3815 " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n"
3816 " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n"
3817 " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n"
3818 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3821 + HelpExampleCli("z_mergetoaddress", "'[\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf")
3822 + HelpExampleRpc("z_mergetoaddress", "[\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3825 if (!fEnableMergeToAddress) {
3826 throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled.");
3829 LOCK2(cs_main, pwalletMain->cs_wallet);
3831 bool useAny = false;
3832 bool useAnyUTXO = false;
3833 bool useAnyNote = false;
3834 std::set<CBitcoinAddress> taddrs = {};
3835 std::set<libzcash::PaymentAddress> zaddrs = {};
3837 UniValue addresses = params[0].get_array();
3838 if (addresses.size()==0)
3839 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty.");
3841 // Keep track of addresses to spot duplicates
3842 std::set<std::string> setAddress;
3845 for (const UniValue& o : addresses.getValues()) {
3847 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
3849 std::string address = o.get_str();
3850 if (address == "*") {
3852 } else if (address == "ANY_TADDR") {
3854 } else if (address == "ANY_ZADDR") {
3857 CBitcoinAddress taddr(address);
3858 if (taddr.IsValid()) {
3859 // Ignore any listed t-addrs if we are using all of them
3860 if (!(useAny || useAnyUTXO)) {
3861 taddrs.insert(taddr);
3865 CZCPaymentAddress zaddr(address);
3866 // Ignore listed z-addrs if we are using all of them
3867 if (!(useAny || useAnyNote)) {
3868 zaddrs.insert(zaddr.Get());
3870 } catch (const std::runtime_error&) {
3872 RPC_INVALID_PARAMETER,
3873 string("Invalid parameter, unknown address format: ") + address);
3878 if (setAddress.count(address))
3879 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
3880 setAddress.insert(address);
3883 // Validate the destination address
3884 auto destaddress = params[1].get_str();
3885 bool isToZaddr = false;
3886 CBitcoinAddress taddr(destaddress);
3887 if (!taddr.IsValid()) {
3889 CZCPaymentAddress zaddr(destaddress);
3892 } catch (const std::runtime_error&) {
3893 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
3897 // Convert fee from currency format to zatoshis
3898 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
3899 if (params.size() > 2) {
3900 if (params[2].get_real() == 0.0) {
3903 nFee = AmountFromValue( params[2] );
3907 int nUTXOLimit = MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT;
3908 if (params.size() > 3) {
3909 nUTXOLimit = params[3].get_int();
3910 if (nUTXOLimit < 0) {
3911 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of UTXOs cannot be negative");
3915 int nNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT;
3916 if (params.size() > 4) {
3917 nNoteLimit = params[4].get_int();
3918 if (nNoteLimit < 0) {
3919 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative");
3924 if (params.size() > 5) {
3925 memo = params[5].get_str();
3927 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
3928 } else if (!IsHex(memo)) {
3929 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3931 if (memo.length() > ZC_MEMO_SIZE*2) {
3932 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3936 MergeToAddressRecipient recipient(destaddress, memo);
3938 // Prepare to get UTXOs and notes
3939 std::vector<MergeToAddressInputUTXO> utxoInputs;
3940 std::vector<MergeToAddressInputNote> noteInputs;
3941 CAmount mergedUTXOValue = 0;
3942 CAmount mergedNoteValue = 0;
3943 CAmount remainingUTXOValue = 0;
3944 CAmount remainingNoteValue = 0;
3945 size_t utxoCounter = 0;
3946 size_t noteCounter = 0;
3947 bool maxedOutUTXOsFlag = false;
3948 bool maxedOutNotesFlag = false;
3949 size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (size_t)GetArg("-mempooltxinputlimit", 0);
3951 size_t estimatedTxSize = 200; // tx overhead + wiggle room
3953 estimatedTxSize += JOINSPLIT_SIZE;
3956 if (useAny || useAnyUTXO || taddrs.size() > 0) {
3957 // Get available utxos
3958 vector<COutput> vecOutputs;
3959 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false);
3961 // Find unspent utxos and update estimated size
3962 for (const COutput& out : vecOutputs) {
3963 if (!out.fSpendable) {
3967 CTxDestination address;
3968 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3971 // If taddr is not wildcard "*", filter utxos
3972 if (taddrs.size() > 0 && !taddrs.count(address)) {
3977 CAmount nValue = out.tx->vout[out.i].nValue;
3979 if (!maxedOutUTXOsFlag) {
3980 CBitcoinAddress ba(address);
3981 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
3982 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
3983 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
3985 maxedOutUTXOsFlag = true;
3987 estimatedTxSize += increase;
3988 COutPoint utxo(out.tx->GetHash(), out.i);
3989 utxoInputs.emplace_back(utxo, nValue);
3990 mergedUTXOValue += nValue;
3994 if (maxedOutUTXOsFlag) {
3995 remainingUTXOValue += nValue;
4000 if (useAny || useAnyNote || zaddrs.size() > 0) {
4001 // Get available notes
4002 std::vector<CNotePlaintextEntry> entries;
4003 pwalletMain->GetFilteredNotes(entries, zaddrs);
4005 // Find unspent notes and update estimated size
4006 for (CNotePlaintextEntry& entry : entries) {
4008 CAmount nValue = entry.plaintext.value;
4010 if (!maxedOutNotesFlag) {
4011 // If we haven't added any notes yet and the merge is to a
4012 // z-address, we have already accounted for the first JoinSplit.
4013 size_t increase = (noteInputs.empty() && !isToZaddr) || (noteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0;
4014 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
4015 (nNoteLimit > 0 && noteCounter > nNoteLimit))
4017 maxedOutNotesFlag = true;
4019 estimatedTxSize += increase;
4021 pwalletMain->GetSpendingKey(entry.address, zkey);
4022 noteInputs.emplace_back(entry.jsop, entry.plaintext.note(entry.address), nValue, zkey);
4023 mergedNoteValue += nValue;
4027 if (maxedOutNotesFlag) {
4028 remainingNoteValue += nValue;
4033 size_t numUtxos = utxoInputs.size();
4034 size_t numNotes = noteInputs.size();
4036 if (numUtxos == 0 && numNotes == 0) {
4037 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge.");
4040 // Sanity check: Don't do anything if:
4041 // - We only have one from address
4042 // - It's equal to toaddress
4043 // - The address only contains a single UTXO or note
4044 if (setAddress.size() == 1 && setAddress.count(destaddress) && (numUtxos + numNotes) == 1) {
4045 throw JSONRPCError(RPC_INVALID_PARAMETER, "Destination address is also the only source address, and all its funds are already merged.");
4048 CAmount mergedValue = mergedUTXOValue + mergedNoteValue;
4049 if (mergedValue < nFee) {
4050 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
4051 strprintf("Insufficient funds, have %s, which is less than miners fee %s",
4052 FormatMoney(mergedValue), FormatMoney(nFee)));
4055 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
4056 CAmount netAmount = mergedValue - nFee;
4057 if (nFee > netAmount) {
4058 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
4061 // Keep record of parameters in context object
4062 UniValue contextInfo(UniValue::VOBJ);
4063 contextInfo.push_back(Pair("fromaddresses", params[0]));
4064 contextInfo.push_back(Pair("toaddress", params[1]));
4065 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
4067 // Contextual transaction we will build on
4068 int nextBlockHeight = chainActive.Height() + 1;
4069 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
4070 Params().GetConsensus(),
4072 bool isShielded = numNotes > 0 || isToZaddr;
4073 if (contextualTx.nVersion == 1 && isShielded) {
4074 contextualTx.nVersion = 2; // Tx format should support vjoinsplit
4076 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
4077 contextualTx.nExpiryHeight = nextBlockHeight + expiryDelta;
4080 // Create operation and add to global queue
4081 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4082 std::shared_ptr<AsyncRPCOperation> operation(
4083 new AsyncRPCOperation_mergetoaddress(contextualTx, utxoInputs, noteInputs, recipient, nFee, contextInfo) );
4084 q->addOperation(operation);
4085 AsyncRPCOperationId operationId = operation->getId();
4087 // Return continuation information
4088 UniValue o(UniValue::VOBJ);
4089 o.push_back(Pair("remainingUTXOs", static_cast<uint64_t>(utxoCounter - numUtxos)));
4090 o.push_back(Pair("remainingTransparentValue", ValueFromAmount(remainingUTXOValue)));
4091 o.push_back(Pair("remainingNotes", static_cast<uint64_t>(noteCounter - numNotes)));
4092 o.push_back(Pair("remainingShieldedValue", ValueFromAmount(remainingNoteValue)));
4093 o.push_back(Pair("mergingUTXOs", static_cast<uint64_t>(numUtxos)));
4094 o.push_back(Pair("mergingTransparentValue", ValueFromAmount(mergedUTXOValue)));
4095 o.push_back(Pair("mergingNotes", static_cast<uint64_t>(numNotes)));
4096 o.push_back(Pair("mergingShieldedValue", ValueFromAmount(mergedNoteValue)));
4097 o.push_back(Pair("opid", operationId));
4102 UniValue z_listoperationids(const UniValue& params, bool fHelp)
4104 if (!EnsureWalletIsAvailable(fHelp))
4105 return NullUniValue;
4107 if (fHelp || params.size() > 1)
4108 throw runtime_error(
4109 "z_listoperationids\n"
4110 "\nReturns the list of operation ids currently known to the wallet.\n"
4112 "1. \"status\" (string, optional) Filter result by the operation's state e.g. \"success\".\n"
4114 "[ (json array of string)\n"
4115 " \"operationid\" (string) an operation id belonging to the wallet\n"
4119 + HelpExampleCli("z_listoperationids", "")
4120 + HelpExampleRpc("z_listoperationids", "")
4123 LOCK2(cs_main, pwalletMain->cs_wallet);
4126 bool useFilter = false;
4127 if (params.size()==1) {
4128 filter = params[0].get_str();
4132 UniValue ret(UniValue::VARR);
4133 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4134 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
4135 for (auto id : ids) {
4136 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
4140 std::string state = operation->getStateAsString();
4141 if (useFilter && filter.compare(state)!=0)