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"
32 #include <boost/assign/list_of.hpp>
40 using namespace libzcash;
42 extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
44 int64_t nWalletUnlockTime;
45 static CCriticalSection cs_nWalletUnlockTime;
48 UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
50 std::string HelpRequiringPassphrase()
52 return pwalletMain && pwalletMain->IsCrypted()
53 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
57 bool EnsureWalletIsAvailable(bool avoidException)
62 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
69 void EnsureWalletIsUnlocked()
71 if (pwalletMain->IsLocked())
72 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
75 void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
77 int confirms = wtx.GetDepthInMainChain();
78 entry.push_back(Pair("confirmations", confirms));
80 entry.push_back(Pair("generated", true));
83 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
84 entry.push_back(Pair("blockindex", wtx.nIndex));
85 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
87 uint256 hash = wtx.GetHash();
88 entry.push_back(Pair("txid", hash.GetHex()));
89 UniValue conflicts(UniValue::VARR);
90 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
91 conflicts.push_back(conflict.GetHex());
92 entry.push_back(Pair("walletconflicts", conflicts));
93 entry.push_back(Pair("time", wtx.GetTxTime()));
94 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
95 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
96 entry.push_back(Pair(item.first, item.second));
98 entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
101 string AccountFromValue(const UniValue& value)
103 string strAccount = value.get_str();
104 if (strAccount != "")
105 throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
109 UniValue getnewaddress(const UniValue& params, bool fHelp)
111 if (!EnsureWalletIsAvailable(fHelp))
114 if (fHelp || params.size() > 1)
116 "getnewaddress ( \"account\" )\n"
117 "\nReturns a new Zcash address for receiving payments.\n"
119 "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"
121 "\"zcashaddress\" (string) The new zcash address\n"
123 + HelpExampleCli("getnewaddress", "")
124 + HelpExampleRpc("getnewaddress", "")
127 LOCK2(cs_main, pwalletMain->cs_wallet);
129 // Parse the account first so we don't generate a key if there's an error
131 if (params.size() > 0)
132 strAccount = AccountFromValue(params[0]);
134 if (!pwalletMain->IsLocked())
135 pwalletMain->TopUpKeyPool();
137 // Generate a new key that is added to wallet
139 if (!pwalletMain->GetKeyFromPool(newKey))
140 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
141 CKeyID keyID = newKey.GetID();
143 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
145 return CBitcoinAddress(keyID).ToString();
149 CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
151 CWalletDB walletdb(pwalletMain->strWalletFile);
154 walletdb.ReadAccount(strAccount, account);
156 bool bKeyUsed = false;
158 // Check if the current key has been used
159 if (account.vchPubKey.IsValid())
161 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
162 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
163 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
166 const CWalletTx& wtx = (*it).second;
167 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
168 if (txout.scriptPubKey == scriptPubKey)
173 // Generate a new key
174 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
176 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
177 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
179 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
180 walletdb.WriteAccount(strAccount, account);
183 return CBitcoinAddress(account.vchPubKey.GetID());
186 UniValue getaccountaddress(const UniValue& params, bool fHelp)
188 if (!EnsureWalletIsAvailable(fHelp))
191 if (fHelp || params.size() != 1)
193 "getaccountaddress \"account\"\n"
194 "\nDEPRECATED. Returns the current Zcash address for receiving payments to this account.\n"
196 "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"
198 "\"zcashaddress\" (string) The account zcash address\n"
200 + HelpExampleCli("getaccountaddress", "")
201 + HelpExampleCli("getaccountaddress", "\"\"")
202 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
203 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
206 LOCK2(cs_main, pwalletMain->cs_wallet);
208 // Parse the account first so we don't generate a key if there's an error
209 string strAccount = AccountFromValue(params[0]);
211 UniValue ret(UniValue::VSTR);
213 ret = GetAccountAddress(strAccount).ToString();
218 UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
220 if (!EnsureWalletIsAvailable(fHelp))
223 if (fHelp || params.size() > 1)
225 "getrawchangeaddress\n"
226 "\nReturns a new Zcash address, for receiving change.\n"
227 "This is for use with raw transactions, NOT normal use.\n"
229 "\"address\" (string) The address\n"
231 + HelpExampleCli("getrawchangeaddress", "")
232 + HelpExampleRpc("getrawchangeaddress", "")
235 LOCK2(cs_main, pwalletMain->cs_wallet);
237 if (!pwalletMain->IsLocked())
238 pwalletMain->TopUpKeyPool();
240 CReserveKey reservekey(pwalletMain);
242 if (!reservekey.GetReservedKey(vchPubKey))
243 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
245 reservekey.KeepKey();
247 CKeyID keyID = vchPubKey.GetID();
249 return CBitcoinAddress(keyID).ToString();
253 UniValue setaccount(const UniValue& params, bool fHelp)
255 if (!EnsureWalletIsAvailable(fHelp))
258 if (fHelp || params.size() < 1 || params.size() > 2)
260 "setaccount \"zcashaddress\" \"account\"\n"
261 "\nDEPRECATED. Sets the account associated with the given address.\n"
263 "1. \"zcashaddress\" (string, required) The zcash address to be associated with an account.\n"
264 "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"
266 + HelpExampleCli("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"tabby\"")
267 + HelpExampleRpc("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"tabby\"")
270 LOCK2(cs_main, pwalletMain->cs_wallet);
272 CBitcoinAddress address(params[0].get_str());
273 if (!address.IsValid())
274 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
277 if (params.size() > 1)
278 strAccount = AccountFromValue(params[1]);
280 // Only add the account if the address is yours.
281 if (IsMine(*pwalletMain, address.Get()))
283 // Detect when changing the account of an address that is the 'unused current key' of another account:
284 if (pwalletMain->mapAddressBook.count(address.Get()))
286 string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name;
287 if (address == GetAccountAddress(strOldAccount))
288 GetAccountAddress(strOldAccount, true);
290 pwalletMain->SetAddressBook(address.Get(), strAccount, "receive");
293 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
299 UniValue getaccount(const UniValue& params, bool fHelp)
301 if (!EnsureWalletIsAvailable(fHelp))
304 if (fHelp || params.size() != 1)
306 "getaccount \"zcashaddress\"\n"
307 "\nDEPRECATED. Returns the account associated with the given address.\n"
309 "1. \"zcashaddress\" (string, required) The zcash address for account lookup.\n"
311 "\"accountname\" (string) the account address\n"
313 + HelpExampleCli("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
314 + HelpExampleRpc("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
317 LOCK2(cs_main, pwalletMain->cs_wallet);
319 CBitcoinAddress address(params[0].get_str());
320 if (!address.IsValid())
321 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
324 map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(address.Get());
325 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty())
326 strAccount = (*mi).second.name;
331 UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
333 if (!EnsureWalletIsAvailable(fHelp))
336 if (fHelp || params.size() != 1)
338 "getaddressesbyaccount \"account\"\n"
339 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
341 "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"
343 "[ (json array of string)\n"
344 " \"zcashaddress\" (string) a zcash address associated with the given account\n"
348 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
349 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
352 LOCK2(cs_main, pwalletMain->cs_wallet);
354 string strAccount = AccountFromValue(params[0]);
356 // Find all addresses that have the given account
357 UniValue ret(UniValue::VARR);
358 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
360 const CBitcoinAddress& address = item.first;
361 const string& strName = item.second.name;
362 if (strName == strAccount)
363 ret.push_back(address.ToString());
368 static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
370 CAmount curBalance = pwalletMain->GetBalance();
374 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
376 if (nValue > curBalance)
377 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
379 // Parse Zcash address
380 CScript scriptPubKey = GetScriptForDestination(address);
382 // Create and send the transaction
383 CReserveKey reservekey(pwalletMain);
384 CAmount nFeeRequired;
385 std::string strError;
386 vector<CRecipient> vecSend;
387 int nChangePosRet = -1;
388 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
389 vecSend.push_back(recipient);
390 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
391 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
392 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));
393 throw JSONRPCError(RPC_WALLET_ERROR, strError);
395 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
396 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.");
399 UniValue sendtoaddress(const UniValue& params, bool fHelp)
401 if (!EnsureWalletIsAvailable(fHelp))
404 if (fHelp || params.size() < 2 || params.size() > 5)
406 "sendtoaddress \"zcashaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
407 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
408 + HelpRequiringPassphrase() +
410 "1. \"zcashaddress\" (string, required) The zcash address to send to.\n"
411 "2. \"amount\" (numeric, required) The amount in btc to send. eg 0.1\n"
412 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
413 " This is not part of the transaction, just kept in your wallet.\n"
414 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
415 " to which you're sending the transaction. This is not part of the \n"
416 " transaction, just kept in your wallet.\n"
417 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
418 " The recipient will receive less zcash than you enter in the amount field.\n"
420 "\"transactionid\" (string) The transaction id.\n"
422 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
423 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
424 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
425 + HelpExampleRpc("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
428 LOCK2(cs_main, pwalletMain->cs_wallet);
430 CBitcoinAddress address(params[0].get_str());
431 if (!address.IsValid())
432 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
435 CAmount nAmount = AmountFromValue(params[1]);
437 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
441 if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
442 wtx.mapValue["comment"] = params[2].get_str();
443 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
444 wtx.mapValue["to"] = params[3].get_str();
446 bool fSubtractFeeFromAmount = false;
447 if (params.size() > 4)
448 fSubtractFeeFromAmount = params[4].get_bool();
450 EnsureWalletIsUnlocked();
452 SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, wtx);
454 return wtx.GetHash().GetHex();
457 UniValue listaddressgroupings(const UniValue& params, bool fHelp)
459 if (!EnsureWalletIsAvailable(fHelp))
464 "listaddressgroupings\n"
465 "\nLists groups of addresses which have had their common ownership\n"
466 "made public by common use as inputs or as the resulting change\n"
467 "in past transactions\n"
472 " \"zcashaddress\", (string) The zcash address\n"
473 " amount, (numeric) The amount in btc\n"
474 " \"account\" (string, optional) The account (DEPRECATED)\n"
481 + HelpExampleCli("listaddressgroupings", "")
482 + HelpExampleRpc("listaddressgroupings", "")
485 LOCK2(cs_main, pwalletMain->cs_wallet);
487 UniValue jsonGroupings(UniValue::VARR);
488 map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
489 BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
491 UniValue jsonGrouping(UniValue::VARR);
492 BOOST_FOREACH(CTxDestination address, grouping)
494 UniValue addressInfo(UniValue::VARR);
495 addressInfo.push_back(CBitcoinAddress(address).ToString());
496 addressInfo.push_back(ValueFromAmount(balances[address]));
498 if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
499 addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
501 jsonGrouping.push_back(addressInfo);
503 jsonGroupings.push_back(jsonGrouping);
505 return jsonGroupings;
508 UniValue signmessage(const UniValue& params, bool fHelp)
510 if (!EnsureWalletIsAvailable(fHelp))
513 if (fHelp || params.size() != 2)
515 "signmessage \"zcashaddress\" \"message\"\n"
516 "\nSign a message with the private key of an address"
517 + HelpRequiringPassphrase() + "\n"
519 "1. \"zcashaddress\" (string, required) The zcash address to use for the private key.\n"
520 "2. \"message\" (string, required) The message to create a signature of.\n"
522 "\"signature\" (string) The signature of the message encoded in base 64\n"
524 "\nUnlock the wallet for 30 seconds\n"
525 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
526 "\nCreate the signature\n"
527 + HelpExampleCli("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"my message\"") +
528 "\nVerify the signature\n"
529 + HelpExampleCli("verifymessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"signature\" \"my message\"") +
531 + HelpExampleRpc("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"my message\"")
534 LOCK2(cs_main, pwalletMain->cs_wallet);
536 EnsureWalletIsUnlocked();
538 string strAddress = params[0].get_str();
539 string strMessage = params[1].get_str();
541 CBitcoinAddress addr(strAddress);
543 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
546 if (!addr.GetKeyID(keyID))
547 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
550 if (!pwalletMain->GetKey(keyID, key))
551 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
553 CHashWriter ss(SER_GETHASH, 0);
554 ss << strMessageMagic;
557 vector<unsigned char> vchSig;
558 if (!key.SignCompact(ss.GetHash(), vchSig))
559 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
561 return EncodeBase64(&vchSig[0], vchSig.size());
564 UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
566 if (!EnsureWalletIsAvailable(fHelp))
569 if (fHelp || params.size() < 1 || params.size() > 2)
571 "getreceivedbyaddress \"zcashaddress\" ( minconf )\n"
572 "\nReturns the total amount received by the given zcashaddress in transactions with at least minconf confirmations.\n"
574 "1. \"zcashaddress\" (string, required) The zcash address for transactions.\n"
575 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
577 "amount (numeric) The total amount in btc received at this address.\n"
579 "\nThe amount from transactions with at least 1 confirmation\n"
580 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"") +
581 "\nThe amount including unconfirmed transactions, zero confirmations\n"
582 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 0") +
583 "\nThe amount with at least 6 confirmation, very safe\n"
584 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 6") +
585 "\nAs a json rpc call\n"
586 + HelpExampleRpc("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", 6")
589 LOCK2(cs_main, pwalletMain->cs_wallet);
592 CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
593 if (!address.IsValid())
594 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
595 CScript scriptPubKey = GetScriptForDestination(address.Get());
596 if (!IsMine(*pwalletMain,scriptPubKey))
599 // Minimum confirmations
601 if (params.size() > 1)
602 nMinDepth = params[1].get_int();
606 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
608 const CWalletTx& wtx = (*it).second;
609 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
612 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
613 if (txout.scriptPubKey == scriptPubKey)
614 if (wtx.GetDepthInMainChain() >= nMinDepth)
615 nAmount += txout.nValue;
618 return ValueFromAmount(nAmount);
622 UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
624 if (!EnsureWalletIsAvailable(fHelp))
627 if (fHelp || params.size() < 1 || params.size() > 2)
629 "getreceivedbyaccount \"account\" ( minconf )\n"
630 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
632 "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"
633 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
635 "amount (numeric) The total amount in btc received for this account.\n"
637 "\nAmount received by the default account with at least 1 confirmation\n"
638 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
639 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
640 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
641 "\nThe amount with at least 6 confirmation, very safe\n"
642 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
643 "\nAs a json rpc call\n"
644 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
647 LOCK2(cs_main, pwalletMain->cs_wallet);
649 // Minimum confirmations
651 if (params.size() > 1)
652 nMinDepth = params[1].get_int();
654 // Get the set of pub keys assigned to account
655 string strAccount = AccountFromValue(params[0]);
656 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
660 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
662 const CWalletTx& wtx = (*it).second;
663 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
666 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
668 CTxDestination address;
669 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
670 if (wtx.GetDepthInMainChain() >= nMinDepth)
671 nAmount += txout.nValue;
675 return (double)nAmount / (double)COIN;
679 CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
681 CAmount nBalance = 0;
683 // Tally wallet transactions
684 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
686 const CWalletTx& wtx = (*it).second;
687 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
690 CAmount nReceived, nSent, nFee;
691 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
693 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
694 nBalance += nReceived;
695 nBalance -= nSent + nFee;
698 // Tally internal accounting entries
699 nBalance += walletdb.GetAccountCreditDebit(strAccount);
704 CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
706 CWalletDB walletdb(pwalletMain->strWalletFile);
707 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
711 UniValue getbalance(const UniValue& params, bool fHelp)
713 if (!EnsureWalletIsAvailable(fHelp))
716 if (fHelp || params.size() > 3)
718 "getbalance ( \"account\" minconf includeWatchonly )\n"
719 "\nReturns the server's total available balance.\n"
721 "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"
722 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
723 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
725 "amount (numeric) The total amount in btc received for this account.\n"
727 "\nThe total amount in the wallet\n"
728 + HelpExampleCli("getbalance", "") +
729 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
730 + HelpExampleCli("getbalance", "\"*\" 6") +
731 "\nAs a json rpc call\n"
732 + HelpExampleRpc("getbalance", "\"*\", 6")
735 LOCK2(cs_main, pwalletMain->cs_wallet);
737 if (params.size() == 0)
738 return ValueFromAmount(pwalletMain->GetBalance());
741 if (params.size() > 1)
742 nMinDepth = params[1].get_int();
743 isminefilter filter = ISMINE_SPENDABLE;
744 if(params.size() > 2)
745 if(params[2].get_bool())
746 filter = filter | ISMINE_WATCH_ONLY;
748 if (params[0].get_str() == "*") {
749 // Calculate total balance a different way from GetBalance()
750 // (GetBalance() sums up all unspent TxOuts)
751 // getbalance and "getbalance * 1 true" should return the same number
752 CAmount nBalance = 0;
753 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
755 const CWalletTx& wtx = (*it).second;
756 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
760 string strSentAccount;
761 list<COutputEntry> listReceived;
762 list<COutputEntry> listSent;
763 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
764 if (wtx.GetDepthInMainChain() >= nMinDepth)
766 BOOST_FOREACH(const COutputEntry& r, listReceived)
767 nBalance += r.amount;
769 BOOST_FOREACH(const COutputEntry& s, listSent)
770 nBalance -= s.amount;
773 return ValueFromAmount(nBalance);
776 string strAccount = AccountFromValue(params[0]);
778 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
780 return ValueFromAmount(nBalance);
783 UniValue getunconfirmedbalance(const UniValue ¶ms, bool fHelp)
785 if (!EnsureWalletIsAvailable(fHelp))
788 if (fHelp || params.size() > 0)
790 "getunconfirmedbalance\n"
791 "Returns the server's total unconfirmed balance\n");
793 LOCK2(cs_main, pwalletMain->cs_wallet);
795 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
799 UniValue movecmd(const UniValue& params, bool fHelp)
801 if (!EnsureWalletIsAvailable(fHelp))
804 if (fHelp || params.size() < 3 || params.size() > 5)
806 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
807 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
809 "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"
810 "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"
811 "3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
812 "4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
814 "true|false (boolean) true if successful.\n"
816 "\nMove 0.01 btc from the default account to the account named tabby\n"
817 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
818 "\nMove 0.01 btc timotei to akiko with a comment and funds have 6 confirmations\n"
819 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
820 "\nAs a json rpc call\n"
821 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
824 LOCK2(cs_main, pwalletMain->cs_wallet);
826 string strFrom = AccountFromValue(params[0]);
827 string strTo = AccountFromValue(params[1]);
828 CAmount nAmount = AmountFromValue(params[2]);
830 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
831 if (params.size() > 3)
832 // unused parameter, used to be nMinDepth, keep type-checking it though
833 (void)params[3].get_int();
835 if (params.size() > 4)
836 strComment = params[4].get_str();
838 CWalletDB walletdb(pwalletMain->strWalletFile);
839 if (!walletdb.TxnBegin())
840 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
842 int64_t nNow = GetAdjustedTime();
845 CAccountingEntry debit;
846 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
847 debit.strAccount = strFrom;
848 debit.nCreditDebit = -nAmount;
850 debit.strOtherAccount = strTo;
851 debit.strComment = strComment;
852 walletdb.WriteAccountingEntry(debit);
855 CAccountingEntry credit;
856 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
857 credit.strAccount = strTo;
858 credit.nCreditDebit = nAmount;
860 credit.strOtherAccount = strFrom;
861 credit.strComment = strComment;
862 walletdb.WriteAccountingEntry(credit);
864 if (!walletdb.TxnCommit())
865 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
871 UniValue sendfrom(const UniValue& params, bool fHelp)
873 if (!EnsureWalletIsAvailable(fHelp))
876 if (fHelp || params.size() < 3 || params.size() > 6)
878 "sendfrom \"fromaccount\" \"tozcashaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
879 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a zcash address.\n"
880 "The amount is a real and is rounded to the nearest 0.00000001."
881 + HelpRequiringPassphrase() + "\n"
883 "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"
884 "2. \"tozcashaddress\" (string, required) The zcash address to send funds to.\n"
885 "3. amount (numeric, required) The amount in btc. (transaction fee is added on top).\n"
886 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
887 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
888 " This is not part of the transaction, just kept in your wallet.\n"
889 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
890 " to which you're sending the transaction. This is not part of the transaction, \n"
891 " it is just kept in your wallet.\n"
893 "\"transactionid\" (string) The transaction id.\n"
895 "\nSend 0.01 btc from the default account to the address, must have at least 1 confirmation\n"
896 + HelpExampleCli("sendfrom", "\"\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
897 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
898 + HelpExampleCli("sendfrom", "\"tabby\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
899 "\nAs a json rpc call\n"
900 + HelpExampleRpc("sendfrom", "\"tabby\", \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
903 LOCK2(cs_main, pwalletMain->cs_wallet);
905 string strAccount = AccountFromValue(params[0]);
906 CBitcoinAddress address(params[1].get_str());
907 if (!address.IsValid())
908 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
909 CAmount nAmount = AmountFromValue(params[2]);
911 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
913 if (params.size() > 3)
914 nMinDepth = params[3].get_int();
917 wtx.strFromAccount = strAccount;
918 if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
919 wtx.mapValue["comment"] = params[4].get_str();
920 if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
921 wtx.mapValue["to"] = params[5].get_str();
923 EnsureWalletIsUnlocked();
926 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
927 if (nAmount > nBalance)
928 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
930 SendMoney(address.Get(), nAmount, false, wtx);
932 return wtx.GetHash().GetHex();
936 UniValue sendmany(const UniValue& params, bool fHelp)
938 if (!EnsureWalletIsAvailable(fHelp))
941 if (fHelp || params.size() < 2 || params.size() > 5)
943 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
944 "\nSend multiple times. Amounts are double-precision floating point numbers."
945 + HelpRequiringPassphrase() + "\n"
947 "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"
948 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
950 " \"address\":amount (numeric) The zcash address is the key, the numeric amount in btc is the value\n"
953 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
954 "4. \"comment\" (string, optional) A comment\n"
955 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
956 " The fee will be equally deducted from the amount of each selected address.\n"
957 " Those recipients will receive less zcashs than you enter in their corresponding amount field.\n"
958 " If no addresses are specified here, the sender pays the fee.\n"
960 " \"address\" (string) Subtract fee from this address\n"
964 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
965 " the number of addresses.\n"
967 "\nSend two amounts to two different addresses:\n"
968 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
969 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
970 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
971 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
972 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\",\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
973 "\nAs a json rpc call\n"
974 + HelpExampleRpc("sendmany", "\"\", \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
977 LOCK2(cs_main, pwalletMain->cs_wallet);
979 string strAccount = AccountFromValue(params[0]);
980 UniValue sendTo = params[1].get_obj();
982 if (params.size() > 2)
983 nMinDepth = params[2].get_int();
986 wtx.strFromAccount = strAccount;
987 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
988 wtx.mapValue["comment"] = params[3].get_str();
990 UniValue subtractFeeFromAmount(UniValue::VARR);
991 if (params.size() > 4)
992 subtractFeeFromAmount = params[4].get_array();
994 set<CBitcoinAddress> setAddress;
995 vector<CRecipient> vecSend;
997 CAmount totalAmount = 0;
998 vector<string> keys = sendTo.getKeys();
999 BOOST_FOREACH(const string& name_, keys)
1001 CBitcoinAddress address(name_);
1002 if (!address.IsValid())
1003 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+name_);
1005 if (setAddress.count(address))
1006 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
1007 setAddress.insert(address);
1009 CScript scriptPubKey = GetScriptForDestination(address.Get());
1010 CAmount nAmount = AmountFromValue(sendTo[name_]);
1012 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1013 totalAmount += nAmount;
1015 bool fSubtractFeeFromAmount = false;
1016 for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
1017 const UniValue& addr = subtractFeeFromAmount[idx];
1018 if (addr.get_str() == name_)
1019 fSubtractFeeFromAmount = true;
1022 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1023 vecSend.push_back(recipient);
1026 EnsureWalletIsUnlocked();
1029 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
1030 if (totalAmount > nBalance)
1031 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
1034 CReserveKey keyChange(pwalletMain);
1035 CAmount nFeeRequired = 0;
1036 int nChangePosRet = -1;
1037 string strFailReason;
1038 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
1040 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
1041 if (!pwalletMain->CommitTransaction(wtx, keyChange))
1042 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
1044 return wtx.GetHash().GetHex();
1047 // Defined in rpcmisc.cpp
1048 extern CScript _createmultisig_redeemScript(const UniValue& params);
1050 UniValue addmultisigaddress(const UniValue& params, bool fHelp)
1052 if (!EnsureWalletIsAvailable(fHelp))
1053 return NullUniValue;
1055 if (fHelp || params.size() < 2 || params.size() > 3)
1057 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1058 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
1059 "Each key is a Zcash address or hex-encoded public key.\n"
1060 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
1063 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
1064 "2. \"keysobject\" (string, required) A json array of zcash addresses or hex-encoded public keys\n"
1066 " \"address\" (string) zcash address or hex-encoded public key\n"
1069 "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"
1072 "\"zcashaddress\" (string) A zcash address associated with the keys.\n"
1075 "\nAdd a multisig address from 2 addresses\n"
1076 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
1077 "\nAs json rpc call\n"
1078 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
1080 throw runtime_error(msg);
1083 LOCK2(cs_main, pwalletMain->cs_wallet);
1086 if (params.size() > 2)
1087 strAccount = AccountFromValue(params[2]);
1089 // Construct using pay-to-script-hash:
1090 CScript inner = _createmultisig_redeemScript(params);
1091 CScriptID innerID(inner);
1092 pwalletMain->AddCScript(inner);
1094 pwalletMain->SetAddressBook(innerID, strAccount, "send");
1095 return CBitcoinAddress(innerID).ToString();
1103 vector<uint256> txids;
1108 nConf = std::numeric_limits<int>::max();
1109 fIsWatchonly = false;
1113 UniValue ListReceived(const UniValue& params, bool fByAccounts)
1115 // Minimum confirmations
1117 if (params.size() > 0)
1118 nMinDepth = params[0].get_int();
1120 // Whether to include empty accounts
1121 bool fIncludeEmpty = false;
1122 if (params.size() > 1)
1123 fIncludeEmpty = params[1].get_bool();
1125 isminefilter filter = ISMINE_SPENDABLE;
1126 if(params.size() > 2)
1127 if(params[2].get_bool())
1128 filter = filter | ISMINE_WATCH_ONLY;
1131 map<CBitcoinAddress, tallyitem> mapTally;
1132 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1134 const CWalletTx& wtx = (*it).second;
1136 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
1139 int nDepth = wtx.GetDepthInMainChain();
1140 if (nDepth < nMinDepth)
1143 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1145 CTxDestination address;
1146 if (!ExtractDestination(txout.scriptPubKey, address))
1149 isminefilter mine = IsMine(*pwalletMain, address);
1150 if(!(mine & filter))
1153 tallyitem& item = mapTally[address];
1154 item.nAmount += txout.nValue;
1155 item.nConf = min(item.nConf, nDepth);
1156 item.txids.push_back(wtx.GetHash());
1157 if (mine & ISMINE_WATCH_ONLY)
1158 item.fIsWatchonly = true;
1163 UniValue ret(UniValue::VARR);
1164 map<string, tallyitem> mapAccountTally;
1165 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
1167 const CBitcoinAddress& address = item.first;
1168 const string& strAccount = item.second.name;
1169 map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
1170 if (it == mapTally.end() && !fIncludeEmpty)
1173 CAmount nAmount = 0;
1174 int nConf = std::numeric_limits<int>::max();
1175 bool fIsWatchonly = false;
1176 if (it != mapTally.end())
1178 nAmount = (*it).second.nAmount;
1179 nConf = (*it).second.nConf;
1180 fIsWatchonly = (*it).second.fIsWatchonly;
1185 tallyitem& item = mapAccountTally[strAccount];
1186 item.nAmount += nAmount;
1187 item.nConf = min(item.nConf, nConf);
1188 item.fIsWatchonly = fIsWatchonly;
1192 UniValue obj(UniValue::VOBJ);
1194 obj.push_back(Pair("involvesWatchonly", true));
1195 obj.push_back(Pair("address", address.ToString()));
1196 obj.push_back(Pair("account", strAccount));
1197 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1198 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1199 UniValue transactions(UniValue::VARR);
1200 if (it != mapTally.end())
1202 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1204 transactions.push_back(item.GetHex());
1207 obj.push_back(Pair("txids", transactions));
1214 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1216 CAmount nAmount = (*it).second.nAmount;
1217 int nConf = (*it).second.nConf;
1218 UniValue obj(UniValue::VOBJ);
1219 if((*it).second.fIsWatchonly)
1220 obj.push_back(Pair("involvesWatchonly", true));
1221 obj.push_back(Pair("account", (*it).first));
1222 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1223 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1231 UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
1233 if (!EnsureWalletIsAvailable(fHelp))
1234 return NullUniValue;
1236 if (fHelp || params.size() > 3)
1237 throw runtime_error(
1238 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
1239 "\nList balances by receiving address.\n"
1241 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1242 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
1243 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1248 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1249 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
1250 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
1251 " \"amount\" : x.xxx, (numeric) The total amount in btc received by the address\n"
1252 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1258 + HelpExampleCli("listreceivedbyaddress", "")
1259 + HelpExampleCli("listreceivedbyaddress", "6 true")
1260 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1263 LOCK2(cs_main, pwalletMain->cs_wallet);
1265 return ListReceived(params, false);
1268 UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
1270 if (!EnsureWalletIsAvailable(fHelp))
1271 return NullUniValue;
1273 if (fHelp || params.size() > 3)
1274 throw runtime_error(
1275 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
1276 "\nDEPRECATED. List balances by account.\n"
1278 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1279 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
1280 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
1285 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
1286 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1287 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1288 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1294 + HelpExampleCli("listreceivedbyaccount", "")
1295 + HelpExampleCli("listreceivedbyaccount", "6 true")
1296 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
1299 LOCK2(cs_main, pwalletMain->cs_wallet);
1301 return ListReceived(params, true);
1304 static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
1306 CBitcoinAddress addr;
1308 entry.push_back(Pair("address", addr.ToString()));
1311 void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
1314 string strSentAccount;
1315 list<COutputEntry> listReceived;
1316 list<COutputEntry> listSent;
1318 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
1320 bool fAllAccounts = (strAccount == string("*"));
1321 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
1324 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1326 BOOST_FOREACH(const COutputEntry& s, listSent)
1328 UniValue entry(UniValue::VOBJ);
1329 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
1330 entry.push_back(Pair("involvesWatchonly", true));
1331 entry.push_back(Pair("account", strSentAccount));
1332 MaybePushAddress(entry, s.destination);
1333 entry.push_back(Pair("category", "send"));
1334 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1335 entry.push_back(Pair("vout", s.vout));
1336 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1338 WalletTxToJSON(wtx, entry);
1339 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1340 ret.push_back(entry);
1345 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1347 BOOST_FOREACH(const COutputEntry& r, listReceived)
1350 if (pwalletMain->mapAddressBook.count(r.destination))
1351 account = pwalletMain->mapAddressBook[r.destination].name;
1352 if (fAllAccounts || (account == strAccount))
1354 UniValue entry(UniValue::VOBJ);
1355 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
1356 entry.push_back(Pair("involvesWatchonly", true));
1357 entry.push_back(Pair("account", account));
1358 MaybePushAddress(entry, r.destination);
1359 if (wtx.IsCoinBase())
1361 if (wtx.GetDepthInMainChain() < 1)
1362 entry.push_back(Pair("category", "orphan"));
1363 else if (wtx.GetBlocksToMaturity() > 0)
1364 entry.push_back(Pair("category", "immature"));
1366 entry.push_back(Pair("category", "generate"));
1370 entry.push_back(Pair("category", "receive"));
1372 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1373 entry.push_back(Pair("vout", r.vout));
1375 WalletTxToJSON(wtx, entry);
1376 entry.push_back(Pair("size", static_cast<CTransaction>(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)));
1377 ret.push_back(entry);
1383 void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
1385 bool fAllAccounts = (strAccount == string("*"));
1387 if (fAllAccounts || acentry.strAccount == strAccount)
1389 UniValue entry(UniValue::VOBJ);
1390 entry.push_back(Pair("account", acentry.strAccount));
1391 entry.push_back(Pair("category", "move"));
1392 entry.push_back(Pair("time", acentry.nTime));
1393 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1394 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1395 entry.push_back(Pair("comment", acentry.strComment));
1396 ret.push_back(entry);
1400 UniValue listtransactions(const UniValue& params, bool fHelp)
1402 if (!EnsureWalletIsAvailable(fHelp))
1403 return NullUniValue;
1405 if (fHelp || params.size() > 4)
1406 throw runtime_error(
1407 "listtransactions ( \"account\" count from includeWatchonly)\n"
1408 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1410 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
1411 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1412 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
1413 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
1417 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
1418 " It will be \"\" for the default account.\n"
1419 " \"address\":\"zcashaddress\", (string) The zcash address of the transaction. Not present for \n"
1420 " move transactions (category = move).\n"
1421 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1422 " transaction between accounts, and not associated with an address,\n"
1423 " transaction id or block. 'send' and 'receive' transactions are \n"
1424 " associated with an address, transaction id and block details\n"
1425 " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the\n"
1426 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1427 " and for the 'move' category for inbound funds.\n"
1428 " \"vout\" : n, (numeric) the vout value\n"
1429 " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the \n"
1430 " 'send' category of transactions.\n"
1431 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1432 " 'receive' category of transactions.\n"
1433 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1434 " category of transactions.\n"
1435 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1436 " category of transactions.\n"
1437 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1438 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1439 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1440 " for 'send' and 'receive' category of transactions.\n"
1441 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1442 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1443 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1444 " negative amounts).\n"
1445 " \"size\": n, (numeric) Transaction size in bytes\n"
1450 "\nList the most recent 10 transactions in the systems\n"
1451 + HelpExampleCli("listtransactions", "") +
1452 "\nList transactions 100 to 120\n"
1453 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
1454 "\nAs a json rpc call\n"
1455 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
1458 LOCK2(cs_main, pwalletMain->cs_wallet);
1460 string strAccount = "*";
1461 if (params.size() > 0)
1462 strAccount = params[0].get_str();
1464 if (params.size() > 1)
1465 nCount = params[1].get_int();
1467 if (params.size() > 2)
1468 nFrom = params[2].get_int();
1469 isminefilter filter = ISMINE_SPENDABLE;
1470 if(params.size() > 3)
1471 if(params[3].get_bool())
1472 filter = filter | ISMINE_WATCH_ONLY;
1475 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1477 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1479 UniValue ret(UniValue::VARR);
1481 std::list<CAccountingEntry> acentries;
1482 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
1484 // iterate backwards until we have nCount items to return:
1485 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1487 CWalletTx *const pwtx = (*it).second.first;
1489 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
1490 CAccountingEntry *const pacentry = (*it).second.second;
1492 AcentryToJSON(*pacentry, strAccount, ret);
1494 if ((int)ret.size() >= (nCount+nFrom)) break;
1496 // ret is newest to oldest
1498 if (nFrom > (int)ret.size())
1500 if ((nFrom + nCount) > (int)ret.size())
1501 nCount = ret.size() - nFrom;
1503 vector<UniValue> arrTmp = ret.getValues();
1505 vector<UniValue>::iterator first = arrTmp.begin();
1506 std::advance(first, nFrom);
1507 vector<UniValue>::iterator last = arrTmp.begin();
1508 std::advance(last, nFrom+nCount);
1510 if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
1511 if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
1513 std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
1517 ret.push_backV(arrTmp);
1522 UniValue listaccounts(const UniValue& params, bool fHelp)
1524 if (!EnsureWalletIsAvailable(fHelp))
1525 return NullUniValue;
1527 if (fHelp || params.size() > 2)
1528 throw runtime_error(
1529 "listaccounts ( minconf includeWatchonly)\n"
1530 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
1532 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
1533 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
1535 "{ (json object where keys are account names, and values are numeric balances\n"
1536 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1540 "\nList account balances where there at least 1 confirmation\n"
1541 + HelpExampleCli("listaccounts", "") +
1542 "\nList account balances including zero confirmation transactions\n"
1543 + HelpExampleCli("listaccounts", "0") +
1544 "\nList account balances for 6 or more confirmations\n"
1545 + HelpExampleCli("listaccounts", "6") +
1546 "\nAs json rpc call\n"
1547 + HelpExampleRpc("listaccounts", "6")
1550 LOCK2(cs_main, pwalletMain->cs_wallet);
1553 if (params.size() > 0)
1554 nMinDepth = params[0].get_int();
1555 isminefilter includeWatchonly = ISMINE_SPENDABLE;
1556 if(params.size() > 1)
1557 if(params[1].get_bool())
1558 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
1560 map<string, CAmount> mapAccountBalances;
1561 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
1562 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
1563 mapAccountBalances[entry.second.name] = 0;
1566 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1568 const CWalletTx& wtx = (*it).second;
1570 string strSentAccount;
1571 list<COutputEntry> listReceived;
1572 list<COutputEntry> listSent;
1573 int nDepth = wtx.GetDepthInMainChain();
1574 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
1576 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
1577 mapAccountBalances[strSentAccount] -= nFee;
1578 BOOST_FOREACH(const COutputEntry& s, listSent)
1579 mapAccountBalances[strSentAccount] -= s.amount;
1580 if (nDepth >= nMinDepth)
1582 BOOST_FOREACH(const COutputEntry& r, listReceived)
1583 if (pwalletMain->mapAddressBook.count(r.destination))
1584 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
1586 mapAccountBalances[""] += r.amount;
1590 list<CAccountingEntry> acentries;
1591 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1592 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1593 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1595 UniValue ret(UniValue::VOBJ);
1596 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
1597 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1602 UniValue listsinceblock(const UniValue& params, bool fHelp)
1604 if (!EnsureWalletIsAvailable(fHelp))
1605 return NullUniValue;
1608 throw runtime_error(
1609 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
1610 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1612 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1613 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
1614 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
1617 " \"transactions\": [\n"
1618 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
1619 " \"address\":\"zcashaddress\", (string) The zcash address of the transaction. Not present for move transactions (category = move).\n"
1620 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
1621 " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n"
1622 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1623 " \"vout\" : n, (numeric) the vout value\n"
1624 " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the 'send' category of transactions.\n"
1625 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1626 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1627 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1628 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
1629 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
1630 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1631 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1632 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1633 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1635 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1638 + HelpExampleCli("listsinceblock", "")
1639 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1640 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1643 LOCK2(cs_main, pwalletMain->cs_wallet);
1645 CBlockIndex *pindex = NULL;
1646 int target_confirms = 1;
1647 isminefilter filter = ISMINE_SPENDABLE;
1649 if (params.size() > 0)
1653 blockId.SetHex(params[0].get_str());
1654 BlockMap::iterator it = mapBlockIndex.find(blockId);
1655 if (it != mapBlockIndex.end())
1656 pindex = it->second;
1659 if (params.size() > 1)
1661 target_confirms = params[1].get_int();
1663 if (target_confirms < 1)
1664 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1667 if(params.size() > 2)
1668 if(params[2].get_bool())
1669 filter = filter | ISMINE_WATCH_ONLY;
1671 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
1673 UniValue transactions(UniValue::VARR);
1675 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1677 CWalletTx tx = (*it).second;
1679 if (depth == -1 || tx.GetDepthInMainChain() < depth)
1680 ListTransactions(tx, "*", 0, true, transactions, filter);
1683 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
1684 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
1686 UniValue ret(UniValue::VOBJ);
1687 ret.push_back(Pair("transactions", transactions));
1688 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1693 UniValue gettransaction(const UniValue& params, bool fHelp)
1695 if (!EnsureWalletIsAvailable(fHelp))
1696 return NullUniValue;
1698 if (fHelp || params.size() < 1 || params.size() > 2)
1699 throw runtime_error(
1700 "gettransaction \"txid\" ( includeWatchonly )\n"
1701 "\nGet detailed information about in-wallet transaction <txid>\n"
1703 "1. \"txid\" (string, required) The transaction id\n"
1704 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
1707 " \"amount\" : x.xxx, (numeric) The transaction amount in btc\n"
1708 " \"confirmations\" : n, (numeric) The number of confirmations\n"
1709 " \"blockhash\" : \"hash\", (string) The block hash\n"
1710 " \"blockindex\" : xx, (numeric) The block index\n"
1711 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
1712 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
1713 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1714 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1715 " \"details\" : [\n"
1717 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
1718 " \"address\" : \"zcashaddress\", (string) The zcash address involved in the transaction\n"
1719 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
1720 " \"amount\" : x.xxx (numeric) The amount in btc\n"
1721 " \"vout\" : n, (numeric) the vout value\n"
1725 " \"vjoinsplit\" : [\n"
1727 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
1728 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
1729 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
1730 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
1731 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
1732 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
1736 " \"hex\" : \"data\" (string) Raw data for transaction\n"
1740 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1741 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
1742 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1745 LOCK2(cs_main, pwalletMain->cs_wallet);
1748 hash.SetHex(params[0].get_str());
1750 isminefilter filter = ISMINE_SPENDABLE;
1751 if(params.size() > 1)
1752 if(params[1].get_bool())
1753 filter = filter | ISMINE_WATCH_ONLY;
1755 UniValue entry(UniValue::VOBJ);
1756 if (!pwalletMain->mapWallet.count(hash))
1757 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1758 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1760 CAmount nCredit = wtx.GetCredit(filter);
1761 CAmount nDebit = wtx.GetDebit(filter);
1762 CAmount nNet = nCredit - nDebit;
1763 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
1765 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
1766 if (wtx.IsFromMe(filter))
1767 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1769 WalletTxToJSON(wtx, entry);
1771 UniValue details(UniValue::VARR);
1772 ListTransactions(wtx, "*", 0, false, details, filter);
1773 entry.push_back(Pair("details", details));
1775 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
1776 entry.push_back(Pair("hex", strHex));
1782 UniValue backupwallet(const UniValue& params, bool fHelp)
1784 if (!EnsureWalletIsAvailable(fHelp))
1785 return NullUniValue;
1787 if (fHelp || params.size() != 1)
1788 throw runtime_error(
1789 "backupwallet \"destination\"\n"
1790 "\nSafely copies wallet.dat to destination filename\n"
1792 "1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
1794 "\"path\" (string) The full path of the destination file\n"
1796 + HelpExampleCli("backupwallet", "\"backupdata\"")
1797 + HelpExampleRpc("backupwallet", "\"backupdata\"")
1800 LOCK2(cs_main, pwalletMain->cs_wallet);
1802 boost::filesystem::path exportdir;
1804 exportdir = GetExportDir();
1805 } catch (const std::runtime_error& e) {
1806 throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
1808 if (exportdir.empty()) {
1809 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
1811 std::string unclean = params[0].get_str();
1812 std::string clean = SanitizeFilename(unclean);
1813 if (clean.compare(unclean) != 0) {
1814 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
1816 boost::filesystem::path exportfilepath = exportdir / clean;
1818 if (!BackupWallet(*pwalletMain, exportfilepath.string()))
1819 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1821 return exportfilepath.string();
1825 UniValue keypoolrefill(const UniValue& params, bool fHelp)
1827 if (!EnsureWalletIsAvailable(fHelp))
1828 return NullUniValue;
1830 if (fHelp || params.size() > 1)
1831 throw runtime_error(
1832 "keypoolrefill ( newsize )\n"
1833 "\nFills the keypool."
1834 + HelpRequiringPassphrase() + "\n"
1836 "1. newsize (numeric, optional, default=100) The new keypool size\n"
1838 + HelpExampleCli("keypoolrefill", "")
1839 + HelpExampleRpc("keypoolrefill", "")
1842 LOCK2(cs_main, pwalletMain->cs_wallet);
1844 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1845 unsigned int kpSize = 0;
1846 if (params.size() > 0) {
1847 if (params[0].get_int() < 0)
1848 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1849 kpSize = (unsigned int)params[0].get_int();
1852 EnsureWalletIsUnlocked();
1853 pwalletMain->TopUpKeyPool(kpSize);
1855 if (pwalletMain->GetKeyPoolSize() < kpSize)
1856 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1858 return NullUniValue;
1862 static void LockWallet(CWallet* pWallet)
1864 LOCK(cs_nWalletUnlockTime);
1865 nWalletUnlockTime = 0;
1869 UniValue walletpassphrase(const UniValue& params, bool fHelp)
1871 if (!EnsureWalletIsAvailable(fHelp))
1872 return NullUniValue;
1874 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1875 throw runtime_error(
1876 "walletpassphrase \"passphrase\" timeout\n"
1877 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
1878 "This is needed prior to performing transactions related to private keys such as sending zcash\n"
1880 "1. \"passphrase\" (string, required) The wallet passphrase\n"
1881 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
1883 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
1884 "time that overrides the old one.\n"
1886 "\nunlock the wallet for 60 seconds\n"
1887 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1888 "\nLock the wallet again (before 60 seconds)\n"
1889 + HelpExampleCli("walletlock", "") +
1890 "\nAs json rpc call\n"
1891 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1894 LOCK2(cs_main, pwalletMain->cs_wallet);
1898 if (!pwalletMain->IsCrypted())
1899 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1901 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1902 SecureString strWalletPass;
1903 strWalletPass.reserve(100);
1904 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1905 // Alternately, find a way to make params[0] mlock()'d to begin with.
1906 strWalletPass = params[0].get_str().c_str();
1908 if (strWalletPass.length() > 0)
1910 if (!pwalletMain->Unlock(strWalletPass))
1911 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1914 throw runtime_error(
1915 "walletpassphrase <passphrase> <timeout>\n"
1916 "Stores the wallet decryption key in memory for <timeout> seconds.");
1918 // No need to check return values, because the wallet was unlocked above
1919 pwalletMain->UpdateNullifierNoteMap();
1920 pwalletMain->TopUpKeyPool();
1922 int64_t nSleepTime = params[1].get_int64();
1923 LOCK(cs_nWalletUnlockTime);
1924 nWalletUnlockTime = GetTime() + nSleepTime;
1925 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
1927 return NullUniValue;
1931 UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
1933 if (!EnsureWalletIsAvailable(fHelp))
1934 return NullUniValue;
1936 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1937 throw runtime_error(
1938 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
1939 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
1941 "1. \"oldpassphrase\" (string) The current passphrase\n"
1942 "2. \"newpassphrase\" (string) The new passphrase\n"
1944 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
1945 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
1948 LOCK2(cs_main, pwalletMain->cs_wallet);
1952 if (!pwalletMain->IsCrypted())
1953 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
1955 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1956 // Alternately, find a way to make params[0] mlock()'d to begin with.
1957 SecureString strOldWalletPass;
1958 strOldWalletPass.reserve(100);
1959 strOldWalletPass = params[0].get_str().c_str();
1961 SecureString strNewWalletPass;
1962 strNewWalletPass.reserve(100);
1963 strNewWalletPass = params[1].get_str().c_str();
1965 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1966 throw runtime_error(
1967 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1968 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1970 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
1971 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1973 return NullUniValue;
1977 UniValue walletlock(const UniValue& params, bool fHelp)
1979 if (!EnsureWalletIsAvailable(fHelp))
1980 return NullUniValue;
1982 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
1983 throw runtime_error(
1985 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
1986 "After calling this method, you will need to call walletpassphrase again\n"
1987 "before being able to call any methods which require the wallet to be unlocked.\n"
1989 "\nSet the passphrase for 2 minutes to perform a transaction\n"
1990 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
1991 "\nPerform a send (requires passphrase set)\n"
1992 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
1993 "\nClear the passphrase since we are done before 2 minutes is up\n"
1994 + HelpExampleCli("walletlock", "") +
1995 "\nAs json rpc call\n"
1996 + HelpExampleRpc("walletlock", "")
1999 LOCK2(cs_main, pwalletMain->cs_wallet);
2003 if (!pwalletMain->IsCrypted())
2004 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
2007 LOCK(cs_nWalletUnlockTime);
2008 pwalletMain->Lock();
2009 nWalletUnlockTime = 0;
2012 return NullUniValue;
2016 UniValue encryptwallet(const UniValue& params, bool fHelp)
2018 if (!EnsureWalletIsAvailable(fHelp))
2019 return NullUniValue;
2021 auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-developerencryptwallet", false);
2023 std::string strWalletEncryptionDisabledMsg = "";
2024 if (!fEnableWalletEncryption) {
2025 strWalletEncryptionDisabledMsg = "\nWARNING: Wallet encryption is DISABLED. This call always fails.\n";
2028 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2029 throw runtime_error(
2030 "encryptwallet \"passphrase\"\n"
2031 + strWalletEncryptionDisabledMsg +
2032 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2033 "After this, any calls that interact with private keys such as sending or signing \n"
2034 "will require the passphrase to be set prior the making these calls.\n"
2035 "Use the walletpassphrase call for this, and then walletlock call.\n"
2036 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2037 "Note that this will shutdown the server.\n"
2039 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2041 "\nEncrypt you wallet\n"
2042 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
2043 "\nNow set the passphrase to use the wallet, such as for signing or sending zcash\n"
2044 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2045 "\nNow we can so something like sign\n"
2046 + HelpExampleCli("signmessage", "\"zcashaddress\" \"test message\"") +
2047 "\nNow lock the wallet again by removing the passphrase\n"
2048 + HelpExampleCli("walletlock", "") +
2049 "\nAs a json rpc call\n"
2050 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2053 LOCK2(cs_main, pwalletMain->cs_wallet);
2057 if (!fEnableWalletEncryption) {
2058 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
2060 if (pwalletMain->IsCrypted())
2061 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
2063 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2064 // Alternately, find a way to make params[0] mlock()'d to begin with.
2065 SecureString strWalletPass;
2066 strWalletPass.reserve(100);
2067 strWalletPass = params[0].get_str().c_str();
2069 if (strWalletPass.length() < 1)
2070 throw runtime_error(
2071 "encryptwallet <passphrase>\n"
2072 "Encrypts the wallet with <passphrase>.");
2074 if (!pwalletMain->EncryptWallet(strWalletPass))
2075 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
2077 // BDB seems to have a bad habit of writing old data into
2078 // slack space in .dat files; that is bad if the old data is
2079 // unencrypted private keys. So:
2081 return "wallet encrypted; Zcash server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
2084 UniValue lockunspent(const UniValue& params, bool fHelp)
2086 if (!EnsureWalletIsAvailable(fHelp))
2087 return NullUniValue;
2089 if (fHelp || params.size() < 1 || params.size() > 2)
2090 throw runtime_error(
2091 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2092 "\nUpdates list of temporarily unspendable outputs.\n"
2093 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
2094 "A locked transaction output will not be chosen by automatic coin selection, when spending zcash.\n"
2095 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2096 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2097 "Also see the listunspent call\n"
2099 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2100 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2101 " [ (json array of json objects)\n"
2103 " \"txid\":\"id\", (string) The transaction id\n"
2104 " \"vout\": n (numeric) The output number\n"
2110 "true|false (boolean) Whether the command was successful or not\n"
2113 "\nList the unspent transactions\n"
2114 + HelpExampleCli("listunspent", "") +
2115 "\nLock an unspent transaction\n"
2116 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2117 "\nList the locked transactions\n"
2118 + HelpExampleCli("listlockunspent", "") +
2119 "\nUnlock the transaction again\n"
2120 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2121 "\nAs a json rpc call\n"
2122 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2125 LOCK2(cs_main, pwalletMain->cs_wallet);
2127 if (params.size() == 1)
2128 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
2130 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
2132 bool fUnlock = params[0].get_bool();
2134 if (params.size() == 1) {
2136 pwalletMain->UnlockAllCoins();
2140 UniValue outputs = params[1].get_array();
2141 for (size_t idx = 0; idx < outputs.size(); idx++) {
2142 const UniValue& output = outputs[idx];
2143 if (!output.isObject())
2144 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
2145 const UniValue& o = output.get_obj();
2147 RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
2149 string txid = find_value(o, "txid").get_str();
2151 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
2153 int nOutput = find_value(o, "vout").get_int();
2155 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
2157 COutPoint outpt(uint256S(txid), nOutput);
2160 pwalletMain->UnlockCoin(outpt);
2162 pwalletMain->LockCoin(outpt);
2168 UniValue listlockunspent(const UniValue& params, bool fHelp)
2170 if (!EnsureWalletIsAvailable(fHelp))
2171 return NullUniValue;
2173 if (fHelp || params.size() > 0)
2174 throw runtime_error(
2176 "\nReturns list of temporarily unspendable outputs.\n"
2177 "See the lockunspent call to lock and unlock transactions for spending.\n"
2181 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2182 " \"vout\" : n (numeric) The vout value\n"
2187 "\nList the unspent transactions\n"
2188 + HelpExampleCli("listunspent", "") +
2189 "\nLock an unspent transaction\n"
2190 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2191 "\nList the locked transactions\n"
2192 + HelpExampleCli("listlockunspent", "") +
2193 "\nUnlock the transaction again\n"
2194 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2195 "\nAs a json rpc call\n"
2196 + HelpExampleRpc("listlockunspent", "")
2199 LOCK2(cs_main, pwalletMain->cs_wallet);
2201 vector<COutPoint> vOutpts;
2202 pwalletMain->ListLockedCoins(vOutpts);
2204 UniValue ret(UniValue::VARR);
2206 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
2207 UniValue o(UniValue::VOBJ);
2209 o.push_back(Pair("txid", outpt.hash.GetHex()));
2210 o.push_back(Pair("vout", (int)outpt.n));
2217 UniValue settxfee(const UniValue& params, bool fHelp)
2219 if (!EnsureWalletIsAvailable(fHelp))
2220 return NullUniValue;
2222 if (fHelp || params.size() < 1 || params.size() > 1)
2223 throw runtime_error(
2225 "\nSet the transaction fee per kB.\n"
2227 "1. amount (numeric, required) The transaction fee in BTC/kB rounded to the nearest 0.00000001\n"
2229 "true|false (boolean) Returns true if successful\n"
2231 + HelpExampleCli("settxfee", "0.00001")
2232 + HelpExampleRpc("settxfee", "0.00001")
2235 LOCK2(cs_main, pwalletMain->cs_wallet);
2238 CAmount nAmount = AmountFromValue(params[0]);
2240 payTxFee = CFeeRate(nAmount, 1000);
2244 UniValue getwalletinfo(const UniValue& params, bool fHelp)
2246 if (!EnsureWalletIsAvailable(fHelp))
2247 return NullUniValue;
2249 if (fHelp || params.size() != 0)
2250 throw runtime_error(
2252 "Returns an object containing various wallet state info.\n"
2255 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
2256 " \"balance\": xxxxxxx, (numeric) the total confirmed zcash balance of the wallet\n"
2257 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed zcash balance of the wallet\n"
2258 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet\n"
2259 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2260 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2261 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2262 " \"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"
2263 " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in ZEC/KB\n"
2266 + HelpExampleCli("getwalletinfo", "")
2267 + HelpExampleRpc("getwalletinfo", "")
2270 LOCK2(cs_main, pwalletMain->cs_wallet);
2272 UniValue obj(UniValue::VOBJ);
2273 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2274 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
2275 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2276 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
2277 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
2278 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
2279 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2280 if (pwalletMain->IsCrypted())
2281 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
2282 obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
2286 UniValue resendwallettransactions(const UniValue& params, bool fHelp)
2288 if (!EnsureWalletIsAvailable(fHelp))
2289 return NullUniValue;
2291 if (fHelp || params.size() != 0)
2292 throw runtime_error(
2293 "resendwallettransactions\n"
2294 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2295 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2297 "Returns array of transaction ids that were re-broadcast.\n"
2300 LOCK2(cs_main, pwalletMain->cs_wallet);
2302 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
2303 UniValue result(UniValue::VARR);
2304 BOOST_FOREACH(const uint256& txid, txids)
2306 result.push_back(txid.ToString());
2311 UniValue listunspent(const UniValue& params, bool fHelp)
2313 if (!EnsureWalletIsAvailable(fHelp))
2314 return NullUniValue;
2316 if (fHelp || params.size() > 3)
2317 throw runtime_error(
2318 "listunspent ( minconf maxconf [\"address\",...] )\n"
2319 "\nReturns array of unspent transaction outputs\n"
2320 "with between minconf and maxconf (inclusive) confirmations.\n"
2321 "Optionally filter to only include txouts paid to specified addresses.\n"
2322 "Results are an array of Objects, each of which has:\n"
2323 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2325 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2326 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
2327 "3. \"addresses\" (string) A json array of zcash addresses to filter\n"
2329 " \"address\" (string) zcash address\n"
2333 "[ (array of json object)\n"
2335 " \"txid\" : \"txid\", (string) the transaction id \n"
2336 " \"vout\" : n, (numeric) the vout value\n"
2337 " \"address\" : \"address\", (string) the zcash address\n"
2338 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2339 " \"scriptPubKey\" : \"key\", (string) the script key\n"
2340 " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n"
2341 " \"confirmations\" : n (numeric) The number of confirmations\n"
2347 + HelpExampleCli("listunspent", "")
2348 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2349 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2352 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
2355 if (params.size() > 0)
2356 nMinDepth = params[0].get_int();
2358 int nMaxDepth = 9999999;
2359 if (params.size() > 1)
2360 nMaxDepth = params[1].get_int();
2362 set<CBitcoinAddress> setAddress;
2363 if (params.size() > 2) {
2364 UniValue inputs = params[2].get_array();
2365 for (size_t idx = 0; idx < inputs.size(); idx++) {
2366 const UniValue& input = inputs[idx];
2367 CBitcoinAddress address(input.get_str());
2368 if (!address.IsValid())
2369 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Zcash address: ")+input.get_str());
2370 if (setAddress.count(address))
2371 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
2372 setAddress.insert(address);
2376 UniValue results(UniValue::VARR);
2377 vector<COutput> vecOutputs;
2378 assert(pwalletMain != NULL);
2379 LOCK2(cs_main, pwalletMain->cs_wallet);
2380 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2381 BOOST_FOREACH(const COutput& out, vecOutputs) {
2382 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
2385 if (setAddress.size()) {
2386 CTxDestination address;
2387 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
2390 if (!setAddress.count(address))
2394 CAmount nValue = out.tx->vout[out.i].nValue;
2395 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
2396 UniValue entry(UniValue::VOBJ);
2397 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
2398 entry.push_back(Pair("vout", out.i));
2399 CTxDestination address;
2400 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
2401 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
2402 if (pwalletMain->mapAddressBook.count(address))
2403 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
2405 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
2406 if (pk.IsPayToScriptHash()) {
2407 CTxDestination address;
2408 if (ExtractDestination(pk, address)) {
2409 const CScriptID& hash = boost::get<CScriptID>(address);
2410 CScript redeemScript;
2411 if (pwalletMain->GetCScript(hash, redeemScript))
2412 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
2415 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
2416 entry.push_back(Pair("confirmations",out.nDepth));
2417 entry.push_back(Pair("spendable", out.fSpendable));
2418 results.push_back(entry);
2424 UniValue fundrawtransaction(const UniValue& params, bool fHelp)
2426 if (!EnsureWalletIsAvailable(fHelp))
2427 return NullUniValue;
2429 if (fHelp || params.size() != 1)
2430 throw runtime_error(
2431 "fundrawtransaction \"hexstring\"\n"
2432 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
2433 "This will not modify existing inputs, and will add one change output to the outputs.\n"
2434 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
2435 "The inputs added will not be signed, use signrawtransaction for that.\n"
2437 "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
2440 " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
2441 " \"fee\": n, (numeric) The fee added to the transaction\n"
2442 " \"changepos\": n (numeric) The position of the added change output, or -1\n"
2446 "\nCreate a transaction with no inputs\n"
2447 + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
2448 "\nAdd sufficient unsigned inputs to meet the output value\n"
2449 + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
2450 "\nSign the transaction\n"
2451 + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
2452 "\nSend the transaction\n"
2453 + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
2456 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
2458 // parse hex string from parameter
2459 CTransaction origTx;
2460 if (!DecodeHexTx(origTx, params[0].get_str()))
2461 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2463 CMutableTransaction tx(origTx);
2465 string strFailReason;
2466 int nChangePos = -1;
2467 if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
2468 throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
2470 UniValue result(UniValue::VOBJ);
2471 result.push_back(Pair("hex", EncodeHexTx(tx)));
2472 result.push_back(Pair("changepos", nChangePos));
2473 result.push_back(Pair("fee", ValueFromAmount(nFee)));
2478 UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
2481 throw runtime_error(
2482 "zcsamplejoinsplit\n"
2484 "Perform a joinsplit and return the JSDescription.\n"
2491 uint256 anchor = ZCIncrementalMerkleTree().root();
2492 JSDescription samplejoinsplit(*pzcashParams,
2495 {JSInput(), JSInput()},
2496 {JSOutput(), JSOutput()},
2500 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2501 ss << samplejoinsplit;
2503 return HexStr(ss.begin(), ss.end());
2506 UniValue zc_benchmark(const UniValue& params, bool fHelp)
2508 if (!EnsureWalletIsAvailable(fHelp)) {
2509 return NullUniValue;
2512 if (fHelp || params.size() < 2) {
2513 throw runtime_error(
2514 "zcbenchmark benchmarktype samplecount\n"
2516 "Runs a benchmark of the selected type samplecount times,\n"
2517 "returning the running times of each sample.\n"
2521 " \"runningtime\": runningtime\n"
2524 " \"runningtime\": runningtime\n"
2533 std::string benchmarktype = params[0].get_str();
2534 int samplecount = params[1].get_int();
2536 if (samplecount <= 0) {
2537 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2540 std::vector<double> sample_times;
2542 if (benchmarktype == "createjoinsplit") {
2543 /* Load the proving now key so that it doesn't happen as part of the
2544 * first joinsplit. */
2545 pzcashParams->loadProvingKey();
2548 JSDescription samplejoinsplit;
2550 if (benchmarktype == "verifyjoinsplit") {
2551 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, PROTOCOL_VERSION);
2552 ss >> samplejoinsplit;
2555 for (int i = 0; i < samplecount; i++) {
2556 if (benchmarktype == "sleep") {
2557 sample_times.push_back(benchmark_sleep());
2558 } else if (benchmarktype == "parameterloading") {
2559 sample_times.push_back(benchmark_parameter_loading());
2560 } else if (benchmarktype == "createjoinsplit") {
2561 if (params.size() < 3) {
2562 sample_times.push_back(benchmark_create_joinsplit());
2564 int nThreads = params[2].get_int();
2565 std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
2566 // Divide by nThreads^2 to get average seconds per JoinSplit because
2567 // we are running one JoinSplit per thread.
2568 sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
2570 } else if (benchmarktype == "verifyjoinsplit") {
2571 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2572 #ifdef ENABLE_MINING
2573 } else if (benchmarktype == "solveequihash") {
2574 if (params.size() < 3) {
2575 sample_times.push_back(benchmark_solve_equihash());
2577 int nThreads = params[2].get_int();
2578 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
2579 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
2582 } else if (benchmarktype == "verifyequihash") {
2583 sample_times.push_back(benchmark_verify_equihash());
2584 } else if (benchmarktype == "validatelargetx") {
2585 sample_times.push_back(benchmark_large_tx());
2586 } else if (benchmarktype == "trydecryptnotes") {
2587 int nAddrs = params[2].get_int();
2588 sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
2589 } else if (benchmarktype == "incnotewitnesses") {
2590 int nTxs = params[2].get_int();
2591 sample_times.push_back(benchmark_increment_note_witnesses(nTxs));
2592 } else if (benchmarktype == "connectblockslow") {
2593 if (Params().NetworkIDString() != "regtest") {
2594 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2596 sample_times.push_back(benchmark_connectblock_slow());
2598 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2602 UniValue results(UniValue::VARR);
2603 for (auto time : sample_times) {
2604 UniValue result(UniValue::VOBJ);
2605 result.push_back(Pair("runningtime", time));
2606 results.push_back(result);
2612 UniValue zc_raw_receive(const UniValue& params, bool fHelp)
2614 if (!EnsureWalletIsAvailable(fHelp)) {
2615 return NullUniValue;
2618 if (fHelp || params.size() != 2) {
2619 throw runtime_error(
2620 "zcrawreceive zcsecretkey encryptednote\n"
2622 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
2623 "are in the blockchain as indicated by the \"exists\" result.\n"
2626 " \"amount\": value,\n"
2627 " \"note\": noteplaintext,\n"
2628 " \"exists\": exists\n"
2633 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
2637 CZCSpendingKey spendingkey(params[0].get_str());
2638 SpendingKey k = spendingkey.Get();
2641 unsigned char nonce;
2642 ZCNoteEncryption::Ciphertext ct;
2646 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
2652 } catch(const std::exception &) {
2653 throw runtime_error(
2654 "encrypted_note could not be decoded"
2659 ZCNoteDecryption decryptor(k.viewing_key());
2661 NotePlaintext npt = NotePlaintext::decrypt(
2668 PaymentAddress payment_addr = k.address();
2669 Note decrypted_note = npt.note(payment_addr);
2671 assert(pwalletMain != NULL);
2672 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2674 uint256 commitment = decrypted_note.cm();
2675 pwalletMain->WitnessNoteCommitment(
2681 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2684 UniValue result(UniValue::VOBJ);
2685 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value)));
2686 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2687 result.push_back(Pair("exists", (bool) witnesses[0]));
2693 UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
2695 if (!EnsureWalletIsAvailable(fHelp)) {
2696 return NullUniValue;
2699 if (fHelp || params.size() != 5) {
2700 throw runtime_error(
2701 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
2702 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
2703 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
2705 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
2706 "Outputs are confidential between sender/receiver. The vpub_old and\n"
2707 "vpub_new values are globally public and move transparent value into\n"
2708 "or out of the confidential value store, respectively.\n"
2710 "Note: The caller is responsible for delivering the output enc1 and\n"
2711 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
2712 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
2713 "payments in-band on the blockchain.)\n"
2716 " \"encryptednote1\": enc1,\n"
2717 " \"encryptednote2\": enc2,\n"
2718 " \"rawtxn\": rawtxout\n"
2726 if (!DecodeHexTx(tx, params[0].get_str()))
2727 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2729 UniValue inputs = params[1].get_obj();
2730 UniValue outputs = params[2].get_obj();
2732 CAmount vpub_old(0);
2733 CAmount vpub_new(0);
2735 if (params[3].get_real() != 0.0)
2736 vpub_old = AmountFromValue(params[3]);
2738 if (params[4].get_real() != 0.0)
2739 vpub_new = AmountFromValue(params[4]);
2741 std::vector<JSInput> vjsin;
2742 std::vector<JSOutput> vjsout;
2743 std::vector<Note> notes;
2744 std::vector<SpendingKey> keys;
2745 std::vector<uint256> commitments;
2747 for (const string& name_ : inputs.getKeys()) {
2748 CZCSpendingKey spendingkey(inputs[name_].get_str());
2749 SpendingKey k = spendingkey.Get();
2756 CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
2760 PaymentAddress addr = k.address();
2761 Note note = npt.note(addr);
2762 notes.push_back(note);
2763 commitments.push_back(note.cm());
2767 std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
2768 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
2770 assert(witnesses.size() == notes.size());
2771 assert(notes.size() == keys.size());
2774 for (size_t i = 0; i < witnesses.size(); i++) {
2775 if (!witnesses[i]) {
2776 throw runtime_error(
2777 "joinsplit input could not be found in tree"
2781 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
2785 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
2786 vjsin.push_back(JSInput());
2789 for (const string& name_ : outputs.getKeys()) {
2790 CZCPaymentAddress pubaddr(name_);
2791 PaymentAddress addrTo = pubaddr.Get();
2792 CAmount nAmount = AmountFromValue(outputs[name_]);
2794 vjsout.push_back(JSOutput(addrTo, nAmount));
2797 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
2798 vjsout.push_back(JSOutput());
2802 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
2803 throw runtime_error("unsupported joinsplit input/output counts");
2806 uint256 joinSplitPubKey;
2807 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
2808 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
2810 CMutableTransaction mtx(tx);
2812 mtx.joinSplitPubKey = joinSplitPubKey;
2814 JSDescription jsdesc(*pzcashParams,
2817 {vjsin[0], vjsin[1]},
2818 {vjsout[0], vjsout[1]},
2823 auto verifier = libzcash::ProofVerifier::Strict();
2824 assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
2827 mtx.vjoinsplit.push_back(jsdesc);
2829 // Empty output script.
2831 CTransaction signTx(mtx);
2832 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
2834 // Add the signature
2835 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
2836 dataToBeSigned.begin(), 32,
2841 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
2842 dataToBeSigned.begin(), 32,
2843 mtx.joinSplitPubKey.begin()
2846 CTransaction rawTx(mtx);
2848 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2851 std::string encryptedNote1;
2852 std::string encryptedNote2;
2854 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2855 ss2 << ((unsigned char) 0x00);
2856 ss2 << jsdesc.ephemeralKey;
2857 ss2 << jsdesc.ciphertexts[0];
2858 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
2860 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
2863 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
2864 ss2 << ((unsigned char) 0x01);
2865 ss2 << jsdesc.ephemeralKey;
2866 ss2 << jsdesc.ciphertexts[1];
2867 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
2869 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
2872 UniValue result(UniValue::VOBJ);
2873 result.push_back(Pair("encryptednote1", encryptedNote1));
2874 result.push_back(Pair("encryptednote2", encryptedNote2));
2875 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
2879 UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
2881 if (!EnsureWalletIsAvailable(fHelp)) {
2882 return NullUniValue;
2885 if (fHelp || params.size() != 0) {
2886 throw runtime_error(
2889 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
2892 " \"zcaddress\": zcaddr,\n"
2893 " \"zcsecretkey\": zcsecretkey,\n"
2898 auto k = SpendingKey::random();
2899 auto addr = k.address();
2900 auto viewing_key = k.viewing_key();
2902 CDataStream viewing(SER_NETWORK, PROTOCOL_VERSION);
2904 viewing << viewing_key;
2906 CZCPaymentAddress pubaddr(addr);
2907 CZCSpendingKey spendingkey(k);
2908 std::string viewing_hex = HexStr(viewing.begin(), viewing.end());
2910 UniValue result(UniValue::VOBJ);
2911 result.push_back(Pair("zcaddress", pubaddr.ToString()));
2912 result.push_back(Pair("zcsecretkey", spendingkey.ToString()));
2913 result.push_back(Pair("zcviewingkey", viewing_hex));
2918 UniValue z_getnewaddress(const UniValue& params, bool fHelp)
2920 if (!EnsureWalletIsAvailable(fHelp))
2921 return NullUniValue;
2923 if (fHelp || params.size() > 0)
2924 throw runtime_error(
2926 "\nReturns a new zaddr for receiving payments.\n"
2929 "\"zcashaddress\" (string) The new zaddr\n"
2931 + HelpExampleCli("z_getnewaddress", "")
2932 + HelpExampleRpc("z_getnewaddress", "")
2935 LOCK2(cs_main, pwalletMain->cs_wallet);
2937 EnsureWalletIsUnlocked();
2939 CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
2940 std::string result = pubaddr.ToString();
2945 UniValue z_listaddresses(const UniValue& params, bool fHelp)
2947 if (!EnsureWalletIsAvailable(fHelp))
2948 return NullUniValue;
2950 if (fHelp || params.size() > 1)
2951 throw runtime_error(
2953 "\nReturns the list of zaddr belonging to the wallet.\n"
2956 "[ (json array of string)\n"
2957 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
2961 + HelpExampleCli("z_listaddresses", "")
2962 + HelpExampleRpc("z_listaddresses", "")
2965 LOCK2(cs_main, pwalletMain->cs_wallet);
2967 UniValue ret(UniValue::VARR);
2968 std::set<libzcash::PaymentAddress> addresses;
2969 pwalletMain->GetPaymentAddresses(addresses);
2970 for (auto addr : addresses ) {
2971 ret.push_back(CZCPaymentAddress(addr).ToString());
2976 CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1) {
2977 set<CBitcoinAddress> setAddress;
2978 vector<COutput> vecOutputs;
2979 CAmount balance = 0;
2981 if (transparentAddress.length() > 0) {
2982 CBitcoinAddress taddr = CBitcoinAddress(transparentAddress);
2983 if (!taddr.IsValid()) {
2984 throw std::runtime_error("invalid transparent address");
2986 setAddress.insert(taddr);
2989 LOCK2(cs_main, pwalletMain->cs_wallet);
2991 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2993 BOOST_FOREACH(const COutput& out, vecOutputs) {
2994 if (out.nDepth < minDepth) {
2998 if (setAddress.size()) {
2999 CTxDestination address;
3000 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3004 if (!setAddress.count(address)) {
3009 CAmount nValue = out.tx->vout[out.i].nValue;
3015 CAmount getBalanceZaddr(std::string address, int minDepth = 1) {
3016 CAmount balance = 0;
3017 std::vector<CNotePlaintextEntry> entries;
3018 LOCK2(cs_main, pwalletMain->cs_wallet);
3019 pwalletMain->GetFilteredNotes(entries, address, minDepth);
3020 for (auto & entry : entries) {
3021 balance += CAmount(entry.plaintext.value);
3027 UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
3029 if (!EnsureWalletIsAvailable(fHelp))
3030 return NullUniValue;
3032 if (fHelp || params.size()==0 || params.size() >2)
3033 throw runtime_error(
3034 "z_listreceivedbyaddress \"address\" ( minconf )\n"
3035 "\nReturn a list of amounts received by a zaddr belonging to the node’s wallet.\n"
3037 "1. \"address\" (string) The private address.\n"
3038 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3041 " \"txid\": xxxxx, (string) the transaction id\n"
3042 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
3043 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
3047 LOCK2(cs_main, pwalletMain->cs_wallet);
3050 if (params.size() > 1) {
3051 nMinDepth = params[1].get_int();
3053 if (nMinDepth < 0) {
3054 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3057 // Check that the from address is valid.
3058 auto fromaddress = params[0].get_str();
3060 libzcash::PaymentAddress zaddr;
3061 CZCPaymentAddress address(fromaddress);
3063 zaddr = address.Get();
3064 } catch (const std::runtime_error&) {
3065 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
3068 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3069 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3073 UniValue result(UniValue::VARR);
3074 std::vector<CNotePlaintextEntry> entries;
3075 pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false);
3076 for (CNotePlaintextEntry & entry : entries) {
3077 UniValue obj(UniValue::VOBJ);
3078 obj.push_back(Pair("txid",entry.jsop.hash.ToString()));
3079 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value))));
3080 std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
3081 obj.push_back(Pair("memo", HexStr(data)));
3082 result.push_back(obj);
3088 UniValue z_getbalance(const UniValue& params, bool fHelp)
3090 if (!EnsureWalletIsAvailable(fHelp))
3091 return NullUniValue;
3093 if (fHelp || params.size()==0 || params.size() >2)
3094 throw runtime_error(
3095 "z_getbalance \"address\" ( minconf )\n"
3096 "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
3098 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
3099 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3101 "amount (numeric) The total amount in ZEC received for this address.\n"
3103 "\nThe total amount received by address \"myaddress\"\n"
3104 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
3105 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
3106 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
3107 "\nAs a json rpc call\n"
3108 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
3111 LOCK2(cs_main, pwalletMain->cs_wallet);
3114 if (params.size() > 1) {
3115 nMinDepth = params[1].get_int();
3117 if (nMinDepth < 0) {
3118 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3121 // Check that the from address is valid.
3122 auto fromaddress = params[0].get_str();
3123 bool fromTaddr = false;
3124 CBitcoinAddress taddr(fromaddress);
3125 fromTaddr = taddr.IsValid();
3126 libzcash::PaymentAddress zaddr;
3128 CZCPaymentAddress address(fromaddress);
3130 zaddr = address.Get();
3131 } catch (const std::runtime_error&) {
3132 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3134 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3135 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3139 CAmount nBalance = 0;
3141 nBalance = getBalanceTaddr(fromaddress, nMinDepth);
3143 nBalance = getBalanceZaddr(fromaddress, nMinDepth);
3146 return ValueFromAmount(nBalance);
3150 UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
3152 if (!EnsureWalletIsAvailable(fHelp))
3153 return NullUniValue;
3155 if (fHelp || params.size() > 1)
3156 throw runtime_error(
3157 "z_gettotalbalance ( minconf )\n"
3158 "\nReturn the total value of funds stored in the node’s wallet.\n"
3160 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
3163 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
3164 " \"private\": xxxxx, (numeric) the total balance of private funds\n"
3165 " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
3168 "\nThe total amount in the wallet\n"
3169 + HelpExampleCli("z_gettotalbalance", "") +
3170 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3171 + HelpExampleCli("z_gettotalbalance", "5") +
3172 "\nAs a json rpc call\n"
3173 + HelpExampleRpc("z_gettotalbalance", "5")
3176 LOCK2(cs_main, pwalletMain->cs_wallet);
3179 if (params.size() == 1) {
3180 nMinDepth = params[0].get_int();
3182 if (nMinDepth < 0) {
3183 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3186 // getbalance and "getbalance * 1 true" should return the same number
3187 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
3188 // pwalletMain->GetBalance() does not accept min depth parameter
3189 // so we use our own method to get balance of utxos.
3190 CAmount nBalance = getBalanceTaddr("", nMinDepth);
3191 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth);
3192 CAmount nTotalBalance = nBalance + nPrivateBalance;
3193 UniValue result(UniValue::VOBJ);
3194 result.push_back(Pair("transparent", FormatMoney(nBalance)));
3195 result.push_back(Pair("private", FormatMoney(nPrivateBalance)));
3196 result.push_back(Pair("total", FormatMoney(nTotalBalance)));
3200 UniValue z_getoperationresult(const UniValue& params, bool fHelp)
3202 if (!EnsureWalletIsAvailable(fHelp))
3203 return NullUniValue;
3205 if (fHelp || params.size() > 1)
3206 throw runtime_error(
3207 "z_getoperationresult ([\"operationid\", ... ]) \n"
3208 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3209 + HelpRequiringPassphrase() + "\n"
3211 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3213 "\" [object, ...]\" (array) A list of JSON objects\n"
3216 // This call will remove finished operations
3217 return z_getoperationstatus_IMPL(params, true);
3220 UniValue z_getoperationstatus(const UniValue& params, bool fHelp)
3222 if (!EnsureWalletIsAvailable(fHelp))
3223 return NullUniValue;
3225 if (fHelp || params.size() > 1)
3226 throw runtime_error(
3227 "z_getoperationstatus ([\"operationid\", ... ]) \n"
3228 "\nGet operation status and any associated result or error data. The operation will remain in memory."
3229 + HelpRequiringPassphrase() + "\n"
3231 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3233 "\" [object, ...]\" (array) A list of JSON objects\n"
3236 // This call is idempotent so we don't want to remove finished operations
3237 return z_getoperationstatus_IMPL(params, false);
3240 UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedOperations=false)
3242 LOCK2(cs_main, pwalletMain->cs_wallet);
3244 std::set<AsyncRPCOperationId> filter;
3245 if (params.size()==1) {
3246 UniValue ids = params[0].get_array();
3247 for (const UniValue & v : ids.getValues()) {
3248 filter.insert(v.get_str());
3251 bool useFilter = (filter.size()>0);
3253 UniValue ret(UniValue::VARR);
3254 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3255 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3257 for (auto id : ids) {
3258 if (useFilter && !filter.count(id))
3261 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3264 // It's possible that the operation was removed from the internal queue and map during this loop
3265 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3268 UniValue obj = operation->getStatus();
3269 std::string s = obj["status"].get_str();
3270 if (fRemoveFinishedOperations) {
3271 // Caller is only interested in retrieving finished results
3272 if ("success"==s || "failed"==s || "cancelled"==s) {
3274 q->popOperationForId(id);
3281 std::vector<UniValue> arrTmp = ret.getValues();
3283 // sort results chronologically by creation_time
3284 std::sort(arrTmp.begin(), arrTmp.end(), [](UniValue a, UniValue b) -> bool {
3285 const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
3286 const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
3292 ret.push_backV(arrTmp);
3298 // Here we define the maximum number of zaddr outputs that can be included in a transaction.
3299 // If input notes are small, we might actually require more than one joinsplit per zaddr output.
3300 // For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
3301 // We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
3302 #define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1)
3304 // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
3305 #define CTXIN_SPEND_DUST_SIZE 148
3306 #define CTXOUT_REGULAR_SIZE 34
3308 UniValue z_sendmany(const UniValue& params, bool fHelp)
3310 if (!EnsureWalletIsAvailable(fHelp))
3311 return NullUniValue;
3313 if (fHelp || params.size() < 2 || params.size() > 4)
3314 throw runtime_error(
3315 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
3316 "\nSend multiple times. Amounts are double-precision floating point numbers."
3317 "\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
3318 "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
3319 + strprintf("\nCurrently, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS)
3320 + HelpRequiringPassphrase() + "\n"
3322 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
3323 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
3325 " \"address\":address (string, required) The address is a taddr or zaddr\n"
3326 " \"amount\":amount (numeric, required) The numeric amount in ZEC is the value\n"
3327 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3329 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
3330 "4. fee (numeric, optional, default="
3331 + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
3333 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
3336 LOCK2(cs_main, pwalletMain->cs_wallet);
3338 // Check that the from address is valid.
3339 auto fromaddress = params[0].get_str();
3340 bool fromTaddr = false;
3341 CBitcoinAddress taddr(fromaddress);
3342 fromTaddr = taddr.IsValid();
3343 libzcash::PaymentAddress zaddr;
3345 CZCPaymentAddress address(fromaddress);
3347 zaddr = address.Get();
3348 } catch (const std::runtime_error&) {
3350 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3354 // Check that we have the spending key
3356 if (!pwalletMain->HaveSpendingKey(zaddr)) {
3357 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3361 UniValue outputs = params[1].get_array();
3363 if (outputs.size()==0)
3364 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3366 // Keep track of addresses to spot duplicates
3367 set<std::string> setAddress;
3370 std::vector<SendManyRecipient> taddrRecipients;
3371 std::vector<SendManyRecipient> zaddrRecipients;
3372 CAmount nTotalOut = 0;
3374 for (const UniValue& o : outputs.getValues()) {
3376 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
3378 // sanity check, report error if unknown key-value pairs
3379 for (const string& name_ : o.getKeys()) {
3380 std::string s = name_;
3381 if (s != "address" && s != "amount" && s!="memo")
3382 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3385 string address = find_value(o, "address").get_str();
3386 bool isZaddr = false;
3387 CBitcoinAddress taddr(address);
3388 if (!taddr.IsValid()) {
3390 CZCPaymentAddress zaddr(address);
3393 } catch (const std::runtime_error&) {
3394 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3398 if (setAddress.count(address))
3399 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3400 setAddress.insert(address);
3402 UniValue memoValue = find_value(o, "memo");
3404 if (!memoValue.isNull()) {
3405 memo = memoValue.get_str();
3407 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
3408 } else if (!IsHex(memo)) {
3409 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3411 if (memo.length() > ZC_MEMO_SIZE*2) {
3412 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3416 UniValue av = find_value(o, "amount");
3417 CAmount nAmount = AmountFromValue( av );
3419 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3422 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3424 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3427 nTotalOut += nAmount;
3430 // Check the number of zaddr outputs does not exceed the limit.
3431 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS) {
3432 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
3435 // As a sanity check, estimate and verify that the size of the transaction will be valid.
3436 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
3438 CMutableTransaction mtx;
3440 for (int i = 0; i < zaddrRecipients.size(); i++) {
3441 mtx.vjoinsplit.push_back(JSDescription());
3443 CTransaction tx(mtx);
3444 txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion);
3446 txsize += CTXIN_SPEND_DUST_SIZE;
3447 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
3449 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
3450 if (txsize > MAX_TX_SIZE) {
3451 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", MAX_TX_SIZE ));
3454 // Minimum confirmations
3456 if (params.size() > 2) {
3457 nMinDepth = params[2].get_int();
3459 if (nMinDepth < 0) {
3460 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3463 // Fee in Zatoshis, not currency format)
3464 CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
3465 if (params.size() > 3) {
3466 if (params[3].get_real() == 0.0) {
3469 nFee = AmountFromValue( params[3] );
3472 // Check that the user specified fee is sane.
3473 if (nFee > nTotalOut) {
3474 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s", FormatMoney(nFee), FormatMoney(nTotalOut)));
3478 // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
3479 UniValue o(UniValue::VOBJ);
3480 o.push_back(Pair("fromaddress", params[0]));
3481 o.push_back(Pair("amounts", params[1]));
3482 o.push_back(Pair("minconf", nMinDepth));
3483 o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
3484 UniValue contextInfo = o;
3486 // Create operation and add to global queue
3487 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3488 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
3489 q->addOperation(operation);
3490 AsyncRPCOperationId operationId = operation->getId();
3495 UniValue z_listoperationids(const UniValue& params, bool fHelp)
3497 if (!EnsureWalletIsAvailable(fHelp))
3498 return NullUniValue;
3500 if (fHelp || params.size() > 1)
3501 throw runtime_error(
3502 "z_listoperationids\n"
3503 "\nReturns the list of operation ids currently known to the wallet.\n"
3505 "1. \"status\" (string, optional) Filter result by the operation's state state e.g. \"success\".\n"
3507 "[ (json array of string)\n"
3508 " \"operationid\" (string) an operation id belonging to the wallet\n"
3512 + HelpExampleCli("z_listoperationids", "")
3513 + HelpExampleRpc("z_listoperationids", "")
3516 LOCK2(cs_main, pwalletMain->cs_wallet);
3519 bool useFilter = false;
3520 if (params.size()==1) {
3521 filter = params[0].get_str();
3525 UniValue ret(UniValue::VARR);
3526 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3527 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3528 for (auto id : ids) {
3529 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3533 std::string state = operation->getStateAsString();
3534 if (useFilter && filter.compare(state)!=0)