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