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