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