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