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