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