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.
13 #include "rpcserver.h"
16 #include "utilmoneystr.h"
19 #include "primitives/transaction.h"
20 #include "zcbenchmarks.h"
21 #include "script/interpreter.h"
24 #include "asyncrpcoperation.h"
25 #include "asyncrpcqueue.h"
26 #include "wallet/asyncrpcoperation_sendmany.h"
27 #include "wallet/asyncrpcoperation_shieldcoinbase.h"
33 #include <boost/assign/list_of.hpp>
41 using namespace libzcash;
43 extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
45 int64_t nWalletUnlockTime;
46 static CCriticalSection cs_nWalletUnlockTime;
49 UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
51 std::string HelpRequiringPassphrase()
53 return pwalletMain && pwalletMain->IsCrypted()
54 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
58 bool EnsureWalletIsAvailable(bool avoidException)
63 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
70 void EnsureWalletIsUnlocked()
72 if (pwalletMain->IsLocked())
73 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
76 void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
78 int confirms = wtx.GetDepthInMainChain();
79 entry.push_back(Pair("confirmations", confirms));
81 entry.push_back(Pair("generated", true));
84 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
85 entry.push_back(Pair("blockindex", wtx.nIndex));
86 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
88 uint256 hash = wtx.GetHash();
89 entry.push_back(Pair("txid", hash.GetHex()));
90 UniValue conflicts(UniValue::VARR);
91 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
92 conflicts.push_back(conflict.GetHex());
93 entry.push_back(Pair("walletconflicts", conflicts));
94 entry.push_back(Pair("time", wtx.GetTxTime()));
95 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
96 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
97 entry.push_back(Pair(item.first, item.second));
99 entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
102 string AccountFromValue(const UniValue& value)
104 string strAccount = value.get_str();
105 if (strAccount != "")
106 throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
110 UniValue getnewaddress(const UniValue& params, bool fHelp)
112 if (!EnsureWalletIsAvailable(fHelp))
115 if (fHelp || params.size() > 1)
117 "getnewaddress ( \"account\" )\n"
118 "\nReturns a new Zcash address for receiving payments.\n"
120 "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"
122 "\"zcashaddress\" (string) The new Zcash address\n"
124 + HelpExampleCli("getnewaddress", "")
125 + HelpExampleRpc("getnewaddress", "")
128 LOCK2(cs_main, pwalletMain->cs_wallet);
130 // Parse the account first so we don't generate a key if there's an error
132 if (params.size() > 0)
133 strAccount = AccountFromValue(params[0]);
135 if (!pwalletMain->IsLocked())
136 pwalletMain->TopUpKeyPool();
138 // Generate a new key that is added to wallet
140 if (!pwalletMain->GetKeyFromPool(newKey))
141 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
142 CKeyID keyID = newKey.GetID();
144 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
146 return CBitcoinAddress(keyID).ToString();
150 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
152 CWalletDB walletdb(pwalletMain->strWalletFile);
155 walletdb.ReadAccount(strAccount, account);
157 bool bKeyUsed = false;
159 // Check if the current key has been used
160 if (account.vchPubKey.IsValid())
162 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
163 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
164 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
167 const CWalletTx& wtx = (*it).second;
168 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
169 if (txout.scriptPubKey == scriptPubKey)
174 // Generate a new key
175 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
177 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
178 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
180 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
181 walletdb.WriteAccount(strAccount, account);
184 return CBitcoinAddress(account.vchPubKey.GetID());
187 UniValue getaccountaddress(const UniValue& params, bool fHelp)
189 if (!EnsureWalletIsAvailable(fHelp))
192 if (fHelp || params.size() != 1)
194 "getaccountaddress \"account\"\n"
195 "\nDEPRECATED. Returns the current Zcash address for receiving payments to this account.\n"
197 "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"
199 "\"zcashaddress\" (string) The account Zcash address\n"
201 + HelpExampleCli("getaccountaddress", "")
202 + HelpExampleCli("getaccountaddress", "\"\"")
203 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
204 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
207 LOCK2(cs_main, pwalletMain->cs_wallet);
209 // Parse the account first so we don't generate a key if there's an error
210 string strAccount = AccountFromValue(params[0]);
212 UniValue ret(UniValue::VSTR);
214 ret = GetAccountAddress(strAccount).ToString();
219 UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
221 if (!EnsureWalletIsAvailable(fHelp))
224 if (fHelp || params.size() > 1)
226 "getrawchangeaddress\n"
227 "\nReturns a new Zcash address, for receiving change.\n"
228 "This is for use with raw transactions, NOT normal use.\n"
230 "\"address\" (string) The address\n"
232 + HelpExampleCli("getrawchangeaddress", "")
233 + HelpExampleRpc("getrawchangeaddress", "")
236 LOCK2(cs_main, pwalletMain->cs_wallet);
238 if (!pwalletMain->IsLocked())
239 pwalletMain->TopUpKeyPool();
241 CReserveKey reservekey(pwalletMain);
243 if (!reservekey.GetReservedKey(vchPubKey))
244 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
246 reservekey.KeepKey();
248 CKeyID keyID = vchPubKey.GetID();
250 return CBitcoinAddress(keyID).ToString();
254 UniValue setaccount(const UniValue& params, bool fHelp)
256 if (!EnsureWalletIsAvailable(fHelp))
259 if (fHelp || params.size() < 1 || params.size() > 2)
261 "setaccount \"zcashaddress\" \"account\"\n"
262 "\nDEPRECATED. Sets the account associated with the given address.\n"
264 "1. \"zcashaddress\" (string, required) The Zcash address to be associated with an account.\n"
265 "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"
267 + HelpExampleCli("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"tabby\"")
268 + HelpExampleRpc("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"tabby\"")
271 LOCK2(cs_main, pwalletMain->cs_wallet);
273 CBitcoinAddress address(params[0].get_str());
274 if (!address.IsValid())
275 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
278 if (params.size() > 1)
279 strAccount = AccountFromValue(params[1]);
281 // Only add the account if the address is yours.
282 if (IsMine(*pwalletMain, address.Get()))
284 // Detect when changing the account of an address that is the 'unused current key' of another account:
285 if (pwalletMain->mapAddressBook.count(address.Get()))
287 string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
288 if (address == GetAccountAddress(strOldAccount))
289 GetAccountAddress(strOldAccount, true);
291 pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
294 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
300 UniValue getaccount(const UniValue& params, bool fHelp)
302 if (!EnsureWalletIsAvailable(fHelp))
305 if (fHelp || params.size() != 1)
307 "getaccount \"zcashaddress\"\n"
308 "\nDEPRECATED. Returns the account associated with the given address.\n"
310 "1. \"zcashaddress\" (string, required) The Zcash address for account lookup.\n"
312 "\"accountname\" (string) the account address\n"
314 + HelpExampleCli("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
315 + HelpExampleRpc("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
318 LOCK2(cs_main, pwalletMain->cs_wallet);
320 CBitcoinAddress address(params[0].get_str());
321 if (!address.IsValid())
322 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
325 map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
326 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
327 strAccount = (*mi).second.name;
332 UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
334 if (!EnsureWalletIsAvailable(fHelp))
337 if (fHelp || params.size() != 1)
339 "getaddressesbyaccount \"account\"\n"
340 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
342 "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"
344 "[ (json array of string)\n"
345 " \"zcashaddress\" (string) a Zcash address associated with the given account\n"
349 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
350 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
353 LOCK2(cs_main, pwalletMain->cs_wallet);
355 string strAccount = AccountFromValue(params[0]);
357 // Find all addresses that have the given account
358 UniValue ret(UniValue::VARR);
359 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
361 const CBitcoinAddress& address = item.first;
362 const string& strName = item.second.name;
363 if (strName == strAccount)
364 ret.push_back(address.ToString());
369 static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
371 CAmount curBalance = pwalletMain->GetBalance();
375 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
377 if (nValue > curBalance)
378 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
380 // Parse Zcash address
381 CScript scriptPubKey = GetScriptForDestination(address);
383 // Create and send the transaction
384 CReserveKey reservekey(pwalletMain);
385 CAmount nFeeRequired;
386 std::string strError;
387 vector<CRecipient> vecSend;
388 int nChangePosRet = -1;
389 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
390 vecSend.push_back(recipient);
391 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
392 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
393 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));
394 throw JSONRPCError(RPC_WALLET_ERROR, strError);
396 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
397 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.");
400 UniValue sendtoaddress(const UniValue& params, bool fHelp)
402 if (!EnsureWalletIsAvailable(fHelp))
405 if (fHelp || params.size() < 2 || params.size() > 5)
407 "sendtoaddress \"zcashaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
408 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
409 + HelpRequiringPassphrase() +
411 "1. \"zcashaddress\" (string, required) The zcash address to send to.\n"
412 "2. \"amount\" (numeric, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n"
413 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
414 " This is not part of the transaction, just kept in your wallet.\n"
415 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
416 " to which you're sending the transaction. This is not part of the \n"
417 " transaction, just kept in your wallet.\n"
418 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
419 " The recipient will receive less Zcash than you enter in the amount field.\n"
421 "\"transactionid\" (string) The transaction id.\n"
423 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
424 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
425 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
426 + HelpExampleRpc("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
429 LOCK2(cs_main, pwalletMain->cs_wallet);
431 CBitcoinAddress address(params[0].get_str());
432 if (!address.IsValid())
433 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
436 CAmount nAmount = AmountFromValue(params[1]);
438 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
442 if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
443 wtx.mapValue["comment"] = params[2].get_str();
444 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
445 wtx.mapValue["to"] = params[3].get_str();
447 bool fSubtractFeeFromAmount = false;
448 if (params.size() > 4)
449 fSubtractFeeFromAmount = params[4].get_bool();
451 EnsureWalletIsUnlocked();
453 SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
455 return wtx.GetHash().GetHex();
458 UniValue listaddressgroupings(const UniValue& params, bool fHelp)
460 if (!EnsureWalletIsAvailable(fHelp))
465 "listaddressgroupings\n"
466 "\nLists groups of addresses which have had their common ownership\n"
467 "made public by common use as inputs or as the resulting change\n"
468 "in past transactions\n"
473 " \"zcashaddress\", (string) The zcash address\n"
474 " amount, (numeric) The amount in " + CURRENCY_UNIT + "\n"
475 " \"account\" (string, optional) The account (DEPRECATED)\n"
482 + HelpExampleCli("listaddressgroupings", "")
483 + HelpExampleRpc("listaddressgroupings", "")
486 LOCK2(cs_main, pwalletMain->cs_wallet);
488 UniValue jsonGroupings(UniValue::VARR);
489 map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
490 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
492 UniValue jsonGrouping(UniValue::VARR);
493 BOOST_FOREACH(CTxDestination address, grouping)
495 UniValue addressInfo(UniValue::VARR);
496 addressInfo.push_back(CBitcoinAddress(address).ToString());
497 addressInfo.push_back(ValueFromAmount(balances[address]));
499 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
500 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
502 jsonGrouping.push_back(addressInfo);
504 jsonGroupings.push_back(jsonGrouping);
506 return jsonGroupings;
509 UniValue signmessage(const UniValue& params, bool fHelp)
511 if (!EnsureWalletIsAvailable(fHelp))
514 if (fHelp || params.size() != 2)
516 "signmessage \"zcashaddress\" \"message\"\n"
517 "\nSign a message with the private key of an address"
518 + HelpRequiringPassphrase() + "\n"
520 "1. \"zcashaddress\" (string, required) The Zcash address to use for the private key.\n"
521 "2. \"message\" (string, required) The message to create a signature of.\n"
523 "\"signature\" (string) The signature of the message encoded in base 64\n"
525 "\nUnlock the wallet for 30 seconds\n"
526 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
527 "\nCreate the signature\n"
528 + HelpExampleCli("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"my message\"") +
529 "\nVerify the signature\n"
530 + HelpExampleCli("verifymessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"signature\" \"my message\"") +
532 + HelpExampleRpc("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"my message\"")
535 LOCK2(cs_main, pwalletMain->cs_wallet);
537 EnsureWalletIsUnlocked();
539 string strAddress = params[0].get_str();
540 string strMessage = params[1].get_str();
542 CBitcoinAddress addr(strAddress);
544 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
547 if (!addr.GetKeyID(keyID))
548 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
551 if (!pwalletMain->GetKey(keyID, key))
552 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
554 CHashWriter ss(SER_GETHASH, 0);
555 ss << strMessageMagic;
558 vector<unsigned char> vchSig;
559 if (!key.SignCompact(ss.GetHash(), vchSig))
560 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
562 return EncodeBase64(&vchSig[0], vchSig.size());
565 UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
567 if (!EnsureWalletIsAvailable(fHelp))
570 if (fHelp || params.size() < 1 || params.size() > 2)
572 "getreceivedbyaddress \"zcashaddress\" ( minconf )\n"
573 "\nReturns the total amount received by the given Zcash address in transactions with at least minconf confirmations.\n"
575 "1. \"zcashaddress\" (string, required) The Zcash address for transactions.\n"
576 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
578 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n"
580 "\nThe amount from transactions with at least 1 confirmation\n"
581 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"") +
582 "\nThe amount including unconfirmed transactions, zero confirmations\n"
583 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 0") +
584 "\nThe amount with at least 6 confirmation, very safe\n"
585 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 6") +
586 "\nAs a json rpc call\n"
587 + HelpExampleRpc("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", 6")
590 LOCK2(cs_main, pwalletMain->cs_wallet);
593 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
594 if (!address.IsValid())
595 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
596 CScript scriptPubKey = GetScriptForDestination(address.Get());
597 if (!IsMine(*pwalletMain,scriptPubKey))
600 // Minimum confirmations
602 if (params.size() > 1)
603 nMinDepth = params[1].get_int();
607 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
609 const CWalletTx& wtx = (*it).second;
610 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
613 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
614 if (txout.scriptPubKey == scriptPubKey)
615 if (wtx.GetDepthInMainChain() >= nMinDepth)
616 nAmount += txout.nValue;
619 return ValueFromAmount(nAmount);
623 UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
625 if (!EnsureWalletIsAvailable(fHelp))
628 if (fHelp || params.size() < 1 || params.size() > 2)
630 "getreceivedbyaccount \"account\" ( minconf )\n"
631 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
633 "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"
634 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
636 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
638 "\nAmount received by the default account with at least 1 confirmation\n"
639 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
640 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
641 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
642 "\nThe amount with at least 6 confirmation, very safe\n"
643 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
644 "\nAs a json rpc call\n"
645 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
648 LOCK2(cs_main, pwalletMain->cs_wallet);
650 // Minimum confirmations
652 if (params.size() > 1)
653 nMinDepth = params[1].get_int();
655 // Get the set of pub keys assigned to account
656 string strAccount = AccountFromValue(params[0]);
657 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
661 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
663 const CWalletTx& wtx = (*it).second;
664 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
667 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
669 CTxDestination address;
670 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
671 if (wtx.GetDepthInMainChain() >= nMinDepth)
672 nAmount += txout.nValue;
676 return (double)nAmount / (double)COIN;
680 CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
682 CAmount nBalance = 0;
684 // Tally wallet transactions
685 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
687 const CWalletTx& wtx = (*it).second;
688 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
691 CAmount nReceived, nSent, nFee;
692 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
694 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
695 nBalance += nReceived;
696 nBalance -= nSent + nFee;
699 // Tally internal accounting entries
700 nBalance += walletdb.GetAccountCreditDebit(strAccount);
705 CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
707 CWalletDB walletdb(pwalletMain->strWalletFile);
708 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
712 UniValue getbalance(const UniValue& params, bool fHelp)
714 if (!EnsureWalletIsAvailable(fHelp))
717 if (fHelp || params.size() > 3)
719 "getbalance ( \"account\" minconf includeWatchonly )\n"
720 "\nReturns the server's total available balance.\n"
722 "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"
723 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
724 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
726 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
728 "\nThe total amount in the wallet\n"
729 + HelpExampleCli("getbalance", "") +
730 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
731 + HelpExampleCli("getbalance", "\"*\" 6") +
732 "\nAs a json rpc call\n"
733 + HelpExampleRpc("getbalance", "\"*\", 6")
736 LOCK2(cs_main, pwalletMain->cs_wallet);
738 if (params.size() == 0)
739 return ValueFromAmount(pwalletMain->GetBalance());
742 if (params.size() > 1)
743 nMinDepth = params[1].get_int();
744 isminefilter filter = ISMINE_SPENDABLE;
745 if(params.size() > 2)
746 if(params[2].get_bool())
747 filter = filter | ISMINE_WATCH_ONLY;
749 if (params[0].get_str() == "*") {
750 // Calculate total balance a different way from GetBalance()
751 // (GetBalance() sums up all unspent TxOuts)
752 // getbalance and "getbalance * 1 true" should return the same number
753 CAmount nBalance = 0;
754 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
756 const CWalletTx& wtx = (*it).second;
757 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
761 string strSentAccount;
762 list<COutputEntry> listReceived;
763 list<COutputEntry> listSent;
764 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
765 if (wtx.GetDepthInMainChain() >= nMinDepth)
767 BOOST_FOREACH(const COutputEntry& r, listReceived)
768 nBalance += r.amount;
770 BOOST_FOREACH(const COutputEntry& s, listSent)
771 nBalance -= s.amount;
774 return ValueFromAmount(nBalance);
777 string strAccount = AccountFromValue(params[0]);
779 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
781 return ValueFromAmount(nBalance);
784 UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp)
786 if (!EnsureWalletIsAvailable(fHelp))
789 if (fHelp || params.size() > 0)
791 "getunconfirmedbalance\n"
792 "Returns the server's total unconfirmed balance\n");
794 LOCK2(cs_main, pwalletMain->cs_wallet);
796 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
800 UniValue movecmd(const UniValue& params, bool fHelp)
802 if (!EnsureWalletIsAvailable(fHelp))
805 if (fHelp || params.size() < 3 || params.size() > 5)
807 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
808 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
810 "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"
811 "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"
812 "3. amount (numeric) Quantity of " + CURRENCY_UNIT + " to move between accounts.\n"
813 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
814 "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
816 "true|false (boolean) true if successful.\n"
818 "\nMove 0.01 " + CURRENCY_UNIT + " from the default account to the account named tabby\n"
819 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
820 "\nMove 0.01 " + CURRENCY_UNIT + " timotei to akiko with a comment and funds have 6 confirmations\n"
821 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
822 "\nAs a json rpc call\n"
823 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
826 LOCK2(cs_main, pwalletMain->cs_wallet);
828 string strFrom = AccountFromValue(params[0]);
829 string strTo = AccountFromValue(params[1]);
830 CAmount nAmount = AmountFromValue(params[2]);
832 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
833 if (params.size() > 3)
834 // unused parameter, used to be nMinDepth, keep type-checking it though
835 (void)params[3].get_int();
837 if (params.size() > 4)
838 strComment = params[4].get_str();
840 CWalletDB walletdb(pwalletMain->strWalletFile);
841 if (!walletdb.TxnBegin())
842 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
844 int64_t nNow = GetAdjustedTime();
847 CAccountingEntry debit;
848 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
849 debit.strAccount = strFrom;
850 debit.nCreditDebit = -nAmount;
852 debit.strOtherAccount = strTo;
853 debit.strComment = strComment;
854 walletdb.WriteAccountingEntry(debit);
857 CAccountingEntry credit;
858 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
859 credit.strAccount = strTo;
860 credit.nCreditDebit = nAmount;
862 credit.strOtherAccount = strFrom;
863 credit.strComment = strComment;
864 walletdb.WriteAccountingEntry(credit);
866 if (!walletdb.TxnCommit())
867 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
873 UniValue sendfrom(const UniValue& params, bool fHelp)
875 if (!EnsureWalletIsAvailable(fHelp))
878 if (fHelp || params.size() < 3 || params.size() > 6)
880 "sendfrom \"fromaccount\" \"tozcashaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
881 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a Zcash address.\n"
882 "The amount is a real and is rounded to the nearest 0.00000001."
883 + HelpRequiringPassphrase() + "\n"
885 "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"
886 "2. \"tozcashaddress\" (string, required) The zcash address to send funds to.\n"
887 "3. amount (numeric, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n"
888 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
889 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
890 " This is not part of the transaction, just kept in your wallet.\n"
891 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
892 " to which you're sending the transaction. This is not part of the transaction, \n"
893 " it is just kept in your wallet.\n"
895 "\"transactionid\" (string) The transaction id.\n"
897 "\nSend 0.01 " + CURRENCY_UNIT + " from the default account to the address, must have at least 1 confirmation\n"
898 + HelpExampleCli("sendfrom", "\"\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
899 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
900 + HelpExampleCli("sendfrom", "\"tabby\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
901 "\nAs a json rpc call\n"
902 + HelpExampleRpc("sendfrom", "\"tabby\", \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
905 LOCK2(cs_main, pwalletMain->cs_wallet);
907 string strAccount = AccountFromValue(params[0]);
908 CBitcoinAddress address(params[1].get_str());
909 if (!address.IsValid())
910 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
911 CAmount nAmount = AmountFromValue(params[2]);
913 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
915 if (params.size() > 3)
916 nMinDepth = params[3].get_int();
919 wtx.strFromAccount = strAccount;
920 if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
921 wtx.mapValue["comment"] = params[4].get_str();
922 if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
923 wtx.mapValue["to"] = params[5].get_str();
925 EnsureWalletIsUnlocked();
928 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
929 if (nAmount > nBalance)
930 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
932 SendMoney(address.Get(), nAmount, false, wtx);
934 return wtx.GetHash().GetHex();
938 UniValue sendmany(const UniValue& params, bool fHelp)
940 if (!EnsureWalletIsAvailable(fHelp))
943 if (fHelp || params.size() < 2 || params.size() > 5)
945 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
946 "\nSend multiple times. Amounts are double-precision floating point numbers."
947 + HelpRequiringPassphrase() + "\n"
949 "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"
950 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
952 " \"address\":amount (numeric) The zcash address is the key, the numeric amount in " + CURRENCY_UNIT + " is the value\n"
955 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
956 "4. \"comment\" (string, optional) A comment\n"
957 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
958 " The fee will be equally deducted from the amount of each selected address.\n"
959 " Those recipients will receive less Zcash than you enter in their corresponding amount field.\n"
960 " If no addresses are specified here, the sender pays the fee.\n"
962 " \"address\" (string) Subtract fee from this address\n"
966 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
967 " the number of addresses.\n"
969 "\nSend two amounts to two different addresses:\n"
970 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
971 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
972 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
973 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
974 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\",\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
975 "\nAs a json rpc call\n"
976 + HelpExampleRpc("sendmany", "\"\", \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
979 LOCK2(cs_main, pwalletMain->cs_wallet);
981 string strAccount = AccountFromValue(params[0]);
982 UniValue sendTo = params[1].get_obj();
984 if (params.size() > 2)
985 nMinDepth = params[2].get_int();
988 wtx.strFromAccount = strAccount;
989 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
990 wtx.mapValue["comment"] = params[3].get_str();
992 UniValue subtractFeeFromAmount(UniValue::VARR);
993 if (params.size() > 4)
994 subtractFeeFromAmount = params[4].get_array();
996 set<CBitcoinAddress> setAddress;
997 vector<CRecipient> vecSend;
999 CAmount totalAmount = 0;
1000 vector<string> keys = sendTo.getKeys();
1001 BOOST_FOREACH(const string& name_, keys)
1003 CBitcoinAddress address(name_);
1004 if (!address.IsValid())
1005 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+name_);
1007 if (setAddress.count(address))
1008 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
1009 setAddress.insert(address);
1011 CScript scriptPubKey = GetScriptForDestination(address.Get());
1012 CAmount nAmount = AmountFromValue(sendTo[name_]);
1014 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1015 totalAmount += nAmount;
1017 bool fSubtractFeeFromAmount = false;
1018 for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
1019 const UniValue& addr = subtractFeeFromAmount[idx];
1020 if (addr.get_str() == name_)
1021 fSubtractFeeFromAmount = true;
1024 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1025 vecSend.push_back(recipient);
1028 EnsureWalletIsUnlocked();
1031 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1032 if (totalAmount > nBalance)
1033 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1036 CReserveKey keyChange(pwalletMain);
1037 CAmount nFeeRequired = 0;
1038 int nChangePosRet = -1;
1039 string strFailReason;
1040 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
1042 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
1043 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1044 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
1046 return wtx.GetHash().GetHex();
1049 // Defined in rpcmisc.cpp
1050 extern CScript _createmultisig_redeemScript(const UniValue& params);
1052 UniValue addmultisigaddress(const UniValue& params, bool fHelp)
1054 if (!EnsureWalletIsAvailable(fHelp))
1055 return NullUniValue;
1057 if (fHelp || params.size() < 2 || params.size() > 3)
1059 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1060 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1061 "Each key is a Zcash address or hex-encoded public key.\n"
1062 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
1065 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1066 "2. \"keysobject\" (string, required) A json array of Zcash addresses or hex-encoded public keys\n"
1068 " \"address\" (string) Zcash address or hex-encoded public key\n"
1071 "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"
1074 "\"zcashaddress\" (string) A Zcash address associated with the keys.\n"
1077 "\nAdd a multisig address from 2 addresses\n"
1078 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
1079 "\nAs json rpc call\n"
1080 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
1082 throw runtime_error(msg);
1085 LOCK2(cs_main, pwalletMain->cs_wallet);
1088 if (params.size() > 2)
1089 strAccount = AccountFromValue(params[2]);
1091 // Construct using pay-to-script-hash:
1092 CScript inner = _createmultisig_redeemScript(params);
1093 CScriptID innerID(inner);
1094 pwalletMain->AddCScript(inner);
1096 pwalletMain->SetAddressBook(innerID, strAccount, "send");
1097 return CBitcoinAddress(innerID).ToString();
1105 vector<uint256> txids;
1110 nConf = std::numeric_limits<int>::max();
1111 fIsWatchonly = false;
1115 UniValue ListReceived(const UniValue& params, bool fByAccounts)
1117 // Minimum confirmations
1119 if (params.size() > 0)
1120 nMinDepth = params[0].get_int();
1122 // Whether to include empty accounts
1123 bool fIncludeEmpty = false;
1124 if (params.size() > 1)
1125 fIncludeEmpty = params[1].get_bool();
1127 isminefilter filter = ISMINE_SPENDABLE;
1128 if(params.size() > 2)
1129 if(params[2].get_bool())
1130 filter = filter | ISMINE_WATCH_ONLY;
1133 map<CBitcoinAddress, tallyitem> mapTally;
1134 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1136 const CWalletTx& wtx = (*it).second;
1138 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
1141 int nDepth = wtx.GetDepthInMainChain();
1142 if (nDepth < nMinDepth)
1145 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1147 CTxDestination address;
1148 if (!ExtractDestination(txout.scriptPubKey, address))
1151 isminefilter mine = IsMine(*pwalletMain, address);
1152 if(!(mine & filter))
1155 tallyitem& item = mapTally[address];
1156 item.nAmount += txout.nValue;
1157 item.nConf = min(item.nConf, nDepth);
1158 item.txids.push_back(wtx.GetHash());
1159 if (mine & ISMINE_WATCH_ONLY)
1160 item.fIsWatchonly = true;
1165 UniValue ret(UniValue::VARR);
1166 map<string, tallyitem> mapAccountTally;
1167 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
1169 const CBitcoinAddress& address = item.first;
1170 const string& strAccount = item.second.name;
1171 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1172 if (it == mapTally.end() && !fIncludeEmpty)
1175 CAmount nAmount = 0;
1176 int nConf = std::numeric_limits<int>::max();
1177 bool fIsWatchonly = false;
1178 if (it != mapTally.end())
1180 nAmount = (*it).second.nAmount;
1181 nConf = (*it).second.nConf;
1182 fIsWatchonly = (*it).second.fIsWatchonly;
1187 tallyitem& item = mapAccountTally[strAccount];
1188 item.nAmount += nAmount;
1189 item.nConf = min(item.nConf, nConf);
1190 item.fIsWatchonly = fIsWatchonly;
1194 UniValue obj(UniValue::VOBJ);
1196 obj.push_back(Pair("involvesWatchonly", true));
1197 obj.push_back(Pair("address", address.ToString()));
1198 obj.push_back(Pair("account", strAccount));
1199 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1200 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1201 UniValue transactions(UniValue::VARR);
1202 if (it != mapTally.end())
1204 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1206 transactions.push_back(item.GetHex());
1209 obj.push_back(Pair("txids", transactions));
1216 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1218 CAmount nAmount = (*it).second.nAmount;
1219 int nConf = (*it).second.nConf;
1220 UniValue obj(UniValue::VOBJ);
1221 if((*it).second.fIsWatchonly)
1222 obj.push_back(Pair("involvesWatchonly", true));
1223 obj.push_back(Pair("account", (*it).first));
1224 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1225 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1233 UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
1235 if (!EnsureWalletIsAvailable(fHelp))
1236 return NullUniValue;
1238 if (fHelp || params.size() > 3)
1239 throw runtime_error(
1240 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
1241 "\nList balances by receiving address.\n"
1243 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1244 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
1245 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1250 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1251 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
1252 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
1253 " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n"
1254 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1260 + HelpExampleCli("listreceivedbyaddress", "")
1261 + HelpExampleCli("listreceivedbyaddress", "6 true")
1262 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1265 LOCK2(cs_main, pwalletMain->cs_wallet);
1267 return ListReceived(params, false);
1270 UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
1272 if (!EnsureWalletIsAvailable(fHelp))
1273 return NullUniValue;
1275 if (fHelp || params.size() > 3)
1276 throw runtime_error(
1277 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
1278 "\nDEPRECATED. List balances by account.\n"
1280 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1281 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
1282 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1287 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1288 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1289 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1290 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1296 + HelpExampleCli("listreceivedbyaccount", "")
1297 + HelpExampleCli("listreceivedbyaccount", "6 true")
1298 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
1301 LOCK2(cs_main, pwalletMain->cs_wallet);
1303 return ListReceived(params, true);
1306 static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
1308 CBitcoinAddress addr;
1310 entry.push_back(Pair("address", addr.ToString()));
1313 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
1316 string strSentAccount;
1317 list<COutputEntry> listReceived;
1318 list<COutputEntry> listSent;
1320 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
1322 bool fAllAccounts = (strAccount == string("*"));
1323 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
1326 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1328 BOOST_FOREACH(const COutputEntry& s, listSent)
1330 UniValue entry(UniValue::VOBJ);
1331 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
1332 entry.push_back(Pair("involvesWatchonly", true));
1333 entry.push_back(Pair("account", strSentAccount));
1334 MaybePushAddress(entry, s.destination);
1335 entry.push_back(Pair("category", "send"));
1336 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1337 entry.push_back(Pair("vout", s.vout));
1338 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1340 WalletTxToJSON(wtx, entry);
1341 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1342 ret.push_back(entry);
1347 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1349 BOOST_FOREACH(const COutputEntry& r, listReceived)
1352 if (pwalletMain->mapAddressBook.count(r.destination))
1353 account = pwalletMain->mapAddressBook[r.destination].name;
1354 if (fAllAccounts || (account == strAccount))
1356 UniValue entry(UniValue::VOBJ);
1357 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
1358 entry.push_back(Pair("involvesWatchonly", true));
1359 entry.push_back(Pair("account", account));
1360 MaybePushAddress(entry, r.destination);
1361 if (wtx.IsCoinBase())
1363 if (wtx.GetDepthInMainChain() < 1)
1364 entry.push_back(Pair("category", "orphan"));
1365 else if (wtx.GetBlocksToMaturity() > 0)
1366 entry.push_back(Pair("category", "immature"));
1368 entry.push_back(Pair("category", "generate"));
1372 entry.push_back(Pair("category", "receive"));
1374 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1375 entry.push_back(Pair("vout", r.vout));
1377 WalletTxToJSON(wtx, entry);
1378 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1379 ret.push_back(entry);
1385 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
1387 bool fAllAccounts = (strAccount == string("*"));
1389 if (fAllAccounts || acentry.strAccount == strAccount)
1391 UniValue entry(UniValue::VOBJ);
1392 entry.push_back(Pair("account", acentry.strAccount));
1393 entry.push_back(Pair("category", "move"));
1394 entry.push_back(Pair("time", acentry.nTime));
1395 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1396 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1397 entry.push_back(Pair("comment", acentry.strComment));
1398 ret.push_back(entry);
1402 UniValue listtransactions(const UniValue& params, bool fHelp)
1404 if (!EnsureWalletIsAvailable(fHelp))
1405 return NullUniValue;
1407 if (fHelp || params.size() > 4)
1408 throw runtime_error(
1409 "listtransactions ( \"account\" count from includeWatchonly)\n"
1410 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1412 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
1413 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1414 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
1415 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
1419 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
1420 " It will be \"\" for the default account.\n"
1421 " \"address\":\"zcashaddress\", (string) The Zcash address of the transaction. Not present for \n"
1422 " move transactions (category = move).\n"
1423 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1424 " transaction between accounts, and not associated with an address,\n"
1425 " transaction id or block. 'send' and 'receive' transactions are \n"
1426 " associated with an address, transaction id and block details\n"
1427 " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the\n"
1428 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1429 " and for the 'move' category for inbound funds.\n"
1430 " \"vout\" : n, (numeric) the vout value\n"
1431 " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
1432 " 'send' category of transactions.\n"
1433 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1434 " 'receive' category of transactions.\n"
1435 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1436 " category of transactions.\n"
1437 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1438 " category of transactions.\n"
1439 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1440 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1441 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1442 " for 'send' and 'receive' category of transactions.\n"
1443 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1444 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1445 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1446 " negative amounts).\n"
1447 " \"size\": n, (numeric) Transaction size in bytes\n"
1452 "\nList the most recent 10 transactions in the systems\n"
1453 + HelpExampleCli("listtransactions", "") +
1454 "\nList transactions 100 to 120\n"
1455 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
1456 "\nAs a json rpc call\n"
1457 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
1460 LOCK2(cs_main, pwalletMain->cs_wallet);
1462 string strAccount = "*";
1463 if (params.size() > 0)
1464 strAccount = params[0].get_str();
1466 if (params.size() > 1)
1467 nCount = params[1].get_int();
1469 if (params.size() > 2)
1470 nFrom = params[2].get_int();
1471 isminefilter filter = ISMINE_SPENDABLE;
1472 if(params.size() > 3)
1473 if(params[3].get_bool())
1474 filter = filter | ISMINE_WATCH_ONLY;
1477 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1479 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1481 UniValue ret(UniValue::VARR);
1483 std::list<CAccountingEntry> acentries;
1484 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1486 // iterate backwards until we have nCount items to return:
1487 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1489 CWalletTx *const pwtx = (*it).second.first;
1491 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1492 CAccountingEntry *const pacentry = (*it).second.second;
1494 AcentryToJSON(*pacentry, strAccount, ret);
1496 if ((int)ret.size() >= (nCount+nFrom)) break;
1498 // ret is newest to oldest
1500 if (nFrom > (int)ret.size())
1502 if ((nFrom + nCount) > (int)ret.size())
1503 nCount = ret.size() - nFrom;
1505 vector<UniValue> arrTmp = ret.getValues();
1507 vector<UniValue>::iterator first = arrTmp.begin();
1508 std::advance(first, nFrom);
1509 vector<UniValue>::iterator last = arrTmp.begin();
1510 std::advance(last, nFrom+nCount);
1512 if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
1513 if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
1515 std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
1519 ret.push_backV(arrTmp);
1524 UniValue listaccounts(const UniValue& params, bool fHelp)
1526 if (!EnsureWalletIsAvailable(fHelp))
1527 return NullUniValue;
1529 if (fHelp || params.size() > 2)
1530 throw runtime_error(
1531 "listaccounts ( minconf includeWatchonly)\n"
1532 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
1534 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
1535 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
1537 "{ (json object where keys are account names, and values are numeric balances\n"
1538 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1542 "\nList account balances where there at least 1 confirmation\n"
1543 + HelpExampleCli("listaccounts", "") +
1544 "\nList account balances including zero confirmation transactions\n"
1545 + HelpExampleCli("listaccounts", "0") +
1546 "\nList account balances for 6 or more confirmations\n"
1547 + HelpExampleCli("listaccounts", "6") +
1548 "\nAs json rpc call\n"
1549 + HelpExampleRpc("listaccounts", "6")
1552 LOCK2(cs_main, pwalletMain->cs_wallet);
1555 if (params.size() > 0)
1556 nMinDepth = params[0].get_int();
1557 isminefilter includeWatchonly = ISMINE_SPENDABLE;
1558 if(params.size() > 1)
1559 if(params[1].get_bool())
1560 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
1562 map<string, CAmount> mapAccountBalances;
1563 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
1564 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
1565 mapAccountBalances[entry.second.name] = 0;
1568 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1570 const CWalletTx& wtx = (*it).second;
1572 string strSentAccount;
1573 list<COutputEntry> listReceived;
1574 list<COutputEntry> listSent;
1575 int nDepth = wtx.GetDepthInMainChain();
1576 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
1578 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1579 mapAccountBalances[strSentAccount] -= nFee;
1580 BOOST_FOREACH(const COutputEntry& s, listSent)
1581 mapAccountBalances[strSentAccount] -= s.amount;
1582 if (nDepth >= nMinDepth)
1584 BOOST_FOREACH(const COutputEntry& r, listReceived)
1585 if (pwalletMain->mapAddressBook.count(r.destination))
1586 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
1588 mapAccountBalances[""] += r.amount;
1592 list<CAccountingEntry> acentries;
1593 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1594 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1595 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1597 UniValue ret(UniValue::VOBJ);
1598 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
1599 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1604 UniValue listsinceblock(const UniValue& params, bool fHelp)
1606 if (!EnsureWalletIsAvailable(fHelp))
1607 return NullUniValue;
1610 throw runtime_error(
1611 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
1612 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1614 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1615 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
1616 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
1619 " \"transactions\": [\n"
1620 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
1621 " \"address\":\"zcashaddress\", (string) The Zcash address of the transaction. Not present for move transactions (category = move).\n"
1622 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1623 " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
1624 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1625 " \"vout\" : n, (numeric) the vout value\n"
1626 " \"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"
1627 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1628 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1629 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1630 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1631 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1632 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1633 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1634 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1635 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1637 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1640 + HelpExampleCli("listsinceblock", "")
1641 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1642 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1645 LOCK2(cs_main, pwalletMain->cs_wallet);
1647 CBlockIndex *pindex = NULL;
1648 int target_confirms = 1;
1649 isminefilter filter = ISMINE_SPENDABLE;
1651 if (params.size() > 0)
1655 blockId.SetHex(params[0].get_str());
1656 BlockMap::iterator it = mapBlockIndex.find(blockId);
1657 if (it != mapBlockIndex.end())
1658 pindex = it->second;
1661 if (params.size() > 1)
1663 target_confirms = params[1].get_int();
1665 if (target_confirms < 1)
1666 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1669 if(params.size() > 2)
1670 if(params[2].get_bool())
1671 filter = filter | ISMINE_WATCH_ONLY;
1673 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
1675 UniValue transactions(UniValue::VARR);
1677 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1679 CWalletTx tx = (*it).second;
1681 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1682 ListTransactions(tx, "*", 0, true, transactions, filter);
1685 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
1686 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
1688 UniValue ret(UniValue::VOBJ);
1689 ret.push_back(Pair("transactions", transactions));
1690 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1695 UniValue gettransaction(const UniValue& params, bool fHelp)
1697 if (!EnsureWalletIsAvailable(fHelp))
1698 return NullUniValue;
1700 if (fHelp || params.size() < 1 || params.size() > 2)
1701 throw runtime_error(
1702 "gettransaction \"txid\" ( includeWatchonly )\n"
1703 "\nGet detailed information about in-wallet transaction <txid>\n"
1705 "1. \"txid\" (string, required) The transaction id\n"
1706 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
1709 " \"amount\" : x.xxx, (numeric) The transaction amount in " + CURRENCY_UNIT + "\n"
1710 " \"confirmations\" : n, (numeric) The number of confirmations\n"
1711 " \"blockhash\" : \"hash\", (string) The block hash\n"
1712 " \"blockindex\" : xx, (numeric) The block index\n"
1713 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
1714 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
1715 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1716 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1717 " \"details\" : [\n"
1719 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
1720 " \"address\" : \"zcashaddress\", (string) The Zcash address involved in the transaction\n"
1721 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
1722 " \"amount\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
1723 " \"vout\" : n, (numeric) the vout value\n"
1727 " \"vjoinsplit\" : [\n"
1729 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
1730 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
1731 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
1732 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
1733 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
1734 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
1738 " \"hex\" : \"data\" (string) Raw data for transaction\n"
1742 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1743 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
1744 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1747 LOCK2(cs_main, pwalletMain->cs_wallet);
1750 hash.SetHex(params[0].get_str());
1752 isminefilter filter = ISMINE_SPENDABLE;
1753 if(params.size() > 1)
1754 if(params[1].get_bool())
1755 filter = filter | ISMINE_WATCH_ONLY;
1757 UniValue entry(UniValue::VOBJ);
1758 if (!pwalletMain->mapWallet.count(hash))
1759 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1760 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1762 CAmount nCredit = wtx.GetCredit(filter);
1763 CAmount nDebit = wtx.GetDebit(filter);
1764 CAmount nNet = nCredit - nDebit;
1765 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1767 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1768 if (wtx.IsFromMe(filter))
1769 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1771 WalletTxToJSON(wtx, entry);
1773 UniValue details(UniValue::VARR);
1774 ListTransactions(wtx, "*", 0, false, details, filter);
1775 entry.push_back(Pair("details", details));
1777 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
1778 entry.push_back(Pair("hex", strHex));
1784 UniValue backupwallet(const UniValue& params, bool fHelp)
1786 if (!EnsureWalletIsAvailable(fHelp))
1787 return NullUniValue;
1789 if (fHelp || params.size() != 1)
1790 throw runtime_error(
1791 "backupwallet \"destination\"\n"
1792 "\nSafely copies wallet.dat to destination filename\n"
1794 "1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
1796 "\"path\" (string) The full path of the destination file\n"
1798 + HelpExampleCli("backupwallet", "\"backupdata\"")
1799 + HelpExampleRpc("backupwallet", "\"backupdata\"")
1802 LOCK2(cs_main, pwalletMain->cs_wallet);
1804 boost::filesystem::path exportdir;
1806 exportdir = GetExportDir();
1807 } catch (const std::runtime_error& e) {
1808 throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
1810 if (exportdir.empty()) {
1811 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
1813 std::string unclean = params[0].get_str();
1814 std::string clean = SanitizeFilename(unclean);
1815 if (clean.compare(unclean) != 0) {
1816 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
1818 boost::filesystem::path exportfilepath = exportdir / clean;
1820 if (!BackupWallet(*pwalletMain, exportfilepath.string()))
1821 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1823 return exportfilepath.string();
1827 UniValue keypoolrefill(const UniValue& params, bool fHelp)
1829 if (!EnsureWalletIsAvailable(fHelp))
1830 return NullUniValue;
1832 if (fHelp || params.size() > 1)
1833 throw runtime_error(
1834 "keypoolrefill ( newsize )\n"
1835 "\nFills the keypool."
1836 + HelpRequiringPassphrase() + "\n"
1838 "1. newsize (numeric, optional, default=100) The new keypool size\n"
1840 + HelpExampleCli("keypoolrefill", "")
1841 + HelpExampleRpc("keypoolrefill", "")
1844 LOCK2(cs_main, pwalletMain->cs_wallet);
1846 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1847 unsigned int kpSize = 0;
1848 if (params.size() > 0) {
1849 if (params[0].get_int() < 0)
1850 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1851 kpSize = (unsigned int)params[0].get_int();
1854 EnsureWalletIsUnlocked();
1855 pwalletMain->TopUpKeyPool(kpSize);
1857 if (pwalletMain->GetKeyPoolSize() < kpSize)
1858 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1860 return NullUniValue;
1864 static void LockWallet(CWallet* pWallet)
1866 LOCK(cs_nWalletUnlockTime);
1867 nWalletUnlockTime = 0;
1871 UniValue walletpassphrase(const UniValue& params, bool fHelp)
1873 if (!EnsureWalletIsAvailable(fHelp))
1874 return NullUniValue;
1876 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1877 throw runtime_error(
1878 "walletpassphrase \"passphrase\" timeout\n"
1879 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
1880 "This is needed prior to performing transactions related to private keys such as sending Zcash\n"
1882 "1. \"passphrase\" (string, required) The wallet passphrase\n"
1883 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
1885 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
1886 "time that overrides the old one.\n"
1888 "\nunlock the wallet for 60 seconds\n"
1889 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1890 "\nLock the wallet again (before 60 seconds)\n"
1891 + HelpExampleCli("walletlock", "") +
1892 "\nAs json rpc call\n"
1893 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1896 LOCK2(cs_main, pwalletMain->cs_wallet);
1900 if (!pwalletMain->IsCrypted())
1901 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1903 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1904 SecureString strWalletPass;
1905 strWalletPass.reserve(100);
1906 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1907 // Alternately, find a way to make params[0] mlock()'d to begin with.
1908 strWalletPass = params[0].get_str().c_str();
1910 if (strWalletPass.length() > 0)
1912 if (!pwalletMain->Unlock(strWalletPass))
1913 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1916 throw runtime_error(
1917 "walletpassphrase <passphrase> <timeout>\n"
1918 "Stores the wallet decryption key in memory for <timeout> seconds.");
1920 // No need to check return values, because the wallet was unlocked above
1921 pwalletMain->UpdateNullifierNoteMap();
1922 pwalletMain->TopUpKeyPool();
1924 int64_t nSleepTime = params[1].get_int64();
1925 LOCK(cs_nWalletUnlockTime);
1926 nWalletUnlockTime = GetTime() + nSleepTime;
1927 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
1929 return NullUniValue;
1933 UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
1935 if (!EnsureWalletIsAvailable(fHelp))
1936 return NullUniValue;
1938 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1939 throw runtime_error(
1940 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
1941 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
1943 "1. \"oldpassphrase\" (string) The current passphrase\n"
1944 "2. \"newpassphrase\" (string) The new passphrase\n"
1946 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
1947 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
1950 LOCK2(cs_main, pwalletMain->cs_wallet);
1954 if (!pwalletMain->IsCrypted())
1955 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1957 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1958 // Alternately, find a way to make params[0] mlock()'d to begin with.
1959 SecureString strOldWalletPass;
1960 strOldWalletPass.reserve(100);
1961 strOldWalletPass = params[0].get_str().c_str();
1963 SecureString strNewWalletPass;
1964 strNewWalletPass.reserve(100);
1965 strNewWalletPass = params[1].get_str().c_str();
1967 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1968 throw runtime_error(
1969 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1970 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1972 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1973 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1975 return NullUniValue;
1979 UniValue walletlock(const UniValue& params, bool fHelp)
1981 if (!EnsureWalletIsAvailable(fHelp))
1982 return NullUniValue;
1984 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1985 throw runtime_error(
1987 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
1988 "After calling this method, you will need to call walletpassphrase again\n"
1989 "before being able to call any methods which require the wallet to be unlocked.\n"
1991 "\nSet the passphrase for 2 minutes to perform a transaction\n"
1992 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
1993 "\nPerform a send (requires passphrase set)\n"
1994 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
1995 "\nClear the passphrase since we are done before 2 minutes is up\n"
1996 + HelpExampleCli("walletlock", "") +
1997 "\nAs json rpc call\n"
1998 + HelpExampleRpc("walletlock", "")
2001 LOCK2(cs_main, pwalletMain->cs_wallet);
2005 if (!pwalletMain->IsCrypted())
2006 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
2009 LOCK(cs_nWalletUnlockTime);
2010 pwalletMain->Lock();
2011 nWalletUnlockTime = 0;
2014 return NullUniValue;
2018 UniValue encryptwallet(const UniValue& params, bool fHelp)
2020 if (!EnsureWalletIsAvailable(fHelp))
2021 return NullUniValue;
2023 auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-developerencryptwallet", false);
2025 std::string strWalletEncryptionDisabledMsg = "";
2026 if (!fEnableWalletEncryption) {
2027 strWalletEncryptionDisabledMsg = "\nWARNING: Wallet encryption is DISABLED. This call always fails.\n";
2030 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2031 throw runtime_error(
2032 "encryptwallet \"passphrase\"\n"
2033 + strWalletEncryptionDisabledMsg +
2034 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2035 "After this, any calls that interact with private keys such as sending or signing \n"
2036 "will require the passphrase to be set prior the making these calls.\n"
2037 "Use the walletpassphrase call for this, and then walletlock call.\n"
2038 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2039 "Note that this will shutdown the server.\n"
2041 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2043 "\nEncrypt you wallet\n"
2044 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
2045 "\nNow set the passphrase to use the wallet, such as for signing or sending Zcash\n"
2046 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2047 "\nNow we can so something like sign\n"
2048 + HelpExampleCli("signmessage", "\"zcashaddress\" \"test message\"") +
2049 "\nNow lock the wallet again by removing the passphrase\n"
2050 + HelpExampleCli("walletlock", "") +
2051 "\nAs a json rpc call\n"
2052 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2055 LOCK2(cs_main, pwalletMain->cs_wallet);
2059 if (!fEnableWalletEncryption) {
2060 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
2062 if (pwalletMain->IsCrypted())
2063 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
2065 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2066 // Alternately, find a way to make params[0] mlock()'d to begin with.
2067 SecureString strWalletPass;
2068 strWalletPass.reserve(100);
2069 strWalletPass = params[0].get_str().c_str();
2071 if (strWalletPass.length() < 1)
2072 throw runtime_error(
2073 "encryptwallet <passphrase>\n"
2074 "Encrypts the wallet with <passphrase>.");
2076 if (!pwalletMain->EncryptWallet(strWalletPass))
2077 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
2079 // BDB seems to have a bad habit of writing old data into
2080 // slack space in .dat files; that is bad if the old data is
2081 // unencrypted private keys. So:
2083 return "wallet encrypted; Zcash server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
2086 UniValue lockunspent(const UniValue& params, bool fHelp)
2088 if (!EnsureWalletIsAvailable(fHelp))
2089 return NullUniValue;
2091 if (fHelp || params.size() < 1 || params.size() > 2)
2092 throw runtime_error(
2093 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2094 "\nUpdates list of temporarily unspendable outputs.\n"
2095 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
2096 "A locked transaction output will not be chosen by automatic coin selection, when spending Zcash.\n"
2097 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2098 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2099 "Also see the listunspent call\n"
2101 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2102 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2103 " [ (json array of json objects)\n"
2105 " \"txid\":\"id\", (string) The transaction id\n"
2106 " \"vout\": n (numeric) The output number\n"
2112 "true|false (boolean) Whether the command was successful or not\n"
2115 "\nList the unspent transactions\n"
2116 + HelpExampleCli("listunspent", "") +
2117 "\nLock an unspent transaction\n"
2118 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2119 "\nList the locked transactions\n"
2120 + HelpExampleCli("listlockunspent", "") +
2121 "\nUnlock the transaction again\n"
2122 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2123 "\nAs a json rpc call\n"
2124 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2127 LOCK2(cs_main, pwalletMain->cs_wallet);
2129 if (params.size() == 1)
2130 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
2132 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
2134 bool fUnlock = params[0].get_bool();
2136 if (params.size() == 1) {
2138 pwalletMain->UnlockAllCoins();
2142 UniValue outputs = params[1].get_array();
2143 for (size_t idx = 0; idx < outputs.size(); idx++) {
2144 const UniValue& output = outputs[idx];
2145 if (!output.isObject())
2146 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
2147 const UniValue& o = output.get_obj();
2149 RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
2151 string txid = find_value(o, "txid").get_str();
2153 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
2155 int nOutput = find_value(o, "vout").get_int();
2157 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
2159 COutPoint outpt(uint256S(txid), nOutput);
2162 pwalletMain->UnlockCoin(outpt);
2164 pwalletMain->LockCoin(outpt);
2170 UniValue listlockunspent(const UniValue& params, bool fHelp)
2172 if (!EnsureWalletIsAvailable(fHelp))
2173 return NullUniValue;
2175 if (fHelp || params.size() > 0)
2176 throw runtime_error(
2178 "\nReturns list of temporarily unspendable outputs.\n"
2179 "See the lockunspent call to lock and unlock transactions for spending.\n"
2183 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2184 " \"vout\" : n (numeric) The vout value\n"
2189 "\nList the unspent transactions\n"
2190 + HelpExampleCli("listunspent", "") +
2191 "\nLock an unspent transaction\n"
2192 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2193 "\nList the locked transactions\n"
2194 + HelpExampleCli("listlockunspent", "") +
2195 "\nUnlock the transaction again\n"
2196 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2197 "\nAs a json rpc call\n"
2198 + HelpExampleRpc("listlockunspent", "")
2201 LOCK2(cs_main, pwalletMain->cs_wallet);
2203 vector<COutPoint> vOutpts;
2204 pwalletMain->ListLockedCoins(vOutpts);
2206 UniValue ret(UniValue::VARR);
2208 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
2209 UniValue o(UniValue::VOBJ);
2211 o.push_back(Pair("txid", outpt.hash.GetHex()));
2212 o.push_back(Pair("vout", (int)outpt.n));
2219 UniValue settxfee(const UniValue& params, bool fHelp)
2221 if (!EnsureWalletIsAvailable(fHelp))
2222 return NullUniValue;
2224 if (fHelp || params.size() < 1 || params.size() > 1)
2225 throw runtime_error(
2227 "\nSet the transaction fee per kB.\n"
2229 "1. amount (numeric, required) The transaction fee in " + CURRENCY_UNIT + "/kB rounded to the nearest 0.00000001\n"
2231 "true|false (boolean) Returns true if successful\n"
2233 + HelpExampleCli("settxfee", "0.00001")
2234 + HelpExampleRpc("settxfee", "0.00001")
2237 LOCK2(cs_main, pwalletMain->cs_wallet);
2240 CAmount nAmount = AmountFromValue(params[0]);
2242 payTxFee = CFeeRate(nAmount, 1000);
2246 UniValue getwalletinfo(const UniValue& params, bool fHelp)
2248 if (!EnsureWalletIsAvailable(fHelp))
2249 return NullUniValue;
2251 if (fHelp || params.size() != 0)
2252 throw runtime_error(
2254 "Returns an object containing various wallet state info.\n"
2257 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
2258 " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2259 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2260 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n"
2261 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2262 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2263 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2264 " \"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"
2265 " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
2268 + HelpExampleCli("getwalletinfo", "")
2269 + HelpExampleRpc("getwalletinfo", "")
2272 LOCK2(cs_main, pwalletMain->cs_wallet);
2274 UniValue obj(UniValue::VOBJ);
2275 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2276 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
2277 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2278 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
2279 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
2280 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
2281 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2282 if (pwalletMain->IsCrypted())
2283 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
2284 obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
2288 UniValue resendwallettransactions(const UniValue& params, bool fHelp)
2290 if (!EnsureWalletIsAvailable(fHelp))
2291 return NullUniValue;
2293 if (fHelp || params.size() != 0)
2294 throw runtime_error(
2295 "resendwallettransactions\n"
2296 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2297 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2299 "Returns array of transaction ids that were re-broadcast.\n"
2302 LOCK2(cs_main, pwalletMain->cs_wallet);
2304 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
2305 UniValue result(UniValue::VARR);
2306 BOOST_FOREACH(const uint256& txid, txids)
2308 result.push_back(txid.ToString());
2313 UniValue listunspent(const UniValue& params, bool fHelp)
2315 if (!EnsureWalletIsAvailable(fHelp))
2316 return NullUniValue;
2318 if (fHelp || params.size() > 3)
2319 throw runtime_error(
2320 "listunspent ( minconf maxconf [\"address\",...] )\n"
2321 "\nReturns array of unspent transaction outputs\n"
2322 "with between minconf and maxconf (inclusive) confirmations.\n"
2323 "Optionally filter to only include txouts paid to specified addresses.\n"
2324 "Results are an array of Objects, each of which has:\n"
2325 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2327 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2328 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
2329 "3. \"addresses\" (string) A json array of Zcash addresses to filter\n"
2331 " \"address\" (string) Zcash address\n"
2335 "[ (array of json object)\n"
2337 " \"txid\" : \"txid\", (string) the transaction id \n"
2338 " \"vout\" : n, (numeric) the vout value\n"
2339 " \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
2340 " \"address\" : \"address\", (string) the zcash address\n"
2341 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2342 " \"scriptPubKey\" : \"key\", (string) the script key\n"
2343 " \"amount\" : x.xxx, (numeric) the transaction amount in " + CURRENCY_UNIT + "\n"
2344 " \"confirmations\" : n (numeric) The number of confirmations\n"
2350 + HelpExampleCli("listunspent", "")
2351 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2352 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2355 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
2358 if (params.size() > 0)
2359 nMinDepth = params[0].get_int();
2361 int nMaxDepth = 9999999;
2362 if (params.size() > 1)
2363 nMaxDepth = params[1].get_int();
2365 set<CBitcoinAddress> setAddress;
2366 if (params.size() > 2) {
2367 UniValue inputs = params[2].get_array();
2368 for (size_t idx = 0; idx < inputs.size(); idx++) {
2369 const UniValue& input = inputs[idx];
2370 CBitcoinAddress address(input.get_str());
2371 if (!address.IsValid())
2372 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+input.get_str());
2373 if (setAddress.count(address))
2374 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2375 setAddress.insert(address);
2379 UniValue results(UniValue::VARR);
2380 vector<COutput> vecOutputs;
2381 assert(pwalletMain != NULL);
2382 LOCK2(cs_main, pwalletMain->cs_wallet);
2383 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2384 BOOST_FOREACH(const COutput& out, vecOutputs) {
2385 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
2388 if (setAddress.size()) {
2389 CTxDestination address;
2390 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
2393 if (!setAddress.count(address))
2397 CAmount nValue = out.tx->vout[out.i].nValue;
2398 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
2399 UniValue entry(UniValue::VOBJ);
2400 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
2401 entry.push_back(Pair("vout", out.i));
2402 entry.push_back(Pair("generated", out.tx->IsCoinBase()));
2403 CTxDestination address;
2404 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2405 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2406 if (pwalletMain->mapAddressBook.count(address))
2407 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
2409 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2410 if (pk.IsPayToScriptHash()) {
2411 CTxDestination address;
2412 if (ExtractDestination(pk, address)) {
2413 const CScriptID& hash = boost::get<CScriptID>(address);
2414 CScript redeemScript;
2415 if (pwalletMain->GetCScript(hash, redeemScript))
2416 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
2419 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
2420 entry.push_back(Pair("confirmations",out.nDepth));
2421 entry.push_back(Pair("spendable", out.fSpendable));
2422 results.push_back(entry);
2428 UniValue fundrawtransaction(const UniValue& params, bool fHelp)
2430 if (!EnsureWalletIsAvailable(fHelp))
2431 return NullUniValue;
2433 if (fHelp || params.size() != 1)
2434 throw runtime_error(
2435 "fundrawtransaction \"hexstring\"\n"
2436 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
2437 "This will not modify existing inputs, and will add one change output to the outputs.\n"
2438 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
2439 "The inputs added will not be signed, use signrawtransaction for that.\n"
2441 "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
2444 " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
2445 " \"fee\": n, (numeric) The fee added to the transaction\n"
2446 " \"changepos\": n (numeric) The position of the added change output, or -1\n"
2450 "\nCreate a transaction with no inputs\n"
2451 + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
2452 "\nAdd sufficient unsigned inputs to meet the output value\n"
2453 + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
2454 "\nSign the transaction\n"
2455 + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
2456 "\nSend the transaction\n"
2457 + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
2460 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
2462 // parse hex string from parameter
2463 CTransaction origTx;
2464 if (!DecodeHexTx(origTx, params[0].get_str()))
2465 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2467 CMutableTransaction tx(origTx);
2469 string strFailReason;
2470 int nChangePos = -1;
2471 if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
2472 throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
2474 UniValue result(UniValue::VOBJ);
2475 result.push_back(Pair("hex", EncodeHexTx(tx)));
2476 result.push_back(Pair("changepos", nChangePos));
2477 result.push_back(Pair("fee", ValueFromAmount(nFee)));
2482 UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
2485 throw runtime_error(
2486 "zcsamplejoinsplit\n"
2488 "Perform a joinsplit and return the JSDescription.\n"
2495 uint256 anchor = ZCIncrementalMerkleTree().root();
2496 JSDescription samplejoinsplit(*pzcashParams,
2499 {JSInput(), JSInput()},
2500 {JSOutput(), JSOutput()},
2504 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2505 ss << samplejoinsplit;
2507 return HexStr(ss.begin(), ss.end());
2510 UniValue zc_benchmark(const UniValue& params, bool fHelp)
2512 if (!EnsureWalletIsAvailable(fHelp)) {
2513 return NullUniValue;
2516 if (fHelp || params.size() < 2) {
2517 throw runtime_error(
2518 "zcbenchmark benchmarktype samplecount\n"
2520 "Runs a benchmark of the selected type samplecount times,\n"
2521 "returning the running times of each sample.\n"
2525 " \"runningtime\": runningtime\n"
2528 " \"runningtime\": runningtime\n"
2537 std::string benchmarktype = params[0].get_str();
2538 int samplecount = params[1].get_int();
2540 if (samplecount <= 0) {
2541 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2544 std::vector<double> sample_times;
2546 JSDescription samplejoinsplit;
2548 if (benchmarktype == "verifyjoinsplit") {
2549 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2550 ss >> samplejoinsplit;
2553 for (int i = 0; i < samplecount; i++) {
2554 if (benchmarktype == "sleep") {
2555 sample_times.push_back(benchmark_sleep());
2556 } else if (benchmarktype == "parameterloading") {
2557 sample_times.push_back(benchmark_parameter_loading());
2558 } else if (benchmarktype == "createjoinsplit") {
2559 if (params.size() < 3) {
2560 sample_times.push_back(benchmark_create_joinsplit());
2562 int nThreads = params[2].get_int();
2563 std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
2564 // Divide by nThreads^2 to get average seconds per JoinSplit because
2565 // we are running one JoinSplit per thread.
2566 sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
2568 } else if (benchmarktype == "verifyjoinsplit") {
2569 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2570 #ifdef ENABLE_MINING
2571 } else if (benchmarktype == "solveequihash") {
2572 if (params.size() < 3) {
2573 sample_times.push_back(benchmark_solve_equihash());
2575 int nThreads = params[2].get_int();
2576 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
2577 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
2580 } else if (benchmarktype == "verifyequihash") {
2581 sample_times.push_back(benchmark_verify_equihash());
2582 } else if (benchmarktype == "validatelargetx") {
2583 sample_times.push_back(benchmark_large_tx());
2584 } else if (benchmarktype == "trydecryptnotes") {
2585 int nAddrs = params[2].get_int();
2586 sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
2587 } else if (benchmarktype == "incnotewitnesses") {
2588 int nTxs = params[2].get_int();
2589 sample_times.push_back(benchmark_increment_note_witnesses(nTxs));
2590 } else if (benchmarktype == "connectblockslow") {
2591 if (Params().NetworkIDString() != "regtest") {
2592 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2594 sample_times.push_back(benchmark_connectblock_slow());
2595 } else if (benchmarktype == "sendtoaddress") {
2596 if (Params().NetworkIDString() != "regtest") {
2597 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2599 auto amount = AmountFromValue(params[2]);
2600 sample_times.push_back(benchmark_sendtoaddress(amount));
2601 } else if (benchmarktype == "loadwallet") {
2602 if (Params().NetworkIDString() != "regtest") {
2603 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2605 sample_times.push_back(benchmark_loadwallet());
2606 } else if (benchmarktype == "listunspent") {
2607 sample_times.push_back(benchmark_listunspent());
2609 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2613 UniValue results(UniValue::VARR);
2614 for (auto time : sample_times) {
2615 UniValue result(UniValue::VOBJ);
2616 result.push_back(Pair("runningtime", time));
2617 results.push_back(result);
2623 UniValue zc_raw_receive(const UniValue& params, bool fHelp)
2625 if (!EnsureWalletIsAvailable(fHelp)) {
2626 return NullUniValue;
2629 if (fHelp || params.size() != 2) {
2630 throw runtime_error(
2631 "zcrawreceive zcsecretkey encryptednote\n"
2633 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
2634 "are in the blockchain as indicated by the \"exists\" result.\n"
2637 " \"amount\": value,\n"
2638 " \"note\": noteplaintext,\n"
2639 " \"exists\": exists\n"
2644 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
2648 CZCSpendingKey spendingkey(params[0].get_str());
2649 SpendingKey k = spendingkey.Get();
2652 unsigned char nonce;
2653 ZCNoteEncryption::Ciphertext ct;
2657 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
2663 } catch(const std::exception &) {
2664 throw runtime_error(
2665 "encrypted_note could not be decoded"
2670 ZCNoteDecryption decryptor(k.viewing_key());
2672 NotePlaintext npt = NotePlaintext::decrypt(
2679 PaymentAddress payment_addr = k.address();
2680 Note decrypted_note = npt.note(payment_addr);
2682 assert(pwalletMain != NULL);
2683 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2685 uint256 commitment = decrypted_note.cm();
2686 pwalletMain->WitnessNoteCommitment(
2692 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2695 UniValue result(UniValue::VOBJ);
2696 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
2697 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2698 result.push_back(Pair("exists", (bool) witnesses[0]));
2704 UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
2706 if (!EnsureWalletIsAvailable(fHelp)) {
2707 return NullUniValue;
2710 if (fHelp || params.size() != 5) {
2711 throw runtime_error(
2712 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
2713 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
2714 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
2716 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
2717 "Outputs are confidential between sender/receiver. The vpub_old and\n"
2718 "vpub_new values are globally public and move transparent value into\n"
2719 "or out of the confidential value store, respectively.\n"
2721 "Note: The caller is responsible for delivering the output enc1 and\n"
2722 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
2723 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
2724 "payments in-band on the blockchain.)\n"
2727 " \"encryptednote1\": enc1,\n"
2728 " \"encryptednote2\": enc2,\n"
2729 " \"rawtxn\": rawtxout\n"
2737 if (!DecodeHexTx(tx, params[0].get_str()))
2738 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2740 UniValue inputs = params[1].get_obj();
2741 UniValue outputs = params[2].get_obj();
2743 CAmount vpub_old(0);
2744 CAmount vpub_new(0);
2746 if (params[3].get_real() != 0.0)
2747 vpub_old = AmountFromValue(params[3]);
2749 if (params[4].get_real() != 0.0)
2750 vpub_new = AmountFromValue(params[4]);
2752 std::vector<JSInput> vjsin;
2753 std::vector<JSOutput> vjsout;
2754 std::vector<Note> notes;
2755 std::vector<SpendingKey> keys;
2756 std::vector<uint256> commitments;
2758 for (const string& name_ : inputs.getKeys()) {
2759 CZCSpendingKey spendingkey(inputs[name_].get_str());
2760 SpendingKey k = spendingkey.Get();
2767 CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
2771 PaymentAddress addr = k.address();
2772 Note note = npt.note(addr);
2773 notes.push_back(note);
2774 commitments.push_back(note.cm());
2778 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2779 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
2781 assert(witnesses.size() == notes.size());
2782 assert(notes.size() == keys.size());
2785 for (size_t i = 0; i < witnesses.size(); i++) {
2786 if (!witnesses[i]) {
2787 throw runtime_error(
2788 "joinsplit input could not be found in tree"
2792 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
2796 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
2797 vjsin.push_back(JSInput());
2800 for (const string& name_ : outputs.getKeys()) {
2801 CZCPaymentAddress pubaddr(name_);
2802 PaymentAddress addrTo = pubaddr.Get();
2803 CAmount nAmount = AmountFromValue(outputs[name_]);
2805 vjsout.push_back(JSOutput(addrTo, nAmount));
2808 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
2809 vjsout.push_back(JSOutput());
2813 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
2814 throw runtime_error("unsupported joinsplit input/output counts");
2817 uint256 joinSplitPubKey;
2818 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
2819 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
2821 CMutableTransaction mtx(tx);
2823 mtx.joinSplitPubKey = joinSplitPubKey;
2825 JSDescription jsdesc(*pzcashParams,
2828 {vjsin[0], vjsin[1]},
2829 {vjsout[0], vjsout[1]},
2834 auto verifier = libzcash::ProofVerifier::Strict();
2835 assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
2838 mtx.vjoinsplit.push_back(jsdesc);
2840 // Empty output script.
2842 CTransaction signTx(mtx);
2843 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
2845 // Add the signature
2846 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
2847 dataToBeSigned.begin(), 32,
2852 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
2853 dataToBeSigned.begin(), 32,
2854 mtx.joinSplitPubKey.begin()
2857 CTransaction rawTx(mtx);
2859 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2862 std::string encryptedNote1;
2863 std::string encryptedNote2;
2865 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2866 ss2 << ((unsigned char) 0x00);
2867 ss2 << jsdesc.ephemeralKey;
2868 ss2 << jsdesc.ciphertexts[0];
2869 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
2871 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
2874 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2875 ss2 << ((unsigned char) 0x01);
2876 ss2 << jsdesc.ephemeralKey;
2877 ss2 << jsdesc.ciphertexts[1];
2878 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
2880 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
2883 UniValue result(UniValue::VOBJ);
2884 result.push_back(Pair("encryptednote1", encryptedNote1));
2885 result.push_back(Pair("encryptednote2", encryptedNote2));
2886 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
2890 UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
2892 if (!EnsureWalletIsAvailable(fHelp)) {
2893 return NullUniValue;
2896 if (fHelp || params.size() != 0) {
2897 throw runtime_error(
2900 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
2903 " \"zcaddress\": zcaddr,\n"
2904 " \"zcsecretkey\": zcsecretkey,\n"
2909 auto k = SpendingKey::random();
2910 auto addr = k.address();
2911 auto viewing_key = k.viewing_key();
2913 CDataStream viewing(SER_NETWORK, PROTOCOL_VERSION);
2915 viewing << viewing_key;
2917 CZCPaymentAddress pubaddr(addr);
2918 CZCSpendingKey spendingkey(k);
2919 std::string viewing_hex = HexStr(viewing.begin(), viewing.end());
2921 UniValue result(UniValue::VOBJ);
2922 result.push_back(Pair("zcaddress", pubaddr.ToString()));
2923 result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
2924 result.push_back(Pair("zcviewingkey", viewing_hex));
2929 UniValue z_getnewaddress(const UniValue& params, bool fHelp)
2931 if (!EnsureWalletIsAvailable(fHelp))
2932 return NullUniValue;
2934 if (fHelp || params.size() > 0)
2935 throw runtime_error(
2937 "\nReturns a new zaddr for receiving payments.\n"
2940 "\"zcashaddress\" (string) The new zaddr\n"
2942 + HelpExampleCli("z_getnewaddress", "")
2943 + HelpExampleRpc("z_getnewaddress", "")
2946 LOCK2(cs_main, pwalletMain->cs_wallet);
2948 EnsureWalletIsUnlocked();
2950 CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
2951 std::string result = pubaddr.ToString();
2956 UniValue z_listaddresses(const UniValue& params, bool fHelp)
2958 if (!EnsureWalletIsAvailable(fHelp))
2959 return NullUniValue;
2961 if (fHelp || params.size() > 1)
2962 throw runtime_error(
2964 "\nReturns the list of zaddr belonging to the wallet.\n"
2967 "[ (json array of string)\n"
2968 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
2972 + HelpExampleCli("z_listaddresses", "")
2973 + HelpExampleRpc("z_listaddresses", "")
2976 LOCK2(cs_main, pwalletMain->cs_wallet);
2978 UniValue ret(UniValue::VARR);
2979 std::set<libzcash::PaymentAddress> addresses;
2980 pwalletMain->GetPaymentAddresses(addresses);
2981 for (auto addr : addresses ) {
2982 ret.push_back(CZCPaymentAddress(addr).ToString());
2987 CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1) {
2988 set<CBitcoinAddress> setAddress;
2989 vector<COutput> vecOutputs;
2990 CAmount balance = 0;
2992 if (transparentAddress.length() > 0) {
2993 CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
2994 if (!taddr.IsValid()) {
2995 throw std::runtime_error("invalid transparent address");
2997 setAddress.insert(taddr);
3000 LOCK2(cs_main, pwalletMain->cs_wallet);
3002 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
3004 BOOST_FOREACH(const COutput& out, vecOutputs) {
3005 if (out.nDepth < minDepth) {
3009 if (setAddress.size()) {
3010 CTxDestination address;
3011 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3015 if (!setAddress.count(address)) {
3020 CAmount nValue = out.tx->vout[out.i].nValue;
3026 CAmount getBalanceZaddr(std::string address, int minDepth = 1) {
3027 CAmount balance = 0;
3028 std::vector<CNotePlaintextEntry> entries;
3029 LOCK2(cs_main, pwalletMain->cs_wallet);
3030 pwalletMain->GetFilteredNotes(entries, address, minDepth);
3031 for (auto & entry : entries) {
3032 balance += CAmount(entry.plaintext.value);
3038 UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
3040 if (!EnsureWalletIsAvailable(fHelp))
3041 return NullUniValue;
3043 if (fHelp || params.size()==0 || params.size() >2)
3044 throw runtime_error(
3045 "z_listreceivedbyaddress \"address\" ( minconf )\n"
3046 "\nReturn a list of amounts received by a zaddr belonging to the node’s wallet.\n"
3048 "1. \"address\" (string) The private address.\n"
3049 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3052 " \"txid\": xxxxx, (string) the transaction id\n"
3053 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
3054 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
3058 LOCK2(cs_main, pwalletMain->cs_wallet);
3061 if (params.size() > 1) {
3062 nMinDepth = params[1].get_int();
3064 if (nMinDepth < 0) {
3065 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3068 // Check that the from address is valid.
3069 auto fromaddress = params[0].get_str();
3071 libzcash::PaymentAddress zaddr;
3072 CZCPaymentAddress address(fromaddress);
3074 zaddr = address.Get();
3075 } catch (const std::runtime_error&) {
3076 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
3079 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3080 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3084 UniValue result(UniValue::VARR);
3085 std::vector<CNotePlaintextEntry> entries;
3086 pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false);
3087 for (CNotePlaintextEntry & entry : entries) {
3088 UniValue obj(UniValue::VOBJ);
3089 obj.push_back(Pair("txid",entry.jsop.hash.ToString()));
3090 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value))));
3091 std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
3092 obj.push_back(Pair("memo", HexStr(data)));
3093 result.push_back(obj);
3099 UniValue z_getbalance(const UniValue& params, bool fHelp)
3101 if (!EnsureWalletIsAvailable(fHelp))
3102 return NullUniValue;
3104 if (fHelp || params.size()==0 || params.size() >2)
3105 throw runtime_error(
3106 "z_getbalance \"address\" ( minconf )\n"
3107 "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
3109 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
3110 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3112 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this address.\n"
3114 "\nThe total amount received by address \"myaddress\"\n"
3115 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
3116 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
3117 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
3118 "\nAs a json rpc call\n"
3119 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
3122 LOCK2(cs_main, pwalletMain->cs_wallet);
3125 if (params.size() > 1) {
3126 nMinDepth = params[1].get_int();
3128 if (nMinDepth < 0) {
3129 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3132 // Check that the from address is valid.
3133 auto fromaddress = params[0].get_str();
3134 bool fromTaddr = false;
3135 CBitcoinAddress taddr(fromaddress);
3136 fromTaddr = taddr.IsValid();
3137 libzcash::PaymentAddress zaddr;
3139 CZCPaymentAddress address(fromaddress);
3141 zaddr = address.Get();
3142 } catch (const std::runtime_error&) {
3143 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3145 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3146 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3150 CAmount nBalance = 0;
3152 nBalance = getBalanceTaddr(fromaddress, nMinDepth);
3154 nBalance = getBalanceZaddr(fromaddress, nMinDepth);
3157 return ValueFromAmount(nBalance);
3161 UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
3163 if (!EnsureWalletIsAvailable(fHelp))
3164 return NullUniValue;
3166 if (fHelp || params.size() > 1)
3167 throw runtime_error(
3168 "z_gettotalbalance ( minconf )\n"
3169 "\nReturn the total value of funds stored in the node’s wallet.\n"
3171 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
3174 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
3175 " \"private\": xxxxx, (numeric) the total balance of private funds\n"
3176 " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
3179 "\nThe total amount in the wallet\n"
3180 + HelpExampleCli("z_gettotalbalance", "") +
3181 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3182 + HelpExampleCli("z_gettotalbalance", "5") +
3183 "\nAs a json rpc call\n"
3184 + HelpExampleRpc("z_gettotalbalance", "5")
3187 LOCK2(cs_main, pwalletMain->cs_wallet);
3190 if (params.size() == 1) {
3191 nMinDepth = params[0].get_int();
3193 if (nMinDepth < 0) {
3194 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3197 // getbalance and "getbalance * 1 true" should return the same number
3198 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
3199 // pwalletMain->GetBalance() does not accept min depth parameter
3200 // so we use our own method to get balance of utxos.
3201 CAmount nBalance = getBalanceTaddr("", nMinDepth);
3202 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth);
3203 CAmount nTotalBalance = nBalance + nPrivateBalance;
3204 UniValue result(UniValue::VOBJ);
3205 result.push_back(Pair("transparent", FormatMoney(nBalance)));
3206 result.push_back(Pair("private", FormatMoney(nPrivateBalance)));
3207 result.push_back(Pair("total", FormatMoney(nTotalBalance)));
3211 UniValue z_getoperationresult(const UniValue& params, bool fHelp)
3213 if (!EnsureWalletIsAvailable(fHelp))
3214 return NullUniValue;
3216 if (fHelp || params.size() > 1)
3217 throw runtime_error(
3218 "z_getoperationresult ([\"operationid\", ... ]) \n"
3219 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3220 + HelpRequiringPassphrase() + "\n"
3222 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3224 "\" [object, ...]\" (array) A list of JSON objects\n"
3227 // This call will remove finished operations
3228 return z_getoperationstatus_IMPL(params, true);
3231 UniValue z_getoperationstatus(const UniValue& params, bool fHelp)
3233 if (!EnsureWalletIsAvailable(fHelp))
3234 return NullUniValue;
3236 if (fHelp || params.size() > 1)
3237 throw runtime_error(
3238 "z_getoperationstatus ([\"operationid\", ... ]) \n"
3239 "\nGet operation status and any associated result or error data. The operation will remain in memory."
3240 + HelpRequiringPassphrase() + "\n"
3242 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3244 "\" [object, ...]\" (array) A list of JSON objects\n"
3247 // This call is idempotent so we don't want to remove finished operations
3248 return z_getoperationstatus_IMPL(params, false);
3251 UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedOperations=false)
3253 LOCK2(cs_main, pwalletMain->cs_wallet);
3255 std::set<AsyncRPCOperationId> filter;
3256 if (params.size()==1) {
3257 UniValue ids = params[0].get_array();
3258 for (const UniValue & v : ids.getValues()) {
3259 filter.insert(v.get_str());
3262 bool useFilter = (filter.size()>0);
3264 UniValue ret(UniValue::VARR);
3265 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3266 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3268 for (auto id : ids) {
3269 if (useFilter && !filter.count(id))
3272 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3275 // It's possible that the operation was removed from the internal queue and map during this loop
3276 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3279 UniValue obj = operation->getStatus();
3280 std::string s = obj["status"].get_str();
3281 if (fRemoveFinishedOperations) {
3282 // Caller is only interested in retrieving finished results
3283 if ("success"==s || "failed"==s || "cancelled"==s) {
3285 q->popOperationForId(id);
3292 std::vector<UniValue> arrTmp = ret.getValues();
3294 // sort results chronologically by creation_time
3295 std::sort(arrTmp.begin(), arrTmp.end(), [](UniValue a, UniValue b) -> bool {
3296 const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
3297 const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
3303 ret.push_backV(arrTmp);
3309 // Here we define the maximum number of zaddr outputs that can be included in a transaction.
3310 // If input notes are small, we might actually require more than one joinsplit per zaddr output.
3311 // For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
3312 // We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
3313 #define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1)
3315 // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
3316 #define CTXIN_SPEND_DUST_SIZE 148
3317 #define CTXOUT_REGULAR_SIZE 34
3319 UniValue z_sendmany(const UniValue& params, bool fHelp)
3321 if (!EnsureWalletIsAvailable(fHelp))
3322 return NullUniValue;
3324 if (fHelp || params.size() < 2 || params.size() > 4)
3325 throw runtime_error(
3326 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
3327 "\nSend multiple times. Amounts are double-precision floating point numbers."
3328 "\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
3329 "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
3330 + strprintf("\nCurrently, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS)
3331 + HelpRequiringPassphrase() + "\n"
3333 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
3334 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
3336 " \"address\":address (string, required) The address is a taddr or zaddr\n"
3337 " \"amount\":amount (numeric, required) The numeric amount in " + CURRENCY_UNIT + " is the value\n"
3338 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3340 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
3341 "4. fee (numeric, optional, default="
3342 + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3344 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3347 LOCK2(cs_main, pwalletMain->cs_wallet);
3349 // Check that the from address is valid.
3350 auto fromaddress = params[0].get_str();
3351 bool fromTaddr = false;
3352 CBitcoinAddress taddr(fromaddress);
3353 fromTaddr = taddr.IsValid();
3354 libzcash::PaymentAddress zaddr;
3356 CZCPaymentAddress address(fromaddress);
3358 zaddr = address.Get();
3359 } catch (const std::runtime_error&) {
3361 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3365 // Check that we have the spending key
3367 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3368 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3372 UniValue outputs = params[1].get_array();
3374 if (outputs.size()==0)
3375 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3377 // Keep track of addresses to spot duplicates
3378 set<std::string> setAddress;
3381 std::vector<SendManyRecipient> taddrRecipients;
3382 std::vector<SendManyRecipient> zaddrRecipients;
3383 CAmount nTotalOut = 0;
3385 for (const UniValue& o : outputs.getValues()) {
3387 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
3389 // sanity check, report error if unknown key-value pairs
3390 for (const string& name_ : o.getKeys()) {
3391 std::string s = name_;
3392 if (s != "address" && s != "amount" && s!="memo")
3393 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3396 string address = find_value(o, "address").get_str();
3397 bool isZaddr = false;
3398 CBitcoinAddress taddr(address);
3399 if (!taddr.IsValid()) {
3401 CZCPaymentAddress zaddr(address);
3404 } catch (const std::runtime_error&) {
3405 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3409 if (setAddress.count(address))
3410 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3411 setAddress.insert(address);
3413 UniValue memoValue = find_value(o, "memo");
3415 if (!memoValue.isNull()) {
3416 memo = memoValue.get_str();
3418 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
3419 } else if (!IsHex(memo)) {
3420 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3422 if (memo.length() > ZC_MEMO_SIZE*2) {
3423 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3427 UniValue av = find_value(o, "amount");
3428 CAmount nAmount = AmountFromValue( av );
3430 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3433 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3435 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3438 nTotalOut += nAmount;
3441 // Check the number of zaddr outputs does not exceed the limit.
3442 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS) {
3443 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
3446 // As a sanity check, estimate and verify that the size of the transaction will be valid.
3447 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
3449 CMutableTransaction mtx;
3451 for (int i = 0; i < zaddrRecipients.size(); i++) {
3452 mtx.vjoinsplit.push_back(JSDescription());
3454 CTransaction tx(mtx);
3455 txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
3457 txsize += CTXIN_SPEND_DUST_SIZE;
3458 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
3460 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
3461 if (txsize > MAX_TX_SIZE) {
3462 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", MAX_TX_SIZE ));
3465 // Minimum confirmations
3467 if (params.size() > 2) {
3468 nMinDepth = params[2].get_int();
3470 if (nMinDepth < 0) {
3471 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3474 // Fee in Zatoshis, not currency format)
3475 CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
3476 if (params.size() > 3) {
3477 if (params[3].get_real() == 0.0) {
3480 nFee = AmountFromValue( params[3] );
3483 // Check that the user specified fee is sane.
3484 if (nFee > nTotalOut) {
3485 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s", FormatMoney(nFee), FormatMoney(nTotalOut)));
3489 // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
3490 UniValue o(UniValue::VOBJ);
3491 o.push_back(Pair("fromaddress", params[0]));
3492 o.push_back(Pair("amounts", params[1]));
3493 o.push_back(Pair("minconf", nMinDepth));
3494 o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
3495 UniValue contextInfo = o;
3497 // Create operation and add to global queue
3498 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3499 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
3500 q->addOperation(operation);
3501 AsyncRPCOperationId operationId = operation->getId();
3507 When estimating the number of coinbase utxos we can shield in a single transaction:
3508 1. Joinsplit description is 1802 bytes.
3509 2. Transaction overhead ~ 100 bytes
3510 3. Spending a typical P2PKH is >=148 bytes, as defined in CTXIN_SPEND_DUST_SIZE.
3511 4. Spending a multi-sig P2SH address can vary greatly:
3512 https://github.com/bitcoin/bitcoin/blob/c3ad56f4e0b587d8d763af03d743fdfc2d180c9b/src/main.cpp#L517
3513 In real-world coinbase utxos, we consider a 3-of-3 multisig, where the size is roughly:
3514 (3*(33+1))+3 = 105 byte redeem script
3515 105 + 1 + 3*(73+1) = 328 bytes of scriptSig, rounded up to 400 based on testnet experiments.
3517 #define CTXIN_SPEND_P2SH_SIZE 400
3519 UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
3521 if (!EnsureWalletIsAvailable(fHelp))
3522 return NullUniValue;
3524 bool fEnableShieldCoinbase = fExperimentalMode && GetBoolArg("-zshieldcoinbase", false);
3525 std::string strDisabledMsg = "";
3526 if (!fEnableShieldCoinbase) {
3527 strDisabledMsg = "\nWARNING: z_shieldcoinbase is DISABLED but can be enabled as an experimental feature.\n";
3530 if (fHelp || params.size() < 2 || params.size() > 3)
3531 throw runtime_error(
3532 "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee )\n"
3534 "\nShield transparent coinbase funds by sending to a shielded zaddr. This is an asynchronous operation and utxos"
3535 "\nselected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent`"
3536 "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding is limited by"
3537 "\nboth the -mempooltxinputlimit=xxx option and a consensus rule defining a maximum transaction size of "
3538 + strprintf("%d bytes.", MAX_TX_SIZE)
3539 + HelpRequiringPassphrase() + "\n"
3541 "1. \"fromaddress\" (string, required) The address is a taddr or \"*\" for all taddrs belonging to the wallet.\n"
3542 "2. \"toaddress\" (string, required) The address is a zaddr.\n"
3543 "3. fee (numeric, optional, default="
3544 + strprintf("%s", FormatMoney(SHIELD_COINBASE_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3547 " \"operationid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3548 " \"shieldedUTXOs\": xxx (numeric) Number of coinbase utxos being shielded.\n"
3549 " \"shieldedValue\": xxx (numeric) Value of coinbase utxos being shielded.\n"
3550 " \"remainingUTXOs\": xxx (numeric) Number of coinbase utxos still available for shielding.\n"
3551 " \"remainingValue\": xxx (numeric) Value of coinbase utxos still available for shielding.\n"
3555 if (!fEnableShieldCoinbase) {
3556 throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_shieldcoinbase is disabled.");
3559 LOCK2(cs_main, pwalletMain->cs_wallet);
3561 // Validate the from address
3562 auto fromaddress = params[0].get_str();
3563 bool isFromWildcard = fromaddress == "*";
3564 CBitcoinAddress taddr;
3565 if (!isFromWildcard) {
3566 taddr = CBitcoinAddress(fromaddress);
3567 if (!taddr.IsValid()) {
3568 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
3572 // Validate the destination address
3573 auto destaddress = params[1].get_str();
3575 CZCPaymentAddress pa(destaddress);
3576 libzcash::PaymentAddress zaddr = pa.Get();
3577 } catch (const std::runtime_error&) {
3578 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
3581 // Convert fee from currency format to zatoshis
3582 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
3583 if (params.size() > 2) {
3584 if (params[2].get_real() == 0.0) {
3587 nFee = AmountFromValue( params[2] );
3591 // Prepare to get coinbase utxos
3592 std::vector<ShieldCoinbaseUTXO> inputs;
3593 CAmount shieldedValue = 0;
3594 CAmount remainingValue = 0;
3595 size_t estimatedTxSize = 2000; // 1802 joinsplit description + tx overhead + wiggle room
3596 size_t utxoCounter = 0;
3597 bool maxedOutFlag = false;
3598 size_t mempoolLimit = (size_t)GetArg("-mempooltxinputlimit", 0);
3600 // Set of addresses to filter utxos by
3601 set<CBitcoinAddress> setAddress = {};
3602 if (!isFromWildcard) {
3603 setAddress.insert(taddr);
3606 // Get available utxos
3607 vector<COutput> vecOutputs;
3608 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true);
3610 // Find unspent coinbase utxos and update estimated size
3611 BOOST_FOREACH(const COutput& out, vecOutputs) {
3612 if (!out.fSpendable) {
3616 CTxDestination address;
3617 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3620 // If taddr is not wildcard "*", filter utxos
3621 if (setAddress.size()>0 && !setAddress.count(address)) {
3625 if (!out.tx->IsCoinBase()) {
3630 CAmount nValue = out.tx->vout[out.i].nValue;
3632 if (!maxedOutFlag) {
3633 CBitcoinAddress ba(address);
3634 size_t increase = (ba.IsScript()) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
3635 if (estimatedTxSize + increase >= MAX_TX_SIZE ||
3636 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
3638 maxedOutFlag = true;
3640 estimatedTxSize += increase;
3641 ShieldCoinbaseUTXO utxo = {out.tx->GetHash(), out.i, nValue};
3642 inputs.push_back(utxo);
3643 shieldedValue += nValue;
3648 remainingValue += nValue;
3652 size_t numUtxos = inputs.size();
3654 if (numUtxos == 0) {
3655 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any coinbase funds to shield.");
3658 if (shieldedValue < nFee) {
3659 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
3660 strprintf("Insufficient coinbase funds, have %s, which is less than miners fee %s",
3661 FormatMoney(shieldedValue), FormatMoney(nFee)));
3664 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
3665 CAmount netAmount = shieldedValue - nFee;
3666 if (nFee > netAmount) {
3667 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
3670 // Keep record of parameters in context object
3671 UniValue contextInfo(UniValue::VOBJ);
3672 contextInfo.push_back(Pair("fromaddress", params[0]));
3673 contextInfo.push_back(Pair("toaddress", params[1]));
3674 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
3676 // Create operation and add to global queue
3677 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3678 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(inputs, destaddress, nFee, contextInfo) );
3679 q->addOperation(operation);
3680 AsyncRPCOperationId operationId = operation->getId();
3682 // Return continuation information
3683 UniValue o(UniValue::VOBJ);
3684 o.push_back(Pair("remainingUTXOs", utxoCounter - numUtxos));
3685 o.push_back(Pair("remainingValue", ValueFromAmount(remainingValue)));
3686 o.push_back(Pair("shieldingUTXOs", numUtxos));
3687 o.push_back(Pair("shieldingValue", ValueFromAmount(shieldedValue)));
3688 o.push_back(Pair("opid", operationId));
3693 UniValue z_listoperationids(const UniValue& params, bool fHelp)
3695 if (!EnsureWalletIsAvailable(fHelp))
3696 return NullUniValue;
3698 if (fHelp || params.size() > 1)
3699 throw runtime_error(
3700 "z_listoperationids\n"
3701 "\nReturns the list of operation ids currently known to the wallet.\n"
3703 "1. \"status\" (string, optional) Filter result by the operation's state state e.g. \"success\".\n"
3705 "[ (json array of string)\n"
3706 " \"operationid\" (string) an operation id belonging to the wallet\n"
3710 + HelpExampleCli("z_listoperationids", "")
3711 + HelpExampleRpc("z_listoperationids", "")
3714 LOCK2(cs_main, pwalletMain->cs_wallet);
3717 bool useFilter = false;
3718 if (params.size()==1) {
3719 filter = params[0].get_str();
3723 UniValue ret(UniValue::VARR);
3724 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3725 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3726 for (auto id : ids) {
3727 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3731 std::string state = operation->getStateAsString();
3732 if (useFilter && filter.compare(state)!=0)