]> Git Repo - VerusCoin.git/blame - src/wallet/rpcwallet.cpp
Add functionality from GetUnspentFilteredNotes to GetFilteredNotes
[VerusCoin.git] / src / wallet / rpcwallet.cpp
CommitLineData
e3bc5698 1// Copyright (c) 2010 Satoshi Nakamoto
f914f1a7 2// Copyright (c) 2009-2014 The Bitcoin Core developers
72fb3d29 3// Distributed under the MIT software license, see the accompanying
e3bc5698
JG
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
eda37330 6#include "amount.h"
be126699 7#include "consensus/upgrades.h"
ae775b5b 8#include "core_io.h"
e3bc5698 9#include "init.h"
3d31e09c 10#include "key_io.h"
8a893c94 11#include "main.h"
51ed9ec9
BD
12#include "net.h"
13#include "netbase.h"
4519a766 14#include "rpc/server.h"
14f888ca 15#include "timedata.h"
36e2141d 16#include "transaction_builder.h"
51ed9ec9 17#include "util.h"
b93173de 18#include "utilmoneystr.h"
51ed9ec9
BD
19#include "wallet.h"
20#include "walletdb.h"
8cb25088 21#include "primitives/transaction.h"
6962bb3d 22#include "zcbenchmarks.h"
6aae9d1a 23#include "script/interpreter.h"
70b4ad2d 24#include "zcash/zip32.h"
51ed9ec9 25
fc72c078
S
26#include "utiltime.h"
27#include "asyncrpcoperation.h"
ed21d5bd 28#include "asyncrpcqueue.h"
6e9c7629 29#include "wallet/asyncrpcoperation_mergetoaddress.h"
fc72c078 30#include "wallet/asyncrpcoperation_sendmany.h"
06c19063 31#include "wallet/asyncrpcoperation_shieldcoinbase.h"
fc72c078 32
320f2cc7
SB
33#include "sodium.h"
34
51ed9ec9
BD
35#include <stdint.h>
36
37#include <boost/assign/list_of.hpp>
25cf6f3d 38
a10a6e2a 39#include <univalue.h>
e3bc5698 40
bcbde86a
S
41#include <numeric>
42
e3bc5698
JG
43using namespace std;
44
2dc35992
SB
45using namespace libzcash;
46
eec85c43
JG
47const std::string ADDR_TYPE_SPROUT = "sprout";
48const std::string ADDR_TYPE_SAPLING = "sapling";
49
0d37ae3a 50extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
f7cfb52d 51
51ed9ec9 52int64_t nWalletUnlockTime;
e3bc5698
JG
53static CCriticalSection cs_nWalletUnlockTime;
54
c1eae280 55// Private method:
0d37ae3a 56UniValue z_getoperationstatus_IMPL(const UniValue&, bool);
c1eae280 57
bdab0cf5 58std::string HelpRequiringPassphrase()
e3bc5698 59{
b0730874 60 return pwalletMain && pwalletMain->IsCrypted()
a6099ef3 61 ? "\nRequires wallet passphrase to be set with walletpassphrase call."
e3bc5698
JG
62 : "";
63}
64
b9fb692d
JS
65bool EnsureWalletIsAvailable(bool avoidException)
66{
67 if (!pwalletMain)
68 {
69 if (!avoidException)
70 throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
71 else
72 return false;
73 }
74 return true;
75}
76
bdab0cf5 77void EnsureWalletIsUnlocked()
e3bc5698
JG
78{
79 if (pwalletMain->IsLocked())
738835d7 80 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
e3bc5698
JG
81}
82
d014114d 83void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
e3bc5698
JG
84{
85 int confirms = wtx.GetDepthInMainChain();
86 entry.push_back(Pair("confirmations", confirms));
e07c8e91
LD
87 if (wtx.IsCoinBase())
88 entry.push_back(Pair("generated", true));
2b72d46f 89 if (confirms > 0)
e3bc5698
JG
90 {
91 entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
92 entry.push_back(Pair("blockindex", wtx.nIndex));
209377a7 93 entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
9bb37bf0 94 entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight));
e3bc5698 95 }
805344dc 96 uint256 hash = wtx.GetHash();
731b89b8 97 entry.push_back(Pair("txid", hash.GetHex()));
38fc4b70 98 UniValue conflicts(UniValue::VARR);
731b89b8
GA
99 BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
100 conflicts.push_back(conflict.GetHex());
101 entry.push_back(Pair("walletconflicts", conflicts));
d56e30ca 102 entry.push_back(Pair("time", wtx.GetTxTime()));
4b61a6a4 103 entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
e3bc5698
JG
104 BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
105 entry.push_back(Pair(item.first, item.second));
f7cfb52d
S
106
107 entry.push_back(Pair("vjoinsplit", TxJoinSplitToJSON(wtx)));
e3bc5698
JG
108}
109
d014114d 110string AccountFromValue(const UniValue& value)
e3bc5698
JG
111{
112 string strAccount = value.get_str();
3c31eb24 113 if (strAccount != "")
7b3351ff 114 throw JSONRPCError(RPC_WALLET_ACCOUNTS_UNSUPPORTED, "Accounts are unsupported");
e3bc5698
JG
115 return strAccount;
116}
117
d014114d 118UniValue getnewaddress(const UniValue& params, bool fHelp)
e3bc5698 119{
b9fb692d 120 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 121 return NullUniValue;
70454796 122
e3bc5698
JG
123 if (fHelp || params.size() > 1)
124 throw runtime_error(
a6099ef3 125 "getnewaddress ( \"account\" )\n"
58c4c0bb 126 "\nReturns a new Zcash address for receiving payments.\n"
a6099ef3 127 "\nArguments:\n"
3c31eb24 128 "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"
a6099ef3 129 "\nResult:\n"
d2c1e4a8 130 "\"zcashaddress\" (string) The new Zcash address\n"
a6099ef3 131 "\nExamples:\n"
132 + HelpExampleCli("getnewaddress", "")
7b782f5b 133 + HelpExampleRpc("getnewaddress", "")
a6099ef3 134 );
e3bc5698 135
4401b2d7
EL
136 LOCK2(cs_main, pwalletMain->cs_wallet);
137
e3bc5698
JG
138 // Parse the account first so we don't generate a key if there's an error
139 string strAccount;
140 if (params.size() > 0)
141 strAccount = AccountFromValue(params[0]);
142
143 if (!pwalletMain->IsLocked())
144 pwalletMain->TopUpKeyPool();
145
146 // Generate a new key that is added to wallet
147 CPubKey newKey;
71ac5052 148 if (!pwalletMain->GetKeyFromPool(newKey))
738835d7 149 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e3bc5698
JG
150 CKeyID keyID = newKey.GetID();
151
a41d5fe0 152 pwalletMain->SetAddressBook(keyID, strAccount, "receive");
e3bc5698 153
07444da1 154 return EncodeDestination(keyID);
e3bc5698
JG
155}
156
157
07444da1 158CTxDestination GetAccountAddress(std::string strAccount, bool bForceNew=false)
e3bc5698
JG
159{
160 CWalletDB walletdb(pwalletMain->strWalletFile);
161
162 CAccount account;
163 walletdb.ReadAccount(strAccount, account);
164
165 bool bKeyUsed = false;
166
167 // Check if the current key has been used
168 if (account.vchPubKey.IsValid())
169 {
0be990ba 170 CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
e3bc5698
JG
171 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
172 it != pwalletMain->mapWallet.end() && account.vchPubKey.IsValid();
173 ++it)
174 {
175 const CWalletTx& wtx = (*it).second;
176 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
177 if (txout.scriptPubKey == scriptPubKey)
178 bKeyUsed = true;
179 }
180 }
181
182 // Generate a new key
183 if (!account.vchPubKey.IsValid() || bForceNew || bKeyUsed)
184 {
71ac5052 185 if (!pwalletMain->GetKeyFromPool(account.vchPubKey))
738835d7 186 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e3bc5698 187
a41d5fe0 188 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive");
e3bc5698
JG
189 walletdb.WriteAccount(strAccount, account);
190 }
191
07444da1 192 return account.vchPubKey.GetID();
e3bc5698
JG
193}
194
d014114d 195UniValue getaccountaddress(const UniValue& params, bool fHelp)
e3bc5698 196{
b9fb692d 197 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 198 return NullUniValue;
70454796 199
e3bc5698
JG
200 if (fHelp || params.size() != 1)
201 throw runtime_error(
a6099ef3 202 "getaccountaddress \"account\"\n"
58c4c0bb 203 "\nDEPRECATED. Returns the current Zcash address for receiving payments to this account.\n"
a6099ef3 204 "\nArguments:\n"
3c31eb24 205 "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"
a6099ef3 206 "\nResult:\n"
d2c1e4a8 207 "\"zcashaddress\" (string) The account Zcash address\n"
a6099ef3 208 "\nExamples:\n"
209 + HelpExampleCli("getaccountaddress", "")
210 + HelpExampleCli("getaccountaddress", "\"\"")
211 + HelpExampleCli("getaccountaddress", "\"myaccount\"")
212 + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
213 );
e3bc5698 214
4401b2d7
EL
215 LOCK2(cs_main, pwalletMain->cs_wallet);
216
e3bc5698
JG
217 // Parse the account first so we don't generate a key if there's an error
218 string strAccount = AccountFromValue(params[0]);
219
d014114d 220 UniValue ret(UniValue::VSTR);
e3bc5698 221
07444da1 222 ret = EncodeDestination(GetAccountAddress(strAccount));
e3bc5698
JG
223 return ret;
224}
225
226
d014114d 227UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
e5e9904c 228{
b9fb692d 229 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 230 return NullUniValue;
70454796 231
e5e9904c
JG
232 if (fHelp || params.size() > 1)
233 throw runtime_error(
234 "getrawchangeaddress\n"
58c4c0bb 235 "\nReturns a new Zcash address, for receiving change.\n"
a6099ef3 236 "This is for use with raw transactions, NOT normal use.\n"
237 "\nResult:\n"
238 "\"address\" (string) The address\n"
239 "\nExamples:\n"
240 + HelpExampleCli("getrawchangeaddress", "")
241 + HelpExampleRpc("getrawchangeaddress", "")
242 );
e5e9904c 243
4401b2d7
EL
244 LOCK2(cs_main, pwalletMain->cs_wallet);
245
e5e9904c
JG
246 if (!pwalletMain->IsLocked())
247 pwalletMain->TopUpKeyPool();
248
249 CReserveKey reservekey(pwalletMain);
250 CPubKey vchPubKey;
251 if (!reservekey.GetReservedKey(vchPubKey))
6c37f7fd 252 throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
e5e9904c
JG
253
254 reservekey.KeepKey();
255
256 CKeyID keyID = vchPubKey.GetID();
257
07444da1 258 return EncodeDestination(keyID);
e5e9904c
JG
259}
260
e3bc5698 261
d014114d 262UniValue setaccount(const UniValue& params, bool fHelp)
e3bc5698 263{
b9fb692d 264 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 265 return NullUniValue;
70454796 266
e3bc5698
JG
267 if (fHelp || params.size() < 1 || params.size() > 2)
268 throw runtime_error(
58c4c0bb 269 "setaccount \"zcashaddress\" \"account\"\n"
7b782f5b 270 "\nDEPRECATED. Sets the account associated with the given address.\n"
a6099ef3 271 "\nArguments:\n"
d2c1e4a8 272 "1. \"zcashaddress\" (string, required) The Zcash address to be associated with an account.\n"
3c31eb24 273 "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"
a6099ef3 274 "\nExamples:\n"
70454796
JG
275 + HelpExampleCli("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"tabby\"")
276 + HelpExampleRpc("setaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"tabby\"")
a6099ef3 277 );
e3bc5698 278
4401b2d7
EL
279 LOCK2(cs_main, pwalletMain->cs_wallet);
280
07444da1
PW
281 CTxDestination dest = DecodeDestination(params[0].get_str());
282 if (!IsValidDestination(dest)) {
58c4c0bb 283 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
07444da1 284 }
e3bc5698 285
e3bc5698
JG
286 string strAccount;
287 if (params.size() > 1)
288 strAccount = AccountFromValue(params[1]);
289
31d6390f 290 // Only add the account if the address is yours.
07444da1 291 if (IsMine(*pwalletMain, dest)) {
31d6390f 292 // Detect when changing the account of an address that is the 'unused current key' of another account:
07444da1
PW
293 if (pwalletMain->mapAddressBook.count(dest)) {
294 std::string strOldAccount = pwalletMain->mapAddressBook[dest].name;
295 if (dest == GetAccountAddress(strOldAccount)) {
31d6390f 296 GetAccountAddress(strOldAccount, true);
07444da1 297 }
31d6390f 298 }
07444da1 299 pwalletMain->SetAddressBook(dest, strAccount, "receive");
e3bc5698 300 }
31d6390f
ES
301 else
302 throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
e3bc5698 303
ed21d5bd 304 return NullUniValue;
e3bc5698
JG
305}
306
307
d014114d 308UniValue getaccount(const UniValue& params, bool fHelp)
e3bc5698 309{
b9fb692d 310 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 311 return NullUniValue;
70454796 312
e3bc5698
JG
313 if (fHelp || params.size() != 1)
314 throw runtime_error(
58c4c0bb 315 "getaccount \"zcashaddress\"\n"
7b782f5b 316 "\nDEPRECATED. Returns the account associated with the given address.\n"
a6099ef3 317 "\nArguments:\n"
d2c1e4a8 318 "1. \"zcashaddress\" (string, required) The Zcash address for account lookup.\n"
a6099ef3 319 "\nResult:\n"
320 "\"accountname\" (string) the account address\n"
321 "\nExamples:\n"
70454796
JG
322 + HelpExampleCli("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
323 + HelpExampleRpc("getaccount", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"")
a6099ef3 324 );
e3bc5698 325
4401b2d7
EL
326 LOCK2(cs_main, pwalletMain->cs_wallet);
327
07444da1
PW
328 CTxDestination dest = DecodeDestination(params[0].get_str());
329 if (!IsValidDestination(dest)) {
58c4c0bb 330 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
07444da1 331 }
e3bc5698 332
07444da1
PW
333 std::string strAccount;
334 std::map<CTxDestination, CAddressBookData>::iterator mi = pwalletMain->mapAddressBook.find(dest);
335 if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.name.empty()) {
61885513 336 strAccount = (*mi).second.name;
07444da1 337 }
e3bc5698
JG
338 return strAccount;
339}
340
341
d014114d 342UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
e3bc5698 343{
b9fb692d 344 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 345 return NullUniValue;
70454796 346
e3bc5698
JG
347 if (fHelp || params.size() != 1)
348 throw runtime_error(
a6099ef3 349 "getaddressesbyaccount \"account\"\n"
7b782f5b 350 "\nDEPRECATED. Returns the list of addresses for the given account.\n"
a6099ef3 351 "\nArguments:\n"
3c31eb24 352 "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"
a6099ef3 353 "\nResult:\n"
354 "[ (json array of string)\n"
d2c1e4a8 355 " \"zcashaddress\" (string) a Zcash address associated with the given account\n"
a6099ef3 356 " ,...\n"
357 "]\n"
358 "\nExamples:\n"
359 + HelpExampleCli("getaddressesbyaccount", "\"tabby\"")
360 + HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
361 );
e3bc5698 362
4401b2d7
EL
363 LOCK2(cs_main, pwalletMain->cs_wallet);
364
e3bc5698
JG
365 string strAccount = AccountFromValue(params[0]);
366
367 // Find all addresses that have the given account
38fc4b70 368 UniValue ret(UniValue::VARR);
07444da1
PW
369 for (const std::pair<CTxDestination, CAddressBookData>& item : pwalletMain->mapAddressBook) {
370 const CTxDestination& dest = item.first;
371 const std::string& strName = item.second.name;
372 if (strName == strAccount) {
373 ret.push_back(EncodeDestination(dest));
374 }
e3bc5698
JG
375 }
376 return ret;
377}
378
292623ad 379static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew)
b93173de 380{
25cf6f3d
PK
381 CAmount curBalance = pwalletMain->GetBalance();
382
b93173de
PJ
383 // Check amount
384 if (nValue <= 0)
4be639ea 385 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
b93173de 386
25cf6f3d 387 if (nValue > curBalance)
b93173de
PJ
388 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
389
58c4c0bb 390 // Parse Zcash address
b93173de
PJ
391 CScript scriptPubKey = GetScriptForDestination(address);
392
393 // Create and send the transaction
394 CReserveKey reservekey(pwalletMain);
395 CAmount nFeeRequired;
25cf6f3d 396 std::string strError;
292623ad
CL
397 vector<CRecipient> vecSend;
398 int nChangePosRet = -1;
399 CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
400 vecSend.push_back(recipient);
401 if (!pwalletMain->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError)) {
402 if (!fSubtractFeeFromAmount && nValue + nFeeRequired > pwalletMain->GetBalance())
403 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));
404 throw JSONRPCError(RPC_WALLET_ERROR, strError);
b93173de
PJ
405 }
406 if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
407 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.");
b93173de
PJ
408}
409
d014114d 410UniValue sendtoaddress(const UniValue& params, bool fHelp)
e3bc5698 411{
b9fb692d 412 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 413 return NullUniValue;
70454796 414
292623ad 415 if (fHelp || params.size() < 2 || params.size() > 5)
e3bc5698 416 throw runtime_error(
58c4c0bb 417 "sendtoaddress \"zcashaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
e743678d 418 "\nSend an amount to a given address. The amount is a real and is rounded to the nearest 0.00000001\n"
a6099ef3 419 + HelpRequiringPassphrase() +
420 "\nArguments:\n"
c938fb1f 421 "1. \"zcashaddress\" (string, required) The Zcash address to send to.\n"
091b2116 422 "2. \"amount\" (numeric, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n"
a6099ef3 423 "3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
424 " This is not part of the transaction, just kept in your wallet.\n"
425 "4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
426 " to which you're sending the transaction. This is not part of the \n"
427 " transaction, just kept in your wallet.\n"
292623ad 428 "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n"
c1652849 429 " The recipient will receive less Zcash than you enter in the amount field.\n"
a6099ef3 430 "\nResult:\n"
b5ef85c7 431 "\"transactionid\" (string) The transaction id.\n"
a6099ef3 432 "\nExamples:\n"
70454796
JG
433 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1")
434 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"donation\" \"seans outpost\"")
435 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1 \"\" \"\" true")
436 + HelpExampleRpc("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
a6099ef3 437 );
e3bc5698 438
4401b2d7
EL
439 LOCK2(cs_main, pwalletMain->cs_wallet);
440
07444da1
PW
441 CTxDestination dest = DecodeDestination(params[0].get_str());
442 if (!IsValidDestination(dest)) {
58c4c0bb 443 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
07444da1 444 }
e3bc5698
JG
445
446 // Amount
a372168e 447 CAmount nAmount = AmountFromValue(params[1]);
e76a3849
WL
448 if (nAmount <= 0)
449 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
450
451 // Wallet comments
452 CWalletTx wtx;
ed21d5bd 453 if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
e3bc5698 454 wtx.mapValue["comment"] = params[2].get_str();
ed21d5bd 455 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
e3bc5698
JG
456 wtx.mapValue["to"] = params[3].get_str();
457
292623ad
CL
458 bool fSubtractFeeFromAmount = false;
459 if (params.size() > 4)
460 fSubtractFeeFromAmount = params[4].get_bool();
461
f914c7a1 462 EnsureWalletIsUnlocked();
e3bc5698 463
07444da1 464 SendMoney(dest, nAmount, fSubtractFeeFromAmount, wtx);
e3bc5698 465
805344dc 466 return wtx.GetHash().GetHex();
e3bc5698
JG
467}
468
d014114d 469UniValue listaddressgroupings(const UniValue& params, bool fHelp)
22dfd735 470{
b9fb692d 471 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 472 return NullUniValue;
70454796 473
22dfd735 474 if (fHelp)
b1093efa
GM
475 throw runtime_error(
476 "listaddressgroupings\n"
a6099ef3 477 "\nLists groups of addresses which have had their common ownership\n"
b1093efa 478 "made public by common use as inputs or as the resulting change\n"
a6099ef3 479 "in past transactions\n"
480 "\nResult:\n"
481 "[\n"
482 " [\n"
483 " [\n"
58c4c0bb 484 " \"zcashaddress\", (string) The zcash address\n"
091b2116 485 " amount, (numeric) The amount in " + CURRENCY_UNIT + "\n"
7b782f5b 486 " \"account\" (string, optional) The account (DEPRECATED)\n"
a6099ef3 487 " ]\n"
488 " ,...\n"
489 " ]\n"
490 " ,...\n"
491 "]\n"
492 "\nExamples:\n"
493 + HelpExampleCli("listaddressgroupings", "")
494 + HelpExampleRpc("listaddressgroupings", "")
495 );
22dfd735 496
4401b2d7
EL
497 LOCK2(cs_main, pwalletMain->cs_wallet);
498
38fc4b70 499 UniValue jsonGroupings(UniValue::VARR);
07444da1
PW
500 std::map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
501 for (const std::set<CTxDestination>& grouping : pwalletMain->GetAddressGroupings()) {
38fc4b70 502 UniValue jsonGrouping(UniValue::VARR);
07444da1 503 for (const CTxDestination& address : grouping)
22dfd735 504 {
38fc4b70 505 UniValue addressInfo(UniValue::VARR);
07444da1 506 addressInfo.push_back(EncodeDestination(address));
22dfd735 507 addressInfo.push_back(ValueFromAmount(balances[address]));
508 {
07444da1
PW
509 if (pwalletMain->mapAddressBook.find(address) != pwalletMain->mapAddressBook.end()) {
510 addressInfo.push_back(pwalletMain->mapAddressBook.find(address)->second.name);
511 }
22dfd735 512 }
513 jsonGrouping.push_back(addressInfo);
514 }
515 jsonGroupings.push_back(jsonGrouping);
516 }
517 return jsonGroupings;
518}
519
d014114d 520UniValue signmessage(const UniValue& params, bool fHelp)
e3bc5698 521{
b9fb692d 522 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 523 return NullUniValue;
70454796 524
e3bc5698
JG
525 if (fHelp || params.size() != 2)
526 throw runtime_error(
30bf78ca
JDL
527 "signmessage \"t-addr\" \"message\"\n"
528 "\nSign a message with the private key of a t-addr"
a6099ef3 529 + HelpRequiringPassphrase() + "\n"
530 "\nArguments:\n"
30bf78ca 531 "1. \"t-addr\" (string, required) The transparent address to use for the private key.\n"
a6099ef3 532 "2. \"message\" (string, required) The message to create a signature of.\n"
533 "\nResult:\n"
534 "\"signature\" (string) The signature of the message encoded in base 64\n"
535 "\nExamples:\n"
536 "\nUnlock the wallet for 30 seconds\n"
537 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
538 "\nCreate the signature\n"
70454796 539 + HelpExampleCli("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"my message\"") +
a6099ef3 540 "\nVerify the signature\n"
70454796 541 + HelpExampleCli("verifymessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"signature\" \"my message\"") +
a6099ef3 542 "\nAs json rpc\n"
70454796 543 + HelpExampleRpc("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"my message\"")
a6099ef3 544 );
e3bc5698 545
4401b2d7
EL
546 LOCK2(cs_main, pwalletMain->cs_wallet);
547
e3bc5698
JG
548 EnsureWalletIsUnlocked();
549
550 string strAddress = params[0].get_str();
551 string strMessage = params[1].get_str();
552
07444da1
PW
553 CTxDestination dest = DecodeDestination(strAddress);
554 if (!IsValidDestination(dest)) {
738835d7 555 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
07444da1 556 }
e3bc5698 557
07444da1
PW
558 const CKeyID *keyID = boost::get<CKeyID>(&dest);
559 if (!keyID) {
738835d7 560 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
07444da1 561 }
e3bc5698
JG
562
563 CKey key;
07444da1 564 if (!pwalletMain->GetKey(*keyID, key)) {
738835d7 565 throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
07444da1 566 }
e3bc5698 567
8980a509 568 CHashWriter ss(SER_GETHASH, 0);
e3bc5698
JG
569 ss << strMessageMagic;
570 ss << strMessage;
571
572 vector<unsigned char> vchSig;
8980a509 573 if (!key.SignCompact(ss.GetHash(), vchSig))
738835d7 574 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
e3bc5698
JG
575
576 return EncodeBase64(&vchSig[0], vchSig.size());
577}
578
d014114d 579UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
e3bc5698 580{
b9fb692d 581 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 582 return NullUniValue;
70454796 583
e3bc5698
JG
584 if (fHelp || params.size() < 1 || params.size() > 2)
585 throw runtime_error(
58c4c0bb 586 "getreceivedbyaddress \"zcashaddress\" ( minconf )\n"
c1652849 587 "\nReturns the total amount received by the given Zcash address in transactions with at least minconf confirmations.\n"
a6099ef3 588 "\nArguments:\n"
d2c1e4a8 589 "1. \"zcashaddress\" (string, required) The Zcash address for transactions.\n"
a6099ef3 590 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
591 "\nResult:\n"
091b2116 592 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n"
a6099ef3 593 "\nExamples:\n"
594 "\nThe amount from transactions with at least 1 confirmation\n"
70454796 595 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\"") +
a6099ef3 596 "\nThe amount including unconfirmed transactions, zero confirmations\n"
70454796 597 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 0") +
c938fb1f 598 "\nThe amount with at least 6 confirmations, very safe\n"
70454796 599 + HelpExampleCli("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" 6") +
a6099ef3 600 "\nAs a json rpc call\n"
70454796 601 + HelpExampleRpc("getreceivedbyaddress", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", 6")
a6099ef3 602 );
e3bc5698 603
4401b2d7
EL
604 LOCK2(cs_main, pwalletMain->cs_wallet);
605
e3bc5698 606 // Bitcoin address
07444da1
PW
607 CTxDestination dest = DecodeDestination(params[0].get_str());
608 if (!IsValidDestination(dest)) {
58c4c0bb 609 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
07444da1
PW
610 }
611 CScript scriptPubKey = GetScriptForDestination(dest);
612 if (!IsMine(*pwalletMain, scriptPubKey)) {
b37b4b2f 613 return ValueFromAmount(0);
07444da1 614 }
e3bc5698
JG
615
616 // Minimum confirmations
617 int nMinDepth = 1;
618 if (params.size() > 1)
619 nMinDepth = params[1].get_int();
620
621 // Tally
a372168e 622 CAmount nAmount = 0;
e3bc5698
JG
623 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
624 {
625 const CWalletTx& wtx = (*it).second;
75a4d512 626 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
627 continue;
628
629 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
630 if (txout.scriptPubKey == scriptPubKey)
631 if (wtx.GetDepthInMainChain() >= nMinDepth)
632 nAmount += txout.nValue;
633 }
634
635 return ValueFromAmount(nAmount);
636}
637
638
d014114d 639UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
e3bc5698 640{
b9fb692d 641 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 642 return NullUniValue;
70454796 643
e3bc5698
JG
644 if (fHelp || params.size() < 1 || params.size() > 2)
645 throw runtime_error(
a6099ef3 646 "getreceivedbyaccount \"account\" ( minconf )\n"
7b782f5b 647 "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
a6099ef3 648 "\nArguments:\n"
3c31eb24 649 "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"
a6099ef3 650 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
651 "\nResult:\n"
091b2116 652 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
a6099ef3 653 "\nExamples:\n"
654 "\nAmount received by the default account with at least 1 confirmation\n"
655 + HelpExampleCli("getreceivedbyaccount", "\"\"") +
656 "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
657 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
658 "\nThe amount with at least 6 confirmation, very safe\n"
659 + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
660 "\nAs a json rpc call\n"
661 + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
662 );
e3bc5698 663
4401b2d7
EL
664 LOCK2(cs_main, pwalletMain->cs_wallet);
665
e3bc5698
JG
666 // Minimum confirmations
667 int nMinDepth = 1;
668 if (params.size() > 1)
669 nMinDepth = params[1].get_int();
670
671 // Get the set of pub keys assigned to account
672 string strAccount = AccountFromValue(params[0]);
3624356e 673 set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
e3bc5698
JG
674
675 // Tally
a372168e 676 CAmount nAmount = 0;
e3bc5698
JG
677 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
678 {
679 const CWalletTx& wtx = (*it).second;
75a4d512 680 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
681 continue;
682
683 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
684 {
685 CTxDestination address;
686 if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
687 if (wtx.GetDepthInMainChain() >= nMinDepth)
688 nAmount += txout.nValue;
689 }
690 }
691
b37b4b2f 692 return ValueFromAmount(nAmount);
e3bc5698
JG
693}
694
695
a372168e 696CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter)
e3bc5698 697{
a372168e 698 CAmount nBalance = 0;
e3bc5698
JG
699
700 // Tally wallet transactions
701 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
702 {
703 const CWalletTx& wtx = (*it).second;
75a4d512 704 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
e3bc5698
JG
705 continue;
706
a372168e 707 CAmount nReceived, nSent, nFee;
d4640d7d 708 wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter);
e3bc5698
JG
709
710 if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
711 nBalance += nReceived;
e07c8e91 712 nBalance -= nSent + nFee;
e3bc5698
JG
713 }
714
715 // Tally internal accounting entries
716 nBalance += walletdb.GetAccountCreditDebit(strAccount);
717
718 return nBalance;
719}
720
a372168e 721CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter)
e3bc5698
JG
722{
723 CWalletDB walletdb(pwalletMain->strWalletFile);
d4640d7d 724 return GetAccountBalance(walletdb, strAccount, nMinDepth, filter);
e3bc5698
JG
725}
726
727
d014114d 728UniValue getbalance(const UniValue& params, bool fHelp)
e3bc5698 729{
b9fb692d 730 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 731 return NullUniValue;
70454796 732
d4640d7d 733 if (fHelp || params.size() > 3)
e3bc5698 734 throw runtime_error(
d4640d7d 735 "getbalance ( \"account\" minconf includeWatchonly )\n"
3c31eb24 736 "\nReturns the server's total available balance.\n"
a6099ef3 737 "\nArguments:\n"
715e5bbe 738 "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"
a6099ef3 739 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
d4640d7d 740 "3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
a6099ef3 741 "\nResult:\n"
091b2116 742 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
a6099ef3 743 "\nExamples:\n"
7b782f5b 744 "\nThe total amount in the wallet\n"
a6099ef3 745 + HelpExampleCli("getbalance", "") +
7b782f5b 746 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3cf1f436 747 + HelpExampleCli("getbalance", "\"*\" 6") +
a6099ef3 748 "\nAs a json rpc call\n"
7b782f5b 749 + HelpExampleRpc("getbalance", "\"*\", 6")
a6099ef3 750 );
e3bc5698 751
4401b2d7
EL
752 LOCK2(cs_main, pwalletMain->cs_wallet);
753
e3bc5698
JG
754 if (params.size() == 0)
755 return ValueFromAmount(pwalletMain->GetBalance());
756
757 int nMinDepth = 1;
758 if (params.size() > 1)
759 nMinDepth = params[1].get_int();
a3e192a3 760 isminefilter filter = ISMINE_SPENDABLE;
a5c6c5d6
J
761 if(params.size() > 2)
762 if(params[2].get_bool())
a3e192a3 763 filter = filter | ISMINE_WATCH_ONLY;
e3bc5698
JG
764
765 if (params[0].get_str() == "*") {
766 // Calculate total balance a different way from GetBalance()
767 // (GetBalance() sums up all unspent TxOuts)
c9fd9078 768 // getbalance and "getbalance * 1 true" should return the same number
a372168e 769 CAmount nBalance = 0;
e3bc5698
JG
770 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
771 {
772 const CWalletTx& wtx = (*it).second;
c9fd9078 773 if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
e3bc5698
JG
774 continue;
775
a372168e 776 CAmount allFee;
e3bc5698 777 string strSentAccount;
1b4568cb
CL
778 list<COutputEntry> listReceived;
779 list<COutputEntry> listSent;
d4640d7d 780 wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
e3bc5698
JG
781 if (wtx.GetDepthInMainChain() >= nMinDepth)
782 {
1b4568cb
CL
783 BOOST_FOREACH(const COutputEntry& r, listReceived)
784 nBalance += r.amount;
e3bc5698 785 }
1b4568cb
CL
786 BOOST_FOREACH(const COutputEntry& s, listSent)
787 nBalance -= s.amount;
e3bc5698 788 nBalance -= allFee;
e3bc5698
JG
789 }
790 return ValueFromAmount(nBalance);
791 }
792
793 string strAccount = AccountFromValue(params[0]);
794
a372168e 795 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter);
e3bc5698
JG
796
797 return ValueFromAmount(nBalance);
798}
799
d014114d 800UniValue getunconfirmedbalance(const UniValue &params, bool fHelp)
6027b460 801{
b9fb692d 802 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 803 return NullUniValue;
70454796 804
6027b460
MB
805 if (fHelp || params.size() > 0)
806 throw runtime_error(
807 "getunconfirmedbalance\n"
808 "Returns the server's total unconfirmed balance\n");
4401b2d7
EL
809
810 LOCK2(cs_main, pwalletMain->cs_wallet);
811
6027b460
MB
812 return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
813}
814
e3bc5698 815
d014114d 816UniValue movecmd(const UniValue& params, bool fHelp)
e3bc5698 817{
b9fb692d 818 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 819 return NullUniValue;
70454796 820
e3bc5698
JG
821 if (fHelp || params.size() < 3 || params.size() > 5)
822 throw runtime_error(
a6099ef3 823 "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
7b782f5b 824 "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
a6099ef3 825 "\nArguments:\n"
3c31eb24
JG
826 "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"
827 "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"
091b2116
RN
828 "3. amount (numeric) Quantity of " + CURRENCY_UNIT + " to move between accounts.\n"
829 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
830 "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
a6099ef3 831 "\nResult:\n"
45bfa137 832 "true|false (boolean) true if successful.\n"
a6099ef3 833 "\nExamples:\n"
091b2116 834 "\nMove 0.01 " + CURRENCY_UNIT + " from the default account to the account named tabby\n"
a6099ef3 835 + HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
091b2116 836 "\nMove 0.01 " + CURRENCY_UNIT + " timotei to akiko with a comment and funds have 6 confirmations\n"
a6099ef3 837 + HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
838 "\nAs a json rpc call\n"
839 + HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
840 );
e3bc5698 841
4401b2d7
EL
842 LOCK2(cs_main, pwalletMain->cs_wallet);
843
e3bc5698
JG
844 string strFrom = AccountFromValue(params[0]);
845 string strTo = AccountFromValue(params[1]);
a372168e 846 CAmount nAmount = AmountFromValue(params[2]);
e76a3849
WL
847 if (nAmount <= 0)
848 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
849 if (params.size() > 3)
850 // unused parameter, used to be nMinDepth, keep type-checking it though
851 (void)params[3].get_int();
852 string strComment;
853 if (params.size() > 4)
854 strComment = params[4].get_str();
855
856 CWalletDB walletdb(pwalletMain->strWalletFile);
857 if (!walletdb.TxnBegin())
738835d7 858 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698 859
51ed9ec9 860 int64_t nNow = GetAdjustedTime();
e3bc5698
JG
861
862 // Debit
863 CAccountingEntry debit;
4291e8fe 864 debit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
865 debit.strAccount = strFrom;
866 debit.nCreditDebit = -nAmount;
867 debit.nTime = nNow;
868 debit.strOtherAccount = strTo;
869 debit.strComment = strComment;
870 walletdb.WriteAccountingEntry(debit);
871
872 // Credit
873 CAccountingEntry credit;
4291e8fe 874 credit.nOrderPos = pwalletMain->IncOrderPosNext(&walletdb);
e3bc5698
JG
875 credit.strAccount = strTo;
876 credit.nCreditDebit = nAmount;
877 credit.nTime = nNow;
878 credit.strOtherAccount = strFrom;
879 credit.strComment = strComment;
880 walletdb.WriteAccountingEntry(credit);
881
882 if (!walletdb.TxnCommit())
738835d7 883 throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
e3bc5698
JG
884
885 return true;
886}
887
888
d014114d 889UniValue sendfrom(const UniValue& params, bool fHelp)
e3bc5698 890{
b9fb692d 891 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 892 return NullUniValue;
70454796 893
e3bc5698
JG
894 if (fHelp || params.size() < 3 || params.size() > 6)
895 throw runtime_error(
58c4c0bb 896 "sendfrom \"fromaccount\" \"tozcashaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
d2c1e4a8 897 "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a Zcash address.\n"
a6099ef3 898 "The amount is a real and is rounded to the nearest 0.00000001."
899 + HelpRequiringPassphrase() + "\n"
900 "\nArguments:\n"
3c31eb24 901 "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"
c938fb1f 902 "2. \"tozcashaddress\" (string, required) The Zcash address to send funds to.\n"
091b2116 903 "3. amount (numeric, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n"
a6099ef3 904 "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
905 "5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
906 " This is not part of the transaction, just kept in your wallet.\n"
907 "6. \"comment-to\" (string, optional) An optional comment to store the name of the person or organization \n"
908 " to which you're sending the transaction. This is not part of the transaction, \n"
909 " it is just kept in your wallet.\n"
910 "\nResult:\n"
b5ef85c7 911 "\"transactionid\" (string) The transaction id.\n"
a6099ef3 912 "\nExamples:\n"
091b2116 913 "\nSend 0.01 " + CURRENCY_UNIT + " from the default account to the address, must have at least 1 confirmation\n"
70454796 914 + HelpExampleCli("sendfrom", "\"\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
a6099ef3 915 "\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
70454796 916 + HelpExampleCli("sendfrom", "\"tabby\" \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
a6099ef3 917 "\nAs a json rpc call\n"
70454796 918 + HelpExampleRpc("sendfrom", "\"tabby\", \"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
a6099ef3 919 );
e3bc5698 920
4401b2d7
EL
921 LOCK2(cs_main, pwalletMain->cs_wallet);
922
07444da1
PW
923 std::string strAccount = AccountFromValue(params[0]);
924 CTxDestination dest = DecodeDestination(params[1].get_str());
925 if (!IsValidDestination(dest)) {
58c4c0bb 926 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Zcash address");
07444da1 927 }
a372168e 928 CAmount nAmount = AmountFromValue(params[2]);
e76a3849
WL
929 if (nAmount <= 0)
930 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
931 int nMinDepth = 1;
932 if (params.size() > 3)
933 nMinDepth = params[3].get_int();
934
935 CWalletTx wtx;
936 wtx.strFromAccount = strAccount;
ed21d5bd 937 if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
e3bc5698 938 wtx.mapValue["comment"] = params[4].get_str();
ed21d5bd 939 if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
e3bc5698
JG
940 wtx.mapValue["to"] = params[5].get_str();
941
942 EnsureWalletIsUnlocked();
943
944 // Check funds
a372168e 945 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
e3bc5698 946 if (nAmount > nBalance)
738835d7 947 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698 948
07444da1 949 SendMoney(dest, nAmount, false, wtx);
e3bc5698 950
805344dc 951 return wtx.GetHash().GetHex();
e3bc5698
JG
952}
953
954
d014114d 955UniValue sendmany(const UniValue& params, bool fHelp)
e3bc5698 956{
b9fb692d 957 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 958 return NullUniValue;
70454796 959
292623ad 960 if (fHelp || params.size() < 2 || params.size() > 5)
e3bc5698 961 throw runtime_error(
40a75733 962 "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
a6099ef3 963 "\nSend multiple times. Amounts are double-precision floating point numbers."
964 + HelpRequiringPassphrase() + "\n"
965 "\nArguments:\n"
3c31eb24 966 "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"
a6099ef3 967 "2. \"amounts\" (string, required) A json object with addresses and amounts\n"
968 " {\n"
c938fb1f 969 " \"address\":amount (numeric) The Zcash address is the key, the numeric amount in " + CURRENCY_UNIT + " is the value\n"
a6099ef3 970 " ,...\n"
971 " }\n"
972 "3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
973 "4. \"comment\" (string, optional) A comment\n"
40a75733 974 "5. subtractfeefromamount (string, optional) A json array with addresses.\n"
292623ad 975 " The fee will be equally deducted from the amount of each selected address.\n"
c1652849 976 " Those recipients will receive less Zcash than you enter in their corresponding amount field.\n"
40a75733
LD
977 " If no addresses are specified here, the sender pays the fee.\n"
978 " [\n"
979 " \"address\" (string) Subtract fee from this address\n"
292623ad 980 " ,...\n"
40a75733 981 " ]\n"
a6099ef3 982 "\nResult:\n"
983 "\"transactionid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n"
b5ef85c7 984 " the number of addresses.\n"
a6099ef3 985 "\nExamples:\n"
986 "\nSend two amounts to two different addresses:\n"
70454796 987 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\"") +
a6099ef3 988 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
70454796 989 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 6 \"testing\"") +
292623ad 990 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
70454796 991 + HelpExampleCli("sendmany", "\"\" \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\" 1 \"\" \"[\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\",\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\"]\"") +
a6099ef3 992 "\nAs a json rpc call\n"
70454796 993 + HelpExampleRpc("sendmany", "\"\", \"{\\\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\\\":0.01,\\\"t1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
a6099ef3 994 );
e3bc5698 995
4401b2d7
EL
996 LOCK2(cs_main, pwalletMain->cs_wallet);
997
e3bc5698 998 string strAccount = AccountFromValue(params[0]);
851f58f9 999 UniValue sendTo = params[1].get_obj();
e3bc5698
JG
1000 int nMinDepth = 1;
1001 if (params.size() > 2)
1002 nMinDepth = params[2].get_int();
1003
1004 CWalletTx wtx;
1005 wtx.strFromAccount = strAccount;
ed21d5bd 1006 if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
e3bc5698
JG
1007 wtx.mapValue["comment"] = params[3].get_str();
1008
38fc4b70 1009 UniValue subtractFeeFromAmount(UniValue::VARR);
292623ad 1010 if (params.size() > 4)
40a75733 1011 subtractFeeFromAmount = params[4].get_array();
292623ad 1012
07444da1
PW
1013 std::set<CTxDestination> destinations;
1014 std::vector<CRecipient> vecSend;
e3bc5698 1015
a372168e 1016 CAmount totalAmount = 0;
07444da1
PW
1017 std::vector<std::string> keys = sendTo.getKeys();
1018 for (const std::string& name_ : keys) {
1019 CTxDestination dest = DecodeDestination(name_);
1020 if (!IsValidDestination(dest)) {
1021 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + name_);
1022 }
e3bc5698 1023
07444da1
PW
1024 if (destinations.count(dest)) {
1025 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
1026 }
1027 destinations.insert(dest);
e3bc5698 1028
07444da1 1029 CScript scriptPubKey = GetScriptForDestination(dest);
ed21d5bd 1030 CAmount nAmount = AmountFromValue(sendTo[name_]);
e76a3849
WL
1031 if (nAmount <= 0)
1032 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
e3bc5698
JG
1033 totalAmount += nAmount;
1034
292623ad 1035 bool fSubtractFeeFromAmount = false;
cc71666a 1036 for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
d014114d 1037 const UniValue& addr = subtractFeeFromAmount[idx];
9756b7bd 1038 if (addr.get_str() == name_)
292623ad 1039 fSubtractFeeFromAmount = true;
9756b7bd 1040 }
292623ad
CL
1041
1042 CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1043 vecSend.push_back(recipient);
e3bc5698
JG
1044 }
1045
1046 EnsureWalletIsUnlocked();
1047
1048 // Check funds
a372168e 1049 CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE);
e3bc5698 1050 if (totalAmount > nBalance)
738835d7 1051 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
e3bc5698
JG
1052
1053 // Send
1054 CReserveKey keyChange(pwalletMain);
a372168e 1055 CAmount nFeeRequired = 0;
292623ad 1056 int nChangePosRet = -1;
1f00f4e9 1057 string strFailReason;
292623ad 1058 bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
e3bc5698 1059 if (!fCreated)
1f00f4e9 1060 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
e3bc5698 1061 if (!pwalletMain->CommitTransaction(wtx, keyChange))
738835d7 1062 throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
e3bc5698 1063
805344dc 1064 return wtx.GetHash().GetHex();
e3bc5698
JG
1065}
1066
4b184205 1067// Defined in rpc/misc.cpp
d014114d 1068extern CScript _createmultisig_redeemScript(const UniValue& params);
34226be7 1069
d014114d 1070UniValue addmultisigaddress(const UniValue& params, bool fHelp)
34226be7 1071{
b9fb692d 1072 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1073 return NullUniValue;
70454796 1074
34226be7
GA
1075 if (fHelp || params.size() < 2 || params.size() > 3)
1076 {
a6099ef3 1077 string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
1078 "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
58c4c0bb 1079 "Each key is a Zcash address or hex-encoded public key.\n"
7b782f5b 1080 "If 'account' is specified (DEPRECATED), assign address to that account.\n"
a6099ef3 1081
1082 "\nArguments:\n"
1083 "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
d2c1e4a8 1084 "2. \"keysobject\" (string, required) A json array of Zcash addresses or hex-encoded public keys\n"
a6099ef3 1085 " [\n"
d2c1e4a8 1086 " \"address\" (string) Zcash address or hex-encoded public key\n"
a6099ef3 1087 " ...,\n"
1088 " ]\n"
3c31eb24 1089 "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"
a6099ef3 1090
1091 "\nResult:\n"
d2c1e4a8 1092 "\"zcashaddress\" (string) A Zcash address associated with the keys.\n"
a6099ef3 1093
1094 "\nExamples:\n"
1095 "\nAdd a multisig address from 2 addresses\n"
70454796 1096 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
a6099ef3 1097 "\nAs json rpc call\n"
70454796 1098 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
a6099ef3 1099 ;
34226be7
GA
1100 throw runtime_error(msg);
1101 }
1102
4401b2d7
EL
1103 LOCK2(cs_main, pwalletMain->cs_wallet);
1104
34226be7
GA
1105 string strAccount;
1106 if (params.size() > 2)
1107 strAccount = AccountFromValue(params[2]);
e3bc5698
JG
1108
1109 // Construct using pay-to-script-hash:
787ee0c9 1110 CScript inner = _createmultisig_redeemScript(params);
066e2a14 1111 CScriptID innerID(inner);
e3bc5698
JG
1112 pwalletMain->AddCScript(inner);
1113
a41d5fe0 1114 pwalletMain->SetAddressBook(innerID, strAccount, "send");
07444da1 1115 return EncodeDestination(innerID);
e3bc5698
JG
1116}
1117
1118
1119struct tallyitem
1120{
a372168e 1121 CAmount nAmount;
e3bc5698 1122 int nConf;
62c9b115 1123 vector<uint256> txids;
0fa2f889 1124 bool fIsWatchonly;
e3bc5698
JG
1125 tallyitem()
1126 {
1127 nAmount = 0;
1128 nConf = std::numeric_limits<int>::max();
0fa2f889 1129 fIsWatchonly = false;
e3bc5698
JG
1130 }
1131};
1132
d014114d 1133UniValue ListReceived(const UniValue& params, bool fByAccounts)
e3bc5698
JG
1134{
1135 // Minimum confirmations
1136 int nMinDepth = 1;
1137 if (params.size() > 0)
1138 nMinDepth = params[0].get_int();
1139
1140 // Whether to include empty accounts
1141 bool fIncludeEmpty = false;
1142 if (params.size() > 1)
1143 fIncludeEmpty = params[1].get_bool();
1144
a3e192a3 1145 isminefilter filter = ISMINE_SPENDABLE;
0fa2f889
J
1146 if(params.size() > 2)
1147 if(params[2].get_bool())
a3e192a3 1148 filter = filter | ISMINE_WATCH_ONLY;
0fa2f889 1149
e3bc5698 1150 // Tally
07444da1
PW
1151 std::map<CTxDestination, tallyitem> mapTally;
1152 for (const std::pair<uint256, CWalletTx>& pairWtx : pwalletMain->mapWallet) {
1153 const CWalletTx& wtx = pairWtx.second;
e3bc5698 1154
75a4d512 1155 if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
e3bc5698
JG
1156 continue;
1157
1158 int nDepth = wtx.GetDepthInMainChain();
1159 if (nDepth < nMinDepth)
1160 continue;
1161
1162 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
1163 {
1164 CTxDestination address;
0fa2f889
J
1165 if (!ExtractDestination(txout.scriptPubKey, address))
1166 continue;
1167
1168 isminefilter mine = IsMine(*pwalletMain, address);
f28707a8 1169 if(!(mine & filter))
e3bc5698
JG
1170 continue;
1171
1172 tallyitem& item = mapTally[address];
1173 item.nAmount += txout.nValue;
1174 item.nConf = min(item.nConf, nDepth);
805344dc 1175 item.txids.push_back(wtx.GetHash());
a3e192a3 1176 if (mine & ISMINE_WATCH_ONLY)
0fa2f889 1177 item.fIsWatchonly = true;
e3bc5698
JG
1178 }
1179 }
1180
1181 // Reply
38fc4b70 1182 UniValue ret(UniValue::VARR);
07444da1
PW
1183 std::map<std::string, tallyitem> mapAccountTally;
1184 for (const std::pair<CTxDestination, CAddressBookData>& item : pwalletMain->mapAddressBook) {
1185 const CTxDestination& dest = item.first;
1186 const std::string& strAccount = item.second.name;
1187 std::map<CTxDestination, tallyitem>::iterator it = mapTally.find(dest);
e3bc5698
JG
1188 if (it == mapTally.end() && !fIncludeEmpty)
1189 continue;
1190
a372168e 1191 CAmount nAmount = 0;
e3bc5698 1192 int nConf = std::numeric_limits<int>::max();
0fa2f889 1193 bool fIsWatchonly = false;
e3bc5698
JG
1194 if (it != mapTally.end())
1195 {
1196 nAmount = (*it).second.nAmount;
1197 nConf = (*it).second.nConf;
0fa2f889 1198 fIsWatchonly = (*it).second.fIsWatchonly;
e3bc5698
JG
1199 }
1200
1201 if (fByAccounts)
1202 {
1203 tallyitem& item = mapAccountTally[strAccount];
1204 item.nAmount += nAmount;
1205 item.nConf = min(item.nConf, nConf);
0fa2f889 1206 item.fIsWatchonly = fIsWatchonly;
e3bc5698
JG
1207 }
1208 else
1209 {
38fc4b70 1210 UniValue obj(UniValue::VOBJ);
0fa2f889
J
1211 if(fIsWatchonly)
1212 obj.push_back(Pair("involvesWatchonly", true));
07444da1 1213 obj.push_back(Pair("address", EncodeDestination(dest)));
e3bc5698
JG
1214 obj.push_back(Pair("account", strAccount));
1215 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1216 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
38fc4b70 1217 UniValue transactions(UniValue::VARR);
1a204694 1218 if (it != mapTally.end())
62c9b115 1219 {
1a204694
A
1220 BOOST_FOREACH(const uint256& item, (*it).second.txids)
1221 {
1222 transactions.push_back(item.GetHex());
1223 }
62c9b115
A
1224 }
1225 obj.push_back(Pair("txids", transactions));
e3bc5698
JG
1226 ret.push_back(obj);
1227 }
1228 }
1229
1230 if (fByAccounts)
1231 {
1232 for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
1233 {
a372168e 1234 CAmount nAmount = (*it).second.nAmount;
e3bc5698 1235 int nConf = (*it).second.nConf;
38fc4b70 1236 UniValue obj(UniValue::VOBJ);
0fa2f889
J
1237 if((*it).second.fIsWatchonly)
1238 obj.push_back(Pair("involvesWatchonly", true));
e3bc5698
JG
1239 obj.push_back(Pair("account", (*it).first));
1240 obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
1241 obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
1242 ret.push_back(obj);
1243 }
1244 }
1245
1246 return ret;
1247}
1248
d014114d 1249UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
e3bc5698 1250{
b9fb692d 1251 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1252 return NullUniValue;
70454796 1253
0fa2f889 1254 if (fHelp || params.size() > 3)
e3bc5698 1255 throw runtime_error(
0fa2f889 1256 "listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
a6099ef3 1257 "\nList balances by receiving address.\n"
1258 "\nArguments:\n"
1259 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
5617267c 1260 "2. includeempty (numeric, optional, default=false) Whether to include addresses that haven't received any payments.\n"
0fa2f889 1261 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
a6099ef3 1262
1263 "\nResult:\n"
1264 "[\n"
1265 " {\n"
8f6860a0 1266 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
a6099ef3 1267 " \"address\" : \"receivingaddress\", (string) The receiving address\n"
7b782f5b 1268 " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
091b2116 1269 " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n"
a6099ef3 1270 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1271 " }\n"
1272 " ,...\n"
1273 "]\n"
1274
1275 "\nExamples:\n"
1276 + HelpExampleCli("listreceivedbyaddress", "")
1277 + HelpExampleCli("listreceivedbyaddress", "6 true")
0fa2f889 1278 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
a6099ef3 1279 );
e3bc5698 1280
4401b2d7
EL
1281 LOCK2(cs_main, pwalletMain->cs_wallet);
1282
e3bc5698
JG
1283 return ListReceived(params, false);
1284}
1285
d014114d 1286UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
e3bc5698 1287{
b9fb692d 1288 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1289 return NullUniValue;
70454796 1290
0fa2f889 1291 if (fHelp || params.size() > 3)
e3bc5698 1292 throw runtime_error(
0fa2f889 1293 "listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
7b782f5b 1294 "\nDEPRECATED. List balances by account.\n"
a6099ef3 1295 "\nArguments:\n"
1296 "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
1297 "2. includeempty (boolean, optional, default=false) Whether to include accounts that haven't received any payments.\n"
0fa2f889 1298 "3. includeWatchonly (bool, optional, default=false) Whether to include watchonly addresses (see 'importaddress').\n"
a6099ef3 1299
1300 "\nResult:\n"
1301 "[\n"
1302 " {\n"
8f6860a0 1303 " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
a6099ef3 1304 " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
1305 " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
1306 " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
1307 " }\n"
1308 " ,...\n"
1309 "]\n"
1310
1311 "\nExamples:\n"
1312 + HelpExampleCli("listreceivedbyaccount", "")
1313 + HelpExampleCli("listreceivedbyaccount", "6 true")
0fa2f889 1314 + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
a6099ef3 1315 );
e3bc5698 1316
4401b2d7
EL
1317 LOCK2(cs_main, pwalletMain->cs_wallet);
1318
e3bc5698
JG
1319 return ListReceived(params, true);
1320}
1321
851f58f9 1322static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
cc6cfab3 1323{
07444da1
PW
1324 if (IsValidDestination(dest)) {
1325 entry.push_back(Pair("address", EncodeDestination(dest)));
1326 }
cc6cfab3
LD
1327}
1328
d014114d 1329void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
e3bc5698 1330{
a372168e 1331 CAmount nFee;
e3bc5698 1332 string strSentAccount;
1b4568cb
CL
1333 list<COutputEntry> listReceived;
1334 list<COutputEntry> listSent;
e3bc5698 1335
d7d5d23b 1336 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
e3bc5698
JG
1337
1338 bool fAllAccounts = (strAccount == string("*"));
a3e192a3 1339 bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
e3bc5698 1340
e3bc5698
JG
1341 // Sent
1342 if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
1343 {
1b4568cb 1344 BOOST_FOREACH(const COutputEntry& s, listSent)
e3bc5698 1345 {
38fc4b70 1346 UniValue entry(UniValue::VOBJ);
1b4568cb 1347 if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
952877e0 1348 entry.push_back(Pair("involvesWatchonly", true));
e3bc5698 1349 entry.push_back(Pair("account", strSentAccount));
1b4568cb 1350 MaybePushAddress(entry, s.destination);
b96f6a77 1351 entry.push_back(Pair("category", "send"));
1b4568cb
CL
1352 entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
1353 entry.push_back(Pair("vout", s.vout));
e3bc5698
JG
1354 entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
1355 if (fLong)
1356 WalletTxToJSON(wtx, entry);
a8e5ae92 1357 entry.push_back(Pair("size", static_cast<uint64_t>(GetSerializeSize(static_cast<CTransaction>(wtx), SER_NETWORK, PROTOCOL_VERSION))));
e3bc5698
JG
1358 ret.push_back(entry);
1359 }
1360 }
1361
1362 // Received
1363 if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
1364 {
1b4568cb 1365 BOOST_FOREACH(const COutputEntry& r, listReceived)
e3bc5698
JG
1366 {
1367 string account;
1b4568cb
CL
1368 if (pwalletMain->mapAddressBook.count(r.destination))
1369 account = pwalletMain->mapAddressBook[r.destination].name;
e3bc5698
JG
1370 if (fAllAccounts || (account == strAccount))
1371 {
38fc4b70 1372 UniValue entry(UniValue::VOBJ);
1b4568cb 1373 if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
952877e0 1374 entry.push_back(Pair("involvesWatchonly", true));
e3bc5698 1375 entry.push_back(Pair("account", account));
1b4568cb 1376 MaybePushAddress(entry, r.destination);
e07c8e91
LD
1377 if (wtx.IsCoinBase())
1378 {
1379 if (wtx.GetDepthInMainChain() < 1)
1380 entry.push_back(Pair("category", "orphan"));
1381 else if (wtx.GetBlocksToMaturity() > 0)
1382 entry.push_back(Pair("category", "immature"));
1383 else
1384 entry.push_back(Pair("category", "generate"));
1385 }
1386 else
2b72d46f 1387 {
b96f6a77 1388 entry.push_back(Pair("category", "receive"));
2b72d46f 1389 }
1b4568cb
CL
1390 entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
1391 entry.push_back(Pair("vout", r.vout));
e3bc5698
JG
1392 if (fLong)
1393 WalletTxToJSON(wtx, entry);
a8e5ae92 1394 entry.push_back(Pair("size", static_cast<uint64_t>(GetSerializeSize(static_cast<CTransaction>(wtx), SER_NETWORK, PROTOCOL_VERSION))));
e3bc5698
JG
1395 ret.push_back(entry);
1396 }
1397 }
1398 }
1399}
1400
d014114d 1401void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
e3bc5698
JG
1402{
1403 bool fAllAccounts = (strAccount == string("*"));
1404
1405 if (fAllAccounts || acentry.strAccount == strAccount)
1406 {
38fc4b70 1407 UniValue entry(UniValue::VOBJ);
e3bc5698
JG
1408 entry.push_back(Pair("account", acentry.strAccount));
1409 entry.push_back(Pair("category", "move"));
d56e30ca 1410 entry.push_back(Pair("time", acentry.nTime));
e3bc5698
JG
1411 entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
1412 entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
1413 entry.push_back(Pair("comment", acentry.strComment));
1414 ret.push_back(entry);
1415 }
1416}
1417
d014114d 1418UniValue listtransactions(const UniValue& params, bool fHelp)
e3bc5698 1419{
b9fb692d 1420 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1421 return NullUniValue;
70454796 1422
d7d5d23b 1423 if (fHelp || params.size() > 4)
e3bc5698 1424 throw runtime_error(
d7d5d23b 1425 "listtransactions ( \"account\" count from includeWatchonly)\n"
a6099ef3 1426 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
1427 "\nArguments:\n"
7b782f5b 1428 "1. \"account\" (string, optional) DEPRECATED. The account name. Should be \"*\".\n"
a6099ef3 1429 "2. count (numeric, optional, default=10) The number of transactions to return\n"
1430 "3. from (numeric, optional, default=0) The number of transactions to skip\n"
d7d5d23b 1431 "4. includeWatchonly (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')\n"
a6099ef3 1432 "\nResult:\n"
1433 "[\n"
1434 " {\n"
7b782f5b 1435 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. \n"
a6099ef3 1436 " It will be \"\" for the default account.\n"
d2c1e4a8 1437 " \"address\":\"zcashaddress\", (string) The Zcash address of the transaction. Not present for \n"
a6099ef3 1438 " move transactions (category = move).\n"
1439 " \"category\":\"send|receive|move\", (string) The transaction category. 'move' is a local (off blockchain)\n"
1440 " transaction between accounts, and not associated with an address,\n"
1441 " transaction id or block. 'send' and 'receive' transactions are \n"
1442 " associated with an address, transaction id and block details\n"
091b2116 1443 " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the\n"
a6099ef3 1444 " 'move' category for moves outbound. It is positive for the 'receive' category,\n"
1445 " and for the 'move' category for inbound funds.\n"
1b4568cb 1446 " \"vout\" : n, (numeric) the vout value\n"
091b2116 1447 " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
a6099ef3 1448 " 'send' category of transactions.\n"
1449 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
1450 " 'receive' category of transactions.\n"
1451 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive'\n"
1452 " category of transactions.\n"
1453 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive'\n"
1454 " category of transactions.\n"
b5ef85c7 1455 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
a6099ef3 1456 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (midnight Jan 1 1970 GMT).\n"
1457 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (midnight Jan 1 1970 GMT). Available \n"
1458 " for 'send' and 'receive' category of transactions.\n"
1459 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1460 " \"otheraccount\": \"accountname\", (string) For the 'move' category of transactions, the account the funds came \n"
1461 " from (for receiving funds, positive amounts), or went to (for sending funds,\n"
1462 " negative amounts).\n"
f32cade8 1463 " \"size\": n, (numeric) Transaction size in bytes\n"
a6099ef3 1464 " }\n"
1465 "]\n"
1466
1467 "\nExamples:\n"
1468 "\nList the most recent 10 transactions in the systems\n"
1469 + HelpExampleCli("listtransactions", "") +
7b782f5b
LD
1470 "\nList transactions 100 to 120\n"
1471 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
a6099ef3 1472 "\nAs a json rpc call\n"
7b782f5b 1473 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
a6099ef3 1474 );
e3bc5698 1475
4401b2d7
EL
1476 LOCK2(cs_main, pwalletMain->cs_wallet);
1477
e3bc5698
JG
1478 string strAccount = "*";
1479 if (params.size() > 0)
1480 strAccount = params[0].get_str();
1481 int nCount = 10;
1482 if (params.size() > 1)
1483 nCount = params[1].get_int();
1484 int nFrom = 0;
1485 if (params.size() > 2)
1486 nFrom = params[2].get_int();
a3e192a3 1487 isminefilter filter = ISMINE_SPENDABLE;
a5c6c5d6
J
1488 if(params.size() > 3)
1489 if(params[3].get_bool())
a3e192a3 1490 filter = filter | ISMINE_WATCH_ONLY;
e3bc5698
JG
1491
1492 if (nCount < 0)
738835d7 1493 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
e3bc5698 1494 if (nFrom < 0)
738835d7 1495 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
e3bc5698 1496
38fc4b70 1497 UniValue ret(UniValue::VARR);
e3bc5698 1498
ddb709e9
LD
1499 std::list<CAccountingEntry> acentries;
1500 CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
e3bc5698
JG
1501
1502 // iterate backwards until we have nCount items to return:
c3f95ef1 1503 for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
e3bc5698
JG
1504 {
1505 CWalletTx *const pwtx = (*it).second.first;
1506 if (pwtx != 0)
d7d5d23b 1507 ListTransactions(*pwtx, strAccount, 0, true, ret, filter);
e3bc5698
JG
1508 CAccountingEntry *const pacentry = (*it).second.second;
1509 if (pacentry != 0)
1510 AcentryToJSON(*pacentry, strAccount, ret);
1511
1512 if ((int)ret.size() >= (nCount+nFrom)) break;
1513 }
1514 // ret is newest to oldest
1515
1516 if (nFrom > (int)ret.size())
1517 nFrom = ret.size();
1518 if ((nFrom + nCount) > (int)ret.size())
1519 nCount = ret.size() - nFrom;
ed21d5bd
JG
1520
1521 vector<UniValue> arrTmp = ret.getValues();
1522
1523 vector<UniValue>::iterator first = arrTmp.begin();
e3bc5698 1524 std::advance(first, nFrom);
ed21d5bd 1525 vector<UniValue>::iterator last = arrTmp.begin();
e3bc5698
JG
1526 std::advance(last, nFrom+nCount);
1527
ed21d5bd
JG
1528 if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
1529 if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
1530
1531 std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
e3bc5698 1532
ed21d5bd 1533 ret.clear();
38fc4b70 1534 ret.setArray();
ed21d5bd 1535 ret.push_backV(arrTmp);
e3bc5698
JG
1536
1537 return ret;
1538}
1539
d014114d 1540UniValue listaccounts(const UniValue& params, bool fHelp)
e3bc5698 1541{
b9fb692d 1542 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1543 return NullUniValue;
70454796 1544
83f3543f 1545 if (fHelp || params.size() > 2)
e3bc5698 1546 throw runtime_error(
83f3543f 1547 "listaccounts ( minconf includeWatchonly)\n"
7b782f5b 1548 "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
a6099ef3 1549 "\nArguments:\n"
5617267c 1550 "1. minconf (numeric, optional, default=1) Only include transactions with at least this many confirmations\n"
83f3543f 1551 "2. includeWatchonly (bool, optional, default=false) Include balances in watchonly addresses (see 'importaddress')\n"
a6099ef3 1552 "\nResult:\n"
1553 "{ (json object where keys are account names, and values are numeric balances\n"
1554 " \"account\": x.xxx, (numeric) The property name is the account name, and the value is the total balance for the account.\n"
1555 " ...\n"
1556 "}\n"
1557 "\nExamples:\n"
1558 "\nList account balances where there at least 1 confirmation\n"
1559 + HelpExampleCli("listaccounts", "") +
1560 "\nList account balances including zero confirmation transactions\n"
1561 + HelpExampleCli("listaccounts", "0") +
1562 "\nList account balances for 6 or more confirmations\n"
1563 + HelpExampleCli("listaccounts", "6") +
1564 "\nAs json rpc call\n"
1565 + HelpExampleRpc("listaccounts", "6")
1566 );
e3bc5698 1567
4401b2d7
EL
1568 LOCK2(cs_main, pwalletMain->cs_wallet);
1569
e3bc5698
JG
1570 int nMinDepth = 1;
1571 if (params.size() > 0)
1572 nMinDepth = params[0].get_int();
a3e192a3 1573 isminefilter includeWatchonly = ISMINE_SPENDABLE;
a5c6c5d6
J
1574 if(params.size() > 1)
1575 if(params[1].get_bool())
a3e192a3 1576 includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
e3bc5698 1577
a372168e 1578 map<string, CAmount> mapAccountBalances;
61885513 1579 BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) {
83f3543f 1580 if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me
61885513 1581 mapAccountBalances[entry.second.name] = 0;
e3bc5698
JG
1582 }
1583
1584 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
1585 {
1586 const CWalletTx& wtx = (*it).second;
a372168e 1587 CAmount nFee;
e3bc5698 1588 string strSentAccount;
1b4568cb
CL
1589 list<COutputEntry> listReceived;
1590 list<COutputEntry> listSent;
93a18a36
GA
1591 int nDepth = wtx.GetDepthInMainChain();
1592 if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
731b89b8 1593 continue;
83f3543f 1594 wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, includeWatchonly);
e3bc5698 1595 mapAccountBalances[strSentAccount] -= nFee;
1b4568cb
CL
1596 BOOST_FOREACH(const COutputEntry& s, listSent)
1597 mapAccountBalances[strSentAccount] -= s.amount;
93a18a36 1598 if (nDepth >= nMinDepth)
e3bc5698 1599 {
1b4568cb
CL
1600 BOOST_FOREACH(const COutputEntry& r, listReceived)
1601 if (pwalletMain->mapAddressBook.count(r.destination))
1602 mapAccountBalances[pwalletMain->mapAddressBook[r.destination].name] += r.amount;
e3bc5698 1603 else
1b4568cb 1604 mapAccountBalances[""] += r.amount;
e3bc5698
JG
1605 }
1606 }
1607
1608 list<CAccountingEntry> acentries;
1609 CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
1610 BOOST_FOREACH(const CAccountingEntry& entry, acentries)
1611 mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
1612
38fc4b70 1613 UniValue ret(UniValue::VOBJ);
a372168e 1614 BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
e3bc5698
JG
1615 ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
1616 }
1617 return ret;
1618}
1619
d014114d 1620UniValue listsinceblock(const UniValue& params, bool fHelp)
e3bc5698 1621{
b9fb692d 1622 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1623 return NullUniValue;
70454796 1624
e3bc5698
JG
1625 if (fHelp)
1626 throw runtime_error(
d7d5d23b 1627 "listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
a6099ef3 1628 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
1629 "\nArguments:\n"
1630 "1. \"blockhash\" (string, optional) The block hash to list transactions since\n"
1631 "2. target-confirmations: (numeric, optional) The confirmations required, must be 1 or more\n"
d7d5d23b 1632 "3. includeWatchonly: (bool, optional, default=false) Include transactions to watchonly addresses (see 'importaddress')"
a6099ef3 1633 "\nResult:\n"
1634 "{\n"
1635 " \"transactions\": [\n"
7b782f5b 1636 " \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
d2c1e4a8 1637 " \"address\":\"zcashaddress\", (string) The Zcash address of the transaction. Not present for move transactions (category = move).\n"
a6099ef3 1638 " \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
091b2116 1639 " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
a6099ef3 1640 " outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
1b4568cb 1641 " \"vout\" : n, (numeric) the vout value\n"
091b2116 1642 " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the 'send' category of transactions.\n"
a6099ef3 1643 " \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
1644 " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1645 " \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
1646 " \"blocktime\": xxx, (numeric) The block time in seconds since epoch (1 Jan 1970 GMT).\n"
b5ef85c7 1647 " \"txid\": \"transactionid\", (string) The transaction id. Available for 'send' and 'receive' category of transactions.\n"
a6099ef3 1648 " \"time\": xxx, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT).\n"
1649 " \"timereceived\": xxx, (numeric) The time received in seconds since epoch (Jan 1 1970 GMT). Available for 'send' and 'receive' category of transactions.\n"
1650 " \"comment\": \"...\", (string) If a comment is associated with the transaction.\n"
1651 " \"to\": \"...\", (string) If a comment to is associated with the transaction.\n"
1652 " ],\n"
1653 " \"lastblock\": \"lastblockhash\" (string) The hash of the last block\n"
1654 "}\n"
1655 "\nExamples:\n"
1656 + HelpExampleCli("listsinceblock", "")
1657 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1658 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1659 );
e3bc5698 1660
4401b2d7
EL
1661 LOCK2(cs_main, pwalletMain->cs_wallet);
1662
e3bc5698
JG
1663 CBlockIndex *pindex = NULL;
1664 int target_confirms = 1;
a3e192a3 1665 isminefilter filter = ISMINE_SPENDABLE;
e3bc5698
JG
1666
1667 if (params.size() > 0)
1668 {
4f152496 1669 uint256 blockId;
e3bc5698
JG
1670
1671 blockId.SetHex(params[0].get_str());
145d5be8 1672 BlockMap::iterator it = mapBlockIndex.find(blockId);
e4daecda
PW
1673 if (it != mapBlockIndex.end())
1674 pindex = it->second;
e3bc5698
JG
1675 }
1676
1677 if (params.size() > 1)
1678 {
1679 target_confirms = params[1].get_int();
1680
1681 if (target_confirms < 1)
738835d7 1682 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
e3bc5698
JG
1683 }
1684
a5c6c5d6
J
1685 if(params.size() > 2)
1686 if(params[2].get_bool())
a3e192a3 1687 filter = filter | ISMINE_WATCH_ONLY;
a5c6c5d6 1688
4c6d41b8 1689 int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
e3bc5698 1690
38fc4b70 1691 UniValue transactions(UniValue::VARR);
e3bc5698
JG
1692
1693 for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
1694 {
1695 CWalletTx tx = (*it).second;
1696
1697 if (depth == -1 || tx.GetDepthInMainChain() < depth)
d7d5d23b 1698 ListTransactions(tx, "*", 0, true, transactions, filter);
e3bc5698
JG
1699 }
1700
4c6d41b8 1701 CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
4f152496 1702 uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
e3bc5698 1703
38fc4b70 1704 UniValue ret(UniValue::VOBJ);
e3bc5698
JG
1705 ret.push_back(Pair("transactions", transactions));
1706 ret.push_back(Pair("lastblock", lastblock.GetHex()));
1707
1708 return ret;
1709}
1710
d014114d 1711UniValue gettransaction(const UniValue& params, bool fHelp)
e3bc5698 1712{
b9fb692d 1713 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1714 return NullUniValue;
70454796 1715
f87ba3df 1716 if (fHelp || params.size() < 1 || params.size() > 2)
e3bc5698 1717 throw runtime_error(
57e1716d 1718 "gettransaction \"txid\" ( includeWatchonly )\n"
a6099ef3 1719 "\nGet detailed information about in-wallet transaction <txid>\n"
1720 "\nArguments:\n"
1721 "1. \"txid\" (string, required) The transaction id\n"
f87ba3df 1722 "2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
a6099ef3 1723 "\nResult:\n"
1724 "{\n"
091b2116 1725 " \"amount\" : x.xxx, (numeric) The transaction amount in " + CURRENCY_UNIT + "\n"
a6099ef3 1726 " \"confirmations\" : n, (numeric) The number of confirmations\n"
1727 " \"blockhash\" : \"hash\", (string) The block hash\n"
1728 " \"blockindex\" : xx, (numeric) The block index\n"
1729 " \"blocktime\" : ttt, (numeric) The time in seconds since epoch (1 Jan 1970 GMT)\n"
b5ef85c7 1730 " \"txid\" : \"transactionid\", (string) The transaction id.\n"
a6099ef3 1731 " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (1 Jan 1970 GMT)\n"
1732 " \"timereceived\" : ttt, (numeric) The time received in seconds since epoch (1 Jan 1970 GMT)\n"
1733 " \"details\" : [\n"
1734 " {\n"
7b782f5b 1735 " \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
d2c1e4a8 1736 " \"address\" : \"zcashaddress\", (string) The Zcash address involved in the transaction\n"
a6099ef3 1737 " \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
091b2116 1738 " \"amount\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
1b4568cb 1739 " \"vout\" : n, (numeric) the vout value\n"
a6099ef3 1740 " }\n"
1741 " ,...\n"
3a1c20b7 1742 " ],\n"
f7cfb52d
S
1743 " \"vjoinsplit\" : [\n"
1744 " {\n"
1745 " \"anchor\" : \"treestateref\", (string) Merkle root of note commitment tree\n"
1746 " \"nullifiers\" : [ string, ... ] (string) Nullifiers of input notes\n"
1747 " \"commitments\" : [ string, ... ] (string) Note commitments for note outputs\n"
1748 " \"macs\" : [ string, ... ] (string) Message authentication tags\n"
1749 " \"vpub_old\" : x.xxx (numeric) The amount removed from the transparent value pool\n"
1750 " \"vpub_new\" : x.xxx, (numeric) The amount added to the transparent value pool\n"
1751 " }\n"
1752 " ,...\n"
1753 " ],\n"
3a1c20b7 1754 " \"hex\" : \"data\" (string) Raw data for transaction\n"
a6099ef3 1755 "}\n"
1756
ab45ddb5 1757 "\nExamples:\n"
a6099ef3 1758 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
57e1716d 1759 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
a6099ef3 1760 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1761 );
e3bc5698 1762
4401b2d7
EL
1763 LOCK2(cs_main, pwalletMain->cs_wallet);
1764
e3bc5698
JG
1765 uint256 hash;
1766 hash.SetHex(params[0].get_str());
1767
a3e192a3 1768 isminefilter filter = ISMINE_SPENDABLE;
f87ba3df
J
1769 if(params.size() > 1)
1770 if(params[1].get_bool())
a3e192a3 1771 filter = filter | ISMINE_WATCH_ONLY;
f87ba3df 1772
38fc4b70 1773 UniValue entry(UniValue::VOBJ);
e3bc5698 1774 if (!pwalletMain->mapWallet.count(hash))
738835d7 1775 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
e3bc5698
JG
1776 const CWalletTx& wtx = pwalletMain->mapWallet[hash];
1777
ccca27a7 1778 CAmount nCredit = wtx.GetCredit(filter);
a372168e
MF
1779 CAmount nDebit = wtx.GetDebit(filter);
1780 CAmount nNet = nCredit - nDebit;
1781 CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0);
e3bc5698
JG
1782
1783 entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
80dda36a 1784 if (wtx.IsFromMe(filter))
e3bc5698
JG
1785 entry.push_back(Pair("fee", ValueFromAmount(nFee)));
1786
1787 WalletTxToJSON(wtx, entry);
1788
38fc4b70 1789 UniValue details(UniValue::VARR);
f87ba3df 1790 ListTransactions(wtx, "*", 0, false, details, filter);
e3bc5698
JG
1791 entry.push_back(Pair("details", details));
1792
ae775b5b 1793 string strHex = EncodeHexTx(static_cast<CTransaction>(wtx));
3a1c20b7
WL
1794 entry.push_back(Pair("hex", strHex));
1795
e3bc5698
JG
1796 return entry;
1797}
1798
1799
d014114d 1800UniValue backupwallet(const UniValue& params, bool fHelp)
e3bc5698 1801{
b9fb692d 1802 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1803 return NullUniValue;
70454796 1804
e3bc5698
JG
1805 if (fHelp || params.size() != 1)
1806 throw runtime_error(
a6099ef3 1807 "backupwallet \"destination\"\n"
9064d73b 1808 "\nSafely copies wallet.dat to destination filename\n"
a6099ef3 1809 "\nArguments:\n"
9064d73b
S
1810 "1. \"destination\" (string, required) The destination filename, saved in the directory set by -exportdir option.\n"
1811 "\nResult:\n"
1812 "\"path\" (string) The full path of the destination file\n"
a6099ef3 1813 "\nExamples:\n"
9064d73b
S
1814 + HelpExampleCli("backupwallet", "\"backupdata\"")
1815 + HelpExampleRpc("backupwallet", "\"backupdata\"")
a6099ef3 1816 );
e3bc5698 1817
4401b2d7
EL
1818 LOCK2(cs_main, pwalletMain->cs_wallet);
1819
9064d73b
S
1820 boost::filesystem::path exportdir;
1821 try {
1822 exportdir = GetExportDir();
1823 } catch (const std::runtime_error& e) {
1824 throw JSONRPCError(RPC_INTERNAL_ERROR, e.what());
1825 }
1826 if (exportdir.empty()) {
1827 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot backup wallet until the -exportdir option has been set");
1828 }
1829 std::string unclean = params[0].get_str();
1830 std::string clean = SanitizeFilename(unclean);
1831 if (clean.compare(unclean) != 0) {
1832 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Filename is invalid as only alphanumeric characters are allowed. Try '%s' instead.", clean));
1833 }
1834 boost::filesystem::path exportfilepath = exportdir / clean;
1835
1836 if (!BackupWallet(*pwalletMain, exportfilepath.string()))
ad525e9c 1837 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
e3bc5698 1838
9064d73b 1839 return exportfilepath.string();
e3bc5698
JG
1840}
1841
1842
d014114d 1843UniValue keypoolrefill(const UniValue& params, bool fHelp)
e3bc5698 1844{
b9fb692d 1845 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1846 return NullUniValue;
70454796 1847
36bd46f1 1848 if (fHelp || params.size() > 1)
e3bc5698 1849 throw runtime_error(
a6099ef3 1850 "keypoolrefill ( newsize )\n"
1851 "\nFills the keypool."
1852 + HelpRequiringPassphrase() + "\n"
1853 "\nArguments\n"
1854 "1. newsize (numeric, optional, default=100) The new keypool size\n"
1855 "\nExamples:\n"
1856 + HelpExampleCli("keypoolrefill", "")
1857 + HelpExampleRpc("keypoolrefill", "")
1858 );
e3bc5698 1859
4401b2d7
EL
1860 LOCK2(cs_main, pwalletMain->cs_wallet);
1861
f914c7a1
PK
1862 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1863 unsigned int kpSize = 0;
36bd46f1
JG
1864 if (params.size() > 0) {
1865 if (params[0].get_int() < 0)
f914c7a1
PK
1866 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1867 kpSize = (unsigned int)params[0].get_int();
36bd46f1
JG
1868 }
1869
e3bc5698 1870 EnsureWalletIsUnlocked();
36bd46f1 1871 pwalletMain->TopUpKeyPool(kpSize);
e3bc5698 1872
36bd46f1 1873 if (pwalletMain->GetKeyPoolSize() < kpSize)
738835d7 1874 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
e3bc5698 1875
ed21d5bd 1876 return NullUniValue;
e3bc5698
JG
1877}
1878
1879
92f2c1fe 1880static void LockWallet(CWallet* pWallet)
e3bc5698 1881{
92f2c1fe
GA
1882 LOCK(cs_nWalletUnlockTime);
1883 nWalletUnlockTime = 0;
1884 pWallet->Lock();
e3bc5698
JG
1885}
1886
d014114d 1887UniValue walletpassphrase(const UniValue& params, bool fHelp)
e3bc5698 1888{
b9fb692d 1889 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1890 return NullUniValue;
70454796 1891
e3bc5698
JG
1892 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1893 throw runtime_error(
a6099ef3 1894 "walletpassphrase \"passphrase\" timeout\n"
1895 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
c1652849 1896 "This is needed prior to performing transactions related to private keys such as sending Zcash\n"
a6099ef3 1897 "\nArguments:\n"
1898 "1. \"passphrase\" (string, required) The wallet passphrase\n"
1899 "2. timeout (numeric, required) The time to keep the decryption key in seconds.\n"
6c0db81c
WL
1900 "\nNote:\n"
1901 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
1902 "time that overrides the old one.\n"
a6099ef3 1903 "\nExamples:\n"
1904 "\nunlock the wallet for 60 seconds\n"
1905 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1906 "\nLock the wallet again (before 60 seconds)\n"
1907 + HelpExampleCli("walletlock", "") +
1908 "\nAs json rpc call\n"
1909 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1910 );
1911
4401b2d7
EL
1912 LOCK2(cs_main, pwalletMain->cs_wallet);
1913
e3bc5698
JG
1914 if (fHelp)
1915 return true;
1916 if (!pwalletMain->IsCrypted())
738835d7 1917 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
e3bc5698 1918
e3bc5698
JG
1919 // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
1920 SecureString strWalletPass;
1921 strWalletPass.reserve(100);
1922 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1923 // Alternately, find a way to make params[0] mlock()'d to begin with.
1924 strWalletPass = params[0].get_str().c_str();
1925
1926 if (strWalletPass.length() > 0)
1927 {
1928 if (!pwalletMain->Unlock(strWalletPass))
738835d7 1929 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698
JG
1930 }
1931 else
1932 throw runtime_error(
1933 "walletpassphrase <passphrase> <timeout>\n"
1934 "Stores the wallet decryption key in memory for <timeout> seconds.");
1935
6e263a5f 1936 // No need to check return values, because the wallet was unlocked above
1a62587e 1937 pwalletMain->UpdateNullifierNoteMap();
92f2c1fe
GA
1938 pwalletMain->TopUpKeyPool();
1939
51ed9ec9 1940 int64_t nSleepTime = params[1].get_int64();
92f2c1fe
GA
1941 LOCK(cs_nWalletUnlockTime);
1942 nWalletUnlockTime = GetTime() + nSleepTime;
1943 RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
e3bc5698 1944
ed21d5bd 1945 return NullUniValue;
e3bc5698
JG
1946}
1947
1948
d014114d 1949UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
e3bc5698 1950{
b9fb692d 1951 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1952 return NullUniValue;
70454796 1953
e3bc5698
JG
1954 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
1955 throw runtime_error(
a6099ef3 1956 "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
1957 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
1958 "\nArguments:\n"
1959 "1. \"oldpassphrase\" (string) The current passphrase\n"
1960 "2. \"newpassphrase\" (string) The new passphrase\n"
1961 "\nExamples:\n"
1962 + HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
1963 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
1964 );
1965
4401b2d7
EL
1966 LOCK2(cs_main, pwalletMain->cs_wallet);
1967
e3bc5698
JG
1968 if (fHelp)
1969 return true;
1970 if (!pwalletMain->IsCrypted())
738835d7 1971 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
e3bc5698
JG
1972
1973 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
1974 // Alternately, find a way to make params[0] mlock()'d to begin with.
1975 SecureString strOldWalletPass;
1976 strOldWalletPass.reserve(100);
1977 strOldWalletPass = params[0].get_str().c_str();
1978
1979 SecureString strNewWalletPass;
1980 strNewWalletPass.reserve(100);
1981 strNewWalletPass = params[1].get_str().c_str();
1982
1983 if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
1984 throw runtime_error(
1985 "walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
1986 "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
1987
1988 if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
738835d7 1989 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
e3bc5698 1990
ed21d5bd 1991 return NullUniValue;
e3bc5698
JG
1992}
1993
1994
d014114d 1995UniValue walletlock(const UniValue& params, bool fHelp)
e3bc5698 1996{
b9fb692d 1997 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 1998 return NullUniValue;
70454796 1999
e3bc5698
JG
2000 if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
2001 throw runtime_error(
2002 "walletlock\n"
a6099ef3 2003 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
e3bc5698 2004 "After calling this method, you will need to call walletpassphrase again\n"
a6099ef3 2005 "before being able to call any methods which require the wallet to be unlocked.\n"
2006 "\nExamples:\n"
2007 "\nSet the passphrase for 2 minutes to perform a transaction\n"
2008 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
2009 "\nPerform a send (requires passphrase set)\n"
70454796 2010 + HelpExampleCli("sendtoaddress", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
a6099ef3 2011 "\nClear the passphrase since we are done before 2 minutes is up\n"
2012 + HelpExampleCli("walletlock", "") +
2013 "\nAs json rpc call\n"
2014 + HelpExampleRpc("walletlock", "")
2015 );
2016
4401b2d7
EL
2017 LOCK2(cs_main, pwalletMain->cs_wallet);
2018
e3bc5698
JG
2019 if (fHelp)
2020 return true;
2021 if (!pwalletMain->IsCrypted())
738835d7 2022 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
e3bc5698
JG
2023
2024 {
2025 LOCK(cs_nWalletUnlockTime);
2026 pwalletMain->Lock();
2027 nWalletUnlockTime = 0;
2028 }
2029
ed21d5bd 2030 return NullUniValue;
e3bc5698
JG
2031}
2032
2033
d014114d 2034UniValue encryptwallet(const UniValue& params, bool fHelp)
e3bc5698 2035{
b9fb692d 2036 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2037 return NullUniValue;
62c0aa9e 2038
66dfcc13
LR
2039 string enableArg = "developerencryptwallet";
2040 auto fEnableWalletEncryption = fExperimentalMode && GetBoolArg("-" + enableArg, false);
62c0aa9e
JG
2041
2042 std::string strWalletEncryptionDisabledMsg = "";
2043 if (!fEnableWalletEncryption) {
66dfcc13 2044 strWalletEncryptionDisabledMsg = experimentalDisabledHelpMsg("encryptwallet", enableArg);
62c0aa9e
JG
2045 }
2046
e3bc5698
JG
2047 if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
2048 throw runtime_error(
a6099ef3 2049 "encryptwallet \"passphrase\"\n"
62c0aa9e 2050 + strWalletEncryptionDisabledMsg +
a6099ef3 2051 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2052 "After this, any calls that interact with private keys such as sending or signing \n"
2053 "will require the passphrase to be set prior the making these calls.\n"
2054 "Use the walletpassphrase call for this, and then walletlock call.\n"
2055 "If the wallet is already encrypted, use the walletpassphrasechange call.\n"
2056 "Note that this will shutdown the server.\n"
2057 "\nArguments:\n"
2058 "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n"
2059 "\nExamples:\n"
2060 "\nEncrypt you wallet\n"
2061 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
c1652849 2062 "\nNow set the passphrase to use the wallet, such as for signing or sending Zcash\n"
a6099ef3 2063 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2064 "\nNow we can so something like sign\n"
58c4c0bb 2065 + HelpExampleCli("signmessage", "\"zcashaddress\" \"test message\"") +
a6099ef3 2066 "\nNow lock the wallet again by removing the passphrase\n"
2067 + HelpExampleCli("walletlock", "") +
2068 "\nAs a json rpc call\n"
2069 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2070 );
2071
4401b2d7
EL
2072 LOCK2(cs_main, pwalletMain->cs_wallet);
2073
e3bc5698
JG
2074 if (fHelp)
2075 return true;
62c0aa9e 2076 if (!fEnableWalletEncryption) {
1532cb75 2077 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet encryption is disabled.");
62c0aa9e 2078 }
e3bc5698 2079 if (pwalletMain->IsCrypted())
738835d7 2080 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
e3bc5698
JG
2081
2082 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2083 // Alternately, find a way to make params[0] mlock()'d to begin with.
2084 SecureString strWalletPass;
2085 strWalletPass.reserve(100);
2086 strWalletPass = params[0].get_str().c_str();
2087
2088 if (strWalletPass.length() < 1)
2089 throw runtime_error(
2090 "encryptwallet <passphrase>\n"
2091 "Encrypts the wallet with <passphrase>.");
2092
2093 if (!pwalletMain->EncryptWallet(strWalletPass))
738835d7 2094 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
e3bc5698
JG
2095
2096 // BDB seems to have a bad habit of writing old data into
2097 // slack space in .dat files; that is bad if the old data is
331544bc 2098 // unencrypted private keys. So:
e3bc5698 2099 StartShutdown();
58c4c0bb 2100 return "wallet encrypted; Zcash server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
e3bc5698
JG
2101}
2102
d014114d 2103UniValue lockunspent(const UniValue& params, bool fHelp)
fdbb537d 2104{
b9fb692d 2105 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2106 return NullUniValue;
70454796 2107
fdbb537d
JG
2108 if (fHelp || params.size() < 1 || params.size() > 2)
2109 throw runtime_error(
a6099ef3 2110 "lockunspent unlock [{\"txid\":\"txid\",\"vout\":n},...]\n"
2111 "\nUpdates list of temporarily unspendable outputs.\n"
90fd8737 2112 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
c1652849 2113 "A locked transaction output will not be chosen by automatic coin selection, when spending Zcash.\n"
a6099ef3 2114 "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2115 "is always cleared (by virtue of process exit) when a node stops or fails.\n"
2116 "Also see the listunspent call\n"
2117 "\nArguments:\n"
2118 "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n"
2119 "2. \"transactions\" (string, required) A json array of objects. Each object the txid (string) vout (numeric)\n"
2120 " [ (json array of json objects)\n"
2121 " {\n"
2122 " \"txid\":\"id\", (string) The transaction id\n"
2123 " \"vout\": n (numeric) The output number\n"
2124 " }\n"
2125 " ,...\n"
2126 " ]\n"
2127
2128 "\nResult:\n"
2129 "true|false (boolean) Whether the command was successful or not\n"
2130
2131 "\nExamples:\n"
2132 "\nList the unspent transactions\n"
2133 + HelpExampleCli("listunspent", "") +
2134 "\nLock an unspent transaction\n"
2135 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2136 "\nList the locked transactions\n"
2137 + HelpExampleCli("listlockunspent", "") +
2138 "\nUnlock the transaction again\n"
2139 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2140 "\nAs a json rpc call\n"
2141 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2142 );
fdbb537d 2143
4401b2d7
EL
2144 LOCK2(cs_main, pwalletMain->cs_wallet);
2145
fdbb537d 2146 if (params.size() == 1)
ed21d5bd 2147 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
fdbb537d 2148 else
ed21d5bd 2149 RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
fdbb537d
JG
2150
2151 bool fUnlock = params[0].get_bool();
2152
2153 if (params.size() == 1) {
2154 if (fUnlock)
2155 pwalletMain->UnlockAllCoins();
2156 return true;
2157 }
2158
851f58f9 2159 UniValue outputs = params[1].get_array();
cc71666a 2160 for (size_t idx = 0; idx < outputs.size(); idx++) {
ed21d5bd
JG
2161 const UniValue& output = outputs[idx];
2162 if (!output.isObject())
15117692 2163 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
d014114d 2164 const UniValue& o = output.get_obj();
fdbb537d 2165
ed21d5bd 2166 RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
fdbb537d
JG
2167
2168 string txid = find_value(o, "txid").get_str();
2169 if (!IsHex(txid))
15117692 2170 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
fdbb537d
JG
2171
2172 int nOutput = find_value(o, "vout").get_int();
2173 if (nOutput < 0)
15117692 2174 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
fdbb537d 2175
34cdc411 2176 COutPoint outpt(uint256S(txid), nOutput);
fdbb537d
JG
2177
2178 if (fUnlock)
2179 pwalletMain->UnlockCoin(outpt);
2180 else
2181 pwalletMain->LockCoin(outpt);
2182 }
2183
2184 return true;
2185}
2186
d014114d 2187UniValue listlockunspent(const UniValue& params, bool fHelp)
fdbb537d 2188{
b9fb692d 2189 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2190 return NullUniValue;
70454796 2191
fdbb537d
JG
2192 if (fHelp || params.size() > 0)
2193 throw runtime_error(
2194 "listlockunspent\n"
a6099ef3 2195 "\nReturns list of temporarily unspendable outputs.\n"
2196 "See the lockunspent call to lock and unlock transactions for spending.\n"
2197 "\nResult:\n"
2198 "[\n"
2199 " {\n"
2200 " \"txid\" : \"transactionid\", (string) The transaction id locked\n"
2201 " \"vout\" : n (numeric) The vout value\n"
2202 " }\n"
2203 " ,...\n"
2204 "]\n"
2205 "\nExamples:\n"
2206 "\nList the unspent transactions\n"
2207 + HelpExampleCli("listunspent", "") +
2208 "\nLock an unspent transaction\n"
2209 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2210 "\nList the locked transactions\n"
2211 + HelpExampleCli("listlockunspent", "") +
2212 "\nUnlock the transaction again\n"
2213 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2214 "\nAs a json rpc call\n"
2215 + HelpExampleRpc("listlockunspent", "")
2216 );
fdbb537d 2217
4401b2d7
EL
2218 LOCK2(cs_main, pwalletMain->cs_wallet);
2219
fdbb537d
JG
2220 vector<COutPoint> vOutpts;
2221 pwalletMain->ListLockedCoins(vOutpts);
2222
38fc4b70 2223 UniValue ret(UniValue::VARR);
fdbb537d
JG
2224
2225 BOOST_FOREACH(COutPoint &outpt, vOutpts) {
38fc4b70 2226 UniValue o(UniValue::VOBJ);
fdbb537d
JG
2227
2228 o.push_back(Pair("txid", outpt.hash.GetHex()));
2229 o.push_back(Pair("vout", (int)outpt.n));
2230 ret.push_back(o);
2231 }
2232
2233 return ret;
2234}
2235
d014114d 2236UniValue settxfee(const UniValue& params, bool fHelp)
a943bde6 2237{
b9fb692d 2238 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2239 return NullUniValue;
70454796 2240
a943bde6
WL
2241 if (fHelp || params.size() < 1 || params.size() > 1)
2242 throw runtime_error(
2243 "settxfee amount\n"
6943cb9b 2244 "\nSet the transaction fee per kB.\n"
a943bde6 2245 "\nArguments:\n"
091b2116 2246 "1. amount (numeric, required) The transaction fee in " + CURRENCY_UNIT + "/kB rounded to the nearest 0.00000001\n"
a943bde6
WL
2247 "\nResult\n"
2248 "true|false (boolean) Returns true if successful\n"
2249 "\nExamples:\n"
2250 + HelpExampleCli("settxfee", "0.00001")
2251 + HelpExampleRpc("settxfee", "0.00001")
2252 );
2253
4401b2d7
EL
2254 LOCK2(cs_main, pwalletMain->cs_wallet);
2255
a943bde6 2256 // Amount
e76a3849 2257 CAmount nAmount = AmountFromValue(params[0]);
a943bde6 2258
c6cb21d1 2259 payTxFee = CFeeRate(nAmount, 1000);
a943bde6
WL
2260 return true;
2261}
2262
d014114d 2263UniValue getwalletinfo(const UniValue& params, bool fHelp)
a00ebb51 2264{
b9fb692d 2265 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2266 return NullUniValue;
70454796 2267
a00ebb51
DN
2268 if (fHelp || params.size() != 0)
2269 throw runtime_error(
2270 "getwalletinfo\n"
2271 "Returns an object containing various wallet state info.\n"
2272 "\nResult:\n"
2273 "{\n"
2274 " \"walletversion\": xxxxx, (numeric) the wallet version\n"
091b2116
RN
2275 " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2276 " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
2277 " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n"
a00ebb51
DN
2278 " \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
2279 " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
2280 " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
2281 " \"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"
091b2116 2282 " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
82e71233 2283 " \"seedfp\": \"uint256\", (string) the BLAKE2b-256 hash of the HD seed\n"
a00ebb51
DN
2284 "}\n"
2285 "\nExamples:\n"
2286 + HelpExampleCli("getwalletinfo", "")
2287 + HelpExampleRpc("getwalletinfo", "")
2288 );
2289
4401b2d7
EL
2290 LOCK2(cs_main, pwalletMain->cs_wallet);
2291
38fc4b70 2292 UniValue obj(UniValue::VOBJ);
a00ebb51
DN
2293 obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
2294 obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
8024d67d
GM
2295 obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
2296 obj.push_back(Pair("immature_balance", ValueFromAmount(pwalletMain->GetImmatureBalance())));
a00ebb51 2297 obj.push_back(Pair("txcount", (int)pwalletMain->mapWallet.size()));
d56e30ca 2298 obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
a00ebb51
DN
2299 obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
2300 if (pwalletMain->IsCrypted())
d56e30ca 2301 obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
6699b425 2302 obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
82e71233
JS
2303 uint256 seedFp = pwalletMain->GetHDChain().seedFp;
2304 if (!seedFp.IsNull())
2305 obj.push_back(Pair("seedfp", seedFp.GetHex()));
a00ebb51
DN
2306 return obj;
2307}
0f5954c4 2308
d014114d 2309UniValue resendwallettransactions(const UniValue& params, bool fHelp)
0f5954c4 2310{
b9fb692d 2311 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2312 return NullUniValue;
70454796 2313
0f5954c4
GA
2314 if (fHelp || params.size() != 0)
2315 throw runtime_error(
2316 "resendwallettransactions\n"
2317 "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
2318 "Intended only for testing; the wallet code periodically re-broadcasts\n"
2319 "automatically.\n"
2320 "Returns array of transaction ids that were re-broadcast.\n"
2321 );
2322
2323 LOCK2(cs_main, pwalletMain->cs_wallet);
2324
2325 std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
38fc4b70 2326 UniValue result(UniValue::VARR);
0f5954c4
GA
2327 BOOST_FOREACH(const uint256& txid, txids)
2328 {
2329 result.push_back(txid.ToString());
2330 }
2331 return result;
2332}
0b9dc9c8 2333
d014114d 2334UniValue listunspent(const UniValue& params, bool fHelp)
0b9dc9c8
JS
2335{
2336 if (!EnsureWalletIsAvailable(fHelp))
9756b7bd 2337 return NullUniValue;
70454796 2338
0b9dc9c8 2339 if (fHelp || params.size() > 3)
ea9e82df
JS
2340 throw runtime_error(
2341 "listunspent ( minconf maxconf [\"address\",...] )\n"
2342 "\nReturns array of unspent transaction outputs\n"
2343 "with between minconf and maxconf (inclusive) confirmations.\n"
2344 "Optionally filter to only include txouts paid to specified addresses.\n"
2345 "Results are an array of Objects, each of which has:\n"
2346 "{txid, vout, scriptPubKey, amount, confirmations}\n"
2347 "\nArguments:\n"
2348 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2349 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
d2c1e4a8 2350 "3. \"addresses\" (string) A json array of Zcash addresses to filter\n"
ea9e82df 2351 " [\n"
d2c1e4a8 2352 " \"address\" (string) Zcash address\n"
ea9e82df
JS
2353 " ,...\n"
2354 " ]\n"
2355 "\nResult\n"
2356 "[ (array of json object)\n"
2357 " {\n"
181c511c 2358 " \"txid\" : \"txid\", (string) the transaction id \n"
ea9e82df 2359 " \"vout\" : n, (numeric) the vout value\n"
d77a0ac4 2360 " \"generated\" : true|false (boolean) true if txout is a coinbase transaction output\n"
181c511c
PB
2361 " \"address\" : \"address\", (string) the Zcash address\n"
2362 " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
2363 " \"scriptPubKey\" : \"key\", (string) the script key\n"
091b2116 2364 " \"amount\" : x.xxx, (numeric) the transaction amount in " + CURRENCY_UNIT + "\n"
181c511c
PB
2365 " \"confirmations\" : n, (numeric) The number of confirmations\n"
2366 " \"redeemScript\" : n (string) The redeemScript if scriptPubKey is P2SH\n"
2367 " \"spendable\" : xxx (bool) Whether we have the private keys to spend this output\n"
ea9e82df
JS
2368 " }\n"
2369 " ,...\n"
2370 "]\n"
2371
2372 "\nExamples\n"
2373 + HelpExampleCli("listunspent", "")
70454796
JG
2374 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
2375 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"t1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"t1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
ea9e82df
JS
2376 );
2377
9756b7bd 2378 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
ea9e82df 2379
0b9dc9c8
JS
2380 int nMinDepth = 1;
2381 if (params.size() > 0)
ea9e82df
JS
2382 nMinDepth = params[0].get_int();
2383
0b9dc9c8
JS
2384 int nMaxDepth = 9999999;
2385 if (params.size() > 1)
ea9e82df
JS
2386 nMaxDepth = params[1].get_int();
2387
07444da1 2388 std::set<CTxDestination> destinations;
0b9dc9c8 2389 if (params.size() > 2) {
851f58f9 2390 UniValue inputs = params[2].get_array();
cc71666a 2391 for (size_t idx = 0; idx < inputs.size(); idx++) {
d014114d 2392 const UniValue& input = inputs[idx];
07444da1
PW
2393 CTxDestination dest = DecodeDestination(input.get_str());
2394 if (!IsValidDestination(dest)) {
2395 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Zcash address: ") + input.get_str());
2396 }
2397 if (!destinations.insert(dest).second) {
2398 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
2399 }
0b9dc9c8
JS
2400 }
2401 }
ea9e82df 2402
38fc4b70 2403 UniValue results(UniValue::VARR);
0b9dc9c8
JS
2404 vector<COutput> vecOutputs;
2405 assert(pwalletMain != NULL);
2406 LOCK2(cs_main, pwalletMain->cs_wallet);
219953ce 2407 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
0b9dc9c8
JS
2408 BOOST_FOREACH(const COutput& out, vecOutputs) {
2409 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
ea9e82df
JS
2410 continue;
2411
181c511c
PB
2412 CTxDestination address;
2413 const CScript& scriptPubKey = out.tx->vout[out.i].scriptPubKey;
2414 bool fValidAddress = ExtractDestination(scriptPubKey, address);
ea9e82df 2415
07444da1 2416 if (destinations.size() && (!fValidAddress || !destinations.count(address)))
181c511c 2417 continue;
ea9e82df 2418
38fc4b70 2419 UniValue entry(UniValue::VOBJ);
805344dc 2420 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
0b9dc9c8 2421 entry.push_back(Pair("vout", out.i));
d77a0ac4 2422 entry.push_back(Pair("generated", out.tx->IsCoinBase()));
181c511c
PB
2423
2424 if (fValidAddress) {
07444da1 2425 entry.push_back(Pair("address", EncodeDestination(address)));
181c511c 2426
0b9dc9c8 2427 if (pwalletMain->mapAddressBook.count(address))
ea9e82df 2428 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
181c511c
PB
2429
2430 if (scriptPubKey.IsPayToScriptHash()) {
8b08d953 2431 const CScriptID& hash = boost::get<CScriptID>(address);
0b9dc9c8
JS
2432 CScript redeemScript;
2433 if (pwalletMain->GetCScript(hash, redeemScript))
ea9e82df 2434 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
0b9dc9c8
JS
2435 }
2436 }
181c511c
PB
2437
2438 entry.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
2439 entry.push_back(Pair("amount", ValueFromAmount(out.tx->vout[out.i].nValue)));
2440 entry.push_back(Pair("confirmations", out.nDepth));
0b9dc9c8
JS
2441 entry.push_back(Pair("spendable", out.fSpendable));
2442 results.push_back(entry);
2443 }
ea9e82df 2444
0b9dc9c8 2445 return results;
c9fd9078 2446}
730790f7 2447
d72c19a6
S
2448
2449UniValue z_listunspent(const UniValue& params, bool fHelp)
2450{
2451 if (!EnsureWalletIsAvailable(fHelp))
2452 return NullUniValue;
2453
2454 if (fHelp || params.size() > 4)
2455 throw runtime_error(
2456 "z_listunspent ( minconf maxconf includeWatchonly [\"zaddr\",...] )\n"
2457 "\nReturns array of unspent shielded notes with between minconf and maxconf (inclusive) confirmations.\n"
2458 "Optionally filter to only include notes sent to specified addresses.\n"
2459 "When minconf is 0, unspent notes with zero confirmations are returned, even though they are not immediately spendable.\n"
2460 "Results are an array of Objects, each of which has:\n"
5f57babd
S
2461 "{txid, jsindex, jsoutindex, confirmations, address, amount, memo} (Sprout)\n"
2462 "{txid, outindex, confirmations, address, amount, memo} (Sapling)\n"
d72c19a6
S
2463 "\nArguments:\n"
2464 "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n"
2465 "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n"
2466 "3. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
66795a40 2467 "4. \"addresses\" (string) A json array of zaddrs (both Sprout and Sapling) to filter on. Duplicate addresses not allowed.\n"
d72c19a6
S
2468 " [\n"
2469 " \"address\" (string) zaddr\n"
2470 " ,...\n"
2471 " ]\n"
2472 "\nResult\n"
2473 "[ (array of json object)\n"
2474 " {\n"
2475 " \"txid\" : \"txid\", (string) the transaction id \n"
2476 " \"jsindex\" : n (numeric) the joinsplit index\n"
06f2a8f9
JG
2477 " \"jsoutindex\" (sprout) : n (numeric) the output index of the joinsplit\n"
2478 " \"outindex\" (sapling) : n (numeric) the output index\n"
d72c19a6
S
2479 " \"confirmations\" : n (numeric) the number of confirmations\n"
2480 " \"spendable\" : true|false (boolean) true if note can be spent by wallet, false if note has zero confirmations, false if address is watchonly\n"
2481 " \"address\" : \"address\", (string) the shielded address\n"
2482 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
2483 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
0646f749 2484 " \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n"
d72c19a6
S
2485 " }\n"
2486 " ,...\n"
2487 "]\n"
2488
2489 "\nExamples\n"
2490 + HelpExampleCli("z_listunspent", "")
2491 + HelpExampleCli("z_listunspent", "6 9999999 false \"[\\\"ztbx5DLDxa5ZLFTchHhoPNkKs57QzSyib6UqXpEdy76T1aUdFxJt1w9318Z8DJ73XzbnWHKEZP9Yjg712N5kMmP4QzS9iC9\\\",\\\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\\\"]\"")
2492 + HelpExampleRpc("z_listunspent", "6 9999999 false \"[\\\"ztbx5DLDxa5ZLFTchHhoPNkKs57QzSyib6UqXpEdy76T1aUdFxJt1w9318Z8DJ73XzbnWHKEZP9Yjg712N5kMmP4QzS9iC9\\\",\\\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\\\"]\"")
2493 );
2494
2495 RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VBOOL)(UniValue::VARR));
2496
2497 int nMinDepth = 1;
2498 if (params.size() > 0) {
2499 nMinDepth = params[0].get_int();
2500 }
2501 if (nMinDepth < 0) {
2502 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
2503 }
2504
2505 int nMaxDepth = 9999999;
2506 if (params.size() > 1) {
2507 nMaxDepth = params[1].get_int();
2508 }
2509 if (nMaxDepth < nMinDepth) {
2510 throw JSONRPCError(RPC_INVALID_PARAMETER, "Maximum number of confirmations must be greater or equal to the minimum number of confirmations");
2511 }
2512
2513 std::set<libzcash::PaymentAddress> zaddrs = {};
2514
2515 bool fIncludeWatchonly = false;
2516 if (params.size() > 2) {
2517 fIncludeWatchonly = params[2].get_bool();
2518 }
2519
2520 LOCK2(cs_main, pwalletMain->cs_wallet);
2521
2522 // User has supplied zaddrs to filter on
2523 if (params.size() > 3) {
2524 UniValue addresses = params[3].get_array();
2525 if (addresses.size()==0)
2526 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, addresses array is empty.");
2527
2528 // Keep track of addresses to spot duplicates
2529 set<std::string> setAddress;
2530
2531 // Sources
2532 for (const UniValue& o : addresses.getValues()) {
2533 if (!o.isStr()) {
2534 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
2535 }
2536 string address = o.get_str();
80ed13d5 2537 auto zaddr = DecodePaymentAddress(address);
27a6a99c 2538 if (!IsValidPaymentAddress(zaddr)) {
d72c19a6
S
2539 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, address is not a valid zaddr: ") + address);
2540 }
27a6a99c
LR
2541 auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
2542 if (!fIncludeWatchonly && !hasSpendingKey) {
2543 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, spending key for address does not belong to wallet: ") + address);
2544 }
2545 zaddrs.insert(zaddr);
d72c19a6
S
2546
2547 if (setAddress.count(address)) {
2548 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
2549 }
2550 setAddress.insert(address);
2551 }
2552 }
2553 else {
2554 // User did not provide zaddrs, so use default i.e. all addresses
e5eab182 2555 std::set<libzcash::SproutPaymentAddress> sproutzaddrs = {};
25d5e80c 2556 pwalletMain->GetSproutPaymentAddresses(sproutzaddrs);
66795a40 2557
cd1c6e37 2558 // Sapling support
66795a40
JG
2559 std::set<libzcash::SaplingPaymentAddress> saplingzaddrs = {};
2560 pwalletMain->GetSaplingPaymentAddresses(saplingzaddrs);
2561
e5eab182 2562 zaddrs.insert(sproutzaddrs.begin(), sproutzaddrs.end());
66795a40 2563 zaddrs.insert(saplingzaddrs.begin(), saplingzaddrs.end());
d72c19a6
S
2564 }
2565
2566 UniValue results(UniValue::VARR);
2567
2568 if (zaddrs.size() > 0) {
9396b85d
EOW
2569 std::vector<CSproutNotePlaintextEntry> sproutEntries;
2570 std::vector<SaplingNoteEntry> saplingEntries;
94e99acd 2571 pwalletMain->GetUnspentFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, !fIncludeWatchonly);
0646f749 2572 std::set<std::pair<PaymentAddress, uint256>> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs);
66795a40 2573
9396b85d 2574 for (auto & entry : sproutEntries) {
d72c19a6 2575 UniValue obj(UniValue::VOBJ);
0646f749 2576 obj.push_back(Pair("txid", entry.jsop.hash.ToString()));
d72c19a6
S
2577 obj.push_back(Pair("jsindex", (int)entry.jsop.js ));
2578 obj.push_back(Pair("jsoutindex", (int)entry.jsop.n));
9396b85d 2579 obj.push_back(Pair("confirmations", entry.confirmations));
79298516
EOW
2580 bool hasSproutSpendingKey = pwalletMain->HaveSproutSpendingKey(boost::get<libzcash::SproutPaymentAddress>(entry.address));
2581 obj.push_back(Pair("spendable", hasSproutSpendingKey));
80ed13d5 2582 obj.push_back(Pair("address", EncodePaymentAddress(entry.address)));
d266f403 2583 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value()))));
debf6af9 2584 std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end());
d72c19a6 2585 obj.push_back(Pair("memo", HexStr(data)));
79298516 2586 if (hasSproutSpendingKey) {
e4f0d6a8 2587 obj.push_back(Pair("change", pwalletMain->IsNoteSproutChange(nullifierSet, entry.address, entry.jsop)));
79298516 2588 }
d72c19a6
S
2589 results.push_back(obj);
2590 }
66795a40 2591
9396b85d 2592 for (auto & entry : saplingEntries) {
5f57babd
S
2593 UniValue obj(UniValue::VOBJ);
2594 obj.push_back(Pair("txid", entry.op.hash.ToString()));
2595 obj.push_back(Pair("outindex", (int)entry.op.n));
9396b85d 2596 obj.push_back(Pair("confirmations", entry.confirmations));
5f57babd
S
2597 libzcash::SaplingIncomingViewingKey ivk;
2598 libzcash::SaplingFullViewingKey fvk;
2599 pwalletMain->GetSaplingIncomingViewingKey(boost::get<libzcash::SaplingPaymentAddress>(entry.address), ivk);
2600 pwalletMain->GetSaplingFullViewingKey(ivk, fvk);
2601 bool hasSaplingSpendingKey = pwalletMain->HaveSaplingSpendingKey(fvk);
2602 obj.push_back(Pair("spendable", hasSaplingSpendingKey));
2603 obj.push_back(Pair("address", EncodePaymentAddress(entry.address)));
2604 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value())))); // note.value() is equivalent to plaintext.value()
2605 obj.push_back(Pair("memo", HexStr(entry.memo)));
2606 if (hasSaplingSpendingKey) {
2607 obj.push_back(Pair("change", pwalletMain->IsNoteSaplingChange(nullifierSet, entry.address, entry.op)));
2608 }
2609 results.push_back(obj);
06f2a8f9 2610 }
d72c19a6
S
2611 }
2612
2613 return results;
2614}
2615
2616
3d8013a0
MC
2617UniValue fundrawtransaction(const UniValue& params, bool fHelp)
2618{
2619 if (!EnsureWalletIsAvailable(fHelp))
2620 return NullUniValue;
2621
2622 if (fHelp || params.size() != 1)
2623 throw runtime_error(
2624 "fundrawtransaction \"hexstring\"\n"
2625 "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
2626 "This will not modify existing inputs, and will add one change output to the outputs.\n"
2627 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
2628 "The inputs added will not be signed, use signrawtransaction for that.\n"
2629 "\nArguments:\n"
2630 "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
2631 "\nResult:\n"
2632 "{\n"
2633 " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
2634 " \"fee\": n, (numeric) The fee added to the transaction\n"
2635 " \"changepos\": n (numeric) The position of the added change output, or -1\n"
2636 "}\n"
2637 "\"hex\" \n"
2638 "\nExamples:\n"
2639 "\nCreate a transaction with no inputs\n"
2640 + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
2641 "\nAdd sufficient unsigned inputs to meet the output value\n"
2642 + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
2643 "\nSign the transaction\n"
2644 + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
2645 "\nSend the transaction\n"
2646 + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
2647 );
2648
2649 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
2650
2651 // parse hex string from parameter
2652 CTransaction origTx;
2653 if (!DecodeHexTx(origTx, params[0].get_str()))
2654 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2655
2656 CMutableTransaction tx(origTx);
2657 CAmount nFee;
2658 string strFailReason;
2659 int nChangePos = -1;
2660 if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
2661 throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
2662
2663 UniValue result(UniValue::VOBJ);
2664 result.push_back(Pair("hex", EncodeHexTx(tx)));
2665 result.push_back(Pair("changepos", nChangePos));
2666 result.push_back(Pair("fee", ValueFromAmount(nFee)));
2667
2668 return result;
2669}
2670
0d37ae3a 2671UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp)
1737627c
SB
2672{
2673 if (fHelp) {
2674 throw runtime_error(
2675 "zcsamplejoinsplit\n"
2676 "\n"
2677 "Perform a joinsplit and return the JSDescription.\n"
2678 );
2679 }
2680
2681 LOCK(cs_main);
2682
e1a3461c 2683 uint256 joinSplitPubKey;
4fc309f0 2684 uint256 anchor = SproutMerkleTree().root();
34f6ea95 2685 JSDescription samplejoinsplit(true,
b7a6c321 2686 *pzcashParams,
e1a3461c 2687 joinSplitPubKey,
1737627c
SB
2688 anchor,
2689 {JSInput(), JSInput()},
2690 {JSOutput(), JSOutput()},
2691 0,
2692 0);
2693
f55029e7 2694 CDataStream ss(SER_NETWORK, SAPLING_TX_VERSION | (1 << 31));
1737627c
SB
2695 ss << samplejoinsplit;
2696
2697 return HexStr(ss.begin(), ss.end());
2698}
2699
0d37ae3a 2700UniValue zc_benchmark(const UniValue& params, bool fHelp)
6962bb3d
TH
2701{
2702 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 2703 return NullUniValue;
6962bb3d
TH
2704 }
2705
2706 if (fHelp || params.size() < 2) {
2707 throw runtime_error(
2708 "zcbenchmark benchmarktype samplecount\n"
2709 "\n"
2710 "Runs a benchmark of the selected type samplecount times,\n"
2711 "returning the running times of each sample.\n"
2712 "\n"
2713 "Output: [\n"
2714 " {\n"
2715 " \"runningtime\": runningtime\n"
2716 " },\n"
2717 " {\n"
2718 " \"runningtime\": runningtime\n"
2719 " }\n"
2720 " ...\n"
2721 "]\n"
2722 );
2723 }
2724
2725 LOCK(cs_main);
2726
2727 std::string benchmarktype = params[0].get_str();
2728 int samplecount = params[1].get_int();
2729
2730 if (samplecount <= 0) {
2731 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount");
2732 }
2733
2734 std::vector<double> sample_times;
2735
1737627c 2736 JSDescription samplejoinsplit;
2fbbde59
SB
2737
2738 if (benchmarktype == "verifyjoinsplit") {
f55029e7 2739 CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, SAPLING_TX_VERSION | (1 << 31));
1737627c 2740 ss >> samplejoinsplit;
2fbbde59
SB
2741 }
2742
6962bb3d
TH
2743 for (int i = 0; i < samplecount; i++) {
2744 if (benchmarktype == "sleep") {
2745 sample_times.push_back(benchmark_sleep());
2746 } else if (benchmarktype == "parameterloading") {
2747 sample_times.push_back(benchmark_parameter_loading());
2748 } else if (benchmarktype == "createjoinsplit") {
4082dcb1
JG
2749 if (params.size() < 3) {
2750 sample_times.push_back(benchmark_create_joinsplit());
2751 } else {
2752 int nThreads = params[2].get_int();
2753 std::vector<double> vals = benchmark_create_joinsplit_threaded(nThreads);
2754 // Divide by nThreads^2 to get average seconds per JoinSplit because
2755 // we are running one JoinSplit per thread.
2756 sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads));
2757 }
6962bb3d 2758 } else if (benchmarktype == "verifyjoinsplit") {
1737627c 2759 sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit));
2cc0a252 2760#ifdef ENABLE_MINING
bf8def97 2761 } else if (benchmarktype == "solveequihash") {
f7478de6 2762 if (params.size() < 3) {
9e52ca32 2763 sample_times.push_back(benchmark_solve_equihash());
f7478de6
JG
2764 } else {
2765 int nThreads = params[2].get_int();
9e52ca32
JG
2766 std::vector<double> vals = benchmark_solve_equihash_threaded(nThreads);
2767 sample_times.insert(sample_times.end(), vals.begin(), vals.end());
f7478de6 2768 }
2cc0a252 2769#endif
bf8def97 2770 } else if (benchmarktype == "verifyequihash") {
a1cd1a27 2771 sample_times.push_back(benchmark_verify_equihash());
f5edc37f 2772 } else if (benchmarktype == "validatelargetx") {
818b94f9 2773 // Number of inputs in the spending transaction that we will simulate
ddcee7e1 2774 int nInputs = 11130;
818b94f9
JG
2775 if (params.size() >= 3) {
2776 nInputs = params[2].get_int();
2777 }
2778 sample_times.push_back(benchmark_large_tx(nInputs));
0fbab55b 2779 } else if (benchmarktype == "trydecryptnotes") {
88b7f3c2
JG
2780 int nAddrs = params[2].get_int();
2781 sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
0bb3d40f
JG
2782 } else if (benchmarktype == "incnotewitnesses") {
2783 int nTxs = params[2].get_int();
2784 sample_times.push_back(benchmark_increment_note_witnesses(nTxs));
c66c731a
JG
2785 } else if (benchmarktype == "connectblockslow") {
2786 if (Params().NetworkIDString() != "regtest") {
2787 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2788 }
2789 sample_times.push_back(benchmark_connectblock_slow());
a76174b7
JG
2790 } else if (benchmarktype == "sendtoaddress") {
2791 if (Params().NetworkIDString() != "regtest") {
2792 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2793 }
2794 auto amount = AmountFromValue(params[2]);
2795 sample_times.push_back(benchmark_sendtoaddress(amount));
2e8aefdc
AG
2796 } else if (benchmarktype == "loadwallet") {
2797 if (Params().NetworkIDString() != "regtest") {
2798 throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode");
2799 }
2800 sample_times.push_back(benchmark_loadwallet());
99dd50c3
JG
2801 } else if (benchmarktype == "listunspent") {
2802 sample_times.push_back(benchmark_listunspent());
6962bb3d
TH
2803 } else {
2804 throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype");
2805 }
2806 }
2807
0d37ae3a 2808 UniValue results(UniValue::VARR);
9e52ca32 2809 for (auto time : sample_times) {
0d37ae3a 2810 UniValue result(UniValue::VOBJ);
9e52ca32 2811 result.push_back(Pair("runningtime", time));
6962bb3d
TH
2812 results.push_back(result);
2813 }
2814
2815 return results;
2816}
2817
0d37ae3a 2818UniValue zc_raw_receive(const UniValue& params, bool fHelp)
a8ac403d 2819{
f15b9549 2820 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 2821 return NullUniValue;
f15b9549
NW
2822 }
2823
2824 if (fHelp || params.size() != 2) {
2825 throw runtime_error(
eae37941 2826 "zcrawreceive zcsecretkey encryptednote\n"
f15b9549 2827 "\n"
ca0ec80b 2828 "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n"
f15b9549
NW
2829 "are in the blockchain as indicated by the \"exists\" result.\n"
2830 "\n"
2831 "Output: {\n"
2832 " \"amount\": value,\n"
4bc00dc1 2833 " \"note\": noteplaintext,\n"
f15b9549
NW
2834 " \"exists\": exists\n"
2835 "}\n"
2836 );
2837 }
2838
0d37ae3a 2839 RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR));
f15b9549 2840
a8ac403d
SB
2841 LOCK(cs_main);
2842
472f75bc 2843 auto spendingkey = DecodeSpendingKey(params[0].get_str());
e5eab182 2844 if (!IsValidSpendingKey(spendingkey)) {
472f75bc
JG
2845 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
2846 }
e5eab182
JG
2847 if (boost::get<libzcash::SproutSpendingKey>(&spendingkey) == nullptr) {
2848 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout spending keys");
2849 }
2850 SproutSpendingKey k = boost::get<libzcash::SproutSpendingKey>(spendingkey);
a8ac403d 2851
6c36a9fe
SB
2852 uint256 epk;
2853 unsigned char nonce;
2854 ZCNoteEncryption::Ciphertext ct;
2dc35992 2855 uint256 h_sig;
6c36a9fe
SB
2856
2857 {
4bc00dc1 2858 CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION);
6c36a9fe
SB
2859 try {
2860 ssData >> nonce;
2861 ssData >> epk;
2862 ssData >> ct;
2dc35992 2863 ssData >> h_sig;
6c36a9fe
SB
2864 } catch(const std::exception &) {
2865 throw runtime_error(
4bc00dc1 2866 "encrypted_note could not be decoded"
6c36a9fe
SB
2867 );
2868 }
2869 }
2870
642a1caf 2871 ZCNoteDecryption decryptor(k.receiving_key());
a8ac403d 2872
5020a936 2873 SproutNotePlaintext npt = SproutNotePlaintext::decrypt(
2dc35992
SB
2874 decryptor,
2875 ct,
2876 epk,
2877 h_sig,
2878 nonce
2879 );
e5eab182 2880 SproutPaymentAddress payment_addr = k.address();
b230fe68 2881 SproutNote decrypted_note = npt.note(payment_addr);
a8ac403d
SB
2882
2883 assert(pwalletMain != NULL);
8ea8ef98 2884 std::vector<boost::optional<SproutWitness>> witnesses;
a8ac403d 2885 uint256 anchor;
2dc35992 2886 uint256 commitment = decrypted_note.cm();
4bc00dc1 2887 pwalletMain->WitnessNoteCommitment(
2dc35992
SB
2888 {commitment},
2889 witnesses,
2890 anchor
2891 );
a8ac403d
SB
2892
2893 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
2dc35992 2894 ss << npt;
a8ac403d 2895
0d37ae3a 2896 UniValue result(UniValue::VOBJ);
5d99e3e9 2897 result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value())));
4bc00dc1 2898 result.push_back(Pair("note", HexStr(ss.begin(), ss.end())));
2dc35992 2899 result.push_back(Pair("exists", (bool) witnesses[0]));
a8ac403d
SB
2900 return result;
2901}
2902
2dc35992
SB
2903
2904
0d37ae3a 2905UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
730790f7 2906{
f15b9549 2907 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 2908 return NullUniValue;
f15b9549
NW
2909 }
2910
2911 if (fHelp || params.size() != 5) {
2912 throw runtime_error(
eae37941 2913 "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n"
4bc00dc1 2914 " inputs: a JSON object mapping {note: zcsecretkey, ...}\n"
f15b9549
NW
2915 " outputs: a JSON object mapping {zcaddr: value, ...}\n"
2916 "\n"
ca0ec80b 2917 "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n"
f15b9549
NW
2918 "Outputs are confidential between sender/receiver. The vpub_old and\n"
2919 "vpub_new values are globally public and move transparent value into\n"
2920 "or out of the confidential value store, respectively.\n"
2921 "\n"
2922 "Note: The caller is responsible for delivering the output enc1 and\n"
2923 "enc2 to the appropriate recipients, as well as signing rawtxout and\n"
2924 "ensuring it is mined. (A future RPC call will deliver the confidential\n"
2925 "payments in-band on the blockchain.)\n"
2926 "\n"
2927 "Output: {\n"
4bc00dc1
DH
2928 " \"encryptednote1\": enc1,\n"
2929 " \"encryptednote2\": enc2,\n"
f15b9549
NW
2930 " \"rawtxn\": rawtxout\n"
2931 "}\n"
2932 );
2933 }
2934
a8ac403d 2935 LOCK(cs_main);
730790f7
SB
2936
2937 CTransaction tx;
2938 if (!DecodeHexTx(tx, params[0].get_str()))
2939 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
2940
0d37ae3a
JG
2941 UniValue inputs = params[1].get_obj();
2942 UniValue outputs = params[2].get_obj();
730790f7
SB
2943
2944 CAmount vpub_old(0);
2945 CAmount vpub_new(0);
2946
2947 if (params[3].get_real() != 0.0)
2948 vpub_old = AmountFromValue(params[3]);
2949
2950 if (params[4].get_real() != 0.0)
2951 vpub_new = AmountFromValue(params[4]);
2952
b7e4abd6
SB
2953 std::vector<JSInput> vjsin;
2954 std::vector<JSOutput> vjsout;
b230fe68 2955 std::vector<SproutNote> notes;
e5eab182 2956 std::vector<SproutSpendingKey> keys;
2dc35992 2957 std::vector<uint256> commitments;
a8ac403d 2958
0d37ae3a 2959 for (const string& name_ : inputs.getKeys()) {
472f75bc 2960 auto spendingkey = DecodeSpendingKey(inputs[name_].get_str());
e5eab182 2961 if (!IsValidSpendingKey(spendingkey)) {
472f75bc
JG
2962 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
2963 }
e5eab182
JG
2964 if (boost::get<libzcash::SproutSpendingKey>(&spendingkey) == nullptr) {
2965 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout spending keys");
2966 }
2967 SproutSpendingKey k = boost::get<libzcash::SproutSpendingKey>(spendingkey);
a8ac403d 2968
2dc35992 2969 keys.push_back(k);
a8ac403d 2970
5020a936 2971 SproutNotePlaintext npt;
a8ac403d 2972
2dc35992 2973 {
0d37ae3a 2974 CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION);
2dc35992 2975 ssData >> npt;
a8ac403d
SB
2976 }
2977
e5eab182 2978 SproutPaymentAddress addr = k.address();
b230fe68 2979 SproutNote note = npt.note(addr);
2dc35992
SB
2980 notes.push_back(note);
2981 commitments.push_back(note.cm());
2982 }
2983
2984 uint256 anchor;
8ea8ef98 2985 std::vector<boost::optional<SproutWitness>> witnesses;
4bc00dc1 2986 pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor);
2dc35992
SB
2987
2988 assert(witnesses.size() == notes.size());
2989 assert(notes.size() == keys.size());
2990
2991 {
2992 for (size_t i = 0; i < witnesses.size(); i++) {
2993 if (!witnesses[i]) {
2994 throw runtime_error(
b7e4abd6 2995 "joinsplit input could not be found in tree"
2dc35992
SB
2996 );
2997 }
2998
b7e4abd6 2999 vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i]));
2dc35992 3000 }
730790f7 3001 }
730790f7 3002
b7e4abd6
SB
3003 while (vjsin.size() < ZC_NUM_JS_INPUTS) {
3004 vjsin.push_back(JSInput());
a8ac403d 3005 }
730790f7 3006
0d37ae3a 3007 for (const string& name_ : outputs.getKeys()) {
80ed13d5 3008 auto addrTo = DecodePaymentAddress(name_);
e5eab182 3009 if (!IsValidPaymentAddress(addrTo)) {
80ed13d5
JG
3010 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address.");
3011 }
e5eab182
JG
3012 if (boost::get<libzcash::SproutPaymentAddress>(&addrTo) == nullptr) {
3013 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout payment addresses");
3014 }
0d37ae3a 3015 CAmount nAmount = AmountFromValue(outputs[name_]);
730790f7 3016
e5eab182 3017 vjsout.push_back(JSOutput(boost::get<libzcash::SproutPaymentAddress>(addrTo), nAmount));
730790f7
SB
3018 }
3019
b7e4abd6
SB
3020 while (vjsout.size() < ZC_NUM_JS_OUTPUTS) {
3021 vjsout.push_back(JSOutput());
730790f7
SB
3022 }
3023
3024 // TODO
b7e4abd6
SB
3025 if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) {
3026 throw runtime_error("unsupported joinsplit input/output counts");
730790f7
SB
3027 }
3028
320f2cc7
SB
3029 uint256 joinSplitPubKey;
3030 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
3031 crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey);
6aae9d1a
TH
3032
3033 CMutableTransaction mtx(tx);
3034 mtx.nVersion = 2;
3035 mtx.joinSplitPubKey = joinSplitPubKey;
3036
b7a6c321
SB
3037 JSDescription jsdesc(false,
3038 *pzcashParams,
22de1602
SB
3039 joinSplitPubKey,
3040 anchor,
3041 {vjsin[0], vjsin[1]},
3042 {vjsout[0], vjsout[1]},
3043 vpub_old,
3044 vpub_new);
320f2cc7 3045
bc59f537
SB
3046 {
3047 auto verifier = libzcash::ProofVerifier::Strict();
3048 assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey));
3049 }
730790f7 3050
22de1602 3051 mtx.vjoinsplit.push_back(jsdesc);
730790f7 3052
6aae9d1a
TH
3053 // Empty output script.
3054 CScript scriptCode;
3055 CTransaction signTx(mtx);
be126699
JG
3056 auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
3057 uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
6aae9d1a
TH
3058
3059 // Add the signature
320f2cc7
SB
3060 assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
3061 dataToBeSigned.begin(), 32,
3062 joinSplitPrivKey
3063 ) == 0);
3064
3065 // Sanity check
3066 assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
3067 dataToBeSigned.begin(), 32,
3068 mtx.joinSplitPubKey.begin()
3069 ) == 0);
6aae9d1a 3070
730790f7
SB
3071 CTransaction rawTx(mtx);
3072
3073 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
3074 ss << rawTx;
3075
4bc00dc1
DH
3076 std::string encryptedNote1;
3077 std::string encryptedNote2;
6c36a9fe
SB
3078 {
3079 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
3080 ss2 << ((unsigned char) 0x00);
22de1602
SB
3081 ss2 << jsdesc.ephemeralKey;
3082 ss2 << jsdesc.ciphertexts[0];
3083 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
6c36a9fe 3084
4bc00dc1 3085 encryptedNote1 = HexStr(ss2.begin(), ss2.end());
6c36a9fe
SB
3086 }
3087 {
3088 CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
3089 ss2 << ((unsigned char) 0x01);
22de1602
SB
3090 ss2 << jsdesc.ephemeralKey;
3091 ss2 << jsdesc.ciphertexts[1];
3092 ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey);
6c36a9fe 3093
4bc00dc1 3094 encryptedNote2 = HexStr(ss2.begin(), ss2.end());
6c36a9fe
SB
3095 }
3096
0d37ae3a 3097 UniValue result(UniValue::VOBJ);
4bc00dc1
DH
3098 result.push_back(Pair("encryptednote1", encryptedNote1));
3099 result.push_back(Pair("encryptednote2", encryptedNote2));
730790f7
SB
3100 result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
3101 return result;
3102}
3103
0d37ae3a 3104UniValue zc_raw_keygen(const UniValue& params, bool fHelp)
730790f7 3105{
f15b9549 3106 if (!EnsureWalletIsAvailable(fHelp)) {
0d37ae3a 3107 return NullUniValue;
f15b9549
NW
3108 }
3109
3110 if (fHelp || params.size() != 0) {
3111 throw runtime_error(
eae37941 3112 "zcrawkeygen\n"
f15b9549 3113 "\n"
ca0ec80b 3114 "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n"
f15b9549
NW
3115 "\n"
3116 "Output: {\n"
3117 " \"zcaddress\": zcaddr,\n"
3118 " \"zcsecretkey\": zcsecretkey,\n"
7b8d4f87 3119 " \"zcviewingkey\": zcviewingkey,\n"
f15b9549
NW
3120 "}\n"
3121 );
3122 }
3123
e5eab182 3124 auto k = SproutSpendingKey::random();
2dc35992
SB
3125 auto addr = k.address();
3126 auto viewing_key = k.viewing_key();
730790f7 3127
0d37ae3a 3128 UniValue result(UniValue::VOBJ);
80ed13d5 3129 result.push_back(Pair("zcaddress", EncodePaymentAddress(addr)));
472f75bc 3130 result.push_back(Pair("zcsecretkey", EncodeSpendingKey(k)));
8bf3a3d7 3131 result.push_back(Pair("zcviewingkey", EncodeViewingKey(viewing_key)));
730790f7 3132 return result;
f15b9549 3133}
c1c45943
S
3134
3135
0d37ae3a 3136UniValue z_getnewaddress(const UniValue& params, bool fHelp)
c1c45943
S
3137{
3138 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3139 return NullUniValue;
c1c45943 3140
eec85c43
JG
3141 std::string defaultType = ADDR_TYPE_SPROUT;
3142
3143 if (fHelp || params.size() > 1)
c1c45943 3144 throw runtime_error(
eec85c43
JG
3145 "z_getnewaddress ( type )\n"
3146 "\nReturns a new shielded address for receiving payments.\n"
3147 "\nWith no arguments, returns a Sprout address.\n"
c1c45943 3148 "\nArguments:\n"
eec85c43
JG
3149 "1. \"type\" (string, optional, default=\"" + defaultType + "\") The type of address. One of [\""
3150 + ADDR_TYPE_SPROUT + "\", \"" + ADDR_TYPE_SAPLING + "\"].\n"
c1c45943 3151 "\nResult:\n"
eec85c43 3152 "\"zcashaddress\" (string) The new shielded address.\n"
c1c45943
S
3153 "\nExamples:\n"
3154 + HelpExampleCli("z_getnewaddress", "")
eec85c43 3155 + HelpExampleCli("z_getnewaddress", ADDR_TYPE_SAPLING)
c1c45943
S
3156 + HelpExampleRpc("z_getnewaddress", "")
3157 );
3158
3159 LOCK2(cs_main, pwalletMain->cs_wallet);
3160
73699cea
S
3161 EnsureWalletIsUnlocked();
3162
eec85c43
JG
3163 auto addrType = defaultType;
3164 if (params.size() > 0) {
3165 addrType = params[0].get_str();
3166 }
3167
3168 if (addrType == ADDR_TYPE_SPROUT) {
3169 return EncodePaymentAddress(pwalletMain->GenerateNewZKey());
34e222c1 3170 } else if (addrType == ADDR_TYPE_SAPLING) {
eec85c43
JG
3171 return EncodePaymentAddress(pwalletMain->GenerateNewSaplingZKey());
3172 } else {
3173 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid address type");
3174 }
c1c45943
S
3175}
3176
e709997f 3177
0d37ae3a 3178UniValue z_listaddresses(const UniValue& params, bool fHelp)
e709997f
S
3179{
3180 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3181 return NullUniValue;
e709997f
S
3182
3183 if (fHelp || params.size() > 1)
3184 throw runtime_error(
44e37656 3185 "z_listaddresses ( includeWatchonly )\n"
eec85c43 3186 "\nReturns the list of Sprout and Sapling shielded addresses belonging to the wallet.\n"
e709997f 3187 "\nArguments:\n"
44e37656 3188 "1. includeWatchonly (bool, optional, default=false) Also include watchonly addresses (see 'z_importviewingkey')\n"
e709997f
S
3189 "\nResult:\n"
3190 "[ (json array of string)\n"
3191 " \"zaddr\" (string) a zaddr belonging to the wallet\n"
3192 " ,...\n"
3193 "]\n"
3194 "\nExamples:\n"
3195 + HelpExampleCli("z_listaddresses", "")
3196 + HelpExampleRpc("z_listaddresses", "")
3197 );
3198
3199 LOCK2(cs_main, pwalletMain->cs_wallet);
3200
44e37656
JG
3201 bool fIncludeWatchonly = false;
3202 if (params.size() > 0) {
3203 fIncludeWatchonly = params[0].get_bool();
3204 }
3205
0d37ae3a 3206 UniValue ret(UniValue::VARR);
eec85c43
JG
3207 {
3208 std::set<libzcash::SproutPaymentAddress> addresses;
25d5e80c 3209 pwalletMain->GetSproutPaymentAddresses(addresses);
fbd029d9 3210 for (auto addr : addresses) {
25d5e80c 3211 if (fIncludeWatchonly || pwalletMain->HaveSproutSpendingKey(addr)) {
eec85c43
JG
3212 ret.push_back(EncodePaymentAddress(addr));
3213 }
3214 }
3215 }
3216 {
3217 std::set<libzcash::SaplingPaymentAddress> addresses;
3218 pwalletMain->GetSaplingPaymentAddresses(addresses);
3219 libzcash::SaplingIncomingViewingKey ivk;
3220 libzcash::SaplingFullViewingKey fvk;
fbd029d9 3221 for (auto addr : addresses) {
eec85c43
JG
3222 if (fIncludeWatchonly || (
3223 pwalletMain->GetSaplingIncomingViewingKey(addr, ivk) &&
3224 pwalletMain->GetSaplingFullViewingKey(ivk, fvk) &&
3225 pwalletMain->HaveSaplingSpendingKey(fvk)
3226 )) {
3227 ret.push_back(EncodePaymentAddress(addr));
3228 }
44e37656 3229 }
e709997f
S
3230 }
3231 return ret;
3232}
3233
44e37656 3234CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ignoreUnspendable=true) {
b6be3e88 3235 std::set<CTxDestination> destinations;
a0a3334c 3236 vector<COutput> vecOutputs;
70454796
JG
3237 CAmount balance = 0;
3238
a0a3334c 3239 if (transparentAddress.length() > 0) {
b6be3e88
JG
3240 CTxDestination taddr = DecodeDestination(transparentAddress);
3241 if (!IsValidDestination(taddr)) {
a0a3334c
S
3242 throw std::runtime_error("invalid transparent address");
3243 }
b6be3e88 3244 destinations.insert(taddr);
a0a3334c 3245 }
70454796 3246
a0a3334c
S
3247 LOCK2(cs_main, pwalletMain->cs_wallet);
3248
3249 pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
3250
3251 BOOST_FOREACH(const COutput& out, vecOutputs) {
3252 if (out.nDepth < minDepth) {
3253 continue;
3254 }
3255
44e37656
JG
3256 if (ignoreUnspendable && !out.fSpendable) {
3257 continue;
3258 }
3259
b6be3e88 3260 if (destinations.size()) {
a0a3334c
S
3261 CTxDestination address;
3262 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
3263 continue;
3264 }
3265
b6be3e88 3266 if (!destinations.count(address)) {
a0a3334c
S
3267 continue;
3268 }
3269 }
70454796 3270
a0a3334c
S
3271 CAmount nValue = out.tx->vout[out.i].nValue;
3272 balance += nValue;
3273 }
3274 return balance;
3275}
3276
44e37656 3277CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
a0a3334c 3278 CAmount balance = 0;
94e99acd
JG
3279 std::vector<CSproutNotePlaintextEntry> sproutEntries;
3280 std::vector<SaplingNoteEntry> saplingEntries;
a0a3334c 3281 LOCK2(cs_main, pwalletMain->cs_wallet);
94e99acd
JG
3282 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, address, minDepth, true, ignoreUnspendable);
3283 for (auto & entry : sproutEntries) {
d266f403 3284 balance += CAmount(entry.plaintext.value());
a0a3334c 3285 }
053cb349
JG
3286 for (auto & entry : saplingEntries) {
3287 balance += CAmount(entry.note.value());
3288 }
a0a3334c
S
3289 return balance;
3290}
3291
3292
0d37ae3a 3293UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp)
6c41028f
S
3294{
3295 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3296 return NullUniValue;
6c41028f
S
3297
3298 if (fHelp || params.size()==0 || params.size() >2)
3299 throw runtime_error(
3300 "z_listreceivedbyaddress \"address\" ( minconf )\n"
3301 "\nReturn a list of amounts received by a zaddr belonging to the node’s wallet.\n"
3302 "\nArguments:\n"
3303 "1. \"address\" (string) The private address.\n"
3304 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3305 "\nResult:\n"
3306 "{\n"
0646f749
EOW
3307 " \"txid\": xxxxx, (string) the transaction id\n"
3308 " \"amount\": xxxxx, (numeric) the amount of value in the note\n"
3309 " \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
3310 " \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n"
6c41028f 3311 "}\n"
337a99a2
JG
3312 "\nExamples:\n"
3313 + HelpExampleCli("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3314 + HelpExampleRpc("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
6c41028f
S
3315 );
3316
3317 LOCK2(cs_main, pwalletMain->cs_wallet);
3318
3319 int nMinDepth = 1;
3320 if (params.size() > 1) {
3321 nMinDepth = params[1].get_int();
3322 }
3323 if (nMinDepth < 0) {
3324 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3325 }
70454796 3326
6c41028f
S
3327 // Check that the from address is valid.
3328 auto fromaddress = params[0].get_str();
3329
80ed13d5 3330 auto zaddr = DecodePaymentAddress(fromaddress);
e5eab182 3331 if (!IsValidPaymentAddress(zaddr)) {
6c41028f
S
3332 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
3333 }
3334
e4f0d6a8
LR
3335 // Visitor to support Sprout and Sapling addrs
3336 if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), zaddr)) {
44e37656 3337 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
6c41028f 3338 }
70454796 3339
0d37ae3a 3340 UniValue result(UniValue::VARR);
94e99acd
JG
3341 std::vector<CSproutNotePlaintextEntry> sproutEntries;
3342 std::vector<SaplingNoteEntry> saplingEntries;
3343 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, fromaddress, nMinDepth, false, false);
e4f0d6a8
LR
3344
3345 std::set<std::pair<PaymentAddress, uint256>> nullifierSet;
3346 auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
3347 if (hasSpendingKey) {
3348 nullifierSet = pwalletMain->GetNullifiersForAddresses({zaddr});
3349 }
3350
3351 if (boost::get<libzcash::SproutPaymentAddress>(&zaddr) != nullptr) {
3352 for (CSproutNotePlaintextEntry & entry : sproutEntries) {
3353 UniValue obj(UniValue::VOBJ);
3354 obj.push_back(Pair("txid", entry.jsop.hash.ToString()));
3355 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value()))));
3356 std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end());
3357 obj.push_back(Pair("memo", HexStr(data)));
3358 obj.push_back(Pair("jsindex", entry.jsop.js));
3359 obj.push_back(Pair("jsoutindex", entry.jsop.n));
3360 if (hasSpendingKey) {
3361 obj.push_back(Pair("change", pwalletMain->IsNoteSproutChange(nullifierSet, entry.address, entry.jsop)));
3362 }
3363 result.push_back(obj);
3364 }
3365 } else if (boost::get<libzcash::SaplingPaymentAddress>(&zaddr) != nullptr) {
3366 for (SaplingNoteEntry & entry : saplingEntries) {
3367 UniValue obj(UniValue::VOBJ);
3368 obj.push_back(Pair("txid", entry.op.hash.ToString()));
3369 obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value()))));
3370 obj.push_back(Pair("memo", HexStr(entry.memo)));
3371 obj.push_back(Pair("outindex", (int)entry.op.n));
3372 if (hasSpendingKey) {
3373 obj.push_back(Pair("change", pwalletMain->IsNoteSaplingChange(nullifierSet, entry.address, entry.op)));
3374 }
3375 result.push_back(obj);
79298516 3376 }
6c41028f
S
3377 }
3378 return result;
3379}
3380
0d37ae3a 3381UniValue z_getbalance(const UniValue& params, bool fHelp)
a0a3334c
S
3382{
3383 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3384 return NullUniValue;
a0a3334c
S
3385
3386 if (fHelp || params.size()==0 || params.size() >2)
3387 throw runtime_error(
3388 "z_getbalance \"address\" ( minconf )\n"
3389 "\nReturns the balance of a taddr or zaddr belonging to the node’s wallet.\n"
573de712
JG
3390 "\nCAUTION: If the wallet has only an incoming viewing key for this address, then spends cannot be"
3391 "\ndetected, and so the returned balance may be larger than the actual balance.\n"
a0a3334c
S
3392 "\nArguments:\n"
3393 "1. \"address\" (string) The selected address. It may be a transparent or private address.\n"
3394 "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
3395 "\nResult:\n"
6dec2d03 3396 "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this address.\n"
a0a3334c
S
3397 "\nExamples:\n"
3398 "\nThe total amount received by address \"myaddress\"\n"
3399 + HelpExampleCli("z_getbalance", "\"myaddress\"") +
3400 "\nThe total amount received by address \"myaddress\" at least 5 blocks confirmed\n"
3401 + HelpExampleCli("z_getbalance", "\"myaddress\" 5") +
3402 "\nAs a json rpc call\n"
3403 + HelpExampleRpc("z_getbalance", "\"myaddress\", 5")
3404 );
3405
3406 LOCK2(cs_main, pwalletMain->cs_wallet);
3407
3408 int nMinDepth = 1;
3409 if (params.size() > 1) {
3410 nMinDepth = params[1].get_int();
3411 }
12448b64
S
3412 if (nMinDepth < 0) {
3413 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3414 }
70454796 3415
a0a3334c
S
3416 // Check that the from address is valid.
3417 auto fromaddress = params[0].get_str();
3418 bool fromTaddr = false;
b6be3e88
JG
3419 CTxDestination taddr = DecodeDestination(fromaddress);
3420 fromTaddr = IsValidDestination(taddr);
a0a3334c 3421 if (!fromTaddr) {
80ed13d5 3422 auto res = DecodePaymentAddress(fromaddress);
e5eab182 3423 if (!IsValidPaymentAddress(res)) {
a0a3334c
S
3424 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3425 }
053cb349
JG
3426 if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), res)) {
3427 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, spending key or viewing key not found.");
12448b64 3428 }
a0a3334c
S
3429 }
3430
3431 CAmount nBalance = 0;
3432 if (fromTaddr) {
44e37656 3433 nBalance = getBalanceTaddr(fromaddress, nMinDepth, false);
a0a3334c 3434 } else {
44e37656 3435 nBalance = getBalanceZaddr(fromaddress, nMinDepth, false);
a0a3334c
S
3436 }
3437
3438 return ValueFromAmount(nBalance);
3439}
3440
3441
0d37ae3a 3442UniValue z_gettotalbalance(const UniValue& params, bool fHelp)
a0a3334c
S
3443{
3444 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3445 return NullUniValue;
a0a3334c 3446
44e37656 3447 if (fHelp || params.size() > 2)
a0a3334c 3448 throw runtime_error(
44e37656 3449 "z_gettotalbalance ( minconf includeWatchonly )\n"
a0a3334c 3450 "\nReturn the total value of funds stored in the node’s wallet.\n"
573de712
JG
3451 "\nCAUTION: If the wallet contains any addresses for which it only has incoming viewing keys,"
3452 "\nthe returned private balance may be larger than the actual balance, because spends cannot"
3453 "\nbe detected with incoming viewing keys.\n"
a0a3334c
S
3454 "\nArguments:\n"
3455 "1. minconf (numeric, optional, default=1) Only include private and transparent transactions confirmed at least this many times.\n"
44e37656 3456 "2. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress' and 'z_importviewingkey')\n"
a0a3334c
S
3457 "\nResult:\n"
3458 "{\n"
3459 " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
053cb349 3460 " \"private\": xxxxx, (numeric) the total balance of private funds (in both Sprout and Sapling addresses)\n"
a0a3334c
S
3461 " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
3462 "}\n"
3463 "\nExamples:\n"
3464 "\nThe total amount in the wallet\n"
3465 + HelpExampleCli("z_gettotalbalance", "") +
3466 "\nThe total amount in the wallet at least 5 blocks confirmed\n"
3467 + HelpExampleCli("z_gettotalbalance", "5") +
3468 "\nAs a json rpc call\n"
3469 + HelpExampleRpc("z_gettotalbalance", "5")
3470 );
3471
3472 LOCK2(cs_main, pwalletMain->cs_wallet);
3473
3474 int nMinDepth = 1;
44e37656 3475 if (params.size() > 0) {
a0a3334c
S
3476 nMinDepth = params[0].get_int();
3477 }
12448b64
S
3478 if (nMinDepth < 0) {
3479 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3480 }
a0a3334c 3481
44e37656
JG
3482 bool fIncludeWatchonly = false;
3483 if (params.size() > 1) {
3484 fIncludeWatchonly = params[1].get_bool();
3485 }
3486
a0a3334c 3487 // getbalance and "getbalance * 1 true" should return the same number
70454796 3488 // but they don't because wtx.GetAmounts() does not handle tx where there are no outputs
a0a3334c
S
3489 // pwalletMain->GetBalance() does not accept min depth parameter
3490 // so we use our own method to get balance of utxos.
44e37656
JG
3491 CAmount nBalance = getBalanceTaddr("", nMinDepth, !fIncludeWatchonly);
3492 CAmount nPrivateBalance = getBalanceZaddr("", nMinDepth, !fIncludeWatchonly);
a0a3334c 3493 CAmount nTotalBalance = nBalance + nPrivateBalance;
0d37ae3a 3494 UniValue result(UniValue::VOBJ);
f54db399
JG
3495 result.push_back(Pair("transparent", FormatMoney(nBalance)));
3496 result.push_back(Pair("private", FormatMoney(nPrivateBalance)));
3497 result.push_back(Pair("total", FormatMoney(nTotalBalance)));
a0a3334c
S
3498 return result;
3499}
3500
0d37ae3a 3501UniValue z_getoperationresult(const UniValue& params, bool fHelp)
c1eae280
S
3502{
3503 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3504 return NullUniValue;
c1eae280
S
3505
3506 if (fHelp || params.size() > 1)
3507 throw runtime_error(
3508 "z_getoperationresult ([\"operationid\", ... ]) \n"
3509 "\nRetrieve the result and status of an operation which has finished, and then remove the operation from memory."
3510 + HelpRequiringPassphrase() + "\n"
3511 "\nArguments:\n"
3512 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
3513 "\nResult:\n"
3514 "\" [object, ...]\" (array) A list of JSON objects\n"
337a99a2
JG
3515 "\nExamples:\n"
3516 + HelpExampleCli("z_getoperationresult", "'[\"operationid\", ... ]'")
3517 + HelpExampleRpc("z_getoperationresult", "'[\"operationid\", ... ]'")
c1eae280 3518 );
70454796 3519
c1eae280
S
3520 // This call will remove finished operations
3521 return z_getoperationstatus_IMPL(params, true);
3522}
fc72c078 3523
0d37ae3a 3524UniValue z_getoperationstatus(const UniValue& params, bool fHelp)
fc72c078
S
3525{
3526 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3527 return NullUniValue;
fc72c078 3528
34f0001c 3529 if (fHelp || params.size() > 1)
fc72c078 3530 throw runtime_error(
34f0001c 3531 "z_getoperationstatus ([\"operationid\", ... ]) \n"
c1eae280 3532 "\nGet operation status and any associated result or error data. The operation will remain in memory."
fc72c078
S
3533 + HelpRequiringPassphrase() + "\n"
3534 "\nArguments:\n"
c1eae280 3535 "1. \"operationid\" (array, optional) A list of operation ids we are interested in. If not provided, examine all operations known to the node.\n"
fc72c078 3536 "\nResult:\n"
34f0001c 3537 "\" [object, ...]\" (array) A list of JSON objects\n"
337a99a2
JG
3538 "\nExamples:\n"
3539 + HelpExampleCli("z_getoperationstatus", "'[\"operationid\", ... ]'")
3540 + HelpExampleRpc("z_getoperationstatus", "'[\"operationid\", ... ]'")
fc72c078 3541 );
70454796 3542
c1eae280
S
3543 // This call is idempotent so we don't want to remove finished operations
3544 return z_getoperationstatus_IMPL(params, false);
3545}
fc72c078 3546
0d37ae3a 3547UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedOperations=false)
c1eae280 3548{
fc72c078
S
3549 LOCK2(cs_main, pwalletMain->cs_wallet);
3550
34f0001c
S
3551 std::set<AsyncRPCOperationId> filter;
3552 if (params.size()==1) {
0d37ae3a 3553 UniValue ids = params[0].get_array();
c24109ec 3554 for (const UniValue & v : ids.getValues()) {
34f0001c
S
3555 filter.insert(v.get_str());
3556 }
fc72c078 3557 }
34f0001c 3558 bool useFilter = (filter.size()>0);
fc72c078 3559
0d37ae3a 3560 UniValue ret(UniValue::VARR);
34f0001c
S
3561 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
3562 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
3563
3564 for (auto id : ids) {
3565 if (useFilter && !filter.count(id))
3566 continue;
70454796 3567
34f0001c
S
3568 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
3569 if (!operation) {
3570 continue;
3571 // It's possible that the operation was removed from the internal queue and map during this loop
3572 // throw JSONRPCError(RPC_INVALID_PARAMETER, "No operation exists for that id.");
3573 }
fc72c078 3574
2f21206c
S
3575 UniValue obj = operation->getStatus();
3576 std::string s = obj["status"].get_str();
c1eae280
S
3577 if (fRemoveFinishedOperations) {
3578 // Caller is only interested in retrieving finished results
2f21206c
S
3579 if ("success"==s || "failed"==s || "cancelled"==s) {
3580 ret.push_back(obj);
c1eae280
S
3581 q->popOperationForId(id);
3582 }
3583 } else {
2f21206c 3584 ret.push_back(obj);
34f0001c 3585 }
fc72c078
S
3586 }
3587
0d37ae3a
JG
3588 std::vector<UniValue> arrTmp = ret.getValues();
3589
2d2f3d18 3590 // sort results chronologically by creation_time
0d37ae3a 3591 std::sort(arrTmp.begin(), arrTmp.end(), [](UniValue a, UniValue b) -> bool {
2d2f3d18
S
3592 const int64_t t1 = find_value(a.get_obj(), "creation_time").get_int64();
3593 const int64_t t2 = find_value(b.get_obj(), "creation_time").get_int64();
3594 return t1 < t2;
3595 });
3596
0d37ae3a
JG
3597 ret.clear();
3598 ret.setArray();
3599 ret.push_backV(arrTmp);
3600
34f0001c 3601 return ret;
fc72c078
S
3602}
3603
3920292b 3604
892ae945
JG
3605// JSDescription size depends on the transaction version
3606#define V3_JS_DESCRIPTION_SIZE (GetSerializeSize(JSDescription(), SER_NETWORK, (OVERWINTER_TX_VERSION | (1 << 31))))
3920292b
S
3607// Here we define the maximum number of zaddr outputs that can be included in a transaction.
3608// If input notes are small, we might actually require more than one joinsplit per zaddr output.
3609// For now though, we assume we use one joinsplit per zaddr output (and the second output note is change).
3610// We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data.
892ae945 3611#define Z_SENDMANY_MAX_ZADDR_OUTPUTS_BEFORE_SAPLING ((MAX_TX_SIZE_BEFORE_SAPLING / V3_JS_DESCRIPTION_SIZE) - 1)
3920292b
S
3612
3613// transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes
3614#define CTXIN_SPEND_DUST_SIZE 148
3615#define CTXOUT_REGULAR_SIZE 34
3616
0d37ae3a 3617UniValue z_sendmany(const UniValue& params, bool fHelp)
fc72c078
S
3618{
3619 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 3620 return NullUniValue;
fc72c078 3621
af53da02 3622 if (fHelp || params.size() < 2 || params.size() > 4)
fc72c078 3623 throw runtime_error(
af53da02 3624 "z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
fc72c078 3625 "\nSend multiple times. Amounts are double-precision floating point numbers."
da85cdfe 3626 "\nChange generated from a taddr flows to a new taddr address, while change generated from a zaddr returns to itself."
48f9c65b 3627 "\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
892ae945 3628 + strprintf("\nBefore Sapling activates, the maximum number of zaddr outputs is %d due to transaction size limits.\n", Z_SENDMANY_MAX_ZADDR_OUTPUTS_BEFORE_SAPLING)
fc72c078
S
3629 + HelpRequiringPassphrase() + "\n"
3630 "\nArguments:\n"
3631 "1. \"fromaddress\" (string, required) The taddr or zaddr to send the funds from.\n"
3632 "2. \"amounts\" (array, required) An array of json objects representing the amounts to send.\n"
3633 " [{\n"
3634 " \"address\":address (string, required) The address is a taddr or zaddr\n"
6dec2d03 3635 " \"amount\":amount (numeric, required) The numeric amount in " + CURRENCY_UNIT + " is the value\n"
fc72c078
S
3636 " \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
3637 " }, ... ]\n"
3638 "3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
af53da02
S
3639 "4. fee (numeric, optional, default="
3640 + strprintf("%s", FormatMoney(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
fc72c078
S
3641 "\nResult:\n"
3642 "\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
337a99a2
JG
3643 "\nExamples:\n"
3644 + HelpExampleCli("z_sendmany", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" '[{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]'")
3645 + HelpExampleRpc("z_sendmany", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", [{\"address\": \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\" ,\"amount\": 5.0}]")
fc72c078
S
3646 );
3647
3648 LOCK2(cs_main, pwalletMain->cs_wallet);
3649
fc72c078
S
3650 // Check that the from address is valid.
3651 auto fromaddress = params[0].get_str();
3652 bool fromTaddr = false;
af4057b9 3653 bool fromSapling = false;
b6be3e88
JG
3654 CTxDestination taddr = DecodeDestination(fromaddress);
3655 fromTaddr = IsValidDestination(taddr);
fc72c078 3656 if (!fromTaddr) {
80ed13d5 3657 auto res = DecodePaymentAddress(fromaddress);
e5eab182 3658 if (!IsValidPaymentAddress(res)) {
fc72c078
S
3659 // invalid
3660 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or zaddr.");
3661 }
fc72c078 3662
af4057b9
JG
3663 // Check that we have the spending key
3664 if (!boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), res)) {
fc72c078
S
3665 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
3666 }
af4057b9
JG
3667
3668 // Remember whether this is a Sprout or Sapling address
af4057b9 3669 fromSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
fc72c078 3670 }
07d85a64
JG
3671 // This logic will need to be updated if we add a new shielded pool
3672 bool fromSprout = !(fromTaddr || fromSapling);
fc72c078 3673
0d37ae3a 3674 UniValue outputs = params[1].get_array();
fc72c078
S
3675
3676 if (outputs.size()==0)
3677 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amounts array is empty.");
3678
3679 // Keep track of addresses to spot duplicates
3680 set<std::string> setAddress;
3681
af4057b9 3682 // Track whether we see any Sprout addresses
07d85a64 3683 bool noSproutAddrs = !fromSprout;
af4057b9 3684
fc72c078 3685 // Recipients
dafb8161
S
3686 std::vector<SendManyRecipient> taddrRecipients;
3687 std::vector<SendManyRecipient> zaddrRecipients;
af53da02 3688 CAmount nTotalOut = 0;
fc72c078 3689
0d37ae3a
JG
3690 for (const UniValue& o : outputs.getValues()) {
3691 if (!o.isObject())
fc72c078 3692 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
fc72c078 3693
fc72c078 3694 // sanity check, report error if unknown key-value pairs
0d37ae3a
JG
3695 for (const string& name_ : o.getKeys()) {
3696 std::string s = name_;
fc72c078
S
3697 if (s != "address" && s != "amount" && s!="memo")
3698 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown key: ")+s);
3699 }
3700
3701 string address = find_value(o, "address").get_str();
3702 bool isZaddr = false;
b6be3e88
JG
3703 CTxDestination taddr = DecodeDestination(address);
3704 if (!IsValidDestination(taddr)) {
af4057b9
JG
3705 auto res = DecodePaymentAddress(address);
3706 if (IsValidPaymentAddress(res)) {
fc72c078 3707 isZaddr = true;
af4057b9
JG
3708
3709 bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
07d85a64 3710 bool toSprout = !toSapling;
af4057b9
JG
3711 noSproutAddrs = noSproutAddrs && toSapling;
3712
3713 // If we are sending from a shielded address, all recipient
3714 // shielded addresses must be of the same type.
7c02acc5
JG
3715 if (fromSprout && toSapling) {
3716 throw JSONRPCError(
3717 RPC_INVALID_PARAMETER,
3718 "Cannot send from a Sprout address to a Sapling address using z_sendmany");
3719 }
3720 if (fromSapling && toSprout) {
3721 throw JSONRPCError(
3722 RPC_INVALID_PARAMETER,
3723 "Cannot send from a Sapling address to a Sprout address using z_sendmany");
af4057b9 3724 }
80ed13d5 3725 } else {
fc72c078
S
3726 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
3727 }
3728 }
3729
3730 if (setAddress.count(address))
3731 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+address);
3732 setAddress.insert(address);
3733
0d37ae3a 3734 UniValue memoValue = find_value(o, "memo");
fc72c078 3735 string memo;
0d37ae3a 3736 if (!memoValue.isNull()) {
fc72c078
S
3737 memo = memoValue.get_str();
3738 if (!isZaddr) {
c938fb1f 3739 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo cannot be used with a taddr. It can only be used with a zaddr.");
fc72c078
S
3740 } else if (!IsHex(memo)) {
3741 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
3742 }
6114cfe7 3743 if (memo.length() > ZC_MEMO_SIZE*2) {
dafb8161
S
3744 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
3745 }
fc72c078
S
3746 }
3747
0d37ae3a 3748 UniValue av = find_value(o, "amount");
fc72c078
S
3749 CAmount nAmount = AmountFromValue( av );
3750 if (nAmount < 0)
3751 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
3752
dafb8161
S
3753 if (isZaddr) {
3754 zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3755 } else {
3756 taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
3757 }
af53da02
S
3758
3759 nTotalOut += nAmount;
fc72c078
S
3760 }
3761
15ec5525 3762 int nextBlockHeight = chainActive.Height() + 1;
892ae945
JG
3763 CMutableTransaction mtx;
3764 mtx.fOverwintered = true;
3765 mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
3766 mtx.nVersion = SAPLING_TX_VERSION;
25fee350 3767 unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
15ec5525 3768 if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
892ae945
JG
3769 if (NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER)) {
3770 mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
3771 mtx.nVersion = OVERWINTER_TX_VERSION;
3772 } else {
3773 mtx.fOverwintered = false;
3774 mtx.nVersion = 2;
3775 }
3776
15ec5525 3777 max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
15ec5525 3778
892ae945
JG
3779 // Check the number of zaddr outputs does not exceed the limit.
3780 if (zaddrRecipients.size() > Z_SENDMANY_MAX_ZADDR_OUTPUTS_BEFORE_SAPLING) {
3781 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, too many zaddr outputs");
3782 }
3920292b
S
3783 }
3784
3785 // As a sanity check, estimate and verify that the size of the transaction will be valid.
3786 // Depending on the input notes, the actual tx size may turn out to be larger and perhaps invalid.
3787 size_t txsize = 0;
3920292b 3788 for (int i = 0; i < zaddrRecipients.size(); i++) {
4dcc48b8
S
3789 auto address = std::get<0>(zaddrRecipients[i]);
3790 auto res = DecodePaymentAddress(address);
3791 bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
3792 if (toSapling) {
3793 mtx.vShieldedOutput.push_back(OutputDescription());
3794 } else {
3795 JSDescription jsdesc;
3796 if (mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION)) {
3797 jsdesc.proof = GrothProof();
3798 }
3799 mtx.vjoinsplit.push_back(jsdesc);
b7a6c321 3800 }
3920292b
S
3801 }
3802 CTransaction tx(mtx);
a8e5ae92 3803 txsize += GetSerializeSize(tx, SER_NETWORK, tx.nVersion);
3920292b
S
3804 if (fromTaddr) {
3805 txsize += CTXIN_SPEND_DUST_SIZE;
3806 txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change
3807 }
3808 txsize += CTXOUT_REGULAR_SIZE * taddrRecipients.size();
15ec5525
JG
3809 if (txsize > max_tx_size) {
3810 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Too many outputs, size of raw transaction would be larger than limit of %d bytes", max_tx_size ));
3920292b
S
3811 }
3812
fc72c078
S
3813 // Minimum confirmations
3814 int nMinDepth = 1;
12448b64 3815 if (params.size() > 2) {
fc72c078 3816 nMinDepth = params[2].get_int();
12448b64
S
3817 }
3818 if (nMinDepth < 0) {
3819 throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
3820 }
fc72c078 3821
af53da02 3822 // Fee in Zatoshis, not currency format)
e5aa9f61
DL
3823 CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
3824 CAmount nDefaultFee = nFee;
3825
af53da02 3826 if (params.size() > 3) {
7eccce4e
S
3827 if (params[3].get_real() == 0.0) {
3828 nFee = 0;
3829 } else {
3830 nFee = AmountFromValue( params[3] );
3831 }
3832
0b6eeac3 3833 // Check that the user specified fee is not absurd.
e5aa9f61
DL
3834 // This allows amount=0 (and all amount < nDefaultFee) transactions to use the default network fee
3835 // or anything less than nDefaultFee instead of being forced to use a custom fee and leak metadata
3836 if (nTotalOut < nDefaultFee) {
3837 if (nFee > nDefaultFee) {
3838 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Small transaction amount %s has fee %s that is greater than the default fee %s", FormatMoney(nTotalOut), FormatMoney(nFee), FormatMoney(nDefaultFee)));
3839 }
3840 } else {
0b6eeac3 3841 // Check that the user specified fee is not absurd.
e5aa9f61 3842 if (nFee > nTotalOut) {
4b8c52c6 3843 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s and also greater than the default fee", FormatMoney(nFee), FormatMoney(nTotalOut)));
e5aa9f61
DL
3844 }
3845 }
af53da02
S
3846 }
3847
8aa7937d 3848 // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
0d37ae3a 3849 UniValue o(UniValue::VOBJ);
8aa7937d
S
3850 o.push_back(Pair("fromaddress", params[0]));
3851 o.push_back(Pair("amounts", params[1]));
3852 o.push_back(Pair("minconf", nMinDepth));
3853 o.push_back(Pair("fee", std::stod(FormatMoney(nFee))));
0d37ae3a 3854 UniValue contextInfo = o;
8aa7937d 3855
36e2141d
JG
3856 // Builder (used if Sapling addresses are involved)
3857 boost::optional<TransactionBuilder> builder;
af4057b9 3858 if (noSproutAddrs) {
36e2141d
JG
3859 builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
3860 }
3861
072099d7 3862 // Contextual transaction we will build on
36e2141d 3863 // (used if no Sapling addresses are involved)
9bb37bf0 3864 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nextBlockHeight);
e6cd2a83
S
3865 bool isShielded = !fromTaddr || zaddrRecipients.size() > 0;
3866 if (contextualTx.nVersion == 1 && isShielded) {
072099d7
S
3867 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
3868 }
3869
dafb8161 3870 // Create operation and add to global queue
fc72c078 3871 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
36e2141d 3872 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(builder, contextualTx, fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee, contextInfo) );
fc72c078
S
3873 q->addOperation(operation);
3874 AsyncRPCOperationId operationId = operation->getId();
3875 return operationId;
fc72c078 3876}
34f0001c
S
3877
3878
06c19063
S
3879/**
3880When estimating the number of coinbase utxos we can shield in a single transaction:
38811. Joinsplit description is 1802 bytes.
38822. Transaction overhead ~ 100 bytes
38833. Spending a typical P2PKH is >=148 bytes, as defined in CTXIN_SPEND_DUST_SIZE.
38844. Spending a multi-sig P2SH address can vary greatly:
3885 https://github.com/bitcoin/bitcoin/blob/c3ad56f4e0b587d8d763af03d743fdfc2d180c9b/src/main.cpp#L517
3886 In real-world coinbase utxos, we consider a 3-of-3 multisig, where the size is roughly:
3887 (3*(33+1))+3 = 105 byte redeem script
3888 105 + 1 + 3*(73+1) = 328 bytes of scriptSig, rounded up to 400 based on testnet experiments.
3889*/
3890#define CTXIN_SPEND_P2SH_SIZE 400
3891
c5dabd2b
S
3892#define SHIELD_COINBASE_DEFAULT_LIMIT 50
3893
06c19063
S
3894UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
3895{
3896 if (!EnsureWalletIsAvailable(fHelp))
3897 return NullUniValue;
3898
c5dabd2b 3899 if (fHelp || params.size() < 2 || params.size() > 4)
06c19063 3900 throw runtime_error(
c5dabd2b 3901 "z_shieldcoinbase \"fromaddress\" \"tozaddress\" ( fee ) ( limit )\n"
06c19063
S
3902 "\nShield transparent coinbase funds by sending to a shielded zaddr. This is an asynchronous operation and utxos"
3903 "\nselected for shielding will be locked. If there is an error, they are unlocked. The RPC call `listlockunspent`"
c5dabd2b 3904 "\ncan be used to return a list of locked utxos. The number of coinbase utxos selected for shielding can be limited"
31afbcc5
JG
3905 "\nby the caller. If the limit parameter is set to zero, and Overwinter is not yet active, the -mempooltxinputlimit"
3906 "\noption will determine the number of uxtos. Any limit is constrained by the consensus rule defining a maximum"
3907 "\ntransaction size of "
25fee350 3908 + strprintf("%d bytes before Sapling, and %d bytes once Sapling activates.", MAX_TX_SIZE_BEFORE_SAPLING, MAX_TX_SIZE_AFTER_SAPLING)
06c19063
S
3909 + HelpRequiringPassphrase() + "\n"
3910 "\nArguments:\n"
3911 "1. \"fromaddress\" (string, required) The address is a taddr or \"*\" for all taddrs belonging to the wallet.\n"
3912 "2. \"toaddress\" (string, required) The address is a zaddr.\n"
3913 "3. fee (numeric, optional, default="
3914 + strprintf("%s", FormatMoney(SHIELD_COINBASE_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
c5dabd2b 3915 "4. limit (numeric, optional, default="
31afbcc5 3916 + strprintf("%d", SHIELD_COINBASE_DEFAULT_LIMIT) + ") Limit on the maximum number of utxos to shield. Set to 0 to use node option -mempooltxinputlimit (before Overwinter), or as many as will fit in the transaction (after Overwinter).\n"
06c19063
S
3917 "\nResult:\n"
3918 "{\n"
06c19063
S
3919 " \"remainingUTXOs\": xxx (numeric) Number of coinbase utxos still available for shielding.\n"
3920 " \"remainingValue\": xxx (numeric) Value of coinbase utxos still available for shielding.\n"
9eb8089e
JG
3921 " \"shieldingUTXOs\": xxx (numeric) Number of coinbase utxos being shielded.\n"
3922 " \"shieldingValue\": xxx (numeric) Value of coinbase utxos being shielded.\n"
3923 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
06c19063 3924 "}\n"
337a99a2
JG
3925 "\nExamples:\n"
3926 + HelpExampleCli("z_shieldcoinbase", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
3927 + HelpExampleRpc("z_shieldcoinbase", "\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
06c19063
S
3928 );
3929
3930 LOCK2(cs_main, pwalletMain->cs_wallet);
3931
3932 // Validate the from address
3933 auto fromaddress = params[0].get_str();
3934 bool isFromWildcard = fromaddress == "*";
b6be3e88 3935 CTxDestination taddr;
06c19063 3936 if (!isFromWildcard) {
b6be3e88
JG
3937 taddr = DecodeDestination(fromaddress);
3938 if (!IsValidDestination(taddr)) {
06c19063
S
3939 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
3940 }
3941 }
3942
3943 // Validate the destination address
3944 auto destaddress = params[1].get_str();
e5eab182 3945 if (!IsValidPaymentAddressString(destaddress)) {
06c19063
S
3946 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
3947 }
3948
3949 // Convert fee from currency format to zatoshis
3950 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
3951 if (params.size() > 2) {
3952 if (params[2].get_real() == 0.0) {
3953 nFee = 0;
3954 } else {
3955 nFee = AmountFromValue( params[2] );
3956 }
3957 }
3958
c5dabd2b
S
3959 int nLimit = SHIELD_COINBASE_DEFAULT_LIMIT;
3960 if (params.size() > 3) {
3961 nLimit = params[3].get_int();
3962 if (nLimit < 0) {
3963 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of utxos cannot be negative");
3964 }
3965 }
3966
31afbcc5
JG
3967 int nextBlockHeight = chainActive.Height() + 1;
3968 bool overwinterActive = NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER);
25fee350 3969 unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
15ec5525
JG
3970 if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
3971 max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
3972 }
31afbcc5 3973
06c19063
S
3974 // Prepare to get coinbase utxos
3975 std::vector<ShieldCoinbaseUTXO> inputs;
3976 CAmount shieldedValue = 0;
3977 CAmount remainingValue = 0;
3978 size_t estimatedTxSize = 2000; // 1802 joinsplit description + tx overhead + wiggle room
3979 size_t utxoCounter = 0;
3980 bool maxedOutFlag = false;
31afbcc5 3981 size_t mempoolLimit = (nLimit != 0) ? nLimit : (overwinterActive ? 0 : (size_t)GetArg("-mempooltxinputlimit", 0));
06c19063
S
3982
3983 // Set of addresses to filter utxos by
b6be3e88 3984 std::set<CTxDestination> destinations = {};
06c19063 3985 if (!isFromWildcard) {
b6be3e88 3986 destinations.insert(taddr);
06c19063
S
3987 }
3988
3989 // Get available utxos
3990 vector<COutput> vecOutputs;
3991 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, true);
3992
3993 // Find unspent coinbase utxos and update estimated size
3994 BOOST_FOREACH(const COutput& out, vecOutputs) {
3995 if (!out.fSpendable) {
3996 continue;
3997 }
3998
3999 CTxDestination address;
4000 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
4001 continue;
4002 }
4003 // If taddr is not wildcard "*", filter utxos
b6be3e88 4004 if (destinations.size() > 0 && !destinations.count(address)) {
06c19063
S
4005 continue;
4006 }
4007
4008 if (!out.tx->IsCoinBase()) {
4009 continue;
4010 }
4011
4012 utxoCounter++;
5f91a956 4013 auto scriptPubKey = out.tx->vout[out.i].scriptPubKey;
06c19063
S
4014 CAmount nValue = out.tx->vout[out.i].nValue;
4015
4016 if (!maxedOutFlag) {
b6be3e88 4017 size_t increase = (boost::get<CScriptID>(&address) != nullptr) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
15ec5525 4018 if (estimatedTxSize + increase >= max_tx_size ||
06c19063
S
4019 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
4020 {
4021 maxedOutFlag = true;
4022 } else {
4023 estimatedTxSize += increase;
5f91a956 4024 ShieldCoinbaseUTXO utxo = {out.tx->GetHash(), out.i, scriptPubKey, nValue};
06c19063
S
4025 inputs.push_back(utxo);
4026 shieldedValue += nValue;
4027 }
4028 }
4029
4030 if (maxedOutFlag) {
4031 remainingValue += nValue;
4032 }
4033 }
4034
4035 size_t numUtxos = inputs.size();
4036
4037 if (numUtxos == 0) {
4038 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any coinbase funds to shield.");
4039 }
4040
4041 if (shieldedValue < nFee) {
4042 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
4043 strprintf("Insufficient coinbase funds, have %s, which is less than miners fee %s",
4044 FormatMoney(shieldedValue), FormatMoney(nFee)));
4045 }
4046
4047 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
4048 CAmount netAmount = shieldedValue - nFee;
4049 if (nFee > netAmount) {
4050 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
4051 }
4052
4053 // Keep record of parameters in context object
4054 UniValue contextInfo(UniValue::VOBJ);
4055 contextInfo.push_back(Pair("fromaddress", params[0]));
4056 contextInfo.push_back(Pair("toaddress", params[1]));
4057 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
4058
5f91a956
JG
4059 // Builder (used if Sapling addresses are involved)
4060 TransactionBuilder builder = TransactionBuilder(
4061 Params().GetConsensus(), nextBlockHeight, pwalletMain);
4062
072099d7 4063 // Contextual transaction we will build on
5f91a956 4064 // (used if no Sapling addresses are involved)
072099d7 4065 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
9bb37bf0 4066 Params().GetConsensus(), nextBlockHeight);
072099d7
S
4067 if (contextualTx.nVersion == 1) {
4068 contextualTx.nVersion = 2; // Tx format should support vjoinsplits
4069 }
4070
06c19063
S
4071 // Create operation and add to global queue
4072 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
5f91a956 4073 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(builder, contextualTx, inputs, destaddress, nFee, contextInfo) );
06c19063
S
4074 q->addOperation(operation);
4075 AsyncRPCOperationId operationId = operation->getId();
4076
4077 // Return continuation information
4078 UniValue o(UniValue::VOBJ);
4ff92bb6 4079 o.push_back(Pair("remainingUTXOs", static_cast<uint64_t>(utxoCounter - numUtxos)));
06c19063 4080 o.push_back(Pair("remainingValue", ValueFromAmount(remainingValue)));
4ff92bb6 4081 o.push_back(Pair("shieldingUTXOs", static_cast<uint64_t>(numUtxos)));
06c19063
S
4082 o.push_back(Pair("shieldingValue", ValueFromAmount(shieldedValue)));
4083 o.push_back(Pair("opid", operationId));
4084 return o;
4085}
4086
4087
6e9c7629
JG
4088#define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50
4089#define MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT 10
4090
a8e5ae92 4091#define JOINSPLIT_SIZE GetSerializeSize(JSDescription(), SER_NETWORK, PROTOCOL_VERSION)
6e9c7629
JG
4092
4093UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
4094{
4095 if (!EnsureWalletIsAvailable(fHelp))
4096 return NullUniValue;
4097
66dfcc13
LR
4098 string enableArg = "zmergetoaddress";
4099 auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-" + enableArg, false);
553a5c1a
JG
4100 std::string strDisabledMsg = "";
4101 if (!fEnableMergeToAddress) {
66dfcc13 4102 strDisabledMsg = experimentalDisabledHelpMsg("z_mergetoaddress", enableArg);
553a5c1a
JG
4103 }
4104
6e9c7629
JG
4105 if (fHelp || params.size() < 2 || params.size() > 6)
4106 throw runtime_error(
4107 "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n"
553a5c1a 4108 + strDisabledMsg +
6e9c7629
JG
4109 "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`"
4110 "\nto combine those into a single note."
4111 "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they"
4112 "\nare unlocked. The RPC call `listlockunspent` can be used to return a list of locked UTXOs."
4113 "\n\nThe number of UTXOs and notes selected for merging can be limited by the caller. If the transparent limit"
31afbcc5 4114 "\nparameter is set to zero, and Overwinter is not yet active, the -mempooltxinputlimit option will determine the"
66dfcc13
LR
4115 "\nnumber of UTXOs. Any limit is constrained by the consensus rule defining a maximum transaction size of"
4116 + strprintf("\n%d bytes before Sapling, and %d bytes once Sapling activates.", MAX_TX_SIZE_BEFORE_SAPLING, MAX_TX_SIZE_AFTER_SAPLING)
6e9c7629
JG
4117 + HelpRequiringPassphrase() + "\n"
4118 "\nArguments:\n"
4119 "1. fromaddresses (string, required) A JSON array with addresses.\n"
4120 " The following special strings are accepted inside the array:\n"
4121 " - \"*\": Merge both UTXOs and notes from all addresses belonging to the wallet.\n"
4122 " - \"ANY_TADDR\": Merge UTXOs from all t-addrs belonging to the wallet.\n"
4123 " - \"ANY_ZADDR\": Merge notes from all z-addrs belonging to the wallet.\n"
4124 " If a special string is given, any given addresses of that type will be ignored.\n"
4125 " [\n"
4126 " \"address\" (string) Can be a t-addr or a z-addr\n"
4127 " ,...\n"
4128 " ]\n"
4129 "2. \"toaddress\" (string, required) The t-addr or z-addr to send the funds to.\n"
4130 "3. fee (numeric, optional, default="
4131 + strprintf("%s", FormatMoney(MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
4132 "4. transparent_limit (numeric, optional, default="
31afbcc5 4133 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit (before Overwinter), or as many as will fit in the transaction (after Overwinter).\n"
6e9c7629
JG
4134 "4. shielded_limit (numeric, optional, default="
4135 + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n"
4136 "5. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n"
4137 "\nResult:\n"
4138 "{\n"
4139 " \"remainingUTXOs\": xxx (numeric) Number of UTXOs still available for merging.\n"
4140 " \"remainingTransparentValue\": xxx (numeric) Value of UTXOs still available for merging.\n"
4141 " \"remainingNotes\": xxx (numeric) Number of notes still available for merging.\n"
4142 " \"remainingShieldedValue\": xxx (numeric) Value of notes still available for merging.\n"
4143 " \"mergingUTXOs\": xxx (numeric) Number of UTXOs being merged.\n"
4144 " \"mergingTransparentValue\": xxx (numeric) Value of UTXOs being merged.\n"
4145 " \"mergingNotes\": xxx (numeric) Number of notes being merged.\n"
4146 " \"mergingShieldedValue\": xxx (numeric) Value of notes being merged.\n"
4147 " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
4148 "}\n"
4149 "\nExamples:\n"
4150 + HelpExampleCli("z_mergetoaddress", "'[\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf")
4151 + HelpExampleRpc("z_mergetoaddress", "[\"t1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"")
4152 );
4153
553a5c1a
JG
4154 if (!fEnableMergeToAddress) {
4155 throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled.");
4156 }
4157
6e9c7629
JG
4158 LOCK2(cs_main, pwalletMain->cs_wallet);
4159
4160 bool useAny = false;
4161 bool useAnyUTXO = false;
4162 bool useAnyNote = false;
b6be3e88 4163 std::set<CTxDestination> taddrs = {};
6e9c7629
JG
4164 std::set<libzcash::PaymentAddress> zaddrs = {};
4165
4166 UniValue addresses = params[0].get_array();
4167 if (addresses.size()==0)
4168 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, fromaddresses array is empty.");
4169
4170 // Keep track of addresses to spot duplicates
4171 std::set<std::string> setAddress;
4172
4173 // Sources
4174 for (const UniValue& o : addresses.getValues()) {
4175 if (!o.isStr())
4176 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected string");
4177
4178 std::string address = o.get_str();
4179 if (address == "*") {
4180 useAny = true;
4181 } else if (address == "ANY_TADDR") {
4182 useAnyUTXO = true;
4183 } else if (address == "ANY_ZADDR") {
4184 useAnyNote = true;
4185 } else {
b6be3e88
JG
4186 CTxDestination taddr = DecodeDestination(address);
4187 if (IsValidDestination(taddr)) {
6e9c7629
JG
4188 // Ignore any listed t-addrs if we are using all of them
4189 if (!(useAny || useAnyUTXO)) {
4190 taddrs.insert(taddr);
4191 }
4192 } else {
80ed13d5 4193 auto zaddr = DecodePaymentAddress(address);
e5eab182 4194 if (IsValidPaymentAddress(zaddr)) {
6e9c7629
JG
4195 // Ignore listed z-addrs if we are using all of them
4196 if (!(useAny || useAnyNote)) {
e5eab182 4197 zaddrs.insert(zaddr);
6e9c7629 4198 }
80ed13d5 4199 } else {
6e9c7629
JG
4200 throw JSONRPCError(
4201 RPC_INVALID_PARAMETER,
4202 string("Invalid parameter, unknown address format: ") + address);
4203 }
4204 }
4205 }
4206
4207 if (setAddress.count(address))
4208 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ") + address);
4209 setAddress.insert(address);
4210 }
4211
4212 // Validate the destination address
4213 auto destaddress = params[1].get_str();
4214 bool isToZaddr = false;
b6be3e88
JG
4215 CTxDestination taddr = DecodeDestination(destaddress);
4216 if (!IsValidDestination(taddr)) {
e5eab182 4217 if (IsValidPaymentAddressString(destaddress)) {
6e9c7629 4218 isToZaddr = true;
80ed13d5 4219 } else {
6e9c7629
JG
4220 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
4221 }
4222 }
4223
4224 // Convert fee from currency format to zatoshis
4225 CAmount nFee = SHIELD_COINBASE_DEFAULT_MINERS_FEE;
4226 if (params.size() > 2) {
4227 if (params[2].get_real() == 0.0) {
4228 nFee = 0;
4229 } else {
4230 nFee = AmountFromValue( params[2] );
4231 }
4232 }
4233
4234 int nUTXOLimit = MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT;
4235 if (params.size() > 3) {
4236 nUTXOLimit = params[3].get_int();
4237 if (nUTXOLimit < 0) {
4238 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of UTXOs cannot be negative");
4239 }
4240 }
4241
4242 int nNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT;
4243 if (params.size() > 4) {
4244 nNoteLimit = params[4].get_int();
4245 if (nNoteLimit < 0) {
4246 throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative");
4247 }
4248 }
4249
4250 std::string memo;
4251 if (params.size() > 5) {
4252 memo = params[5].get_str();
4253 if (!isToZaddr) {
4254 throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
4255 } else if (!IsHex(memo)) {
4256 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
4257 }
4258 if (memo.length() > ZC_MEMO_SIZE*2) {
4259 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
4260 }
4261 }
4262
4263 MergeToAddressRecipient recipient(destaddress, memo);
4264
31afbcc5
JG
4265 int nextBlockHeight = chainActive.Height() + 1;
4266 bool overwinterActive = NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER);
25fee350 4267 unsigned int max_tx_size = MAX_TX_SIZE_AFTER_SAPLING;
15ec5525
JG
4268 if (!NetworkUpgradeActive(nextBlockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
4269 max_tx_size = MAX_TX_SIZE_BEFORE_SAPLING;
4270 }
31afbcc5 4271
6e9c7629
JG
4272 // Prepare to get UTXOs and notes
4273 std::vector<MergeToAddressInputUTXO> utxoInputs;
4274 std::vector<MergeToAddressInputNote> noteInputs;
4275 CAmount mergedUTXOValue = 0;
4276 CAmount mergedNoteValue = 0;
4277 CAmount remainingUTXOValue = 0;
4278 CAmount remainingNoteValue = 0;
4279 size_t utxoCounter = 0;
4280 size_t noteCounter = 0;
4281 bool maxedOutUTXOsFlag = false;
4282 bool maxedOutNotesFlag = false;
31afbcc5 4283 size_t mempoolLimit = (nUTXOLimit != 0) ? nUTXOLimit : (overwinterActive ? 0 : (size_t)GetArg("-mempooltxinputlimit", 0));
6e9c7629
JG
4284
4285 size_t estimatedTxSize = 200; // tx overhead + wiggle room
4286 if (isToZaddr) {
4287 estimatedTxSize += JOINSPLIT_SIZE;
4288 }
4289
4290 if (useAny || useAnyUTXO || taddrs.size() > 0) {
4291 // Get available utxos
4292 vector<COutput> vecOutputs;
4293 pwalletMain->AvailableCoins(vecOutputs, true, NULL, false, false);
4294
4295 // Find unspent utxos and update estimated size
4296 for (const COutput& out : vecOutputs) {
4297 if (!out.fSpendable) {
4298 continue;
4299 }
4300
4301 CTxDestination address;
4302 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
4303 continue;
4304 }
4305 // If taddr is not wildcard "*", filter utxos
4306 if (taddrs.size() > 0 && !taddrs.count(address)) {
4307 continue;
4308 }
4309
4310 utxoCounter++;
4311 CAmount nValue = out.tx->vout[out.i].nValue;
4312
4313 if (!maxedOutUTXOsFlag) {
b6be3e88 4314 size_t increase = (boost::get<CScriptID>(&address) != nullptr) ? CTXIN_SPEND_P2SH_SIZE : CTXIN_SPEND_DUST_SIZE;
15ec5525 4315 if (estimatedTxSize + increase >= max_tx_size ||
6e9c7629
JG
4316 (mempoolLimit > 0 && utxoCounter > mempoolLimit))
4317 {
4318 maxedOutUTXOsFlag = true;
4319 } else {
4320 estimatedTxSize += increase;
4321 COutPoint utxo(out.tx->GetHash(), out.i);
4322 utxoInputs.emplace_back(utxo, nValue);
4323 mergedUTXOValue += nValue;
4324 }
4325 }
4326
4327 if (maxedOutUTXOsFlag) {
4328 remainingUTXOValue += nValue;
4329 }
4330 }
4331 }
4332
4333 if (useAny || useAnyNote || zaddrs.size() > 0) {
4334 // Get available notes
94e99acd
JG
4335 std::vector<CSproutNotePlaintextEntry> sproutEntries;
4336 std::vector<SaplingNoteEntry> saplingEntries;
4337 pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs);
6e9c7629
JG
4338
4339 // Find unspent notes and update estimated size
94e99acd 4340 for (CSproutNotePlaintextEntry& entry : sproutEntries) {
6e9c7629 4341 noteCounter++;
d266f403 4342 CAmount nValue = entry.plaintext.value();
6e9c7629
JG
4343
4344 if (!maxedOutNotesFlag) {
4345 // If we haven't added any notes yet and the merge is to a
4346 // z-address, we have already accounted for the first JoinSplit.
4347 size_t increase = (noteInputs.empty() && !isToZaddr) || (noteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0;
15ec5525 4348 if (estimatedTxSize + increase >= max_tx_size ||
6e9c7629
JG
4349 (nNoteLimit > 0 && noteCounter > nNoteLimit))
4350 {
4351 maxedOutNotesFlag = true;
4352 } else {
4353 estimatedTxSize += increase;
94e99acd 4354 auto zaddr = entry.address;
e5eab182 4355 SproutSpendingKey zkey;
25d5e80c 4356 pwalletMain->GetSproutSpendingKey(zaddr, zkey);
e5eab182 4357 noteInputs.emplace_back(entry.jsop, entry.plaintext.note(zaddr), nValue, zkey);
6e9c7629
JG
4358 mergedNoteValue += nValue;
4359 }
4360 }
4361
4362 if (maxedOutNotesFlag) {
4363 remainingNoteValue += nValue;
4364 }
4365 }
94e99acd 4366 // TODO: Add Sapling support
6e9c7629
JG
4367 }
4368
4369 size_t numUtxos = utxoInputs.size();
4370 size_t numNotes = noteInputs.size();
4371
4372 if (numUtxos == 0 && numNotes == 0) {
4373 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any funds to merge.");
4374 }
4375
4376 // Sanity check: Don't do anything if:
4377 // - We only have one from address
4378 // - It's equal to toaddress
4379 // - The address only contains a single UTXO or note
4380 if (setAddress.size() == 1 && setAddress.count(destaddress) && (numUtxos + numNotes) == 1) {
4381 throw JSONRPCError(RPC_INVALID_PARAMETER, "Destination address is also the only source address, and all its funds are already merged.");
4382 }
4383
4384 CAmount mergedValue = mergedUTXOValue + mergedNoteValue;
4385 if (mergedValue < nFee) {
4386 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
4387 strprintf("Insufficient funds, have %s, which is less than miners fee %s",
4388 FormatMoney(mergedValue), FormatMoney(nFee)));
4389 }
4390
4391 // Check that the user specified fee is sane (if too high, it can result in error -25 absurd fee)
4392 CAmount netAmount = mergedValue - nFee;
4393 if (nFee > netAmount) {
4394 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the net amount to be shielded %s", FormatMoney(nFee), FormatMoney(netAmount)));
4395 }
4396
4397 // Keep record of parameters in context object
4398 UniValue contextInfo(UniValue::VOBJ);
4399 contextInfo.push_back(Pair("fromaddresses", params[0]));
4400 contextInfo.push_back(Pair("toaddress", params[1]));
4401 contextInfo.push_back(Pair("fee", ValueFromAmount(nFee)));
4402
4403 // Contextual transaction we will build on
4404 CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
4405 Params().GetConsensus(),
7b92f27e 4406 nextBlockHeight);
6e9c7629
JG
4407 bool isShielded = numNotes > 0 || isToZaddr;
4408 if (contextualTx.nVersion == 1 && isShielded) {
4409 contextualTx.nVersion = 2; // Tx format should support vjoinsplit
4410 }
4411
4412 // Create operation and add to global queue
4413 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4414 std::shared_ptr<AsyncRPCOperation> operation(
4415 new AsyncRPCOperation_mergetoaddress(contextualTx, utxoInputs, noteInputs, recipient, nFee, contextInfo) );
4416 q->addOperation(operation);
4417 AsyncRPCOperationId operationId = operation->getId();
4418
4419 // Return continuation information
4420 UniValue o(UniValue::VOBJ);
4ff92bb6 4421 o.push_back(Pair("remainingUTXOs", static_cast<uint64_t>(utxoCounter - numUtxos)));
6e9c7629 4422 o.push_back(Pair("remainingTransparentValue", ValueFromAmount(remainingUTXOValue)));
4ff92bb6 4423 o.push_back(Pair("remainingNotes", static_cast<uint64_t>(noteCounter - numNotes)));
6e9c7629 4424 o.push_back(Pair("remainingShieldedValue", ValueFromAmount(remainingNoteValue)));
4ff92bb6 4425 o.push_back(Pair("mergingUTXOs", static_cast<uint64_t>(numUtxos)));
6e9c7629 4426 o.push_back(Pair("mergingTransparentValue", ValueFromAmount(mergedUTXOValue)));
4ff92bb6 4427 o.push_back(Pair("mergingNotes", static_cast<uint64_t>(numNotes)));
6e9c7629
JG
4428 o.push_back(Pair("mergingShieldedValue", ValueFromAmount(mergedNoteValue)));
4429 o.push_back(Pair("opid", operationId));
4430 return o;
4431}
4432
4433
0d37ae3a 4434UniValue z_listoperationids(const UniValue& params, bool fHelp)
34f0001c
S
4435{
4436 if (!EnsureWalletIsAvailable(fHelp))
0d37ae3a 4437 return NullUniValue;
34f0001c
S
4438
4439 if (fHelp || params.size() > 1)
4440 throw runtime_error(
4441 "z_listoperationids\n"
4442 "\nReturns the list of operation ids currently known to the wallet.\n"
4443 "\nArguments:\n"
c938fb1f 4444 "1. \"status\" (string, optional) Filter result by the operation's state e.g. \"success\".\n"
34f0001c
S
4445 "\nResult:\n"
4446 "[ (json array of string)\n"
4447 " \"operationid\" (string) an operation id belonging to the wallet\n"
4448 " ,...\n"
4449 "]\n"
4450 "\nExamples:\n"
4451 + HelpExampleCli("z_listoperationids", "")
4452 + HelpExampleRpc("z_listoperationids", "")
4453 );
4454
4455 LOCK2(cs_main, pwalletMain->cs_wallet);
4456
4457 std::string filter;
4458 bool useFilter = false;
4459 if (params.size()==1) {
4460 filter = params[0].get_str();
4461 useFilter = true;
4462 }
4463
0d37ae3a 4464 UniValue ret(UniValue::VARR);
34f0001c
S
4465 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
4466 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
4467 for (auto id : ids) {
4468 std::shared_ptr<AsyncRPCOperation> operation = q->getOperationForId(id);
4469 if (!operation) {
4470 continue;
4471 }
4472 std::string state = operation->getStateAsString();
4473 if (useFilter && filter.compare(state)!=0)
4474 continue;
4475 ret.push_back(id);
4476 }
4477
4478 return ret;
4479}
34aca1b0
JS
4480
4481extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
4482extern UniValue importprivkey(const UniValue& params, bool fHelp);
4483extern UniValue importaddress(const UniValue& params, bool fHelp);
4484extern UniValue dumpwallet(const UniValue& params, bool fHelp);
4485extern UniValue importwallet(const UniValue& params, bool fHelp);
4486extern UniValue z_exportkey(const UniValue& params, bool fHelp);
4487extern UniValue z_importkey(const UniValue& params, bool fHelp);
4488extern UniValue z_exportviewingkey(const UniValue& params, bool fHelp);
4489extern UniValue z_importviewingkey(const UniValue& params, bool fHelp);
4490extern UniValue z_exportwallet(const UniValue& params, bool fHelp);
4491extern UniValue z_importwallet(const UniValue& params, bool fHelp);
4492
4493extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp); // in rpcdisclosure.cpp
4494extern UniValue z_validatepaymentdisclosure(const UniValue &params, bool fHelp);
4495
a9496b08 4496static const CRPCCommand commands[] =
34aca1b0
JS
4497{ // category name actor (function) okSafeMode
4498 // --------------------- ------------------------ ----------------------- ----------
4499 { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
4500 { "hidden", "resendwallettransactions", &resendwallettransactions, true },
4501 { "wallet", "addmultisigaddress", &addmultisigaddress, true },
4502 { "wallet", "backupwallet", &backupwallet, true },
4503 { "wallet", "dumpprivkey", &dumpprivkey, true },
4504 { "wallet", "dumpwallet", &dumpwallet, true },
4505 { "wallet", "encryptwallet", &encryptwallet, true },
4506 { "wallet", "getaccountaddress", &getaccountaddress, true },
4507 { "wallet", "getaccount", &getaccount, true },
4508 { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true },
4509 { "wallet", "getbalance", &getbalance, false },
4510 { "wallet", "getnewaddress", &getnewaddress, true },
4511 { "wallet", "getrawchangeaddress", &getrawchangeaddress, true },
4512 { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false },
4513 { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false },
4514 { "wallet", "gettransaction", &gettransaction, false },
4515 { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false },
4516 { "wallet", "getwalletinfo", &getwalletinfo, false },
4517 { "wallet", "importprivkey", &importprivkey, true },
4518 { "wallet", "importwallet", &importwallet, true },
4519 { "wallet", "importaddress", &importaddress, true },
4520 { "wallet", "keypoolrefill", &keypoolrefill, true },
4521 { "wallet", "listaccounts", &listaccounts, false },
4522 { "wallet", "listaddressgroupings", &listaddressgroupings, false },
4523 { "wallet", "listlockunspent", &listlockunspent, false },
4524 { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false },
4525 { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false },
4526 { "wallet", "listsinceblock", &listsinceblock, false },
4527 { "wallet", "listtransactions", &listtransactions, false },
4528 { "wallet", "listunspent", &listunspent, false },
4529 { "wallet", "lockunspent", &lockunspent, true },
4530 { "wallet", "move", &movecmd, false },
4531 { "wallet", "sendfrom", &sendfrom, false },
4532 { "wallet", "sendmany", &sendmany, false },
4533 { "wallet", "sendtoaddress", &sendtoaddress, false },
4534 { "wallet", "setaccount", &setaccount, true },
4535 { "wallet", "settxfee", &settxfee, true },
4536 { "wallet", "signmessage", &signmessage, true },
4537 { "wallet", "walletlock", &walletlock, true },
4538 { "wallet", "walletpassphrasechange", &walletpassphrasechange, true },
4539 { "wallet", "walletpassphrase", &walletpassphrase, true },
4540 { "wallet", "zcbenchmark", &zc_benchmark, true },
4541 { "wallet", "zcrawkeygen", &zc_raw_keygen, true },
4542 { "wallet", "zcrawjoinsplit", &zc_raw_joinsplit, true },
4543 { "wallet", "zcrawreceive", &zc_raw_receive, true },
4544 { "wallet", "zcsamplejoinsplit", &zc_sample_joinsplit, true },
4545 { "wallet", "z_listreceivedbyaddress", &z_listreceivedbyaddress, false },
4546 { "wallet", "z_listunspent", &z_listunspent, false },
4547 { "wallet", "z_getbalance", &z_getbalance, false },
4548 { "wallet", "z_gettotalbalance", &z_gettotalbalance, false },
4549 { "wallet", "z_mergetoaddress", &z_mergetoaddress, false },
4550 { "wallet", "z_sendmany", &z_sendmany, false },
4551 { "wallet", "z_shieldcoinbase", &z_shieldcoinbase, false },
4552 { "wallet", "z_getoperationstatus", &z_getoperationstatus, true },
4553 { "wallet", "z_getoperationresult", &z_getoperationresult, true },
4554 { "wallet", "z_listoperationids", &z_listoperationids, true },
4555 { "wallet", "z_getnewaddress", &z_getnewaddress, true },
4556 { "wallet", "z_listaddresses", &z_listaddresses, true },
4557 { "wallet", "z_exportkey", &z_exportkey, true },
4558 { "wallet", "z_importkey", &z_importkey, true },
4559 { "wallet", "z_exportviewingkey", &z_exportviewingkey, true },
4560 { "wallet", "z_importviewingkey", &z_importviewingkey, true },
4561 { "wallet", "z_exportwallet", &z_exportwallet, true },
4562 { "wallet", "z_importwallet", &z_importwallet, true },
4563 // TODO: rearrange into another category
4564 { "disclosure", "z_getpaymentdisclosure", &z_getpaymentdisclosure, true },
4565 { "disclosure", "z_validatepaymentdisclosure", &z_validatepaymentdisclosure, true }
4566};
4567
a9496b08 4568void RegisterWalletRPCCommands(CRPCTable &tableRPC)
34aca1b0 4569{
a9496b08
WL
4570 for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
4571 tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
34aca1b0 4572}
This page took 1.155676 seconds and 4 git commands to generate.